v1.0.1 release
diff --git a/Readme.md b/Readme.md
index 5cd0c20..43c93df 100644
--- a/Readme.md
+++ b/Readme.md
@@ -3,6 +3,9 @@
 
 To achieve better security, we recommend developers to apply [Non-bypassable Security Paradigm (NbSP)](https://github.com/baidu/rust-sgx-sdk/blob/master/documents/nbsp.pdf) to the system design and implementation.
 
+## v1.0.1 Release
+This version supports the Rust nightly build (nightly-2018-07-16) in master branch and the most recent Rust stable build (stable-2018-07-10). And it supports the latest Intel SGX SDK **v2.2**. New third party libraries include: bytes, http, iovec, rust-crypto, rust-fnv and rust-threshold-secret-sharing. New code sample 'secretsharing' and 'rust-threshold-secret-sharing' is provided by @davidp94. Please refer to [release_notes](release_notes.md) for further details.
+
 ## v1.0.0 Release
 We proudly announce v1.0.0 of rust-sgx-sdk! We port Parity's [Webassembly Interpreter](https://github.com/paritytech/wasmi) to Intel SGX and provide a full functional in-enclave [wasmi sample](samplecode/wasmi), and a [sample solution](samplecode/psi) of two-party private-set-intersection resisting side-channel attacks! From this version, we start to support most recent stable branch of Rust instead of nightly for better stability and future production use. Thus, the [stable branch](https://github.com/baidu/rust-sgx-sdk/tree/rust-stable) of v1.0.0 supports the most recent Rust stable toolchain (1.26.0 stable-2018-05-07), while the master only supports Rust nightly toolchain of nightly-2018-04-11. Please refer to [release_notes](release_notes.md) for further details.
 
@@ -19,7 +22,7 @@
 
 Ubuntu 16.04
 
-[Intel SGX SDK 2.1.3 for Linux](https://01.org/intel-software-guard-extensions/downloads) installed
+[Intel SGX SDK 2.2 for Linux](https://01.org/intel-software-guard-extensions/downloads) installed
 
 Docker (Recommended)
 
@@ -34,7 +37,7 @@
 
 ### Using docker (Recommended) without ME support
 
-First, make sure Intel SGX Driver 2.1.3 is installed and functions well. `/dev/isgx` should be appeared.
+First, make sure Intel SGX Driver 2.2 is installed and functions well. `/dev/isgx` should be appeared.
 
 Second, pull the docker image. If you'd like to work on stable branch of Rust and `rust-stable` branch of this SDK, please pull `baiduxlab/sgx-rust-stable` instead.
 
@@ -138,6 +141,8 @@
 
 * `psi` is a prototype solution of the Private-Set-Intersection problem.
 
+* `secretsharing` shows the usage of Shamir sharing in Rust-SGX environment (provided by @davidp94).
+
 # Samples of ported third-party libraries
 
 As of v0.9.5, we provide 25 ported third-party libraries. All of them could be compiled using xargo (`XARGO_SGX=1` make) or cargo (`make`).
diff --git a/dockerfile/Dockerfile b/dockerfile/Dockerfile
index 24f9a20..0f36903 100644
--- a/dockerfile/Dockerfile
+++ b/dockerfile/Dockerfile
@@ -46,8 +46,8 @@
 #    systemctl enable jhi
 
 RUN mkdir /root/sgx && \
-    wget -O /root/sgx/psw.bin https://download.01.org/intel-sgx/linux-2.1.3/ubuntu64-desktop/sgx_linux_x64_psw_2.1.103.44322.bin && \
-    wget -O /root/sgx/sdk.bin https://download.01.org/intel-sgx/linux-2.1.3/ubuntu64-desktop/sgx_linux_x64_sdk_2.1.103.44322.bin && \
+    wget -O /root/sgx/psw.bin https://download.01.org/intel-sgx/linux-2.2/ubuntu64-desktop/sgx_linux_x64_psw_2.2.100.45311.bin && \
+    wget -O /root/sgx/sdk.bin https://download.01.org/intel-sgx/linux-2.2/ubuntu64-desktop/sgx_linux_x64_sdk_2.2.100.45311.bin && \
     cd /root/sgx && \
     chmod +x /root/sgx/psw.bin && \
     /root/sgx/psw.bin && \
@@ -57,16 +57,16 @@
 
 ADD patch /root/
 
-RUN wget -O /root/src.tar.gz https://github.com/intel/linux-sgx/archive/sgx_2.1.3.tar.gz && \
+RUN wget -O /root/src.tar.gz https://github.com/intel/linux-sgx/archive/sgx_2.2.tar.gz && \
     cd /root && tar xzf src.tar.gz && \
-    cd /root/linux-sgx-sgx_2.1.3 && git apply ../patch && \
-    /root/linux-sgx-sgx_2.1.3/download_prebuilt.sh && \
-    cd /root/linux-sgx-sgx_2.1.3 && make -j && \
-    cp /root/linux-sgx-sgx_2.1.3/build/linux/libsgx_tstdc.a /opt/sgxsdk/lib64/libsgx_tstdc.a
+    cd /root/linux-sgx-sgx_2.2 && git apply ../patch && \
+    /root/linux-sgx-sgx_2.2/download_prebuilt.sh && \
+    cd /root/linux-sgx-sgx_2.2 && make -j && \
+    cp /root/linux-sgx-sgx_2.2/build/linux/libsgx_tstdc.a /opt/sgxsdk/lib64/libsgx_tstdc.a
 
 RUN wget 'https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init' -O /root/rustup-init && \
     chmod +x /root/rustup-init && \
-    echo '1' | /root/rustup-init --default-toolchain nightly-2018-04-12 && \
+    echo '1' | /root/rustup-init --default-toolchain nightly-2018-07-16 && \
     echo 'source /root/.cargo/env' >> /root/.bashrc && \
     /root/.cargo/bin/rustup component add rust-src && \
     /root/.cargo/bin/cargo install xargo && \
diff --git a/dockerfile/experimental/Dockerfile b/dockerfile/experimental/Dockerfile
index 7805ebd..3d4d26f 100644
--- a/dockerfile/experimental/Dockerfile
+++ b/dockerfile/experimental/Dockerfile
@@ -9,7 +9,8 @@
 #   * Redistributions of source code must retain the above copyright
 #     notice, this list of conditions and the following disclaimer.
 #   * 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
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
 #     distribution.
 #   * Neither the name of Baidu, Inc., nor the names of its
 #     contributors may be used to endorse or promote products derived
@@ -54,8 +55,8 @@
 #    cd jhi && mkdir build && cd build && cmake .. && make && make install && \
 #    systemctl enable jhi
 
-RUN wget -O /root/sgx/psw.bin https://download.01.org/intel-sgx/linux-2.1.3/ubuntu64-desktop/sgx_linux_x64_psw_2.1.103.44322.bin && \
-    wget -O /root/sgx/sdk.bin https://download.01.org/intel-sgx/linux-2.1.3/ubuntu64-desktop/sgx_linux_x64_sdk_2.1.103.44322.bin && \
+RUN wget -O /root/sgx/psw.bin https://download.01.org/intel-sgx/linux-2.2/ubuntu64-desktop/sgx_linux_x64_psw_2.2.100.45311.bin && \
+    wget -O /root/sgx/sdk.bin https://download.01.org/intel-sgx/linux-2.2/ubuntu64-desktop/sgx_linux_x64_sdk_2.2.100.45311.bin && \
     cd /root/sgx && \
     chmod +x /root/sgx/psw.bin && \
     /root/sgx/psw.bin && \
@@ -65,18 +66,18 @@
 
 ADD all.patch /root/
 
-RUN wget -O /root/src.tar.gz https://github.com/intel/linux-sgx/archive/sgx_2.1.3.tar.gz && \
-    cd /root && tar xzf src.tar.gz && \
-    cd /root/linux-sgx-sgx_2.1.3 && patch -t -p1 < ../all.patch && \
-    /root/linux-sgx-sgx_2.1.3/download_prebuilt.sh && \
-    cd /root/linux-sgx-sgx_2.1.3 && make -j && \
-    cp /root/linux-sgx-sgx_2.1.3/build/linux/libsgx_tstdc.a /opt/sgxsdk/lib64/libsgx_tstdc.a && \
-    cp /root/linux-sgx-sgx_2.1.3/build/linux/aesm_service /opt/intel/sgxpsw/aesm/aesm_service && \
-    cp /root/linux-sgx-sgx_2.1.3/build/linux/libsgx_uae_service.so /usr/lib/libsgx_uae_service.so
+RUN wget -O /root/src.tar.gz https://github.com/intel/linux-sgx/archive/sgx_2.2.tar.gz && \
+     cd /root && tar xzf src.tar.gz && \
+     cd /root/linux-sgx-sgx_2.2 && patch -t -p1 < ../all.patch && \
+     /root/linux-sgx-sgx_2.2/download_prebuilt.sh && \
+     cd /root/linux-sgx-sgx_2.2 && make -j && \
+     cp /root/linux-sgx-sgx_2.2/build/linux/libsgx_tstdc.a /opt/sgxsdk/lib64/libsgx_tstdc.a && \
+     cp /root/linux-sgx-sgx_2.2/build/linux/aesm_service /opt/intel/sgxpsw/aesm/aesm_service && \
+     cp /root/linux-sgx-sgx_2.2/build/linux/libsgx_uae_service.so /usr/lib/libsgx_uae_service.so
 
 RUN wget 'https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init' -O /root/rustup-init && \
     chmod +x /root/rustup-init && \
-    echo '1' | /root/rustup-init --default-toolchain nightly-2018-04-12 && \
+    echo '1' | /root/rustup-init --default-toolchain nightly-2018-07-16 && \
     echo 'source /root/.cargo/env' >> /root/.bashrc && \
     /root/.cargo/bin/rustup component add rust-src && \
     /root/.cargo/bin/cargo install xargo && \
diff --git a/dockerfile/rust-stable/Dockerfile b/dockerfile/rust-stable/Dockerfile
index 5dd40e8..ba945be 100644
--- a/dockerfile/rust-stable/Dockerfile
+++ b/dockerfile/rust-stable/Dockerfile
@@ -46,8 +46,8 @@
 #    systemctl enable jhi
 
 RUN mkdir /root/sgx && \
-    wget -O /root/sgx/psw.bin https://download.01.org/intel-sgx/linux-2.1.3/ubuntu64-desktop/sgx_linux_x64_psw_2.1.103.44322.bin && \
-    wget -O /root/sgx/sdk.bin https://download.01.org/intel-sgx/linux-2.1.3/ubuntu64-desktop/sgx_linux_x64_sdk_2.1.103.44322.bin && \
+    wget -O /root/sgx/psw.bin https://download.01.org/intel-sgx/linux-2.2/ubuntu64-desktop/sgx_linux_x64_psw_2.2.100.45311.bin && \
+    wget -O /root/sgx/sdk.bin https://download.01.org/intel-sgx/linux-2.2/ubuntu64-desktop/sgx_linux_x64_sdk_2.2.100.45311.bin && \
     cd /root/sgx && \
     chmod +x /root/sgx/psw.bin && \
     /root/sgx/psw.bin && \
@@ -57,16 +57,16 @@
 
 ADD patch /root/
 
-RUN wget -O /root/src.tar.gz https://github.com/intel/linux-sgx/archive/sgx_2.1.3.tar.gz && \
+RUN wget -O /root/src.tar.gz https://github.com/intel/linux-sgx/archive/sgx_2.2.tar.gz && \
     cd /root && tar xzf src.tar.gz && \
-    cd /root/linux-sgx-sgx_2.1.3 && git apply ../patch && \
-    /root/linux-sgx-sgx_2.1.3/download_prebuilt.sh && \
-    cd /root/linux-sgx-sgx_2.1.3 && make -j && \
-    cp /root/linux-sgx-sgx_2.1.3/build/linux/libsgx_tstdc.a /opt/sgxsdk/lib64/libsgx_tstdc.a
+    cd /root/linux-sgx-sgx_2.2 && git apply ../patch && \
+    /root/linux-sgx-sgx_2.2/download_prebuilt.sh && \
+    cd /root/linux-sgx-sgx_2.2 && make -j && \
+    cp /root/linux-sgx-sgx_2.2/build/linux/libsgx_tstdc.a /opt/sgxsdk/lib64/libsgx_tstdc.a
 
 RUN wget 'https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init' -O /root/rustup-init && \
     chmod +x /root/rustup-init && \
-    echo '1' | /root/rustup-init --default-toolchain stable-2018-05-10 && \
+    echo '1' | /root/rustup-init --default-toolchain stable-2018-07-10 && \
     echo 'source /root/.cargo/env' >> /root/.bashrc && \
     /root/.cargo/bin/rustup component add rust-src && \
     /root/.cargo/bin/cargo install xargo && \
diff --git a/release_notes.md b/release_notes.md
index 6ddb270..195328b 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -1,3 +1,16 @@
+# Rust SGX SDK v1.0.1 Release Notes
+
+**Support Intel SGX SDK v2.2**
+
+**Support Rust nightly-2018-07-16**
+
+**Support Rust stable-2018-07-10**
+
+**New third party libraries** bytes, http, iovec, rust-crypto, rust-fnv and rust-threshold-secret-sharing.
+
+**New code sample** Thanks to @davidp94 for the secretsharing code sample.
+
+
 # Rust SGX SDK v1.0.0 Release Notes
 
 Baidu X-Lab provides Rust SGX SDK that is a bundle of basic libraries, scripts and ported libraries for developing Intel SGX programs in Rust programming language. Based on this SDK, developers could easily build up their SGX programs in Rust. Rust SGX SDK provides the strongest defence and helps protect the secret data reside in an enclave effectively even when the OS is compromised. It is important to real world data privacy and cloud security. Since the first day of open source, we have recevied many recommendations and supports from both academic and industry. Today, we are proudly releasing the 1.0.0 version of Rust SGX SDK, indicating that Rust SGX SDK is becoming stable and ready for production.
diff --git a/samplecode/crypto/app/app.c b/samplecode/crypto/app/app.c
index f802a9d..de66a65 100644
--- a/samplecode/crypto/app/app.c
+++ b/samplecode/crypto/app/app.c
@@ -318,7 +318,11 @@
     printf("\n");
 
     printf("[+] Starting aes-gcm-128 decrypt calculation\n");
-    printf("[+] aes-gcm-128 expected plaintext: %s", aes_gcm_plaintext);
+    printf("[+] aes-gcm-128 expected plaintext:");
+    for(i = 0; i < 16; i ++) {
+        printf("%02x", aes_gcm_plaintext[i]);
+    }
+    printf("\n");
 
     uint8_t aes_gcm_decrypted_text[16] = {0};
     sgx_ret = aes_gcm_128_decrypt(global_eid,
@@ -395,6 +399,40 @@
     }
     printf("\n");
 
+    uint8_t rsa_msg[] = {
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+    };
+
+    sgx_ret = rsa_key(global_eid,
+                      &enclave_ret,
+                      rsa_msg,
+                      sizeof(rsa_msg));
+
+    if(sgx_ret != SGX_SUCCESS) {
+        print_error_message(sgx_ret);
+        return -1;
+    }
+    if(enclave_ret != SGX_SUCCESS) {
+        print_error_message(enclave_ret);
+        return -1;
+    }
+    printf("rsa_key success. \n");
+
     /* Destroy the enclave */
     sgx_destroy_enclave(global_eid);
 
diff --git a/samplecode/crypto/enclave/Cargo.toml b/samplecode/crypto/enclave/Cargo.toml
index 428898a..eb6029e 100644
--- a/samplecode/crypto/enclave/Cargo.toml
+++ b/samplecode/crypto/enclave/Cargo.toml
@@ -12,5 +12,6 @@
 
 [target.'cfg(not(target_env = "sgx"))'.dependencies]
 sgx_types = { path = "../../../sgx_types" }
+sgx_trts = { path = "../../../sgx_trts" }
 sgx_tstd = { path = "../../../sgx_tstd" }
-sgx_tcrypto = { path = "../../../sgx_tcrypto" }
+sgx_tcrypto = { path = "../../../sgx_tcrypto" }
\ No newline at end of file
diff --git a/samplecode/crypto/enclave/Enclave.config.xml b/samplecode/crypto/enclave/Enclave.config.xml
index ee4c3f7..f9c49f8 100644
--- a/samplecode/crypto/enclave/Enclave.config.xml
+++ b/samplecode/crypto/enclave/Enclave.config.xml
@@ -2,8 +2,8 @@
 <EnclaveConfiguration>
   <ProdID>0</ProdID>
   <ISVSVN>0</ISVSVN>
-  <StackMaxSize>0x40000</StackMaxSize>
-  <HeapMaxSize>0x100000</HeapMaxSize>
+  <StackMaxSize>0x80000</StackMaxSize>
+  <HeapMaxSize>0x10000000</HeapMaxSize>
   <TCSNum>1</TCSNum>
   <TCSPolicy>1</TCSPolicy>
   <DisableDebug>0</DisableDebug>
diff --git a/samplecode/crypto/enclave/Enclave.edl b/samplecode/crypto/enclave/Enclave.edl
index 08ba4ac..f11d72b 100644
--- a/samplecode/crypto/enclave/Enclave.edl
+++ b/samplecode/crypto/enclave/Enclave.edl
@@ -60,6 +60,8 @@
                                      [in] uint8_t key[16],
                                      [out] uint8_t cmac[16]);
 
+        public sgx_status_t rsa_key([in, size=len] const uint8_t* text, size_t len);
+
     };
 
     untrusted {
diff --git a/samplecode/crypto/enclave/src/lib.rs b/samplecode/crypto/enclave/src/lib.rs
index d412b93..5ce4fd5 100644
--- a/samplecode/crypto/enclave/src/lib.rs
+++ b/samplecode/crypto/enclave/src/lib.rs
@@ -34,12 +34,14 @@
 
 extern crate sgx_types;
 extern crate sgx_tcrypto;
+extern crate sgx_trts;
 #[cfg(not(target_env = "sgx"))]
 #[macro_use]
 extern crate sgx_tstd as std;
 
 use sgx_types::*;
 use sgx_tcrypto::*;
+use sgx_trts::memeq::ConsttimeMemEq;
 use std::vec::Vec;
 use std::slice;
 use std::ptr;
@@ -354,3 +356,102 @@
 
     sgx_status_t::SGX_SUCCESS
 }
+
+
+#[no_mangle]
+pub extern "C" fn rsa_key(text: * const u8, text_len: usize) -> sgx_status_t {
+
+    let text_slice = unsafe { slice::from_raw_parts(text, text_len) };
+
+    if text_slice.len() != text_len {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+
+    let mod_size: i32 = 256;
+    let exp_size: i32 = 4;
+    let mut n: Vec<u8> = vec![0_u8; mod_size as usize];
+    let mut d: Vec<u8> = vec![0_u8; mod_size as usize];
+    let mut e: Vec<u8> = vec![1, 0, 1, 0];
+    let mut p: Vec<u8> = vec![0_u8; mod_size as usize / 2];
+    let mut q: Vec<u8> = vec![0_u8; mod_size as usize / 2];
+    let mut dmp1: Vec<u8> = vec![0_u8; mod_size as usize / 2];
+    let mut dmq1: Vec<u8> = vec![0_u8; mod_size as usize / 2];
+    let mut iqmp: Vec<u8> = vec![0_u8; mod_size as usize / 2];
+
+    let result = rsgx_create_rsa_key_pair(mod_size, 
+                                          exp_size, 
+                                          n.as_mut_slice(),
+                                          d.as_mut_slice(),
+                                          e.as_mut_slice(),
+                                          p.as_mut_slice(),
+                                          q.as_mut_slice(),
+                                          dmp1.as_mut_slice(),
+                                          dmq1.as_mut_slice(),
+                                          iqmp.as_mut_slice());
+
+    match result {
+        Err(x) => {
+            return x;
+        },
+        Ok(()) => {},
+    }
+
+    let privkey = SgxRsaPrivKey::new();
+    let pubkey = SgxRsaPubKey::new();
+
+    let result = pubkey.create(mod_size,
+                               exp_size,
+                               n.as_slice(),
+                               e.as_slice());
+    match result {
+        Err(x) => return x,
+        Ok(()) => {},
+    };
+
+    let result = privkey.create(mod_size,
+                                exp_size,
+                                e.as_slice(),
+                                p.as_slice(),
+                                q.as_slice(),
+                                dmp1.as_slice(),
+                                dmq1.as_slice(),
+                                iqmp.as_slice());
+    match result {
+        Err(x) => return x,
+        Ok(()) => {},
+    };
+
+    let mut ciphertext: Vec<u8> = vec![0_u8; 256];
+    let mut chipertext_len: usize = ciphertext.len();
+    let ret = pubkey.encrypt_sha256(ciphertext.as_mut_slice(),
+                                    &mut chipertext_len,
+                                    text_slice);
+    match ret {
+        Err(x) => {
+            return x;
+        },
+        Ok(()) => {
+            println!("rsa chipertext_len: {:?}", chipertext_len);
+        },
+    };
+
+    let mut plaintext: Vec<u8> = vec![0_u8; 256];
+    let mut plaintext_len: usize = plaintext.len();
+    let ret = privkey.decrypt_sha256(plaintext.as_mut_slice(),
+                                     &mut plaintext_len,
+                                     ciphertext.as_slice());
+    match ret {
+        Err(x) => {
+            return x;
+        },
+        Ok(()) => {
+            println!("rsa plaintext_len: {:?}", plaintext_len);
+        },
+    };
+
+    if plaintext[..plaintext_len].consttime_memeq(text_slice) == false {
+        return sgx_status_t::SGX_ERROR_UNEXPECTED;
+    }
+
+    sgx_status_t::SGX_SUCCESS
+}
\ No newline at end of file
diff --git a/samplecode/hello-rust/app/Cargo.toml b/samplecode/hello-rust/app/Cargo.toml
index 60e48cb..c88842b 100644
--- a/samplecode/hello-rust/app/Cargo.toml
+++ b/samplecode/hello-rust/app/Cargo.toml
@@ -7,3 +7,4 @@
 [dependencies]
 sgx_types = { path = "../../../sgx_types" }
 sgx_urts = { path = "../../../sgx_urts" }
+dirs = "1.0.2"
diff --git a/samplecode/hello-rust/app/src/main.rs b/samplecode/hello-rust/app/src/main.rs
index 79c72f7..215390d 100644
--- a/samplecode/hello-rust/app/src/main.rs
+++ b/samplecode/hello-rust/app/src/main.rs
@@ -28,13 +28,13 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 use sgx_types::*;
 use sgx_urts::SgxEnclave;
 
 use std::io::{Read, Write};
 use std::fs;
 use std::path;
-use std::env;
 
 static ENCLAVE_FILE: &'static str = "enclave.signed.so";
 static ENCLAVE_TOKEN: &'static str = "enclave.token";
@@ -53,7 +53,7 @@
     // 
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
@@ -147,4 +147,4 @@
     println!("[+] say_something success...");
     
     enclave.destroy();
-}
\ No newline at end of file
+}
diff --git a/samplecode/machine-learning/app/Cargo.toml b/samplecode/machine-learning/app/Cargo.toml
index 60e48cb..c88842b 100644
--- a/samplecode/machine-learning/app/Cargo.toml
+++ b/samplecode/machine-learning/app/Cargo.toml
@@ -7,3 +7,4 @@
 [dependencies]
 sgx_types = { path = "../../../sgx_types" }
 sgx_urts = { path = "../../../sgx_urts" }
+dirs = "1.0.2"
diff --git a/samplecode/machine-learning/app/src/main.rs b/samplecode/machine-learning/app/src/main.rs
index 169842a..f5e615e 100644
--- a/samplecode/machine-learning/app/src/main.rs
+++ b/samplecode/machine-learning/app/src/main.rs
@@ -28,13 +28,13 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 use sgx_types::*;
 use sgx_urts::SgxEnclave;
 
 use std::io::{Read, Write};
 use std::fs;
 use std::path;
-use std::env;
 
 static ENCLAVE_FILE: &'static str = "enclave.signed.so";
 static ENCLAVE_TOKEN: &'static str = "enclave.token";
@@ -52,7 +52,7 @@
     // 
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
diff --git a/samplecode/protobuf/app/Cargo.toml b/samplecode/protobuf/app/Cargo.toml
index 10f49a0..391ef5f 100644
--- a/samplecode/protobuf/app/Cargo.toml
+++ b/samplecode/protobuf/app/Cargo.toml
@@ -7,4 +7,5 @@
 [dependencies]
 sgx_types = { path = "../../../sgx_types" }
 sgx_urts = { path = "../../../sgx_urts" }
-protobuf = "1.4.4"
+protobuf = "=1.4.4"
+dirs = "1.0.2"
diff --git a/samplecode/protobuf/app/src/main.rs b/samplecode/protobuf/app/src/main.rs
index 7cf3559..d28ca83 100644
--- a/samplecode/protobuf/app/src/main.rs
+++ b/samplecode/protobuf/app/src/main.rs
@@ -28,6 +28,7 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 extern crate protobuf;
 
 use sgx_types::*;
@@ -36,7 +37,6 @@
 use std::io::{Read, Write};
 use std::fs;
 use std::path;
-use std::env;
 
 mod person;
 use person::Person;
@@ -60,7 +60,7 @@
     // 
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
diff --git a/samplecode/secretsharing/Makefile b/samplecode/secretsharing/Makefile
index 506bef3..55c4f03 100644
--- a/samplecode/secretsharing/Makefile
+++ b/samplecode/secretsharing/Makefile
@@ -30,7 +30,7 @@
 ######## SGX SDK Settings ########
 
 SGX_SDK ?= /opt/intel/sgxsdk
-SGX_MODE ?= SW
+SGX_MODE ?= HW
 SGX_ARCH ?= x64
 
 ifeq ($(shell getconf LONG_BIT), 32)
diff --git a/samplecode/secretsharing/enclave/Cargo.toml b/samplecode/secretsharing/enclave/Cargo.toml
index 54314a7..0851183 100644
--- a/samplecode/secretsharing/enclave/Cargo.toml
+++ b/samplecode/secretsharing/enclave/Cargo.toml
@@ -1,10 +1,10 @@
 [package]
-name = "Helloworldsampleenclave"
+name = "Secretsharingenclave"
 version = "1.0.0"
 authors = ["Baidu"]
 
 [lib]
-name = "helloworldsampleenclave"
+name = "secretsharingenclave"
 crate-type = ["staticlib"]
 
 [features]
@@ -15,4 +15,4 @@
 sgx_tstd = { path = "../../../sgx_tstd" }
 
 [dependencies]
-threshold-secret-sharing = { path = "../../../third_party/rust-threshold-secret-sharing" }
\ No newline at end of file
+threshold-secret-sharing = { path = "../../../third_party/rust-threshold-secret-sharing" }
diff --git a/samplecode/secretsharing/enclave/Makefile b/samplecode/secretsharing/enclave/Makefile
index 5799f22..5c3221d 100644
--- a/samplecode/secretsharing/enclave/Makefile
+++ b/samplecode/secretsharing/enclave/Makefile
@@ -36,10 +36,9 @@
 
 $(Rust_Enclave_Name): $(Rust_Enclave_Files)
 ifeq ($(XARGO_SGX), 1)
-	cd ../../../xargo/xargo && cargo build --release
-	RUST_TARGET_PATH=$(Rust_Target_Path) RUSTC_BOOTSTRAP=1 ../../../xargo/xargo/target/release/xargo build --target x86_64-unknown-linux-sgx --release
-	cp ./target/x86_64-unknown-linux-sgx/release/libhelloworldsampleenclave.a ../lib/libenclave.a
+	RUST_TARGET_PATH=$(Rust_Target_Path) RUSTC_BOOTSTRAP=1 xargo build --target x86_64-unknown-linux-sgx --release
+	cp ./target/x86_64-unknown-linux-sgx/release/libsecretsharingenclave.a ../lib/libenclave.a
 else
 	RUSTC_BOOTSTRAP=1 cargo build --release
-	cp ./target/release/libhelloworldsampleenclave.a ../lib/libenclave.a
-endif
\ No newline at end of file
+	cp ./target/release/libsecretsharingenclave.a ../lib/libenclave.a
+endif
diff --git a/samplecode/secretsharing/enclave/Xargo.toml b/samplecode/secretsharing/enclave/Xargo.toml
index 8457060..4b0ad79 100644
--- a/samplecode/secretsharing/enclave/Xargo.toml
+++ b/samplecode/secretsharing/enclave/Xargo.toml
@@ -3,23 +3,18 @@
 panic_unwind = {}
 panic_abort = {}
 
-[dependencies.compiler_builtins]
-features = ["c", "compiler-builtins"]
-git = "https://github.com/rust-lang-nursery/compiler-builtins"
-stage = 1
-
 [dependencies.std]
 path = "../../../xargo/sgx_tstd"
-stage = 2
+stage = 1
 
 [dependencies.sgx_rand]
 path = "../../../xargo/sgx_rand"
-stage = 3
+stage = 2
 
 [dependencies.sgx_serialize]
 path = "../../../xargo/sgx_serialize"
-stage = 3
+stage = 2
 
 [dependencies.sgx_tunittest]
 path = "../../../xargo/sgx_tunittest"
-stage = 3
\ No newline at end of file
+stage = 2
diff --git a/samplecode/secretsharing/enclave/src/lib.rs b/samplecode/secretsharing/enclave/src/lib.rs
index a6b38bb..8962324 100644
--- a/samplecode/secretsharing/enclave/src/lib.rs
+++ b/samplecode/secretsharing/enclave/src/lib.rs
@@ -26,7 +26,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#![crate_name = "helloworldsampleenclave"]
+#![crate_name = "secretsharingenclave"]
 #![crate_type = "staticlib"]
 
 #![cfg_attr(not(target_env = "sgx"), no_std)]
diff --git a/samplecode/sgxtime/app/Cargo.toml b/samplecode/sgxtime/app/Cargo.toml
index 60e48cb..c88842b 100644
--- a/samplecode/sgxtime/app/Cargo.toml
+++ b/samplecode/sgxtime/app/Cargo.toml
@@ -7,3 +7,4 @@
 [dependencies]
 sgx_types = { path = "../../../sgx_types" }
 sgx_urts = { path = "../../../sgx_urts" }
+dirs = "1.0.2"
diff --git a/samplecode/sgxtime/app/src/main.rs b/samplecode/sgxtime/app/src/main.rs
index d73189d..0d1d2a8 100644
--- a/samplecode/sgxtime/app/src/main.rs
+++ b/samplecode/sgxtime/app/src/main.rs
@@ -28,13 +28,13 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 use sgx_types::*;
 use sgx_urts::SgxEnclave;
 
 use std::io::{Read, Write};
 use std::fs;
 use std::path;
-use std::env;
 
 static ENCLAVE_FILE: &'static str = "enclave.signed.so";
 static ENCLAVE_TOKEN: &'static str = "enclave.token";
@@ -52,7 +52,7 @@
     // 
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
diff --git a/samplecode/test_all.sh b/samplecode/test_all.sh
deleted file mode 100755
index 499d73e..0000000
--- a/samplecode/test_all.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2017-2018 Baidu, Inc. All Rights Reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-#  * Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-#  * 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.
-#  * Neither the name of Baidu, Inc., nor the names of its
-#    contributors may be used to endorse or promote products derived
-#    from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "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 COPYRIGHT
-# OWNER 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.
-#
-
-test_cases=(backtrace \
-            crypto \
-            file \
-            hello-rust \
-            helloworld \
-#            hugemem \
-            localattestation \
-            machine-learning \
-            protobuf \
-            sealeddata \
-            serialize \
-            thread \
-            unit-test \
-            zlib-lazy-static-sample)
-
-for i in ${test_cases[@]}
-do
-	cd ${i} && make && cd bin && echo -e '\n' | ./app && cd ../ && make clean && \
-	   XARGO_SGX=1 make && cd bin && echo -e '\n' | ./app && cd ../ && make clean && cd ..
-done
-
-echo "Done!"
diff --git a/samplecode/tls/tlsclient/app/Cargo.toml b/samplecode/tls/tlsclient/app/Cargo.toml
index ad0baca..1acab10 100644
--- a/samplecode/tls/tlsclient/app/Cargo.toml
+++ b/samplecode/tls/tlsclient/app/Cargo.toml
@@ -8,3 +8,4 @@
 sgx_types = { path = "../../../../sgx_types" }
 sgx_urts = { path = "../../../../sgx_urts" }
 mio = "0.6"
+dirs = "1.0.2"
diff --git a/samplecode/tls/tlsclient/app/src/main.rs b/samplecode/tls/tlsclient/app/src/main.rs
index 36c2170..5ecf989 100644
--- a/samplecode/tls/tlsclient/app/src/main.rs
+++ b/samplecode/tls/tlsclient/app/src/main.rs
@@ -30,6 +30,7 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 use sgx_types::*;
 use sgx_urts::SgxEnclave;
 
@@ -40,7 +41,6 @@
 use std::ffi::CString;
 use std::fs;
 use std::path;
-use std::env;
 use std::net::SocketAddr;
 use std::str;
 use std::ptr;
@@ -75,7 +75,7 @@
     //
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
diff --git a/samplecode/tls/tlsserver/app/Cargo.toml b/samplecode/tls/tlsserver/app/Cargo.toml
index ad0baca..1acab10 100644
--- a/samplecode/tls/tlsserver/app/Cargo.toml
+++ b/samplecode/tls/tlsserver/app/Cargo.toml
@@ -8,3 +8,4 @@
 sgx_types = { path = "../../../../sgx_types" }
 sgx_urts = { path = "../../../../sgx_urts" }
 mio = "0.6"
+dirs = "1.0.2"
diff --git a/samplecode/tls/tlsserver/app/src/main.rs b/samplecode/tls/tlsserver/app/src/main.rs
index c3a63b6..ab0654f 100644
--- a/samplecode/tls/tlsserver/app/src/main.rs
+++ b/samplecode/tls/tlsserver/app/src/main.rs
@@ -31,6 +31,7 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 use sgx_types::*;
 use sgx_urts::SgxEnclave;
 
@@ -41,7 +42,6 @@
 use std::ffi::CString;
 use std::fs;
 use std::path;
-use std::env;
 use std::net;
 use std::str;
 use std::ptr;
@@ -80,7 +80,7 @@
     //
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
@@ -651,4 +651,4 @@
     println!("[+] Test tlsServer in enclave, done!");
 
     enclave.destroy();
-}
\ No newline at end of file
+}
diff --git a/samplecode/unit-test/app/Cargo.toml b/samplecode/unit-test/app/Cargo.toml
index 60e48cb..c88842b 100644
--- a/samplecode/unit-test/app/Cargo.toml
+++ b/samplecode/unit-test/app/Cargo.toml
@@ -7,3 +7,4 @@
 [dependencies]
 sgx_types = { path = "../../../sgx_types" }
 sgx_urts = { path = "../../../sgx_urts" }
+dirs = "1.0.2"
diff --git a/samplecode/unit-test/app/src/main.rs b/samplecode/unit-test/app/src/main.rs
index 8991838..8ff35aa 100644
--- a/samplecode/unit-test/app/src/main.rs
+++ b/samplecode/unit-test/app/src/main.rs
@@ -28,13 +28,13 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 use sgx_types::*;
 use sgx_urts::SgxEnclave;
 
 use std::io::{Read, Write};
 use std::fs;
 use std::path;
-use std::env;
 
 static ENCLAVE_FILE: &'static str = "enclave.signed.so";
 static ENCLAVE_TOKEN: &'static str = "enclave.token";
@@ -52,7 +52,7 @@
     //
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
diff --git a/samplecode/wasmi/app/Cargo.toml b/samplecode/wasmi/app/Cargo.toml
index a4fb80f..0c7516a 100644
--- a/samplecode/wasmi/app/Cargo.toml
+++ b/samplecode/wasmi/app/Cargo.toml
@@ -12,3 +12,4 @@
 serde_json = {version = "1.0.17"}
 serde_derive = {version = "1.0.5"}
 wasmi = { path = "wasmi-0.1.1", version = "0.1.1" }
+dirs = "1.0.2"
diff --git a/samplecode/wasmi/app/src/main.rs b/samplecode/wasmi/app/src/main.rs
index 3fc78a1..68b01fb 100644
--- a/samplecode/wasmi/app/src/main.rs
+++ b/samplecode/wasmi/app/src/main.rs
@@ -28,6 +28,7 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 
 extern crate wabt;
 extern crate wasmi;
@@ -36,7 +37,7 @@
 use sgx_urts::SgxEnclave;
 
 use std::io::{Read, Write};
-use std::{fs, path, env};
+use std::{fs, path};
 
 use wasmi::{RuntimeValue, Error as InterpreterError};
 use wabt::script::{Action, Command, CommandKind, ScriptParser, Value};
@@ -147,7 +148,7 @@
     // 
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
diff --git a/samplecode/zlib-lazy-static-sample/app/Cargo.toml b/samplecode/zlib-lazy-static-sample/app/Cargo.toml
index 60e48cb..c88842b 100644
--- a/samplecode/zlib-lazy-static-sample/app/Cargo.toml
+++ b/samplecode/zlib-lazy-static-sample/app/Cargo.toml
@@ -7,3 +7,4 @@
 [dependencies]
 sgx_types = { path = "../../../sgx_types" }
 sgx_urts = { path = "../../../sgx_urts" }
+dirs = "1.0.2"
diff --git a/samplecode/zlib-lazy-static-sample/app/src/main.rs b/samplecode/zlib-lazy-static-sample/app/src/main.rs
index 8ce952d..e0f7fb3 100644
--- a/samplecode/zlib-lazy-static-sample/app/src/main.rs
+++ b/samplecode/zlib-lazy-static-sample/app/src/main.rs
@@ -28,13 +28,13 @@
 
 extern crate sgx_types;
 extern crate sgx_urts;
+extern crate dirs;
 use sgx_types::*;
 use sgx_urts::SgxEnclave;
 
 use std::io::{Read, Write};
 use std::fs;
 use std::path;
-use std::env;
 
 static ENCLAVE_FILE: &'static str = "enclave.signed.so";
 static ENCLAVE_TOKEN: &'static str = "enclave.token";
@@ -52,7 +52,7 @@
     // 
     // try to get the token saved in $HOME */
     let mut home_dir = path::PathBuf::new();
-    let use_token = match env::home_dir() {
+    let use_token = match dirs::home_dir() {
         Some(path) => {
             println!("[+] Home dir is {}", path.display());
             home_dir = path;
diff --git a/sgx_alloc/Cargo.toml b/sgx_alloc/Cargo.toml
index e3a4951..8788b6f 100644
--- a/sgx_alloc/Cargo.toml
+++ b/sgx_alloc/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_alloc"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_alloc/src/lib.rs b/sgx_alloc/src/lib.rs
index 646e802..42d83fa 100644
--- a/sgx_alloc/src/lib.rs
+++ b/sgx_alloc/src/lib.rs
@@ -31,15 +31,16 @@
 //! This crate equals to the `liballoc_system` crate in Rust.
 //! It connects Rust memory allocation to Intel SGX's sgx_tstd library.
 //! It is essential, because we depends on Intel SGX's SDK.
+//! 2018-06-22 Add liballoc components here
 
 #![no_std]
 
-#![feature(global_allocator)]
 #![feature(allocator_api)]
 
 extern crate sgx_trts;
 
-use core::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace};
+use core::alloc::{GlobalAlloc, Alloc, AllocErr, Layout, };
+use core::ptr::NonNull;
 
 // The minimum alignment guaranteed by the architecture. This value is used to
 // add fast paths for low alignment values. In practice, the alignment is a
@@ -53,153 +54,105 @@
 
 unsafe impl Alloc for System {
     #[inline]
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
-        (&*self).alloc(layout)
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+        NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&mut self, layout: Layout)
-        -> Result<*mut u8, AllocErr>
+        -> Result<NonNull<u8>, AllocErr>
     {
-        (&*self).alloc_zeroed(layout)
+        NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
     }
 
     #[inline]
-    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
-        (&*self).dealloc(ptr, layout)
+    unsafe fn dealloc(&mut self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
+        GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
     }
 
     #[inline]
     unsafe fn realloc(&mut self,
-                      ptr: *mut u8,
-                      old_layout: Layout,
-                      new_layout: Layout) -> Result<*mut u8, AllocErr> {
-        (&*self).realloc(ptr, old_layout, new_layout)
+                      ptr: core::ptr::NonNull<u8>,
+                      layout: Layout,
+                      new_size: usize) -> Result<NonNull<u8>, AllocErr> {
+        NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
     }
+}
 
-    fn oom(&mut self, err: AllocErr) -> ! {
-        (&*self).oom(err)
-    }
 
-    #[inline]
-    fn usable_size(&self, layout: &Layout) -> (usize, usize) {
-        (&self).usable_size(layout)
-    }
+mod realloc_fallback {
+    use core::alloc::{GlobalAlloc, Layout};
+    use core::cmp;
+    use core::ptr;
 
-    #[inline]
-    unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
-        (&*self).alloc_excess(layout)
-    }
+    impl super::System {
+        pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
+                                              new_size: usize) -> *mut u8 {
+            // Docs for GlobalAlloc::realloc require this to be valid:
+            let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
 
-    #[inline]
-    unsafe fn realloc_excess(&mut self,
-                             ptr: *mut u8,
-                             layout: Layout,
-                             new_layout: Layout) -> Result<Excess, AllocErr> {
-        (&*self).realloc_excess(ptr, layout, new_layout)
-    }
-
-    #[inline]
-    unsafe fn grow_in_place(&mut self,
-                            ptr: *mut u8,
-                            layout: Layout,
-                            new_layout: Layout) -> Result<(), CannotReallocInPlace> {
-        (&*self).grow_in_place(ptr, layout, new_layout)
-    }
-
-    #[inline]
-    unsafe fn shrink_in_place(&mut self,
-                              ptr: *mut u8,
-                              layout: Layout,
-                              new_layout: Layout) -> Result<(), CannotReallocInPlace> {
-        (&*self).shrink_in_place(ptr, layout, new_layout)
+            let new_ptr = GlobalAlloc::alloc(self, new_layout);
+            if !new_ptr.is_null() {
+                let size = cmp::min(old_layout.size(), new_size);
+                ptr::copy_nonoverlapping(ptr, new_ptr, size);
+                GlobalAlloc::dealloc(self, ptr, old_layout);
+            }
+            new_ptr
+        }
     }
 }
 
 mod platform {
 
     use sgx_trts::libc::{self, c_void};
-    use core::cmp;
     use core::ptr;
 
     use MIN_ALIGN;
     use System;
-    use core::heap::{Alloc, AllocErr, Layout};
+    use core::alloc::{GlobalAlloc, Layout};
 
-    unsafe impl<'a> Alloc for &'a System {
+    unsafe impl GlobalAlloc for System {
         #[inline]
-        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
             let ptr = if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
                 libc::malloc(layout.size()) as *mut u8
             } else {
                 aligned_malloc(&layout)
             };
-            if !ptr.is_null() {
-                Ok(ptr)
-            } else {
-                Err(AllocErr::Exhausted { request: layout })
-            }
+            ptr
         }
 
         #[inline]
-        unsafe fn alloc_zeroed(&mut self, layout: Layout)
-            -> Result<*mut u8, AllocErr>
+        unsafe fn alloc_zeroed(&self, layout: Layout)
+            -> *mut u8
         {
             if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
-                let ptr = libc::calloc(layout.size(), 1) as *mut u8;
-                if !ptr.is_null() {
-                    Ok(ptr)
-                } else {
-                    Err(AllocErr::Exhausted { request: layout })
-                }
+                libc::calloc(layout.size(), 1) as *mut u8
             } else {
-                let ret = self.alloc(layout.clone());
-                if let Ok(ptr) = ret {
+                let ptr = self.alloc(layout.clone());
+                if !ptr.is_null() {
                     ptr::write_bytes(ptr, 0, layout.size());
                 }
-                ret
+                ptr 
             }
         }
 
         #[inline]
-        unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) {
+        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
             libc::free(ptr as *mut c_void)
         }
 
         #[inline]
-        unsafe fn realloc(&mut self,
+        unsafe fn realloc(&self,
                           ptr: *mut u8,
-                          old_layout: Layout,
-                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
-            if old_layout.align() != new_layout.align() {
-                return Err(AllocErr::Unsupported {
-                    details: "cannot change alignment on `realloc`",
-                })
-            }
-
-            if new_layout.align() <= MIN_ALIGN  && new_layout.align() <= new_layout.size() {
-                let ptr = libc::realloc(ptr as *mut c_void, new_layout.size());
-                if !ptr.is_null() {
-                    Ok(ptr as *mut u8)
-                } else {
-                    Err(AllocErr::Exhausted { request: new_layout })
-                }
+                          layout: Layout,
+                          new_size: usize) -> *mut u8 {
+            if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+                libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
             } else {
-                let res = self.alloc(new_layout.clone());
-                if let Ok(new_ptr) = res {
-                    let size = cmp::min(old_layout.size(), new_layout.size());
-                    ptr::copy_nonoverlapping(ptr, new_ptr, size);
-                    self.dealloc(ptr, old_layout);
-                }
-                res
+                self.realloc_fallback(ptr, layout, new_size)
             }
         }
-
-        fn oom(&mut self, err: AllocErr) -> ! {
-
-            use sgx_trts::oom;
-            oom::rsgx_oom(err)
-        }
     }
 
     #[inline]
diff --git a/sgx_rand/Cargo.toml b/sgx_rand/Cargo.toml
index 7fd1efe..8f6eef3 100644
--- a/sgx_rand/Cargo.toml
+++ b/sgx_rand/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_rand"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_rand_derive/Cargo.toml b/sgx_rand_derive/Cargo.toml
index 5392f7e..c79a8e9 100644
--- a/sgx_rand_derive/Cargo.toml
+++ b/sgx_rand_derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_rand_derive"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_serialize/Cargo.toml b/sgx_serialize/Cargo.toml
index cb1f1f1..207e4d0 100644
--- a/sgx_serialize/Cargo.toml
+++ b/sgx_serialize/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_serialize"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_serialize_derive/Cargo.toml b/sgx_serialize_derive/Cargo.toml
index a41ae08..f431ad0 100644
--- a/sgx_serialize_derive/Cargo.toml
+++ b/sgx_serialize_derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_serialize_derive"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_serialize_derive_internals/Cargo.toml b/sgx_serialize_derive_internals/Cargo.toml
index af55b53..4c3f759 100644
--- a/sgx_serialize_derive_internals/Cargo.toml
+++ b/sgx_serialize_derive_internals/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_serialize_derive_internals"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_tcrypto/Cargo.toml b/sgx_tcrypto/Cargo.toml
index 98610cc..addfd53 100644
--- a/sgx_tcrypto/Cargo.toml
+++ b/sgx_tcrypto/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tcrypto"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_tcrypto/src/crypto.rs b/sgx_tcrypto/src/crypto.rs
index 33cacda..60f8cf0 100644
--- a/sgx_tcrypto/src/crypto.rs
+++ b/sgx_tcrypto/src/crypto.rs
@@ -2264,4 +2264,445 @@
             _ => Err(ret),
         }
     }
-}
\ No newline at end of file
+}
+
+pub fn rsgx_create_rsa_key_pair(n_byte_size: i32,
+                                e_byte_size: i32,
+                                n: &mut [u8],
+                                d: &mut [u8],
+                                e: &mut [u8],
+                                p: &mut [u8],
+                                q: &mut [u8],
+                                dmp1: &mut [u8],
+                                dmq1: &mut [u8],
+                                iqmp: &mut [u8]) -> SgxError {
+
+    if (n_byte_size <= 0) || (e_byte_size <= 0) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (n.len() == 0) || (n.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (d.len() == 0) || (d.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (e.len() == 0) || (e.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (p.len() == 0) || (p.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (q.len() == 0) || (q.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (dmp1.len() == 0) || (dmp1.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (dmq1.len() == 0) || (dmq1.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (iqmp.len() == 0) || (iqmp.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+
+    let ret = unsafe {
+        sgx_create_rsa_key_pair(n_byte_size,
+                                e_byte_size,
+                                n.as_mut_ptr(),
+                                d.as_mut_ptr(),
+                                e.as_mut_ptr(),
+                                p.as_mut_ptr(),
+                                q.as_mut_ptr(),
+                                dmp1.as_mut_ptr(),
+                                dmq1.as_mut_ptr(),
+                                iqmp.as_mut_ptr())
+    };
+    match ret {
+        sgx_status_t::SGX_SUCCESS => Ok(()),
+        _ => Err(ret),
+    }
+}
+
+fn rsgx_create_rsa_priv_key(mod_size: i32,
+                            exp_size: i32,
+                            e: &[u8],
+                            p: &[u8],
+                            q: &[u8],
+                            dmp1: &[u8],
+                            dmq1: &[u8],
+                            iqmp: &[u8],
+                            new_pri_key: &mut sgx_rsa_key_t) -> sgx_status_t {
+
+    if (mod_size <= 0) || (exp_size <= 0) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (e.len() == 0) || (e.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (p.len() == 0) || (p.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (q.len() == 0) || (q.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (dmp1.len() == 0) || (dmp1.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (dmq1.len() == 0) || (dmq1.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (iqmp.len() == 0) || (iqmp.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+
+    unsafe {
+        sgx_create_rsa_priv2_key(mod_size,
+                                 exp_size,
+                                 e.as_ptr(),
+                                 p.as_ptr(),
+                                 q.as_ptr(),
+                                 dmp1.as_ptr(),
+                                 dmq1.as_ptr(),
+                                 iqmp.as_ptr(),
+                                 new_pri_key as * mut sgx_rsa_key_t)
+    }
+}
+
+fn rsgx_create_rsa_pub_key(mod_size: i32,
+                           exp_size: i32,
+                           n: &[u8],
+                           e: &[u8],
+                           new_pub_key: &mut sgx_rsa_key_t) -> sgx_status_t {
+
+    if (mod_size <= 0) || (exp_size <= 0) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (n.len() == 0) || (n.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if (e.len() == 0) || (e.len() > i32::max_value() as usize) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+
+    unsafe {
+        sgx_create_rsa_pub1_key(mod_size,
+                                exp_size,
+                                n.as_ptr(),
+                                e.as_ptr(),
+                                new_pub_key as * mut sgx_rsa_key_t)
+    }
+}
+
+fn rsgx_free_rsa_key(rsa_key: sgx_rsa_key_t,
+                     key_type: sgx_rsa_key_type_t,
+                     mod_size: i32,
+                     exp_size: i32) -> sgx_status_t {
+
+    if (mod_size <= 0) || (exp_size <= 0) {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+
+    unsafe {
+        sgx_free_rsa_key(rsa_key, key_type, mod_size, exp_size)
+    }
+}
+
+fn rsgx_rsa_priv_decrypt_sha256(rsa_key: sgx_rsa_key_t,
+                                out_data: &mut [u8],
+                                out_len: &mut usize,
+                                in_data: &[u8]) -> sgx_status_t {
+
+    if in_data.len() == 0 {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if * out_len != 0 && out_data.len() != * out_len {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+
+    unsafe {
+         let mut p_out_data: * mut u8 = ptr::null_mut();
+        if * out_len != 0 {
+            p_out_data = out_data.as_mut_ptr();
+        }
+        sgx_rsa_priv_decrypt_sha256(rsa_key,
+                                    p_out_data,
+                                    out_len as * mut usize,
+                                    in_data.as_ptr(),
+                                    in_data.len())
+    }
+}
+
+fn rsgx_rsa_pub_encrypt_sha256(rsa_key: sgx_rsa_key_t,
+                               out_data: &mut [u8],
+                               out_len: &mut usize,
+                               in_data: &[u8]) -> sgx_status_t {
+
+    if in_data.len() == 0 {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    if * out_len != 0 && out_data.len() != * out_len {
+        return sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
+    }
+    
+    unsafe {
+        let mut p_out_data: * mut u8 = ptr::null_mut();
+        if * out_len != 0 {
+            p_out_data = out_data.as_mut_ptr();
+        }
+        sgx_rsa_pub_encrypt_sha256(rsa_key,
+                                   p_out_data,
+                                   out_len as * mut usize,
+                                   in_data.as_ptr(),
+                                   in_data.len())
+    }
+}
+
+pub struct SgxRsaPrivKey {
+    key: RefCell<sgx_rsa_key_t>,
+    mod_size: Cell<i32>,
+    exp_size: Cell<i32>,
+    createflag: Cell<bool>,
+}
+
+impl SgxRsaPrivKey {
+
+    pub fn new() -> Self {
+        SgxRsaPrivKey {
+            key: RefCell::new(ptr::null_mut() as sgx_rsa_key_t),
+            mod_size: Cell::new(0),
+            exp_size: Cell::new(0),
+            createflag: Cell::new(false),
+        }
+    }
+
+    pub fn create(&self, 
+                  mod_size: i32,
+                  exp_size: i32,
+                  e: &[u8],
+                  p: &[u8],
+                  q: &[u8],
+                  dmp1: &[u8],
+                  dmq1: &[u8],
+                  iqmp: &[u8]) -> SgxError {
+
+        
+        if self.createflag.get() == true {
+            return Ok(());
+        }
+
+        let ret = rsgx_create_rsa_priv_key(mod_size,
+                                           exp_size,
+                                           e,
+                                           p,
+                                           q,
+                                           dmp1,
+                                           dmq1,
+                                           iqmp,
+                                           self.key.borrow_mut().deref_mut());
+        match ret {
+            sgx_status_t::SGX_SUCCESS => {
+                self.mod_size.set(mod_size);
+                self.exp_size.set(exp_size);
+                self.createflag.set(true);
+                Ok(())
+            },
+            _ => Err(ret),
+        }
+    }
+
+    pub fn decrypt_sha256(&self,
+                          out_data: &mut [u8],
+                          out_len: &mut usize,
+                          in_data: &[u8]) -> SgxError {
+
+        if self.createflag.get() == false {
+            return Err(sgx_status_t::SGX_ERROR_INVALID_STATE);
+        }
+
+        let ret = rsgx_rsa_priv_decrypt_sha256(*self.key.borrow(),
+                                               out_data,
+                                               out_len,
+                                               in_data);
+        match ret {
+            sgx_status_t::SGX_SUCCESS => {
+                Ok(())
+            },
+            _ => Err(ret),
+        }
+    }
+
+    pub fn free(&self) -> SgxError {
+
+        if self.createflag.get() == false {
+            return Ok(());
+        }
+
+        let ret = {
+            let key = *self.key.borrow();
+            if key.is_null() == true {
+                sgx_status_t::SGX_SUCCESS
+            } else {
+                rsgx_free_rsa_key(key, 
+                                  sgx_rsa_key_type_t::SGX_RSA_PRIVATE_KEY, 
+                                  self.mod_size.get(),
+                                  self.exp_size.get())
+            }
+        };
+
+        match ret {
+            sgx_status_t::SGX_SUCCESS => {
+                self.createflag.set(false);
+                *self.key.borrow_mut() = ptr::null_mut();
+                Ok(())
+            },
+            _ => Err(ret),
+        }
+    }
+}
+
+impl Default for SgxRsaPrivKey {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl Drop for SgxRsaPrivKey {
+    fn drop(&mut self) {
+        let _ = self.free();
+    }
+}
+
+pub struct SgxRsaPubKey {
+    key: RefCell<sgx_rsa_key_t>,
+    mod_size: Cell<i32>,
+    exp_size: Cell<i32>,
+    createflag: Cell<bool>,
+}
+
+impl SgxRsaPubKey {
+
+    pub fn new() -> Self {
+        SgxRsaPubKey {
+            key: RefCell::new(ptr::null_mut() as sgx_rsa_key_t),
+            mod_size: Cell::new(0),
+            exp_size: Cell::new(0),
+            createflag: Cell::new(false),
+        }
+    }
+
+    pub fn create(&self, 
+                  mod_size: i32,
+                  exp_size: i32,
+                  n: &[u8],
+                  e: &[u8]) -> SgxError {
+        
+        if self.createflag.get() == true {
+            return Ok(());
+        }
+
+        let ret = rsgx_create_rsa_pub_key(mod_size,
+                                          exp_size,
+                                          n,
+                                          e,
+                                          self.key.borrow_mut().deref_mut());
+        match ret {
+            sgx_status_t::SGX_SUCCESS => {
+                self.mod_size.set(mod_size);
+                self.exp_size.set(exp_size);
+                self.createflag.set(true);
+                Ok(())
+            },
+            _ => Err(ret),
+        }
+    }
+
+    pub fn encrypt_sha256(&self,
+                          out_data: &mut [u8],
+                          out_len: &mut usize, 
+                          in_data: &[u8]) -> SgxError {
+
+        if self.createflag.get() == false {
+            return Err(sgx_status_t::SGX_ERROR_INVALID_STATE);
+        }
+
+        let ret = rsgx_rsa_pub_encrypt_sha256(*self.key.borrow(),
+                                              out_data,
+                                              out_len,
+                                              in_data);
+        match ret {
+            sgx_status_t::SGX_SUCCESS => {
+                Ok(())
+            },
+            _ => Err(ret),
+        }
+    }
+
+    pub fn free(&self) -> SgxError {
+
+        if self.createflag.get() == false {
+            return Ok(());
+        }
+
+        let ret = {
+            let key = *self.key.borrow();
+            if key.is_null() == true {
+                sgx_status_t::SGX_SUCCESS
+            } else {
+                rsgx_free_rsa_key(key, 
+                                  sgx_rsa_key_type_t::SGX_RSA_PUBLIC_KEY, 
+                                  self.mod_size.get(),
+                                  self.exp_size.get())
+            }
+        };
+
+        match ret {
+            sgx_status_t::SGX_SUCCESS => {
+                self.createflag.set(false);
+                *self.key.borrow_mut() = ptr::null_mut();
+                Ok(())
+            },
+            _ => Err(ret),
+        }
+    }
+}
+
+impl Default for SgxRsaPubKey {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl Drop for SgxRsaPubKey {
+    fn drop(&mut self) {
+        let _ = self.free();
+    }
+}
+
+pub fn rsgx_calculate_ecdsa_priv_key(hash_drg: &[u8],
+                                    sgx_nistp256_r_m1: &[u8],
+                                    out_key: &mut [u8]) -> SgxError {
+
+    if (hash_drg.len() == 0) || (hash_drg.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (sgx_nistp256_r_m1.len() == 0) || (sgx_nistp256_r_m1.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+    if (out_key.len() == 0) || (out_key.len() > i32::max_value() as usize) {
+        return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
+    }
+
+    let ret = unsafe {
+        sgx_calculate_ecdsa_priv_key(hash_drg.as_ptr(),
+                                     hash_drg.len() as i32,
+                                     sgx_nistp256_r_m1.as_ptr(),
+                                     sgx_nistp256_r_m1.len() as i32,
+                                     out_key.as_mut_ptr(),
+                                     out_key.len() as i32)
+    };
+
+    match ret {
+        sgx_status_t::SGX_SUCCESS => Ok(()),
+        _ => Err(ret),
+    }
+}
diff --git a/sgx_tdh/Cargo.toml b/sgx_tdh/Cargo.toml
index 52ff65d..0e507e6 100644
--- a/sgx_tdh/Cargo.toml
+++ b/sgx_tdh/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tdh"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_tkey_exchange/Cargo.toml b/sgx_tkey_exchange/Cargo.toml
index 3f96fd0..6d57a75 100644
--- a/sgx_tkey_exchange/Cargo.toml
+++ b/sgx_tkey_exchange/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tkey_exchange"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_tprotected_fs/Cargo.toml b/sgx_tprotected_fs/Cargo.toml
index b65530b..6cfeacb 100644
--- a/sgx_tprotected_fs/Cargo.toml
+++ b/sgx_tprotected_fs/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tprotected_fs"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml
index 4aa0627..62f62b4 100644
--- a/sgx_trts/Cargo.toml
+++ b/sgx_trts/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_trts"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_trts/src/c_str.rs b/sgx_trts/src/c_str.rs
index 7670769..b7a5aac 100644
--- a/sgx_trts/src/c_str.rs
+++ b/sgx_trts/src/c_str.rs
@@ -52,7 +52,7 @@
 use alloc::string::String;
 use alloc::slice;
 use alloc::rc::Rc;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 
 use alloc::str::{self, Utf8Error};
 
diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs
index 54ec898..14119bd 100644
--- a/sgx_trts/src/lib.rs
+++ b/sgx_trts/src/lib.rs
@@ -81,6 +81,7 @@
 #![feature(const_atomic_ptr_new)]
 #![feature(ascii_ctype)]
 #![feature(asm)]
+#![feature(lang_items)]
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 #![allow(overflowing_literals)]
diff --git a/sgx_trts/src/oom.rs b/sgx_trts/src/oom.rs
index 04dd16c..734f46c 100644
--- a/sgx_trts/src/oom.rs
+++ b/sgx_trts/src/oom.rs
@@ -29,7 +29,8 @@
 use trts;
 use core::sync::atomic::{AtomicPtr, Ordering};
 use core::mem;
-use alloc::heap::AllocErr;
+use core::alloc::AllocErr;
+use core::alloc::Layout;
 
 static SGX_OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(default_oom_handler as * mut ());
 
@@ -47,6 +48,11 @@
     handler(err);
 }
 
+#[lang = "oom"]
+pub extern fn rust_oom(_layout: Layout) -> ! {
+    trts::rsgx_abort()
+}
+
 /// Set a custom handler for out-of-memory conditions
 ///
 /// To avoid recursive OOM failures, it is critical that the OOM handler does
@@ -54,4 +60,4 @@
 pub fn set_panic_handler(handler: fn(AllocErr) -> !) {
 
     SGX_OOM_HANDLER.store(handler as * mut (), Ordering::SeqCst);
-}
\ No newline at end of file
+}
diff --git a/sgx_tse/Cargo.toml b/sgx_tse/Cargo.toml
index 1eb3742..0ccef33 100644
--- a/sgx_tse/Cargo.toml
+++ b/sgx_tse/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tse"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_tseal/Cargo.toml b/sgx_tseal/Cargo.toml
index 8e8108d..3f20f8e 100644
--- a/sgx_tseal/Cargo.toml
+++ b/sgx_tseal/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tseal"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_tservice/Cargo.toml b/sgx_tservice/Cargo.toml
index fd99df2..f3a016b 100644
--- a/sgx_tservice/Cargo.toml
+++ b/sgx_tservice/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tservice"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_tstd/Cargo.toml b/sgx_tstd/Cargo.toml
index 7bf1cc7..11c8622 100644
--- a/sgx_tstd/Cargo.toml
+++ b/sgx_tstd/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tstd"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 build = "build.rs"
 repository = "https://github.com/baidu/rust-sgx-sdk"
diff --git a/sgx_tstd/src/collections/hash/map.rs b/sgx_tstd/src/collections/hash/map.rs
index 1f2fcac..be5155e 100644
--- a/sgx_tstd/src/collections/hash/map.rs
+++ b/sgx_tstd/src/collections/hash/map.rs
@@ -29,22 +29,22 @@
 use self::Entry::*;
 use self::VacantEntryState::*;
 
-use alloc::heap::Heap;
-use alloc::allocator::CollectionAllocErr;
-use core::cell::Cell;
-use core::heap::Alloc;
-use core::borrow::Borrow;
-use core::cmp::max;
-use core::fmt::{self, Debug};
+use alloc::collections::CollectionAllocErr;
+use cell::Cell;
+use borrow::Borrow;
+use cmp::max;
+use fmt::{self, Debug};
 #[allow(deprecated)]
-use core::hash::{Hash, Hasher, BuildHasher, SipHasher13};
-use core::iter::{FromIterator, FusedIterator};
-use core::mem::{self, replace};
+use hash::{Hash, Hasher, BuildHasher, SipHasher13};
+use iter::{FromIterator, FusedIterator};
+use mem::{self, replace};
 use ops::{Deref, Index};
 use sys;
 
-use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash};
+use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable,
+                   SafeHash};
 use super::table::BucketState::{Empty, Full};
+use super::table::Fallibility::{Fallible, Infallible};
 
 const MIN_NONZERO_RAW_CAPACITY: usize = 32;     // must be a power of two
 
@@ -53,6 +53,7 @@
 struct DefaultResizePolicy;
 
 impl DefaultResizePolicy {
+    #[inline]
     fn new() -> DefaultResizePolicy {
         DefaultResizePolicy
     }
@@ -230,7 +231,7 @@
 // so we round that up to 128.
 //
 // At a load factor of α, the odds of finding the target bucket after exactly n
-// unsuccesful probes[1] are
+// unsuccessful probes[1] are
 //
 // Pr_α{displacement = n} =
 // (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1))
@@ -280,8 +281,155 @@
 /// the [`Eq`] trait, changes while it is in the map. This is normally only
 /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
 ///
+/// Relevant papers/articles:
+///
+/// 1. Pedro Celis. ["Robin Hood Hashing"](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf)
+/// 2. Emmanuel Goossaert. ["Robin Hood
+///    hashing"](http://codecapsule.com/2013/11/11/robin-hood-hashing/)
+/// 3. Emmanuel Goossaert. ["Robin Hood hashing: backward shift
+///    deletion"](http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/)
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// // Type inference lets us omit an explicit type signature (which
+/// // would be `HashMap<String, String>` in this example).
+/// let mut book_reviews = HashMap::new();
+///
+/// // Review some books.
+/// book_reviews.insert(
+///     "Adventures of Huckleberry Finn".to_string(),
+///     "My favorite book.".to_string(),
+/// );
+/// book_reviews.insert(
+///     "Grimms' Fairy Tales".to_string(),
+///     "Masterpiece.".to_string(),
+/// );
+/// book_reviews.insert(
+///     "Pride and Prejudice".to_string(),
+///     "Very enjoyable.".to_string(),
+/// );
+/// book_reviews.insert(
+///     "The Adventures of Sherlock Holmes".to_string(),
+///     "Eye lyked it alot.".to_string(),
+/// );
+///
+/// // Check for a specific one.
+/// // When collections store owned values (String), they can still be
+/// // queried using references (&str).
+/// if !book_reviews.contains_key("Les Misérables") {
+///     println!("We've got {} reviews, but Les Misérables ain't one.",
+///              book_reviews.len());
+/// }
+///
+/// // oops, this review has a lot of spelling mistakes, let's delete it.
+/// book_reviews.remove("The Adventures of Sherlock Holmes");
+///
+/// // Look up the values associated with some keys.
+/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
+/// for &book in &to_find {
+///     match book_reviews.get(book) {
+///         Some(review) => println!("{}: {}", book, review),
+///         None => println!("{} is unreviewed.", book)
+///     }
+/// }
+///
+/// // Iterate over everything.
+/// for (book, review) in &book_reviews {
+///     println!("{}: \"{}\"", book, review);
+/// }
+/// ```
+///
+/// `HashMap` also implements an [`Entry API`](#method.entry), which allows
+/// for more complex methods of getting, setting, updating and removing keys and
+/// their values:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// // type inference lets us omit an explicit type signature (which
+/// // would be `HashMap<&str, u8>` in this example).
+/// let mut player_stats = HashMap::new();
+///
+/// fn random_stat_buff() -> u8 {
+///     // could actually return some random value here - let's just return
+///     // some fixed value for now
+///     42
+/// }
+///
+/// // insert a key only if it doesn't already exist
+/// player_stats.entry("health").or_insert(100);
+///
+/// // insert a key using a function that provides a new value only if it
+/// // doesn't already exist
+/// player_stats.entry("defence").or_insert_with(random_stat_buff);
+///
+/// // update a key, guarding against the key possibly not being set
+/// let stat = player_stats.entry("attack").or_insert(100);
+/// *stat += random_stat_buff();
+/// ```
+///
+/// The easiest way to use `HashMap` with a custom type as key is to derive [`Eq`] and [`Hash`].
+/// We must also derive [`PartialEq`].
+///
+/// [`Eq`]: ../../std/cmp/trait.Eq.html
+/// [`Hash`]: ../../std/hash/trait.Hash.html
+/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html
+/// [`RefCell`]: ../../std/cell/struct.RefCell.html
+/// [`Cell`]: ../../std/cell/struct.Cell.html
+/// [`default`]: #method.default
+/// [`with_hasher`]: #method.with_hasher
+/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher
+/// [`fnv`]: https://crates.io/crates/fnv
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// #[derive(Hash, Eq, PartialEq, Debug)]
+/// struct Viking {
+///     name: String,
+///     country: String,
+/// }
+///
+/// impl Viking {
+///     /// Create a new Viking.
+///     fn new(name: &str, country: &str) -> Viking {
+///         Viking { name: name.to_string(), country: country.to_string() }
+///     }
+/// }
+///
+/// // Use a HashMap to store the vikings' health points.
+/// let mut vikings = HashMap::new();
+///
+/// vikings.insert(Viking::new("Einar", "Norway"), 25);
+/// vikings.insert(Viking::new("Olaf", "Denmark"), 24);
+/// vikings.insert(Viking::new("Harald", "Iceland"), 12);
+///
+/// // Use derived implementation to print the status of the vikings.
+/// for (viking, health) in &vikings {
+///     println!("{:?} has {} hp", viking, health);
+/// }
+/// ```
+///
+/// A `HashMap` with fixed list of elements can be initialized from an array:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// fn main() {
+///     let timber_resources: HashMap<&str, i32> =
+///     [("Norway", 100),
+///      ("Denmark", 50),
+///      ("Iceland", 10)]
+///      .iter().cloned().collect();
+///     // use the values stored in map
+/// }
+/// ```
 
 #[derive(Clone)]
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashMap<K, V, S = RandomState> {
     // All hashes are keyed on these values, to prevent hash collision attacks.
     hash_builder: S,
@@ -326,7 +474,7 @@
             Empty(bucket) => {
                 // Found a hole!
                 return InternalEntry::Vacant {
-                    hash: hash,
+                    hash,
                     elem: NoElem(bucket, displacement),
                 };
             }
@@ -340,7 +488,7 @@
             // We can finish the search early if we hit any bucket
             // with a lower distance to initial bucket than we've probed.
             return InternalEntry::Vacant {
-                hash: hash,
+                hash,
                 elem: NeqElem(full, probe_displacement),
             };
         }
@@ -506,7 +654,18 @@
 
 impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
     /// Creates an empty `HashMap`.
+    ///
+    /// The hash map is initially created with a capacity of 0, so it will not allocate until it
+    /// is first inserted into.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// let mut map: HashMap<&str, i32> = HashMap::new();
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> HashMap<K, V, RandomState> {
         Default::default()
     }
@@ -515,7 +674,15 @@
     ///
     /// The hash map will be able to hold at least `capacity` elements without
     /// reallocating. If `capacity` is 0, the hash map will not allocate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize) -> HashMap<K, V, RandomState> {
         HashMap::with_capacity_and_hasher(capacity, Default::default())
     }
@@ -535,10 +702,21 @@
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let s = RandomState::new();
+    /// let mut map = HashMap::with_hasher(s);
+    /// map.insert(1, 2);
+    /// ```
     #[inline]
+    //#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
         HashMap {
-            hash_builder: hash_builder,
+            hash_builder,
             resize_policy: DefaultResizePolicy::new(),
             table: RawTable::new(0),
         }
@@ -555,19 +733,43 @@
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let s = RandomState::new();
+    /// let mut map = HashMap::with_capacity_and_hasher(10, s);
+    /// map.insert(1, 2);
+    /// ```
     #[inline]
+    //#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
         let resize_policy = DefaultResizePolicy::new();
         let raw_cap = resize_policy.raw_capacity(capacity);
         HashMap {
-            hash_builder: hash_builder,
-            resize_policy: resize_policy,
+            hash_builder,
+            resize_policy,
             table: RawTable::new(raw_cap),
         }
     }
 
     /// Returns a reference to the map's [`BuildHasher`].
     ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let hasher = RandomState::new();
+    /// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher);
+    /// let hasher: &RandomState = map.hasher();
+    /// ```
+    //#[stable(feature = "hashmap_public_hasher", since = "1.9.0")]
     pub fn hasher(&self) -> &S {
         &self.hash_builder
     }
@@ -577,7 +779,15 @@
     /// This number is a lower bound; the `HashMap<K, V>` might be able to hold
     /// more, but is guaranteed to be able to hold at least this many.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// let map: HashMap<i32, i32> = HashMap::with_capacity(100);
+    /// assert!(map.capacity() >= 100);
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn capacity(&self) -> usize {
         self.resize_policy.capacity(self.raw_capacity())
     }
@@ -596,12 +806,22 @@
     ///
     /// Panics if the new allocation size overflows [`usize`].
     ///
+    /// [`usize`]: ../../std/primitive.usize.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// let mut map: HashMap<&str, i32> = HashMap::new();
+    /// map.reserve(10);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve(&mut self, additional: usize) {
-        match self.try_reserve(additional) {
+        match self.reserve_internal(additional, Infallible) {
             Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
-            Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e),
+            Err(CollectionAllocErr::AllocErr) => unreachable!(),
             Ok(()) => { /* yay */ }
-         }
+        }
     }
 
     /// Tries to reserve capacity for at least `additional` more elements to be inserted
@@ -613,18 +833,34 @@
     /// If the capacity overflows, or the allocator reports a failure, then an error
     /// is returned.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(try_reserve)]
+    /// use std::collections::HashMap;
+    /// let mut map: HashMap<&str, isize> = HashMap::new();
+    /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?");
+    /// ```
+    //#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
     pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
+        self.reserve_internal(additional, Fallible)
+    }
+
+    fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility)
+        -> Result<(), CollectionAllocErr> {
+
         let remaining = self.capacity() - self.len(); // this can't overflow
         if remaining < additional {
-            let min_cap = self.len().checked_add(additional)
+            let min_cap = self.len()
+                .checked_add(additional)
                 .ok_or(CollectionAllocErr::CapacityOverflow)?;
             let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?;
-            self.try_resize(raw_cap)?;
+            self.try_resize(raw_cap, fallibility)?;
         } else if self.table.tag() && remaining <= self.len() {
             // Probe sequence is too long and table is half full,
             // resize early to reduce probing length.
             let new_capacity = self.table.capacity() * 2;
-            self.try_resize(new_capacity)?;
+            self.try_resize(new_capacity, fallibility)?;
         }
         Ok(())
     }
@@ -636,11 +872,21 @@
     ///   2) Ensure `new_raw_cap` is a power of two or zero.
     #[inline(never)]
     #[cold]
-    fn try_resize(&mut self, new_raw_cap: usize) -> Result<(), CollectionAllocErr> {
+    fn try_resize(
+        &mut self,
+        new_raw_cap: usize,
+        fallibility: Fallibility,
+    ) -> Result<(), CollectionAllocErr> {
         assert!(self.table.size() <= new_raw_cap);
         assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0);
 
-        let mut old_table = replace(&mut self.table, RawTable::try_new(new_raw_cap)?);
+        let mut old_table = replace(
+            &mut self.table,
+            match fallibility {
+                Infallible => RawTable::new(new_raw_cap),
+                Fallible => RawTable::try_new(new_raw_cap)?,
+            }
+        );
         let old_size = old_table.size();
 
         if old_table.size() == 0 {
@@ -686,6 +932,19 @@
     /// down as much as possible while maintaining the internal rules
     /// and possibly leaving some space in accordance with the resize policy.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
+    /// map.insert(1, 2);
+    /// map.insert(3, 4);
+    /// assert!(map.capacity() >= 100);
+    /// map.shrink_to_fit();
+    /// assert!(map.capacity() >= 2);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn shrink_to_fit(&mut self) {
         let new_raw_cap = self.resize_policy.raw_capacity(self.len());
         if self.raw_capacity() != new_raw_cap {
@@ -708,6 +967,22 @@
     /// Panics if the current capacity is smaller than the supplied
     /// minimum capacity.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(shrink_to)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
+    /// map.insert(1, 2);
+    /// map.insert(3, 4);
+    /// assert!(map.capacity() >= 100);
+    /// map.shrink_to(10);
+    /// assert!(map.capacity() >= 10);
+    /// map.shrink_to(0);
+    /// assert!(map.capacity() >= 2);
+    /// ```
+    //#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
         assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity");
 
@@ -746,6 +1021,21 @@
     /// An iterator visiting all keys in arbitrary order.
     /// The iterator element type is `&'a K`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// for key in map.keys() {
+    ///     println!("{}", key);
+    /// }
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn keys(&self) -> Keys<K, V> {
         Keys { inner: self.iter() }
     }
@@ -753,6 +1043,21 @@
     /// An iterator visiting all values in arbitrary order.
     /// The iterator element type is `&'a V`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// for val in map.values() {
+    ///     println!("{}", val);
+    /// }
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn values(&self) -> Values<K, V> {
         Values { inner: self.iter() }
     }
@@ -760,6 +1065,26 @@
     /// An iterator visiting all values mutably in arbitrary order.
     /// The iterator element type is `&'a mut V`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    ///
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// for val in map.values_mut() {
+    ///     *val = *val + 10;
+    /// }
+    ///
+    /// for val in map.values() {
+    ///     println!("{}", val);
+    /// }
+    /// ```
+    //#[stable(feature = "map_values_mut", since = "1.10.0")]
     pub fn values_mut(&mut self) -> ValuesMut<K, V> {
         ValuesMut { inner: self.iter_mut() }
     }
@@ -767,6 +1092,21 @@
     /// An iterator visiting all key-value pairs in arbitrary order.
     /// The iterator element type is `(&'a K, &'a V)`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// for (key, val) in map.iter() {
+    ///     println!("key: {} val: {}", key, val);
+    /// }
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter(&self) -> Iter<K, V> {
         Iter { inner: self.table.iter() }
     }
@@ -775,12 +1115,50 @@
     /// with mutable references to the values.
     /// The iterator element type is `(&'a K, &'a mut V)`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// // Update all values
+    /// for (_, val) in map.iter_mut() {
+    ///     *val *= 2;
+    /// }
+    ///
+    /// for (key, val) in &map {
+    ///     println!("key: {} val: {}", key, val);
+    /// }
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<K, V> {
         IterMut { inner: self.table.iter_mut() }
     }
 
     /// Gets the given key's corresponding entry in the map for in-place manipulation.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut letters = HashMap::new();
+    ///
+    /// for ch in "a short treatise on fungi".chars() {
+    ///     let counter = letters.entry(ch).or_insert(0);
+    ///     *counter += 1;
+    /// }
+    ///
+    /// assert_eq!(letters[&'s'], 2);
+    /// assert_eq!(letters[&'t'], 3);
+    /// assert_eq!(letters[&'u'], 1);
+    /// assert_eq!(letters.get(&'y'), None);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn entry(&mut self, key: K) -> Entry<K, V> {
         // Gotta resize now.
         self.reserve(1);
@@ -791,13 +1169,35 @@
 
     /// Returns the number of elements in the map.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut a = HashMap::new();
+    /// assert_eq!(a.len(), 0);
+    /// a.insert(1, "a");
+    /// assert_eq!(a.len(), 1);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         self.table.size()
     }
 
     /// Returns true if the map contains no elements.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut a = HashMap::new();
+    /// assert!(a.is_empty());
+    /// a.insert(1, "a");
+    /// assert!(!a.is_empty());
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -805,7 +1205,24 @@
     /// Clears the map, returning all key-value pairs as an iterator. Keeps the
     /// allocated memory for reuse.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut a = HashMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    ///
+    /// for (k, v) in a.drain().take(1) {
+    ///     assert!(k == 1 || k == 2);
+    ///     assert!(v == "a" || v == "b");
+    /// }
+    ///
+    /// assert!(a.is_empty());
+    /// ```
     #[inline]
+    //#[stable(feature = "drain", since = "1.6.0")]
     pub fn drain(&mut self) -> Drain<K, V> {
         Drain { inner: self.table.drain() }
     }
@@ -813,6 +1230,17 @@
     /// Clears the map, removing all key-value pairs. Keeps the allocated memory
     /// for reuse.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut a = HashMap::new();
+    /// a.insert(1, "a");
+    /// a.clear();
+    /// assert!(a.is_empty());
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn clear(&mut self) {
         self.drain();
@@ -827,6 +1255,17 @@
     /// [`Eq`]: ../../std/cmp/trait.Eq.html
     /// [`Hash`]: ../../std/hash/trait.Hash.html
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert(1, "a");
+    /// assert_eq!(map.get(&1), Some(&"a"));
+    /// assert_eq!(map.get(&2), None);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
         where K: Borrow<Q>,
@@ -844,6 +1283,18 @@
     /// [`Eq`]: ../../std/cmp/trait.Eq.html
     /// [`Hash`]: ../../std/hash/trait.Hash.html
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_get_key_value)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert(1, "a");
+    /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
+    /// assert_eq!(map.get_key_value(&2), None);
+    /// ```
+    //#[unstable(feature = "map_get_key_value", issue = "49347")]
     pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
         where K: Borrow<Q>,
               Q: Hash + Eq
@@ -860,6 +1311,17 @@
     /// [`Eq`]: ../../std/cmp/trait.Eq.html
     /// [`Hash`]: ../../std/hash/trait.Hash.html
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert(1, "a");
+    /// assert_eq!(map.contains_key(&1), true);
+    /// assert_eq!(map.contains_key(&2), false);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
         where K: Borrow<Q>,
               Q: Hash + Eq
@@ -876,6 +1338,19 @@
     /// [`Eq`]: ../../std/cmp/trait.Eq.html
     /// [`Hash`]: ../../std/hash/trait.Hash.html
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert(1, "a");
+    /// if let Some(x) = map.get_mut(&1) {
+    ///     *x = "b";
+    /// }
+    /// assert_eq!(map[&1], "b");
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
         where K: Borrow<Q>,
               Q: Hash + Eq
@@ -895,6 +1370,20 @@
     /// [`None`]: ../../std/option/enum.Option.html#variant.None
     /// [module-level documentation]: index.html#insert-and-complex-keys
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// assert_eq!(map.insert(37, "a"), None);
+    /// assert_eq!(map.is_empty(), false);
+    ///
+    /// map.insert(37, "b");
+    /// assert_eq!(map.insert(37, "c"), Some("b"));
+    /// assert_eq!(map[&37], "c");
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, k: K, v: V) -> Option<V> {
         let hash = self.make_hash(&k);
         self.reserve(1);
@@ -911,6 +1400,17 @@
     /// [`Eq`]: ../../std/cmp/trait.Eq.html
     /// [`Hash`]: ../../std/hash/trait.Hash.html
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert(1, "a");
+    /// assert_eq!(map.remove(&1), Some("a"));
+    /// assert_eq!(map.remove(&1), None);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
         where K: Borrow<Q>,
               Q: Hash + Eq
@@ -925,6 +1425,22 @@
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the key type.
     ///
+    /// [`Eq`]: ../../std/cmp/trait.Eq.html
+    /// [`Hash`]: ../../std/hash/trait.Hash.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// # fn main() {
+    /// let mut map = HashMap::new();
+    /// map.insert(1, "a");
+    /// assert_eq!(map.remove_entry(&1), Some((1, "a")));
+    /// assert_eq!(map.remove(&1), None);
+    /// # }
+    /// ```
+    //#[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
     pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
         where K: Borrow<Q>,
               Q: Hash + Eq
@@ -940,6 +1456,16 @@
     ///
     /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns `false`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<i32, i32> = (0..8).map(|x|(x, x*10)).collect();
+    /// map.retain(|&k, _| k % 2 == 0);
+    /// assert_eq!(map.len(), 4);
+    /// ```
+    //#[stable(feature = "retain_hash_collection", since = "1.18.0")]
     pub fn retain<F>(&mut self, mut f: F)
         where F: FnMut(&K, &mut V) -> bool
     {
@@ -976,6 +1502,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> PartialEq for HashMap<K, V, S>
     where K: Eq + Hash,
           V: PartialEq,
@@ -990,6 +1517,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> Eq for HashMap<K, V, S>
     where K: Eq + Hash,
           V: Eq,
@@ -997,6 +1525,7 @@
 {
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> Debug for HashMap<K, V, S>
     where K: Eq + Hash + Debug,
           V: Debug,
@@ -1007,6 +1536,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> Default for HashMap<K, V, S>
     where K: Eq + Hash,
           S: BuildHasher + Default
@@ -1017,6 +1547,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
     where K: Eq + Hash + Borrow<Q>,
           Q: Eq + Hash,
@@ -1042,17 +1573,20 @@
 ///
 /// [`iter`]: struct.HashMap.html#method.iter
 /// [`HashMap`]: struct.HashMap.html
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a, V: 'a> {
     inner: table::Iter<'a, K, V>,
 }
 
-// FIXME(#19839) Remove in favor of `#[derive(Clone)]`
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Clone for Iter<'a, K, V> {
     fn clone(&self) -> Iter<'a, K, V> {
         Iter { inner: self.inner.clone() }
     }
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_list()
@@ -1068,6 +1602,7 @@
 ///
 /// [`iter_mut`]: struct.HashMap.html#method.iter_mut
 /// [`HashMap`]: struct.HashMap.html
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, K: 'a, V: 'a> {
     inner: table::IterMut<'a, K, V>,
 }
@@ -1079,6 +1614,7 @@
 ///
 /// [`into_iter`]: struct.HashMap.html#method.into_iter
 /// [`HashMap`]: struct.HashMap.html
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K, V> {
     pub(super) inner: table::IntoIter<K, V>,
 }
@@ -1090,17 +1626,20 @@
 ///
 /// [`keys`]: struct.HashMap.html#method.keys
 /// [`HashMap`]: struct.HashMap.html
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Keys<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
 }
 
-// FIXME(#19839) Remove in favor of `#[derive(Clone)]`
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Clone for Keys<'a, K, V> {
     fn clone(&self) -> Keys<'a, K, V> {
         Keys { inner: self.inner.clone() }
     }
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K: Debug, V> fmt::Debug for Keys<'a, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_list()
@@ -1116,17 +1655,20 @@
 ///
 /// [`values`]: struct.HashMap.html#method.values
 /// [`HashMap`]: struct.HashMap.html
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Values<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
 }
 
-// FIXME(#19839) Remove in favor of `#[derive(Clone)]`
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Clone for Values<'a, K, V> {
     fn clone(&self) -> Values<'a, K, V> {
         Values { inner: self.inner.clone() }
     }
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K, V: Debug> fmt::Debug for Values<'a, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_list()
@@ -1142,6 +1684,7 @@
 ///
 /// [`drain`]: struct.HashMap.html#method.drain
 /// [`HashMap`]: struct.HashMap.html
+//#[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, K: 'a, V: 'a> {
     pub(super) inner: table::Drain<'a, K, V>,
 }
@@ -1153,6 +1696,7 @@
 ///
 /// [`values_mut`]: struct.HashMap.html#method.values_mut
 /// [`HashMap`]: struct.HashMap.html
+//#[stable(feature = "map_values_mut", since = "1.10.0")]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
@@ -1183,14 +1727,14 @@
             InternalEntry::Occupied { elem } => {
                 Some(Occupied(OccupiedEntry {
                     key: Some(key),
-                    elem: elem,
+                    elem,
                 }))
             }
             InternalEntry::Vacant { hash, elem } => {
                 Some(Vacant(VacantEntry {
-                    hash: hash,
-                    key: key,
-                    elem: elem,
+                    hash,
+                    key,
+                    elem,
                 }))
             }
             InternalEntry::TableIsEmpty => None,
@@ -1204,14 +1748,20 @@
 ///
 /// [`HashMap`]: struct.HashMap.html
 /// [`entry`]: struct.HashMap.html#method.entry
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub enum Entry<'a, K: 'a, V: 'a> {
     /// An occupied entry.
-    Occupied(OccupiedEntry<'a, K, V>),
+    //#[stable(feature = "rust1", since = "1.0.0")]
+    Occupied(//#[stable(feature = "rust1", since = "1.0.0")]
+             OccupiedEntry<'a, K, V>),
 
     /// A vacant entry.
-    Vacant(VacantEntry<'a, K, V>),
+    //#[stable(feature = "rust1", since = "1.0.0")]
+    Vacant(//#[stable(feature = "rust1", since = "1.0.0")]
+           VacantEntry<'a, K, V>),
 }
 
+//#[stable(feature= "debug_hash_map", since = "1.12.0")]
 impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
@@ -1233,11 +1783,13 @@
 /// It is part of the [`Entry`] enum.
 ///
 /// [`Entry`]: enum.Entry.html
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
     key: Option<K>,
     elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
 }
 
+//#[stable(feature= "debug_hash_map", since = "1.12.0")]
 impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_struct("OccupiedEntry")
@@ -1251,12 +1803,14 @@
 /// It is part of the [`Entry`] enum.
 ///
 /// [`Entry`]: enum.Entry.html
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct VacantEntry<'a, K: 'a, V: 'a> {
     hash: SafeHash,
     key: K,
     elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
 }
 
+//#[stable(feature= "debug_hash_map", since = "1.12.0")]
 impl<'a, K: 'a + Debug, V: 'a> Debug for VacantEntry<'a, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("VacantEntry")
@@ -1274,6 +1828,7 @@
     NoElem(EmptyBucket<K, V, M>, usize),
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S>
     where K: Eq + Hash,
           S: BuildHasher
@@ -1286,6 +1841,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S>
     where K: Eq + Hash,
           S: BuildHasher
@@ -1298,6 +1854,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> IntoIterator for HashMap<K, V, S>
     where K: Eq + Hash,
           S: BuildHasher
@@ -1309,11 +1866,25 @@
     /// pair out of the map in arbitrary order. The map cannot be used after
     /// calling this.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// // Not possible with .iter()
+    /// let vec: Vec<(&str, i32)> = map.into_iter().collect();
+    /// ```
     fn into_iter(self) -> IntoIter<K, V> {
         IntoIter { inner: self.table.into_iter() }
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Iter<'a, K, V> {
     type Item = (&'a K, &'a V);
 
@@ -1326,7 +1897,7 @@
         self.inner.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
     #[inline]
     fn len(&self) -> usize {
@@ -1334,8 +1905,10 @@
     }
 }
 
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for IterMut<'a, K, V> {
     type Item = (&'a K, &'a mut V);
 
@@ -1348,16 +1921,17 @@
         self.inner.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K, V> fmt::Debug for IterMut<'a, K, V>
     where K: fmt::Debug,
           V: fmt::Debug,
@@ -1369,7 +1943,7 @@
     }
 }
 
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V> Iterator for IntoIter<K, V> {
     type Item = (K, V);
 
@@ -1382,16 +1956,17 @@
         self.inner.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V> ExactSizeIterator for IntoIter<K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<K, V> FusedIterator for IntoIter<K, V> {}
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<K: Debug, V: Debug> fmt::Debug for IntoIter<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_list()
@@ -1400,6 +1975,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Keys<'a, K, V> {
     type Item = &'a K;
 
@@ -1412,17 +1988,17 @@
         self.inner.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
 
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Values<'a, K, V> {
     type Item = &'a V;
 
@@ -1435,16 +2011,17 @@
         self.inner.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
 
+//#[stable(feature = "map_values_mut", since = "1.10.0")]
 impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
     type Item = &'a mut V;
 
@@ -1457,16 +2034,17 @@
         self.inner.size_hint()
     }
 }
-
+//#[stable(feature = "map_values_mut", since = "1.10.0")]
 impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K, V> fmt::Debug for ValuesMut<'a, K, V>
     where K: fmt::Debug,
           V: fmt::Debug,
@@ -1478,6 +2056,7 @@
     }
 }
 
+//#[stable(feature = "drain", since = "1.6.0")]
 impl<'a, K, V> Iterator for Drain<'a, K, V> {
     type Item = (K, V);
 
@@ -1490,16 +2069,17 @@
         self.inner.size_hint()
     }
 }
-
+//#[stable(feature = "drain", since = "1.6.0")]
 impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Drain<'a, K, V> {}
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K, V> fmt::Debug for Drain<'a, K, V>
     where K: fmt::Debug,
           V: fmt::Debug,
@@ -1512,10 +2092,23 @@
 }
 
 impl<'a, K, V> Entry<'a, K, V> {
-
+    //#[stable(feature = "rust1", since = "1.0.0")]
     /// Ensures a value is in the entry by inserting the default if empty, and returns
     /// a mutable reference to the value in the entry.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    ///
+    /// *map.entry("poneyland").or_insert(12) += 10;
+    /// assert_eq!(map["poneyland"], 22);
+    /// ```
     pub fn or_insert(self, default: V) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -1523,10 +2116,22 @@
         }
     }
 
-
+    //#[stable(feature = "rust1", since = "1.0.0")]
     /// Ensures a value is in the entry by inserting the result of the default function if empty,
     /// and returns a mutable reference to the value in the entry.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, String> = HashMap::new();
+    /// let s = "hoho".to_string();
+    ///
+    /// map.entry("poneyland").or_insert_with(|| s);
+    ///
+    /// assert_eq!(map["poneyland"], "hoho".to_string());
+    /// ```
     pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -1536,6 +2141,15 @@
 
     /// Returns a reference to this entry's key.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
+    //#[stable(feature = "map_entry_keys", since = "1.10.0")]
     pub fn key(&self) -> &K {
         match *self {
             Occupied(ref entry) => entry.key(),
@@ -1546,8 +2160,26 @@
     /// Provides in-place mutable access to an occupied entry before any
     /// potential inserts into the map.
     ///
-    pub fn and_modify<F>(self, mut f: F) -> Self
-        where F: FnMut(&mut V)
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    ///
+    /// map.entry("poneyland")
+    ///    .and_modify(|e| { *e += 1 })
+    ///    .or_insert(42);
+    /// assert_eq!(map["poneyland"], 42);
+    ///
+    /// map.entry("poneyland")
+    ///    .and_modify(|e| { *e += 1 })
+    ///    .or_insert(42);
+    /// assert_eq!(map["poneyland"], 43);
+    /// ```
+    //#[stable(feature = "entry_and_modify", since = "1.26.0")]
+    pub fn and_modify<F>(self, f: F) -> Self
+        where F: FnOnce(&mut V)
     {
         match self {
             Occupied(mut entry) => {
@@ -1557,12 +2189,26 @@
             Vacant(entry) => Vacant(entry),
         }
     }
+
 }
 
 impl<'a, K, V: Default> Entry<'a, K, V> {
+    //#[stable(feature = "entry_or_default", since = "1.28.0")]
     /// Ensures a value is in the entry by inserting the default value if empty,
     /// and returns a mutable reference to the value in the entry.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// # fn main() {
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, Option<u32>> = HashMap::new();
+    /// map.entry("poneyland").or_default();
+    ///
+    /// assert_eq!(map["poneyland"], None);
+    /// # }
+    /// ```
     pub fn or_default(self) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -1574,12 +2220,39 @@
 impl<'a, K, V> OccupiedEntry<'a, K, V> {
     /// Gets a reference to the key in the entry.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
+    //#[stable(feature = "map_entry_keys", since = "1.10.0")]
     pub fn key(&self) -> &K {
         self.elem.read().0
     }
 
     /// Take the ownership of the key and value from the map.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     // We delete the entry from the map.
+    ///     o.remove_entry();
+    /// }
+    ///
+    /// assert_eq!(map.contains_key("poneyland"), false);
+    /// ```
+    //#[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
     pub fn remove_entry(self) -> (K, V) {
         let (k, v, _) = pop_internal(self.elem);
         (k, v)
@@ -1587,12 +2260,52 @@
 
     /// Gets a reference to the value in the entry.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     assert_eq!(o.get(), &12);
+    /// }
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn get(&self) -> &V {
         self.elem.read().1
     }
 
     /// Gets a mutable reference to the value in the entry.
     ///
+    /// If you need a reference to the `OccupiedEntry` which may outlive the
+    /// destruction of the `Entry` value, see [`into_mut`].
+    ///
+    /// [`into_mut`]: #method.into_mut
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+    ///     *o.get_mut() += 10;
+    ///     assert_eq!(*o.get(), 22);
+    ///
+    ///     // We can use the same Entry multiple times.
+    ///     *o.get_mut() += 2;
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 24);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut(&mut self) -> &mut V {
         self.elem.read_mut().1
     }
@@ -1600,12 +2313,49 @@
     /// Converts the OccupiedEntry into a mutable reference to the value in the entry
     /// with a lifetime bound to the map itself.
     ///
+    /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
+    ///
+    /// [`get_mut`]: #method.get_mut
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     *o.into_mut() += 10;
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 22);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_mut(self) -> &'a mut V {
         self.elem.into_mut_refs().1
     }
 
     /// Sets the value of the entry, and returns the entry's old value.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+    ///     assert_eq!(o.insert(15), 12);
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 15);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, mut value: V) -> V {
         let old_value = self.get_mut();
         mem::swap(&mut value, old_value);
@@ -1614,6 +2364,22 @@
 
     /// Takes the value out of the entry, and returns it.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     assert_eq!(o.remove(), 12);
+    /// }
+    ///
+    /// assert_eq!(map.contains_key("poneyland"), false);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove(self) -> V {
         pop_internal(self.elem).1
     }
@@ -1628,6 +2394,25 @@
     /// Replaces the entry, returning the old key and value. The new key in the hash map will be
     /// the key used to create this entry.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_entry_replace)]
+    /// use std::collections::hash_map::{Entry, HashMap};
+    /// use std::rc::Rc;
+    ///
+    /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
+    /// map.insert(Rc::new("Stringthing".to_string()), 15);
+    ///
+    /// let my_key = Rc::new("Stringthing".to_string());
+    ///
+    /// if let Entry::Occupied(entry) = map.entry(my_key) {
+    ///     // Also replace the key with a handle to our other key.
+    ///     let (old_key, old_value): (Rc<String>, u32) = entry.replace_entry(16);
+    /// }
+    ///
+    /// ```
+    //#[unstable(feature = "map_entry_replace", issue = "44286")]
     pub fn replace_entry(mut self, value: V) -> (K, V) {
         let (old_key, old_value) = self.elem.read_mut();
 
@@ -1639,6 +2424,30 @@
 
     /// Replaces the key in the hash map with the key used to create this entry.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_entry_replace)]
+    /// use std::collections::hash_map::{Entry, HashMap};
+    /// use std::rc::Rc;
+    ///
+    /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
+    /// let mut known_strings: Vec<Rc<String>> = Vec::new();
+    ///
+    /// // Initialise known strings, run program, etc.
+    ///
+    /// reclaim_memory(&mut map, &known_strings);
+    ///
+    /// fn reclaim_memory(map: &mut HashMap<Rc<String>, u32>, known_strings: &[Rc<String>] ) {
+    ///     for s in known_strings {
+    ///         if let Entry::Occupied(entry) = map.entry(s.clone()) {
+    ///             // Replaces the entry's key with our version of it in `known_strings`.
+    ///             entry.replace_key();
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    //#[unstable(feature = "map_entry_replace", issue = "44286")]
     pub fn replace_key(mut self) -> K {
         let (old_key, _) = self.elem.read_mut();
         mem::replace(old_key, self.key.unwrap())
@@ -1649,12 +2458,34 @@
     /// Gets a reference to the key that would be used when inserting a value
     /// through the `VacantEntry`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
+    //#[stable(feature = "map_entry_keys", since = "1.10.0")]
     pub fn key(&self) -> &K {
         &self.key
     }
 
     /// Take ownership of the key.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    ///
+    /// if let Entry::Vacant(v) = map.entry("poneyland") {
+    ///     v.into_key();
+    /// }
+    /// ```
+    //#[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
     pub fn into_key(self) -> K {
         self.key
     }
@@ -1662,6 +2493,20 @@
     /// Sets the value of the entry with the VacantEntry's key,
     /// and returns a mutable reference to it.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    ///
+    /// if let Entry::Vacant(o) = map.entry("poneyland") {
+    ///     o.insert(37);
+    /// }
+    /// assert_eq!(map["poneyland"], 37);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(self, value: V) -> &'a mut V {
         let b = match self.elem {
             NeqElem(mut bucket, disp) => {
@@ -1681,6 +2526,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S>
     where K: Eq + Hash,
           S: BuildHasher + Default
@@ -1692,6 +2538,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S>
     where K: Eq + Hash,
           S: BuildHasher
@@ -1714,6 +2561,7 @@
     }
 }
 
+//#[stable(feature = "hash_extend_copy", since = "1.4.0")]
 impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
     where K: Eq + Hash + Copy,
           V: Copy,
@@ -1733,7 +2581,18 @@
 /// [`HashMap`]: struct.HashMap.html
 /// [`Hasher`]: ../../hash/trait.Hasher.html
 ///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashMap;
+/// use std::collections::hash_map::RandomState;
+///
+/// let s = RandomState::new();
+/// let mut map = HashMap::with_hasher(s);
+/// map.insert(1, 2);
+/// ```
 #[derive(Clone)]
+//#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
 pub struct RandomState {
     k0: u64,
     k1: u64,
@@ -1742,9 +2601,17 @@
 impl RandomState {
     /// Constructs a new `RandomState` that is initialized with random keys.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let s = RandomState::new();
+    /// ```
     #[inline]
     #[allow(deprecated)]
     // rand
+    //#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn new() -> RandomState {
         // Historically this function did not cache keys from the OS and instead
         // simply always called `rand::thread_rng().gen()` twice. In #31356 it
@@ -1769,6 +2636,7 @@
     }
 }
 
+//#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
 impl BuildHasher for RandomState {
     type Hasher = DefaultHasher;
     #[inline]
@@ -1785,6 +2653,7 @@
 ///
 /// [`RandomState`]: struct.RandomState.html
 /// [`Hasher`]: ../../hash/trait.Hasher.html
+//#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
 #[allow(deprecated)]
 #[derive(Clone, Debug)]
 pub struct DefaultHasher(SipHasher13);
@@ -1795,12 +2664,14 @@
     /// This hasher is not guaranteed to be the same as all other
     /// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
     /// instances created through `new` or `default`.
+    //#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
     #[allow(deprecated)]
     pub fn new() -> DefaultHasher {
         DefaultHasher(SipHasher13::new_with_keys(0, 0))
     }
 }
 
+//#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
 impl Default for DefaultHasher {
     /// Creates a new `DefaultHasher` using [`new`]. See its documentation for more.
     ///
@@ -1810,6 +2681,7 @@
     }
 }
 
+//#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
 impl Hasher for DefaultHasher {
     #[inline]
     fn write(&mut self, msg: &[u8]) {
@@ -1822,6 +2694,7 @@
     }
 }
 
+//#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
 impl Default for RandomState {
     /// Constructs a new `RandomState`.
     #[inline]
@@ -1830,6 +2703,7 @@
     }
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl fmt::Debug for RandomState {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.pad("RandomState { .. }")
@@ -1906,3 +2780,925 @@
         d
     }
 }
+
+#[cfg(test)]
+mod test_map {
+    use super::HashMap;
+    use super::Entry::{Occupied, Vacant};
+    use super::RandomState;
+    use cell::RefCell;
+    use rand::{thread_rng, Rng};
+    use realstd::collections::CollectionAllocErr::*;
+    use realstd::mem::size_of;
+    use realstd::usize;
+
+    #[test]
+    fn test_zero_capacities() {
+        type HM = HashMap<i32, i32>;
+
+        let m = HM::new();
+        assert_eq!(m.capacity(), 0);
+
+        let m = HM::default();
+        assert_eq!(m.capacity(), 0);
+
+        let m = HM::with_hasher(RandomState::new());
+        assert_eq!(m.capacity(), 0);
+
+        let m = HM::with_capacity(0);
+        assert_eq!(m.capacity(), 0);
+
+        let m = HM::with_capacity_and_hasher(0, RandomState::new());
+        assert_eq!(m.capacity(), 0);
+
+        let mut m = HM::new();
+        m.insert(1, 1);
+        m.insert(2, 2);
+        m.remove(&1);
+        m.remove(&2);
+        m.shrink_to_fit();
+        assert_eq!(m.capacity(), 0);
+
+        let mut m = HM::new();
+        m.reserve(0);
+        assert_eq!(m.capacity(), 0);
+    }
+
+    #[test]
+    fn test_create_capacity_zero() {
+        let mut m = HashMap::with_capacity(0);
+
+        assert!(m.insert(1, 1).is_none());
+
+        assert!(m.contains_key(&1));
+        assert!(!m.contains_key(&0));
+    }
+
+    #[test]
+    fn test_insert() {
+        let mut m = HashMap::new();
+        assert_eq!(m.len(), 0);
+        assert!(m.insert(1, 2).is_none());
+        assert_eq!(m.len(), 1);
+        assert!(m.insert(2, 4).is_none());
+        assert_eq!(m.len(), 2);
+        assert_eq!(*m.get(&1).unwrap(), 2);
+        assert_eq!(*m.get(&2).unwrap(), 4);
+    }
+
+    #[test]
+    fn test_clone() {
+        let mut m = HashMap::new();
+        assert_eq!(m.len(), 0);
+        assert!(m.insert(1, 2).is_none());
+        assert_eq!(m.len(), 1);
+        assert!(m.insert(2, 4).is_none());
+        assert_eq!(m.len(), 2);
+        let m2 = m.clone();
+        assert_eq!(*m2.get(&1).unwrap(), 2);
+        assert_eq!(*m2.get(&2).unwrap(), 4);
+        assert_eq!(m2.len(), 2);
+    }
+
+    thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) }
+
+    #[derive(Hash, PartialEq, Eq)]
+    struct Droppable {
+        k: usize,
+    }
+
+    impl Droppable {
+        fn new(k: usize) -> Droppable {
+            DROP_VECTOR.with(|slot| {
+                slot.borrow_mut()[k] += 1;
+            });
+
+            Droppable { k: k }
+        }
+    }
+
+    impl Drop for Droppable {
+        fn drop(&mut self) {
+            DROP_VECTOR.with(|slot| {
+                slot.borrow_mut()[self.k] -= 1;
+            });
+        }
+    }
+
+    impl Clone for Droppable {
+        fn clone(&self) -> Droppable {
+            Droppable::new(self.k)
+        }
+    }
+
+    #[test]
+    fn test_drops() {
+        DROP_VECTOR.with(|slot| {
+            *slot.borrow_mut() = vec![0; 200];
+        });
+
+        {
+            let mut m = HashMap::new();
+
+            DROP_VECTOR.with(|v| {
+                for i in 0..200 {
+                    assert_eq!(v.borrow()[i], 0);
+                }
+            });
+
+            for i in 0..100 {
+                let d1 = Droppable::new(i);
+                let d2 = Droppable::new(i + 100);
+                m.insert(d1, d2);
+            }
+
+            DROP_VECTOR.with(|v| {
+                for i in 0..200 {
+                    assert_eq!(v.borrow()[i], 1);
+                }
+            });
+
+            for i in 0..50 {
+                let k = Droppable::new(i);
+                let v = m.remove(&k);
+
+                assert!(v.is_some());
+
+                DROP_VECTOR.with(|v| {
+                    assert_eq!(v.borrow()[i], 1);
+                    assert_eq!(v.borrow()[i+100], 1);
+                });
+            }
+
+            DROP_VECTOR.with(|v| {
+                for i in 0..50 {
+                    assert_eq!(v.borrow()[i], 0);
+                    assert_eq!(v.borrow()[i+100], 0);
+                }
+
+                for i in 50..100 {
+                    assert_eq!(v.borrow()[i], 1);
+                    assert_eq!(v.borrow()[i+100], 1);
+                }
+            });
+        }
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..200 {
+                assert_eq!(v.borrow()[i], 0);
+            }
+        });
+    }
+
+    #[test]
+    fn test_into_iter_drops() {
+        DROP_VECTOR.with(|v| {
+            *v.borrow_mut() = vec![0; 200];
+        });
+
+        let hm = {
+            let mut hm = HashMap::new();
+
+            DROP_VECTOR.with(|v| {
+                for i in 0..200 {
+                    assert_eq!(v.borrow()[i], 0);
+                }
+            });
+
+            for i in 0..100 {
+                let d1 = Droppable::new(i);
+                let d2 = Droppable::new(i + 100);
+                hm.insert(d1, d2);
+            }
+
+            DROP_VECTOR.with(|v| {
+                for i in 0..200 {
+                    assert_eq!(v.borrow()[i], 1);
+                }
+            });
+
+            hm
+        };
+
+        // By the way, ensure that cloning doesn't screw up the dropping.
+        drop(hm.clone());
+
+        {
+            let mut half = hm.into_iter().take(50);
+
+            DROP_VECTOR.with(|v| {
+                for i in 0..200 {
+                    assert_eq!(v.borrow()[i], 1);
+                }
+            });
+
+            for _ in half.by_ref() {}
+
+            DROP_VECTOR.with(|v| {
+                let nk = (0..100)
+                    .filter(|&i| v.borrow()[i] == 1)
+                    .count();
+
+                let nv = (0..100)
+                    .filter(|&i| v.borrow()[i + 100] == 1)
+                    .count();
+
+                assert_eq!(nk, 50);
+                assert_eq!(nv, 50);
+            });
+        };
+
+        DROP_VECTOR.with(|v| {
+            for i in 0..200 {
+                assert_eq!(v.borrow()[i], 0);
+            }
+        });
+    }
+
+    #[test]
+    fn test_empty_remove() {
+        let mut m: HashMap<i32, bool> = HashMap::new();
+        assert_eq!(m.remove(&0), None);
+    }
+
+    #[test]
+    fn test_empty_entry() {
+        let mut m: HashMap<i32, bool> = HashMap::new();
+        match m.entry(0) {
+            Occupied(_) => panic!(),
+            Vacant(_) => {}
+        }
+        assert!(*m.entry(0).or_insert(true));
+        assert_eq!(m.len(), 1);
+    }
+
+    #[test]
+    fn test_empty_iter() {
+        let mut m: HashMap<i32, bool> = HashMap::new();
+        assert_eq!(m.drain().next(), None);
+        assert_eq!(m.keys().next(), None);
+        assert_eq!(m.values().next(), None);
+        assert_eq!(m.values_mut().next(), None);
+        assert_eq!(m.iter().next(), None);
+        assert_eq!(m.iter_mut().next(), None);
+        assert_eq!(m.len(), 0);
+        assert!(m.is_empty());
+        assert_eq!(m.into_iter().next(), None);
+    }
+
+    #[test]
+    fn test_lots_of_insertions() {
+        let mut m = HashMap::new();
+
+        // Try this a few times to make sure we never screw up the hashmap's
+        // internal state.
+        for _ in 0..10 {
+            assert!(m.is_empty());
+
+            for i in 1..1001 {
+                assert!(m.insert(i, i).is_none());
+
+                for j in 1..i + 1 {
+                    let r = m.get(&j);
+                    assert_eq!(r, Some(&j));
+                }
+
+                for j in i + 1..1001 {
+                    let r = m.get(&j);
+                    assert_eq!(r, None);
+                }
+            }
+
+            for i in 1001..2001 {
+                assert!(!m.contains_key(&i));
+            }
+
+            // remove forwards
+            for i in 1..1001 {
+                assert!(m.remove(&i).is_some());
+
+                for j in 1..i + 1 {
+                    assert!(!m.contains_key(&j));
+                }
+
+                for j in i + 1..1001 {
+                    assert!(m.contains_key(&j));
+                }
+            }
+
+            for i in 1..1001 {
+                assert!(!m.contains_key(&i));
+            }
+
+            for i in 1..1001 {
+                assert!(m.insert(i, i).is_none());
+            }
+
+            // remove backwards
+            for i in (1..1001).rev() {
+                assert!(m.remove(&i).is_some());
+
+                for j in i..1001 {
+                    assert!(!m.contains_key(&j));
+                }
+
+                for j in 1..i {
+                    assert!(m.contains_key(&j));
+                }
+            }
+        }
+    }
+
+    #[test]
+    fn test_find_mut() {
+        let mut m = HashMap::new();
+        assert!(m.insert(1, 12).is_none());
+        assert!(m.insert(2, 8).is_none());
+        assert!(m.insert(5, 14).is_none());
+        let new = 100;
+        match m.get_mut(&5) {
+            None => panic!(),
+            Some(x) => *x = new,
+        }
+        assert_eq!(m.get(&5), Some(&new));
+    }
+
+    #[test]
+    fn test_insert_overwrite() {
+        let mut m = HashMap::new();
+        assert!(m.insert(1, 2).is_none());
+        assert_eq!(*m.get(&1).unwrap(), 2);
+        assert!(!m.insert(1, 3).is_none());
+        assert_eq!(*m.get(&1).unwrap(), 3);
+    }
+
+    #[test]
+    fn test_insert_conflicts() {
+        let mut m = HashMap::with_capacity(4);
+        assert!(m.insert(1, 2).is_none());
+        assert!(m.insert(5, 3).is_none());
+        assert!(m.insert(9, 4).is_none());
+        assert_eq!(*m.get(&9).unwrap(), 4);
+        assert_eq!(*m.get(&5).unwrap(), 3);
+        assert_eq!(*m.get(&1).unwrap(), 2);
+    }
+
+    #[test]
+    fn test_conflict_remove() {
+        let mut m = HashMap::with_capacity(4);
+        assert!(m.insert(1, 2).is_none());
+        assert_eq!(*m.get(&1).unwrap(), 2);
+        assert!(m.insert(5, 3).is_none());
+        assert_eq!(*m.get(&1).unwrap(), 2);
+        assert_eq!(*m.get(&5).unwrap(), 3);
+        assert!(m.insert(9, 4).is_none());
+        assert_eq!(*m.get(&1).unwrap(), 2);
+        assert_eq!(*m.get(&5).unwrap(), 3);
+        assert_eq!(*m.get(&9).unwrap(), 4);
+        assert!(m.remove(&1).is_some());
+        assert_eq!(*m.get(&9).unwrap(), 4);
+        assert_eq!(*m.get(&5).unwrap(), 3);
+    }
+
+    #[test]
+    fn test_is_empty() {
+        let mut m = HashMap::with_capacity(4);
+        assert!(m.insert(1, 2).is_none());
+        assert!(!m.is_empty());
+        assert!(m.remove(&1).is_some());
+        assert!(m.is_empty());
+    }
+
+    #[test]
+    fn test_remove() {
+        let mut m = HashMap::new();
+        m.insert(1, 2);
+        assert_eq!(m.remove(&1), Some(2));
+        assert_eq!(m.remove(&1), None);
+    }
+
+    #[test]
+    fn test_remove_entry() {
+        let mut m = HashMap::new();
+        m.insert(1, 2);
+        assert_eq!(m.remove_entry(&1), Some((1, 2)));
+        assert_eq!(m.remove(&1), None);
+    }
+
+    #[test]
+    fn test_iterate() {
+        let mut m = HashMap::with_capacity(4);
+        for i in 0..32 {
+            assert!(m.insert(i, i*2).is_none());
+        }
+        assert_eq!(m.len(), 32);
+
+        let mut observed: u32 = 0;
+
+        for (k, v) in &m {
+            assert_eq!(*v, *k * 2);
+            observed |= 1 << *k;
+        }
+        assert_eq!(observed, 0xFFFF_FFFF);
+    }
+
+    #[test]
+    fn test_keys() {
+        let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+        let map: HashMap<_, _> = vec.into_iter().collect();
+        let keys: Vec<_> = map.keys().cloned().collect();
+        assert_eq!(keys.len(), 3);
+        assert!(keys.contains(&1));
+        assert!(keys.contains(&2));
+        assert!(keys.contains(&3));
+    }
+
+    #[test]
+    fn test_values() {
+        let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+        let map: HashMap<_, _> = vec.into_iter().collect();
+        let values: Vec<_> = map.values().cloned().collect();
+        assert_eq!(values.len(), 3);
+        assert!(values.contains(&'a'));
+        assert!(values.contains(&'b'));
+        assert!(values.contains(&'c'));
+    }
+
+    #[test]
+    fn test_values_mut() {
+        let vec = vec![(1, 1), (2, 2), (3, 3)];
+        let mut map: HashMap<_, _> = vec.into_iter().collect();
+        for value in map.values_mut() {
+            *value = (*value) * 2
+        }
+        let values: Vec<_> = map.values().cloned().collect();
+        assert_eq!(values.len(), 3);
+        assert!(values.contains(&2));
+        assert!(values.contains(&4));
+        assert!(values.contains(&6));
+    }
+
+    #[test]
+    fn test_find() {
+        let mut m = HashMap::new();
+        assert!(m.get(&1).is_none());
+        m.insert(1, 2);
+        match m.get(&1) {
+            None => panic!(),
+            Some(v) => assert_eq!(*v, 2),
+        }
+    }
+
+    #[test]
+    fn test_eq() {
+        let mut m1 = HashMap::new();
+        m1.insert(1, 2);
+        m1.insert(2, 3);
+        m1.insert(3, 4);
+
+        let mut m2 = HashMap::new();
+        m2.insert(1, 2);
+        m2.insert(2, 3);
+
+        assert!(m1 != m2);
+
+        m2.insert(3, 4);
+
+        assert_eq!(m1, m2);
+    }
+
+    #[test]
+    fn test_show() {
+        let mut map = HashMap::new();
+        let empty: HashMap<i32, i32> = HashMap::new();
+
+        map.insert(1, 2);
+        map.insert(3, 4);
+
+        let map_str = format!("{:?}", map);
+
+        assert!(map_str == "{1: 2, 3: 4}" ||
+                map_str == "{3: 4, 1: 2}");
+        assert_eq!(format!("{:?}", empty), "{}");
+    }
+
+    #[test]
+    fn test_expand() {
+        let mut m = HashMap::new();
+
+        assert_eq!(m.len(), 0);
+        assert!(m.is_empty());
+
+        let mut i = 0;
+        let old_raw_cap = m.raw_capacity();
+        while old_raw_cap == m.raw_capacity() {
+            m.insert(i, i);
+            i += 1;
+        }
+
+        assert_eq!(m.len(), i);
+        assert!(!m.is_empty());
+    }
+
+    #[test]
+    fn test_behavior_resize_policy() {
+        let mut m = HashMap::new();
+
+        assert_eq!(m.len(), 0);
+        assert_eq!(m.raw_capacity(), 0);
+        assert!(m.is_empty());
+
+        m.insert(0, 0);
+        m.remove(&0);
+        assert!(m.is_empty());
+        let initial_raw_cap = m.raw_capacity();
+        m.reserve(initial_raw_cap);
+        let raw_cap = m.raw_capacity();
+
+        assert_eq!(raw_cap, initial_raw_cap * 2);
+
+        let mut i = 0;
+        for _ in 0..raw_cap * 3 / 4 {
+            m.insert(i, i);
+            i += 1;
+        }
+        // three quarters full
+
+        assert_eq!(m.len(), i);
+        assert_eq!(m.raw_capacity(), raw_cap);
+
+        for _ in 0..raw_cap / 4 {
+            m.insert(i, i);
+            i += 1;
+        }
+        // half full
+
+        let new_raw_cap = m.raw_capacity();
+        assert_eq!(new_raw_cap, raw_cap * 2);
+
+        for _ in 0..raw_cap / 2 - 1 {
+            i -= 1;
+            m.remove(&i);
+            assert_eq!(m.raw_capacity(), new_raw_cap);
+        }
+        // A little more than one quarter full.
+        m.shrink_to_fit();
+        assert_eq!(m.raw_capacity(), raw_cap);
+        // again, a little more than half full
+        for _ in 0..raw_cap / 2 - 1 {
+            i -= 1;
+            m.remove(&i);
+        }
+        m.shrink_to_fit();
+
+        assert_eq!(m.len(), i);
+        assert!(!m.is_empty());
+        assert_eq!(m.raw_capacity(), initial_raw_cap);
+    }
+
+    #[test]
+    fn test_reserve_shrink_to_fit() {
+        let mut m = HashMap::new();
+        m.insert(0, 0);
+        m.remove(&0);
+        assert!(m.capacity() >= m.len());
+        for i in 0..128 {
+            m.insert(i, i);
+        }
+        m.reserve(256);
+
+        let usable_cap = m.capacity();
+        for i in 128..(128 + 256) {
+            m.insert(i, i);
+            assert_eq!(m.capacity(), usable_cap);
+        }
+
+        for i in 100..(128 + 256) {
+            assert_eq!(m.remove(&i), Some(i));
+        }
+        m.shrink_to_fit();
+
+        assert_eq!(m.len(), 100);
+        assert!(!m.is_empty());
+        assert!(m.capacity() >= m.len());
+
+        for i in 0..100 {
+            assert_eq!(m.remove(&i), Some(i));
+        }
+        m.shrink_to_fit();
+        m.insert(0, 0);
+
+        assert_eq!(m.len(), 1);
+        assert!(m.capacity() >= m.len());
+        assert_eq!(m.remove(&0), Some(0));
+    }
+
+    #[test]
+    fn test_from_iter() {
+        let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+        let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+        for &(k, v) in &xs {
+            assert_eq!(map.get(&k), Some(&v));
+        }
+    }
+
+    #[test]
+    fn test_size_hint() {
+        let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+        let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+        let mut iter = map.iter();
+
+        for _ in iter.by_ref().take(3) {}
+
+        assert_eq!(iter.size_hint(), (3, Some(3)));
+    }
+
+    #[test]
+    fn test_iter_len() {
+        let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+        let map: HashMap<_, _> = xs.iter().cloned().collect();
+
+        let mut iter = map.iter();
+
+        for _ in iter.by_ref().take(3) {}
+
+        assert_eq!(iter.len(), 3);
+    }
+
+    #[test]
+    fn test_mut_size_hint() {
+        let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+        let mut iter = map.iter_mut();
+
+        for _ in iter.by_ref().take(3) {}
+
+        assert_eq!(iter.size_hint(), (3, Some(3)));
+    }
+
+    #[test]
+    fn test_iter_mut_len() {
+        let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
+
+        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+        let mut iter = map.iter_mut();
+
+        for _ in iter.by_ref().take(3) {}
+
+        assert_eq!(iter.len(), 3);
+    }
+
+    #[test]
+    fn test_index() {
+        let mut map = HashMap::new();
+
+        map.insert(1, 2);
+        map.insert(2, 1);
+        map.insert(3, 4);
+
+        assert_eq!(map[&2], 1);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_index_nonexistent() {
+        let mut map = HashMap::new();
+
+        map.insert(1, 2);
+        map.insert(2, 1);
+        map.insert(3, 4);
+
+        map[&4];
+    }
+
+    #[test]
+    fn test_entry() {
+        let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+
+        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+        // Existing key (insert)
+        match map.entry(1) {
+            Vacant(_) => unreachable!(),
+            Occupied(mut view) => {
+                assert_eq!(view.get(), &10);
+                assert_eq!(view.insert(100), 10);
+            }
+        }
+        assert_eq!(map.get(&1).unwrap(), &100);
+        assert_eq!(map.len(), 6);
+
+
+        // Existing key (update)
+        match map.entry(2) {
+            Vacant(_) => unreachable!(),
+            Occupied(mut view) => {
+                let v = view.get_mut();
+                let new_v = (*v) * 10;
+                *v = new_v;
+            }
+        }
+        assert_eq!(map.get(&2).unwrap(), &200);
+        assert_eq!(map.len(), 6);
+
+        // Existing key (take)
+        match map.entry(3) {
+            Vacant(_) => unreachable!(),
+            Occupied(view) => {
+                assert_eq!(view.remove(), 30);
+            }
+        }
+        assert_eq!(map.get(&3), None);
+        assert_eq!(map.len(), 5);
+
+
+        // Inexistent key (insert)
+        match map.entry(10) {
+            Occupied(_) => unreachable!(),
+            Vacant(view) => {
+                assert_eq!(*view.insert(1000), 1000);
+            }
+        }
+        assert_eq!(map.get(&10).unwrap(), &1000);
+        assert_eq!(map.len(), 6);
+    }
+
+    #[test]
+    fn test_entry_take_doesnt_corrupt() {
+        #![allow(deprecated)] //rand
+        // Test for #19292
+        fn check(m: &HashMap<i32, ()>) {
+            for k in m.keys() {
+                assert!(m.contains_key(k),
+                        "{} is in keys() but not in the map?", k);
+            }
+        }
+
+        let mut m = HashMap::new();
+        let mut rng = thread_rng();
+
+        // Populate the map with some items.
+        for _ in 0..50 {
+            let x = rng.gen_range(-10, 10);
+            m.insert(x, ());
+        }
+
+        for i in 0..1000 {
+            let x = rng.gen_range(-10, 10);
+            match m.entry(x) {
+                Vacant(_) => {}
+                Occupied(e) => {
+                    println!("{}: remove {}", i, x);
+                    e.remove();
+                }
+            }
+
+            check(&m);
+        }
+    }
+
+    #[test]
+    fn test_extend_ref() {
+        let mut a = HashMap::new();
+        a.insert(1, "one");
+        let mut b = HashMap::new();
+        b.insert(2, "two");
+        b.insert(3, "three");
+
+        a.extend(&b);
+
+        assert_eq!(a.len(), 3);
+        assert_eq!(a[&1], "one");
+        assert_eq!(a[&2], "two");
+        assert_eq!(a[&3], "three");
+    }
+
+    #[test]
+    fn test_capacity_not_less_than_len() {
+        let mut a = HashMap::new();
+        let mut item = 0;
+
+        for _ in 0..116 {
+            a.insert(item, 0);
+            item += 1;
+        }
+
+        assert!(a.capacity() > a.len());
+
+        let free = a.capacity() - a.len();
+        for _ in 0..free {
+            a.insert(item, 0);
+            item += 1;
+        }
+
+        assert_eq!(a.len(), a.capacity());
+
+        // Insert at capacity should cause allocation.
+        a.insert(item, 0);
+        assert!(a.capacity() > a.len());
+    }
+
+    #[test]
+    fn test_occupied_entry_key() {
+        let mut a = HashMap::new();
+        let key = "hello there";
+        let value = "value goes here";
+        assert!(a.is_empty());
+        a.insert(key.clone(), value.clone());
+        assert_eq!(a.len(), 1);
+        assert_eq!(a[key], value);
+
+        match a.entry(key.clone()) {
+            Vacant(_) => panic!(),
+            Occupied(e) => assert_eq!(key, *e.key()),
+        }
+        assert_eq!(a.len(), 1);
+        assert_eq!(a[key], value);
+    }
+
+    #[test]
+    fn test_vacant_entry_key() {
+        let mut a = HashMap::new();
+        let key = "hello there";
+        let value = "value goes here";
+
+        assert!(a.is_empty());
+        match a.entry(key.clone()) {
+            Occupied(_) => panic!(),
+            Vacant(e) => {
+                assert_eq!(key, *e.key());
+                e.insert(value.clone());
+            }
+        }
+        assert_eq!(a.len(), 1);
+        assert_eq!(a[key], value);
+    }
+
+    #[test]
+    fn test_retain() {
+        let mut map: HashMap<i32, i32> = (0..100).map(|x|(x, x*10)).collect();
+
+        map.retain(|&k, _| k % 2 == 0);
+        assert_eq!(map.len(), 50);
+        assert_eq!(map[&2], 20);
+        assert_eq!(map[&4], 40);
+        assert_eq!(map[&6], 60);
+    }
+
+    #[test]
+    fn test_adaptive() {
+        const TEST_LEN: usize = 5000;
+        // by cloning we get maps with the same hasher seed
+        let mut first = HashMap::new();
+        let mut second = first.clone();
+        first.extend((0..TEST_LEN).map(|i| (i, i)));
+        second.extend((TEST_LEN..TEST_LEN * 2).map(|i| (i, i)));
+
+        for (&k, &v) in &second {
+            let prev_cap = first.capacity();
+            let expect_grow = first.len() == prev_cap;
+            first.insert(k, v);
+            if !expect_grow && first.capacity() != prev_cap {
+                return;
+            }
+        }
+        panic!("Adaptive early resize failed");
+    }
+
+    #[test]
+    fn test_try_reserve() {
+
+        let mut empty_bytes: HashMap<u8,u8> = HashMap::new();
+
+        const MAX_USIZE: usize = usize::MAX;
+
+        // HashMap and RawTables use complicated size calculations
+        // hashes_size is sizeof(HashUint) * capacity;
+        // pairs_size is sizeof((K. V)) * capacity;
+        // alignment_hashes_size is 8
+        // alignment_pairs size is 4
+        let size_of_multiplier = (size_of::<usize>() + size_of::<(u8, u8)>()).next_power_of_two();
+        // The following formula is used to calculate the new capacity
+        let max_no_ovf = ((MAX_USIZE / 11) * 10) / size_of_multiplier - 1;
+
+        if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) {
+        } else { panic!("usize::MAX should trigger an overflow!"); }
+
+        if size_of::<usize>() < 8 {
+            if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) {
+            } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") }
+        } else {
+            if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) {
+            } else { panic!("isize::MAX + 1 should trigger an OOM!") }
+        }
+    }
+
+}
diff --git a/sgx_tstd/src/collections/hash/mod.rs b/sgx_tstd/src/collections/hash/mod.rs
index 4321acf..ea004da 100644
--- a/sgx_tstd/src/collections/hash/mod.rs
+++ b/sgx_tstd/src/collections/hash/mod.rs
@@ -38,4 +38,4 @@
     fn get(&self, key: &Q) -> Option<&Self::Key>;
     fn take(&mut self, key: &Q) -> Option<Self::Key>;
     fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/collections/hash/set.rs b/sgx_tstd/src/collections/hash/set.rs
index 6d8d9f5..a37400f 100644
--- a/sgx_tstd/src/collections/hash/set.rs
+++ b/sgx_tstd/src/collections/hash/set.rs
@@ -26,11 +26,11 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-use core::borrow::Borrow;
-use core::fmt;
-use core::hash::{Hash, BuildHasher};
-use core::iter::{Chain, FromIterator, FusedIterator};
-use core::ops::{BitOr, BitAnd, BitXor, Sub};
+use borrow::Borrow;
+use fmt;
+use hash::{Hash, BuildHasher};
+use iter::{Chain, FromIterator, FusedIterator};
+use ops::{BitOr, BitAnd, BitXor, Sub};
 
 use super::Recover;
 use super::map::{self, HashMap, Keys, RandomState};
@@ -62,7 +62,80 @@
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
 /// unsafe code.
 ///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashSet;
+/// // Type inference lets us omit an explicit type signature (which
+/// // would be `HashSet<String>` in this example).
+/// let mut books = HashSet::new();
+///
+/// // Add some books.
+/// books.insert("A Dance With Dragons".to_string());
+/// books.insert("To Kill a Mockingbird".to_string());
+/// books.insert("The Odyssey".to_string());
+/// books.insert("The Great Gatsby".to_string());
+///
+/// // Check for a specific one.
+/// if !books.contains("The Winds of Winter") {
+///     println!("We have {} books, but The Winds of Winter ain't one.",
+///              books.len());
+/// }
+///
+/// // Remove a book.
+/// books.remove("The Odyssey");
+///
+/// // Iterate over everything.
+/// for book in &books {
+///     println!("{}", book);
+/// }
+/// ```
+///
+/// The easiest way to use `HashSet` with a custom type is to derive
+/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`], this will in the
+/// future be implied by [`Eq`].
+///
+/// ```
+/// use std::collections::HashSet;
+/// #[derive(Hash, Eq, PartialEq, Debug)]
+/// struct Viking {
+///     name: String,
+///     power: usize,
+/// }
+///
+/// let mut vikings = HashSet::new();
+///
+/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
+/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
+/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 });
+/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 });
+///
+/// // Use derived implementation to print the vikings.
+/// for x in &vikings {
+///     println!("{:?}", x);
+/// }
+/// ```
+///
+/// A `HashSet` with fixed list of elements can be initialized from an array:
+///
+/// ```
+/// use std::collections::HashSet;
+///
+/// fn main() {
+///     let viking_names: HashSet<&'static str> =
+///         [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
+///     // use the values stored in the set
+/// }
+/// ```
+///
+/// [`Cell`]: ../../std/cell/struct.Cell.html
+/// [`Eq`]: ../../std/cmp/trait.Eq.html
+/// [`Hash`]: ../../std/hash/trait.Hash.html
+/// [`HashMap`]: struct.HashMap.html
+/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html
+/// [`RefCell`]: ../../std/cell/struct.RefCell.html
 #[derive(Clone)]
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashSet<T, S = RandomState> {
     map: HashMap<T, (), S>,
 }
@@ -73,7 +146,14 @@
     /// The hash set is initially created with a capacity of 0, so it will not allocate until it
     /// is first inserted into.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let set: HashSet<i32> = HashSet::new();
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> HashSet<T, RandomState> {
         HashSet { map: HashMap::new() }
     }
@@ -83,7 +163,15 @@
     /// The hash set will be able to hold at least `capacity` elements without
     /// reallocating. If `capacity` is 0, the hash set will not allocate.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let set: HashSet<i32> = HashSet::with_capacity(10);
+    /// assert!(set.capacity() >= 10);
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize) -> HashSet<T, RandomState> {
         HashSet { map: HashMap::with_capacity(capacity) }
     }
@@ -103,7 +191,18 @@
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let s = RandomState::new();
+    /// let mut set = HashSet::with_hasher(s);
+    /// set.insert(2);
+    /// ```
     #[inline]
+    //#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hasher: S) -> HashSet<T, S> {
         HashSet { map: HashMap::with_hasher(hasher) }
     }
@@ -119,7 +218,18 @@
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let s = RandomState::new();
+    /// let mut set = HashSet::with_capacity_and_hasher(10, s);
+    /// set.insert(1);
+    /// ```
     #[inline]
+    //#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
         HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) }
     }
@@ -127,13 +237,33 @@
     /// Returns a reference to the set's [`BuildHasher`].
     ///
     /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_map::RandomState;
+    ///
+    /// let hasher = RandomState::new();
+    /// let set: HashSet<i32> = HashSet::with_hasher(hasher);
+    /// let hasher: &RandomState = set.hasher();
+    /// ```
+    //#[stable(feature = "hashmap_public_hasher", since = "1.9.0")]
     pub fn hasher(&self) -> &S {
         self.map.hasher()
     }
 
     /// Returns the number of elements the set can hold without reallocating.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let set: HashSet<i32> = HashSet::with_capacity(100);
+    /// assert!(set.capacity() >= 100);
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn capacity(&self) -> usize {
         self.map.capacity()
     }
@@ -146,6 +276,15 @@
     ///
     /// Panics if the new allocation size overflows `usize`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let mut set: HashSet<i32> = HashSet::new();
+    /// set.reserve(10);
+    /// assert!(set.capacity() >= 10);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve(&mut self, additional: usize) {
         self.map.reserve(additional)
     }
@@ -154,6 +293,19 @@
     /// down as much as possible while maintaining the internal rules
     /// and possibly leaving some space in accordance with the resize policy.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::with_capacity(100);
+    /// set.insert(1);
+    /// set.insert(2);
+    /// assert!(set.capacity() >= 100);
+    /// set.shrink_to_fit();
+    /// assert!(set.capacity() >= 2);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn shrink_to_fit(&mut self) {
         self.map.shrink_to_fit()
     }
@@ -165,7 +317,23 @@
     /// Panics if the current capacity is smaller than the supplied
     /// minimum capacity.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(shrink_to)]
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::with_capacity(100);
+    /// set.insert(1);
+    /// set.insert(2);
+    /// assert!(set.capacity() >= 100);
+    /// set.shrink_to(10);
+    /// assert!(set.capacity() >= 10);
+    /// set.shrink_to(0);
+    /// assert!(set.capacity() >= 2);
+    /// ```
     #[inline]
+    //#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
         self.map.shrink_to(min_capacity)
     }
@@ -173,6 +341,20 @@
     /// An iterator visiting all elements in arbitrary order.
     /// The iterator element type is `&'a T`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// set.insert("a");
+    /// set.insert("b");
+    ///
+    /// // Will print in an arbitrary order.
+    /// for x in set.iter() {
+    ///     println!("{}", x);
+    /// }
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter(&self) -> Iter<T> {
         Iter { iter: self.map.keys() }
     }
@@ -180,16 +362,56 @@
     /// Visits the values representing the difference,
     /// i.e. the values that are in `self` but not in `other`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    ///
+    /// // Can be seen as `a - b`.
+    /// for x in a.difference(&b) {
+    ///     println!("{}", x); // Print 1
+    /// }
+    ///
+    /// let diff: HashSet<_> = a.difference(&b).collect();
+    /// assert_eq!(diff, [1].iter().collect());
+    ///
+    /// // Note that difference is not symmetric,
+    /// // and `b - a` means something else:
+    /// let diff: HashSet<_> = b.difference(&a).collect();
+    /// assert_eq!(diff, [4].iter().collect());
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
         Difference {
             iter: self.iter(),
-            other: other,
+            other,
         }
     }
 
     /// Visits the values representing the symmetric difference,
     /// i.e. the values that are in `self` or in `other` but not in both.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    ///
+    /// // Print 1, 4 in arbitrary order.
+    /// for x in a.symmetric_difference(&b) {
+    ///     println!("{}", x);
+    /// }
+    ///
+    /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect();
+    /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect();
+    ///
+    /// assert_eq!(diff1, diff2);
+    /// assert_eq!(diff1, [1, 4].iter().collect());
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn symmetric_difference<'a>(&'a self,
                                     other: &'a HashSet<T, S>)
                                     -> SymmetricDifference<'a, T, S> {
@@ -199,40 +421,122 @@
     /// Visits the values representing the intersection,
     /// i.e. the values that are both in `self` and `other`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    ///
+    /// // Print 2, 3 in arbitrary order.
+    /// for x in a.intersection(&b) {
+    ///     println!("{}", x);
+    /// }
+    ///
+    /// let intersection: HashSet<_> = a.intersection(&b).collect();
+    /// assert_eq!(intersection, [2, 3].iter().collect());
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
         Intersection {
             iter: self.iter(),
-            other: other,
+            other,
         }
     }
 
     /// Visits the values representing the union,
     /// i.e. all the values in `self` or `other`, without duplicates.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    ///
+    /// // Print 1, 2, 3, 4 in arbitrary order.
+    /// for x in a.union(&b) {
+    ///     println!("{}", x);
+    /// }
+    ///
+    /// let union: HashSet<_> = a.union(&b).collect();
+    /// assert_eq!(union, [1, 2, 3, 4].iter().collect());
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
         Union { iter: self.iter().chain(other.difference(self)) }
     }
 
     /// Returns the number of elements in the set.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut v = HashSet::new();
+    /// assert_eq!(v.len(), 0);
+    /// v.insert(1);
+    /// assert_eq!(v.len(), 1);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         self.map.len()
     }
 
     /// Returns true if the set contains no elements.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut v = HashSet::new();
+    /// assert!(v.is_empty());
+    /// v.insert(1);
+    /// assert!(!v.is_empty());
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
         self.map.is_empty()
     }
 
     /// Clears the set, returning all elements in an iterator.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// assert!(!set.is_empty());
+    ///
+    /// // print 1, 2, 3 in an arbitrary order
+    /// for i in set.drain() {
+    ///     println!("{}", i);
+    /// }
+    ///
+    /// assert!(set.is_empty());
+    /// ```
     #[inline]
+    //#[stable(feature = "drain", since = "1.6.0")]
     pub fn drain(&mut self) -> Drain<T> {
         Drain { iter: self.map.drain() }
     }
 
     /// Clears the set, removing all values.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut v = HashSet::new();
+    /// v.insert(1);
+    /// v.clear();
+    /// assert!(v.is_empty());
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn clear(&mut self) {
         self.map.clear()
     }
@@ -243,6 +547,19 @@
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the value type.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// assert_eq!(set.contains(&1), true);
+    /// assert_eq!(set.contains(&4), false);
+    /// ```
+    ///
+    /// [`Eq`]: ../../std/cmp/trait.Eq.html
+    /// [`Hash`]: ../../std/hash/trait.Hash.html
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
         where T: Borrow<Q>,
               Q: Hash + Eq
@@ -256,8 +573,19 @@
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the value type.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// assert_eq!(set.get(&2), Some(&2));
+    /// assert_eq!(set.get(&4), None);
+    /// ```
+    ///
     /// [`Eq`]: ../../std/cmp/trait.Eq.html
     /// [`Hash`]: ../../std/hash/trait.Hash.html
+    //#[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
         where T: Borrow<Q>,
               Q: Hash + Eq
@@ -268,6 +596,21 @@
     /// Returns `true` if `self` has no elements in common with `other`.
     /// This is equivalent to checking for an empty intersection.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut b = HashSet::new();
+    ///
+    /// assert_eq!(a.is_disjoint(&b), true);
+    /// b.insert(4);
+    /// assert_eq!(a.is_disjoint(&b), true);
+    /// b.insert(1);
+    /// assert_eq!(a.is_disjoint(&b), false);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_disjoint(&self, other: &HashSet<T, S>) -> bool {
         self.iter().all(|v| !other.contains(v))
     }
@@ -275,6 +618,21 @@
     /// Returns `true` if the set is a subset of another,
     /// i.e. `other` contains at least all the values in `self`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = HashSet::new();
+    ///
+    /// assert_eq!(set.is_subset(&sup), true);
+    /// set.insert(2);
+    /// assert_eq!(set.is_subset(&sup), true);
+    /// set.insert(4);
+    /// assert_eq!(set.is_subset(&sup), false);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_subset(&self, other: &HashSet<T, S>) -> bool {
         self.iter().all(|v| other.contains(v))
     }
@@ -282,7 +640,25 @@
     /// Returns `true` if the set is a superset of another,
     /// i.e. `self` contains at least all the values in `other`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let sub: HashSet<_> = [1, 2].iter().cloned().collect();
+    /// let mut set = HashSet::new();
+    ///
+    /// assert_eq!(set.is_superset(&sub), false);
+    ///
+    /// set.insert(0);
+    /// set.insert(1);
+    /// assert_eq!(set.is_superset(&sub), false);
+    ///
+    /// set.insert(2);
+    /// assert_eq!(set.is_superset(&sub), true);
+    /// ```
     #[inline]
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_superset(&self, other: &HashSet<T, S>) -> bool {
         other.is_subset(self)
     }
@@ -293,12 +669,38 @@
     ///
     /// If the set did have this value present, `false` is returned.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// assert_eq!(set.insert(2), true);
+    /// assert_eq!(set.insert(2), false);
+    /// assert_eq!(set.len(), 1);
+    /// ```
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, value: T) -> bool {
         self.map.insert(value, ()).is_none()
     }
 
     /// Adds a value to the set, replacing the existing value, if any, that is equal to the given
     /// one. Returns the replaced value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    /// set.insert(Vec::<i32>::new());
+    ///
+    /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0);
+    /// set.replace(Vec::with_capacity(10));
+    /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10);
+    /// ```
+    //#[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn replace(&mut self, value: T) -> Option<T> {
         Recover::replace(&mut self.map, value)
     }
@@ -310,6 +712,21 @@
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the value type.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// set.insert(2);
+    /// assert_eq!(set.remove(&2), true);
+    /// assert_eq!(set.remove(&2), false);
+    /// ```
+    ///
+    /// [`Eq`]: ../../std/cmp/trait.Eq.html
+    /// [`Hash`]: ../../std/hash/trait.Hash.html
+    //#[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
         where T: Borrow<Q>,
               Q: Hash + Eq
@@ -323,8 +740,19 @@
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
     /// the value type.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// assert_eq!(set.take(&2), Some(2));
+    /// assert_eq!(set.take(&2), None);
+    /// ```
+    ///
     /// [`Eq`]: ../../std/cmp/trait.Eq.html
     /// [`Hash`]: ../../std/hash/trait.Hash.html
+    //#[stable(feature = "set_recovery", since = "1.9.0")]
     pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
         where T: Borrow<Q>,
               Q: Hash + Eq
@@ -336,6 +764,17 @@
     ///
     /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let xs = [1,2,3,4,5,6];
+    /// let mut set: HashSet<i32> = xs.iter().cloned().collect();
+    /// set.retain(|&k| k % 2 == 0);
+    /// assert_eq!(set.len(), 3);
+    /// ```
+    //#[stable(feature = "retain_hash_collection", since = "1.18.0")]
     pub fn retain<F>(&mut self, mut f: F)
         where F: FnMut(&T) -> bool
     {
@@ -343,6 +782,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> PartialEq for HashSet<T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -356,12 +796,14 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> Eq for HashSet<T, S>
     where T: Eq + Hash,
           S: BuildHasher
 {
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> fmt::Debug for HashSet<T, S>
     where T: Eq + Hash + fmt::Debug,
           S: BuildHasher
@@ -371,6 +813,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> FromIterator<T> for HashSet<T, S>
     where T: Eq + Hash,
           S: BuildHasher + Default
@@ -382,6 +825,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> Extend<T> for HashSet<T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -391,6 +835,7 @@
     }
 }
 
+//#[stable(feature = "hash_extend_copy", since = "1.4.0")]
 impl<'a, T, S> Extend<&'a T> for HashSet<T, S>
     where T: 'a + Eq + Hash + Copy,
           S: BuildHasher
@@ -400,6 +845,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> Default for HashSet<T, S>
     where T: Eq + Hash,
           S: BuildHasher + Default
@@ -410,6 +856,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, 'b, T, S> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
@@ -418,11 +865,30 @@
 
     /// Returns the union of `self` and `rhs` as a new `HashSet<T, S>`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    ///
+    /// let set = &a | &b;
+    ///
+    /// let mut i = 0;
+    /// let expected = [1, 2, 3, 4, 5];
+    /// for x in &set {
+    ///     assert!(expected.contains(x));
+    ///     i += 1;
+    /// }
+    /// assert_eq!(i, expected.len());
+    /// ```
     fn bitor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
         self.union(rhs).cloned().collect()
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, 'b, T, S> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
@@ -431,11 +897,30 @@
 
     /// Returns the intersection of `self` and `rhs` as a new `HashSet<T, S>`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+    /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect();
+    ///
+    /// let set = &a & &b;
+    ///
+    /// let mut i = 0;
+    /// let expected = [2, 3];
+    /// for x in &set {
+    ///     assert!(expected.contains(x));
+    ///     i += 1;
+    /// }
+    /// assert_eq!(i, expected.len());
+    /// ```
     fn bitand(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
         self.intersection(rhs).cloned().collect()
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, 'b, T, S> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
@@ -444,11 +929,30 @@
 
     /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, S>`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    ///
+    /// let set = &a ^ &b;
+    ///
+    /// let mut i = 0;
+    /// let expected = [1, 2, 4, 5];
+    /// for x in &set {
+    ///     assert!(expected.contains(x));
+    ///     i += 1;
+    /// }
+    /// assert_eq!(i, expected.len());
+    /// ```
     fn bitxor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
         self.symmetric_difference(rhs).cloned().collect()
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, 'b, T, S> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
@@ -457,6 +961,24 @@
 
     /// Returns the difference of `self` and `rhs` as a new `HashSet<T, S>`.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
+    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    ///
+    /// let set = &a - &b;
+    ///
+    /// let mut i = 0;
+    /// let expected = [1, 2];
+    /// for x in &set {
+    ///     assert!(expected.contains(x));
+    ///     i += 1;
+    /// }
+    /// assert_eq!(i, expected.len());
+    /// ```
     fn sub(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
         self.difference(rhs).cloned().collect()
     }
@@ -469,6 +991,7 @@
 ///
 /// [`HashSet`]: struct.HashSet.html
 /// [`iter`]: struct.HashSet.html#method.iter
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a> {
     iter: Keys<'a, K, ()>,
 }
@@ -480,6 +1003,7 @@
 ///
 /// [`HashSet`]: struct.HashSet.html
 /// [`into_iter`]: struct.HashSet.html#method.into_iter
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K> {
     iter: map::IntoIter<K, ()>,
 }
@@ -491,6 +1015,7 @@
 ///
 /// [`HashSet`]: struct.HashSet.html
 /// [`drain`]: struct.HashSet.html#method.drain
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Drain<'a, K: 'a> {
     iter: map::Drain<'a, K, ()>,
 }
@@ -502,6 +1027,7 @@
 ///
 /// [`HashSet`]: struct.HashSet.html
 /// [`intersection`]: struct.HashSet.html#method.intersection
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Intersection<'a, T: 'a, S: 'a> {
     // iterator of the first set
     iter: Iter<'a, T>,
@@ -516,6 +1042,7 @@
 ///
 /// [`HashSet`]: struct.HashSet.html
 /// [`difference`]: struct.HashSet.html#method.difference
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Difference<'a, T: 'a, S: 'a> {
     // iterator of the first set
     iter: Iter<'a, T>,
@@ -530,6 +1057,7 @@
 ///
 /// [`HashSet`]: struct.HashSet.html
 /// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
     iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>,
 }
@@ -541,10 +1069,12 @@
 ///
 /// [`HashSet`]: struct.HashSet.html
 /// [`union`]: struct.HashSet.html#method.union
+//#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Union<'a, T: 'a, S: 'a> {
     iter: Chain<Iter<'a, T>, Difference<'a, T, S>>,
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> IntoIterator for &'a HashSet<T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -557,6 +1087,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> IntoIterator for HashSet<T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -568,17 +1099,34 @@
     /// of the set in arbitrary order. The set cannot be used after calling
     /// this.
     ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// set.insert("a".to_string());
+    /// set.insert("b".to_string());
+    ///
+    /// // Not possible to collect to a Vec<String> with a regular `.iter()`.
+    /// let v: Vec<String> = set.into_iter().collect();
+    ///
+    /// // Will print in an arbitrary order.
+    /// for x in &v {
+    ///     println!("{}", x);
+    /// }
+    /// ```
     fn into_iter(self) -> IntoIter<T> {
         IntoIter { iter: self.map.into_iter() }
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K> Clone for Iter<'a, K> {
     fn clone(&self) -> Iter<'a, K> {
         Iter { iter: self.iter.clone() }
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K> Iterator for Iter<'a, K> {
     type Item = &'a K;
 
@@ -589,21 +1137,23 @@
         self.iter.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K> ExactSizeIterator for Iter<'a, K> {
     fn len(&self) -> usize {
         self.iter.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K> FusedIterator for Iter<'a, K> {}
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_list().entries(self.clone()).finish()
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K> Iterator for IntoIter<K> {
     type Item = K;
 
@@ -614,15 +1164,16 @@
         self.iter.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<K> ExactSizeIterator for IntoIter<K> {
     fn len(&self) -> usize {
         self.iter.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<K> FusedIterator for IntoIter<K> {}
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<K: fmt::Debug> fmt::Debug for IntoIter<K> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let entries_iter = self.iter
@@ -633,6 +1184,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K> Iterator for Drain<'a, K> {
     type Item = K;
 
@@ -643,15 +1195,16 @@
         self.iter.size_hint()
     }
 }
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K> ExactSizeIterator for Drain<'a, K> {
     fn len(&self) -> usize {
         self.iter.len()
     }
 }
-
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K> FusedIterator for Drain<'a, K> {}
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let entries_iter = self.iter
@@ -662,12 +1215,14 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Intersection<'a, T, S> {
     fn clone(&self) -> Intersection<'a, T, S> {
         Intersection { iter: self.iter.clone(), ..*self }
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Iterator for Intersection<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -689,6 +1244,7 @@
     }
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, T, S> fmt::Debug for Intersection<'a, T, S>
     where T: fmt::Debug + Eq + Hash,
           S: BuildHasher
@@ -698,18 +1254,21 @@
     }
 }
 
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for Intersection<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
 {
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Difference<'a, T, S> {
     fn clone(&self) -> Difference<'a, T, S> {
         Difference { iter: self.iter.clone(), ..*self }
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Iterator for Difference<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -731,12 +1290,14 @@
     }
 }
 
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for Difference<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
 {
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, T, S> fmt::Debug for Difference<'a, T, S>
     where T: fmt::Debug + Eq + Hash,
           S: BuildHasher
@@ -746,13 +1307,14 @@
     }
 }
 
-
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> {
     fn clone(&self) -> SymmetricDifference<'a, T, S> {
         SymmetricDifference { iter: self.iter.clone() }
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -767,12 +1329,14 @@
     }
 }
 
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
 {
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S>
     where T: fmt::Debug + Eq + Hash,
           S: BuildHasher
@@ -782,18 +1346,21 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Union<'a, T, S> {
     fn clone(&self) -> Union<'a, T, S> {
         Union { iter: self.iter.clone() }
     }
 }
 
+//#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for Union<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
 {
 }
 
+//#[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, T, S> fmt::Debug for Union<'a, T, S>
     where T: fmt::Debug + Eq + Hash,
           S: BuildHasher
@@ -803,6 +1370,7 @@
     }
 }
 
+//#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Iterator for Union<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -848,3 +1416,386 @@
         d
     }
 }
+
+#[cfg(test)]
+mod test_set {
+    use super::HashSet;
+    use super::super::map::RandomState;
+
+    #[test]
+    fn test_zero_capacities() {
+        type HS = HashSet<i32>;
+
+        let s = HS::new();
+        assert_eq!(s.capacity(), 0);
+
+        let s = HS::default();
+        assert_eq!(s.capacity(), 0);
+
+        let s = HS::with_hasher(RandomState::new());
+        assert_eq!(s.capacity(), 0);
+
+        let s = HS::with_capacity(0);
+        assert_eq!(s.capacity(), 0);
+
+        let s = HS::with_capacity_and_hasher(0, RandomState::new());
+        assert_eq!(s.capacity(), 0);
+
+        let mut s = HS::new();
+        s.insert(1);
+        s.insert(2);
+        s.remove(&1);
+        s.remove(&2);
+        s.shrink_to_fit();
+        assert_eq!(s.capacity(), 0);
+
+        let mut s = HS::new();
+        s.reserve(0);
+        assert_eq!(s.capacity(), 0);
+    }
+
+    #[test]
+    fn test_disjoint() {
+        let mut xs = HashSet::new();
+        let mut ys = HashSet::new();
+        assert!(xs.is_disjoint(&ys));
+        assert!(ys.is_disjoint(&xs));
+        assert!(xs.insert(5));
+        assert!(ys.insert(11));
+        assert!(xs.is_disjoint(&ys));
+        assert!(ys.is_disjoint(&xs));
+        assert!(xs.insert(7));
+        assert!(xs.insert(19));
+        assert!(xs.insert(4));
+        assert!(ys.insert(2));
+        assert!(ys.insert(-11));
+        assert!(xs.is_disjoint(&ys));
+        assert!(ys.is_disjoint(&xs));
+        assert!(ys.insert(7));
+        assert!(!xs.is_disjoint(&ys));
+        assert!(!ys.is_disjoint(&xs));
+    }
+
+    #[test]
+    fn test_subset_and_superset() {
+        let mut a = HashSet::new();
+        assert!(a.insert(0));
+        assert!(a.insert(5));
+        assert!(a.insert(11));
+        assert!(a.insert(7));
+
+        let mut b = HashSet::new();
+        assert!(b.insert(0));
+        assert!(b.insert(7));
+        assert!(b.insert(19));
+        assert!(b.insert(250));
+        assert!(b.insert(11));
+        assert!(b.insert(200));
+
+        assert!(!a.is_subset(&b));
+        assert!(!a.is_superset(&b));
+        assert!(!b.is_subset(&a));
+        assert!(!b.is_superset(&a));
+
+        assert!(b.insert(5));
+
+        assert!(a.is_subset(&b));
+        assert!(!a.is_superset(&b));
+        assert!(!b.is_subset(&a));
+        assert!(b.is_superset(&a));
+    }
+
+    #[test]
+    fn test_iterate() {
+        let mut a = HashSet::new();
+        for i in 0..32 {
+            assert!(a.insert(i));
+        }
+        let mut observed: u32 = 0;
+        for k in &a {
+            observed |= 1 << *k;
+        }
+        assert_eq!(observed, 0xFFFF_FFFF);
+    }
+
+    #[test]
+    fn test_intersection() {
+        let mut a = HashSet::new();
+        let mut b = HashSet::new();
+
+        assert!(a.insert(11));
+        assert!(a.insert(1));
+        assert!(a.insert(3));
+        assert!(a.insert(77));
+        assert!(a.insert(103));
+        assert!(a.insert(5));
+        assert!(a.insert(-5));
+
+        assert!(b.insert(2));
+        assert!(b.insert(11));
+        assert!(b.insert(77));
+        assert!(b.insert(-9));
+        assert!(b.insert(-42));
+        assert!(b.insert(5));
+        assert!(b.insert(3));
+
+        let mut i = 0;
+        let expected = [3, 5, 11, 77];
+        for x in a.intersection(&b) {
+            assert!(expected.contains(x));
+            i += 1
+        }
+        assert_eq!(i, expected.len());
+    }
+
+    #[test]
+    fn test_difference() {
+        let mut a = HashSet::new();
+        let mut b = HashSet::new();
+
+        assert!(a.insert(1));
+        assert!(a.insert(3));
+        assert!(a.insert(5));
+        assert!(a.insert(9));
+        assert!(a.insert(11));
+
+        assert!(b.insert(3));
+        assert!(b.insert(9));
+
+        let mut i = 0;
+        let expected = [1, 5, 11];
+        for x in a.difference(&b) {
+            assert!(expected.contains(x));
+            i += 1
+        }
+        assert_eq!(i, expected.len());
+    }
+
+    #[test]
+    fn test_symmetric_difference() {
+        let mut a = HashSet::new();
+        let mut b = HashSet::new();
+
+        assert!(a.insert(1));
+        assert!(a.insert(3));
+        assert!(a.insert(5));
+        assert!(a.insert(9));
+        assert!(a.insert(11));
+
+        assert!(b.insert(-2));
+        assert!(b.insert(3));
+        assert!(b.insert(9));
+        assert!(b.insert(14));
+        assert!(b.insert(22));
+
+        let mut i = 0;
+        let expected = [-2, 1, 5, 11, 14, 22];
+        for x in a.symmetric_difference(&b) {
+            assert!(expected.contains(x));
+            i += 1
+        }
+        assert_eq!(i, expected.len());
+    }
+
+    #[test]
+    fn test_union() {
+        let mut a = HashSet::new();
+        let mut b = HashSet::new();
+
+        assert!(a.insert(1));
+        assert!(a.insert(3));
+        assert!(a.insert(5));
+        assert!(a.insert(9));
+        assert!(a.insert(11));
+        assert!(a.insert(16));
+        assert!(a.insert(19));
+        assert!(a.insert(24));
+
+        assert!(b.insert(-2));
+        assert!(b.insert(1));
+        assert!(b.insert(5));
+        assert!(b.insert(9));
+        assert!(b.insert(13));
+        assert!(b.insert(19));
+
+        let mut i = 0;
+        let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
+        for x in a.union(&b) {
+            assert!(expected.contains(x));
+            i += 1
+        }
+        assert_eq!(i, expected.len());
+    }
+
+    #[test]
+    fn test_from_iter() {
+        let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+
+        let set: HashSet<_> = xs.iter().cloned().collect();
+
+        for x in &xs {
+            assert!(set.contains(x));
+        }
+    }
+
+    #[test]
+    fn test_move_iter() {
+        let hs = {
+            let mut hs = HashSet::new();
+
+            hs.insert('a');
+            hs.insert('b');
+
+            hs
+        };
+
+        let v = hs.into_iter().collect::<Vec<char>>();
+        assert!(v == ['a', 'b'] || v == ['b', 'a']);
+    }
+
+    #[test]
+    fn test_eq() {
+        // These constants once happened to expose a bug in insert().
+        // I'm keeping them around to prevent a regression.
+        let mut s1 = HashSet::new();
+
+        s1.insert(1);
+        s1.insert(2);
+        s1.insert(3);
+
+        let mut s2 = HashSet::new();
+
+        s2.insert(1);
+        s2.insert(2);
+
+        assert!(s1 != s2);
+
+        s2.insert(3);
+
+        assert_eq!(s1, s2);
+    }
+
+    #[test]
+    fn test_show() {
+        let mut set = HashSet::new();
+        let empty = HashSet::<i32>::new();
+
+        set.insert(1);
+        set.insert(2);
+
+        let set_str = format!("{:?}", set);
+
+        assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
+        assert_eq!(format!("{:?}", empty), "{}");
+    }
+
+    #[test]
+    fn test_trivial_drain() {
+        let mut s = HashSet::<i32>::new();
+        for _ in s.drain() {}
+        assert!(s.is_empty());
+        drop(s);
+
+        let mut s = HashSet::<i32>::new();
+        drop(s.drain());
+        assert!(s.is_empty());
+    }
+
+    #[test]
+    fn test_drain() {
+        let mut s: HashSet<_> = (1..100).collect();
+
+        // try this a bunch of times to make sure we don't screw up internal state.
+        for _ in 0..20 {
+            assert_eq!(s.len(), 99);
+
+            {
+                let mut last_i = 0;
+                let mut d = s.drain();
+                for (i, x) in d.by_ref().take(50).enumerate() {
+                    last_i = i;
+                    assert!(x != 0);
+                }
+                assert_eq!(last_i, 49);
+            }
+
+            for _ in &s {
+                panic!("s should be empty!");
+            }
+
+            // reset to try again.
+            s.extend(1..100);
+        }
+    }
+
+    #[test]
+    fn test_replace() {
+        use hash;
+
+        #[derive(Debug)]
+        struct Foo(&'static str, i32);
+
+        impl PartialEq for Foo {
+            fn eq(&self, other: &Self) -> bool {
+                self.0 == other.0
+            }
+        }
+
+        impl Eq for Foo {}
+
+        impl hash::Hash for Foo {
+            fn hash<H: hash::Hasher>(&self, h: &mut H) {
+                self.0.hash(h);
+            }
+        }
+
+        let mut s = HashSet::new();
+        assert_eq!(s.replace(Foo("a", 1)), None);
+        assert_eq!(s.len(), 1);
+        assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1)));
+        assert_eq!(s.len(), 1);
+
+        let mut it = s.iter();
+        assert_eq!(it.next(), Some(&Foo("a", 2)));
+        assert_eq!(it.next(), None);
+    }
+
+    #[test]
+    fn test_extend_ref() {
+        let mut a = HashSet::new();
+        a.insert(1);
+
+        a.extend(&[2, 3, 4]);
+
+        assert_eq!(a.len(), 4);
+        assert!(a.contains(&1));
+        assert!(a.contains(&2));
+        assert!(a.contains(&3));
+        assert!(a.contains(&4));
+
+        let mut b = HashSet::new();
+        b.insert(5);
+        b.insert(6);
+
+        a.extend(&b);
+
+        assert_eq!(a.len(), 6);
+        assert!(a.contains(&1));
+        assert!(a.contains(&2));
+        assert!(a.contains(&3));
+        assert!(a.contains(&4));
+        assert!(a.contains(&5));
+        assert!(a.contains(&6));
+    }
+
+    #[test]
+    fn test_retain() {
+        let xs = [1, 2, 3, 4, 5, 6];
+        let mut set: HashSet<i32> = xs.iter().cloned().collect();
+        set.retain(|&k| k % 2 == 0);
+        assert_eq!(set.len(), 3);
+        assert!(set.contains(&2));
+        assert!(set.contains(&4));
+        assert!(set.contains(&6));
+    }
+}
diff --git a/sgx_tstd/src/collections/hash/table.rs b/sgx_tstd/src/collections/hash/table.rs
index 85901fe..9ceee1d 100644
--- a/sgx_tstd/src/collections/hash/table.rs
+++ b/sgx_tstd/src/collections/hash/table.rs
@@ -26,17 +26,15 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-use alloc::heap::Heap;
-use core::heap::{Alloc, Layout};
-
-use core::cmp;
-use core::hash::{BuildHasher, Hash, Hasher};
-use core::marker;
-use core::mem::{align_of, size_of, needs_drop};
-use core::mem;
-use core::ops::{Deref, DerefMut};
-use core::ptr::{self, Unique, NonNull};
-use alloc::allocator::CollectionAllocErr;
+use alloc::alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error};
+use alloc::collections::CollectionAllocErr;
+use hash::{BuildHasher, Hash, Hasher};
+use marker;
+use mem::{size_of, needs_drop};
+use mem;
+use ops::{Deref, DerefMut};
+use ptr::{self, Unique, NonNull};
+use core::hint;
 
 use self::BucketState::*;
 
@@ -100,7 +98,7 @@
 ///
 /// Essential invariants of this structure:
 ///
-///   - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw`
+///   - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw`
 ///     points to 'undefined' contents. Don't read from it. This invariant is
 ///     enforced outside this module with the `EmptyBucket`, `FullBucket`,
 ///     and `SafeHash` types.
@@ -236,6 +234,20 @@
     SafeHash::new(state.finish())
 }
 
+// `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically
+// ensure that a `FullBucket` points to an index with a non-zero hash,
+// and a `SafeHash` is just a `HashUint` with a different name, this is
+// safe.
+//
+// This test ensures that a `SafeHash` really IS the same size as a
+// `HashUint`. If you need to change the size of `SafeHash` (and
+// consequently made this test fail), `replace` needs to be
+// modified to no longer assume this.
+#[test]
+fn can_alias_safehash_as_hash() {
+    assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>())
+}
+
 // RawBucket methods are unsafe as it's possible to
 // make a RawBucket point to invalid memory using safe code.
 impl<K, V> RawBucket<K, V> {
@@ -356,14 +368,14 @@
         let ib_index = ib_index & table.capacity_mask;
         Bucket {
             raw: table.raw_bucket_at(ib_index),
-            table: table,
+            table,
         }
     }
 
     pub fn first(table: M) -> Bucket<K, V, M> {
         Bucket {
             raw: table.raw_bucket_at(0),
-            table: table,
+            table,
         }
     }
 
@@ -458,7 +470,7 @@
         match self.next().peek() {
             Full(bucket) => {
                 Ok(GapThenFull {
-                    gap: gap,
+                    gap,
                     full: bucket,
                 })
             }
@@ -658,51 +670,39 @@
     }
 }
 
-
-/// Rounds up to a multiple of a power of two. Returns the closest multiple
-/// of `target_alignment` that is higher or equal to `unrounded`.
-///
-/// # Panics
-///
-/// Panics if `target_alignment` is not a power of two.
-#[inline]
-fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize {
-    assert!(target_alignment.is_power_of_two());
-    (unrounded + target_alignment - 1) & !(target_alignment - 1)
+// Returns a Layout which describes the allocation required for a hash table,
+// and the offset of the array of (key, value) pairs in the allocation.
+fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> {
+    let hashes = Layout::array::<HashUint>(capacity)?;
+    let pairs = Layout::array::<(K, V)>(capacity)?;
+    hashes.extend(pairs).map(|(layout, _)| {
+        // LLVM seems to have trouble properly const-propagating pairs.align(),
+        // possibly due to the use of NonZeroUsize. This little hack allows it
+        // to generate optimal code.
+        //
+        // See https://github.com/rust-lang/rust/issues/51346 for more details.
+        (
+            layout,
+            hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()),
+        )
+    })
 }
 
-// Returns a tuple of (pairs_offset, end_of_pairs_offset),
-// from the start of a mallocated array.
-#[inline]
-fn calculate_offsets(hashes_size: usize,
-                     pairs_size: usize,
-                     pairs_align: usize)
-                     -> (usize, usize, bool) {
-    let pairs_offset = round_up_to_next(hashes_size, pairs_align);
-    let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size);
-
-    (pairs_offset, end_of_pairs, oflo)
+pub(crate) enum Fallibility {
+    Fallible,
+    Infallible,
 }
 
-// Returns a tuple of (minimum required malloc alignment,
-// array_size), from the start of a mallocated array.
-fn calculate_allocation(hash_size: usize,
-                        hash_align: usize,
-                        pairs_size: usize,
-                        pairs_align: usize)
-                        -> (usize, usize, bool) {
-    let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
-
-    let align = cmp::max(hash_align, pairs_align);
-
-    (align, end_of_pairs, oflo)
-}
+use self::Fallibility::*;
 
 impl<K, V> RawTable<K, V> {
     /// Does not initialize the buckets. The caller should ensure they,
     /// at the very least, set every hash to EMPTY_BUCKET.
     /// Returns an error if it cannot allocate or capacity overflows.
-    unsafe fn try_new_uninitialized(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> {
+    unsafe fn new_uninitialized_internal(
+        capacity: usize,
+        fallibility: Fallibility,
+    ) -> Result<RawTable<K, V>, CollectionAllocErr> {
         if capacity == 0 {
             return Ok(RawTable {
                 size: 0,
@@ -712,44 +712,20 @@
             });
         }
 
-        // No need for `checked_mul` before a more restrictive check performed
-        // later in this method.
-        let hashes_size = capacity.wrapping_mul(size_of::<HashUint>());
-        let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>());
-
         // Allocating hashmaps is a little tricky. We need to allocate two
         // arrays, but since we know their sizes and alignments up front,
         // we just allocate a single array, and then have the subarrays
         // point into it.
-        //
-        // This is great in theory, but in practice getting the alignment
-        // right is a little subtle. Therefore, calculating offsets has been
-        // factored out into a different function.
-        let (alignment, size, oflo) = calculate_allocation(hashes_size,
-                                                           align_of::<HashUint>(),
-                                                           pairs_size,
-                                                           align_of::<(K, V)>());
-        if oflo {
-            return Err(CollectionAllocErr::CapacityOverflow);
-        }
-
-        // One check for overflow that covers calculation and rounding of size.
-        let size_of_bucket = size_of::<HashUint>().checked_add(size_of::<(K, V)>())
-            .ok_or(CollectionAllocErr::CapacityOverflow)?;
-        let capacity_mul_size_of_bucket = capacity.checked_mul(size_of_bucket);
-        if capacity_mul_size_of_bucket.is_none() || size < capacity_mul_size_of_bucket.unwrap() {
-            return Err(CollectionAllocErr::CapacityOverflow);
-        }
-
-        let buffer = Heap.alloc(Layout::from_size_align(size, alignment)
-            .ok_or(CollectionAllocErr::CapacityOverflow)?)?;
-
-        let hashes = buffer as *mut HashUint;
+        let (layout, _) = calculate_layout::<K, V>(capacity)?;
+        let buffer = Global.alloc(layout).map_err(|e| match fallibility {
+            Infallible => handle_alloc_error(layout),
+            Fallible => e,
+        })?;
 
         Ok(RawTable {
             capacity_mask: capacity.wrapping_sub(1),
             size: 0,
-            hashes: TaggedHashUintPtr::new(hashes),
+            hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()),
             marker: marker::PhantomData,
         })
     }
@@ -757,48 +733,50 @@
     /// Does not initialize the buckets. The caller should ensure they,
     /// at the very least, set every hash to EMPTY_BUCKET.
     unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
-        match Self::try_new_uninitialized(capacity) {
+        match Self::new_uninitialized_internal(capacity, Infallible) {
             Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
-            Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e),
+            Err(CollectionAllocErr::AllocErr) => unreachable!(),
             Ok(table) => { table }
         }
     }
 
     fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
-        let hashes_size = self.capacity() * size_of::<HashUint>();
-        let pairs_size = self.capacity() * size_of::<(K, V)>();
-
-        let (pairs_offset, _, oflo) =
-            calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
-        debug_assert!(!oflo, "capacity overflow");
-
+        let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity())
+            .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
         let buffer = self.hashes.ptr() as *mut u8;
         unsafe {
             RawBucket {
                 hash_start: buffer as *mut HashUint,
-                pair_start: buffer.offset(pairs_offset as isize) as *const (K, V),
+                pair_start: buffer.add(pairs_offset) as *const (K, V),
                 idx: index,
                 _marker: marker::PhantomData,
             }
         }
     }
 
-    /// Tries to create a new raw table from a given capacity. If it cannot allocate,
-    /// it returns with AllocErr.
-    pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> {
+    fn new_internal(
+        capacity: usize,
+        fallibility: Fallibility,
+    ) -> Result<RawTable<K, V>, CollectionAllocErr> {
         unsafe {
-            let ret = RawTable::try_new_uninitialized(capacity)?;
+            let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?;
             ptr::write_bytes(ret.hashes.ptr(), 0, capacity);
             Ok(ret)
         }
     }
 
+    /// Tries to create a new raw table from a given capacity. If it cannot allocate,
+    /// it returns with AllocErr.
+    pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> {
+        Self::new_internal(capacity, Fallible)
+    }
+
     /// Creates a new raw table from a given capacity. All buckets are
     /// initially empty.
     pub fn new(capacity: usize) -> RawTable<K, V> {
-        match Self::try_new(capacity) {
+        match Self::new_internal(capacity, Infallible) {
             Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
-            Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e),
+            Err(CollectionAllocErr::AllocErr) => unreachable!(),
             Ok(table) => { table }
         }
     }
@@ -905,7 +883,7 @@
     marker: marker::PhantomData<&'a ()>,
 }
 
-// FIXME(#19839) Remove in favor of `#[derive(Clone)]`
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
 impl<'a, K, V> Clone for RawBuckets<'a, K, V> {
     fn clone(&self) -> RawBuckets<'a, K, V> {
         RawBuckets {
@@ -956,7 +934,7 @@
 unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {}
 unsafe impl<'a, K: Sync, V: Sync> Send for Iter<'a, K, V> {}
 
-// FIXME(#19839) Remove in favor of `#[derive(Clone)]`
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
 impl<'a, K, V> Clone for Iter<'a, K, V> {
     fn clone(&self) -> Iter<'a, K, V> {
         Iter {
@@ -1113,7 +1091,7 @@
 
 impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
     fn drop(&mut self) {
-        for _ in self {}
+        self.for_each(drop);
     }
 }
 
@@ -1162,18 +1140,10 @@
             }
         }
 
-        let hashes_size = self.capacity() * size_of::<HashUint>();
-        let pairs_size = self.capacity() * size_of::<(K, V)>();
-        let (align, size, oflo) = calculate_allocation(hashes_size,
-                                                       align_of::<HashUint>(),
-                                                       pairs_size,
-                                                       align_of::<(K, V)>());
-
-        debug_assert!(!oflo, "should be impossible");
-
+        let (layout, _) = calculate_layout::<K, V>(self.capacity())
+            .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
         unsafe {
-            Heap.dealloc(self.hashes.ptr() as *mut u8,
-                         Layout::from_size_align(size, align).unwrap());
+            Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout);
             // Remember how everything was allocated out of one buffer
             // during initialization? We only need one call to free here.
         }
diff --git a/sgx_tstd/src/collections/mod.rs b/sgx_tstd/src/collections/mod.rs
index 0dca51e..676248a 100644
--- a/sgx_tstd/src/collections/mod.rs
+++ b/sgx_tstd/src/collections/mod.rs
@@ -35,20 +35,21 @@
 //!
 
 pub use ops::Bound;
-pub use alloc::{BinaryHeap, BTreeMap, BTreeSet};
-pub use alloc::{LinkedList, VecDeque};
-pub use alloc::{binary_heap, btree_map, btree_set};
-pub use alloc::{linked_list, vec_deque};
+pub use alloc::collections::{BinaryHeap,BTreeMap, BTreeSet};
+pub use alloc::collections::{LinkedList, VecDeque};
+pub use alloc::collections::{binary_heap, btree_map, btree_set};
+pub use alloc::collections::{linked_list, vec_deque};
 
 pub use self::hash_map::HashMap;
 pub use self::hash_set::HashSet;
 
+
 /// Range syntax
 pub mod range {
     pub use ops::RangeBounds as RangeArgument;
 }
 
-pub use alloc::allocator::CollectionAllocErr;
+pub use alloc::collections::CollectionAllocErr;
 
 mod hash;
 
@@ -60,4 +61,4 @@
 pub mod hash_set {
     //! A hash set implemented as a `HashMap` where the value is `()`.
     pub use super::hash::set::*;
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/error.rs b/sgx_tstd/src/error.rs
index 642b18d..b17fc0c 100644
--- a/sgx_tstd/src/error.rs
+++ b/sgx_tstd/src/error.rs
@@ -26,7 +26,6 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-use alloc::allocator;
 use core::any::TypeId;
 use core::cell;
 use core::mem::transmute;
@@ -37,7 +36,8 @@
 use alloc::string::{self, String};
 use alloc::boxed::Box;
 use alloc::borrow::Cow;
-use std_unicode::char;
+use alloc::alloc;
+use core::char;
 
 /// Base functionality for all errors in Rust.
 pub trait Error: Debug + Display {
@@ -120,15 +120,15 @@
     fn description(&self) -> &str { *self }
 }
 
-impl Error for allocator::AllocErr {
+impl Error for alloc::AllocErr {
     fn description(&self) -> &str {
-        allocator::AllocErr::description(self)
+        "memory allocation failed"
     }
 }
 
-impl Error for allocator::CannotReallocInPlace {
+impl Error for alloc::CannotReallocInPlace {
     fn description(&self) -> &str {
-        allocator::CannotReallocInPlace::description(self)
+        alloc::CannotReallocInPlace::description(self)
     }
 }
 
diff --git a/sgx_tstd/src/f32.rs b/sgx_tstd/src/f32.rs
index eaaf7cf..21b1b90 100644
--- a/sgx_tstd/src/f32.rs
+++ b/sgx_tstd/src/f32.rs
@@ -29,14 +29,13 @@
 //! This module provides constants which are specific to the implementation
 //! of the `f32` floating point data type.
 //!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
+//! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
 //!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
 
 #![allow(missing_docs)]
 
-use core::num;
-use core::intrinsics;
-use core::num::FpCategory;
+use intrinsics;
 use sys::cmath;
 
 pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON};
@@ -45,104 +44,12 @@
 pub use core::f32::{MIN, MIN_POSITIVE, MAX};
 pub use core::f32::consts;
 
-#[lang = "f32"]
+#[lang = "f32_runtime"]
 impl f32 {
-    /// Returns `true` if this value is `NaN` and false otherwise.
-    ///
-    /// ```
-    /// use std::f32;
-    ///
-    /// let nan = f32::NAN;
-    /// let f = 7.0_f32;
-    ///
-    /// assert!(nan.is_nan());
-    /// assert!(!f.is_nan());
-    /// ```
-    #[inline]
-    pub fn is_nan(self) -> bool { num::Float::is_nan(self) }
-
-    /// Returns `true` if this value is positive infinity or negative infinity and
-    /// false otherwise.
-    ///
-    /// ```
-    /// use std::f32;
-    ///
-    /// let f = 7.0f32;
-    /// let inf = f32::INFINITY;
-    /// let neg_inf = f32::NEG_INFINITY;
-    /// let nan = f32::NAN;
-    ///
-    /// assert!(!f.is_infinite());
-    /// assert!(!nan.is_infinite());
-    ///
-    /// assert!(inf.is_infinite());
-    /// assert!(neg_inf.is_infinite());
-    /// ```
-    #[inline]
-    pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) }
-
-    /// Returns `true` if this number is neither infinite nor `NaN`.
-    ///
-    /// ```
-    /// use std::f32;
-    ///
-    /// let f = 7.0f32;
-    /// let inf = f32::INFINITY;
-    /// let neg_inf = f32::NEG_INFINITY;
-    /// let nan = f32::NAN;
-    ///
-    /// assert!(f.is_finite());
-    ///
-    /// assert!(!nan.is_finite());
-    /// assert!(!inf.is_finite());
-    /// assert!(!neg_inf.is_finite());
-    /// ```
-    #[inline]
-    pub fn is_finite(self) -> bool { num::Float::is_finite(self) }
-
-    /// Returns `true` if the number is neither zero, infinite,
-    /// [subnormal][subnormal], or `NaN`.
-    ///
-    /// ```
-    /// use std::f32;
-    ///
-    /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
-    /// let max = f32::MAX;
-    /// let lower_than_min = 1.0e-40_f32;
-    /// let zero = 0.0_f32;
-    ///
-    /// assert!(min.is_normal());
-    /// assert!(max.is_normal());
-    ///
-    /// assert!(!zero.is_normal());
-    /// assert!(!f32::NAN.is_normal());
-    /// assert!(!f32::INFINITY.is_normal());
-    /// // Values between `0` and `min` are Subnormal.
-    /// assert!(!lower_than_min.is_normal());
-    /// ```
-    /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
-    #[inline]
-    pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
-
-    /// Returns the floating point category of the number. If only one property
-    /// is going to be tested, it is generally faster to use the specific
-    /// predicate instead.
-    ///
-    /// ```
-    /// use std::num::FpCategory;
-    /// use std::f32;
-    ///
-    /// let num = 12.4_f32;
-    /// let inf = f32::INFINITY;
-    ///
-    /// assert_eq!(num.classify(), FpCategory::Normal);
-    /// assert_eq!(inf.classify(), FpCategory::Infinite);
-    /// ```
-    #[inline]
-    pub fn classify(self) -> FpCategory { num::Float::classify(self) }
-
     /// Returns the largest integer less than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.99_f32;
     /// let g = 3.0_f32;
@@ -173,6 +80,8 @@
 
     /// Returns the smallest integer greater than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.01_f32;
     /// let g = 4.0_f32;
@@ -192,6 +101,8 @@
     /// Returns the nearest integer to a number. Round half-way cases away from
     /// `0.0`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f32;
     /// let g = -3.3_f32;
@@ -206,6 +117,8 @@
 
     /// Returns the integer part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f32;
     /// let g = -3.7_f32;
@@ -220,6 +133,8 @@
 
     /// Returns the fractional part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -237,6 +152,8 @@
     /// Computes the absolute value of `self`. Returns `NAN` if the
     /// number is `NAN`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -252,7 +169,9 @@
     /// assert!(f32::NAN.abs().is_nan());
     /// ```
     #[inline]
-    pub fn abs(self) -> f32 { num::Float::abs(self) }
+    pub fn abs(self) -> f32 {
+        unsafe { intrinsics::fabsf32(self) }
+    }
 
     /// Returns a number that represents the sign of `self`.
     ///
@@ -260,6 +179,8 @@
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
     /// - `NAN` if the number is `NAN`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -271,37 +192,21 @@
     /// assert!(f32::NAN.signum().is_nan());
     /// ```
     #[inline]
-    pub fn signum(self) -> f32 { num::Float::signum(self) }
-
-    /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
-    /// positive sign bit and positive infinity.
-    ///
-    /// ```
-    /// let f = 7.0_f32;
-    /// let g = -7.0_f32;
-    ///
-    /// assert!(f.is_sign_positive());
-    /// assert!(!g.is_sign_positive());
-    /// ```
-    #[inline]
-    pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
-    /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
-    /// negative sign bit and negative infinity.
-    ///
-    /// ```
-    /// let f = 7.0f32;
-    /// let g = -7.0f32;
-    ///
-    /// assert!(!f.is_sign_negative());
-    /// assert!(g.is_sign_negative());
-    /// ```
-    #[inline]
-    pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) }
+    pub fn signum(self) -> f32 {
+        if self.is_nan() {
+            NAN
+        } else {
+            unsafe { intrinsics::copysignf32(1.0, self) }
+        }
+    }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` can be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction.
+    ///
+    /// # Examples
     ///
     /// ```
     /// use std::f32;
@@ -320,23 +225,65 @@
         unsafe { intrinsics::fmaf32(self, a, b) }
     }
 
-    /// Takes the reciprocal (inverse) of a number, `1/x`.
+    /// Calculates Euclidean division, the matching method for `mod_euc`.
+    ///
+    /// This computes the integer `n` such that
+    /// `self = n * rhs + self.mod_euc(rhs)`.
+    /// In other words, the result is `self / rhs` rounded to the integer `n`
+    /// such that `self >= n * rhs`.
+    ///
+    /// # Examples
     ///
     /// ```
-    /// use std::f32;
-    ///
-    /// let x = 2.0_f32;
-    /// let abs_difference = (x.recip() - (1.0/x)).abs();
-    ///
-    /// assert!(abs_difference <= f32::EPSILON);
+    /// #![feature(euclidean_division)]
+    /// let a: f32 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0
+    /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0
+    /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0
+    /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0
     /// ```
     #[inline]
-    pub fn recip(self) -> f32 { num::Float::recip(self) }
+    pub fn div_euc(self, rhs: f32) -> f32 {
+        let q = (self / rhs).trunc();
+        if self % rhs < 0.0 {
+            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }
+        }
+        q
+    }
+
+    /// Calculates the Euclidean modulo (self mod rhs), which is never negative.
+    ///
+    /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(euclidean_division)]
+    /// let a: f32 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.mod_euc(b), 3.0);
+    /// assert_eq!((-a).mod_euc(b), 1.0);
+    /// assert_eq!(a.mod_euc(-b), 3.0);
+    /// assert_eq!((-a).mod_euc(-b), 1.0);
+    /// ```
+    #[inline]
+    pub fn mod_euc(self, rhs: f32) -> f32 {
+        let r = self % rhs;
+        if r < 0.0 {
+            r + rhs.abs()
+        } else {
+            r
+        }
+    }
+
 
     /// Raises a number to an integer power.
     ///
     /// Using this function is generally faster than using `powf`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -346,10 +293,14 @@
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[inline]
-    pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) }
+    pub fn powi(self, n: i32) -> f32 {
+        unsafe { intrinsics::powif32(self, n) }
+    }
 
     /// Raises a number to a floating point power.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -371,6 +322,8 @@
     ///
     /// Returns NaN if `self` is a negative number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -393,6 +346,8 @@
 
     /// Returns `e^(self)`, (the exponential function).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -416,6 +371,8 @@
 
     /// Returns `2^(self)`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -433,6 +390,8 @@
 
     /// Returns the natural logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -460,6 +419,8 @@
     /// `self.log2()` can produce more accurate results for base 2, and
     /// `self.log10()` can produce more accurate results for base 10.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -475,6 +436,8 @@
 
     /// Returns the base 2 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -495,6 +458,8 @@
 
     /// Returns the base 10 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -514,89 +479,10 @@
         return unsafe { intrinsics::log10f32(self) };
     }
 
-    /// Converts radians to degrees.
-    ///
-    /// ```
-    /// use std::f32::{self, consts};
-    ///
-    /// let angle = consts::PI;
-    ///
-    /// let abs_difference = (angle.to_degrees() - 180.0).abs();
-    ///
-    /// assert!(abs_difference <= f32::EPSILON);
-    /// ```
-    #[inline]
-    pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
-
-    /// Converts degrees to radians.
-    ///
-    /// ```
-    /// use std::f32::{self, consts};
-    ///
-    /// let angle = 180.0f32;
-    ///
-    /// let abs_difference = (angle.to_radians() - consts::PI).abs();
-    ///
-    /// assert!(abs_difference <= f32::EPSILON);
-    /// ```
-    #[inline]
-    pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
-
-    /// Returns the maximum of the two numbers.
-    ///
-    /// ```
-    /// let x = 1.0f32;
-    /// let y = 2.0f32;
-    ///
-    /// assert_eq!(x.max(y), y);
-    /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
-
-    #[inline]
-    pub fn max(self, other: f32) -> f32 {
-        num::Float::max(self, other)
-    }
-
-    /// Returns the minimum of the two numbers.
-    ///
-    /// ```
-    /// let x = 1.0f32;
-    /// let y = 2.0f32;
-    ///
-    /// assert_eq!(x.min(y), x);
-    /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
-    #[inline]
-    pub fn min(self, other: f32) -> f32 {
-        num::Float::min(self, other)
-    }
-
-    /// The positive difference of two numbers.
-    ///
-    /// * If `self <= other`: `0:0`
-    /// * Else: `self - other`
-    ///
-    /// ```
-    /// use std::f32;
-    ///
-    /// let x = 3.0f32;
-    /// let y = -3.0f32;
-    ///
-    /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
-    /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
-    ///
-    /// assert!(abs_difference_x <= f32::EPSILON);
-    /// assert!(abs_difference_y <= f32::EPSILON);
-    /// ```
-    #[inline]
-    pub fn abs_sub(self, other: f32) -> f32 {
-        unsafe { cmath::fdimf(self, other) }
-    }
-
     /// Takes the cubic root of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -615,6 +501,8 @@
     /// Calculates the length of the hypotenuse of a right-angle triangle given
     /// legs of length `x` and `y`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -633,6 +521,8 @@
 
     /// Computes the sine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -653,6 +543,8 @@
 
     /// Computes the cosine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -673,6 +565,8 @@
 
     /// Computes the tangent of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -690,6 +584,8 @@
     /// the range [-pi/2, pi/2] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -709,6 +605,8 @@
     /// the range [0, pi] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -727,6 +625,8 @@
     /// Computes the arctangent of a number. Return value is in radians in the
     /// range [-pi/2, pi/2];
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -749,6 +649,8 @@
     /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
     /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -777,6 +679,8 @@
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
     /// `(sin(x), cos(x))`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -797,6 +701,8 @@
     /// Returns `e^(self) - 1` in a way that is accurate even if the
     /// number is close to zero.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -815,6 +721,8 @@
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
     /// the operations were performed separately.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -832,6 +740,8 @@
 
     /// Hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -852,6 +762,8 @@
 
     /// Hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -872,6 +784,8 @@
 
     /// Hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -892,6 +806,8 @@
 
     /// Inverse hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -913,6 +829,8 @@
 
     /// Inverse hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -933,6 +851,8 @@
 
     /// Inverse hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f32;
     ///
@@ -947,54 +867,4 @@
     pub fn atanh(self) -> f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
-
-    /// Raw transmutation to `u32`.
-    ///
-    /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
-    ///
-    /// See `from_bits` for some discussion of the portability of this operation
-    /// (there are almost no issues).
-    ///
-    /// Note that this function is distinct from `as` casting, which attempts to
-    /// preserve the *numeric* value, and not the bitwise value.
-    ///
-    #[inline]
-    pub fn to_bits(self) -> u32 {
-        num::Float::to_bits(self)
-    }
-
-    /// Raw transmutation from `u32`.
-    ///
-    /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms.
-    /// It turns out this is incredibly portable, for two reasons:
-    ///
-    /// * Floats and Ints have the same endianness on all supported platforms.
-    /// * IEEE-754 very precisely specifies the bit layout of floats.
-    ///
-    /// However there is one caveat: prior to the 2008 version of IEEE-754, how
-    /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
-    /// (notably x86 and ARM) picked the interpretation that was ultimately
-    /// standardized in 2008, but some didn't (notably MIPS). As a result, all
-    /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
-    ///
-    /// Rather than trying to preserve signaling-ness cross-platform, this
-    /// implementation favours preserving the exact bits. This means that
-    /// any payloads encoded in NaNs will be preserved even if the result of
-    /// this method is sent over the network from an x86 machine to a MIPS one.
-    ///
-    /// If the results of this method are only manipulated by the same
-    /// architecture that produced them, then there is no portability concern.
-    ///
-    /// If the input isn't NaN, then there is no portability concern.
-    ///
-    /// If you don't care about signalingness (very likely), then there is no
-    /// portability concern.
-    ///
-    /// Note that this function is distinct from `as` casting, which attempts to
-    /// preserve the *numeric* value, and not the bitwise value.
-    ///
-    #[inline]
-    pub fn from_bits(v: u32) -> Self {
-        num::Float::from_bits(v)
-    }
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/f64.rs b/sgx_tstd/src/f64.rs
index 551354b..88fc88e 100644
--- a/sgx_tstd/src/f64.rs
+++ b/sgx_tstd/src/f64.rs
@@ -29,14 +29,13 @@
 //! This module provides constants which are specific to the implementation
 //! of the `f64` floating point data type.
 //!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
+//! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
 //!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
 
 #![allow(missing_docs)]
 
-use core::num;
-use core::intrinsics;
-use core::num::FpCategory;
+use intrinsics;
 use sys::cmath;
 
 pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON};
@@ -45,104 +44,12 @@
 pub use core::f64::{MIN, MIN_POSITIVE, MAX};
 pub use core::f64::consts;
 
-#[lang = "f64"]
+#[lang = "f64_runtime"]
 impl f64 {
-    /// Returns `true` if this value is `NaN` and false otherwise.
-    ///
-    /// ```
-    /// use std::f64;
-    ///
-    /// let nan = f64::NAN;
-    /// let f = 7.0_f64;
-    ///
-    /// assert!(nan.is_nan());
-    /// assert!(!f.is_nan());
-    /// ```
-    #[inline]
-    pub fn is_nan(self) -> bool { num::Float::is_nan(self) }
-
-    /// Returns `true` if this value is positive infinity or negative infinity and
-    /// false otherwise.
-    ///
-    /// ```
-    /// use std::f64;
-    ///
-    /// let f = 7.0f64;
-    /// let inf = f64::INFINITY;
-    /// let neg_inf = f64::NEG_INFINITY;
-    /// let nan = f64::NAN;
-    ///
-    /// assert!(!f.is_infinite());
-    /// assert!(!nan.is_infinite());
-    ///
-    /// assert!(inf.is_infinite());
-    /// assert!(neg_inf.is_infinite());
-    /// ```
-    #[inline]
-    pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) }
-
-    /// Returns `true` if this number is neither infinite nor `NaN`.
-    ///
-    /// ```
-    /// use std::f64;
-    ///
-    /// let f = 7.0f64;
-    /// let inf: f64 = f64::INFINITY;
-    /// let neg_inf: f64 = f64::NEG_INFINITY;
-    /// let nan: f64 = f64::NAN;
-    ///
-    /// assert!(f.is_finite());
-    ///
-    /// assert!(!nan.is_finite());
-    /// assert!(!inf.is_finite());
-    /// assert!(!neg_inf.is_finite());
-    /// ```
-    #[inline]
-    pub fn is_finite(self) -> bool { num::Float::is_finite(self) }
-
-    /// Returns `true` if the number is neither zero, infinite,
-    /// [subnormal][subnormal], or `NaN`.
-    ///
-    /// ```
-    /// use std::f64;
-    ///
-    /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
-    /// let max = f64::MAX;
-    /// let lower_than_min = 1.0e-308_f64;
-    /// let zero = 0.0f64;
-    ///
-    /// assert!(min.is_normal());
-    /// assert!(max.is_normal());
-    ///
-    /// assert!(!zero.is_normal());
-    /// assert!(!f64::NAN.is_normal());
-    /// assert!(!f64::INFINITY.is_normal());
-    /// // Values between `0` and `min` are Subnormal.
-    /// assert!(!lower_than_min.is_normal());
-    /// ```
-    /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
-    #[inline]
-    pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
-
-    /// Returns the floating point category of the number. If only one property
-    /// is going to be tested, it is generally faster to use the specific
-    /// predicate instead.
-    ///
-    /// ```
-    /// use std::num::FpCategory;
-    /// use std::f64;
-    ///
-    /// let num = 12.4_f64;
-    /// let inf = f64::INFINITY;
-    ///
-    /// assert_eq!(num.classify(), FpCategory::Normal);
-    /// assert_eq!(inf.classify(), FpCategory::Infinite);
-    /// ```
-    #[inline]
-    pub fn classify(self) -> FpCategory { num::Float::classify(self) }
-
     /// Returns the largest integer less than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.99_f64;
     /// let g = 3.0_f64;
@@ -157,6 +64,8 @@
 
     /// Returns the smallest integer greater than or equal to a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.01_f64;
     /// let g = 4.0_f64;
@@ -172,6 +81,8 @@
     /// Returns the nearest integer to a number. Round half-way cases away from
     /// `0.0`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f64;
     /// let g = -3.3_f64;
@@ -186,6 +97,8 @@
 
     /// Returns the integer part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 3.3_f64;
     /// let g = -3.7_f64;
@@ -200,6 +113,8 @@
 
     /// Returns the fractional part of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 3.5_f64;
     /// let y = -3.5_f64;
@@ -215,6 +130,8 @@
     /// Computes the absolute value of `self`. Returns `NAN` if the
     /// number is `NAN`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -230,7 +147,9 @@
     /// assert!(f64::NAN.abs().is_nan());
     /// ```
     #[inline]
-    pub fn abs(self) -> f64 { num::Float::abs(self) }
+    pub fn abs(self) -> f64 {
+        unsafe { intrinsics::fabsf64(self) }
+    }
 
     /// Returns a number that represents the sign of `self`.
     ///
@@ -238,6 +157,8 @@
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
     /// - `NAN` if the number is `NAN`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -249,43 +170,21 @@
     /// assert!(f64::NAN.signum().is_nan());
     /// ```
     #[inline]
-    pub fn signum(self) -> f64 { num::Float::signum(self) }
-
-    /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
-    /// positive sign bit and positive infinity.
-    ///
-    /// ```
-    /// let f = 7.0_f64;
-    /// let g = -7.0_f64;
-    ///
-    /// assert!(f.is_sign_positive());
-    /// assert!(!g.is_sign_positive());
-    /// ```
-    #[inline]
-    pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
-    #[inline]
-    pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
-    /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
-    /// negative sign bit and negative infinity.
-    ///
-    /// ```
-    /// let f = 7.0_f64;
-    /// let g = -7.0_f64;
-    ///
-    /// assert!(!f.is_sign_negative());
-    /// assert!(g.is_sign_negative());
-    /// ```
-    #[inline]
-    pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) }
-
-    #[inline]
-    pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) }
+    pub fn signum(self) -> f64 {
+        if self.is_nan() {
+            NAN
+        } else {
+            unsafe { intrinsics::copysignf64(1.0, self) }
+        }
+    }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` can be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction.
+    ///
+    /// # Examples
     ///
     /// ```
     /// let m = 10.0_f64;
@@ -302,21 +201,64 @@
         unsafe { intrinsics::fmaf64(self, a, b) }
     }
 
-    /// Takes the reciprocal (inverse) of a number, `1/x`.
+    /// Calculates Euclidean division, the matching method for `mod_euc`.
+    ///
+    /// This computes the integer `n` such that
+    /// `self = n * rhs + self.mod_euc(rhs)`.
+    /// In other words, the result is `self / rhs` rounded to the integer `n`
+    /// such that `self >= n * rhs`.
+    ///
+    /// # Examples
     ///
     /// ```
-    /// let x = 2.0_f64;
-    /// let abs_difference = (x.recip() - (1.0/x)).abs();
-    ///
-    /// assert!(abs_difference < 1e-10);
+    /// #![feature(euclidean_division)]
+    /// let a: f64 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0
+    /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0
+    /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0
+    /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0
     /// ```
     #[inline]
-    pub fn recip(self) -> f64 { num::Float::recip(self) }
+    pub fn div_euc(self, rhs: f64) -> f64 {
+        let q = (self / rhs).trunc();
+        if self % rhs < 0.0 {
+            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }
+        }
+        q
+    }
+
+    /// Calculates the Euclidean modulo (self mod rhs), which is never negative.
+    ///
+    /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(euclidean_division)]
+    /// let a: f64 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.mod_euc(b), 3.0);
+    /// assert_eq!((-a).mod_euc(b), 1.0);
+    /// assert_eq!(a.mod_euc(-b), 3.0);
+    /// assert_eq!((-a).mod_euc(-b), 1.0);
+    /// ```
+    #[inline]
+    pub fn mod_euc(self, rhs: f64) -> f64 {
+        let r = self % rhs;
+        if r < 0.0 {
+            r + rhs.abs()
+        } else {
+            r
+        }
+    }
 
     /// Raises a number to an integer power.
     ///
     /// Using this function is generally faster than using `powf`
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 2.0_f64;
     /// let abs_difference = (x.powi(2) - x*x).abs();
@@ -324,10 +266,14 @@
     /// assert!(abs_difference < 1e-10);
     /// ```
     #[inline]
-    pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) }
+    pub fn powi(self, n: i32) -> f64 {
+        unsafe { intrinsics::powif64(self, n) }
+    }
 
     /// Raises a number to a floating point power.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 2.0_f64;
     /// let abs_difference = (x.powf(2.0) - x*x).abs();
@@ -343,6 +289,8 @@
     ///
     /// Returns NaN if `self` is a negative number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let positive = 4.0_f64;
     /// let negative = -4.0_f64;
@@ -363,6 +311,8 @@
 
     /// Returns `e^(self)`, (the exponential function).
     ///
+    /// # Examples
+    ///
     /// ```
     /// let one = 1.0_f64;
     /// // e^1
@@ -380,6 +330,8 @@
 
     /// Returns `2^(self)`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 2.0_f64;
     ///
@@ -395,6 +347,8 @@
 
     /// Returns the natural logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let one = 1.0_f64;
     /// // e^1
@@ -416,6 +370,8 @@
     /// `self.log2()` can produce more accurate results for base 2, and
     /// `self.log10()` can produce more accurate results for base 10.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let five = 5.0_f64;
     ///
@@ -429,6 +385,8 @@
 
     /// Returns the base 2 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let two = 2.0_f64;
     ///
@@ -440,12 +398,17 @@
     #[inline]
     pub fn log2(self) -> f64 {
         self.log_wrapper(|n| {
+            #[cfg(target_os = "android")]
+            return ::sys::android::log2f64(n);
+            #[cfg(not(target_os = "android"))]
             return unsafe { intrinsics::log2f64(n) };
         })
     }
 
     /// Returns the base 10 logarithm of the number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let ten = 10.0_f64;
     ///
@@ -459,86 +422,10 @@
         self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } })
     }
 
-    /// Converts radians to degrees.
-    ///
-    /// ```
-    /// use std::f64::consts;
-    ///
-    /// let angle = consts::PI;
-    ///
-    /// let abs_difference = (angle.to_degrees() - 180.0).abs();
-    ///
-    /// assert!(abs_difference < 1e-10);
-    /// ```
-    #[inline]
-    pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) }
-
-    /// Converts degrees to radians.
-    ///
-    /// ```
-    /// use std::f64::consts;
-    ///
-    /// let angle = 180.0_f64;
-    ///
-    /// let abs_difference = (angle.to_radians() - consts::PI).abs();
-    ///
-    /// assert!(abs_difference < 1e-10);
-    /// ```
-    #[inline]
-    pub fn to_radians(self) -> f64 { num::Float::to_radians(self) }
-
-    /// Returns the maximum of the two numbers.
-    ///
-    /// ```
-    /// let x = 1.0_f64;
-    /// let y = 2.0_f64;
-    ///
-    /// assert_eq!(x.max(y), y);
-    /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
-    #[inline]
-    pub fn max(self, other: f64) -> f64 {
-        num::Float::max(self, other)
-    }
-
-    /// Returns the minimum of the two numbers.
-    ///
-    /// ```
-    /// let x = 1.0_f64;
-    /// let y = 2.0_f64;
-    ///
-    /// assert_eq!(x.min(y), x);
-    /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
-    #[inline]
-    pub fn min(self, other: f64) -> f64 {
-        num::Float::min(self, other)
-    }
-
-    /// The positive difference of two numbers.
-    ///
-    /// * If `self <= other`: `0:0`
-    /// * Else: `self - other`
-    ///
-    /// ```
-    /// let x = 3.0_f64;
-    /// let y = -3.0_f64;
-    ///
-    /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
-    /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
-    ///
-    /// assert!(abs_difference_x < 1e-10);
-    /// assert!(abs_difference_y < 1e-10);
-    /// ```
-    #[inline]
-     pub fn abs_sub(self, other: f64) -> f64 {
-         unsafe { cmath::fdim(self, other) }
-     }
-
     /// Takes the cubic root of a number.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 8.0_f64;
     ///
@@ -555,6 +442,8 @@
     /// Calculates the length of the hypotenuse of a right-angle triangle given
     /// legs of length `x` and `y`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 2.0_f64;
     /// let y = 3.0_f64;
@@ -571,6 +460,8 @@
 
     /// Computes the sine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -587,6 +478,8 @@
 
     /// Computes the cosine of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -603,6 +496,8 @@
 
     /// Computes the tangent of a number (in radians).
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -620,6 +515,8 @@
     /// the range [-pi/2, pi/2] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -639,6 +536,8 @@
     /// the range [0, pi] or NaN if the number is outside the range
     /// [-1, 1].
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -657,6 +556,8 @@
     /// Computes the arctangent of a number. Return value is in radians in the
     /// range [-pi/2, pi/2];
     ///
+    /// # Examples
+    ///
     /// ```
     /// let f = 1.0_f64;
     ///
@@ -677,6 +578,8 @@
     /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
     /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -705,6 +608,8 @@
     /// Simultaneously computes the sine and cosine of the number, `x`. Returns
     /// `(sin(x), cos(x))`.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -725,6 +630,8 @@
     /// Returns `e^(self) - 1` in a way that is accurate even if the
     /// number is close to zero.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 7.0_f64;
     ///
@@ -741,6 +648,8 @@
     /// Returns `ln(1+n)` (natural logarithm) more accurately than if
     /// the operations were performed separately.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -758,6 +667,8 @@
 
     /// Hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -778,6 +689,8 @@
 
     /// Hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -798,6 +711,8 @@
 
     /// Hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -818,6 +733,8 @@
 
     /// Inverse hyperbolic sine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 1.0_f64;
     /// let f = x.sinh().asinh();
@@ -837,6 +754,8 @@
 
     /// Inverse hyperbolic cosine function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// let x = 1.0_f64;
     /// let f = x.cosh().acosh();
@@ -855,6 +774,8 @@
 
     /// Inverse hyperbolic tangent function.
     ///
+    /// # Examples
+    ///
     /// ```
     /// use std::f64;
     ///
@@ -894,54 +815,4 @@
             }
         }
     }
-
-    /// Raw transmutation to `u64`.
-    ///
-    /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
-    ///
-    /// See `from_bits` for some discussion of the portability of this operation
-    /// (there are almost no issues).
-    ///
-    /// Note that this function is distinct from `as` casting, which attempts to
-    /// preserve the *numeric* value, and not the bitwise value.
-    ///
-    #[inline]
-    pub fn to_bits(self) -> u64 {
-        num::Float::to_bits(self)
-    }
-
-    /// Raw transmutation from `u64`.
-    ///
-    /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms.
-    /// It turns out this is incredibly portable, for two reasons:
-    ///
-    /// * Floats and Ints have the same endianness on all supported platforms.
-    /// * IEEE-754 very precisely specifies the bit layout of floats.
-    ///
-    /// However there is one caveat: prior to the 2008 version of IEEE-754, how
-    /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
-    /// (notably x86 and ARM) picked the interpretation that was ultimately
-    /// standardized in 2008, but some didn't (notably MIPS). As a result, all
-    /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
-    ///
-    /// Rather than trying to preserve signaling-ness cross-platform, this
-    /// implementation favours preserving the exact bits. This means that
-    /// any payloads encoded in NaNs will be preserved even if the result of
-    /// this method is sent over the network from an x86 machine to a MIPS one.
-    ///
-    /// If the results of this method are only manipulated by the same
-    /// architecture that produced them, then there is no portability concern.
-    ///
-    /// If the input isn't NaN, then there is no portability concern.
-    ///
-    /// If you don't care about signalingness (very likely), then there is no
-    /// portability concern.
-    ///
-    /// Note that this function is distinct from `as` casting, which attempts to
-    /// preserve the *numeric* value, and not the bitwise value.
-    ///
-    #[inline]
-    pub fn from_bits(v: u64) -> Self {
-        num::Float::from_bits(v)
-    }
 }
diff --git a/sgx_tstd/src/ffi/os_str.rs b/sgx_tstd/src/ffi/os_str.rs
index ab1be9e..1e97bdf 100644
--- a/sgx_tstd/src/ffi/os_str.rs
+++ b/sgx_tstd/src/ffi/os_str.rs
@@ -36,7 +36,7 @@
 use alloc::string::String;
 use alloc::boxed::Box;
 use alloc::rc::Rc;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 
 
 /// A type that can represent owned, mutable platform-native strings, but is
@@ -538,4 +538,4 @@
     fn as_inner(&self) -> &Slice {
         &self.inner
     }
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/io/lazy.rs b/sgx_tstd/src/io/lazy.rs
index ca4b293..aae8245 100644
--- a/sgx_tstd/src/io/lazy.rs
+++ b/sgx_tstd/src/io/lazy.rs
@@ -28,7 +28,7 @@
 
 use sync::SgxThreadMutex;
 use sys_common;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 use core::cell::{Cell, UnsafeCell};
 use core::ptr;
 
@@ -158,4 +158,4 @@
         *self.opt.get() = Some(ret.clone());
         ret
     }
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/io/stdio.rs b/sgx_tstd/src/io/stdio.rs
index c101b04..326e015 100644
--- a/sgx_tstd/src/io/stdio.rs
+++ b/sgx_tstd/src/io/stdio.rs
@@ -33,7 +33,7 @@
 use sys::stdio;
 use core::cell::RefCell;
 use core::fmt;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 
 /// A handle to a raw instance of the standard input stream of this process.
 ///
@@ -476,4 +476,4 @@
 pub fn _eprint(args: fmt::Arguments) {
 
     print_to(args, stderr, "stderr");
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/lib.rs b/sgx_tstd/src/lib.rs
index 33ee1f2..89e74ae 100644
--- a/sgx_tstd/src/lib.rs
+++ b/sgx_tstd/src/lib.rs
@@ -51,7 +51,6 @@
 #![allow(dead_code)]
 
 #![feature(alloc)]
-#![feature(global_allocator)]
 #![feature(allocator_api)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
@@ -74,7 +73,6 @@
 #![feature(hashmap_internals)]
 #![feature(integer_atomics)]
 #![feature(lang_items)]
-#![feature(macro_reexport)]
 #![feature(macro_vis_matcher)]
 #![feature(nonzero)]
 #![feature(needs_panic_runtime)]
@@ -102,6 +100,12 @@
 #![feature(panic_unwind)]
 #![feature(libc)]
 #![feature(panic_internals)]
+#![feature(std_internals)]
+#![feature(panic_info_message)]
+#![feature(extern_prelude)]
+#![feature(use_extern_macros)]
+#![feature(unicode_internals)]
+#![feature(panic_implementation)]
 
 #![default_lib_allocator]
 
@@ -116,18 +120,15 @@
 // We want to reexport a few macros from core but libcore has already been
 // imported by the compiler (via our #[no_std] attribute) In this case we just
 // add a new crate name so we can attach the reexports to it.
-#[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq,
-                 debug_assert_ne, unreachable, unimplemented, write, writeln, try)]
+pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq,debug_assert_ne, unreachable, unimplemented, write, writeln, try};
+
 #[macro_use]
 extern crate core as __core;
 
-#[allow(unused_imports)]
 #[macro_use]
-#[macro_reexport(vec, format)]
 extern crate alloc;
-extern crate std_unicode;
-//#[cfg(all(target_env = "sgx", feature = "backtrace"))]
-//extern crate libc;
+
+pub use core::unicode::*;
 
 // We always need an unwinder currently for backtraces
 #[cfg(feature = "backtrace")]
@@ -139,11 +140,13 @@
 
 extern crate sgx_alloc;
 #[macro_use]
-#[macro_reexport(cfg_if, __cfg_if_items, __cfg_if_apply)]
 extern crate sgx_types;
+pub use sgx_types::{cfg_if, __cfg_if_items, __cfg_if_apply};
+
 #[macro_use]
-#[macro_reexport(global_ctors_object, global_dtors_object)]
 extern crate sgx_trts;
+pub use sgx_trts::{global_ctors_object, global_dtors_object};
+
 extern crate sgx_tprotected_fs;
 
 // The standard macros that are not built-in to the compiler.
@@ -183,6 +186,7 @@
 pub use core::u32;
 pub use core::u64;
 pub use core::u128;
+pub use core::char;
 pub use alloc::boxed;
 pub use alloc::rc;
 pub use alloc::borrow;
@@ -191,7 +195,7 @@
 pub use alloc::str;
 pub use alloc::string;
 pub use alloc::vec;
-pub use std_unicode::char;
+pub use alloc::format;
 
 pub mod f32;
 pub mod f64;
@@ -214,7 +218,7 @@
 pub mod path;
 pub mod sync;
 pub mod time;
-pub mod heap;
+//pub mod heap;
 pub mod enclave;
 pub mod untrusted;
 
@@ -239,5 +243,4 @@
 pub use cpuid::*;
 pub use self::thread::{rsgx_thread_self, rsgx_thread_equal};
 
-
-
+pub use sgx_trts::oom::rust_oom;
diff --git a/sgx_tstd/src/num.rs b/sgx_tstd/src/num.rs
index 3141687..b58b32e 100644
--- a/sgx_tstd/src/num.rs
+++ b/sgx_tstd/src/num.rs
@@ -38,6 +38,6 @@
 
 #[allow(deprecated)]
 pub use core::num::{
-    NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32,
-    NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize,
-};
\ No newline at end of file
+    NonZeroU8, NonZeroU16, NonZeroU32,
+    NonZeroU64, NonZeroU128, NonZeroUsize,
+};
diff --git a/sgx_tstd/src/panic.rs b/sgx_tstd/src/panic.rs
index 890f558..5f369eb 100644
--- a/sgx_tstd/src/panic.rs
+++ b/sgx_tstd/src/panic.rs
@@ -37,7 +37,7 @@
 use core::sync::atomic;
 use alloc::boxed::Box;
 use alloc::rc::Rc;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 
 pub use panicking::set_panic_handler;
 pub use core::panic::{PanicInfo, Location};
diff --git a/sgx_tstd/src/panicking.rs b/sgx_tstd/src/panicking.rs
index 792fcdd..bed699d 100644
--- a/sgx_tstd/src/panicking.rs
+++ b/sgx_tstd/src/panicking.rs
@@ -38,6 +38,7 @@
 use core::ptr;
 use core::raw;
 use core::sync::atomic::{AtomicPtr, Ordering};
+use core::panic::BoxMeUp;
 use alloc::boxed::Box;
 use alloc::string::String;
 
@@ -130,7 +131,7 @@
                                 data_ptr: *mut usize,
                                 vtable_ptr: *mut usize) -> u32;
     #[unwind(allowed)]
-    fn __rust_start_panic(data: usize, vtable: usize) -> u32;
+    fn __rust_start_panic(payload: usize) -> u32;
 }
 
 pub fn update_panic_count(amt: isize) -> usize {
@@ -215,7 +216,10 @@
     update_panic_count(0) != 0
 }
 
+use core::intrinsics;
+
 /// Entry point of panic from the libcore crate.
+#[cfg(stage0)]
 #[lang = "panic_fmt"]
 #[unwind(allowed)]
 pub extern fn rust_begin_panic(msg: fmt::Arguments,
@@ -225,12 +229,22 @@
     begin_panic_fmt(&msg, &(file, line, col))
 }
 
+/// Entry point of panic from the libcore crate.
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+#[panic_implementation]
+#[unwind(allowed)]
+pub fn rust_begin_panic(info: &PanicInfo) -> ! {
+    continue_panic_fmt(&info)
+}
+
 /// The entry point for panicking with a formatted message.
 ///
 /// This is designed to reduce the amount of code required at the call
 /// site as much as possible (so that `panic!()` has as low an impact
 /// on (e.g.) the inlining of other functions as possible), by moving
 /// the actual formatting into this shared place.
+#[cfg(stage0)]
 #[inline(never)] #[cold]
 pub fn begin_panic_fmt(msg: &fmt::Arguments,
                        file_line_col: &(&'static str, u32, u32)) -> ! {
@@ -248,6 +262,74 @@
     rust_panic_with_hook(Box::new(s), Some(msg), file_line_col)
 }
 
+// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update
+struct PanicPayload<'a> {
+    inner: &'a fmt::Arguments<'a>,
+    string: Option<String>,
+}
+
+impl<'a> PanicPayload<'a> {
+    fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
+        PanicPayload { inner, string: None }
+    }
+
+    fn fill(&mut self) -> &mut String {
+        use fmt::Write;
+
+        let inner = self.inner;
+        self.string.get_or_insert_with(|| {
+            let mut s = String::new();
+            drop(s.write_fmt(*inner));
+            s
+        })
+    }
+}
+
+unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
+    fn box_me_up(&mut self) -> *mut (Any + Send) {
+        let contents = mem::replace(self.fill(), String::new());
+        Box::into_raw(Box::new(contents))
+    }
+
+    fn get(&mut self) -> &(Any + Send) {
+        self.fill()
+    }
+}
+
+/// The entry point for panicking with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[cfg(not(stage0))]
+#[inline(never)] #[cold]
+pub fn begin_panic_fmt(msg: &fmt::Arguments,
+                       file_line_col: &(&'static str, u32, u32)) -> ! {
+    let (file, line, col) = *file_line_col;
+    let info = PanicInfo::internal_constructor(
+        Some(msg),
+        Location::internal_constructor(file, line, col),
+    );
+    continue_panic_fmt(&info)
+}
+
+#[cfg(not(stage0))]
+fn continue_panic_fmt(info: &PanicInfo) -> ! {
+    // We do two allocations here, unfortunately. But (a) they're
+    // required with the current scheme, and (b) we don't handle
+    // panic + OOM properly anyway (see comment in begin_panic
+    // below).
+
+    let loc = info.location().unwrap(); // The current implementation always returns Some
+    let msg = info.message().unwrap(); // The current implementation always returns Some
+    let file_line_col = (loc.file(), loc.line(), loc.column());
+    rust_panic_with_hook(
+        &mut PanicPayload::new(msg),
+        info.message(),
+        &file_line_col);
+}
+
 /// This is the entry point of panicking for panic!() and assert!().
 #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
 pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! {
@@ -258,7 +340,34 @@
     // be performed in the parent of this thread instead of the thread that's
     // panicking.
 
-    rust_panic_with_hook(Box::new(msg), None, file_line_col)
+    rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col);
+
+    struct PanicPayload<A> {
+        inner: Option<A>,
+    }
+
+    impl<A: Send + 'static> PanicPayload<A> {
+        fn new(inner: A) -> PanicPayload<A> {
+            PanicPayload { inner: Some(inner) }
+        }
+    }
+
+    unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
+        fn box_me_up(&mut self) -> *mut (Any + Send) {
+            let data = match self.inner.take() {
+                Some(a) => Box::new(a) as Box<Any + Send>,
+                None => Box::new(()),
+            };
+            Box::into_raw(data)
+        }
+
+        fn get(&mut self) -> &(Any + Send) {
+            match self.inner {
+                Some(ref a) => a,
+                None => &(),
+            }
+        }
+    }
 }
 
 /// Executes the primary logic for a panic, including checking for recursive
@@ -269,9 +378,9 @@
 /// run panic hooks, and then delegate to the actual implementation of panics.
 #[inline(never)]
 #[cold]
-fn rust_panic_with_hook(payload: Box<Any + Send>,
+fn rust_panic_with_hook(payload: &mut BoxMeUp,
                         message: Option<&fmt::Arguments>,
-                        file_line_col: &(&'static str, u32, u32)) -> ! {
+                        file_line_col: &(&str, u32, u32)) -> ! {
     let (file, line, col) = *file_line_col;
 
     let panics = update_panic_count(1);
@@ -289,9 +398,8 @@
 
     {
         let info = PanicInfo::internal_constructor(
-            &*payload,
             message,
-            Location::internal_constructor(file, line, col),
+			Location::internal_constructor(file, line, col),
         );
         panic_handler(&info);
     }
@@ -313,18 +421,32 @@
 /// Shim around rust_panic. Called by resume_unwind.
 pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! {
     update_panic_count(1);
-    rust_panic(msg)
+    struct RewrapBox(Box<Any + Send>);
+
+    unsafe impl BoxMeUp for RewrapBox {
+        fn box_me_up(&mut self) -> *mut (Any + Send) {
+            Box::into_raw(mem::replace(&mut self.0, Box::new(())))
+        }
+
+        fn get(&mut self) -> &(Any + Send) {
+            &*self.0
+        }
+    }
+
+    rust_panic(&mut RewrapBox(msg))
 }
 
 /// A private no-mangle function on which to slap yer breakpoints.
 #[no_mangle]
 #[allow(unused_variables)]
 #[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
-pub fn rust_panic(msg: Box<Any + Send>) -> ! {
+pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! {
     let code = unsafe {
-        let obj = mem::transmute::<_, raw::TraitObject>(msg);
-        __rust_start_panic(obj.data as usize, obj.vtable as usize)
+        let obj = &mut msg as *mut &mut BoxMeUp;
+        __rust_start_panic(obj as usize)
     };
     //rtabort!("failed to initiate panic, error {}", code)
     rsgx_abort()
 }
+
+
diff --git a/sgx_tstd/src/path.rs b/sgx_tstd/src/path.rs
index d60589a..8c7e0ce 100644
--- a/sgx_tstd/src/path.rs
+++ b/sgx_tstd/src/path.rs
@@ -49,7 +49,7 @@
 use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
 use alloc::borrow::{Borrow, Cow};
 use alloc::rc::Rc;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 use core::cmp;
 use core::fmt;
 use core::hash::{Hash, Hasher};
diff --git a/sgx_tstd/src/sync/condvar.rs b/sgx_tstd/src/sync/condvar.rs
index 252cc19..0c8aaf1 100644
--- a/sgx_tstd/src/sync/condvar.rs
+++ b/sgx_tstd/src/sync/condvar.rs
@@ -39,14 +39,14 @@
 //!
 use sgx_types::{self, SysError, sgx_thread_mutex_t, sgx_thread_cond_t, sgx_thread_condattr_t};
 use sgx_trts::libc;
-use sgx_trts::oom;
+use sgx_trts::trts::rsgx_abort;
 use super::mutex::{self, SgxThreadMutex, SgxMutexGuard};
 use sys_common::poison::{LockResult, PoisonError};
 use core::sync::atomic::{AtomicUsize, Ordering};
 use core::cell::UnsafeCell;
 use core::fmt;
 use core::mem;
-use alloc::heap::{AllocErr, Layout};
+use core::alloc::{AllocErr, Layout};
 use alloc::boxed::Box;
 
 pub unsafe fn raw_cond(lock: &mut sgx_thread_cond_t) -> * mut sgx_thread_cond_t {
@@ -379,9 +379,10 @@
             let ret = self.inner.broadcast();
             match ret {
                 Err(r) if r == libc::ENOMEM => {
-                    let layout = Layout::from_size_align(mem::size_of::<usize>(), 1).unwrap();
-                    let err = AllocErr::Exhausted { request: layout };
-                    oom::rsgx_oom(err)
+                    //let _layout = Layout::from_size_align(mem::size_of::<usize>(), 1).unwrap();
+                    //let err = AllocErr::Exhausted { request: layout };
+                    //oom::rsgx_oom(err)
+                    rsgx_abort()
                 },
                 _ => {},
             }
diff --git a/sgx_tstd/src/sync/mod.rs b/sgx_tstd/src/sync/mod.rs
index 245fae5..e47e0f5 100644
--- a/sgx_tstd/src/sync/mod.rs
+++ b/sgx_tstd/src/sync/mod.rs
@@ -38,7 +38,7 @@
 //! Synchronization library supports, as well as the OCALLs that each API function needs.
 //!
 
-pub use alloc::arc::{Arc, Weak};
+pub use alloc::sync::{Arc, Weak};
 pub use core::sync::atomic;
 
 pub use self::barrier::{Barrier, BarrierWaitResult};
diff --git a/sgx_tstd/src/sys/os_str.rs b/sgx_tstd/src/sys/os_str.rs
index bdb107b..b1512e9 100644
--- a/sgx_tstd/src/sys/os_str.rs
+++ b/sgx_tstd/src/sys/os_str.rs
@@ -35,9 +35,9 @@
 use alloc::vec::Vec;
 use alloc::boxed::Box;
 use alloc::rc::Rc;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 use sys_common::bytestring::debug_fmt_bytestring;
-use std_unicode::lossy::Utf8Lossy;
+use core::str::lossy::Utf8Lossy;
 
 #[derive(Clone, Hash)]
 pub struct Buf {
diff --git a/sgx_tstd/src/sys_common/bytestring.rs b/sgx_tstd/src/sys_common/bytestring.rs
index 2aa22d1..cfcdb50 100644
--- a/sgx_tstd/src/sys_common/bytestring.rs
+++ b/sgx_tstd/src/sys_common/bytestring.rs
@@ -29,7 +29,7 @@
 #![allow(dead_code)]
 
 use core::fmt::{Formatter, Result, Write};
-use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk};
+use core::str::lossy::{Utf8Lossy, Utf8LossyChunk};
 
 pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result {
     // Writes out a valid unicode string with the correct escape sequences
@@ -48,4 +48,4 @@
         }
     }
     f.write_str("\"")
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/sys_common/wtf8.rs b/sgx_tstd/src/sys_common/wtf8.rs
index 17d9f59..c8a8f80 100644
--- a/sgx_tstd/src/sys_common/wtf8.rs
+++ b/sgx_tstd/src/sys_common/wtf8.rs
@@ -34,7 +34,7 @@
 #![allow(dead_code)]
 
 use alloc::borrow::Cow;
-use std_unicode::char;
+use core::char;
 use core::str::next_code_point;
 use core::fmt;
 use core::hash::{Hash, Hasher};
@@ -44,7 +44,7 @@
 use core::str;
 use alloc::slice;
 use alloc::rc::Rc;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 use sys_common::AsInner;
 
 const UTF8_REPLACEMENT_CHARACTER: &'static str = "\u{FFFD}";
@@ -897,4 +897,4 @@
 
     pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
     pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/thread/mod.rs b/sgx_tstd/src/thread/mod.rs
index 0bfa919..efc5a8d 100644
--- a/sgx_tstd/src/thread/mod.rs
+++ b/sgx_tstd/src/thread/mod.rs
@@ -34,7 +34,7 @@
 use sync::{SgxMutex, SgxCondvar};
 use core::sync::atomic::AtomicUsize;
 use core::sync::atomic::Ordering::SeqCst;
-use alloc::arc::Arc;
+use alloc::sync::Arc;
 
 #[macro_use] mod local;
 pub use self::local::{LocalKey, LocalKeyInner, AccessError};
@@ -254,4 +254,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/sgx_tunittest/Cargo.toml b/sgx_tunittest/Cargo.toml
index c847232..e586008 100644
--- a/sgx_tunittest/Cargo.toml
+++ b/sgx_tunittest/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_tunittest"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_types/Cargo.toml b/sgx_types/Cargo.toml
index 0624307..d87c77a 100644
--- a/sgx_types/Cargo.toml
+++ b/sgx_types/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["Baidu"]
 name = "sgx_types"
-version = "1.0.0"
+version = "1.0.1"
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
 documentation = "https://dingelish.github.io/"
diff --git a/sgx_types/src/error.rs b/sgx_types/src/error.rs
index f33e4b8..6e4253a 100644
--- a/sgx_types/src/error.rs
+++ b/sgx_types/src/error.rs
@@ -116,6 +116,8 @@
         SGX_ERROR_WASM_LOAD_MODULE_ERROR        = 0x0F00F003,   /* sgxwasm loadmodule error */
         SGX_ERROR_WASM_TRY_LOAD_ERROR           = 0x0F00F004,   /* sgxwasm tryload error */
         SGX_ERROR_WASM_REGISTER_ERROR           = 0x0F00F005,   /* sgxwasm register error */
+        SGX_ERROR_FAAS_BUFFER_TOO_SHORT         = 0x0F00E001,   /* faas output buffer not long enough */
+        SGX_ERROR_FAAS_INTERNAL_ERROR           = 0x0F00E002,   /* faas exec internal error */
     }
 }
 
@@ -198,6 +200,8 @@
             sgx_status_t::SGX_ERROR_WASM_LOAD_MODULE_ERROR => "sgxwasm loadmodule error.",
             sgx_status_t::SGX_ERROR_WASM_TRY_LOAD_ERROR => "sgxwasm tryload error.",
             sgx_status_t::SGX_ERROR_WASM_REGISTER_ERROR => "sgxwasm register error.",
+            sgx_status_t::SGX_ERROR_FAAS_BUFFER_TOO_SHORT => "faas output buffer too short.",
+            sgx_status_t::SGX_ERROR_FAAS_INTERNAL_ERROR => "faas exec internal error.",
         }
     }
 
@@ -279,6 +283,8 @@
             sgx_status_t::SGX_ERROR_WASM_LOAD_MODULE_ERROR => "SGX_ERROR_WASM_LOAD_MODULE_ERROR",
             sgx_status_t::SGX_ERROR_WASM_TRY_LOAD_ERROR    => "SGX_ERROR_WASM_TRY_LOAD_ERROR",
             sgx_status_t::SGX_ERROR_WASM_REGISTER_ERROR    => "SGX_ERROR_WASM_REGISTER_ERROR",
+            sgx_status_t::SGX_ERROR_FAAS_BUFFER_TOO_SHORT   => "SGX_ERROR_FAAS_BUFFER_TOO_SHORT",
+            sgx_status_t::SGX_ERROR_FAAS_INTERNAL_ERROR => "SGX_ERROR_FAAS_INTERNAL_ERROR",
         }
     }
 }
diff --git a/sgx_types/src/function.rs b/sgx_types/src/function.rs
index 28b3df3..09bb4b5 100644
--- a/sgx_types/src/function.rs
+++ b/sgx_types/src/function.rs
@@ -461,6 +461,16 @@
                                         misc_attr: * mut sgx_misc_attribute_t,
                                         sealed_key: * const ::uint8_t) -> sgx_status_t;
 
+    /* intel sgx sdk 2.2 */
+    pub fn sgx_create_enclave_ex(file_name: * const ::c_char,
+                                 debug: ::int32_t,
+                                 launch_token: * mut sgx_launch_token_t,
+                                 launch_token_updated: * mut ::int32_t,
+                                 enclave_id: * mut sgx_enclave_id_t,
+                                 misc_attr: * mut sgx_misc_attribute_t,
+                                 ex_features: ::uint32_t,
+                                 ex_features_p: [* const ::c_void; 32]) -> sgx_status_t;
+
     pub fn sgx_destroy_enclave(enclave_id: sgx_enclave_id_t) -> sgx_status_t;
 }
 
diff --git a/sgx_types/src/types.rs b/sgx_types/src/types.rs
index d0ce57b..d0358f4 100644
--- a/sgx_types/src/types.rs
+++ b/sgx_types/src/types.rs
@@ -26,6 +26,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+use core::default::Default;
+use core::mem::transmute;
 use error::*;
 use marker::ContiguousMemory;
 
@@ -674,6 +676,8 @@
 pub const DMQ1_SIZE_IN_UINT: ::size_t   = (DMQ1_SIZE_IN_BYTES / 4);
 pub const IQMP_SIZE_IN_UINT: ::size_t   = (IQMP_SIZE_IN_BYTES / 4);
 
+pub type sgx_rsa_key_t = * mut ::c_void;
+
 
 /* intel sgx sdk 2.1.3 */
 impl_copy_clone! {
@@ -933,26 +937,26 @@
 //
 
 
-pub type sgx_ecall_get_ga_trusted_t = fn(eid: sgx_enclave_id_t,
-                                         retval: * mut sgx_status_t,
-                                         context: sgx_ra_context_t,
-                                         g_a: * mut sgx_ec256_public_t) -> sgx_status_t;
+pub type sgx_ecall_get_ga_trusted_t = extern "C" fn(eid: sgx_enclave_id_t,
+                                                    retval: * mut sgx_status_t,
+                                                    context: sgx_ra_context_t,
+                                                    g_a: * mut sgx_ec256_public_t) -> sgx_status_t;
 
-pub type sgx_ecall_proc_msg2_trusted_t = fn(eid: sgx_enclave_id_t,
-                                            retval: * mut sgx_status_t,
-                                            context: sgx_ra_context_t,
-                                            p_msg2: * const sgx_ra_msg2_t,
-                                            p_qe_target: * const sgx_target_info_t,
-                                            p_report: * mut sgx_report_t,
-                                            nonce: * mut sgx_quote_nonce_t) -> sgx_status_t;
+pub type sgx_ecall_proc_msg2_trusted_t = extern "C" fn(eid: sgx_enclave_id_t,
+                                                       retval: * mut sgx_status_t,
+                                                       context: sgx_ra_context_t,
+                                                       p_msg2: * const sgx_ra_msg2_t,
+                                                       p_qe_target: * const sgx_target_info_t,
+                                                       p_report: * mut sgx_report_t,
+                                                       nonce: * mut sgx_quote_nonce_t) -> sgx_status_t;
 
-pub type sgx_ecall_get_msg3_trusted_t = fn(eid: sgx_enclave_id_t,
-                                           retval: * mut sgx_status_t,
-                                           context: sgx_ra_context_t,
-                                           quote_size: ::uint32_t,
-                                           qe_report: * mut sgx_report_t,
-                                           p_msg3: * mut sgx_ra_msg3_t,
-                                           msg3_size: ::uint32_t) -> sgx_status_t;
+pub type sgx_ecall_get_msg3_trusted_t = extern "C" fn(eid: sgx_enclave_id_t,
+                                                      retval: * mut sgx_status_t,
+                                                      context: sgx_ra_context_t,
+                                                      quote_size: ::uint32_t,
+                                                      qe_report: * mut sgx_report_t,
+                                                      p_msg3: * mut sgx_ra_msg3_t,
+                                                      msg3_size: ::uint32_t) -> sgx_status_t;
 
 //
 // sgx_urts.h
@@ -961,15 +965,21 @@
 
 pub type sgx_launch_token_t = [::uint8_t; 1024];
 
-
-
+/* intel sgx sdk 2.2 */
+pub const MAX_EX_FEATURES_COUNT: ::size_t = 32;
+pub const SGX_CREATE_ENCLAVE_EX_PCL_BIT_IDX: ::size_t = 0;
+pub const SGX_CREATE_ENCLAVE_EX_PCL: ::uint32_t = (1 << SGX_CREATE_ENCLAVE_EX_PCL_BIT_IDX as ::uint32_t);
+pub const SGX_CREATE_ENCLAVE_EX_SWITCHLESS_BIT_IDX: ::size_t = 1;
+pub const SGX_CREATE_ENCLAVE_EX_SWITCHLESS: ::uint32_t = (1 << SGX_CREATE_ENCLAVE_EX_SWITCHLESS_BIT_IDX as ::uint32_t);
+pub const _SGX_LAST_EX_FEATURE_IDX_: ::uint32_t = SGX_CREATE_ENCLAVE_EX_SWITCHLESS_BIT_IDX as ::uint32_t;
+pub const _SGX_EX_FEATURES_MASK_: ::uint32_t = (0xFFFFFFFF_u32 >> (MAX_EX_FEATURES_COUNT as ::uint32_t - 1 - _SGX_LAST_EX_FEATURE_IDX_));
 //
 // trts.pic.h
 //
-pub const ENCLAVE_INIT_NOT_STARTED: u32 = 0;
-pub const ENCLAVE_INIT_IN_PROGRESS: u32 = 1;
-pub const ENCLAVE_INIT_DONE: u32        = 2;
-pub const ENCLAVE_CRASHED: u32          = 3;
+pub const ENCLAVE_INIT_NOT_STARTED: ::uint32_t = 0;
+pub const ENCLAVE_INIT_IN_PROGRESS: ::uint32_t = 1;
+pub const ENCLAVE_INIT_DONE: ::uint32_t        = 2;
+pub const ENCLAVE_CRASHED: ::uint32_t          = 3;
 
 //
 // sgx_cpuid.h
@@ -1002,7 +1012,6 @@
 //
 /* intel sgx sdk 2.0 */
 impl_enum! {
-
     #[repr(u32)]
     #[derive(Copy, Clone, PartialEq, Eq)]
     pub enum sgx_device_status_t {
@@ -1011,8 +1020,71 @@
         SGX_DISABLED_LEGACY_OS          = 2,  /* SGX is disabled and a Software Control Interface is not available to enable it */
         SGX_DISABLED                    = 3,  /* SGX is not enabled on this platform. More details are unavailable */
         SGX_DISABLED_SCI_AVAILABLE      = 4,  /* SGX is disabled, but a Software Control Interface is available to enable it */
-        SGX_DISABLED_MANUAL_ENABLE      = 5, /* SGX is disabled, but can be enabled manually in the BIOS setup */
-        SGX_DISABLED_HYPERV_ENABLED     = 6, /* Detected an unsupported version of Windows* 10 with Hyper-V enabled */
-        SGX_DISABLED_UNSUPPORTED_CPU    = 7, /* SGX is not supported by this CPU */
+        SGX_DISABLED_MANUAL_ENABLE      = 5,  /* SGX is disabled, but can be enabled manually in the BIOS setup */
+        SGX_DISABLED_HYPERV_ENABLED     = 6,  /* Detected an unsupported version of Windows* 10 with Hyper-V enabled */
+        SGX_DISABLED_UNSUPPORTED_CPU    = 7,  /* SGX is not supported by this CPU */
+    }
+}
+
+
+//
+// sgx_uswitchless.h
+//
+
+/* intel sgx sdk 2.2 */
+impl_enum! {
+    #[repr(u32)]
+    #[derive(Copy, Clone, PartialEq, Eq)]
+    pub enum sgx_uswitchless_worker_type_t {
+        SGX_USWITCHLESS_WORKER_TYPE_UNTRUSTED  = 0,
+        SGX_USWITCHLESS_WORKER_TYPE_TRUSTED    = 1,
+    }
+}
+
+impl_enum! {
+    #[repr(u32)]
+    #[derive(Copy, Clone, PartialEq, Eq)]
+    pub enum sgx_uswitchless_worker_event_t {
+        SGX_USWITCHLESS_WORKER_EVENT_START  = 0,  /* a worker thread starts */
+        SGX_USWITCHLESS_WORKER_EVENT_IDLE   = 1,  /* a worker thread is idle */
+        SGX_USWITCHLESS_WORKER_EVENT_MISS   = 2,  /* a worker thread misses some tasks */
+        SGX_USWITCHLESS_WORKER_EVENT_EXIT   = 3,  /* a worker thread exits */
+        SGX_USWITCHLESS_WORKER_EVENT_NUM    = 4,
+    }
+}
+
+impl_struct! {
+    pub struct sgx_uswitchless_worker_stats_t {
+        pub processed: ::uint64_t,  /* # of tasks that all workers have processed */
+        pub missed: ::uint64_t,     /* # of tasks that all workers have missed */
+    }
+}
+
+pub type sgx_uswitchless_worker_callback_t = extern "C" fn(worker_type: sgx_uswitchless_worker_type_t,
+                                                           worker_event: sgx_uswitchless_worker_event_t,
+                                                           worker_stats: * const sgx_uswitchless_worker_stats_t);
+
+pub const SL_DEFAULT_FALLBACK_RETRIES: ::uint32_t = 20000;
+pub const SL_DEFAULT_SLEEP_RETRIES: ::uint32_t = 20000;
+pub const SL_DEFUALT_MAX_TASKS_QWORDS: ::uint32_t = 1;
+pub const SL_MAX_TASKS_MAX_QWORDS: ::uint32_t = 8;
+
+pub const _SGX_USWITCHLESS_WORKER_EVENT_NUM: ::size_t = 4;
+
+pub struct sgx_uswitchless_config_t {
+    pub switchless_calls_pool_size_qwords: ::uint32_t,
+    pub num_uworkers: ::uint32_t,
+    pub num_tworkers: ::uint32_t,
+    pub retries_before_fallback: ::uint32_t,
+    pub retries_before_sleep: ::uint32_t,
+    pub callback_func: [sgx_uswitchless_worker_callback_t; _SGX_USWITCHLESS_WORKER_EVENT_NUM],
+}
+
+impl Default for sgx_uswitchless_config_t {
+    fn default() -> sgx_uswitchless_config_t {
+        let mut config: sgx_uswitchless_config_t = unsafe{ transmute([0u8; 56]) };
+        config.num_uworkers = 1;
+        config.num_tworkers = 1;
+        config
     }
 }
\ No newline at end of file
diff --git a/sgx_unwind/Cargo.toml b/sgx_unwind/Cargo.toml
index f2ef3bf..e0bdff8 100644
--- a/sgx_unwind/Cargo.toml
+++ b/sgx_unwind/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["The Rust Project Developers"]
 name = "sgx_unwind"
-version = "0.0.0"
+version = "0.0.1"
 build = "build.rs"
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/sgx_urts/Cargo.toml b/sgx_urts/Cargo.toml
index 68500fa..f082aa7 100644
--- a/sgx_urts/Cargo.toml
+++ b/sgx_urts/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sgx_urts"
-version = "1.0.0"
+version = "1.0.1"
 authors = ["Baidu"]
 repository = "https://github.com/baidu/rust-sgx-sdk"
 license-file = "LICENSE"
diff --git a/third_party/bytes/.gitignore b/third_party/bytes/.gitignore
new file mode 100644
index 0000000..4fffb2f
--- /dev/null
+++ b/third_party/bytes/.gitignore
@@ -0,0 +1,2 @@
+/target
+/Cargo.lock
diff --git a/third_party/bytes/.travis.yml b/third_party/bytes/.travis.yml
new file mode 100644
index 0000000..dbc744e
--- /dev/null
+++ b/third_party/bytes/.travis.yml
@@ -0,0 +1,85 @@
+---
+dist: trusty
+language: rust
+services: docker
+sudo: required
+rust: stable
+
+env:
+  global:
+    - CRATE_NAME=bytes
+    # Default job
+    - TARGET=x86_64-unknown-linux-gnu
+    - secure: "f17G5kb6uAQlAG9+GknFFYAmngGBqy9h+3FtNbp3mXTI0FOLltz00Ul5kGPysE4eagypm/dWOuvBkNjN01jhE6fCbekmInEsobIuanatrk6TvXT6caJqykxhPJC2cUoq8pKnMqEOuucEqPPUH6Qy6Hz4/2cRu5JV22Uv9dtS29Q="
+
+matrix:
+  include:
+    # Run build on oldest supported rust version. Do not change the rust
+    # version without a Github issue first.
+    #
+    # This job will also build and deploy the docs to gh-pages.
+    - env: TARGET=x86_64-unknown-linux-gnu
+      rust: 1.15.0
+      after_success:
+        - |
+            pip install 'travis-cargo<0.2' --user &&
+            export PATH=$HOME/.local/bin:$PATH
+        - travis-cargo doc
+        - travis-cargo doc-upload
+
+    # Run tests on some extra platforms
+    - env: TARGET=i686-unknown-linux-gnu
+    - env: TARGET=armv7-unknown-linux-gnueabihf
+    - env: RUST_TEST_THREADS=1 TARGET=powerpc-unknown-linux-gnu
+    - env: RUST_TEST_THREADS=1 TARGET=powerpc64-unknown-linux-gnu
+
+    # Serde implementation
+    - env: EXTRA_ARGS="--features serde"
+
+    # WASM support
+    - rust: beta
+      script:
+        - rustup target add wasm32-unknown-unknown
+        - cargo build --target=wasm32-unknown-unknown
+
+    # Sanitizers
+    - rust: nightly
+      os: linux
+      script:
+        - |
+          set -e
+
+          export RUST_TEST_THREADS=1
+          export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0"
+          export TSAN_OPTIONS="suppressions=`pwd`/ci/tsan"
+
+          # Run address sanitizer
+          RUSTFLAGS="-Z sanitizer=address" \
+          cargo test --tests --target x86_64-unknown-linux-gnu
+
+          # Run thread sanitizer
+          RUSTFLAGS="-Z sanitizer=thread" \
+          cargo test --tests --target x86_64-unknown-linux-gnu
+
+before_install: set -e
+
+install:
+  - sh ci/install.sh
+  - source ~/.cargo/env || true
+
+script:
+  - bash ci/script.sh
+
+after_script: set +e
+
+before_deploy:
+  - sh ci/before_deploy.sh
+
+cache: cargo
+before_cache:
+  # Travis can't cache files that are not readable by "others"
+  - chmod -R a+r $HOME/.cargo
+
+notifications:
+  email:
+    on_success: never
diff --git a/third_party/bytes/CHANGELOG.md b/third_party/bytes/CHANGELOG.md
new file mode 100644
index 0000000..42a4025
--- /dev/null
+++ b/third_party/bytes/CHANGELOG.md
@@ -0,0 +1,64 @@
+# 0.4.8 (May 25, 2018)
+
+* Fix panic in `BytesMut` `FromIterator` implementation.
+* Bytes: Recycle space when reserving space in vec mode (#197).
+* Bytes: Add resize fn (#203).
+
+# 0.4.7 (April 27, 2018)
+
+* Make `Buf` and `BufMut` usable as trait objects (#186).
+* impl BorrowMut for BytesMut (#185).
+* Improve accessor performance (#195).
+
+# 0.4.6 (Janary 8, 2018)
+
+* Implement FromIterator for Bytes/BytesMut (#148).
+* Add `advance` fn to Bytes/BytesMut (#166).
+* Add `unsplit` fn to `BytesMut` (#162, #173).
+* Improvements to Bytes split fns (#92).
+
+# 0.4.5 (August 12, 2017)
+
+* Fix range bug in `Take::bytes`
+* Misc performance improvements
+* Add extra `PartialEq` implementations.
+* Add `Bytes::with_capacity`
+* Implement `AsMut[u8]` for `BytesMut`
+
+# 0.4.4 (May 26, 2017)
+
+* Add serde support behind feature flag
+* Add `extend_from_slice` on `Bytes` and `BytesMut`
+* Add `truncate` and `clear` on `Bytes`
+* Misc additional std trait implementations
+* Misc performance improvements
+
+# 0.4.3 (April 30, 2017)
+
+* Fix Vec::advance_mut bug
+* Bump minimum Rust version to 1.15
+* Misc performance tweaks
+
+# 0.4.2 (April 5, 2017)
+
+* Misc performance tweaks
+* Improved `Debug` implementation for `Bytes`
+* Avoid some incorrect assert panics
+
+# 0.4.1 (March 15, 2017)
+
+* Expose `buf` module and have most types available from there vs. root.
+* Implement `IntoBuf` for `T: Buf`.
+* Add `FromBuf` and `Buf::collect`.
+* Add iterator adapter for `Buf`.
+* Add scatter/gather support to `Buf` and `BufMut`.
+* Add `Buf::chain`.
+* Reduce allocations on repeated calls to `BytesMut::reserve`.
+* Implement `Debug` for more types.
+* Remove `Source` in favor of `IntoBuf`.
+* Implement `Extend` for `BytesMut`.
+
+
+# 0.4.0 (February 24, 2017)
+
+* Initial release
diff --git a/third_party/bytes/Cargo.toml b/third_party/bytes/Cargo.toml
new file mode 100644
index 0000000..7bb1ffd
--- /dev/null
+++ b/third_party/bytes/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+
+name          = "bytes"
+version       = "0.4.8" # don't forget to update html_root_url
+license       = "MIT/Apache-2.0"
+authors       = ["Carl Lerche <me@carllerche.com>"]
+description   = "Types and traits for working with bytes"
+documentation = "https://carllerche.github.io/bytes/bytes"
+homepage      = "https://github.com/carllerche/bytes"
+repository    = "https://github.com/carllerche/bytes"
+readme        = "README.md"
+keywords      = ["buffers", "zero-copy", "io"]
+exclude       = [
+    ".gitignore",
+    ".travis.yml",
+    "deploy.sh",
+    "bench/**/*",
+    "test/**/*"
+]
+categories = ["network-programming", "data-structures"]
+
+[target.'cfg(not(target_env = "sgx"))'.dependencies]
+sgx_tstd = { path =  "../../sgx_tstd" }
+
+[dependencies]
+byteorder = { path = "../byteorder" }
+iovec = { path = "../iovec" }
+serde = { path = "../serde-rs/serde/serde" }
+
+[dev-dependencies]
+serde_test = "1.0"
diff --git a/third_party/bytes/LICENSE-APACHE b/third_party/bytes/LICENSE-APACHE
new file mode 100644
index 0000000..87d73e7
--- /dev/null
+++ b/third_party/bytes/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright 2017 Carl Lerche
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/bytes/LICENSE-MIT b/third_party/bytes/LICENSE-MIT
new file mode 100644
index 0000000..6c296be
--- /dev/null
+++ b/third_party/bytes/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017 Carl Lerche
+
+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/third_party/bytes/README.md b/third_party/bytes/README.md
new file mode 100644
index 0000000..3a88c56
--- /dev/null
+++ b/third_party/bytes/README.md
@@ -0,0 +1,42 @@
+# Bytes
+
+A utility library for working with bytes.
+
+[![Crates.io](https://img.shields.io/crates/v/bytes.svg?maxAge=2592000)](https://crates.io/crates/bytes)
+[![Build Status](https://travis-ci.org/carllerche/bytes.svg?branch=master)](https://travis-ci.org/carllerche/bytes)
+
+[Documentation](https://carllerche.github.io/bytes/bytes/index.html)
+
+## Usage
+
+To use `bytes`, first add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+bytes = "0.4"
+```
+
+Next, add this to your crate:
+
+```rust
+extern crate bytes;
+
+use bytes::{Bytes, BytesMut, Buf, BufMut};
+```
+
+## Serde support
+
+Serde support is optional and disabled by default. To enable use the feature `serde`.
+
+```toml
+[dependencies]
+bytes = { version = "0.4", features = ["serde"] }
+```
+
+# License
+
+`bytes` is primarily distributed under the terms of both the MIT license and the
+Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
diff --git a/third_party/bytes/Xargo.toml b/third_party/bytes/Xargo.toml
new file mode 100644
index 0000000..48ad024
--- /dev/null
+++ b/third_party/bytes/Xargo.toml
@@ -0,0 +1,20 @@
+[dependencies]
+alloc = {}
+panic_unwind = {}
+panic_abort = {}
+
+[dependencies.std]
+path = "../../xargo/sgx_tstd"
+stage = 1
+
+[dependencies.sgx_rand]
+path = "../../xargo/sgx_rand"
+stage = 2
+
+[dependencies.sgx_serialize]
+path = "../../xargo/sgx_serialize"
+stage = 2
+
+[dependencies.sgx_tunittest]
+path = "../../xargo/sgx_tunittest"
+stage = 2
\ No newline at end of file
diff --git a/third_party/bytes/benches/bytes.rs b/third_party/bytes/benches/bytes.rs
new file mode 100644
index 0000000..d268db5
--- /dev/null
+++ b/third_party/bytes/benches/bytes.rs
@@ -0,0 +1,217 @@
+#![feature(test)]
+
+extern crate bytes;
+extern crate test;
+
+use test::Bencher;
+use bytes::{Bytes, BytesMut, BufMut};
+
+#[bench]
+fn alloc_small(b: &mut Bencher) {
+    b.iter(|| {
+        for _ in 0..1024 {
+            test::black_box(BytesMut::with_capacity(12));
+        }
+    })
+}
+
+#[bench]
+fn alloc_mid(b: &mut Bencher) {
+    b.iter(|| {
+        test::black_box(BytesMut::with_capacity(128));
+    })
+}
+
+#[bench]
+fn alloc_big(b: &mut Bencher) {
+    b.iter(|| {
+        test::black_box(BytesMut::with_capacity(4096));
+    })
+}
+
+#[bench]
+fn split_off_and_drop(b: &mut Bencher) {
+    b.iter(|| {
+        for _ in 0..1024 {
+            let v = vec![10; 200];
+            let mut b = Bytes::from(v);
+            test::black_box(b.split_off(100));
+            test::black_box(b);
+        }
+    })
+}
+
+#[bench]
+fn deref_unique(b: &mut Bencher) {
+    let mut buf = BytesMut::with_capacity(4096);
+    buf.put(&[0u8; 1024][..]);
+
+    b.iter(|| {
+        for _ in 0..1024 {
+            test::black_box(&buf[..]);
+        }
+    })
+}
+
+#[bench]
+fn deref_unique_unroll(b: &mut Bencher) {
+    let mut buf = BytesMut::with_capacity(4096);
+    buf.put(&[0u8; 1024][..]);
+
+    b.iter(|| {
+        for _ in 0..128 {
+            test::black_box(&buf[..]);
+            test::black_box(&buf[..]);
+            test::black_box(&buf[..]);
+            test::black_box(&buf[..]);
+            test::black_box(&buf[..]);
+            test::black_box(&buf[..]);
+            test::black_box(&buf[..]);
+            test::black_box(&buf[..]);
+        }
+    })
+}
+
+#[bench]
+fn deref_shared(b: &mut Bencher) {
+    let mut buf = BytesMut::with_capacity(4096);
+    buf.put(&[0u8; 1024][..]);
+    let _b2 = buf.split_off(1024);
+
+    b.iter(|| {
+        for _ in 0..1024 {
+            test::black_box(&buf[..]);
+        }
+    })
+}
+
+#[bench]
+fn deref_inline(b: &mut Bencher) {
+    let mut buf = BytesMut::with_capacity(8);
+    buf.put(&[0u8; 8][..]);
+
+    b.iter(|| {
+        for _ in 0..1024 {
+            test::black_box(&buf[..]);
+        }
+    })
+}
+
+#[bench]
+fn deref_two(b: &mut Bencher) {
+    let mut buf1 = BytesMut::with_capacity(8);
+    buf1.put(&[0u8; 8][..]);
+
+    let mut buf2 = BytesMut::with_capacity(4096);
+    buf2.put(&[0u8; 1024][..]);
+
+    b.iter(|| {
+        for _ in 0..512 {
+            test::black_box(&buf1[..]);
+            test::black_box(&buf2[..]);
+        }
+    })
+}
+
+#[bench]
+fn alloc_write_split_to_mid(b: &mut Bencher) {
+    b.iter(|| {
+        let mut buf = BytesMut::with_capacity(128);
+        buf.put_slice(&[0u8; 64]);
+        test::black_box(buf.split_to(64));
+    })
+}
+
+#[bench]
+fn drain_write_drain(b: &mut Bencher) {
+    let data = [0u8; 128];
+
+    b.iter(|| {
+        let mut buf = BytesMut::with_capacity(1024);
+        let mut parts = Vec::with_capacity(8);
+
+        for _ in 0..8 {
+            buf.put(&data[..]);
+            parts.push(buf.split_to(128));
+        }
+
+        test::black_box(parts);
+    })
+}
+
+#[bench]
+fn fmt_write(b: &mut Bencher) {
+    use std::fmt::Write;
+    let mut buf = BytesMut::with_capacity(128);
+    let s = "foo bar baz quux lorem ipsum dolor et";
+
+    b.bytes = s.len() as u64;
+    b.iter(|| {
+        let _ = write!(buf, "{}", s);
+        test::black_box(&buf);
+        unsafe { buf.set_len(0); }
+    })
+}
+
+#[bench]
+fn from_long_slice(b: &mut Bencher) {
+    let data = [0u8; 128];
+    b.bytes = data.len() as u64;
+    b.iter(|| {
+        let buf = BytesMut::from(&data[..]);
+        test::black_box(buf);
+    })
+}
+
+#[bench]
+fn slice_empty(b: &mut Bencher) {
+    b.iter(|| {
+        let b = Bytes::from(vec![17; 1024]).clone();
+        for i in 0..1000 {
+            test::black_box(b.slice(i % 100, i % 100));
+        }
+    })
+}
+
+#[bench]
+fn slice_short_from_arc(b: &mut Bencher) {
+    b.iter(|| {
+        // `clone` is to convert to ARC
+        let b = Bytes::from(vec![17; 1024]).clone();
+        for i in 0..1000 {
+            test::black_box(b.slice(1, 2 + i % 10));
+        }
+    })
+}
+
+// Keep in sync with bytes.rs
+#[cfg(target_pointer_width = "64")]
+const INLINE_CAP: usize = 4 * 8 - 1;
+#[cfg(target_pointer_width = "32")]
+const INLINE_CAP: usize = 4 * 4 - 1;
+
+#[bench]
+fn slice_avg_le_inline_from_arc(b: &mut Bencher) {
+    b.iter(|| {
+        // `clone` is to convert to ARC
+        let b = Bytes::from(vec![17; 1024]).clone();
+        for i in 0..1000 {
+            // [1, INLINE_CAP]
+            let len = 1 + i % (INLINE_CAP - 1);
+            test::black_box(b.slice(i % 10, i % 10 + len));
+        }
+    })
+}
+
+#[bench]
+fn slice_large_le_inline_from_arc(b: &mut Bencher) {
+    b.iter(|| {
+        // `clone` is to convert to ARC
+        let b = Bytes::from(vec![17; 1024]).clone();
+        for i in 0..1000 {
+            // [INLINE_CAP - 10, INLINE_CAP]
+            let len = INLINE_CAP - 9 + i % 10;
+            test::black_box(b.slice(i % 10, i % 10 + len));
+        }
+    })
+}
diff --git a/third_party/bytes/ci/before_deploy.ps1 b/third_party/bytes/ci/before_deploy.ps1
new file mode 100644
index 0000000..191a30b
--- /dev/null
+++ b/third_party/bytes/ci/before_deploy.ps1
@@ -0,0 +1,23 @@
+# This script takes care of packaging the build artifacts that will go in the
+# release zipfile
+
+$SRC_DIR = $PWD.Path
+$STAGE = [System.Guid]::NewGuid().ToString()
+
+Set-Location $ENV:Temp
+New-Item -Type Directory -Name $STAGE
+Set-Location $STAGE
+
+$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
+
+# TODO Update this to package the right artifacts
+Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\hello.exe" '.\'
+
+7z a "$ZIP" *
+
+Push-AppveyorArtifact "$ZIP"
+
+Remove-Item *.* -Force
+Set-Location ..
+Remove-Item $STAGE
+Set-Location $SRC_DIR
diff --git a/third_party/bytes/ci/before_deploy.sh b/third_party/bytes/ci/before_deploy.sh
new file mode 100644
index 0000000..026dc28
--- /dev/null
+++ b/third_party/bytes/ci/before_deploy.sh
@@ -0,0 +1,33 @@
+# This script takes care of building your crate and packaging it for release
+
+set -ex
+
+main() {
+    local src=$(pwd) \
+          stage=
+
+    case $TRAVIS_OS_NAME in
+        linux)
+            stage=$(mktemp -d)
+            ;;
+        osx)
+            stage=$(mktemp -d -t tmp)
+            ;;
+    esac
+
+    test -f Cargo.lock || cargo generate-lockfile
+
+    # TODO Update this to build the artifacts that matter to you
+    cross rustc --bin hello --target $TARGET --release -- -C lto
+
+    # TODO Update this to package the right artifacts
+    cp target/$TARGET/release/hello $stage/
+
+    cd $stage
+    tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
+    cd $src
+
+    rm -rf $stage
+}
+
+main
diff --git a/third_party/bytes/ci/install.sh b/third_party/bytes/ci/install.sh
new file mode 100644
index 0000000..76bb734
--- /dev/null
+++ b/third_party/bytes/ci/install.sh
@@ -0,0 +1,31 @@
+set -ex
+
+main() {
+    curl https://sh.rustup.rs -sSf | \
+        sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
+
+    local target=
+    if [ $TRAVIS_OS_NAME = linux ]; then
+        target=x86_64-unknown-linux-gnu
+        sort=sort
+    else
+        target=x86_64-apple-darwin
+        sort=gsort  # for `sort --sort-version`, from brew's coreutils.
+    fi
+
+    # This fetches latest stable release
+    local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
+                       | cut -d/ -f3 \
+                       | grep -E '^v[0-9.]+$' \
+                       | $sort --version-sort \
+                       | tail -n1)
+    echo cross version: $tag
+    curl -LSfs https://japaric.github.io/trust/install.sh | \
+        sh -s -- \
+           --force \
+           --git japaric/cross \
+           --tag $tag \
+           --target $target
+}
+
+main
diff --git a/third_party/bytes/ci/script.sh b/third_party/bytes/ci/script.sh
new file mode 100644
index 0000000..d1ed7f9
--- /dev/null
+++ b/third_party/bytes/ci/script.sh
@@ -0,0 +1,18 @@
+# This script takes care of testing your crate
+
+set -ex
+
+main() {
+    cross build --target $TARGET $EXTRA_ARGS
+
+    if [ ! -z $DISABLE_TESTS ]; then
+        return
+    fi
+
+    cross test --target $TARGET $EXTRA_ARGS
+}
+
+# we don't run the "test phase" when doing deploys
+if [ -z $TRAVIS_TAG ]; then
+    main
+fi
diff --git a/third_party/bytes/ci/tsan b/third_party/bytes/ci/tsan
new file mode 100644
index 0000000..18bfc63
--- /dev/null
+++ b/third_party/bytes/ci/tsan
@@ -0,0 +1,21 @@
+# TSAN suppressions file for `bytes`
+
+# TSAN does not understand fences and `Arc::drop` is implemented using a fence.
+# This causes many false positives.
+race:Arc*drop
+race:arc*Weak*drop
+
+# `std` mpsc is not used in any Bytes code base. This race is triggered by some
+# rust runtime logic.
+race:std*mpsc_queue
+
+# Not sure why this is warning, but it is in the test harness and not the library.
+race:TestEvent*clone
+race:test::run_tests_console::*closure
+
+# Probably more fences in std.
+race:__call_tls_dtors
+
+# `is_inline` is explicitly called concurrently without synchronization. The
+# safety explanation can be found in a comment.
+race:Inner::is_inline
diff --git a/third_party/bytes/src/buf/buf.rs b/third_party/bytes/src/buf/buf.rs
new file mode 100644
index 0000000..a6e8fd9
--- /dev/null
+++ b/third_party/bytes/src/buf/buf.rs
@@ -0,0 +1,1062 @@
+use std::prelude::v1::*;
+use super::{IntoBuf, Take, Reader, Iter, FromBuf, Chain};
+use byteorder::{BigEndian, ByteOrder, LittleEndian};
+use iovec::IoVec;
+
+use std::{cmp, io, ptr};
+
+macro_rules! buf_get_impl {
+    ($this:ident, $size:expr, $conv:path) => ({
+         // try to convert directly from the bytes
+        let ret = {
+            // this Option<ret> trick is to avoid keeping a borrow on self
+            // when advance() is called (mut borrow) and to call bytes() only once
+            if let Some(src) = $this.bytes().get(..($size)) {
+                Some($conv(src))
+            } else {
+                None
+            }
+        };
+        if let Some(ret) = ret {
+             // if the direct convertion was possible, advance and return
+            $this.advance($size);
+            return ret;
+        } else {
+            // if not we copy the bytes in a temp buffer then convert
+            let mut buf = [0; ($size)];
+            $this.copy_to_slice(&mut buf); // (do the advance)
+            return $conv(&buf);
+        }
+    });
+    ($this:ident, $buf_size:expr, $conv:path, $len_to_read:expr) => ({
+        // The same trick as above does not improve the best case speed.
+        // It seems to be linked to the way the method is optimised by the compiler
+        let mut buf = [0; ($buf_size)];
+        $this.copy_to_slice(&mut buf[..($len_to_read)]);
+        return $conv(&buf[..($len_to_read)], $len_to_read);
+    });
+}
+
+/// Read bytes from a buffer.
+///
+/// A buffer stores bytes in memory such that read operations are infallible.
+/// The underlying storage may or may not be in contiguous memory. A `Buf` value
+/// is a cursor into the buffer. Reading from `Buf` advances the cursor
+/// position. It can be thought of as an efficient `Iterator` for collections of
+/// bytes.
+///
+/// The simplest `Buf` is a `Cursor` wrapping a `[u8]`.
+///
+/// ```
+/// use bytes::Buf;
+/// use std::io::Cursor;
+///
+/// let mut buf = Cursor::new(b"hello world");
+///
+/// assert_eq!(b'h', buf.get_u8());
+/// assert_eq!(b'e', buf.get_u8());
+/// assert_eq!(b'l', buf.get_u8());
+///
+/// let mut rest = [0; 8];
+/// buf.copy_to_slice(&mut rest);
+///
+/// assert_eq!(&rest[..], b"lo world");
+/// ```
+pub trait Buf {
+    /// Returns the number of bytes between the current position and the end of
+    /// the buffer.
+    ///
+    /// This value is greater than or equal to the length of the slice returned
+    /// by `bytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world");
+    ///
+    /// assert_eq!(buf.remaining(), 11);
+    ///
+    /// buf.get_u8();
+    ///
+    /// assert_eq!(buf.remaining(), 10);
+    /// ```
+    ///
+    /// # Implementer notes
+    ///
+    /// Implementations of `remaining` should ensure that the return value does
+    /// not change unless a call is made to `advance` or any other function that
+    /// is documented to change the `Buf`'s current position.
+    fn remaining(&self) -> usize;
+
+    /// Returns a slice starting at the current position and of length between 0
+    /// and `Buf::remaining()`.
+    ///
+    /// This is a lower level function. Most operations are done with other
+    /// functions.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world");
+    ///
+    /// assert_eq!(buf.bytes(), b"hello world");
+    ///
+    /// buf.advance(6);
+    ///
+    /// assert_eq!(buf.bytes(), b"world");
+    /// ```
+    ///
+    /// # Implementer notes
+    ///
+    /// This function should never panic. Once the end of the buffer is reached,
+    /// i.e., `Buf::remaining` returns 0, calls to `bytes` should return an
+    /// empty slice.
+    fn bytes(&self) -> &[u8];
+
+    /// Fills `dst` with potentially multiple slices starting at `self`'s
+    /// current position.
+    ///
+    /// If the `Buf` is backed by disjoint slices of bytes, `bytes_vec` enables
+    /// fetching more than one slice at once. `dst` is a slice of `IoVec`
+    /// references, enabling the slice to be directly used with [`writev`]
+    /// without any further conversion. The sum of the lengths of all the
+    /// buffers in `dst` will be less than or equal to `Buf::remaining()`.
+    ///
+    /// The entries in `dst` will be overwritten, but the data **contained** by
+    /// the slices **will not** be modified. If `bytes_vec` does not fill every
+    /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices
+    /// in `self.
+    ///
+    /// This is a lower level function. Most operations are done with other
+    /// functions.
+    ///
+    /// # Implementer notes
+    ///
+    /// This function should never panic. Once the end of the buffer is reached,
+    /// i.e., `Buf::remaining` returns 0, calls to `bytes_vec` must return 0
+    /// without mutating `dst`.
+    ///
+    /// Implementations should also take care to properly handle being called
+    /// with `dst` being a zero length slice.
+    ///
+    /// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html
+    fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize {
+        if dst.is_empty() {
+            return 0;
+        }
+
+        if self.has_remaining() {
+            dst[0] = self.bytes().into();
+            1
+        } else {
+            0
+        }
+    }
+
+    /// Advance the internal cursor of the Buf
+    ///
+    /// The next call to `bytes` will return a slice starting `cnt` bytes
+    /// further into the underlying buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world");
+    ///
+    /// assert_eq!(buf.bytes(), b"hello world");
+    ///
+    /// buf.advance(6);
+    ///
+    /// assert_eq!(buf.bytes(), b"world");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function **may** panic if `cnt > self.remaining()`.
+    ///
+    /// # Implementer notes
+    ///
+    /// It is recommended for implementations of `advance` to panic if `cnt >
+    /// self.remaining()`. If the implementation does not panic, the call must
+    /// behave as if `cnt == self.remaining()`.
+    ///
+    /// A call with `cnt == 0` should never panic and be a no-op.
+    fn advance(&mut self, cnt: usize);
+
+    /// Returns true if there are any more bytes to consume
+    ///
+    /// This is equivalent to `self.remaining() != 0`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"a");
+    ///
+    /// assert!(buf.has_remaining());
+    ///
+    /// buf.get_u8();
+    ///
+    /// assert!(!buf.has_remaining());
+    /// ```
+    fn has_remaining(&self) -> bool {
+        self.remaining() > 0
+    }
+
+    /// Copies bytes from `self` into `dst`.
+    ///
+    /// The cursor is advanced by the number of bytes copied. `self` must have
+    /// enough remaining bytes to fill `dst`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world");
+    /// let mut dst = [0; 5];
+    ///
+    /// buf.copy_to_slice(&mut dst);
+    /// assert_eq!(b"hello", &dst);
+    /// assert_eq!(6, buf.remaining());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if `self.remaining() < dst.len()`
+    fn copy_to_slice(&mut self, dst: &mut [u8]) {
+        let mut off = 0;
+
+        assert!(self.remaining() >= dst.len());
+
+        while off < dst.len() {
+            let cnt;
+
+            unsafe {
+                let src = self.bytes();
+                cnt = cmp::min(src.len(), dst.len() - off);
+
+                ptr::copy_nonoverlapping(
+                    src.as_ptr(), dst[off..].as_mut_ptr(), cnt);
+
+                off += src.len();
+            }
+
+            self.advance(cnt);
+        }
+    }
+
+    /// Gets an unsigned 8 bit integer from `self`.
+    ///
+    /// The current position is advanced by 1.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08 hello");
+    /// assert_eq!(8, buf.get_u8());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is no more remaining data in `self`.
+    fn get_u8(&mut self) -> u8 {
+        assert!(self.remaining() >= 1);
+        let ret = self.bytes()[0];
+        self.advance(1);
+        ret
+    }
+
+    /// Gets a signed 8 bit integer from `self`.
+    ///
+    /// The current position is advanced by 1.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08 hello");
+    /// assert_eq!(8, buf.get_i8());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is no more remaining data in `self`.
+    fn get_i8(&mut self) -> i8 {
+        assert!(self.remaining() >= 1);
+        let ret = self.bytes()[0] as i8;
+        self.advance(1);
+        ret
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_u16_be or get_u16_le")]
+    fn get_u16<T: ByteOrder>(&mut self) -> u16 where Self: Sized {
+        let mut buf = [0; 2];
+        self.copy_to_slice(&mut buf);
+        T::read_u16(&buf)
+    }
+
+    /// Gets an unsigned 16 bit integer from `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08\x09 hello");
+    /// assert_eq!(0x0809, buf.get_u16_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_u16_be(&mut self) -> u16 {
+        buf_get_impl!(self, 2, BigEndian::read_u16);
+    }
+
+    /// Gets an unsigned 16 bit integer from `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x09\x08 hello");
+    /// assert_eq!(0x0809, buf.get_u16_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_u16_le(&mut self) -> u16 {
+        buf_get_impl!(self, 2, LittleEndian::read_u16);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_i16_be or get_i16_le")]
+    fn get_i16<T: ByteOrder>(&mut self) -> i16 where Self: Sized {
+        let mut buf = [0; 2];
+        self.copy_to_slice(&mut buf);
+        T::read_i16(&buf)
+    }
+
+    /// Gets a signed 16 bit integer from `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08\x09 hello");
+    /// assert_eq!(0x0809, buf.get_i16_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_i16_be(&mut self) -> i16 {
+        buf_get_impl!(self, 2, BigEndian::read_i16);
+    }
+
+    /// Gets a signed 16 bit integer from `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x09\x08 hello");
+    /// assert_eq!(0x0809, buf.get_i16_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_i16_le(&mut self) -> i16 {
+        buf_get_impl!(self, 2, LittleEndian::read_i16);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_u32_be or get_u32_le")]
+    fn get_u32<T: ByteOrder>(&mut self) -> u32 where Self: Sized {
+        let mut buf = [0; 4];
+        self.copy_to_slice(&mut buf);
+        T::read_u32(&buf)
+    }
+
+    /// Gets an unsigned 32 bit integer from `self` in the big-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello");
+    /// assert_eq!(0x0809A0A1, buf.get_u32_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_u32_be(&mut self) -> u32 {
+        buf_get_impl!(self, 4, BigEndian::read_u32);
+    }
+
+    /// Gets an unsigned 32 bit integer from `self` in the little-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\xA1\xA0\x09\x08 hello");
+    /// assert_eq!(0x0809A0A1, buf.get_u32_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_u32_le(&mut self) -> u32 {
+        buf_get_impl!(self, 4, LittleEndian::read_u32);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_i32_be or get_i32_le")]
+    fn get_i32<T: ByteOrder>(&mut self) -> i32 where Self: Sized {
+        let mut buf = [0; 4];
+        self.copy_to_slice(&mut buf);
+        T::read_i32(&buf)
+    }
+
+    /// Gets a signed 32 bit integer from `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello");
+    /// assert_eq!(0x0809A0A1, buf.get_i32_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_i32_be(&mut self) -> i32 {
+        buf_get_impl!(self, 4, BigEndian::read_i32);
+    }
+
+    /// Gets a signed 32 bit integer from `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\xA1\xA0\x09\x08 hello");
+    /// assert_eq!(0x0809A0A1, buf.get_i32_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_i32_le(&mut self) -> i32 {
+        buf_get_impl!(self, 4, LittleEndian::read_i32);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_u64_be or get_u64_le")]
+    fn get_u64<T: ByteOrder>(&mut self) -> u64 where Self: Sized {
+        let mut buf = [0; 8];
+        self.copy_to_slice(&mut buf);
+        T::read_u64(&buf)
+    }
+
+    /// Gets an unsigned 64 bit integer from `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello");
+    /// assert_eq!(0x0102030405060708, buf.get_u64_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_u64_be(&mut self) -> u64 {
+        buf_get_impl!(self, 8, BigEndian::read_u64);
+    }
+
+    /// Gets an unsigned 64 bit integer from `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08\x07\x06\x05\x04\x03\x02\x01 hello");
+    /// assert_eq!(0x0102030405060708, buf.get_u64_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_u64_le(&mut self) -> u64 {
+        buf_get_impl!(self, 8, LittleEndian::read_u64);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_i64_be or get_i64_le")]
+    fn get_i64<T: ByteOrder>(&mut self) -> i64 where Self: Sized {
+        let mut buf = [0; 8];
+        self.copy_to_slice(&mut buf);
+        T::read_i64(&buf)
+    }
+
+    /// Gets a signed 64 bit integer from `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello");
+    /// assert_eq!(0x0102030405060708, buf.get_i64_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_i64_be(&mut self) -> i64 {
+        buf_get_impl!(self, 8, BigEndian::read_i64);
+    }
+
+    /// Gets a signed 64 bit integer from `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x08\x07\x06\x05\x04\x03\x02\x01 hello");
+    /// assert_eq!(0x0102030405060708, buf.get_i64_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_i64_le(&mut self) -> i64 {
+        buf_get_impl!(self, 8, LittleEndian::read_i64);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_uint_be or get_uint_le")]
+    fn get_uint<T: ByteOrder>(&mut self, nbytes: usize) -> u64 where Self: Sized {
+        let mut buf = [0; 8];
+        self.copy_to_slice(&mut buf[..nbytes]);
+        T::read_uint(&buf[..nbytes], nbytes)
+    }
+
+    /// Gets an unsigned n-byte integer from `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Buf, BigEndian};
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x01\x02\x03 hello");
+    /// assert_eq!(0x010203, buf.get_uint_be(3));
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_uint_be(&mut self, nbytes: usize) -> u64 {
+        buf_get_impl!(self, 8, BigEndian::read_uint, nbytes);
+    }
+
+    /// Gets an unsigned n-byte integer from `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x03\x02\x01 hello");
+    /// assert_eq!(0x010203, buf.get_uint_le(3));
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_uint_le(&mut self, nbytes: usize) -> u64 {
+        buf_get_impl!(self, 8, LittleEndian::read_uint, nbytes);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_int_be or get_int_le")]
+    fn get_int<T: ByteOrder>(&mut self, nbytes: usize) -> i64 where Self: Sized {
+        let mut buf = [0; 8];
+        self.copy_to_slice(&mut buf[..nbytes]);
+        T::read_int(&buf[..nbytes], nbytes)
+    }
+
+    /// Gets a signed n-byte integer from `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x01\x02\x03 hello");
+    /// assert_eq!(0x010203, buf.get_int_be(3));
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_int_be(&mut self, nbytes: usize) -> i64 {
+        buf_get_impl!(self, 8, BigEndian::read_int, nbytes);
+    }
+
+    /// Gets a signed n-byte integer from `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x03\x02\x01 hello");
+    /// assert_eq!(0x010203, buf.get_int_le(3));
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_int_le(&mut self, nbytes: usize) -> i64 {
+        buf_get_impl!(self, 8, LittleEndian::read_int, nbytes);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_f32_be or get_f32_le")]
+    fn get_f32<T: ByteOrder>(&mut self) -> f32 where Self: Sized {
+        let mut buf = [0; 4];
+        self.copy_to_slice(&mut buf);
+        T::read_f32(&buf)
+    }
+
+    /// Gets an IEEE754 single-precision (4 bytes) floating point number from
+    /// `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x3F\x99\x99\x9A hello");
+    /// assert_eq!(1.2f32, buf.get_f32_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_f32_be(&mut self) -> f32 {
+        buf_get_impl!(self, 4, BigEndian::read_f32);
+    }
+
+    /// Gets an IEEE754 single-precision (4 bytes) floating point number from
+    /// `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x9A\x99\x99\x3F hello");
+    /// assert_eq!(1.2f32, buf.get_f32_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_f32_le(&mut self) -> f32 {
+        buf_get_impl!(self, 4, LittleEndian::read_f32);
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use get_f64_be or get_f64_le")]
+    fn get_f64<T: ByteOrder>(&mut self) -> f64 where Self: Sized {
+        let mut buf = [0; 8];
+        self.copy_to_slice(&mut buf);
+        T::read_f64(&buf)
+    }
+
+    /// Gets an IEEE754 double-precision (8 bytes) floating point number from
+    /// `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x3F\xF3\x33\x33\x33\x33\x33\x33 hello");
+    /// assert_eq!(1.2f64, buf.get_f64_be());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_f64_be(&mut self) -> f64 {
+        buf_get_impl!(self, 8, BigEndian::read_f64);
+    }
+
+    /// Gets an IEEE754 double-precision (8 bytes) floating point number from
+    /// `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"\x33\x33\x33\x33\x33\x33\xF3\x3F hello");
+    /// assert_eq!(1.2f64, buf.get_f64_le());
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining data in `self`.
+    fn get_f64_le(&mut self) -> f64 {
+        buf_get_impl!(self, 8, LittleEndian::read_f64);
+    }
+
+    /// Transforms a `Buf` into a concrete buffer.
+    ///
+    /// `collect()` can operate on any value that implements `Buf`, and turn it
+    /// into the relevent concrete buffer type.
+    ///
+    /// # Examples
+    ///
+    /// Collecting a buffer and loading the contents into a `Vec<u8>`.
+    ///
+    /// ```
+    /// use bytes::{Buf, Bytes, IntoBuf};
+    ///
+    /// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+    /// let vec: Vec<u8> = buf.collect();
+    ///
+    /// assert_eq!(vec, &b"hello world"[..]);
+    /// ```
+    fn collect<B>(self) -> B
+        where Self: Sized,
+              B: FromBuf,
+    {
+        B::from_buf(self)
+    }
+
+    /// Creates an adaptor which will read at most `limit` bytes from `self`.
+    ///
+    /// This function returns a new instance of `Buf` which will read at most
+    /// `limit` bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Buf, BufMut};
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new("hello world").take(5);
+    /// let mut dst = vec![];
+    ///
+    /// dst.put(&mut buf);
+    /// assert_eq!(dst, b"hello");
+    ///
+    /// let mut buf = buf.into_inner();
+    /// dst.clear();
+    /// dst.put(&mut buf);
+    /// assert_eq!(dst, b" world");
+    /// ```
+    fn take(self, limit: usize) -> Take<Self>
+        where Self: Sized
+    {
+        super::take::new(self, limit)
+    }
+
+    /// Creates an adaptor which will chain this buffer with another.
+    ///
+    /// The returned `Buf` instance will first consume all bytes from `self`.
+    /// Afterwards the output is equivalent to the output of next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Bytes, Buf, IntoBuf};
+    /// use bytes::buf::Chain;
+    ///
+    /// let buf = Bytes::from(&b"hello "[..]).into_buf()
+    ///             .chain(Bytes::from(&b"world"[..]));
+    ///
+    /// let full: Bytes = buf.collect();
+    /// assert_eq!(full[..], b"hello world"[..]);
+    /// ```
+    fn chain<U>(self, next: U) -> Chain<Self, U::Buf>
+        where U: IntoBuf,
+              Self: Sized,
+    {
+        Chain::new(self, next.into_buf())
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `Buf`.
+    ///
+    /// The returned adaptor also implements `Buf` and will simply borrow `self`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Buf, BufMut};
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new("hello world");
+    /// let mut dst = vec![];
+    ///
+    /// {
+    ///     let mut reference = buf.by_ref();
+    ///     dst.put(&mut reference.take(5));
+    ///     assert_eq!(dst, b"hello");
+    /// } // drop our &mut reference so we can use `buf` again
+    ///
+    /// dst.clear();
+    /// dst.put(&mut buf);
+    /// assert_eq!(dst, b" world");
+    /// ```
+    fn by_ref(&mut self) -> &mut Self where Self: Sized {
+        self
+    }
+
+    /// Creates an adaptor which implements the `Read` trait for `self`.
+    ///
+    /// This function returns a new value which implements `Read` by adapting
+    /// the `Read` trait functions to the `Buf` trait functions. Given that
+    /// `Buf` operations are infallible, none of the `Read` functions will
+    /// return with `Err`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Buf, IntoBuf, Bytes};
+    /// use std::io::Read;
+    ///
+    /// let buf = Bytes::from("hello world").into_buf();
+    ///
+    /// let mut reader = buf.reader();
+    /// let mut dst = [0; 1024];
+    ///
+    /// let num = reader.read(&mut dst).unwrap();
+    ///
+    /// assert_eq!(11, num);
+    /// assert_eq!(&dst[..11], b"hello world");
+    /// ```
+    fn reader(self) -> Reader<Self> where Self: Sized {
+        super::reader::new(self)
+    }
+
+    /// Returns an iterator over the bytes contained by the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Buf, IntoBuf, Bytes};
+    ///
+    /// let buf = Bytes::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    /// assert_eq!(iter.next(), Some(b'b'));
+    /// assert_eq!(iter.next(), Some(b'c'));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    fn iter(self) -> Iter<Self> where Self: Sized {
+        super::iter::new(self)
+    }
+}
+
+impl<'a, T: Buf + ?Sized> Buf for &'a mut T {
+    fn remaining(&self) -> usize {
+        (**self).remaining()
+    }
+
+    fn bytes(&self) -> &[u8] {
+        (**self).bytes()
+    }
+
+    fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize {
+        (**self).bytes_vec(dst)
+    }
+
+    fn advance(&mut self, cnt: usize) {
+        (**self).advance(cnt)
+    }
+}
+
+impl<T: Buf + ?Sized> Buf for Box<T> {
+    fn remaining(&self) -> usize {
+        (**self).remaining()
+    }
+
+    fn bytes(&self) -> &[u8] {
+        (**self).bytes()
+    }
+
+    fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize {
+        (**self).bytes_vec(dst)
+    }
+
+    fn advance(&mut self, cnt: usize) {
+        (**self).advance(cnt)
+    }
+}
+
+impl<T: AsRef<[u8]>> Buf for io::Cursor<T> {
+    fn remaining(&self) -> usize {
+        let len = self.get_ref().as_ref().len();
+        let pos = self.position();
+
+        if pos >= len as u64 {
+            return 0;
+        }
+
+        len - pos as usize
+    }
+
+    fn bytes(&self) -> &[u8] {
+        let len = self.get_ref().as_ref().len();
+        let pos = self.position() as usize;
+
+        if pos >= len {
+            return Default::default();
+        }
+
+        &(self.get_ref().as_ref())[pos..]
+    }
+
+    fn advance(&mut self, cnt: usize) {
+        let pos = (self.position() as usize)
+            .checked_add(cnt).expect("overflow");
+
+        assert!(pos <= self.get_ref().as_ref().len());
+
+        self.set_position(pos as u64);
+    }
+}
+
+impl Buf for Option<[u8; 1]> {
+    fn remaining(&self) -> usize {
+        if self.is_some() {
+            1
+        } else {
+            0
+        }
+    }
+
+    fn bytes(&self) -> &[u8] {
+        self.as_ref().map(AsRef::as_ref)
+            .unwrap_or(Default::default())
+    }
+
+    fn advance(&mut self, cnt: usize) {
+        if cnt == 0 {
+            return;
+        }
+
+        if self.is_none() {
+            panic!("overflow");
+        } else {
+            assert_eq!(1, cnt);
+            *self = None;
+        }
+    }
+}
+
+// The existance of this function makes the compiler catch if the Buf
+// trait is "object-safe" or not.
+fn _assert_trait_object(_b: &Buf) {}
diff --git a/third_party/bytes/src/buf/buf_mut.rs b/third_party/bytes/src/buf/buf_mut.rs
new file mode 100644
index 0000000..73ad62f
--- /dev/null
+++ b/third_party/bytes/src/buf/buf_mut.rs
@@ -0,0 +1,1063 @@
+use std::prelude::v1::*;
+use super::{IntoBuf, Writer};
+use byteorder::{LittleEndian, ByteOrder, BigEndian};
+use iovec::IoVec;
+
+use std::{cmp, io, ptr, usize};
+
+/// A trait for values that provide sequential write access to bytes.
+///
+/// Write bytes to a buffer
+///
+/// A buffer stores bytes in memory such that write operations are infallible.
+/// The underlying storage may or may not be in contiguous memory. A `BufMut`
+/// value is a cursor into the buffer. Writing to `BufMut` advances the cursor
+/// position.
+///
+/// The simplest `BufMut` is a `Vec<u8>`.
+///
+/// ```
+/// use bytes::BufMut;
+///
+/// let mut buf = vec![];
+///
+/// buf.put("hello world");
+///
+/// assert_eq!(buf, b"hello world");
+/// ```
+pub trait BufMut {
+    /// Returns the number of bytes that can be written from the current
+    /// position until the end of the buffer is reached.
+    ///
+    /// This value is greater than or equal to the length of the slice returned
+    /// by `bytes_mut`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    /// use std::io::Cursor;
+    ///
+    /// let mut dst = [0; 10];
+    /// let mut buf = Cursor::new(&mut dst[..]);
+    ///
+    /// assert_eq!(10, buf.remaining_mut());
+    /// buf.put("hello");
+    ///
+    /// assert_eq!(5, buf.remaining_mut());
+    /// ```
+    ///
+    /// # Implementer notes
+    ///
+    /// Implementations of `remaining_mut` should ensure that the return value
+    /// does not change unless a call is made to `advance_mut` or any other
+    /// function that is documented to change the `BufMut`'s current position.
+    fn remaining_mut(&self) -> usize;
+
+    /// Advance the internal cursor of the BufMut
+    ///
+    /// The next call to `bytes_mut` will return a slice starting `cnt` bytes
+    /// further into the underlying buffer.
+    ///
+    /// This function is unsafe because there is no guarantee that the bytes
+    /// being advanced past have been initialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = Vec::with_capacity(16);
+    ///
+    /// unsafe {
+    ///     buf.bytes_mut()[0] = b'h';
+    ///     buf.bytes_mut()[1] = b'e';
+    ///
+    ///     buf.advance_mut(2);
+    ///
+    ///     buf.bytes_mut()[0] = b'l';
+    ///     buf.bytes_mut()[1..3].copy_from_slice(b"lo");
+    ///
+    ///     buf.advance_mut(3);
+    /// }
+    ///
+    /// assert_eq!(5, buf.len());
+    /// assert_eq!(buf, b"hello");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function **may** panic if `cnt > self.remaining_mut()`.
+    ///
+    /// # Implementer notes
+    ///
+    /// It is recommended for implementations of `advance_mut` to panic if
+    /// `cnt > self.remaining_mut()`. If the implementation does not panic,
+    /// the call must behave as if `cnt == self.remaining_mut()`.
+    ///
+    /// A call with `cnt == 0` should never panic and be a no-op.
+    unsafe fn advance_mut(&mut self, cnt: usize);
+
+    /// Returns true if there is space in `self` for more bytes.
+    ///
+    /// This is equivalent to `self.remaining_mut() != 0`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    /// use std::io::Cursor;
+    ///
+    /// let mut dst = [0; 5];
+    /// let mut buf = Cursor::new(&mut dst);
+    ///
+    /// assert!(buf.has_remaining_mut());
+    ///
+    /// buf.put("hello");
+    ///
+    /// assert!(!buf.has_remaining_mut());
+    /// ```
+    fn has_remaining_mut(&self) -> bool {
+        self.remaining_mut() > 0
+    }
+
+    /// Returns a mutable slice starting at the current BufMut position and of
+    /// length between 0 and `BufMut::remaining_mut()`.
+    ///
+    /// This is a lower level function. Most operations are done with other
+    /// functions.
+    ///
+    /// The returned byte slice may represent uninitialized memory.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = Vec::with_capacity(16);
+    ///
+    /// unsafe {
+    ///     buf.bytes_mut()[0] = b'h';
+    ///     buf.bytes_mut()[1] = b'e';
+    ///
+    ///     buf.advance_mut(2);
+    ///
+    ///     buf.bytes_mut()[0] = b'l';
+    ///     buf.bytes_mut()[1..3].copy_from_slice(b"lo");
+    ///
+    ///     buf.advance_mut(3);
+    /// }
+    ///
+    /// assert_eq!(5, buf.len());
+    /// assert_eq!(buf, b"hello");
+    /// ```
+    ///
+    /// # Implementer notes
+    ///
+    /// This function should never panic. `bytes_mut` should return an empty
+    /// slice **if and only if** `remaining_mut` returns 0. In other words,
+    /// `bytes_mut` returning an empty slice implies that `remaining_mut` will
+    /// return 0 and `remaining_mut` returning 0 implies that `bytes_mut` will
+    /// return an empty slice.
+    unsafe fn bytes_mut(&mut self) -> &mut [u8];
+
+    /// Fills `dst` with potentially multiple mutable slices starting at `self`'s
+    /// current position.
+    ///
+    /// If the `BufMut` is backed by disjoint slices of bytes, `bytes_vec_mut`
+    /// enables fetching more than one slice at once. `dst` is a slice of
+    /// mutable `IoVec` references, enabling the slice to be directly used with
+    /// [`readv`] without any further conversion. The sum of the lengths of all
+    /// the buffers in `dst` will be less than or equal to
+    /// `Buf::remaining_mut()`.
+    ///
+    /// The entries in `dst` will be overwritten, but the data **contained** by
+    /// the slices **will not** be modified. If `bytes_vec_mut` does not fill every
+    /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices
+    /// in `self.
+    ///
+    /// This is a lower level function. Most operations are done with other
+    /// functions.
+    ///
+    /// # Implementer notes
+    ///
+    /// This function should never panic. Once the end of the buffer is reached,
+    /// i.e., `BufMut::remaining_mut` returns 0, calls to `bytes_vec_mut` must
+    /// return 0 without mutating `dst`.
+    ///
+    /// Implementations should also take care to properly handle being called
+    /// with `dst` being a zero length slice.
+    ///
+    /// [`readv`]: http://man7.org/linux/man-pages/man2/readv.2.html
+    unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize {
+        if dst.is_empty() {
+            return 0;
+        }
+
+        if self.has_remaining_mut() {
+            dst[0] = self.bytes_mut().into();
+            1
+        } else {
+            0
+        }
+    }
+
+    /// Transfer bytes into `self` from `src` and advance the cursor by the
+    /// number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    ///
+    /// buf.put(b'h');
+    /// buf.put(&b"ello"[..]);
+    /// buf.put(" world");
+    ///
+    /// assert_eq!(buf, b"hello world");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics if `self` does not have enough capacity to contain `src`.
+    fn put<T: IntoBuf>(&mut self, src: T) where Self: Sized {
+        use super::Buf;
+
+        let mut src = src.into_buf();
+
+        assert!(self.remaining_mut() >= src.remaining());
+
+        while src.has_remaining() {
+            let l;
+
+            unsafe {
+                let s = src.bytes();
+                let d = self.bytes_mut();
+                l = cmp::min(s.len(), d.len());
+
+                ptr::copy_nonoverlapping(
+                    s.as_ptr(),
+                    d.as_mut_ptr(),
+                    l);
+            }
+
+            src.advance(l);
+            unsafe { self.advance_mut(l); }
+        }
+    }
+
+    /// Transfer bytes into `self` from `src` and advance the cursor by the
+    /// number of bytes written.
+    ///
+    /// `self` must have enough remaining capacity to contain all of `src`.
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    /// use std::io::Cursor;
+    ///
+    /// let mut dst = [0; 6];
+    ///
+    /// {
+    ///     let mut buf = Cursor::new(&mut dst);
+    ///     buf.put_slice(b"hello");
+    ///
+    ///     assert_eq!(1, buf.remaining_mut());
+    /// }
+    ///
+    /// assert_eq!(b"hello\0", &dst);
+    /// ```
+    fn put_slice(&mut self, src: &[u8]) {
+        let mut off = 0;
+
+        assert!(self.remaining_mut() >= src.len(), "buffer overflow");
+
+        while off < src.len() {
+            let cnt;
+
+            unsafe {
+                let dst = self.bytes_mut();
+                cnt = cmp::min(dst.len(), src.len() - off);
+
+                ptr::copy_nonoverlapping(
+                    src[off..].as_ptr(),
+                    dst.as_mut_ptr(),
+                    cnt);
+
+                off += cnt;
+
+            }
+
+            unsafe { self.advance_mut(cnt); }
+        }
+    }
+
+    /// Writes an unsigned 8 bit integer to `self`.
+    ///
+    /// The current position is advanced by 1.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_u8(0x01);
+    /// assert_eq!(buf, b"\x01");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_u8(&mut self, n: u8) {
+        let src = [n];
+        self.put_slice(&src);
+    }
+
+    /// Writes a signed 8 bit integer to `self`.
+    ///
+    /// The current position is advanced by 1.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_i8(0x01);
+    /// assert_eq!(buf, b"\x01");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_i8(&mut self, n: i8) {
+        let src = [n as u8];
+        self.put_slice(&src)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_u16_be or put_u16_le")]
+    fn put_u16<T: ByteOrder>(&mut self, n: u16) where Self: Sized {
+        let mut buf = [0; 2];
+        T::write_u16(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes an unsigned 16 bit integer to `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_u16_be(0x0809);
+    /// assert_eq!(buf, b"\x08\x09");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_u16_be(&mut self, n: u16) {
+        let mut buf = [0; 2];
+        BigEndian::write_u16(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes an unsigned 16 bit integer to `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_u16_le(0x0809);
+    /// assert_eq!(buf, b"\x09\x08");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_u16_le(&mut self, n: u16) {
+        let mut buf = [0; 2];
+        LittleEndian::write_u16(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_i16_be or put_i16_le")]
+    fn put_i16<T: ByteOrder>(&mut self, n: i16) where Self: Sized {
+        let mut buf = [0; 2];
+        T::write_i16(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes a signed 16 bit integer to `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_i16_be(0x0809);
+    /// assert_eq!(buf, b"\x08\x09");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_i16_be(&mut self, n: i16) {
+        let mut buf = [0; 2];
+        BigEndian::write_i16(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes a signed 16 bit integer to `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 2.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_i16_le(0x0809);
+    /// assert_eq!(buf, b"\x09\x08");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_i16_le(&mut self, n: i16) {
+        let mut buf = [0; 2];
+        LittleEndian::write_i16(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_u32_be or put_u32_le")]
+    fn put_u32<T: ByteOrder>(&mut self, n: u32) where Self: Sized {
+        let mut buf = [0; 4];
+        T::write_u32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes an unsigned 32 bit integer to `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_u32_be(0x0809A0A1);
+    /// assert_eq!(buf, b"\x08\x09\xA0\xA1");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_u32_be(&mut self, n: u32) {
+        let mut buf = [0; 4];
+        BigEndian::write_u32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes an unsigned 32 bit integer to `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_u32_le(0x0809A0A1);
+    /// assert_eq!(buf, b"\xA1\xA0\x09\x08");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_u32_le(&mut self, n: u32) {
+        let mut buf = [0; 4];
+        LittleEndian::write_u32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_i32_be or put_i32_le")]
+    fn put_i32<T: ByteOrder>(&mut self, n: i32) where Self: Sized {
+        let mut buf = [0; 4];
+        T::write_i32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes a signed 32 bit integer to `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_i32_be(0x0809A0A1);
+    /// assert_eq!(buf, b"\x08\x09\xA0\xA1");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_i32_be(&mut self, n: i32) {
+        let mut buf = [0; 4];
+        BigEndian::write_i32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes a signed 32 bit integer to `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_i32_le(0x0809A0A1);
+    /// assert_eq!(buf, b"\xA1\xA0\x09\x08");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_i32_le(&mut self, n: i32) {
+        let mut buf = [0; 4];
+        LittleEndian::write_i32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_u64_be or put_u64_le")]
+    fn put_u64<T: ByteOrder>(&mut self, n: u64) where Self: Sized {
+        let mut buf = [0; 8];
+        T::write_u64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes an unsigned 64 bit integer to `self` in the big-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_u64_be(0x0102030405060708);
+    /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_u64_be(&mut self, n: u64) {
+        let mut buf = [0; 8];
+        BigEndian::write_u64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes an unsigned 64 bit integer to `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_u64_le(0x0102030405060708);
+    /// assert_eq!(buf, b"\x08\x07\x06\x05\x04\x03\x02\x01");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_u64_le(&mut self, n: u64) {
+        let mut buf = [0; 8];
+        LittleEndian::write_u64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_i64_be or put_i64_le")]
+    fn put_i64<T: ByteOrder>(&mut self, n: i64) where Self: Sized {
+        let mut buf = [0; 8];
+        T::write_i64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes a signed 64 bit integer to `self` in the big-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_i64_be(0x0102030405060708);
+    /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_i64_be(&mut self, n: i64) {
+        let mut buf = [0; 8];
+        BigEndian::write_i64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes a signed 64 bit integer to `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_i64_le(0x0102030405060708);
+    /// assert_eq!(buf, b"\x08\x07\x06\x05\x04\x03\x02\x01");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_i64_le(&mut self, n: i64) {
+        let mut buf = [0; 8];
+        LittleEndian::write_i64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_uint_be or put_uint_le")]
+    fn put_uint<T: ByteOrder>(&mut self, n: u64, nbytes: usize) where Self: Sized {
+        let mut buf = [0; 8];
+        T::write_uint(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
+    }
+
+    /// Writes an unsigned n-byte integer to `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_uint_be(0x010203, 3);
+    /// assert_eq!(buf, b"\x01\x02\x03");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_uint_be(&mut self, n: u64, nbytes: usize) {
+        let mut buf = [0; 8];
+        BigEndian::write_uint(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
+    }
+
+    /// Writes an unsigned n-byte integer to `self` in the little-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_uint_le(0x010203, 3);
+    /// assert_eq!(buf, b"\x03\x02\x01");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_uint_le(&mut self, n: u64, nbytes: usize) {
+        let mut buf = [0; 8];
+        LittleEndian::write_uint(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_int_be or put_int_le")]
+    fn put_int<T: ByteOrder>(&mut self, n: i64, nbytes: usize) where Self: Sized {
+        let mut buf = [0; 8];
+        T::write_int(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
+    }
+
+    /// Writes a signed n-byte integer to `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_int_be(0x010203, 3);
+    /// assert_eq!(buf, b"\x01\x02\x03");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_int_be(&mut self, n: i64, nbytes: usize) {
+        let mut buf = [0; 8];
+        BigEndian::write_int(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
+    }
+
+    /// Writes a signed n-byte integer to `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by `nbytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_int_le(0x010203, 3);
+    /// assert_eq!(buf, b"\x03\x02\x01");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_int_le(&mut self, n: i64, nbytes: usize) {
+        let mut buf = [0; 8];
+        LittleEndian::write_int(&mut buf, n, nbytes);
+        self.put_slice(&buf[0..nbytes])
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_f32_be or put_f32_le")]
+    fn put_f32<T: ByteOrder>(&mut self, n: f32) where Self: Sized {
+        let mut buf = [0; 4];
+        T::write_f32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes  an IEEE754 single-precision (4 bytes) floating point number to
+    /// `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_f32_be(1.2f32);
+    /// assert_eq!(buf, b"\x3F\x99\x99\x9A");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_f32_be(&mut self, n: f32) {
+        let mut buf = [0; 4];
+        BigEndian::write_f32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes  an IEEE754 single-precision (4 bytes) floating point number to
+    /// `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 4.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_f32_le(1.2f32);
+    /// assert_eq!(buf, b"\x9A\x99\x99\x3F");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_f32_le(&mut self, n: f32) {
+        let mut buf = [0; 4];
+        LittleEndian::write_f32(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    #[doc(hidden)]
+    #[deprecated(note="use put_f64_be or put_f64_le")]
+    fn put_f64<T: ByteOrder>(&mut self, n: f64) where Self: Sized {
+        let mut buf = [0; 8];
+        T::write_f64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes  an IEEE754 double-precision (8 bytes) floating point number to
+    /// `self` in big-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_f64_be(1.2f64);
+    /// assert_eq!(buf, b"\x3F\xF3\x33\x33\x33\x33\x33\x33");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_f64_be(&mut self, n: f64) {
+        let mut buf = [0; 8];
+        BigEndian::write_f64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Writes  an IEEE754 double-precision (8 bytes) floating point number to
+    /// `self` in little-endian byte order.
+    ///
+    /// The current position is advanced by 8.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![];
+    /// buf.put_f64_le(1.2f64);
+    /// assert_eq!(buf, b"\x33\x33\x33\x33\x33\x33\xF3\x3F");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This function panics if there is not enough remaining capacity in
+    /// `self`.
+    fn put_f64_le(&mut self, n: f64) {
+        let mut buf = [0; 8];
+        LittleEndian::write_f64(&mut buf, n);
+        self.put_slice(&buf)
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `BufMut`.
+    ///
+    /// The returned adapter also implements `BufMut` and will simply borrow
+    /// `self`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    /// use std::io;
+    ///
+    /// let mut buf = vec![];
+    ///
+    /// {
+    ///     let mut reference = buf.by_ref();
+    ///
+    ///     // Adapt reference to `std::io::Write`.
+    ///     let mut writer = reference.writer();
+    ///
+    ///     // Use the buffer as a writter
+    ///     io::Write::write(&mut writer, &b"hello world"[..]).unwrap();
+    /// } // drop our &mut reference so that we can use `buf` again
+    ///
+    /// assert_eq!(buf, &b"hello world"[..]);
+    /// ```
+    fn by_ref(&mut self) -> &mut Self where Self: Sized {
+        self
+    }
+
+    /// Creates an adaptor which implements the `Write` trait for `self`.
+    ///
+    /// This function returns a new value which implements `Write` by adapting
+    /// the `Write` trait functions to the `BufMut` trait functions. Given that
+    /// `BufMut` operations are infallible, none of the `Write` functions will
+    /// return with `Err`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BufMut;
+    /// use std::io::Write;
+    ///
+    /// let mut buf = vec![].writer();
+    ///
+    /// let num = buf.write(&b"hello world"[..]).unwrap();
+    /// assert_eq!(11, num);
+    ///
+    /// let buf = buf.into_inner();
+    ///
+    /// assert_eq!(*buf, b"hello world"[..]);
+    /// ```
+    fn writer(self) -> Writer<Self> where Self: Sized {
+        super::writer::new(self)
+    }
+}
+
+impl<'a, T: BufMut + ?Sized> BufMut for &'a mut T {
+    fn remaining_mut(&self) -> usize {
+        (**self).remaining_mut()
+    }
+
+    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
+        (**self).bytes_mut()
+    }
+
+    unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize {
+        (**self).bytes_vec_mut(dst)
+    }
+
+    unsafe fn advance_mut(&mut self, cnt: usize) {
+        (**self).advance_mut(cnt)
+    }
+}
+
+impl<T: BufMut + ?Sized> BufMut for Box<T> {
+    fn remaining_mut(&self) -> usize {
+        (**self).remaining_mut()
+    }
+
+    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
+        (**self).bytes_mut()
+    }
+
+    unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize {
+        (**self).bytes_vec_mut(dst)
+    }
+
+    unsafe fn advance_mut(&mut self, cnt: usize) {
+        (**self).advance_mut(cnt)
+    }
+}
+
+impl<T: AsMut<[u8]> + AsRef<[u8]>> BufMut for io::Cursor<T> {
+    fn remaining_mut(&self) -> usize {
+        use Buf;
+        self.remaining()
+    }
+
+    /// Advance the internal cursor of the BufMut
+    unsafe fn advance_mut(&mut self, cnt: usize) {
+        use Buf;
+        self.advance(cnt);
+    }
+
+    /// Returns a mutable slice starting at the current BufMut position and of
+    /// length between 0 and `BufMut::remaining()`.
+    ///
+    /// The returned byte slice may represent uninitialized memory.
+    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
+        let len = self.get_ref().as_ref().len();
+        let pos = self.position() as usize;
+
+        if pos >= len {
+            return Default::default();
+        }
+
+        &mut (self.get_mut().as_mut())[pos..]
+    }
+}
+
+impl BufMut for Vec<u8> {
+    #[inline]
+    fn remaining_mut(&self) -> usize {
+        usize::MAX - self.len()
+    }
+
+    #[inline]
+    unsafe fn advance_mut(&mut self, cnt: usize) {
+        let len = self.len();
+        let remaining = self.capacity() - len;
+        if cnt > remaining {
+            // Reserve additional capacity, and ensure that the total length
+            // will not overflow usize.
+            self.reserve(cnt);
+        }
+
+        self.set_len(len + cnt);
+    }
+
+    #[inline]
+    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
+        use std::slice;
+
+        if self.capacity() == self.len() {
+            self.reserve(64); // Grow the vec
+        }
+
+        let cap = self.capacity();
+        let len = self.len();
+
+        let ptr = self.as_mut_ptr();
+        &mut slice::from_raw_parts_mut(ptr, cap)[len..]
+    }
+}
+
+// The existance of this function makes the compiler catch if the BufMut
+// trait is "object-safe" or not.
+fn _assert_trait_object(_b: &BufMut) {}
diff --git a/third_party/bytes/src/buf/chain.rs b/third_party/bytes/src/buf/chain.rs
new file mode 100644
index 0000000..7dd44ab
--- /dev/null
+++ b/third_party/bytes/src/buf/chain.rs
@@ -0,0 +1,226 @@
+use {Buf, BufMut};
+use iovec::IoVec;
+
+/// A `Chain` sequences two buffers.
+///
+/// `Chain` is an adapter that links two underlying buffers and provides a
+/// continous view across both buffers. It is able to sequence either immutable
+/// buffers ([`Buf`] values) or mutable buffers ([`BufMut`] values).
+///
+/// This struct is generally created by calling [`Buf::chain`]. Please see that
+/// function's documentation for more detail.
+///
+/// # Examples
+///
+/// ```
+/// use bytes::{Bytes, Buf, IntoBuf};
+/// use bytes::buf::Chain;
+///
+/// let buf = Bytes::from(&b"hello "[..]).into_buf()
+///             .chain(Bytes::from(&b"world"[..]));
+///
+/// let full: Bytes = buf.collect();
+/// assert_eq!(full[..], b"hello world"[..]);
+/// ```
+///
+/// [`Buf::chain`]: trait.Buf.html#method.chain
+/// [`Buf`]: trait.Buf.html
+/// [`BufMut`]: trait.BufMut.html
+#[derive(Debug)]
+pub struct Chain<T, U> {
+    a: T,
+    b: U,
+}
+
+impl<T, U> Chain<T, U> {
+    /// Creates a new `Chain` sequencing the provided values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    /// use bytes::buf::Chain;
+    ///
+    /// let buf = Chain::new(
+    ///     BytesMut::with_capacity(1024),
+    ///     BytesMut::with_capacity(1024));
+    ///
+    /// // Use the chained buffer
+    /// ```
+    pub fn new(a: T, b: U) -> Chain<T, U> {
+        Chain {
+            a: a,
+            b: b,
+        }
+    }
+
+    /// Gets a reference to the first underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Bytes, Buf, IntoBuf};
+    ///
+    /// let buf = Bytes::from(&b"hello"[..]).into_buf()
+    ///             .chain(Bytes::from(&b"world"[..]));
+    ///
+    /// assert_eq!(buf.first_ref().get_ref()[..], b"hello"[..]);
+    /// ```
+    pub fn first_ref(&self) -> &T {
+        &self.a
+    }
+
+    /// Gets a mutable reference to the first underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Bytes, Buf, IntoBuf};
+    ///
+    /// let mut buf = Bytes::from(&b"hello "[..]).into_buf()
+    ///                 .chain(Bytes::from(&b"world"[..]));
+    ///
+    /// buf.first_mut().set_position(1);
+    ///
+    /// let full: Bytes = buf.collect();
+    /// assert_eq!(full[..], b"ello world"[..]);
+    /// ```
+    pub fn first_mut(&mut self) -> &mut T {
+        &mut self.a
+    }
+
+    /// Gets a reference to the last underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Bytes, Buf, IntoBuf};
+    ///
+    /// let buf = Bytes::from(&b"hello"[..]).into_buf()
+    ///             .chain(Bytes::from(&b"world"[..]));
+    ///
+    /// assert_eq!(buf.last_ref().get_ref()[..], b"world"[..]);
+    /// ```
+    pub fn last_ref(&self) -> &U {
+        &self.b
+    }
+
+    /// Gets a mutable reference to the last underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Bytes, Buf, IntoBuf};
+    ///
+    /// let mut buf = Bytes::from(&b"hello "[..]).into_buf()
+    ///                 .chain(Bytes::from(&b"world"[..]));
+    ///
+    /// buf.last_mut().set_position(1);
+    ///
+    /// let full: Bytes = buf.collect();
+    /// assert_eq!(full[..], b"hello orld"[..]);
+    /// ```
+    pub fn last_mut(&mut self) -> &mut U {
+        &mut self.b
+    }
+
+    /// Consumes this `Chain`, returning the underlying values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Bytes, Buf, IntoBuf};
+    ///
+    /// let buf = Bytes::from(&b"hello"[..]).into_buf()
+    ///             .chain(Bytes::from(&b"world"[..]));
+    ///
+    /// let (first, last) = buf.into_inner();
+    /// assert_eq!(first.get_ref()[..], b"hello"[..]);
+    /// assert_eq!(last.get_ref()[..], b"world"[..]);
+    /// ```
+    pub fn into_inner(self) -> (T, U) {
+        (self.a, self.b)
+    }
+}
+
+impl<T, U> Buf for Chain<T, U>
+    where T: Buf,
+          U: Buf,
+{
+    fn remaining(&self) -> usize {
+        self.a.remaining() + self.b.remaining()
+    }
+
+    fn bytes(&self) -> &[u8] {
+        if self.a.has_remaining() {
+            self.a.bytes()
+        } else {
+            self.b.bytes()
+        }
+    }
+
+    fn advance(&mut self, mut cnt: usize) {
+        let a_rem = self.a.remaining();
+
+        if a_rem != 0 {
+            if a_rem >= cnt {
+                self.a.advance(cnt);
+                return;
+            }
+
+            // Consume what is left of a
+            self.a.advance(a_rem);
+
+            cnt -= a_rem;
+        }
+
+        self.b.advance(cnt);
+    }
+
+    fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize {
+        let mut n = self.a.bytes_vec(dst);
+        n += self.b.bytes_vec(&mut dst[n..]);
+        n
+    }
+}
+
+impl<T, U> BufMut for Chain<T, U>
+    where T: BufMut,
+          U: BufMut,
+{
+    fn remaining_mut(&self) -> usize {
+        self.a.remaining_mut() + self.b.remaining_mut()
+    }
+
+    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
+        if self.a.has_remaining_mut() {
+            self.a.bytes_mut()
+        } else {
+            self.b.bytes_mut()
+        }
+    }
+
+    unsafe fn advance_mut(&mut self, mut cnt: usize) {
+        let a_rem = self.a.remaining_mut();
+
+        if a_rem != 0 {
+            if a_rem >= cnt {
+                self.a.advance_mut(cnt);
+                return;
+            }
+
+            // Consume what is left of a
+            self.a.advance_mut(a_rem);
+
+            cnt -= a_rem;
+        }
+
+        self.b.advance_mut(cnt);
+    }
+
+    unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize {
+        let mut n = self.a.bytes_vec_mut(dst);
+        n += self.b.bytes_vec_mut(&mut dst[n..]);
+        n
+    }
+}
diff --git a/third_party/bytes/src/buf/from_buf.rs b/third_party/bytes/src/buf/from_buf.rs
new file mode 100644
index 0000000..7ddccf6
--- /dev/null
+++ b/third_party/bytes/src/buf/from_buf.rs
@@ -0,0 +1,118 @@
+use std::prelude::v1::*;
+use {Buf, BufMut, IntoBuf, Bytes, BytesMut};
+
+/// Conversion from a [`Buf`]
+///
+/// Implementing `FromBuf` for a type defines how it is created from a buffer.
+/// This is common for types which represent byte storage of some kind.
+///
+/// [`FromBuf::from_buf`] is rarely called explicitly, and it is instead used
+/// through [`Buf::collect`]. See [`Buf::collect`] documentation for more examples.
+///
+/// See also [`IntoBuf`].
+///
+/// # Examples
+///
+/// Basic  usage:
+///
+/// ```
+/// use bytes::{Bytes, IntoBuf};
+/// use bytes::buf::FromBuf;
+///
+/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+/// let vec = Vec::from_buf(buf);
+///
+/// assert_eq!(vec, &b"hello world"[..]);
+/// ```
+///
+/// Using [`Buf::collect`] to implicitly use `FromBuf`:
+///
+/// ```
+/// use bytes::{Buf, Bytes, IntoBuf};
+///
+/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+/// let vec: Vec<u8> = buf.collect();
+///
+/// assert_eq!(vec, &b"hello world"[..]);
+/// ```
+///
+/// Implementing `FromBuf` for your type:
+///
+/// ```
+/// use bytes::{BufMut, Bytes};
+/// use bytes::buf::{IntoBuf, FromBuf};
+///
+/// // A sample buffer, that's just a wrapper over Vec<u8>
+/// struct MyBuffer(Vec<u8>);
+///
+/// impl FromBuf for MyBuffer {
+///     fn from_buf<B>(buf: B) -> Self where B: IntoBuf {
+///         let mut v = Vec::new();
+///         v.put(buf.into_buf());
+///         MyBuffer(v)
+///     }
+/// }
+///
+/// // Now we can make a new buf
+/// let buf = Bytes::from(&b"hello world"[..]);
+///
+/// // And make a MyBuffer out of it
+/// let my_buf = MyBuffer::from_buf(buf);
+///
+/// assert_eq!(my_buf.0, &b"hello world"[..]);
+/// ```
+///
+/// [`Buf`]: trait.Buf.html
+/// [`FromBuf::from_buf`]: #method.from_buf
+/// [`Buf::collect`]: trait.Buf.html#method.collect
+/// [`IntoBuf`]: trait.IntoBuf.html
+pub trait FromBuf {
+    /// Creates a value from a buffer.
+    ///
+    /// See the [type-level documentation](#) for more details.
+    ///
+    /// # Examples
+    ///
+    /// Basic  usage:
+    ///
+    /// ```
+    /// use bytes::{Bytes, IntoBuf};
+    /// use bytes::buf::FromBuf;
+    ///
+    /// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+    /// let vec = Vec::from_buf(buf);
+    ///
+    /// assert_eq!(vec, &b"hello world"[..]);
+    /// ```
+    fn from_buf<T>(buf: T) -> Self where T: IntoBuf;
+}
+
+impl FromBuf for Vec<u8> {
+    fn from_buf<T>(buf: T) -> Self
+        where T: IntoBuf
+    {
+        let buf = buf.into_buf();
+        let mut ret = Vec::with_capacity(buf.remaining());
+        ret.put(buf);
+        ret
+    }
+}
+
+impl FromBuf for Bytes {
+    fn from_buf<T>(buf: T) -> Self
+        where T: IntoBuf
+    {
+        BytesMut::from_buf(buf).freeze()
+    }
+}
+
+impl FromBuf for BytesMut {
+    fn from_buf<T>(buf: T) -> Self
+        where T: IntoBuf
+    {
+        let buf = buf.into_buf();
+        let mut ret = BytesMut::with_capacity(buf.remaining());
+        ret.put(buf);
+        ret
+    }
+}
diff --git a/third_party/bytes/src/buf/into_buf.rs b/third_party/bytes/src/buf/into_buf.rs
new file mode 100644
index 0000000..5c8a8d2
--- /dev/null
+++ b/third_party/bytes/src/buf/into_buf.rs
@@ -0,0 +1,139 @@
+use std::prelude::v1::*;
+use super::{Buf};
+
+use std::io;
+
+/// Conversion into a `Buf`
+///
+/// An `IntoBuf` implementation defines how to convert a value into a `Buf`.
+/// This is common for types that represent byte storage of some kind. `IntoBuf`
+/// may be implemented directly for types or on references for those types.
+///
+/// # Examples
+///
+/// ```
+/// use bytes::{Buf, IntoBuf, BigEndian};
+///
+/// let bytes = b"\x00\x01hello world";
+/// let mut buf = bytes.into_buf();
+///
+/// assert_eq!(1, buf.get_u16::<BigEndian>());
+///
+/// let mut rest = [0; 11];
+/// buf.copy_to_slice(&mut rest);
+///
+/// assert_eq!(b"hello world", &rest);
+/// ```
+pub trait IntoBuf {
+    /// The `Buf` type that `self` is being converted into
+    type Buf: Buf;
+
+    /// Creates a `Buf` from a value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Buf, IntoBuf, BigEndian};
+    ///
+    /// let bytes = b"\x00\x01hello world";
+    /// let mut buf = bytes.into_buf();
+    ///
+    /// assert_eq!(1, buf.get_u16::<BigEndian>());
+    ///
+    /// let mut rest = [0; 11];
+    /// buf.copy_to_slice(&mut rest);
+    ///
+    /// assert_eq!(b"hello world", &rest);
+    /// ```
+    fn into_buf(self) -> Self::Buf;
+}
+
+impl<T: Buf> IntoBuf for T {
+    type Buf = Self;
+
+    fn into_buf(self) -> Self {
+        self
+    }
+}
+
+impl<'a> IntoBuf for &'a [u8] {
+    type Buf = io::Cursor<&'a [u8]>;
+
+    fn into_buf(self) -> Self::Buf {
+        io::Cursor::new(self)
+    }
+}
+
+impl<'a> IntoBuf for &'a str {
+    type Buf = io::Cursor<&'a [u8]>;
+
+    fn into_buf(self) -> Self::Buf {
+        self.as_bytes().into_buf()
+    }
+}
+
+impl IntoBuf for Vec<u8> {
+    type Buf = io::Cursor<Vec<u8>>;
+
+    fn into_buf(self) -> Self::Buf {
+        io::Cursor::new(self)
+    }
+}
+
+impl<'a> IntoBuf for &'a Vec<u8> {
+    type Buf = io::Cursor<&'a [u8]>;
+
+    fn into_buf(self) -> Self::Buf {
+        io::Cursor::new(&self[..])
+    }
+}
+
+// Kind of annoying... but this impl is required to allow passing `&'static
+// [u8]` where for<'a> &'a T: IntoBuf is required.
+impl<'a> IntoBuf for &'a &'static [u8] {
+    type Buf = io::Cursor<&'static [u8]>;
+
+    fn into_buf(self) -> Self::Buf {
+        io::Cursor::new(self)
+    }
+}
+
+impl<'a> IntoBuf for &'a &'static str {
+    type Buf = io::Cursor<&'static [u8]>;
+
+    fn into_buf(self) -> Self::Buf {
+        self.as_bytes().into_buf()
+    }
+}
+
+impl IntoBuf for String {
+    type Buf = io::Cursor<Vec<u8>>;
+
+    fn into_buf(self) -> Self::Buf {
+        self.into_bytes().into_buf()
+    }
+}
+
+impl<'a> IntoBuf for &'a String {
+    type Buf = io::Cursor<&'a [u8]>;
+
+    fn into_buf(self) -> Self::Buf {
+        self.as_bytes().into_buf()
+    }
+}
+
+impl IntoBuf for u8 {
+    type Buf = Option<[u8; 1]>;
+
+    fn into_buf(self) -> Self::Buf {
+        Some([self])
+    }
+}
+
+impl IntoBuf for i8 {
+    type Buf = Option<[u8; 1]>;
+
+    fn into_buf(self) -> Self::Buf {
+        Some([self as u8; 1])
+    }
+}
diff --git a/third_party/bytes/src/buf/iter.rs b/third_party/bytes/src/buf/iter.rs
new file mode 100644
index 0000000..9345c05
--- /dev/null
+++ b/third_party/bytes/src/buf/iter.rs
@@ -0,0 +1,116 @@
+use Buf;
+
+/// Iterator over the bytes contained by the buffer.
+///
+/// This struct is created by the [`iter`] method on [`Buf`].
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use bytes::{Buf, IntoBuf, Bytes};
+///
+/// let buf = Bytes::from(&b"abc"[..]).into_buf();
+/// let mut iter = buf.iter();
+///
+/// assert_eq!(iter.next(), Some(b'a'));
+/// assert_eq!(iter.next(), Some(b'b'));
+/// assert_eq!(iter.next(), Some(b'c'));
+/// assert_eq!(iter.next(), None);
+/// ```
+///
+/// [`iter`]: trait.Buf.html#method.iter
+/// [`Buf`]: trait.Buf.html
+#[derive(Debug)]
+pub struct Iter<T> {
+    inner: T,
+}
+
+impl<T> Iter<T> {
+    /// Consumes this `Iter`, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, IntoBuf, Bytes};
+    ///
+    /// let buf = Bytes::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    ///
+    /// let buf = iter.into_inner();
+    /// assert_eq!(2, buf.remaining());
+    /// ```
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+
+    /// Gets a reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, IntoBuf, Bytes};
+    ///
+    /// let buf = Bytes::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    ///
+    /// assert_eq!(2, iter.get_ref().remaining());
+    /// ```
+    pub fn get_ref(&self) -> &T {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, IntoBuf, BytesMut};
+    ///
+    /// let buf = BytesMut::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    ///
+    /// iter.get_mut().set_position(0);
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+}
+
+pub fn new<T>(inner: T) -> Iter<T> {
+    Iter { inner: inner }
+}
+
+impl<T: Buf> Iterator for Iter<T> {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<u8> {
+        if !self.inner.has_remaining() {
+            return None;
+        }
+
+        let b = self.inner.bytes()[0];
+        self.inner.advance(1);
+        Some(b)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let rem = self.inner.remaining();
+        (rem, Some(rem))
+    }
+}
+
+impl<T: Buf> ExactSizeIterator for Iter<T> { }
diff --git a/third_party/bytes/src/buf/mod.rs b/third_party/bytes/src/buf/mod.rs
new file mode 100644
index 0000000..1f74e0a
--- /dev/null
+++ b/third_party/bytes/src/buf/mod.rs
@@ -0,0 +1,37 @@
+//! Utilities for working with buffers.
+//!
+//! A buffer is any structure that contains a sequence of bytes. The bytes may
+//! or may not be stored in contiguous memory. This module contains traits used
+//! to abstract over buffers as well as utilities for working with buffer types.
+//!
+//! # `Buf`, `BufMut`
+//!
+//! These are the two foundational traits for abstractly working with buffers.
+//! They can be thought as iterators for byte structures. They offer additional
+//! performance over `Iterator` by providing an API optimized for byte slices.
+//!
+//! See [`Buf`] and [`BufMut`] for more details.
+//!
+//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
+//! [`Buf`]: trait.Buf.html
+//! [`BufMut`]: trait.BufMut.html
+
+mod buf;
+mod buf_mut;
+mod from_buf;
+mod chain;
+mod into_buf;
+mod iter;
+mod reader;
+mod take;
+mod writer;
+
+pub use self::buf::Buf;
+pub use self::buf_mut::BufMut;
+pub use self::from_buf::FromBuf;
+pub use self::chain::Chain;
+pub use self::into_buf::IntoBuf;
+pub use self::iter::Iter;
+pub use self::reader::Reader;
+pub use self::take::Take;
+pub use self::writer::Writer;
diff --git a/third_party/bytes/src/buf/reader.rs b/third_party/bytes/src/buf/reader.rs
new file mode 100644
index 0000000..59f9c33
--- /dev/null
+++ b/third_party/bytes/src/buf/reader.rs
@@ -0,0 +1,88 @@
+use {Buf};
+
+use std::{cmp, io};
+
+/// A `Buf` adapter which implements `io::Read` for the inner value.
+///
+/// This struct is generally created by calling `reader()` on `Buf`. See
+/// documentation of [`reader()`](trait.Buf.html#method.reader) for more
+/// details.
+#[derive(Debug)]
+pub struct Reader<B> {
+    buf: B,
+}
+
+pub fn new<B>(buf: B) -> Reader<B> {
+    Reader { buf: buf }
+}
+
+impl<B: Buf> Reader<B> {
+    /// Gets a reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::Buf;
+    /// use std::io::{self, Cursor};
+    ///
+    /// let mut buf = Cursor::new(b"hello world").reader();
+    ///
+    /// assert_eq!(0, buf.get_ref().position());
+    /// ```
+    pub fn get_ref(&self) -> &B {
+        &self.buf
+    }
+
+    /// Gets a mutable reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::Buf;
+    /// use std::io::{self, Cursor};
+    ///
+    /// let mut buf = Cursor::new(b"hello world").reader();
+    /// let mut dst = vec![];
+    ///
+    /// buf.get_mut().set_position(2);
+    /// io::copy(&mut buf, &mut dst).unwrap();
+    ///
+    /// assert_eq!(*dst, b"llo world"[..]);
+    /// ```
+    pub fn get_mut(&mut self) -> &mut B {
+        &mut self.buf
+    }
+
+    /// Consumes this `Reader`, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::Buf;
+    /// use std::io::{self, Cursor};
+    ///
+    /// let mut buf = Cursor::new(b"hello world").reader();
+    /// let mut dst = vec![];
+    ///
+    /// io::copy(&mut buf, &mut dst).unwrap();
+    ///
+    /// let buf = buf.into_inner();
+    /// assert_eq!(0, buf.remaining());
+    /// ```
+    pub fn into_inner(self) -> B {
+        self.buf
+    }
+}
+
+impl<B: Buf + Sized> io::Read for Reader<B> {
+    fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
+        let len = cmp::min(self.buf.remaining(), dst.len());
+
+        Buf::copy_to_slice(&mut self.buf, &mut dst[0..len]);
+        Ok(len)
+    }
+}
diff --git a/third_party/bytes/src/buf/take.rs b/third_party/bytes/src/buf/take.rs
new file mode 100644
index 0000000..a0c8ed4
--- /dev/null
+++ b/third_party/bytes/src/buf/take.rs
@@ -0,0 +1,155 @@
+use {Buf};
+
+use std::cmp;
+
+/// A `Buf` adapter which limits the bytes read from an underlying buffer.
+///
+/// This struct is generally created by calling `take()` on `Buf`. See
+/// documentation of [`take()`](trait.Buf.html#method.take) for more details.
+#[derive(Debug)]
+pub struct Take<T> {
+    inner: T,
+    limit: usize,
+}
+
+pub fn new<T>(inner: T, limit: usize) -> Take<T> {
+    Take {
+        inner: inner,
+        limit: limit,
+    }
+}
+
+impl<T> Take<T> {
+    /// Consumes this `Take`, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, BufMut};
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world").take(2);
+    /// let mut dst = vec![];
+    ///
+    /// dst.put(&mut buf);
+    /// assert_eq!(*dst, b"he"[..]);
+    ///
+    /// let mut buf = buf.into_inner();
+    ///
+    /// dst.clear();
+    /// dst.put(&mut buf);
+    /// assert_eq!(*dst, b"llo world"[..]);
+    /// ```
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+
+    /// Gets a reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, BufMut};
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world").take(2);
+    ///
+    /// assert_eq!(0, buf.get_ref().position());
+    /// ```
+    pub fn get_ref(&self) -> &T {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, BufMut};
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world").take(2);
+    /// let mut dst = vec![];
+    ///
+    /// buf.get_mut().set_position(2);
+    ///
+    /// dst.put(&mut buf);
+    /// assert_eq!(*dst, b"ll"[..]);
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+
+    /// Returns the maximum number of bytes that can be read.
+    ///
+    /// # Note
+    ///
+    /// If the inner `Buf` has fewer bytes than indicated by this method then
+    /// that is the actual number of available bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::Buf;
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world").take(2);
+    ///
+    /// assert_eq!(2, buf.limit());
+    /// assert_eq!(b'h', buf.get_u8());
+    /// assert_eq!(1, buf.limit());
+    /// ```
+    pub fn limit(&self) -> usize {
+        self.limit
+    }
+
+    /// Sets the maximum number of bytes that can be read.
+    ///
+    /// # Note
+    ///
+    /// If the inner `Buf` has fewer bytes than `lim` then that is the actual
+    /// number of available bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, BufMut};
+    /// use std::io::Cursor;
+    ///
+    /// let mut buf = Cursor::new(b"hello world").take(2);
+    /// let mut dst = vec![];
+    ///
+    /// dst.put(&mut buf);
+    /// assert_eq!(*dst, b"he"[..]);
+    ///
+    /// dst.clear();
+    ///
+    /// buf.set_limit(3);
+    /// dst.put(&mut buf);
+    /// assert_eq!(*dst, b"llo"[..]);
+    /// ```
+    pub fn set_limit(&mut self, lim: usize) {
+        self.limit = lim
+    }
+}
+
+impl<T: Buf> Buf for Take<T> {
+    fn remaining(&self) -> usize {
+        cmp::min(self.inner.remaining(), self.limit)
+    }
+
+    fn bytes(&self) -> &[u8] {
+        let bytes = self.inner.bytes();
+        &bytes[..cmp::min(bytes.len(), self.limit)]
+    }
+
+    fn advance(&mut self, cnt: usize) {
+        assert!(cnt <= self.limit);
+        self.inner.advance(cnt);
+        self.limit -= cnt;
+    }
+}
diff --git a/third_party/bytes/src/buf/writer.rs b/third_party/bytes/src/buf/writer.rs
new file mode 100644
index 0000000..38a739a
--- /dev/null
+++ b/third_party/bytes/src/buf/writer.rs
@@ -0,0 +1,88 @@
+use BufMut;
+
+use std::{cmp, io};
+
+/// A `BufMut` adapter which implements `io::Write` for the inner value.
+///
+/// This struct is generally created by calling `writer()` on `BufMut`. See
+/// documentation of [`writer()`](trait.BufMut.html#method.writer) for more
+/// details.
+#[derive(Debug)]
+pub struct Writer<B> {
+    buf: B,
+}
+
+pub fn new<B>(buf: B) -> Writer<B> {
+    Writer { buf: buf }
+}
+
+impl<B: BufMut> Writer<B> {
+    /// Gets a reference to the underlying `BufMut`.
+    ///
+    /// It is inadvisable to directly write to the underlying `BufMut`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = Vec::with_capacity(1024).writer();
+    ///
+    /// assert_eq!(1024, buf.get_ref().capacity());
+    /// ```
+    pub fn get_ref(&self) -> &B {
+        &self.buf
+    }
+
+    /// Gets a mutable reference to the underlying `BufMut`.
+    ///
+    /// It is inadvisable to directly write to the underlying `BufMut`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::BufMut;
+    ///
+    /// let mut buf = vec![].writer();
+    ///
+    /// buf.get_mut().reserve(1024);
+    ///
+    /// assert_eq!(1024, buf.get_ref().capacity());
+    /// ```
+    pub fn get_mut(&mut self) -> &mut B {
+        &mut self.buf
+    }
+
+    /// Consumes this `Writer`, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::BufMut;
+    /// use std::io::{self, Cursor};
+    ///
+    /// let mut buf = vec![].writer();
+    /// let mut src = Cursor::new(b"hello world");
+    ///
+    /// io::copy(&mut src, &mut buf).unwrap();
+    ///
+    /// let buf = buf.into_inner();
+    /// assert_eq!(*buf, b"hello world"[..]);
+    /// ```
+    pub fn into_inner(self) -> B {
+        self.buf
+    }
+}
+
+impl<B: BufMut + Sized> io::Write for Writer<B> {
+    fn write(&mut self, src: &[u8]) -> io::Result<usize> {
+        let n = cmp::min(self.buf.remaining_mut(), src.len());
+
+        self.buf.put(&src[0..n]);
+        Ok(n)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
diff --git a/third_party/bytes/src/bytes.rs b/third_party/bytes/src/bytes.rs
new file mode 100644
index 0000000..d762044
--- /dev/null
+++ b/third_party/bytes/src/bytes.rs
@@ -0,0 +1,2830 @@
+use std::prelude::v1::*;
+use {IntoBuf, Buf, BufMut};
+use buf::Iter;
+use debug;
+
+use std::{cmp, fmt, mem, hash, ops, slice, ptr, usize};
+use std::borrow::{Borrow, BorrowMut};
+use std::io::Cursor;
+use std::sync::atomic::{self, AtomicUsize, AtomicPtr};
+use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, AcqRel};
+use std::iter::{FromIterator, Iterator};
+
+/// A reference counted contiguous slice of memory.
+///
+/// `Bytes` is an efficient container for storing and operating on contiguous
+/// slices of memory. It is intended for use primarily in networking code, but
+/// could have applications elsewhere as well.
+///
+/// `Bytes` values facilitate zero-copy network programming by allowing multiple
+/// `Bytes` objects to point to the same underlying memory. This is managed by
+/// using a reference count to track when the memory is no longer needed and can
+/// be freed.
+///
+/// ```
+/// use bytes::Bytes;
+///
+/// let mut mem = Bytes::from(&b"Hello world"[..]);
+/// let a = mem.slice(0, 5);
+///
+/// assert_eq!(&a[..], b"Hello");
+///
+/// let b = mem.split_to(6);
+///
+/// assert_eq!(&mem[..], b"world");
+/// assert_eq!(&b[..], b"Hello ");
+/// ```
+///
+/// # Memory layout
+///
+/// The `Bytes` struct itself is fairly small, limited to a pointer to the
+/// memory and 4 `usize` fields used to track information about which segment of
+/// the underlying memory the `Bytes` handle has access to.
+///
+/// The memory layout looks like this:
+///
+/// ```text
+/// +-------+
+/// | Bytes |
+/// +-------+
+///  /      \_____
+/// |              \
+/// v               v
+/// +-----+------------------------------------+
+/// | Arc |         |      Data     |          |
+/// +-----+------------------------------------+
+/// ```
+///
+/// `Bytes` keeps both a pointer to the shared `Arc` containing the full memory
+/// slice and a pointer to the start of the region visible by the handle.
+/// `Bytes` also tracks the length of its view into the memory.
+///
+/// # Sharing
+///
+/// The memory itself is reference counted, and multiple `Bytes` objects may
+/// point to the same region. Each `Bytes` handle point to different sections within
+/// the memory region, and `Bytes` handle may or may not have overlapping views
+/// into the memory.
+///
+///
+/// ```text
+///
+///    Arc ptrs                   +---------+
+///    ________________________ / | Bytes 2 |
+///   /                           +---------+
+///  /          +-----------+     |         |
+/// |_________/ |  Bytes 1  |     |         |
+/// |           +-----------+     |         |
+/// |           |           | ___/ data     | tail
+/// |      data |      tail |/              |
+/// v           v           v               v
+/// +-----+---------------------------------+-----+
+/// | Arc |     |           |               |     |
+/// +-----+---------------------------------+-----+
+/// ```
+///
+/// # Mutating
+///
+/// While `Bytes` handles may potentially represent overlapping views of the
+/// underlying memory slice and may not be mutated, `BytesMut` handles are
+/// guaranteed to be the only handle able to view that slice of memory. As such,
+/// `BytesMut` handles are able to mutate the underlying memory. Note that
+/// holding a unique view to a region of memory does not mean that there are no
+/// other `Bytes` and `BytesMut` handles with disjoint views of the underlying
+/// memory.
+///
+/// # Inline bytes
+///
+/// As an optimization, when the slice referenced by a `Bytes` or `BytesMut`
+/// handle is small enough [1], `Bytes` will avoid the allocation by inlining
+/// the slice directly in the handle. In this case, a clone is no longer
+/// "shallow" and the data will be copied.
+///
+/// [1] Small enough: 31 bytes on 64 bit systems, 15 on 32 bit systems.
+///
+pub struct Bytes {
+    inner: Inner,
+}
+
+/// A unique reference to a contiguous slice of memory.
+///
+/// `BytesMut` represents a unique view into a potentially shared memory region.
+/// Given the uniqueness guarantee, owners of `BytesMut` handles are able to
+/// mutate the memory. It is similar to a `Vec<u8>` but with less copies and
+/// allocations.
+///
+/// For more detail, see [Bytes](struct.Bytes.html).
+///
+/// # Growth
+///
+/// One key difference from `Vec<u8>` is that most operations **do not
+/// implicitly grow the buffer**. This means that calling `my_bytes.put("hello
+/// world");` could panic if `my_bytes` does not have enough capacity. Before
+/// writing to the buffer, ensure that there is enough remaining capacity by
+/// calling `my_bytes.remaining_mut()`. In general, avoiding calls to `reserve`
+/// is preferable.
+///
+/// The only exception is `extend` which implicitly reserves required capacity.
+///
+/// # Examples
+///
+/// ```
+/// use bytes::{BytesMut, BufMut};
+///
+/// let mut buf = BytesMut::with_capacity(64);
+///
+/// buf.put(b'h');
+/// buf.put(b'e');
+/// buf.put("llo");
+///
+/// assert_eq!(&buf[..], b"hello");
+///
+/// // Freeze the buffer so that it can be shared
+/// let a = buf.freeze();
+///
+/// // This does not allocate, instead `b` points to the same memory.
+/// let b = a.clone();
+///
+/// assert_eq!(&a[..], b"hello");
+/// assert_eq!(&b[..], b"hello");
+/// ```
+pub struct BytesMut {
+    inner: Inner,
+}
+
+// Both `Bytes` and `BytesMut` are backed by `Inner` and functions are delegated
+// to `Inner` functions. The `Bytes` and `BytesMut` shims ensure that functions
+// that mutate the underlying buffer are only performed when the data range
+// being mutated is only available via a single `BytesMut` handle.
+//
+// # Data storage modes
+//
+// The goal of `bytes` is to be as efficient as possible across a wide range of
+// potential usage patterns. As such, `bytes` needs to be able to handle buffers
+// that are never shared, shared on a single thread, and shared across many
+// threads. `bytes` also needs to handle both tiny buffers as well as very large
+// buffers. For example, [Cassandra](http://cassandra.apache.org) values have
+// been known to be in the hundreds of megabyte, and HTTP header values can be a
+// few characters in size.
+//
+// To achieve high performance in these various situations, `Bytes` and
+// `BytesMut` use different strategies for storing the buffer depending on the
+// usage pattern.
+//
+// ## Delayed `Arc` allocation
+//
+// When a `Bytes` or `BytesMut` is first created, there is only one outstanding
+// handle referencing the buffer. Since sharing is not yet required, an `Arc`* is
+// not used and the buffer is backed by a `Vec<u8>` directly. Using an
+// `Arc<Vec<u8>>` requires two allocations, so if the buffer ends up never being
+// shared, that allocation is avoided.
+//
+// When sharing does become necessary (`clone`, `split_to`, `split_off`), that
+// is when the buffer is promoted to being shareable. The `Vec<u8>` is moved
+// into an `Arc` and both the original handle and the new handle use the same
+// buffer via the `Arc`.
+//
+// * `Arc` is being used to signify an atomically reference counted cell. We
+// don't use the `Arc` implementation provided by `std` and instead use our own.
+// This ends up simplifying a number of the `unsafe` code snippets.
+//
+// ## Inlining small buffers
+//
+// The `Bytes` / `BytesMut` structs require 4 pointer sized fields. On 64 bit
+// systems, this ends up being 32 bytes, which is actually a lot of storage for
+// cases where `Bytes` is being used to represent small byte strings, such as
+// HTTP header names and values.
+//
+// To avoid any allocation at all in these cases, `Bytes` will use the struct
+// itself for storing the buffer, reserving 1 byte for meta data. This means
+// that, on 64 bit systems, 31 byte buffers require no allocation at all.
+//
+// The byte used for metadata stores a 2 bits flag used to indicate that the
+// buffer is stored inline as well as 6 bits for tracking the buffer length (the
+// return value of `Bytes::len`).
+//
+// ## Static buffers
+//
+// `Bytes` can also represent a static buffer, which is created with
+// `Bytes::from_static`. No copying or allocations are required for tracking
+// static buffers. The pointer to the `&'static [u8]`, the length, and a flag
+// tracking that the `Bytes` instance represents a static buffer is stored in
+// the `Bytes` struct.
+//
+// # Struct layout
+//
+// Both `Bytes` and `BytesMut` are wrappers around `Inner`, which provides the
+// data fields as well as all of the function implementations.
+//
+// The `Inner` struct is carefully laid out in order to support the
+// functionality described above as well as being as small as possible. Size is
+// important as growing the size of the `Bytes` struct from 32 bytes to 40 bytes
+// added as much as 15% overhead in benchmarks using `Bytes` in an HTTP header
+// map structure.
+//
+// The `Inner` struct contains the following fields:
+//
+// * `ptr: *mut u8`
+// * `len: usize`
+// * `cap: usize`
+// * `arc: AtomicPtr<Shared>`
+//
+// ## `ptr: *mut u8`
+//
+// A pointer to start of the handle's buffer view. When backed by a `Vec<u8>`,
+// this is always the `Vec`'s pointer. When backed by an `Arc<Vec<u8>>`, `ptr`
+// may have been shifted to point somewhere inside the buffer.
+//
+// When in "inlined" mode, `ptr` is used as part of the inlined buffer.
+//
+// ## `len: usize`
+//
+// The length of the handle's buffer view. When backed by a `Vec<u8>`, this is
+// always the `Vec`'s length. The slice represented by `ptr` and `len` should
+// (ideally) always be initialized memory.
+//
+// When in "inlined" mode, `len` is used as part of the inlined buffer.
+//
+// ## `cap: usize`
+//
+// The capacity of the handle's buffer view. When backed by a `Vec<u8>`, this is
+// always the `Vec`'s capacity. The slice represented by `ptr+len` and `cap-len`
+// may or may not be initialized memory.
+//
+// When in "inlined" mode, `cap` is used as part of the inlined buffer.
+//
+// ## `arc: AtomicPtr<Shared>`
+//
+// When `Inner` is in allocated mode (backed by Vec<u8> or Arc<Vec<u8>>), this
+// will be the pointer to the `Arc` structure tracking the ref count for the
+// underlying buffer. When the pointer is null, then the `Arc` has not been
+// allocated yet and `self` is the only outstanding handle for the underlying
+// buffer.
+//
+// The lower two bits of `arc` are used to track the storage mode of `Inner`.
+// `0b01` indicates inline storage, `0b10` indicates static storage, and `0b11`
+// indicates vector storage, not yet promoted to Arc.  Since pointers to
+// allocated structures are aligned, the lower two bits of a pointer will always
+// be 0. This allows disambiguating between a pointer and the two flags.
+//
+// When in "inlined" mode, the least significant byte of `arc` is also used to
+// store the length of the buffer view (vs. the capacity, which is a constant).
+//
+// The rest of `arc`'s bytes are used as part of the inline buffer, which means
+// that those bytes need to be located next to the `ptr`, `len`, and `cap`
+// fields, which make up the rest of the inline buffer. This requires special
+// casing the layout of `Inner` depending on if the target platform is bit or
+// little endian.
+//
+// On little endian platforms, the `arc` field must be the first field in the
+// struct. On big endian platforms, the `arc` field must be the last field in
+// the struct. Since a deterministic struct layout is required, `Inner` is
+// annotated with `#[repr(C)]`.
+//
+// # Thread safety
+//
+// `Bytes::clone()` returns a new `Bytes` handle with no copying. This is done
+// by bumping the buffer ref count and returning a new struct pointing to the
+// same buffer. However, the `Arc` structure is lazily allocated. This means
+// that if `Bytes` is stored itself in an `Arc` (`Arc<Bytes>`), the `clone`
+// function can be called concurrently from multiple threads. This is why an
+// `AtomicPtr` is used for the `arc` field vs. a `*const`.
+//
+// Care is taken to ensure that the need for synchronization is minimized. Most
+// operations do not require any synchronization.
+//
+#[cfg(target_endian = "little")]
+#[repr(C)]
+struct Inner {
+    // WARNING: Do not access the fields directly unless you know what you are
+    // doing. Instead, use the fns. See implementation comment above.
+    arc: AtomicPtr<Shared>,
+    ptr: *mut u8,
+    len: usize,
+    cap: usize,
+}
+
+#[cfg(target_endian = "big")]
+#[repr(C)]
+struct Inner {
+    // WARNING: Do not access the fields directly unless you know what you are
+    // doing. Instead, use the fns. See implementation comment above.
+    ptr: *mut u8,
+    len: usize,
+    cap: usize,
+    arc: AtomicPtr<Shared>,
+}
+
+// Thread-safe reference-counted container for the shared storage. This mostly
+// the same as `std::sync::Arc` but without the weak counter. The ref counting
+// fns are based on the ones found in `std`.
+//
+// The main reason to use `Shared` instead of `std::sync::Arc` is that it ends
+// up making the overall code simpler and easier to reason about. This is due to
+// some of the logic around setting `Inner::arc` and other ways the `arc` field
+// is used. Using `Arc` ended up requiring a number of funky transmutes and
+// other shenanigans to make it work.
+struct Shared {
+    vec: Vec<u8>,
+    original_capacity_repr: usize,
+    ref_count: AtomicUsize,
+}
+
+// Buffer storage strategy flags.
+const KIND_ARC: usize = 0b00;
+const KIND_INLINE: usize = 0b01;
+const KIND_STATIC: usize = 0b10;
+const KIND_VEC: usize = 0b11;
+const KIND_MASK: usize = 0b11;
+
+// The max original capacity value. Any `Bytes` allocated with a greater initial
+// capacity will default to this.
+const MAX_ORIGINAL_CAPACITY_WIDTH: usize = 17;
+// The original capacity algorithm will not take effect unless the originally
+// allocated capacity was at least 1kb in size.
+const MIN_ORIGINAL_CAPACITY_WIDTH: usize = 10;
+// The original capacity is stored in powers of 2 starting at 1kb to a max of
+// 64kb. Representing it as such requires only 3 bits of storage.
+const ORIGINAL_CAPACITY_MASK: usize = 0b11100;
+const ORIGINAL_CAPACITY_OFFSET: usize = 2;
+
+// When the storage is in the `Vec` representation, the pointer can be advanced
+// at most this value. This is due to the amount of storage available to track
+// the offset is usize - number of KIND bits and number of ORIGINAL_CAPACITY
+// bits.
+const VEC_POS_OFFSET: usize = 5;
+const MAX_VEC_POS: usize = usize::MAX >> VEC_POS_OFFSET;
+const NOT_VEC_POS_MASK: usize = 0b11111;
+
+// Bit op constants for extracting the inline length value from the `arc` field.
+const INLINE_LEN_MASK: usize = 0b11111100;
+const INLINE_LEN_OFFSET: usize = 2;
+
+// Byte offset from the start of `Inner` to where the inline buffer data
+// starts. On little endian platforms, the first byte of the struct is the
+// storage flag, so the data is shifted by a byte. On big endian systems, the
+// data starts at the beginning of the struct.
+#[cfg(target_endian = "little")]
+const INLINE_DATA_OFFSET: isize = 1;
+#[cfg(target_endian = "big")]
+const INLINE_DATA_OFFSET: isize = 0;
+
+#[cfg(target_pointer_width = "64")]
+const PTR_WIDTH: usize = 64;
+#[cfg(target_pointer_width = "32")]
+const PTR_WIDTH: usize = 32;
+
+// Inline buffer capacity. This is the size of `Inner` minus 1 byte for the
+// metadata.
+#[cfg(target_pointer_width = "64")]
+const INLINE_CAP: usize = 4 * 8 - 1;
+#[cfg(target_pointer_width = "32")]
+const INLINE_CAP: usize = 4 * 4 - 1;
+
+/*
+ *
+ * ===== Bytes =====
+ *
+ */
+
+impl Bytes {
+    /// Creates a new `Bytes` with the specified capacity.
+    ///
+    /// The returned `Bytes` will be able to hold at least `capacity` bytes
+    /// without reallocating. If `capacity` is under `4 * size_of::<usize>() - 1`,
+    /// then `BytesMut` will not allocate.
+    ///
+    /// It is important to note that this function does not specify the length
+    /// of the returned `Bytes`, but only the capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let mut bytes = Bytes::with_capacity(64);
+    ///
+    /// // `bytes` contains no data, even though there is capacity
+    /// assert_eq!(bytes.len(), 0);
+    ///
+    /// bytes.extend_from_slice(&b"hello world"[..]);
+    ///
+    /// assert_eq!(&bytes[..], b"hello world");
+    /// ```
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Bytes {
+        Bytes {
+            inner: Inner::with_capacity(capacity),
+        }
+    }
+
+    /// Creates a new empty `Bytes`.
+    ///
+    /// This will not allocate and the returned `Bytes` handle will be empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let b = Bytes::new();
+    /// assert_eq!(&b[..], b"");
+    /// ```
+    #[inline]
+    pub fn new() -> Bytes {
+        Bytes::with_capacity(0)
+    }
+
+    /// Creates a new `Bytes` from a static slice.
+    ///
+    /// The returned `Bytes` will point directly to the static slice. There is
+    /// no allocating or copying.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let b = Bytes::from_static(b"hello");
+    /// assert_eq!(&b[..], b"hello");
+    /// ```
+    #[inline]
+    pub fn from_static(bytes: &'static [u8]) -> Bytes {
+        Bytes {
+            inner: Inner::from_static(bytes),
+        }
+    }
+
+    /// Returns the number of bytes contained in this `Bytes`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let b = Bytes::from(&b"hello"[..]);
+    /// assert_eq!(b.len(), 5);
+    /// ```
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    /// Returns true if the `Bytes` has a length of 0.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let b = Bytes::new();
+    /// assert!(b.is_empty());
+    /// ```
+    pub fn is_empty(&self) -> bool {
+        self.inner.is_empty()
+    }
+
+    /// Returns a slice of self for the index range `[begin..end)`.
+    ///
+    /// This will increment the reference count for the underlying memory and
+    /// return a new `Bytes` handle set to the slice.
+    ///
+    /// This operation is `O(1)`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let a = Bytes::from(&b"hello world"[..]);
+    /// let b = a.slice(2, 5);
+    ///
+    /// assert_eq!(&b[..], b"llo");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Requires that `begin <= end` and `end <= self.len()`, otherwise slicing
+    /// will panic.
+    pub fn slice(&self, begin: usize, end: usize) -> Bytes {
+        assert!(begin <= end);
+        assert!(end <= self.len());
+
+        if end - begin <= INLINE_CAP {
+            return Bytes::from(&self[begin..end]);
+        }
+
+        let mut ret = self.clone();
+
+        unsafe {
+            ret.inner.set_end(end);
+            ret.inner.set_start(begin);
+        }
+
+        ret
+    }
+
+    /// Returns a slice of self for the index range `[begin..self.len())`.
+    ///
+    /// This will increment the reference count for the underlying memory and
+    /// return a new `Bytes` handle set to the slice.
+    ///
+    /// This operation is `O(1)` and is equivalent to `self.slice(begin,
+    /// self.len())`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let a = Bytes::from(&b"hello world"[..]);
+    /// let b = a.slice_from(6);
+    ///
+    /// assert_eq!(&b[..], b"world");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Requires that `begin <= self.len()`, otherwise slicing will panic.
+    pub fn slice_from(&self, begin: usize) -> Bytes {
+        self.slice(begin, self.len())
+    }
+
+    /// Returns a slice of self for the index range `[0..end)`.
+    ///
+    /// This will increment the reference count for the underlying memory and
+    /// return a new `Bytes` handle set to the slice.
+    ///
+    /// This operation is `O(1)` and is equivalent to `self.slice(0, end)`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let a = Bytes::from(&b"hello world"[..]);
+    /// let b = a.slice_to(5);
+    ///
+    /// assert_eq!(&b[..], b"hello");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Requires that `end <= self.len()`, otherwise slicing will panic.
+    pub fn slice_to(&self, end: usize) -> Bytes {
+        self.slice(0, end)
+    }
+
+    /// Splits the bytes into two at the given index.
+    ///
+    /// Afterwards `self` contains elements `[0, at)`, and the returned `Bytes`
+    /// contains elements `[at, len)`.
+    ///
+    /// This is an `O(1)` operation that just increases the reference count and
+    /// sets a few indices.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let mut a = Bytes::from(&b"hello world"[..]);
+    /// let b = a.split_off(5);
+    ///
+    /// assert_eq!(&a[..], b"hello");
+    /// assert_eq!(&b[..], b" world");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics if `at > len`.
+    pub fn split_off(&mut self, at: usize) -> Bytes {
+        assert!(at <= self.len());
+
+        if at == self.len() {
+            return Bytes::new();
+        }
+
+        if at == 0 {
+            return mem::replace(self, Bytes::new());
+        }
+
+        Bytes {
+            inner: self.inner.split_off(at),
+        }
+    }
+
+    /// Splits the bytes into two at the given index.
+    ///
+    /// Afterwards `self` contains elements `[at, len)`, and the returned
+    /// `Bytes` contains elements `[0, at)`.
+    ///
+    /// This is an `O(1)` operation that just increases the reference count and
+    /// sets a few indices.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let mut a = Bytes::from(&b"hello world"[..]);
+    /// let b = a.split_to(5);
+    ///
+    /// assert_eq!(&a[..], b" world");
+    /// assert_eq!(&b[..], b"hello");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics if `at > len`.
+    pub fn split_to(&mut self, at: usize) -> Bytes {
+        assert!(at <= self.len());
+
+        if at == self.len() {
+            return mem::replace(self, Bytes::new());
+        }
+
+        if at == 0 {
+            return Bytes::new();
+        }
+
+        Bytes {
+            inner: self.inner.split_to(at),
+        }
+    }
+
+    #[deprecated(since = "0.4.1", note = "use split_to instead")]
+    #[doc(hidden)]
+    pub fn drain_to(&mut self, at: usize) -> Bytes {
+        self.split_to(at)
+    }
+
+    /// Shortens the buffer, keeping the first `len` bytes and dropping the
+    /// rest.
+    ///
+    /// If `len` is greater than the buffer's current length, this has no
+    /// effect.
+    ///
+    /// The [`split_off`] method can emulate `truncate`, but this causes the
+    /// excess bytes to be returned instead of dropped.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let mut buf = Bytes::from(&b"hello world"[..]);
+    /// buf.truncate(5);
+    /// assert_eq!(buf, b"hello"[..]);
+    /// ```
+    ///
+    /// [`split_off`]: #method.split_off
+    pub fn truncate(&mut self, len: usize) {
+        self.inner.truncate(len);
+    }
+
+    /// Shortens the buffer, dropping the first `cnt` bytes and keeping the
+    /// rest.
+    ///
+    /// This is the same function as `Buf::advance`, and in the next breaking
+    /// release of `bytes`, this implementation will be removed in favor of
+    /// having `Bytes` implement `Buf`.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if `cnt` is greater than `self.len()`
+    #[inline]
+    pub fn advance(&mut self, cnt: usize) {
+        assert!(cnt <= self.len(), "cannot advance past `remaining`");
+        unsafe { self.inner.set_start(cnt); }
+    }
+
+    /// Clears the buffer, removing all data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let mut buf = Bytes::from(&b"hello world"[..]);
+    /// buf.clear();
+    /// assert!(buf.is_empty());
+    /// ```
+    pub fn clear(&mut self) {
+        self.truncate(0);
+    }
+
+    /// Attempts to convert into a `BytesMut` handle.
+    ///
+    /// This will only succeed if there are no other outstanding references to
+    /// the underlying chunk of memory. `Bytes` handles that contain inlined
+    /// bytes will always be convertable to `BytesMut`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let a = Bytes::from(&b"Mary had a little lamb, little lamb, little lamb..."[..]);
+    ///
+    /// // Create a shallow clone
+    /// let b = a.clone();
+    ///
+    /// // This will fail because `b` shares a reference with `a`
+    /// let a = a.try_mut().unwrap_err();
+    ///
+    /// drop(b);
+    ///
+    /// // This will succeed
+    /// let mut a = a.try_mut().unwrap();
+    ///
+    /// a[0] = b'b';
+    ///
+    /// assert_eq!(&a[..4], b"bary");
+    /// ```
+    pub fn try_mut(mut self) -> Result<BytesMut, Bytes> {
+        if self.inner.is_mut_safe() {
+            Ok(BytesMut { inner: self.inner })
+        } else {
+            Err(self)
+        }
+    }
+
+    /// Appends given bytes to this object.
+    ///
+    /// If this `Bytes` object has not enough capacity, it is resized first.
+    /// If it is shared (`refcount > 1`), it is copied first.
+    ///
+    /// This operation can be less effective than the similar operation on
+    /// `BytesMut`, especially on small additions.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::Bytes;
+    ///
+    /// let mut buf = Bytes::from("aabb");
+    /// buf.extend_from_slice(b"ccdd");
+    /// buf.extend_from_slice(b"eeff");
+    ///
+    /// assert_eq!(b"aabbccddeeff", &buf[..]);
+    /// ```
+    pub fn extend_from_slice(&mut self, extend: &[u8]) {
+        if extend.is_empty() {
+            return;
+        }
+
+        let new_cap = self.len().checked_add(extend.len()).expect("capacity overflow");
+
+        let result = match mem::replace(self, Bytes::new()).try_mut() {
+            Ok(mut bytes_mut) => {
+                bytes_mut.extend_from_slice(extend);
+                bytes_mut
+            },
+            Err(bytes) => {
+                let mut bytes_mut = BytesMut::with_capacity(new_cap);
+                bytes_mut.put_slice(&bytes);
+                bytes_mut.put_slice(extend);
+                bytes_mut
+            }
+        };
+
+        mem::replace(self, result.freeze());
+    }
+}
+
+impl IntoBuf for Bytes {
+    type Buf = Cursor<Self>;
+
+    fn into_buf(self) -> Self::Buf {
+        Cursor::new(self)
+    }
+}
+
+impl<'a> IntoBuf for &'a Bytes {
+    type Buf = Cursor<Self>;
+
+    fn into_buf(self) -> Self::Buf {
+        Cursor::new(self)
+    }
+}
+
+impl Clone for Bytes {
+    fn clone(&self) -> Bytes {
+        Bytes {
+            inner: unsafe { self.inner.shallow_clone(false) },
+        }
+    }
+}
+
+impl AsRef<[u8]> for Bytes {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        self.inner.as_ref()
+    }
+}
+
+impl ops::Deref for Bytes {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        self.inner.as_ref()
+    }
+}
+
+impl From<BytesMut> for Bytes {
+    fn from(src: BytesMut) -> Bytes {
+        src.freeze()
+    }
+}
+
+impl From<Vec<u8>> for Bytes {
+    fn from(src: Vec<u8>) -> Bytes {
+        BytesMut::from(src).freeze()
+    }
+}
+
+impl From<String> for Bytes {
+    fn from(src: String) -> Bytes {
+        BytesMut::from(src).freeze()
+    }
+}
+
+impl<'a> From<&'a [u8]> for Bytes {
+    fn from(src: &'a [u8]) -> Bytes {
+        BytesMut::from(src).freeze()
+    }
+}
+
+impl<'a> From<&'a str> for Bytes {
+    fn from(src: &'a str) -> Bytes {
+        BytesMut::from(src).freeze()
+    }
+}
+
+impl FromIterator<u8> for BytesMut {
+    fn from_iter<T: IntoIterator<Item = u8>>(into_iter: T) -> Self {
+        let iter = into_iter.into_iter();
+        let (min, maybe_max) = iter.size_hint();
+
+        let mut out = BytesMut::with_capacity(maybe_max.unwrap_or(min));
+
+        for i in iter {
+            out.reserve(1);
+            out.put(i);
+        }
+
+        out
+    }
+}
+
+impl FromIterator<u8> for Bytes {
+    fn from_iter<T: IntoIterator<Item = u8>>(into_iter: T) -> Self {
+        BytesMut::from_iter(into_iter).freeze()
+    }
+}
+
+impl PartialEq for Bytes {
+    fn eq(&self, other: &Bytes) -> bool {
+        self.inner.as_ref() == other.inner.as_ref()
+    }
+}
+
+impl PartialOrd for Bytes {
+    fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
+        self.inner.as_ref().partial_cmp(other.inner.as_ref())
+    }
+}
+
+impl Ord for Bytes {
+    fn cmp(&self, other: &Bytes) -> cmp::Ordering {
+        self.inner.as_ref().cmp(other.inner.as_ref())
+    }
+}
+
+impl Eq for Bytes {
+}
+
+impl Default for Bytes {
+    #[inline]
+    fn default() -> Bytes {
+        Bytes::new()
+    }
+}
+
+impl fmt::Debug for Bytes {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&debug::BsDebug(&self.inner.as_ref()), fmt)
+    }
+}
+
+impl hash::Hash for Bytes {
+    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
+        let s: &[u8] = self.as_ref();
+        s.hash(state);
+    }
+}
+
+impl Borrow<[u8]> for Bytes {
+    fn borrow(&self) -> &[u8] {
+        self.as_ref()
+    }
+}
+
+impl IntoIterator for Bytes {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<Bytes>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
+impl<'a> IntoIterator for &'a Bytes {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<&'a Bytes>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
+impl Extend<u8> for Bytes {
+    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item = u8> {
+        let iter = iter.into_iter();
+
+        let (lower, upper) = iter.size_hint();
+
+        // Avoid possible conversion into mut if there's nothing to add
+        if let Some(0) = upper {
+            return;
+        }
+
+        let mut bytes_mut = match mem::replace(self, Bytes::new()).try_mut() {
+            Ok(bytes_mut) => bytes_mut,
+            Err(bytes) => {
+                let mut bytes_mut = BytesMut::with_capacity(bytes.len() + lower);
+                bytes_mut.put_slice(&bytes);
+                bytes_mut
+            }
+        };
+
+        bytes_mut.extend(iter);
+
+        mem::replace(self, bytes_mut.freeze());
+    }
+}
+
+impl<'a> Extend<&'a u8> for Bytes {
+    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item = &'a u8> {
+        self.extend(iter.into_iter().map(|b| *b))
+    }
+}
+
+/*
+ *
+ * ===== BytesMut =====
+ *
+ */
+
+impl BytesMut {
+    /// Creates a new `BytesMut` with the specified capacity.
+    ///
+    /// The returned `BytesMut` will be able to hold at least `capacity` bytes
+    /// without reallocating. If `capacity` is under `4 * size_of::<usize>() - 1`,
+    /// then `BytesMut` will not allocate.
+    ///
+    /// It is important to note that this function does not specify the length
+    /// of the returned `BytesMut`, but only the capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{BytesMut, BufMut};
+    ///
+    /// let mut bytes = BytesMut::with_capacity(64);
+    ///
+    /// // `bytes` contains no data, even though there is capacity
+    /// assert_eq!(bytes.len(), 0);
+    ///
+    /// bytes.put(&b"hello world"[..]);
+    ///
+    /// assert_eq!(&bytes[..], b"hello world");
+    /// ```
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> BytesMut {
+        BytesMut {
+            inner: Inner::with_capacity(capacity),
+        }
+    }
+
+    /// Creates a new `BytesMut` with default capacity.
+    ///
+    /// Resulting object has length 0 and unspecified capacity.
+    /// This function does not allocate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{BytesMut, BufMut};
+    ///
+    /// let mut bytes = BytesMut::new();
+    ///
+    /// assert_eq!(0, bytes.len());
+    ///
+    /// bytes.reserve(2);
+    /// bytes.put_slice(b"xy");
+    ///
+    /// assert_eq!(&b"xy"[..], &bytes[..]);
+    /// ```
+    #[inline]
+    pub fn new() -> BytesMut {
+        BytesMut::with_capacity(0)
+    }
+
+    /// Returns the number of bytes contained in this `BytesMut`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let b = BytesMut::from(&b"hello"[..]);
+    /// assert_eq!(b.len(), 5);
+    /// ```
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    /// Returns true if the `BytesMut` has a length of 0.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let b = BytesMut::with_capacity(64);
+    /// assert!(b.is_empty());
+    /// ```
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Returns the number of bytes the `BytesMut` can hold without reallocating.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let b = BytesMut::with_capacity(64);
+    /// assert_eq!(b.capacity(), 64);
+    /// ```
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
+    /// Converts `self` into an immutable `Bytes`.
+    ///
+    /// The conversion is zero cost and is used to indicate that the slice
+    /// referenced by the handle will no longer be mutated. Once the conversion
+    /// is done, the handle can be cloned and shared across threads.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{BytesMut, BufMut};
+    /// use std::thread;
+    ///
+    /// let mut b = BytesMut::with_capacity(64);
+    /// b.put("hello world");
+    /// let b1 = b.freeze();
+    /// let b2 = b1.clone();
+    ///
+    /// let th = thread::spawn(move || {
+    ///     assert_eq!(&b1[..], b"hello world");
+    /// });
+    ///
+    /// assert_eq!(&b2[..], b"hello world");
+    /// th.join().unwrap();
+    /// ```
+    #[inline]
+    pub fn freeze(self) -> Bytes {
+        Bytes { inner: self.inner }
+    }
+
+    /// Splits the bytes into two at the given index.
+    ///
+    /// Afterwards `self` contains elements `[0, at)`, and the returned
+    /// `BytesMut` contains elements `[at, capacity)`.
+    ///
+    /// This is an `O(1)` operation that just increases the reference count
+    /// and sets a few indices.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut a = BytesMut::from(&b"hello world"[..]);
+    /// let mut b = a.split_off(5);
+    ///
+    /// a[0] = b'j';
+    /// b[0] = b'!';
+    ///
+    /// assert_eq!(&a[..], b"jello");
+    /// assert_eq!(&b[..], b"!world");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics if `at > capacity`.
+    pub fn split_off(&mut self, at: usize) -> BytesMut {
+        BytesMut {
+            inner: self.inner.split_off(at),
+        }
+    }
+
+    /// Removes the bytes from the current view, returning them in a new
+    /// `BytesMut` handle.
+    ///
+    /// Afterwards, `self` will be empty, but will retain any additional
+    /// capacity that it had before the operation. This is identical to
+    /// `self.split_to(self.len())`.
+    ///
+    /// This is an `O(1)` operation that just increases the reference count and
+    /// sets a few indices.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{BytesMut, BufMut};
+    ///
+    /// let mut buf = BytesMut::with_capacity(1024);
+    /// buf.put(&b"hello world"[..]);
+    ///
+    /// let other = buf.take();
+    ///
+    /// assert!(buf.is_empty());
+    /// assert_eq!(1013, buf.capacity());
+    ///
+    /// assert_eq!(other, b"hello world"[..]);
+    /// ```
+    pub fn take(&mut self) -> BytesMut {
+        let len = self.len();
+        self.split_to(len)
+    }
+
+    #[deprecated(since = "0.4.1", note = "use take instead")]
+    #[doc(hidden)]
+    pub fn drain(&mut self) -> BytesMut {
+        self.take()
+    }
+
+    /// Splits the buffer into two at the given index.
+    ///
+    /// Afterwards `self` contains elements `[at, len)`, and the returned `BytesMut`
+    /// contains elements `[0, at)`.
+    ///
+    /// This is an `O(1)` operation that just increases the reference count and
+    /// sets a few indices.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut a = BytesMut::from(&b"hello world"[..]);
+    /// let mut b = a.split_to(5);
+    ///
+    /// a[0] = b'!';
+    /// b[0] = b'j';
+    ///
+    /// assert_eq!(&a[..], b"!world");
+    /// assert_eq!(&b[..], b"jello");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics if `at > len`.
+    pub fn split_to(&mut self, at: usize) -> BytesMut {
+        BytesMut {
+            inner: self.inner.split_to(at),
+        }
+    }
+
+    #[deprecated(since = "0.4.1", note = "use split_to instead")]
+    #[doc(hidden)]
+    pub fn drain_to(&mut self, at: usize) -> BytesMut {
+        self.split_to(at)
+    }
+
+    /// Shortens the buffer, keeping the first `len` bytes and dropping the
+    /// rest.
+    ///
+    /// If `len` is greater than the buffer's current length, this has no
+    /// effect.
+    ///
+    /// The [`split_off`] method can emulate `truncate`, but this causes the
+    /// excess bytes to be returned instead of dropped.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut buf = BytesMut::from(&b"hello world"[..]);
+    /// buf.truncate(5);
+    /// assert_eq!(buf, b"hello"[..]);
+    /// ```
+    ///
+    /// [`split_off`]: #method.split_off
+    pub fn truncate(&mut self, len: usize) {
+        self.inner.truncate(len);
+    }
+
+    /// Shortens the buffer, dropping the first `cnt` bytes and keeping the
+    /// rest.
+    ///
+    /// This is the same function as `Buf::advance`, and in the next breaking
+    /// release of `bytes`, this implementation will be removed in favor of
+    /// having `BytesMut` implement `Buf`.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if `cnt` is greater than `self.len()`
+    #[inline]
+    pub fn advance(&mut self, cnt: usize) {
+        assert!(cnt <= self.len(), "cannot advance past `remaining`");
+        unsafe { self.inner.set_start(cnt); }
+    }
+
+    /// Clears the buffer, removing all data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut buf = BytesMut::from(&b"hello world"[..]);
+    /// buf.clear();
+    /// assert!(buf.is_empty());
+    /// ```
+    pub fn clear(&mut self) {
+        self.truncate(0);
+    }
+
+    /// Resizes the buffer so that `len` is equal to `new_len`.
+    ///
+    /// If `new_len` is greater than `len`, the buffer is extended by the
+    /// difference with each additional byte set to `value`. If `new_len` is
+    /// less than `len`, the buffer is simply truncated.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut buf = BytesMut::new();
+    ///
+    /// buf.resize(3, 0x1);
+    /// assert_eq!(&buf[..], &[0x1, 0x1, 0x1]);
+    ///
+    /// buf.resize(2, 0x2);
+    /// assert_eq!(&buf[..], &[0x1, 0x1]);
+    ///
+    /// buf.resize(4, 0x3);
+    /// assert_eq!(&buf[..], &[0x1, 0x1, 0x3, 0x3]);
+    /// ```
+    pub fn resize(&mut self, new_len: usize, value: u8) {
+        self.inner.resize(new_len, value);
+    }
+
+    /// Sets the length of the buffer.
+    ///
+    /// This will explicitly set the size of the buffer without actually
+    /// modifying the data, so it is up to the caller to ensure that the data
+    /// has been initialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut b = BytesMut::from(&b"hello world"[..]);
+    ///
+    /// unsafe {
+    ///     b.set_len(5);
+    /// }
+    ///
+    /// assert_eq!(&b[..], b"hello");
+    ///
+    /// unsafe {
+    ///     b.set_len(11);
+    /// }
+    ///
+    /// assert_eq!(&b[..], b"hello world");
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// This method will panic if `len` is out of bounds for the underlying
+    /// slice or if it comes after the `end` of the configured window.
+    pub unsafe fn set_len(&mut self, len: usize) {
+        self.inner.set_len(len)
+    }
+
+    /// Reserves capacity for at least `additional` more bytes to be inserted
+    /// into the given `BytesMut`.
+    ///
+    /// More than `additional` bytes may be reserved in order to avoid frequent
+    /// reallocations. A call to `reserve` may result in an allocation.
+    ///
+    /// Before allocating new buffer space, the function will attempt to reclaim
+    /// space in the existing buffer. If the current handle references a small
+    /// view in the original buffer and all other handles have been dropped,
+    /// and the requested capacity is less than or equal to the existing
+    /// buffer's capacity, then the current view will be copied to the front of
+    /// the buffer and the handle will take ownership of the full buffer.
+    ///
+    /// # Examples
+    ///
+    /// In the following example, a new buffer is allocated.
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut buf = BytesMut::from(&b"hello"[..]);
+    /// buf.reserve(64);
+    /// assert!(buf.capacity() >= 69);
+    /// ```
+    ///
+    /// In the following example, the existing buffer is reclaimed.
+    ///
+    /// ```
+    /// use bytes::{BytesMut, BufMut};
+    ///
+    /// let mut buf = BytesMut::with_capacity(128);
+    /// buf.put(&[0; 64][..]);
+    ///
+    /// let ptr = buf.as_ptr();
+    /// let other = buf.take();
+    ///
+    /// assert!(buf.is_empty());
+    /// assert_eq!(buf.capacity(), 64);
+    ///
+    /// drop(other);
+    /// buf.reserve(128);
+    ///
+    /// assert_eq!(buf.capacity(), 128);
+    /// assert_eq!(buf.as_ptr(), ptr);
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity overflows `usize`.
+    pub fn reserve(&mut self, additional: usize) {
+        self.inner.reserve(additional)
+    }
+
+    /// Appends given bytes to this object.
+    ///
+    /// If this `BytesMut` object has not enough capacity, it is resized first.
+    /// So unlike `put_slice` operation, `extend_from_slice` does not panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut buf = BytesMut::with_capacity(0);
+    /// buf.extend_from_slice(b"aaabbb");
+    /// buf.extend_from_slice(b"cccddd");
+    ///
+    /// assert_eq!(b"aaabbbcccddd", &buf[..]);
+    /// ```
+    pub fn extend_from_slice(&mut self, extend: &[u8]) {
+        self.reserve(extend.len());
+        self.put_slice(extend);
+    }
+
+    /// Combine splitted BytesMut objects back as contiguous.
+    ///
+    /// If `BytesMut` objects were not contiguous originally, they will be extended.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::BytesMut;
+    ///
+    /// let mut buf = BytesMut::with_capacity(64);
+    /// buf.extend_from_slice(b"aaabbbcccddd");
+    ///
+    /// let splitted = buf.split_off(6);
+    /// assert_eq!(b"aaabbb", &buf[..]);
+    /// assert_eq!(b"cccddd", &splitted[..]);
+    ///
+    /// buf.unsplit(splitted);
+    /// assert_eq!(b"aaabbbcccddd", &buf[..]);
+    /// ```
+    pub fn unsplit(&mut self, other: BytesMut) {
+        let ptr;
+
+        if other.is_empty() {
+            return;
+        }
+
+        if self.is_empty() {
+            *self = other;
+            return;
+        }
+
+        unsafe {
+            ptr = self.inner.ptr.offset(self.inner.len as isize); 
+        }
+        if ptr == other.inner.ptr &&
+           self.inner.kind() == KIND_ARC &&
+           other.inner.kind() == KIND_ARC
+        {
+            debug_assert_eq!(self.inner.arc.load(Acquire),
+                             other.inner.arc.load(Acquire));
+            // Contiguous blocks, just combine directly
+            self.inner.len += other.inner.len;
+            self.inner.cap += other.inner.cap;
+        }
+        else {
+            self.extend_from_slice(&other);
+        }
+    }
+}
+
+impl BufMut for BytesMut {
+    #[inline]
+    fn remaining_mut(&self) -> usize {
+        self.capacity() - self.len()
+    }
+
+    #[inline]
+    unsafe fn advance_mut(&mut self, cnt: usize) {
+        let new_len = self.len() + cnt;
+
+        // This call will panic if `cnt` is too big
+        self.inner.set_len(new_len);
+    }
+
+    #[inline]
+    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
+        let len = self.len();
+
+        // This will never panic as `len` can never become invalid
+        &mut self.inner.as_raw()[len..]
+    }
+
+    #[inline]
+    fn put_slice(&mut self, src: &[u8]) {
+        assert!(self.remaining_mut() >= src.len());
+
+        let len = src.len();
+
+        unsafe {
+            self.bytes_mut()[..len].copy_from_slice(src);
+            self.advance_mut(len);
+        }
+    }
+
+    #[inline]
+    fn put_u8(&mut self, n: u8) {
+        self.inner.put_u8(n);
+    }
+
+    #[inline]
+    fn put_i8(&mut self, n: i8) {
+        self.put_u8(n as u8);
+    }
+}
+
+impl IntoBuf for BytesMut {
+    type Buf = Cursor<Self>;
+
+    fn into_buf(self) -> Self::Buf {
+        Cursor::new(self)
+    }
+}
+
+impl<'a> IntoBuf for &'a BytesMut {
+    type Buf = Cursor<&'a BytesMut>;
+
+    fn into_buf(self) -> Self::Buf {
+        Cursor::new(self)
+    }
+}
+
+impl AsRef<[u8]> for BytesMut {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        self.inner.as_ref()
+    }
+}
+
+impl ops::Deref for BytesMut {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        self.as_ref()
+    }
+}
+
+impl AsMut<[u8]> for BytesMut {
+    fn as_mut(&mut self) -> &mut [u8] {
+        self.inner.as_mut()
+    }
+}
+
+impl ops::DerefMut for BytesMut {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut [u8] {
+        self.inner.as_mut()
+    }
+}
+
+impl From<Vec<u8>> for BytesMut {
+    fn from(src: Vec<u8>) -> BytesMut {
+        BytesMut {
+            inner: Inner::from_vec(src),
+        }
+    }
+}
+
+impl From<String> for BytesMut {
+    fn from(src: String) -> BytesMut {
+        BytesMut::from(src.into_bytes())
+    }
+}
+
+impl<'a> From<&'a [u8]> for BytesMut {
+    fn from(src: &'a [u8]) -> BytesMut {
+        let len = src.len();
+
+        if len == 0 {
+            BytesMut::new()
+        } else if len <= INLINE_CAP {
+            unsafe {
+                let mut inner: Inner = mem::uninitialized();
+
+                // Set inline mask
+                inner.arc = AtomicPtr::new(KIND_INLINE as *mut Shared);
+                inner.set_inline_len(len);
+                inner.as_raw()[0..len].copy_from_slice(src);
+
+                BytesMut {
+                    inner: inner,
+                }
+            }
+        } else {
+            BytesMut::from(src.to_vec())
+        }
+    }
+}
+
+impl<'a> From<&'a str> for BytesMut {
+    fn from(src: &'a str) -> BytesMut {
+        BytesMut::from(src.as_bytes())
+    }
+}
+
+impl From<Bytes> for BytesMut {
+    fn from(src: Bytes) -> BytesMut {
+        src.try_mut()
+            .unwrap_or_else(|src| BytesMut::from(&src[..]))
+    }
+}
+
+impl PartialEq for BytesMut {
+    fn eq(&self, other: &BytesMut) -> bool {
+        self.inner.as_ref() == other.inner.as_ref()
+    }
+}
+
+impl PartialOrd for BytesMut {
+    fn partial_cmp(&self, other: &BytesMut) -> Option<cmp::Ordering> {
+        self.inner.as_ref().partial_cmp(other.inner.as_ref())
+    }
+}
+
+impl Ord for BytesMut {
+    fn cmp(&self, other: &BytesMut) -> cmp::Ordering {
+        self.inner.as_ref().cmp(other.inner.as_ref())
+    }
+}
+
+impl Eq for BytesMut {
+}
+
+impl Default for BytesMut {
+    #[inline]
+    fn default() -> BytesMut {
+        BytesMut::new()
+    }
+}
+
+impl fmt::Debug for BytesMut {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&debug::BsDebug(&self.inner.as_ref()), fmt)
+    }
+}
+
+impl hash::Hash for BytesMut {
+    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
+        let s: &[u8] = self.as_ref();
+        s.hash(state);
+    }
+}
+
+impl Borrow<[u8]> for BytesMut {
+    fn borrow(&self) -> &[u8] {
+        self.as_ref()
+    }
+}
+
+impl BorrowMut<[u8]> for BytesMut {
+    fn borrow_mut(&mut self) -> &mut [u8] {
+        self.as_mut()
+    }
+}
+
+impl fmt::Write for BytesMut {
+    #[inline]
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        if self.remaining_mut() >= s.len() {
+            self.put_slice(s.as_bytes());
+            Ok(())
+        } else {
+            Err(fmt::Error)
+        }
+    }
+
+    #[inline]
+    fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
+        fmt::write(self, args)
+    }
+}
+
+impl Clone for BytesMut {
+    fn clone(&self) -> BytesMut {
+        BytesMut::from(&self[..])
+    }
+}
+
+impl IntoIterator for BytesMut {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<BytesMut>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
+impl<'a> IntoIterator for &'a BytesMut {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<&'a BytesMut>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
+impl Extend<u8> for BytesMut {
+    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item = u8> {
+        let iter = iter.into_iter();
+
+        let (lower, _) = iter.size_hint();
+        self.reserve(lower);
+
+        for b in iter {
+            unsafe {
+                self.bytes_mut()[0] = b;
+                self.advance_mut(1);
+            }
+        }
+    }
+}
+
+impl<'a> Extend<&'a u8> for BytesMut {
+    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item = &'a u8> {
+        self.extend(iter.into_iter().map(|b| *b))
+    }
+}
+
+/*
+ *
+ * ===== Inner =====
+ *
+ */
+
+impl Inner {
+    #[inline]
+    fn from_static(bytes: &'static [u8]) -> Inner {
+        let ptr = bytes.as_ptr() as *mut u8;
+
+        Inner {
+            // `arc` won't ever store a pointer. Instead, use it to
+            // track the fact that the `Bytes` handle is backed by a
+            // static buffer.
+            arc: AtomicPtr::new(KIND_STATIC as *mut Shared),
+            ptr: ptr,
+            len: bytes.len(),
+            cap: bytes.len(),
+        }
+    }
+
+    #[inline]
+    fn from_vec(mut src: Vec<u8>) -> Inner {
+        let len = src.len();
+        let cap = src.capacity();
+        let ptr = src.as_mut_ptr();
+
+        mem::forget(src);
+
+        let original_capacity_repr = original_capacity_to_repr(cap);
+        let arc = (original_capacity_repr << ORIGINAL_CAPACITY_OFFSET) | KIND_VEC;
+
+        Inner {
+            arc: AtomicPtr::new(arc as *mut Shared),
+            ptr: ptr,
+            len: len,
+            cap: cap,
+        }
+    }
+
+    #[inline]
+    fn with_capacity(capacity: usize) -> Inner {
+        if capacity <= INLINE_CAP {
+            unsafe {
+                // Using uninitialized memory is ~30% faster
+                let mut inner: Inner = mem::uninitialized();
+                inner.arc = AtomicPtr::new(KIND_INLINE as *mut Shared);
+                inner
+            }
+        } else {
+            Inner::from_vec(Vec::with_capacity(capacity))
+        }
+    }
+
+    /// Return a slice for the handle's view into the shared buffer
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        unsafe {
+            if self.is_inline() {
+                slice::from_raw_parts(self.inline_ptr(), self.inline_len())
+            } else {
+                slice::from_raw_parts(self.ptr, self.len)
+            }
+        }
+    }
+
+    /// Return a mutable slice for the handle's view into the shared buffer
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8] {
+        debug_assert!(!self.is_static());
+
+        unsafe {
+            if self.is_inline() {
+                slice::from_raw_parts_mut(self.inline_ptr(), self.inline_len())
+            } else {
+                slice::from_raw_parts_mut(self.ptr, self.len)
+            }
+        }
+    }
+
+    /// Return a mutable slice for the handle's view into the shared buffer
+    /// including potentially uninitialized bytes.
+    #[inline]
+    unsafe fn as_raw(&mut self) -> &mut [u8] {
+        debug_assert!(!self.is_static());
+
+        if self.is_inline() {
+            slice::from_raw_parts_mut(self.inline_ptr(), INLINE_CAP)
+        } else {
+            slice::from_raw_parts_mut(self.ptr, self.cap)
+        }
+    }
+
+    /// Insert a byte into the next slot and advance the len by 1.
+    #[inline]
+    fn put_u8(&mut self, n: u8) {
+        if self.is_inline() {
+            let len = self.inline_len();
+            assert!(len < INLINE_CAP);
+            unsafe {
+                *self.inline_ptr().offset(len as isize) = n;
+            }
+            self.set_inline_len(len + 1);
+        } else {
+            assert!(self.len < self.cap);
+            unsafe {
+                *self.ptr.offset(self.len as isize) = n;
+            }
+            self.len += 1;
+        }
+    }
+
+    #[inline]
+    fn len(&self) -> usize {
+        if self.is_inline() {
+            self.inline_len()
+        } else {
+            self.len
+        }
+    }
+
+    /// Pointer to the start of the inline buffer
+    #[inline]
+    unsafe fn inline_ptr(&self) -> *mut u8 {
+        (self as *const Inner as *mut Inner as *mut u8)
+            .offset(INLINE_DATA_OFFSET)
+    }
+
+    #[inline]
+    fn inline_len(&self) -> usize {
+        let p: &usize = unsafe { mem::transmute(&self.arc) };
+        (p & INLINE_LEN_MASK) >> INLINE_LEN_OFFSET
+    }
+
+    /// Set the length of the inline buffer. This is done by writing to the
+    /// least significant byte of the `arc` field.
+    #[inline]
+    fn set_inline_len(&mut self, len: usize) {
+        debug_assert!(len <= INLINE_CAP);
+        let p = self.arc.get_mut();
+        *p = ((*p as usize & !INLINE_LEN_MASK) | (len << INLINE_LEN_OFFSET)) as _;
+    }
+
+    /// slice.
+    #[inline]
+    unsafe fn set_len(&mut self, len: usize) {
+        if self.is_inline() {
+            assert!(len <= INLINE_CAP);
+            self.set_inline_len(len);
+        } else {
+            assert!(len <= self.cap);
+            self.len = len;
+        }
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    #[inline]
+    fn capacity(&self) -> usize {
+        if self.is_inline() {
+            INLINE_CAP
+        } else {
+            self.cap
+        }
+    }
+
+    fn split_off(&mut self, at: usize) -> Inner {
+        let mut other = unsafe { self.shallow_clone(true) };
+
+        unsafe {
+            other.set_start(at);
+            self.set_end(at);
+        }
+
+        return other
+    }
+
+    fn split_to(&mut self, at: usize) -> Inner {
+        let mut other = unsafe { self.shallow_clone(true) };
+
+        unsafe {
+            other.set_end(at);
+            self.set_start(at);
+        }
+
+        return other
+    }
+
+    fn truncate(&mut self, len: usize) {
+        if len <= self.len() {
+            unsafe { self.set_len(len); }
+        }
+    }
+
+    fn resize(&mut self, new_len: usize, value: u8) {
+        let len = self.len();
+        if new_len > len {
+            let additional = new_len - len;
+            self.reserve(additional);
+            unsafe {
+                let dst = self.as_raw()[len..].as_mut_ptr();
+                ptr::write_bytes(dst, value, additional);
+                self.set_len(new_len);
+            }
+        } else {
+            self.truncate(new_len);
+        }
+    }
+
+    unsafe fn set_start(&mut self, start: usize) {
+        // Setting the start to 0 is a no-op, so return early if this is the
+        // case.
+        if start == 0 {
+            return;
+        }
+
+        let kind = self.kind();
+
+        // Always check `inline` first, because if the handle is using inline
+        // data storage, all of the `Inner` struct fields will be gibberish.
+        if kind == KIND_INLINE {
+            assert!(start <= INLINE_CAP);
+
+            let len = self.inline_len();
+
+            if len <= start {
+                self.set_inline_len(0);
+            } else {
+                // `set_start` is essentially shifting data off the front of the
+                // view. Inlined buffers only track the length of the slice.
+                // So, to update the start, the data at the new starting point
+                // is copied to the beginning of the buffer.
+                let new_len = len - start;
+
+                let dst = self.inline_ptr();
+                let src = (dst as *const u8).offset(start as isize);
+
+                ptr::copy(src, dst, new_len);
+
+                self.set_inline_len(new_len);
+            }
+        } else {
+            assert!(start <= self.cap);
+
+            if kind == KIND_VEC {
+                // Setting the start when in vec representation is a little more
+                // complicated. First, we have to track how far ahead the
+                // "start" of the byte buffer from the beginning of the vec. We
+                // also have to ensure that we don't exceed the maximum shift.
+                let (mut pos, prev) = self.uncoordinated_get_vec_pos();
+                pos += start;
+
+                if pos <= MAX_VEC_POS {
+                    self.uncoordinated_set_vec_pos(pos, prev);
+                } else {
+                    // The repr must be upgraded to ARC. This will never happen
+                    // on 64 bit systems and will only happen on 32 bit systems
+                    // when shifting past 134,217,727 bytes. As such, we don't
+                    // worry too much about performance here.
+                    let _ = self.shallow_clone(true);
+                }
+            }
+
+            // Updating the start of the view is setting `ptr` to point to the
+            // new start and updating the `len` field to reflect the new length
+            // of the view.
+            self.ptr = self.ptr.offset(start as isize);
+
+            if self.len >= start {
+                self.len -= start;
+            } else {
+                self.len = 0;
+            }
+
+            self.cap -= start;
+        }
+    }
+
+    unsafe fn set_end(&mut self, end: usize) {
+        debug_assert!(self.is_shared());
+
+        // Always check `inline` first, because if the handle is using inline
+        // data storage, all of the `Inner` struct fields will be gibberish.
+        if self.is_inline() {
+            assert!(end <= INLINE_CAP);
+            let new_len = cmp::min(self.inline_len(), end);
+            self.set_inline_len(new_len);
+        } else {
+            assert!(end <= self.cap);
+
+            self.cap = end;
+            self.len = cmp::min(self.len, end);
+        }
+    }
+
+    /// Checks if it is safe to mutate the memory
+    fn is_mut_safe(&mut self) -> bool {
+        let kind = self.kind();
+
+        // Always check `inline` first, because if the handle is using inline
+        // data storage, all of the `Inner` struct fields will be gibberish.
+        if kind == KIND_INLINE {
+            // Inlined buffers can always be mutated as the data is never shared
+            // across handles.
+            true
+        } else if kind == KIND_VEC {
+            true
+        } else if kind == KIND_STATIC {
+            false
+        } else {
+            // Otherwise, the underlying buffer is potentially shared with other
+            // handles, so the ref_count needs to be checked.
+            unsafe { (**self.arc.get_mut()).is_unique() }
+        }
+    }
+
+    /// Increments the ref count. This should only be done if it is known that
+    /// it can be done safely. As such, this fn is not public, instead other
+    /// fns will use this one while maintaining the guarantees.
+    /// Parameter `mut_self` should only be set to `true` if caller holds
+    /// `&mut self` reference.
+    ///
+    /// "Safely" is defined as not exposing two `BytesMut` values that point to
+    /// the same byte window.
+    ///
+    /// This function is thread safe.
+    unsafe fn shallow_clone(&self, mut_self: bool) -> Inner {
+        // Always check `inline` first, because if the handle is using inline
+        // data storage, all of the `Inner` struct fields will be gibberish.
+        if self.is_inline() {
+            // In this case, a shallow_clone still involves copying the data.
+            //
+            // TODO: Just copy the fields
+            let mut inner: Inner = mem::uninitialized();
+            let len = self.inline_len();
+
+            inner.arc = AtomicPtr::new(KIND_INLINE as *mut Shared);
+            inner.set_inline_len(len);
+            inner.as_raw()[0..len].copy_from_slice(self.as_ref());
+            inner
+        } else {
+            // The function requires `&self`, this means that `shallow_clone`
+            // could be called concurrently.
+            //
+            // The first step is to load the value of `arc`. This will determine
+            // how to proceed. The `Acquire` ordering synchronizes with the
+            // `compare_and_swap` that comes later in this function. The goal is
+            // to ensure that if `arc` is currently set to point to a `Shared`,
+            // that the current thread acquires the associated memory.
+            let mut arc = self.arc.load(Acquire);
+
+            // If  the buffer is still tracked in a `Vec<u8>`. It is time to
+            // promote the vec to an `Arc`. This could potentially be called
+            // concurrently, so some care must be taken.
+            if arc as usize & KIND_MASK == KIND_VEC {
+                let original_capacity_repr =
+                    (arc as usize & ORIGINAL_CAPACITY_MASK) >> ORIGINAL_CAPACITY_OFFSET;
+
+                // The vec offset cannot be concurrently mutated, so there
+                // should be no danger reading it.
+                let off = (arc as usize) >> VEC_POS_OFFSET;
+
+                // First, allocate a new `Shared` instance containing the
+                // `Vec` fields. It's important to note that `ptr`, `len`,
+                // and `cap` cannot be mutated without having `&mut self`.
+                // This means that these fields will not be concurrently
+                // updated and since the buffer hasn't been promoted to an
+                // `Arc`, those three fields still are the components of the
+                // vector.
+                let shared = Box::new(Shared {
+                    vec: rebuild_vec(self.ptr, self.len, self.cap, off),
+                    original_capacity_repr: original_capacity_repr,
+                    // Initialize refcount to 2. One for this reference, and one
+                    // for the new clone that will be returned from
+                    // `shallow_clone`.
+                    ref_count: AtomicUsize::new(2),
+                });
+
+                let shared = Box::into_raw(shared);
+
+                // The pointer should be aligned, so this assert should
+                // always succeed.
+                debug_assert!(0 == (shared as usize & 0b11));
+
+                // If there are no references to self in other threads,
+                // expensive atomic operations can be avoided.
+                if mut_self {
+                    self.arc.store(shared, Relaxed);
+                    return Inner {
+                        arc: AtomicPtr::new(shared),
+                        .. *self
+                    };
+                }
+
+                // Try compare & swapping the pointer into the `arc` field.
+                // `Release` is used synchronize with other threads that
+                // will load the `arc` field.
+                //
+                // If the `compare_and_swap` fails, then the thread lost the
+                // race to promote the buffer to shared. The `Acquire`
+                // ordering will synchronize with the `compare_and_swap`
+                // that happened in the other thread and the `Shared`
+                // pointed to by `actual` will be visible.
+                let actual = self.arc.compare_and_swap(arc, shared, AcqRel);
+
+                if actual == arc {
+                    // The upgrade was successful, the new handle can be
+                    // returned.
+                    return Inner {
+                        arc: AtomicPtr::new(shared),
+                        .. *self
+                    };
+                }
+
+                // The upgrade failed, a concurrent clone happened. Release
+                // the allocation that was made in this thread, it will not
+                // be needed.
+                let shared = Box::from_raw(shared);
+                mem::forget(*shared);
+
+                // Update the `arc` local variable and fall through to a ref
+                // count update
+                arc = actual;
+            } else if arc as usize & KIND_MASK == KIND_STATIC {
+                // Static buffer
+                return Inner {
+                    arc: AtomicPtr::new(arc),
+                    .. *self
+                };
+            }
+
+            // Buffer already promoted to shared storage, so increment ref
+            // count.
+            //
+            // Relaxed ordering is acceptable as the memory has already been
+            // acquired via the `Acquire` load above.
+            let old_size = (*arc).ref_count.fetch_add(1, Relaxed);
+
+            if old_size == usize::MAX {
+                panic!(); // TODO: abort
+            }
+
+            Inner {
+                arc: AtomicPtr::new(arc),
+                .. *self
+            }
+        }
+    }
+
+    #[inline]
+    fn reserve(&mut self, additional: usize) {
+        let len = self.len();
+        let rem = self.capacity() - len;
+
+        if additional <= rem {
+            // The handle can already store at least `additional` more bytes, so
+            // there is no further work needed to be done.
+            return;
+        }
+
+        let kind = self.kind();
+
+        // Always check `inline` first, because if the handle is using inline
+        // data storage, all of the `Inner` struct fields will be gibberish.
+        if kind == KIND_INLINE {
+            let new_cap = len + additional;
+
+            // Promote to a vector
+            let mut v = Vec::with_capacity(new_cap);
+            v.extend_from_slice(self.as_ref());
+
+            self.ptr = v.as_mut_ptr();
+            self.len = v.len();
+            self.cap = v.capacity();
+
+            // Since the minimum capacity is `INLINE_CAP`, don't bother encoding
+            // the original capacity as INLINE_CAP
+            self.arc = AtomicPtr::new(KIND_VEC as *mut Shared);
+
+            mem::forget(v);
+            return;
+        }
+
+        if kind == KIND_VEC {
+            // If there's enough free space before the start of the buffer, then
+            // just copy the data backwards and reuse the already-allocated
+            // space.
+            //
+            // Otherwise, since backed by a vector, use `Vec::reserve`
+            unsafe {
+                let (off, prev) = self.uncoordinated_get_vec_pos();
+
+                // Only reuse space if we stand to gain at least capacity/2
+                // bytes of space back
+                if off >= additional && off >= (self.cap / 2) {
+                    // There's space - reuse it
+                    //
+                    // Just move the pointer back to the start after copying
+                    // data back.
+                    let base_ptr = self.ptr.offset(-(off as isize));
+                    ptr::copy(self.ptr, base_ptr, self.len);
+                    self.ptr = base_ptr;
+                    self.uncoordinated_set_vec_pos(0, prev);
+
+                    // Length stays constant, but since we moved backwards we
+                    // can gain capacity back.
+                    self.cap += off;
+                } else {
+                    // No space - allocate more
+                    let mut v = rebuild_vec(self.ptr, self.len, self.cap, off);
+                    v.reserve(additional);
+
+                    // Update the info
+                    self.ptr = v.as_mut_ptr().offset(off as isize);
+                    self.len = v.len() - off;
+                    self.cap = v.capacity() - off;
+
+                    // Drop the vec reference
+                    mem::forget(v);
+                }
+                return;
+            }
+        }
+
+        let arc = *self.arc.get_mut();
+
+        debug_assert!(kind == KIND_ARC);
+
+        // Reserving involves abandoning the currently shared buffer and
+        // allocating a new vector with the requested capacity.
+        //
+        // Compute the new capacity
+        let mut new_cap = len + additional;
+        let original_capacity;
+        let original_capacity_repr;
+
+        unsafe {
+            original_capacity_repr = (*arc).original_capacity_repr;
+            original_capacity = original_capacity_from_repr(original_capacity_repr);
+
+            // First, try to reclaim the buffer. This is possible if the current
+            // handle is the only outstanding handle pointing to the buffer.
+            if (*arc).is_unique() {
+                // This is the only handle to the buffer. It can be reclaimed.
+                // However, before doing the work of copying data, check to make
+                // sure that the vector has enough capacity.
+                let v = &mut (*arc).vec;
+
+                if v.capacity() >= new_cap {
+                    // The capacity is sufficient, reclaim the buffer
+                    let ptr = v.as_mut_ptr();
+
+                    ptr::copy(self.ptr, ptr, len);
+
+                    self.ptr = ptr;
+                    self.cap = v.capacity();
+
+                    return;
+                }
+
+                // The vector capacity is not sufficient. The reserve request is
+                // asking for more than the initial buffer capacity. Allocate more
+                // than requested if `new_cap` is not much bigger than the current
+                // capacity.
+                //
+                // There are some situations, using `reserve_exact` that the
+                // buffer capacity could be below `original_capacity`, so do a
+                // check.
+                new_cap = cmp::max(
+                    cmp::max(v.capacity() << 1, new_cap),
+                    original_capacity);
+            } else {
+                new_cap = cmp::max(new_cap, original_capacity);
+            }
+        }
+
+        // Create a new vector to store the data
+        let mut v = Vec::with_capacity(new_cap);
+
+        // Copy the bytes
+        v.extend_from_slice(self.as_ref());
+
+        // Release the shared handle. This must be done *after* the bytes are
+        // copied.
+        release_shared(arc);
+
+        // Update self
+        self.ptr = v.as_mut_ptr();
+        self.len = v.len();
+        self.cap = v.capacity();
+
+        let arc = (original_capacity_repr << ORIGINAL_CAPACITY_OFFSET) | KIND_VEC;
+
+        self.arc = AtomicPtr::new(arc as *mut Shared);
+
+        // Forget the vector handle
+        mem::forget(v);
+    }
+
+    /// Returns true if the buffer is stored inline
+    #[inline]
+    fn is_inline(&self) -> bool {
+        self.kind() == KIND_INLINE
+    }
+
+    /// Used for `debug_assert` statements. &mut is used to guarantee that it is
+    /// safe to check VEC_KIND
+    #[inline]
+    fn is_shared(&mut self) -> bool {
+        match self.kind() {
+            KIND_VEC => false,
+            _ => true,
+        }
+    }
+
+    /// Used for `debug_assert` statements
+    #[inline]
+    fn is_static(&mut self) -> bool {
+        match self.kind() {
+            KIND_STATIC => true,
+            _ => false,
+        }
+    }
+
+    #[inline]
+    fn kind(&self) -> usize {
+        // This function is going to probably raise some eyebrows. The function
+        // returns true if the buffer is stored inline. This is done by checking
+        // the least significant bit in the `arc` field.
+        //
+        // Now, you may notice that `arc` is an `AtomicPtr` and this is
+        // accessing it as a normal field without performing an atomic load...
+        //
+        // Again, the function only cares about the least significant bit, and
+        // this bit is set when `Inner` is created and never changed after that.
+        // All platforms have atomic "word" operations and won't randomly flip
+        // bits, so even without any explicit atomic operations, reading the
+        // flag will be correct.
+        //
+        // This function is very critical performance wise as it is called for
+        // every operation. Performing an atomic load would mess with the
+        // compiler's ability to optimize. Simple benchmarks show up to a 10%
+        // slowdown using a `Relaxed` atomic load on x86.
+
+        #[cfg(target_endian = "little")]
+        #[inline]
+        fn imp(arc: &AtomicPtr<Shared>) -> usize {
+            unsafe {
+                let p: &u8 = mem::transmute(arc);
+                (*p as usize) & KIND_MASK
+            }
+        }
+
+        #[cfg(target_endian = "big")]
+        #[inline]
+        fn imp(arc: &AtomicPtr<Shared>) -> usize {
+            unsafe {
+                let p: &usize = mem::transmute(arc);
+                *p & KIND_MASK
+            }
+        }
+
+        imp(&self.arc)
+    }
+
+    #[inline]
+    fn uncoordinated_get_vec_pos(&mut self) -> (usize, usize) {
+        // Similar to above, this is a pretty crazed function. This should only
+        // be called when in the KIND_VEC mode. This + the &mut self argument
+        // guarantees that there is no possibility of concurrent calls to this
+        // function.
+        let prev = unsafe {
+            let p: &AtomicPtr<Shared> = &self.arc;
+            let p: &usize = mem::transmute(p);
+            *p
+        };
+
+        (prev >> VEC_POS_OFFSET, prev)
+    }
+
+    #[inline]
+    fn uncoordinated_set_vec_pos(&mut self, pos: usize, prev: usize) {
+        // Once more... crazy
+        debug_assert!(pos <= MAX_VEC_POS);
+
+        unsafe {
+            let p: &mut AtomicPtr<Shared> = &mut self.arc;
+            let p: &mut usize = mem::transmute(p);
+            *p = (pos << VEC_POS_OFFSET) | (prev & NOT_VEC_POS_MASK);
+        }
+    }
+}
+
+fn rebuild_vec(ptr: *mut u8, mut len: usize, mut cap: usize, off: usize) -> Vec<u8> {
+    unsafe {
+        let ptr = ptr.offset(-(off as isize));
+        len += off;
+        cap += off;
+
+        Vec::from_raw_parts(ptr, len, cap)
+    }
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) {
+        let kind = self.kind();
+
+        if kind == KIND_VEC {
+            let (off, _) = self.uncoordinated_get_vec_pos();
+
+            // Vector storage, free the vector
+            let _ = rebuild_vec(self.ptr, self.len, self.cap, off);
+        } else if kind == KIND_ARC {
+            release_shared(*self.arc.get_mut());
+        }
+    }
+}
+
+fn release_shared(ptr: *mut Shared) {
+    // `Shared` storage... follow the drop steps from Arc.
+    unsafe {
+        if (*ptr).ref_count.fetch_sub(1, Release) != 1 {
+            return;
+        }
+
+        // This fence is needed to prevent reordering of use of the data and
+        // deletion of the data.  Because it is marked `Release`, the decreasing
+        // of the reference count synchronizes with this `Acquire` fence. This
+        // means that use of the data happens before decreasing the reference
+        // count, which happens before this fence, which happens before the
+        // deletion of the data.
+        //
+        // As explained in the [Boost documentation][1],
+        //
+        // > It is important to enforce any possible access to the object in one
+        // > thread (through an existing reference) to *happen before* deleting
+        // > the object in a different thread. This is achieved by a "release"
+        // > operation after dropping a reference (any access to the object
+        // > through this reference must obviously happened before), and an
+        // > "acquire" operation before deleting the object.
+        //
+        // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
+        atomic::fence(Acquire);
+
+        // Drop the data
+        Box::from_raw(ptr);
+    }
+}
+
+impl Shared {
+    fn is_unique(&self) -> bool {
+        // The goal is to check if the current handle is the only handle
+        // that currently has access to the buffer. This is done by
+        // checking if the `ref_count` is currently 1.
+        //
+        // The `Acquire` ordering synchronizes with the `Release` as
+        // part of the `fetch_sub` in `release_shared`. The `fetch_sub`
+        // operation guarantees that any mutations done in other threads
+        // are ordered before the `ref_count` is decremented. As such,
+        // this `Acquire` will guarantee that those mutations are
+        // visible to the current thread.
+        self.ref_count.load(Acquire) == 1
+    }
+}
+
+fn original_capacity_to_repr(cap: usize) -> usize {
+    let width = PTR_WIDTH - ((cap >> MIN_ORIGINAL_CAPACITY_WIDTH).leading_zeros() as usize);
+    cmp::min(width, MAX_ORIGINAL_CAPACITY_WIDTH - MIN_ORIGINAL_CAPACITY_WIDTH)
+}
+
+fn original_capacity_from_repr(repr: usize) -> usize {
+    if repr == 0 {
+        return 0;
+    }
+
+    1 << (repr + (MIN_ORIGINAL_CAPACITY_WIDTH - 1))
+}
+
+#[test]
+fn test_original_capacity_to_repr() {
+    for &cap in &[0, 1, 16, 1000] {
+        assert_eq!(0, original_capacity_to_repr(cap));
+    }
+
+    for &cap in &[1024, 1025, 1100, 2000, 2047] {
+        assert_eq!(1, original_capacity_to_repr(cap));
+    }
+
+    for &cap in &[2048, 2049] {
+        assert_eq!(2, original_capacity_to_repr(cap));
+    }
+
+    // TODO: more
+
+    for &cap in &[65536, 65537, 68000, 1 << 17, 1 << 18, 1 << 20, 1 << 30] {
+        assert_eq!(7, original_capacity_to_repr(cap), "cap={}", cap);
+    }
+}
+
+#[test]
+fn test_original_capacity_from_repr() {
+    assert_eq!(0, original_capacity_from_repr(0));
+    assert_eq!(1024, original_capacity_from_repr(1));
+    assert_eq!(1024 * 2, original_capacity_from_repr(2));
+    assert_eq!(1024 * 4, original_capacity_from_repr(3));
+    assert_eq!(1024 * 8, original_capacity_from_repr(4));
+    assert_eq!(1024 * 16, original_capacity_from_repr(5));
+    assert_eq!(1024 * 32, original_capacity_from_repr(6));
+    assert_eq!(1024 * 64, original_capacity_from_repr(7));
+}
+
+unsafe impl Send for Inner {}
+unsafe impl Sync for Inner {}
+
+/*
+ *
+ * ===== PartialEq / PartialOrd =====
+ *
+ */
+
+impl PartialEq<[u8]> for BytesMut {
+    fn eq(&self, other: &[u8]) -> bool {
+        &**self == other
+    }
+}
+
+impl PartialOrd<[u8]> for BytesMut {
+    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
+        (**self).partial_cmp(other)
+    }
+}
+
+impl PartialEq<BytesMut> for [u8] {
+    fn eq(&self, other: &BytesMut) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<BytesMut> for [u8] {
+    fn partial_cmp(&self, other: &BytesMut) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl PartialEq<str> for BytesMut {
+    fn eq(&self, other: &str) -> bool {
+        &**self == other.as_bytes()
+    }
+}
+
+impl PartialOrd<str> for BytesMut {
+    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+        (**self).partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialEq<BytesMut> for str {
+    fn eq(&self, other: &BytesMut) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<BytesMut> for str {
+    fn partial_cmp(&self, other: &BytesMut) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl PartialEq<Vec<u8>> for BytesMut {
+    fn eq(&self, other: &Vec<u8>) -> bool {
+        *self == &other[..]
+    }
+}
+
+impl PartialOrd<Vec<u8>> for BytesMut {
+    fn partial_cmp(&self, other: &Vec<u8>) -> Option<cmp::Ordering> {
+        (**self).partial_cmp(&other[..])
+    }
+}
+
+impl PartialEq<BytesMut> for Vec<u8> {
+    fn eq(&self, other: &BytesMut) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<BytesMut> for Vec<u8> {
+    fn partial_cmp(&self, other: &BytesMut) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl PartialEq<String> for BytesMut {
+    fn eq(&self, other: &String) -> bool {
+        *self == &other[..]
+    }
+}
+
+impl PartialOrd<String> for BytesMut {
+    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
+        (**self).partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialEq<BytesMut> for String {
+    fn eq(&self, other: &BytesMut) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<BytesMut> for String {
+    fn partial_cmp(&self, other: &BytesMut) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl<'a, T: ?Sized> PartialEq<&'a T> for BytesMut
+    where BytesMut: PartialEq<T>
+{
+    fn eq(&self, other: &&'a T) -> bool {
+        *self == **other
+    }
+}
+
+impl<'a, T: ?Sized> PartialOrd<&'a T> for BytesMut
+    where BytesMut: PartialOrd<T>
+{
+    fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
+        self.partial_cmp(*other)
+    }
+}
+
+impl<'a> PartialEq<BytesMut> for &'a [u8] {
+    fn eq(&self, other: &BytesMut) -> bool {
+        *other == *self
+    }
+}
+
+impl<'a> PartialOrd<BytesMut> for &'a [u8] {
+    fn partial_cmp(&self, other: &BytesMut) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl<'a> PartialEq<BytesMut> for &'a str {
+    fn eq(&self, other: &BytesMut) -> bool {
+        *other == *self
+    }
+}
+
+impl<'a> PartialOrd<BytesMut> for &'a str {
+    fn partial_cmp(&self, other: &BytesMut) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl PartialEq<[u8]> for Bytes {
+    fn eq(&self, other: &[u8]) -> bool {
+        self.inner.as_ref() == other
+    }
+}
+
+impl PartialOrd<[u8]> for Bytes {
+    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
+        self.inner.as_ref().partial_cmp(other)
+    }
+}
+
+impl PartialEq<Bytes> for [u8] {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<Bytes> for [u8] {
+    fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl PartialEq<str> for Bytes {
+    fn eq(&self, other: &str) -> bool {
+        self.inner.as_ref() == other.as_bytes()
+    }
+}
+
+impl PartialOrd<str> for Bytes {
+    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+        self.inner.as_ref().partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialEq<Bytes> for str {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<Bytes> for str {
+    fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl PartialEq<Vec<u8>> for Bytes {
+    fn eq(&self, other: &Vec<u8>) -> bool {
+        *self == &other[..]
+    }
+}
+
+impl PartialOrd<Vec<u8>> for Bytes {
+    fn partial_cmp(&self, other: &Vec<u8>) -> Option<cmp::Ordering> {
+        self.inner.as_ref().partial_cmp(&other[..])
+    }
+}
+
+impl PartialEq<Bytes> for Vec<u8> {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<Bytes> for Vec<u8> {
+    fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl PartialEq<String> for Bytes {
+    fn eq(&self, other: &String) -> bool {
+        *self == &other[..]
+    }
+}
+
+impl PartialOrd<String> for Bytes {
+    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
+        self.inner.as_ref().partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialEq<Bytes> for String {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<Bytes> for String {
+    fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl<'a> PartialEq<Bytes> for &'a [u8] {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl<'a> PartialOrd<Bytes> for &'a [u8] {
+    fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl<'a> PartialEq<Bytes> for &'a str {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl<'a> PartialOrd<Bytes> for &'a str {
+    fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
+        other.partial_cmp(self)
+    }
+}
+
+impl<'a, T: ?Sized> PartialEq<&'a T> for Bytes
+    where Bytes: PartialEq<T>
+{
+    fn eq(&self, other: &&'a T) -> bool {
+        *self == **other
+    }
+}
+
+impl<'a, T: ?Sized> PartialOrd<&'a T> for Bytes
+    where Bytes: PartialOrd<T>
+{
+    fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
+        self.partial_cmp(&**other)
+    }
+}
+
+impl PartialEq<BytesMut> for Bytes
+{
+    fn eq(&self, other: &BytesMut) -> bool {
+        &other[..] == &self[..]
+    }
+}
+
+impl PartialEq<Bytes> for BytesMut
+{
+    fn eq(&self, other: &Bytes) -> bool {
+        &other[..] == &self[..]
+    }
+}
diff --git a/third_party/bytes/src/debug.rs b/third_party/bytes/src/debug.rs
new file mode 100644
index 0000000..f8b830a
--- /dev/null
+++ b/third_party/bytes/src/debug.rs
@@ -0,0 +1,40 @@
+use std::fmt;
+
+/// Alternative implementation of `fmt::Debug` for byte slice.
+///
+/// Standard `Debug` implementation for `[u8]` is comma separated
+/// list of numbers. Since large amount of byte strings are in fact
+/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP),
+/// it is convenient to print strings as ASCII when possible.
+///
+/// This struct wraps `&[u8]` just to override `fmt::Debug`.
+///
+/// `BsDebug` is not a part of public API of bytes crate.
+pub struct BsDebug<'a>(pub &'a [u8]);
+
+impl<'a> fmt::Debug for BsDebug<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        try!(write!(fmt, "b\""));
+        for &c in self.0 {
+            // https://doc.rust-lang.org/reference.html#byte-escapes
+            if c == b'\n' {
+                try!(write!(fmt, "\\n"));
+            } else if c == b'\r' {
+                try!(write!(fmt, "\\r"));
+            } else if c == b'\t' {
+                try!(write!(fmt, "\\t"));
+            } else if c == b'\\' || c == b'"' {
+                try!(write!(fmt, "\\{}", c as char));
+            } else if c == b'\0' {
+                try!(write!(fmt, "\\0"));
+            // ASCII printable
+            } else if c >= 0x20 && c < 0x7f {
+                try!(write!(fmt, "{}", c as char));
+            } else {
+                try!(write!(fmt, "\\x{:02x}", c));
+            }
+        }
+        try!(write!(fmt, "\""));
+        Ok(())
+    }
+}
diff --git a/third_party/bytes/src/lib.rs b/third_party/bytes/src/lib.rs
new file mode 100644
index 0000000..4f9e36c
--- /dev/null
+++ b/third_party/bytes/src/lib.rs
@@ -0,0 +1,108 @@
+//! Provides abstractions for working with bytes.
+//!
+//! The `bytes` crate provides an efficient byte buffer structure
+//! ([`Bytes`](struct.Bytes.html)) and traits for working with buffer
+//! implementations ([`Buf`], [`BufMut`]).
+//!
+//! [`Buf`]: trait.Buf.html
+//! [`BufMut`]: trait.BufMut.html
+//!
+//! # `Bytes`
+//!
+//! `Bytes` is an efficient container for storing and operating on continguous
+//! slices of memory. It is intended for use primarily in networking code, but
+//! could have applications elsewhere as well.
+//!
+//! `Bytes` values facilitate zero-copy network programming by allowing multiple
+//! `Bytes` objects to point to the same underlying memory. This is managed by
+//! using a reference count to track when the memory is no longer needed and can
+//! be freed.
+//!
+//! A `Bytes` handle can be created directly from an existing byte store (such as &[u8]
+//! or Vec<u8>), but usually a `BytesMut` is used first and written to. For
+//! example:
+//!
+//! ```rust
+//! use bytes::{BytesMut, BufMut, BigEndian};
+//!
+//! let mut buf = BytesMut::with_capacity(1024);
+//! buf.put(&b"hello world"[..]);
+//! buf.put_u16::<BigEndian>(1234);
+//!
+//! let a = buf.take();
+//! assert_eq!(a, b"hello world\x04\xD2"[..]);
+//!
+//! buf.put(&b"goodbye world"[..]);
+//!
+//! let b = buf.take();
+//! assert_eq!(b, b"goodbye world"[..]);
+//!
+//! assert_eq!(buf.capacity(), 998);
+//! ```
+//!
+//! In the above example, only a single buffer of 1024 is allocated. The handles
+//! `a` and `b` will share the underlying buffer and maintain indices tracking
+//! the view into the buffer represented by the handle.
+//!
+//! See the [struct docs] for more details.
+//!
+//! [struct docs]: struct.Bytes.html
+//!
+//! # `Buf`, `BufMut`
+//!
+//! These two traits provide read and write access to buffers. The underlying
+//! storage may or may not be in contiguous memory. For example, `Bytes` is a
+//! buffer that guarantees contiguous memory, but a [rope] stores the bytes in
+//! disjoint chunks. `Buf` and `BufMut` maintain cursors tracking the current
+//! position in the underlying byte storage. When bytes are read or written, the
+//! cursor is advanced.
+//!
+//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
+//!
+//! ## Relation with `Read` and `Write`
+//!
+//! At first glance, it may seem that `Buf` and `BufMut` overlap in
+//! functionality with `std::io::Read` and `std::io::Write`. However, they
+//! serve different purposes. A buffer is the value that is provided as an
+//! argument to `Read::read` and `Write::write`. `Read` and `Write` may then
+//! perform a syscall, which has the potential of failing. Operations on `Buf`
+//! and `BufMut` are infallible.
+
+#![deny(warnings, missing_docs, missing_debug_implementations)]
+#![doc(html_root_url = "https://docs.rs/bytes/0.4.8")]
+
+#![cfg_attr(not(target_env = "sgx"), no_std)]
+#![cfg_attr(target_env = "sgx", feature(rustc_private))]
+
+#[cfg(not(target_env = "sgx"))]
+#[macro_use]
+extern crate sgx_tstd as std;
+
+extern crate byteorder;
+extern crate iovec;
+
+pub mod buf;
+pub use buf::{
+    Buf,
+    BufMut,
+    IntoBuf,
+};
+#[deprecated(since = "0.4.1", note = "moved to `buf` module")]
+#[doc(hidden)]
+pub use buf::{
+    Reader,
+    Writer,
+    Take,
+};
+
+mod bytes;
+mod debug;
+pub use bytes::{Bytes, BytesMut};
+
+#[deprecated]
+pub use byteorder::{ByteOrder, BigEndian, LittleEndian};
+
+// Optional Serde support
+#[cfg(feature = "serde")]
+#[doc(hidden)]
+pub mod serde;
diff --git a/third_party/bytes/src/serde.rs b/third_party/bytes/src/serde.rs
new file mode 100644
index 0000000..d45caff
--- /dev/null
+++ b/third_party/bytes/src/serde.rs
@@ -0,0 +1,82 @@
+extern crate serde;
+
+use std::{cmp, fmt};
+use self::serde::{Serialize, Serializer, Deserialize, Deserializer, de};
+use super::{Bytes, BytesMut};
+
+macro_rules! serde_impl {
+    ($ty:ident, $visitor_ty:ident) => (
+        impl Serialize for $ty {
+            #[inline]
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+                where S: Serializer
+            {
+                serializer.serialize_bytes(&self)
+            }
+        }
+
+        struct $visitor_ty;
+
+        impl<'de> de::Visitor<'de> for $visitor_ty {
+            type Value = $ty;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("byte array")
+            }
+
+            #[inline]
+            fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
+                where V: de::SeqAccess<'de>
+            {
+                let len = cmp::min(seq.size_hint().unwrap_or(0), 4096);
+                let mut values = Vec::with_capacity(len);
+
+                while let Some(value) = try!(seq.next_element()) {
+                    values.push(value);
+                }
+
+                Ok(values.into())
+            }
+
+            #[inline]
+            fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+                where E: de::Error
+            {
+                Ok($ty::from(v))
+            }
+
+            #[inline]
+            fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
+                where E: de::Error
+            {
+                Ok($ty::from(v))
+            }
+
+            #[inline]
+            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+                where E: de::Error
+            {
+                Ok($ty::from(v))
+            }
+
+            #[inline]
+            fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+                where E: de::Error
+            {
+                Ok($ty::from(v))
+            }
+        }
+
+        impl<'de> Deserialize<'de> for $ty {
+            #[inline]
+            fn deserialize<D>(deserializer: D) -> Result<$ty, D::Error>
+                where D: Deserializer<'de>
+            {
+                deserializer.deserialize_byte_buf($visitor_ty)
+            }
+        }
+    );
+}
+
+serde_impl!(Bytes, BytesVisitor);
+serde_impl!(BytesMut, BytesMutVisitor);
diff --git a/third_party/bytes/tests/test_buf.rs b/third_party/bytes/tests/test_buf.rs
new file mode 100644
index 0000000..f25c25f
--- /dev/null
+++ b/third_party/bytes/tests/test_buf.rs
@@ -0,0 +1,58 @@
+extern crate bytes;
+extern crate byteorder;
+extern crate iovec;
+
+use bytes::Buf;
+use iovec::IoVec;
+use std::io::Cursor;
+
+#[test]
+fn test_fresh_cursor_vec() {
+    let mut buf = Cursor::new(b"hello".to_vec());
+
+    assert_eq!(buf.remaining(), 5);
+    assert_eq!(buf.bytes(), b"hello");
+
+    buf.advance(2);
+
+    assert_eq!(buf.remaining(), 3);
+    assert_eq!(buf.bytes(), b"llo");
+
+    buf.advance(3);
+
+    assert_eq!(buf.remaining(), 0);
+    assert_eq!(buf.bytes(), b"");
+}
+
+#[test]
+fn test_get_u8() {
+    let mut buf = Cursor::new(b"\x21zomg");
+    assert_eq!(0x21, buf.get_u8());
+}
+
+#[test]
+fn test_get_u16() {
+    let buf = b"\x21\x54zomg";
+    assert_eq!(0x2154, Cursor::new(buf).get_u16_be());
+    assert_eq!(0x5421, Cursor::new(buf).get_u16_le());
+}
+
+#[test]
+#[should_panic]
+fn test_get_u16_buffer_underflow() {
+    let mut buf = Cursor::new(b"\x21");
+    buf.get_u16_be();
+}
+
+#[test]
+fn test_bufs_vec() {
+    let buf = Cursor::new(b"hello world");
+
+    let b1: &[u8] = &mut [0];
+    let b2: &[u8] = &mut [0];
+
+    let mut dst: [&IoVec; 2] =
+        [b1.into(), b2.into()];
+
+    assert_eq!(1, buf.bytes_vec(&mut dst[..]));
+}
diff --git a/third_party/bytes/tests/test_buf_mut.rs b/third_party/bytes/tests/test_buf_mut.rs
new file mode 100644
index 0000000..2c8faa1
--- /dev/null
+++ b/third_party/bytes/tests/test_buf_mut.rs
@@ -0,0 +1,83 @@
+extern crate bytes;
+extern crate byteorder;
+extern crate iovec;
+
+use bytes::{BufMut, BytesMut};
+use iovec::IoVec;
+use std::usize;
+use std::fmt::Write;
+
+#[test]
+fn test_vec_as_mut_buf() {
+    let mut buf = Vec::with_capacity(64);
+
+    assert_eq!(buf.remaining_mut(), usize::MAX);
+
+    unsafe {
+        assert!(buf.bytes_mut().len() >= 64);
+    }
+
+    buf.put(&b"zomg"[..]);
+
+    assert_eq!(&buf, b"zomg");
+
+    assert_eq!(buf.remaining_mut(), usize::MAX - 4);
+    assert_eq!(buf.capacity(), 64);
+
+    for _ in 0..16 {
+        buf.put(&b"zomg"[..]);
+    }
+
+    assert_eq!(buf.len(), 68);
+}
+
+#[test]
+fn test_put_u8() {
+    let mut buf = Vec::with_capacity(8);
+    buf.put::<u8>(33);
+    assert_eq!(b"\x21", &buf[..]);
+}
+
+#[test]
+fn test_put_u16() {
+    let mut buf = Vec::with_capacity(8);
+    buf.put_u16_be(8532);
+    assert_eq!(b"\x21\x54", &buf[..]);
+
+    buf.clear();
+    buf.put_u16_le(8532);
+    assert_eq!(b"\x54\x21", &buf[..]);
+}
+
+#[test]
+fn test_vec_advance_mut() {
+    // Regression test for carllerche/bytes#108.
+    let mut buf = Vec::with_capacity(8);
+    unsafe {
+        buf.advance_mut(12);
+        assert_eq!(buf.len(), 12);
+        assert!(buf.capacity() >= 12, "capacity: {}", buf.capacity());
+    }
+}
+
+#[test]
+fn test_clone() {
+    let mut buf = BytesMut::with_capacity(100);
+    buf.write_str("this is a test").unwrap();
+    let buf2 = buf.clone();
+
+    buf.write_str(" of our emergecy broadcast system").unwrap();
+    assert!(buf != buf2);
+}
+
+#[test]
+fn test_bufs_vec_mut() {
+    use std::mem;
+
+    let mut buf = BytesMut::from(&b"hello world"[..]);
+
+    unsafe {
+        let mut dst: [&mut IoVec; 2] = mem::zeroed();
+        assert_eq!(1, buf.bytes_vec_mut(&mut dst[..]));
+    }
+}
diff --git a/third_party/bytes/tests/test_bytes.rs b/third_party/bytes/tests/test_bytes.rs
new file mode 100644
index 0000000..03da9dd
--- /dev/null
+++ b/third_party/bytes/tests/test_bytes.rs
@@ -0,0 +1,712 @@
+extern crate bytes;
+
+use bytes::{Bytes, BytesMut, BufMut};
+
+const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
+const SHORT: &'static [u8] = b"hello world";
+
+fn inline_cap() -> usize {
+    use std::mem;
+    4 * mem::size_of::<usize>() - 1
+}
+
+fn is_sync<T: Sync>() {}
+fn is_send<T: Send>() {}
+
+#[test]
+fn test_bounds() {
+    is_sync::<Bytes>();
+    is_sync::<BytesMut>();
+    is_send::<Bytes>();
+    is_send::<BytesMut>();
+}
+
+#[test]
+fn from_slice() {
+    let a = Bytes::from(&b"abcdefgh"[..]);
+    assert_eq!(a, b"abcdefgh"[..]);
+    assert_eq!(a, &b"abcdefgh"[..]);
+    assert_eq!(a, Vec::from(&b"abcdefgh"[..]));
+    assert_eq!(b"abcdefgh"[..], a);
+    assert_eq!(&b"abcdefgh"[..], a);
+    assert_eq!(Vec::from(&b"abcdefgh"[..]), a);
+
+    let a = BytesMut::from(&b"abcdefgh"[..]);
+    assert_eq!(a, b"abcdefgh"[..]);
+    assert_eq!(a, &b"abcdefgh"[..]);
+    assert_eq!(a, Vec::from(&b"abcdefgh"[..]));
+    assert_eq!(b"abcdefgh"[..], a);
+    assert_eq!(&b"abcdefgh"[..], a);
+    assert_eq!(Vec::from(&b"abcdefgh"[..]), a);
+}
+
+#[test]
+fn fmt() {
+    let a = format!("{:?}", Bytes::from(&b"abcdefg"[..]));
+    let b = "b\"abcdefg\"";
+
+    assert_eq!(a, b);
+
+    let a = format!("{:?}", BytesMut::from(&b"abcdefg"[..]));
+    assert_eq!(a, b);
+}
+
+#[test]
+fn fmt_write() {
+    use std::fmt::Write;
+    use std::iter::FromIterator;
+    let s = String::from_iter((0..10).map(|_| "abcdefg"));
+
+    let mut a = BytesMut::with_capacity(64);
+    write!(a, "{}", &s[..64]).unwrap();
+    assert_eq!(a, s[..64].as_bytes());
+
+
+    let mut b = BytesMut::with_capacity(64);
+    write!(b, "{}", &s[..32]).unwrap();
+    write!(b, "{}", &s[32..64]).unwrap();
+    assert_eq!(b, s[..64].as_bytes());
+
+
+    let mut c = BytesMut::with_capacity(64);
+    write!(c, "{}", s).unwrap_err();
+    assert!(c.is_empty());
+}
+
+#[test]
+fn len() {
+    let a = Bytes::from(&b"abcdefg"[..]);
+    assert_eq!(a.len(), 7);
+
+    let a = BytesMut::from(&b"abcdefg"[..]);
+    assert_eq!(a.len(), 7);
+
+    let a = Bytes::from(&b""[..]);
+    assert!(a.is_empty());
+
+    let a = BytesMut::from(&b""[..]);
+    assert!(a.is_empty());
+}
+
+#[test]
+fn index() {
+    let a = Bytes::from(&b"hello world"[..]);
+    assert_eq!(a[0..5], *b"hello");
+}
+
+#[test]
+fn slice() {
+    let a = Bytes::from(&b"hello world"[..]);
+
+    let b = a.slice(3, 5);
+    assert_eq!(b, b"lo"[..]);
+
+    let b = a.slice(0, 0);
+    assert_eq!(b, b""[..]);
+
+    let b = a.slice(3, 3);
+    assert_eq!(b, b""[..]);
+
+    let b = a.slice(a.len(), a.len());
+    assert_eq!(b, b""[..]);
+
+    let b = a.slice_to(5);
+    assert_eq!(b, b"hello"[..]);
+
+    let b = a.slice_from(3);
+    assert_eq!(b, b"lo world"[..]);
+}
+
+#[test]
+#[should_panic]
+fn slice_oob_1() {
+    let a = Bytes::from(&b"hello world"[..]);
+    a.slice(5, inline_cap() + 1);
+}
+
+#[test]
+#[should_panic]
+fn slice_oob_2() {
+    let a = Bytes::from(&b"hello world"[..]);
+    a.slice(inline_cap() + 1, inline_cap() + 5);
+}
+
+#[test]
+fn split_off() {
+    let mut hello = Bytes::from(&b"helloworld"[..]);
+    let world = hello.split_off(5);
+
+    assert_eq!(hello, &b"hello"[..]);
+    assert_eq!(world, &b"world"[..]);
+
+    let mut hello = BytesMut::from(&b"helloworld"[..]);
+    let world = hello.split_off(5);
+
+    assert_eq!(hello, &b"hello"[..]);
+    assert_eq!(world, &b"world"[..]);
+}
+
+#[test]
+#[should_panic]
+fn split_off_oob() {
+    let mut hello = Bytes::from(&b"helloworld"[..]);
+    hello.split_off(inline_cap() + 1);
+}
+
+#[test]
+fn split_off_uninitialized() {
+    let mut bytes = BytesMut::with_capacity(1024);
+    let other = bytes.split_off(128);
+
+    assert_eq!(bytes.len(), 0);
+    assert_eq!(bytes.capacity(), 128);
+
+    assert_eq!(other.len(), 0);
+    assert_eq!(other.capacity(), 896);
+}
+
+#[test]
+fn split_off_to_loop() {
+    let s = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    for i in 0..(s.len() + 1) {
+        {
+            let mut bytes = Bytes::from(&s[..]);
+            let off = bytes.split_off(i);
+            assert_eq!(i, bytes.len());
+            let mut sum = Vec::new();
+            sum.extend(&bytes);
+            sum.extend(&off);
+            assert_eq!(&s[..], &sum[..]);
+        }
+        {
+            let mut bytes = BytesMut::from(&s[..]);
+            let off = bytes.split_off(i);
+            assert_eq!(i, bytes.len());
+            let mut sum = Vec::new();
+            sum.extend(&bytes);
+            sum.extend(&off);
+            assert_eq!(&s[..], &sum[..]);
+        }
+        {
+            let mut bytes = Bytes::from(&s[..]);
+            let off = bytes.split_to(i);
+            assert_eq!(i, off.len());
+            let mut sum = Vec::new();
+            sum.extend(&off);
+            sum.extend(&bytes);
+            assert_eq!(&s[..], &sum[..]);
+        }
+        {
+            let mut bytes = BytesMut::from(&s[..]);
+            let off = bytes.split_to(i);
+            assert_eq!(i, off.len());
+            let mut sum = Vec::new();
+            sum.extend(&off);
+            sum.extend(&bytes);
+            assert_eq!(&s[..], &sum[..]);
+        }
+    }
+}
+
+#[test]
+fn split_to_1() {
+    // Inline
+    let mut a = Bytes::from(SHORT);
+    let b = a.split_to(4);
+
+    assert_eq!(SHORT[4..], a);
+    assert_eq!(SHORT[..4], b);
+
+    // Allocated
+    let mut a = Bytes::from(LONG);
+    let b = a.split_to(4);
+
+    assert_eq!(LONG[4..], a);
+    assert_eq!(LONG[..4], b);
+
+    let mut a = Bytes::from(LONG);
+    let b = a.split_to(30);
+
+    assert_eq!(LONG[30..], a);
+    assert_eq!(LONG[..30], b);
+}
+
+#[test]
+fn split_to_2() {
+    let mut a = Bytes::from(LONG);
+    assert_eq!(LONG, a);
+
+    let b = a.split_to(1);
+
+    assert_eq!(LONG[1..], a);
+    drop(b);
+}
+
+#[test]
+#[should_panic]
+fn split_to_oob() {
+    let mut hello = Bytes::from(&b"helloworld"[..]);
+    hello.split_to(inline_cap() + 1);
+}
+
+#[test]
+#[should_panic]
+fn split_to_oob_mut() {
+    let mut hello = BytesMut::from(&b"helloworld"[..]);
+    hello.split_to(inline_cap() + 1);
+}
+
+#[test]
+fn split_to_uninitialized() {
+    let mut bytes = BytesMut::with_capacity(1024);
+    let other = bytes.split_to(128);
+
+    assert_eq!(bytes.len(), 0);
+    assert_eq!(bytes.capacity(), 896);
+
+    assert_eq!(other.len(), 0);
+    assert_eq!(other.capacity(), 128);
+}
+
+#[test]
+fn split_off_to_at_gt_len() {
+    fn make_bytes() -> Bytes {
+        let mut bytes = BytesMut::with_capacity(100);
+        bytes.put_slice(&[10, 20, 30, 40]);
+        bytes.freeze()
+    }
+
+    use std::panic;
+
+    make_bytes().split_to(4);
+    make_bytes().split_off(4);
+
+    assert!(panic::catch_unwind(move || {
+        make_bytes().split_to(5);
+    }).is_err());
+
+    assert!(panic::catch_unwind(move || {
+        make_bytes().split_off(5);
+    }).is_err());
+}
+
+#[test]
+fn fns_defined_for_bytes_mut() {
+    let mut bytes = BytesMut::from(&b"hello world"[..]);
+
+    bytes.as_ptr();
+    bytes.as_mut_ptr();
+
+    // Iterator
+    let v: Vec<u8> = bytes.iter().map(|b| *b).collect();
+    assert_eq!(&v[..], bytes);
+}
+
+#[test]
+fn reserve_convert() {
+    // Inline -> Vec
+    let mut bytes = BytesMut::with_capacity(8);
+    bytes.put("hello");
+    bytes.reserve(40);
+    assert_eq!(bytes.capacity(), 45);
+    assert_eq!(bytes, "hello");
+
+    // Inline -> Inline
+    let mut bytes = BytesMut::with_capacity(inline_cap());
+    bytes.put("abcdefghijkl");
+
+    let a = bytes.split_to(10);
+    bytes.reserve(inline_cap() - 3);
+    assert_eq!(inline_cap(), bytes.capacity());
+
+    assert_eq!(bytes, "kl");
+    assert_eq!(a, "abcdefghij");
+
+    // Vec -> Vec
+    let mut bytes = BytesMut::from(LONG);
+    bytes.reserve(64);
+    assert_eq!(bytes.capacity(), LONG.len() + 64);
+
+    // Arc -> Vec
+    let mut bytes = BytesMut::from(LONG);
+    let a = bytes.split_to(30);
+
+    bytes.reserve(128);
+    assert!(bytes.capacity() >= bytes.len() + 128);
+
+    drop(a);
+}
+
+#[test]
+fn reserve_growth() {
+    let mut bytes = BytesMut::with_capacity(64);
+    bytes.put("hello world");
+    let _ = bytes.take();
+
+    bytes.reserve(65);
+    assert_eq!(bytes.capacity(), 128);
+}
+
+#[test]
+fn reserve_allocates_at_least_original_capacity() {
+    let mut bytes = BytesMut::with_capacity(1024);
+
+    for i in 0..1020 {
+        bytes.put(i as u8);
+    }
+
+    let _other = bytes.take();
+
+    bytes.reserve(16);
+    assert_eq!(bytes.capacity(), 1024);
+}
+
+#[test]
+fn reserve_max_original_capacity_value() {
+    const SIZE: usize = 128 * 1024;
+
+    let mut bytes = BytesMut::with_capacity(SIZE);
+
+    for _ in 0..SIZE {
+        bytes.put(0u8);
+    }
+
+    let _other = bytes.take();
+
+    bytes.reserve(16);
+    assert_eq!(bytes.capacity(), 64 * 1024);
+}
+
+// Without either looking at the internals of the BytesMut or doing weird stuff
+// with the memory allocator, there's no good way to automatically verify from
+// within the program that this actually recycles memory. Instead, just exercise
+// the code path to ensure that the results are correct.
+#[test]
+fn reserve_vec_recycling() {
+    let mut bytes = BytesMut::from(Vec::with_capacity(16));
+    assert_eq!(bytes.capacity(), 16);
+    bytes.put("0123456789012345");
+    bytes.advance(10);
+    assert_eq!(bytes.capacity(), 6);
+    bytes.reserve(8);
+    assert_eq!(bytes.capacity(), 16);
+}
+
+#[test]
+fn reserve_in_arc_unique_does_not_overallocate() {
+    let mut bytes = BytesMut::with_capacity(1000);
+    bytes.take();
+
+    // now bytes is Arc and refcount == 1
+
+    assert_eq!(1000, bytes.capacity());
+    bytes.reserve(2001);
+    assert_eq!(2001, bytes.capacity());
+}
+
+#[test]
+fn reserve_in_arc_unique_doubles() {
+    let mut bytes = BytesMut::with_capacity(1000);
+    bytes.take();
+
+    // now bytes is Arc and refcount == 1
+
+    assert_eq!(1000, bytes.capacity());
+    bytes.reserve(1001);
+    assert_eq!(2000, bytes.capacity());
+}
+
+#[test]
+fn reserve_in_arc_nonunique_does_not_overallocate() {
+    let mut bytes = BytesMut::with_capacity(1000);
+    let _copy = bytes.take();
+
+    // now bytes is Arc and refcount == 2
+
+    assert_eq!(1000, bytes.capacity());
+    bytes.reserve(2001);
+    assert_eq!(2001, bytes.capacity());
+}
+
+#[test]
+fn inline_storage() {
+    let mut bytes = BytesMut::with_capacity(inline_cap());
+    let zero = [0u8; 64];
+
+    bytes.put(&zero[0..inline_cap()]);
+    assert_eq!(*bytes, zero[0..inline_cap()]);
+}
+
+#[test]
+fn extend_mut() {
+    let mut bytes = BytesMut::with_capacity(0);
+    bytes.extend(LONG);
+    assert_eq!(*bytes, LONG[..]);
+}
+
+#[test]
+fn extend_shr() {
+    let mut bytes = Bytes::new();
+    bytes.extend(LONG);
+    assert_eq!(*bytes, LONG[..]);
+}
+
+#[test]
+fn extend_from_slice_mut() {
+    for &i in &[3, 34] {
+        let mut bytes = BytesMut::new();
+        bytes.extend_from_slice(&LONG[..i]);
+        bytes.extend_from_slice(&LONG[i..]);
+        assert_eq!(LONG[..], *bytes);
+    }
+}
+
+#[test]
+fn extend_from_slice_shr() {
+    for &i in &[3, 34] {
+        let mut bytes = Bytes::new();
+        bytes.extend_from_slice(&LONG[..i]);
+        bytes.extend_from_slice(&LONG[i..]);
+        assert_eq!(LONG[..], *bytes);
+    }
+}
+
+#[test]
+fn from_static() {
+    let mut a = Bytes::from_static(b"ab");
+    let b = a.split_off(1);
+
+    assert_eq!(a, b"a"[..]);
+    assert_eq!(b, b"b"[..]);
+}
+
+#[test]
+fn advance_inline() {
+    let mut a = Bytes::from(&b"hello world"[..]);
+    a.advance(6);
+    assert_eq!(a, &b"world"[..]);
+}
+
+#[test]
+fn advance_static() {
+    let mut a = Bytes::from_static(b"hello world");
+    a.advance(6);
+    assert_eq!(a, &b"world"[..]);
+}
+
+#[test]
+fn advance_vec() {
+    let mut a = BytesMut::from(b"hello world boooo yah world zomg wat wat".to_vec());
+    a.advance(16);
+    assert_eq!(a, b"o yah world zomg wat wat"[..]);
+
+    a.advance(4);
+    assert_eq!(a, b"h world zomg wat wat"[..]);
+
+    // Reserve some space.
+    a.reserve(1024);
+    assert_eq!(a, b"h world zomg wat wat"[..]);
+
+    a.advance(6);
+    assert_eq!(a, b"d zomg wat wat"[..]);
+}
+
+#[test]
+#[should_panic]
+fn advance_past_len() {
+    let mut a = BytesMut::from(b"hello world".to_vec());
+    a.advance(20);
+}
+
+#[test]
+// Only run these tests on little endian systems. CI uses qemu for testing
+// little endian... and qemu doesn't really support threading all that well.
+#[cfg(target_endian = "little")]
+fn stress() {
+    // Tests promoting a buffer from a vec -> shared in a concurrent situation
+    use std::sync::{Arc, Barrier};
+    use std::thread;
+
+    const THREADS: usize = 8;
+    const ITERS: usize = 1_000;
+
+    for i in 0..ITERS {
+        let data = [i as u8; 256];
+        let buf = Arc::new(Bytes::from(&data[..]));
+
+        let barrier = Arc::new(Barrier::new(THREADS));
+        let mut joins = Vec::with_capacity(THREADS);
+
+        for _ in 0..THREADS {
+            let c = barrier.clone();
+            let buf = buf.clone();
+
+            joins.push(thread::spawn(move || {
+                c.wait();
+                let buf: Bytes = (*buf).clone();
+                drop(buf);
+            }));
+        }
+
+        for th in joins {
+            th.join().unwrap();
+        }
+
+        assert_eq!(*buf, data[..]);
+    }
+}
+
+#[test]
+fn partial_eq_bytesmut() {
+    let bytes = Bytes::from(&b"The quick red fox"[..]);
+    let bytesmut = BytesMut::from(&b"The quick red fox"[..]);
+    assert!(bytes == bytesmut);
+    assert!(bytesmut == bytes);
+    let bytes2 = Bytes::from(&b"Jumped over the lazy brown dog"[..]);
+    assert!(bytes2 != bytesmut);
+    assert!(bytesmut != bytes2);
+}
+
+#[test]
+fn unsplit_basic() {
+    let mut buf = BytesMut::with_capacity(64);
+    buf.extend_from_slice(b"aaabbbcccddd");
+
+    let splitted = buf.split_off(6);
+    assert_eq!(b"aaabbb", &buf[..]);
+    assert_eq!(b"cccddd", &splitted[..]);
+
+    buf.unsplit(splitted);
+    assert_eq!(b"aaabbbcccddd", &buf[..]);
+}
+
+#[test]
+fn unsplit_empty_other() {
+    let mut buf = BytesMut::with_capacity(64);
+    buf.extend_from_slice(b"aaabbbcccddd");
+
+    // empty other
+    let other = BytesMut::new();
+
+    buf.unsplit(other);
+    assert_eq!(b"aaabbbcccddd", &buf[..]);
+}
+
+#[test]
+fn unsplit_empty_self() {
+    // empty self
+    let mut buf = BytesMut::new();
+
+    let mut other = BytesMut::with_capacity(64);
+    other.extend_from_slice(b"aaabbbcccddd");
+
+    buf.unsplit(other);
+    assert_eq!(b"aaabbbcccddd", &buf[..]);
+}
+
+#[test]
+fn unsplit_inline_arc() {
+    let mut buf = BytesMut::with_capacity(8); //inline
+    buf.extend_from_slice(b"aaaabbbb");
+
+    let mut buf2 = BytesMut::with_capacity(64);
+    buf2.extend_from_slice(b"ccccddddeeee");
+
+    buf2.split_off(8); //arc
+
+    buf.unsplit(buf2);
+    assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
+}
+
+#[test]
+fn unsplit_arc_inline() {
+    let mut buf = BytesMut::with_capacity(64);
+    buf.extend_from_slice(b"aaaabbbbeeee");
+
+    buf.split_off(8); //arc
+
+    let mut buf2 = BytesMut::with_capacity(8); //inline
+    buf2.extend_from_slice(b"ccccdddd");
+
+    buf.unsplit(buf2);
+    assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
+
+}
+
+#[test]
+fn unsplit_both_inline() {
+    let mut buf = BytesMut::with_capacity(16); //inline
+    buf.extend_from_slice(b"aaaabbbbccccdddd");
+
+    let splitted = buf.split_off(8); // both inline
+    assert_eq!(b"aaaabbbb", &buf[..]);
+    assert_eq!(b"ccccdddd", &splitted[..]);
+
+    buf.unsplit(splitted);
+    assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
+}
+
+
+#[test]
+fn unsplit_arc_different() {
+    let mut buf = BytesMut::with_capacity(64);
+    buf.extend_from_slice(b"aaaabbbbeeee");
+
+    buf.split_off(8); //arc
+
+    let mut buf2 = BytesMut::with_capacity(64);
+    buf2.extend_from_slice(b"ccccddddeeee");
+
+    buf2.split_off(8); //arc
+
+    buf.unsplit(buf2);
+    assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
+}
+
+#[test]
+fn unsplit_arc_non_contiguous() {
+    let mut buf = BytesMut::with_capacity(64);
+    buf.extend_from_slice(b"aaaabbbbeeeeccccdddd");
+
+    let mut buf2 = buf.split_off(8); //arc
+
+    let buf3 = buf2.split_off(4); //arc
+
+    buf.unsplit(buf3);
+    assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
+}
+
+#[test]
+fn unsplit_two_split_offs() {
+    let mut buf = BytesMut::with_capacity(64);
+    buf.extend_from_slice(b"aaaabbbbccccdddd");
+
+    let mut buf2 = buf.split_off(8); //arc
+    let buf3 = buf2.split_off(4); //arc
+
+    buf2.unsplit(buf3);
+    buf.unsplit(buf2);
+    assert_eq!(b"aaaabbbbccccdddd", &buf[..]);
+}
+
+#[test]
+fn from_iter_no_size_hint() {
+    use std::iter;
+
+    let mut expect = vec![];
+
+    let actual: Bytes = iter::repeat(b'x')
+        .scan(100, |cnt, item| {
+            if *cnt >= 1 {
+                *cnt -= 1;
+                expect.push(item);
+                Some(item)
+            } else {
+                None
+            }
+        })
+        .collect();
+
+    assert_eq!(&actual[..], &expect[..]);
+}
diff --git a/third_party/bytes/tests/test_chain.rs b/third_party/bytes/tests/test_chain.rs
new file mode 100644
index 0000000..2789e7c
--- /dev/null
+++ b/third_party/bytes/tests/test_chain.rs
@@ -0,0 +1,122 @@
+extern crate bytes;
+extern crate iovec;
+
+use bytes::{Buf, BufMut, Bytes, BytesMut};
+use bytes::buf::Chain;
+use iovec::IoVec;
+use std::io::Cursor;
+
+#[test]
+fn collect_two_bufs() {
+    let a = Cursor::new(Bytes::from(&b"hello"[..]));
+    let b = Cursor::new(Bytes::from(&b"world"[..]));
+
+    let res: Vec<u8> = a.chain(b).collect();
+    assert_eq!(res, &b"helloworld"[..]);
+}
+
+#[test]
+fn writing_chained() {
+    let mut a = BytesMut::with_capacity(64);
+    let mut b = BytesMut::with_capacity(64);
+
+    {
+        let mut buf = Chain::new(&mut a, &mut b);
+
+        for i in 0..128 {
+            buf.put(i as u8);
+        }
+    }
+
+    assert_eq!(64, a.len());
+    assert_eq!(64, b.len());
+
+    for i in 0..64 {
+        let expect = i as u8;
+        assert_eq!(expect, a[i]);
+        assert_eq!(expect + 64, b[i]);
+    }
+}
+
+#[test]
+fn iterating_two_bufs() {
+    let a = Cursor::new(Bytes::from(&b"hello"[..]));
+    let b = Cursor::new(Bytes::from(&b"world"[..]));
+
+    let res: Vec<u8> = a.chain(b).iter().collect();
+    assert_eq!(res, &b"helloworld"[..]);
+}
+
+#[test]
+fn vectored_read() {
+    let a = Cursor::new(Bytes::from(&b"hello"[..]));
+    let b = Cursor::new(Bytes::from(&b"world"[..]));
+
+    let mut buf = a.chain(b);
+
+    {
+        let b1: &[u8] = &mut [0];
+        let b2: &[u8] = &mut [0];
+        let b3: &[u8] = &mut [0];
+        let b4: &[u8] = &mut [0];
+        let mut iovecs: [&IoVec; 4] =
+            [b1.into(), b2.into(), b3.into(), b4.into()];
+
+        assert_eq!(2, buf.bytes_vec(&mut iovecs));
+        assert_eq!(iovecs[0][..], b"hello"[..]);
+        assert_eq!(iovecs[1][..], b"world"[..]);
+        assert_eq!(iovecs[2][..], b"\0"[..]);
+        assert_eq!(iovecs[3][..], b"\0"[..]);
+    }
+
+    buf.advance(2);
+
+    {
+        let b1: &[u8] = &mut [0];
+        let b2: &[u8] = &mut [0];
+        let b3: &[u8] = &mut [0];
+        let b4: &[u8] = &mut [0];
+        let mut iovecs: [&IoVec; 4] =
+            [b1.into(), b2.into(), b3.into(), b4.into()];
+
+        assert_eq!(2, buf.bytes_vec(&mut iovecs));
+        assert_eq!(iovecs[0][..], b"llo"[..]);
+        assert_eq!(iovecs[1][..], b"world"[..]);
+        assert_eq!(iovecs[2][..], b"\0"[..]);
+        assert_eq!(iovecs[3][..], b"\0"[..]);
+    }
+
+    buf.advance(3);
+
+    {
+        let b1: &[u8] = &mut [0];
+        let b2: &[u8] = &mut [0];
+        let b3: &[u8] = &mut [0];
+        let b4: &[u8] = &mut [0];
+        let mut iovecs: [&IoVec; 4] =
+            [b1.into(), b2.into(), b3.into(), b4.into()];
+
+        assert_eq!(1, buf.bytes_vec(&mut iovecs));
+        assert_eq!(iovecs[0][..], b"world"[..]);
+        assert_eq!(iovecs[1][..], b"\0"[..]);
+        assert_eq!(iovecs[2][..], b"\0"[..]);
+        assert_eq!(iovecs[3][..], b"\0"[..]);
+    }
+
+    buf.advance(3);
+
+    {
+        let b1: &[u8] = &mut [0];
+        let b2: &[u8] = &mut [0];
+        let b3: &[u8] = &mut [0];
+        let b4: &[u8] = &mut [0];
+        let mut iovecs: [&IoVec; 4] =
+            [b1.into(), b2.into(), b3.into(), b4.into()];
+
+        assert_eq!(1, buf.bytes_vec(&mut iovecs));
+        assert_eq!(iovecs[0][..], b"ld"[..]);
+        assert_eq!(iovecs[1][..], b"\0"[..]);
+        assert_eq!(iovecs[2][..], b"\0"[..]);
+        assert_eq!(iovecs[3][..], b"\0"[..]);
+    }
+}
diff --git a/third_party/bytes/tests/test_debug.rs b/third_party/bytes/tests/test_debug.rs
new file mode 100644
index 0000000..9945a28
--- /dev/null
+++ b/third_party/bytes/tests/test_debug.rs
@@ -0,0 +1,35 @@
+extern crate bytes;
+
+use bytes::Bytes;
+
+#[test]
+fn fmt() {
+    let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect();
+
+    let expected = "b\"\
+        \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\
+        \\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\
+        \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\
+        \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\
+        \x20!\\\"#$%&'()*+,-./0123456789:;<=>?\
+        @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\
+        `abcdefghijklmnopqrstuvwxyz{|}~\\x7f\
+        \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\
+        \\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\
+        \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\
+        \\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\
+        \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\
+        \\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\
+        \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\
+        \\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\
+        \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\
+        \\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\
+        \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\
+        \\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\
+        \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\
+        \\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\
+        \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\
+        \\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\"";
+
+    assert_eq!(expected, format!("{:?}", Bytes::from(vec)));
+}
diff --git a/third_party/bytes/tests/test_from_buf.rs b/third_party/bytes/tests/test_from_buf.rs
new file mode 100644
index 0000000..216bf12
--- /dev/null
+++ b/third_party/bytes/tests/test_from_buf.rs
@@ -0,0 +1,34 @@
+extern crate bytes;
+
+use bytes::{Buf, Bytes, BytesMut};
+use std::io::Cursor;
+
+const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
+const SHORT: &'static [u8] = b"hello world";
+
+#[test]
+fn collect_to_vec() {
+    let buf: Vec<u8> = Cursor::new(SHORT).collect();
+    assert_eq!(buf, SHORT);
+
+    let buf: Vec<u8> = Cursor::new(LONG).collect();
+    assert_eq!(buf, LONG);
+}
+
+#[test]
+fn collect_to_bytes() {
+    let buf: Bytes = Cursor::new(SHORT).collect();
+    assert_eq!(buf, SHORT);
+
+    let buf: Bytes = Cursor::new(LONG).collect();
+    assert_eq!(buf, LONG);
+}
+
+#[test]
+fn collect_to_bytes_mut() {
+    let buf: BytesMut = Cursor::new(SHORT).collect();
+    assert_eq!(buf, SHORT);
+
+    let buf: BytesMut = Cursor::new(LONG).collect();
+    assert_eq!(buf, LONG);
+}
diff --git a/third_party/bytes/tests/test_iter.rs b/third_party/bytes/tests/test_iter.rs
new file mode 100644
index 0000000..c16dbf6
--- /dev/null
+++ b/third_party/bytes/tests/test_iter.rs
@@ -0,0 +1,22 @@
+extern crate bytes;
+
+use bytes::{Buf, IntoBuf, Bytes};
+
+#[test]
+fn iter_len() {
+    let buf = Bytes::from(&b"hello world"[..]).into_buf();
+    let iter = buf.iter();
+
+    assert_eq!(iter.size_hint(), (11, Some(11)));
+    assert_eq!(iter.len(), 11);
+}
+
+
+#[test]
+fn empty_iter_len() {
+    let buf = Bytes::from(&b""[..]).into_buf();
+    let iter = buf.iter();
+
+    assert_eq!(iter.size_hint(), (0, Some(0)));
+    assert_eq!(iter.len(), 0);
+}
diff --git a/third_party/bytes/tests/test_serde.rs b/third_party/bytes/tests/test_serde.rs
new file mode 100644
index 0000000..ff44024
--- /dev/null
+++ b/third_party/bytes/tests/test_serde.rs
@@ -0,0 +1,21 @@
+#![cfg(feature = "serde")]
+
+extern crate bytes;
+extern crate serde_test;
+use serde_test::{Token, assert_tokens};
+
+#[test]
+fn test_ser_de_empty() {
+    let b = bytes::Bytes::new();
+    assert_tokens(&b, &[Token::Bytes(b"")]);
+    let b = bytes::BytesMut::with_capacity(0);
+    assert_tokens(&b, &[Token::Bytes(b"")]);
+}
+
+#[test]
+fn test_ser_de() {
+    let b = bytes::Bytes::from(&b"bytes"[..]);
+    assert_tokens(&b, &[Token::Bytes(b"bytes")]);
+    let b = bytes::BytesMut::from(&b"bytes"[..]);
+    assert_tokens(&b, &[Token::Bytes(b"bytes")]);
+}
diff --git a/third_party/bytes/tests/test_take.rs b/third_party/bytes/tests/test_take.rs
new file mode 100644
index 0000000..93e0c6c
--- /dev/null
+++ b/third_party/bytes/tests/test_take.rs
@@ -0,0 +1,13 @@
+extern crate bytes;
+
+use bytes::Buf;
+use std::io::Cursor;
+
+#[test]
+fn long_take() {
+    // Tests that take with a size greater than the buffer length will not
+    // overrun the buffer. Regression test for #138.
+    let buf = Cursor::new(b"hello world").take(100);
+    assert_eq!(11, buf.remaining());
+    assert_eq!(b"hello world", buf.bytes());
+}
diff --git a/third_party/bytes/x86_64-unknown-linux-sgx.json b/third_party/bytes/x86_64-unknown-linux-sgx.json
new file mode 100644
index 0000000..6cbb524
--- /dev/null
+++ b/third_party/bytes/x86_64-unknown-linux-sgx.json
@@ -0,0 +1,31 @@
+{
+  "arch": "x86_64",
+  "cpu": "x86-64",
+  "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
+  "dynamic-linking": true,
+  "env": "sgx",
+  "exe-allocation-crate": "alloc_system",
+  "executables": true,
+  "has-elf-tls": true,
+  "has-rpath": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-unknown-linux-gnu",
+  "max-atomic-width": 64,
+  "os": "linux",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relro-level": "full",
+  "stack-probes": true,
+  "target-c-int-width": "32",
+  "target-endian": "little",
+  "target-family": "unix",
+  "target-pointer-width": "64",
+  "vendor": "unknown"
+}
diff --git a/third_party/http/.gitignore b/third_party/http/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/third_party/http/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/third_party/http/.travis.yml b/third_party/http/.travis.yml
new file mode 100644
index 0000000..053ba1f
--- /dev/null
+++ b/third_party/http/.travis.yml
@@ -0,0 +1,26 @@
+language: rust
+sudo: false
+
+cache: cargo
+
+matrix:
+  include:
+    - rust: stable
+    - rust: beta
+    - rust: nightly
+    # ensure wasm always builds
+    - rust: stable
+      script:
+        - rustup target add wasm32-unknown-unknown
+        - cargo build --target=wasm32-unknown-unknown
+    # minimum rustc version
+    - rust: 1.20.0
+      script: cargo build
+
+script:
+  - cargo test
+  - 'if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo test --benches; fi'
+
+notifications:
+  email:
+    on_success: never
diff --git a/third_party/http/CHANGELOG.md b/third_party/http/CHANGELOG.md
new file mode 100644
index 0000000..31a38f1
--- /dev/null
+++ b/third_party/http/CHANGELOG.md
@@ -0,0 +1,50 @@
+# 0.1.7 (June 22, 2018)
+
+* Add `From<uN> for HeaderValue` for most integer types (#218).
+* Add `Uri::into_parts()` inherent method (same as `Parts::from(uri)`) (#214).
+* Fix converting `Uri`s in authority-form to `Parts` and then back into `Uri` (#216).
+* Fix `Authority` parsing to reject multiple port sections (#215).
+* Fix parsing 1 character authority-form `Uri`s into illegal forms (#220).
+
+# 0.1.6 (June 13, 2018)
+
+* Add `HeaderName::from_static()` constructor (#195).
+* Add `Authority::from_static()` constructor (#186).
+* Implement `From<HeaderName>` for `HeaderValue` (#184).
+* Fix duplicate keys when iterating over `header::Keys` (#201).
+
+# 0.1.5 (February 28, 2018)
+
+* Add websocket handshake related header constants (#162).
+* Parsing `Authority` with an empty string now returns an error (#164).
+* Implement `PartialEq<u16>` for `StatusCode` (#153).
+* Implement `HttpTryFrom<&Uri>` for `Uri` (#165).
+* Implement `FromStr` for `Method` (#167).
+* Implement `HttpTryFrom<String>` for `Uri` (#171).
+* Add `into_body` fns to `Request` and `Response` (#172).
+* Fix `Request::options` (#177).
+
+# 0.1.4 (January 4, 2018)
+
+* Add PathAndQuery::from_static (#148).
+* Impl PartialOrd / PartialEq for Authority and PathAndQuery (#150).
+* Add `map` fn to `Request` and `Response` (#151).
+
+# 0.1.3 (December 11, 2017)
+
+* Add `Scheme` associated consts for common protos.
+
+# 0.1.2 (November 29, 2017)
+
+* Add Uri accessor for scheme part.
+* Fix Uri parsing bug (#134)
+
+# 0.1.1 (October 9, 2017)
+
+* Provide Uri accessors for parts (#129)
+* Add Request builder helpers. (#123)
+* Misc performance improvements (#126)
+
+# 0.1.0 (September 8, 2017)
+
+* Initial release.
diff --git a/third_party/http/Cargo.toml b/third_party/http/Cargo.toml
new file mode 100644
index 0000000..588712f
--- /dev/null
+++ b/third_party/http/Cargo.toml
@@ -0,0 +1,46 @@
+[package]
+name = "http"
+# When releasing to crates.io:
+# - Update html_root_url in lib.rs.
+# - Update CHANGELOG.md.
+# - Create git tag
+version = "0.1.7"
+readme = "README.md"
+documentation = "https://docs.rs/http"
+repository = "https://github.com/hyperium/http"
+homepage = "https://github.com/hyperium/http"
+license = "MIT/Apache-2.0"
+authors = [
+  "Alex Crichton <alex@alexcrichton.com>",
+  "Carl Lerche <me@carllerche.com>",
+  "Sean McArthur <sean@seanmonstar.com>",
+]
+description = """
+A set of types for representing HTTP requests and responses.
+"""
+keywords = ["http"]
+categories = ["web-programming"]
+
+[dependencies]
+bytes = { path = "../bytes" }
+fnv = { path = "../rust-fnv" }
+itoa = { path = "../itoa" }
+
+[target.'cfg(not(target_env = "sgx"))'.dependencies]
+sgx_tstd = { path =  "../../sgx_tstd" }
+
+[dev-dependencies]
+indexmap = "1.0"
+quickcheck = "0.6"
+rand = "0.4"
+seahash = "3.0.5"
+serde = "1.0"
+serde_json = "1.0"
+
+[[bench]]
+name = "header_map"
+path = "benches/header_map/mod.rs"
+
+[[bench]]
+name = "header_value"
+path = "benches/header_value.rs"
diff --git a/third_party/http/LICENSE-APACHE b/third_party/http/LICENSE-APACHE
new file mode 100644
index 0000000..80176c2
--- /dev/null
+++ b/third_party/http/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright 2017 http-rs authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/http/LICENSE-MIT b/third_party/http/LICENSE-MIT
new file mode 100644
index 0000000..0cbc550
--- /dev/null
+++ b/third_party/http/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017 http-rs 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/third_party/http/README.md b/third_party/http/README.md
new file mode 100644
index 0000000..04f2fb3
--- /dev/null
+++ b/third_party/http/README.md
@@ -0,0 +1,80 @@
+# HTTP
+
+A general purpose library of common HTTP types
+
+[![Build Status](https://travis-ci.org/hyperium/http.svg?branch=master)](https://travis-ci.org/hyperium/http)
+[![Crates.io](https://img.shields.io/crates/v/http.svg?maxAge=2592000)](https://crates.io/crates/http)
+[![Documentation](https://docs.rs/http/badge.svg)][dox]
+
+More information about this crate can be found in the [crate
+documentation][dox].
+
+[dox]: https://docs.rs/http
+
+## Usage
+
+To use `http`, first add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+http = "0.1"
+```
+
+Next, add this to your crate:
+
+```rust
+extern crate http;
+
+use http::{Request, Response};
+
+fn main() {
+    // ...
+}
+```
+
+## Examples
+
+Create an HTTP request:
+
+```rust
+extern crate http;
+
+use http::Request;
+
+fn main() {
+    let request = Request::builder()
+      .uri("https://www.rust-lang.org/")
+      .header("User-Agent", "awesome/1.0")
+      .body(())
+      .unwrap();
+}
+```
+
+Create an HTTP response:
+
+```rust
+extern crate http;
+
+use http::{Response, StatusCode};
+
+fn main() {
+    let response = Response::builder()
+      .status(StatusCode::MOVED_PERMANENTLY)
+      .header("Location", "https://www.rust-lang.org/install.html")
+      .body(())
+      .unwrap();
+}
+```
+
+# License
+
+Licensed under either of
+
+- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://apache.org/licenses/LICENSE-2.0)
+- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+# Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
diff --git a/third_party/http/Xargo.toml b/third_party/http/Xargo.toml
new file mode 100644
index 0000000..48ad024
--- /dev/null
+++ b/third_party/http/Xargo.toml
@@ -0,0 +1,20 @@
+[dependencies]
+alloc = {}
+panic_unwind = {}
+panic_abort = {}
+
+[dependencies.std]
+path = "../../xargo/sgx_tstd"
+stage = 1
+
+[dependencies.sgx_rand]
+path = "../../xargo/sgx_rand"
+stage = 2
+
+[dependencies.sgx_serialize]
+path = "../../xargo/sgx_serialize"
+stage = 2
+
+[dependencies.sgx_tunittest]
+path = "../../xargo/sgx_tunittest"
+stage = 2
\ No newline at end of file
diff --git a/third_party/http/benches/header_map/basic.rs b/third_party/http/benches/header_map/basic.rs
new file mode 100644
index 0000000..4ce7ed6
--- /dev/null
+++ b/third_party/http/benches/header_map/basic.rs
@@ -0,0 +1,586 @@
+macro_rules! bench {
+    ($name:ident($map:ident, $b:ident) $body:expr) => {
+        mod $name {
+            #[allow(unused_imports)]
+            use test::{self, Bencher};
+            use seahash::SeaHasher;
+            use fnv::FnvHasher;
+            use std::hash::BuildHasherDefault;
+            use http::header::*;
+            #[allow(unused_imports)]
+            use super::custom_hdr;
+
+            #[bench]
+            fn header_map($b: &mut Bencher) {
+                let $map = || HeaderMap::default();
+                $body
+            }
+
+            #[bench]
+            fn order_map_fnv($b: &mut Bencher) {
+                use indexmap::IndexMap;
+                let $map = || IndexMap::<_, _, BuildHasherDefault<FnvHasher>>::default();
+                $body
+            }
+
+            #[bench]
+            fn vec_map($b: &mut Bencher) {
+                use vec_map::VecMap;
+
+                let $map = || VecMap::with_capacity(0);
+                $body
+            }
+
+            #[bench]
+            fn order_map_seahash($b: &mut Bencher) {
+                use indexmap::IndexMap;
+                let $map = || IndexMap::<_, _, BuildHasherDefault<SeaHasher>>::default();
+                $body
+            }
+
+            /*
+            #[bench]
+            fn order_map_siphash($b: &mut Bencher) {
+                use indexmap::IndexMap;
+                let $map = || IndexMap::new();
+                $body
+            }
+
+            #[bench]
+            fn std_map_siphash($b: &mut Bencher) {
+                use std::collections::HashMap;
+                let $map = || HashMap::new();
+                $body
+            }
+            */
+        }
+    };
+}
+
+bench!(new_insert_get_host(new_map, b) {
+    b.iter(|| {
+        let mut h = new_map();
+        h.insert(HOST, "hyper.rs");
+        test::black_box(h.get(&HOST));
+    })
+});
+
+bench!(insert_4_std_get_30(new_map, b) {
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for i in 0..4 {
+            h.insert(super::STD[i].clone(), "foo");
+        }
+
+        for i in 0..30 {
+            test::black_box(h.get(&super::STD[i % 4]));
+        }
+    })
+});
+
+bench!(insert_6_std_get_6(new_map, b) {
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for i in 0..6 {
+            h.insert(super::STD[i].clone(), "foo");
+        }
+
+        for i in 0..6 {
+            test::black_box(h.get(&super::STD[i % 4]));
+        }
+    })
+});
+
+/*
+bench!(insert_remove_host(new_map, b) {
+    let mut h = new_map();
+
+    b.iter(|| {
+        test::black_box(h.insert(HOST, "hyper.rs"));
+        test::black_box(h.remove(&HOST));
+    })
+});
+
+bench!(insert_insert_host(new_map, b) {
+    let mut h = new_map();
+
+    b.iter(|| {
+        test::black_box(h.insert(HOST, "hyper.rs"));
+        test::black_box(h.insert(HOST, "hyper.rs"));
+    })
+});
+*/
+
+bench!(get_10_of_20_std(new_map, b) {
+    let mut h = new_map();
+
+    for hdr in super::STD[10..30].iter() {
+        h.insert(hdr.clone(), hdr.as_str().to_string());
+    }
+
+    b.iter(|| {
+        for hdr in &super::STD[10..20] {
+            test::black_box(h.get(hdr));
+        }
+    })
+});
+
+bench!(get_100_std(new_map, b) {
+    let mut h = new_map();
+
+    for hdr in super::STD.iter() {
+        h.insert(hdr.clone(), hdr.as_str().to_string());
+    }
+
+    b.iter(|| {
+        for i in 0..100 {
+            test::black_box(h.get(&super::STD[i % super::STD.len()]));
+        }
+    })
+});
+
+bench!(set_8_get_1_std(new_map, b) {
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &super::STD[0..8] {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&super::STD[0]));
+    })
+});
+
+bench!(set_10_get_1_std(new_map, b) {
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &super::STD[0..10] {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&super::STD[0]));
+    })
+});
+
+bench!(set_20_get_1_std(new_map, b) {
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &super::STD[0..20] {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&super::STD[0]));
+    })
+});
+
+bench!(get_10_custom_short(new_map, b) {
+    let hdrs = custom_hdr(20);
+    let mut h = new_map();
+
+    for hdr in &hdrs {
+        h.insert(hdr.clone(), hdr.as_str().to_string());
+    }
+
+    b.iter(|| {
+        for hdr in &hdrs[..10] {
+            test::black_box(h.get(hdr));
+        }
+    })
+});
+
+bench!(set_10_get_1_custom_short(new_map, b) {
+    let hdrs = custom_hdr(10);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+
+bench!(set_10_get_1_custom_med(new_map, b) {
+    let hdrs = super::med_custom_hdr(10);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+bench!(set_10_get_1_custom_long(new_map, b) {
+    let hdrs = super::long_custom_hdr(10);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+bench!(set_10_get_1_custom_very_long(new_map, b) {
+    let hdrs = super::very_long_custom_hdr(10);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+bench!(set_20_get_1_custom_short(new_map, b) {
+    let hdrs = custom_hdr(20);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+bench!(set_20_get_1_custom_med(new_map, b) {
+    let hdrs = super::med_custom_hdr(20);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+bench!(set_20_get_1_custom_long(new_map, b) {
+    let hdrs = super::long_custom_hdr(20);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+bench!(set_20_get_1_custom_very_long(new_map, b) {
+    let hdrs = super::very_long_custom_hdr(20);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+
+        test::black_box(h.get(&hdrs[0]));
+    })
+});
+
+bench!(insert_all_std_headers(new_map, b) {
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in super::STD {
+            test::black_box(h.insert(hdr.clone(), "foo"));
+        }
+    })
+});
+
+bench!(insert_79_custom_std_headers(new_map, b) {
+    let hdrs = super::custom_std(79);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            h.insert(hdr.clone(), "foo");
+        }
+    })
+});
+
+bench!(insert_100_custom_headers(new_map, b) {
+    let hdrs = custom_hdr(100);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            test::black_box(h.insert(hdr.clone(), "foo"));
+        }
+    })
+});
+
+bench!(insert_500_custom_headers(new_map, b) {
+    let hdrs = custom_hdr(500);
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for hdr in &hdrs {
+            test::black_box(h.insert(hdr.clone(), "foo"));
+        }
+    })
+});
+
+bench!(insert_one_15_char_header(new_map, b) {
+    let hdr: HeaderName = "abcd-abcd-abcde"
+        .parse().unwrap();
+
+    b.iter(|| {
+        let mut h = new_map();
+        h.insert(hdr.clone(), "hello");
+        test::black_box(h);
+    })
+});
+
+bench!(insert_one_25_char_header(new_map, b) {
+    let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcde"
+        .parse().unwrap();
+
+    b.iter(|| {
+        let mut h = new_map();
+        h.insert(hdr.clone(), "hello");
+        test::black_box(h);
+    })
+});
+
+bench!(insert_one_50_char_header(new_map, b) {
+    let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcde"
+        .parse().unwrap();
+
+    b.iter(|| {
+        let mut h = new_map();
+        h.insert(hdr.clone(), "hello");
+        test::black_box(h);
+    })
+});
+
+bench!(insert_one_100_char_header(new_map, b) {
+    let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcdeabcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcde"
+        .parse().unwrap();
+
+    b.iter(|| {
+        let mut h = new_map();
+        h.insert(hdr.clone(), "hello");
+        test::black_box(h);
+    })
+});
+
+const HN_HDRS: [(&'static str, &'static str); 11] = [
+    ("Date", "Fri, 27 Jan 2017 23:00:00 GMT"),
+    ("Content-Type", "text/html; charset=utf-8"),
+    ("Transfer-Encoding", "chunked"),
+    ("Connection", "keep-alive"),
+    ("Set-Cookie", "__cfduid=dbdfbbe3822b61cb8750ba37d894022151485558000; expires=Sat, 27-Jan-18 23:00:00 GMT; path=/; domain=.ycombinator.com; HttpOnly"),
+    ("Vary", "Accept-Encoding"),
+    ("Cache-Control", "private"),
+    ("X-Frame-Options", "DENY"),
+    ("Strict-Transport-Security", "max-age=31556900; includeSubDomains"),
+    ("Server", "cloudflare-nginx"),
+    ("CF-RAY", "327fd1809f3c1baf-SEA"),
+];
+
+bench!(hn_hdrs_set_8_get_many(new_map, b) {
+    let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS[..8].iter()
+        .map(|&(name, val)| (name.parse().unwrap(), val))
+        .collect();
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for &(ref name, val) in hdrs.iter() {
+            h.insert(name.clone(), val);
+        }
+
+        for _ in 0..15 {
+            test::black_box(h.get(&CONTENT_LENGTH));
+            test::black_box(h.get(&VARY));
+        }
+    });
+});
+
+bench!(hn_hdrs_set_8_get_miss(new_map, b) {
+    let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS[..8].iter()
+        .map(|&(name, val)| (name.parse().unwrap(), val))
+        .collect();
+
+    let miss: HeaderName = "x-wat".parse().unwrap();
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for &(ref name, val) in hdrs.iter() {
+            h.insert(name.clone(), val);
+        }
+
+        test::black_box(h.get(&CONTENT_LENGTH));
+        test::black_box(h.get(&miss));
+    });
+});
+
+bench!(hn_hdrs_set_11_get_with_miss(new_map, b) {
+    let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS.iter()
+        .map(|&(name, val)| (name.parse().unwrap(), val))
+        .collect();
+
+    let miss: HeaderName = "x-wat".parse().unwrap();
+
+    b.iter(|| {
+        let mut h = new_map();
+
+        for &(ref name, val) in hdrs.iter() {
+            h.insert(name.clone(), val);
+        }
+
+        for _ in 0..10 {
+            test::black_box(h.get(&CONTENT_LENGTH));
+            test::black_box(h.get(&VARY));
+            test::black_box(h.get(&miss));
+        }
+    });
+});
+
+use http::header::*;
+
+fn custom_hdr(n: usize) -> Vec<HeaderName> {
+    (0..n).map(|i| {
+        let s = format!("x-custom-{}", i);
+        s.parse().unwrap()
+    }).collect()
+}
+
+fn med_custom_hdr(n: usize) -> Vec<HeaderName> {
+    (0..n).map(|i| {
+        let s = format!("content-length-{}", i);
+        s.parse().unwrap()
+    }).collect()
+}
+
+fn long_custom_hdr(n: usize) -> Vec<HeaderName> {
+    (0..n).map(|i| {
+        let s = format!("access-control-allow-headers-{}", i);
+        s.parse().unwrap()
+    }).collect()
+}
+
+fn very_long_custom_hdr(n: usize) -> Vec<HeaderName> {
+    (0..n).map(|i| {
+        let s = format!("access-control-allow-access-control-allow-headers-{}", i);
+        s.parse().unwrap()
+    }).collect()
+}
+
+fn custom_std(n: usize) -> Vec<HeaderName> {
+    (0..n).map(|i| {
+        let s = format!("{}-{}", STD[i % STD.len()].as_str(), i);
+        s.parse().unwrap()
+    }).collect()
+}
+
+const STD: &'static [HeaderName] = &[
+    ACCEPT,
+    ACCEPT_CHARSET,
+    ACCEPT_ENCODING,
+    ACCEPT_LANGUAGE,
+    ACCEPT_RANGES,
+    ACCESS_CONTROL_ALLOW_CREDENTIALS,
+    ACCESS_CONTROL_ALLOW_HEADERS,
+    ACCESS_CONTROL_ALLOW_METHODS,
+    ACCESS_CONTROL_ALLOW_ORIGIN,
+    ACCESS_CONTROL_EXPOSE_HEADERS,
+    ACCESS_CONTROL_MAX_AGE,
+    ACCESS_CONTROL_REQUEST_HEADERS,
+    ACCESS_CONTROL_REQUEST_METHOD,
+    AGE,
+    ALLOW,
+    ALT_SVC,
+    AUTHORIZATION,
+    CACHE_CONTROL,
+    CONNECTION,
+    CONTENT_DISPOSITION,
+    CONTENT_ENCODING,
+    CONTENT_LANGUAGE,
+    CONTENT_LENGTH,
+    CONTENT_LOCATION,
+    CONTENT_RANGE,
+    CONTENT_SECURITY_POLICY,
+    CONTENT_SECURITY_POLICY_REPORT_ONLY,
+    CONTENT_TYPE,
+    COOKIE,
+    DNT,
+    DATE,
+    ETAG,
+    EXPECT,
+    EXPIRES,
+    FORWARDED,
+    FROM,
+    HOST,
+    IF_MATCH,
+    IF_MODIFIED_SINCE,
+    IF_NONE_MATCH,
+    IF_RANGE,
+    IF_UNMODIFIED_SINCE,
+    LAST_MODIFIED,
+    LINK,
+    LOCATION,
+    MAX_FORWARDS,
+    ORIGIN,
+    PRAGMA,
+    PROXY_AUTHENTICATE,
+    PROXY_AUTHORIZATION,
+    PUBLIC_KEY_PINS,
+    PUBLIC_KEY_PINS_REPORT_ONLY,
+    RANGE,
+    REFERER,
+    REFERRER_POLICY,
+    REFRESH,
+    RETRY_AFTER,
+    SERVER,
+    SET_COOKIE,
+    STRICT_TRANSPORT_SECURITY,
+    TE,
+    TRAILER,
+    TRANSFER_ENCODING,
+    USER_AGENT,
+    UPGRADE,
+    UPGRADE_INSECURE_REQUESTS,
+    VARY,
+    VIA,
+    WARNING,
+    WWW_AUTHENTICATE,
+    X_CONTENT_TYPE_OPTIONS,
+    X_DNS_PREFETCH_CONTROL,
+    X_FRAME_OPTIONS,
+    X_XSS_PROTECTION,
+];
diff --git a/third_party/http/benches/header_map/mod.rs b/third_party/http/benches/header_map/mod.rs
new file mode 100644
index 0000000..50a97f7
--- /dev/null
+++ b/third_party/http/benches/header_map/mod.rs
@@ -0,0 +1,10 @@
+#![feature(test)]
+
+extern crate http;
+extern crate test;
+extern crate indexmap;
+extern crate seahash;
+extern crate fnv;
+
+mod basic;
+mod vec_map;
diff --git a/third_party/http/benches/header_map/vec_map.rs b/third_party/http/benches/header_map/vec_map.rs
new file mode 100644
index 0000000..995e806
--- /dev/null
+++ b/third_party/http/benches/header_map/vec_map.rs
@@ -0,0 +1,103 @@
+#![allow(dead_code)]
+
+#[derive(Clone)]
+pub struct VecMap<K, V> {
+    vec: Vec<(K, V)>,
+}
+
+impl<K: PartialEq, V> VecMap<K, V> {
+    #[inline]
+    pub fn with_capacity(cap: usize) -> VecMap<K, V> {
+        VecMap {
+            vec: Vec::with_capacity(cap)
+        }
+    }
+
+    #[inline]
+    pub fn insert(&mut self, key: K, value: V) {
+        match self.find(&key) {
+            Some(pos) => self.vec[pos] = (key, value),
+            None => self.vec.push((key, value))
+        }
+    }
+
+    #[inline]
+    pub fn entry(&mut self, key: K) -> Entry<K, V> {
+        match self.find(&key) {
+            Some(pos) => Entry::Occupied(OccupiedEntry {
+                vec: self,
+                pos: pos,
+            }),
+            None => Entry::Vacant(VacantEntry {
+                vec: self,
+                key: key,
+            })
+        }
+    }
+
+    #[inline]
+    pub fn get<K2: PartialEq<K> + ?Sized>(&self, key: &K2) -> Option<&V> {
+        self.find(key).map(move |pos| &self.vec[pos].1)
+    }
+
+    #[inline]
+    pub fn get_mut<K2: PartialEq<K> + ?Sized>(&mut self, key: &K2) -> Option<&mut V> {
+        self.find(key).map(move |pos| &mut self.vec[pos].1)
+    }
+
+    #[inline]
+    pub fn contains_key<K2: PartialEq<K> + ?Sized>(&self, key: &K2) -> bool {
+        self.find(key).is_some()
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize { self.vec.len() }
+
+    #[inline]
+    pub fn iter(&self) -> ::std::slice::Iter<(K, V)> {
+        self.vec.iter()
+    }
+    #[inline]
+    pub fn remove<K2: PartialEq<K> + ?Sized>(&mut self, key: &K2) -> Option<V> {
+        self.find(key).map(|pos| self.vec.remove(pos)).map(|(_, v)| v)
+    }
+    #[inline]
+    pub fn clear(&mut self) {
+        self.vec.clear();
+    }
+
+    #[inline]
+    fn find<K2: PartialEq<K> + ?Sized>(&self, key: &K2) -> Option<usize> {
+        self.vec.iter().position(|entry| key == &entry.0)
+    }
+}
+
+pub enum Entry<'a, K: 'a, V: 'a> {
+    Vacant(VacantEntry<'a, K, V>),
+    Occupied(OccupiedEntry<'a, K, V>)
+}
+
+pub struct VacantEntry<'a, K: 'a, V: 'a> {
+    vec: &'a mut VecMap<K, V>,
+    key: K,
+}
+
+impl<'a, K, V> VacantEntry<'a, K, V> {
+    pub fn insert(self, val: V) -> &'a mut V {
+        let vec = self.vec;
+        vec.vec.push((self.key, val));
+        let pos = vec.vec.len() - 1;
+        &mut vec.vec[pos].1
+    }
+}
+
+pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
+    vec: &'a mut VecMap<K, V>,
+    pos: usize,
+}
+
+impl<'a, K, V> OccupiedEntry<'a, K, V> {
+    pub fn into_mut(self) -> &'a mut V {
+        &mut self.vec.vec[self.pos].1
+    }
+}
diff --git a/third_party/http/benches/header_value.rs b/third_party/http/benches/header_value.rs
new file mode 100644
index 0000000..d9d2055
--- /dev/null
+++ b/third_party/http/benches/header_value.rs
@@ -0,0 +1,54 @@
+#![feature(test)]
+
+extern crate bytes;
+extern crate http;
+extern crate test;
+
+use bytes::Bytes;
+use http::header::HeaderValue;
+use test::Bencher;
+
+static SHORT: &'static [u8] = b"localhost";
+static LONG: &'static [u8] = b"Mozilla/5.0 (X11; CrOS x86_64 9592.71.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.80 Safari/537.36";
+
+
+#[bench]
+fn from_shared_short(b: &mut Bencher) {
+    b.bytes = SHORT.len() as u64;
+    let bytes = Bytes::from_static(SHORT);
+    b.iter(|| {
+        HeaderValue::from_shared(bytes.clone()).unwrap();
+    });
+}
+
+#[bench]
+fn from_shared_long(b: &mut Bencher) {
+    b.bytes = LONG.len() as u64;
+    let bytes = Bytes::from_static(LONG);
+    b.iter(|| {
+        HeaderValue::from_shared(bytes.clone()).unwrap();
+    });
+}
+
+
+#[bench]
+fn from_shared_unchecked_short(b: &mut Bencher) {
+    b.bytes = SHORT.len() as u64;
+    let bytes = Bytes::from_static(SHORT);
+    b.iter(|| {
+        unsafe {
+            HeaderValue::from_shared_unchecked(bytes.clone());
+        }
+    });
+}
+
+#[bench]
+fn from_shared_unchecked_long(b: &mut Bencher) {
+    b.bytes = LONG.len() as u64;
+    let bytes = Bytes::from_static(LONG);
+    b.iter(|| {
+        unsafe {
+            HeaderValue::from_shared_unchecked(bytes.clone());
+        }
+    });
+}
diff --git a/third_party/http/src/byte_str.rs b/third_party/http/src/byte_str.rs
new file mode 100644
index 0000000..b0e7482
--- /dev/null
+++ b/third_party/http/src/byte_str.rs
@@ -0,0 +1,56 @@
+use bytes::Bytes;
+
+use std::prelude::v1::*;
+use std::{ops, str};
+
+#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct ByteStr {
+    bytes: Bytes,
+}
+
+impl ByteStr {
+    #[inline]
+    pub fn new() -> ByteStr {
+        ByteStr { bytes: Bytes::new() }
+    }
+
+    #[inline]
+    pub fn from_static(val: &'static str) -> ByteStr {
+        ByteStr { bytes: Bytes::from_static(val.as_bytes()) }
+    }
+
+    #[inline]
+    pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr {
+        ByteStr { bytes: bytes }
+    }
+}
+
+impl ops::Deref for ByteStr {
+    type Target = str;
+
+    #[inline]
+    fn deref(&self) -> &str {
+        let b: &[u8] = self.bytes.as_ref();
+        unsafe { str::from_utf8_unchecked(b) }
+    }
+}
+
+impl From<String> for ByteStr {
+    #[inline]
+    fn from(src: String) -> ByteStr {
+        ByteStr { bytes: Bytes::from(src) }
+    }
+}
+
+impl<'a> From<&'a str> for ByteStr {
+    #[inline]
+    fn from(src: &'a str) -> ByteStr {
+        ByteStr { bytes: Bytes::from(src) }
+    }
+}
+
+impl From<ByteStr> for Bytes {
+    fn from(src: ByteStr) -> Self {
+        src.bytes
+    }
+}
diff --git a/third_party/http/src/convert.rs b/third_party/http/src/convert.rs
new file mode 100644
index 0000000..2f901e6
--- /dev/null
+++ b/third_party/http/src/convert.rs
@@ -0,0 +1,45 @@
+use Error;
+use header::{HeaderName, HeaderValue};
+use method::Method;
+use sealed::Sealed;
+use status::StatusCode;
+use uri::Uri;
+
+/// Private trait for the `http` crate to have generic methods with fallible
+/// conversions.
+///
+/// This trait is similar to the `TryFrom` trait proposed in the standard
+/// library, except this is specialized for the `http` crate and isn't intended
+/// for general consumption.
+///
+/// This trait cannot be implemented types outside of the `http` crate, and is
+/// only intended for use as a generic bound on methods in the `http` crate.
+pub trait HttpTryFrom<T>: Sized + Sealed {
+    /// Associated error with the conversion this implementation represents.
+    type Error: Into<Error>;
+
+    #[doc(hidden)]
+    fn try_from(t: T) -> Result<Self, Self::Error>;
+}
+
+macro_rules! reflexive {
+    ($($t:ty,)*) => ($(
+        impl HttpTryFrom<$t> for $t {
+            type Error = Error;
+
+            fn try_from(t: Self) -> Result<Self, Self::Error> {
+                Ok(t)
+            }
+        }
+
+        impl Sealed for $t {}
+    )*)
+}
+
+reflexive! {
+    Uri,
+    Method,
+    StatusCode,
+    HeaderName,
+    HeaderValue,
+}
diff --git a/third_party/http/src/error.rs b/third_party/http/src/error.rs
new file mode 100644
index 0000000..8834059
--- /dev/null
+++ b/third_party/http/src/error.rs
@@ -0,0 +1,144 @@
+use std::error;
+use std::fmt;
+use std::result;
+
+use header;
+use method;
+use status;
+use uri;
+
+/// A generic "error" for HTTP connections
+///
+/// This error type is less specific than the error returned from other
+/// functions in this crate, but all other errors can be converted to this
+/// error. Consumers of this crate can typically consume and work with this form
+/// of error for conversions with the `?` operator.
+#[derive(Debug)]
+pub struct Error {
+    inner: ErrorKind,
+}
+
+/// A `Result` typedef to use with the `http::Error` type
+pub type Result<T> = result::Result<T, Error>;
+
+#[derive(Debug)]
+enum ErrorKind {
+    StatusCode(status::InvalidStatusCode),
+    Method(method::InvalidMethod),
+    Uri(uri::InvalidUri),
+    UriShared(uri::InvalidUriBytes),
+    UriParts(uri::InvalidUriParts),
+    HeaderName(header::InvalidHeaderName),
+    HeaderNameShared(header::InvalidHeaderNameBytes),
+    HeaderValue(header::InvalidHeaderValue),
+    HeaderValueShared(header::InvalidHeaderValueBytes),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        error::Error::description(self).fmt(f)
+    }
+}
+
+impl error::Error for Error {
+    fn description(&self) -> &str {
+        use self::ErrorKind::*;
+
+        match self.inner {
+            StatusCode(ref e) => e.description(),
+            Method(ref e) => e.description(),
+            Uri(ref e) => e.description(),
+            UriShared(ref e) => e.description(),
+            UriParts(ref e) => e.description(),
+            HeaderName(ref e) => e.description(),
+            HeaderNameShared(ref e) => e.description(),
+            HeaderValue(ref e) => e.description(),
+            HeaderValueShared(ref e) => e.description(),
+        }
+    }
+}
+
+impl From<status::InvalidStatusCode> for Error {
+    fn from(err: status::InvalidStatusCode) -> Error {
+        Error { inner: ErrorKind::StatusCode(err) }
+    }
+}
+
+impl From<method::InvalidMethod> for Error {
+    fn from(err: method::InvalidMethod) -> Error {
+        Error { inner: ErrorKind::Method(err) }
+    }
+}
+
+impl From<uri::InvalidUri> for Error {
+    fn from(err: uri::InvalidUri) -> Error {
+        Error { inner: ErrorKind::Uri(err) }
+    }
+}
+
+impl From<uri::InvalidUriBytes> for Error {
+    fn from(err: uri::InvalidUriBytes) -> Error {
+        Error { inner: ErrorKind::UriShared(err) }
+    }
+}
+
+impl From<uri::InvalidUriParts> for Error {
+    fn from(err: uri::InvalidUriParts) -> Error {
+        Error { inner: ErrorKind::UriParts(err) }
+    }
+}
+
+impl From<header::InvalidHeaderName> for Error {
+    fn from(err: header::InvalidHeaderName) -> Error {
+        Error { inner: ErrorKind::HeaderName(err) }
+    }
+}
+
+impl From<header::InvalidHeaderNameBytes> for Error {
+    fn from(err: header::InvalidHeaderNameBytes) -> Error {
+        Error { inner: ErrorKind::HeaderNameShared(err) }
+    }
+}
+
+impl From<header::InvalidHeaderValue> for Error {
+    fn from(err: header::InvalidHeaderValue) -> Error {
+        Error { inner: ErrorKind::HeaderValue(err) }
+    }
+}
+
+impl From<header::InvalidHeaderValueBytes> for Error {
+    fn from(err: header::InvalidHeaderValueBytes) -> Error {
+        Error { inner: ErrorKind::HeaderValueShared(err) }
+    }
+}
+
+// A crate-private type until we can use !.
+//
+// Being crate-private, we should be able to swap the type out in a
+// backwards compatible way.
+pub enum Never {}
+
+impl From<Never> for Error {
+    fn from(never: Never) -> Error {
+        match never {}
+    }
+}
+
+impl fmt::Debug for Never {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {}
+    }
+}
+
+impl fmt::Display for Never {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {}
+    }
+}
+
+impl error::Error for Never {
+    fn description(&self) -> &str {
+        match *self {}
+    }
+}
+
diff --git a/third_party/http/src/extensions.rs b/third_party/http/src/extensions.rs
new file mode 100644
index 0000000..8d2a06a
--- /dev/null
+++ b/third_party/http/src/extensions.rs
@@ -0,0 +1,158 @@
+use std::prelude::v1::*;
+use std::any::{Any, TypeId};
+use std::collections::HashMap;
+use std::hash::BuildHasherDefault;
+use std::fmt;
+
+use fnv::FnvHasher;
+
+type AnyMap = HashMap<TypeId, Box<Any + Send + Sync>, BuildHasherDefault<FnvHasher>>;
+
+/// A type map of protocol extensions.
+///
+/// `Extensions` can be used by `Request` and `Response` to store
+/// extra data derived from the underlying protocol.
+#[derive(Default)]
+pub struct Extensions {
+    map: AnyMap,
+}
+
+impl Extensions {
+    /// Create an empty `Extensions`.
+    #[inline]
+    pub fn new() -> Extensions {
+        Extensions {
+            map: HashMap::default(),
+        }
+    }
+
+    /// Insert a type into this `Extensions`.
+    ///
+    /// If a extension of this type already existed, it will
+    /// be returned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::Extensions;
+    /// let mut ext = Extensions::new();
+    /// assert!(ext.insert(5i32).is_none());
+    /// assert!(ext.insert(4u8).is_none());
+    /// assert_eq!(ext.insert(9i32), Some(5i32));
+    /// ```
+    pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
+        self.map.insert(TypeId::of::<T>(), Box::new(val))
+            .and_then(|boxed| {
+                //TODO: we can use unsafe and remove double checking the type id
+                (boxed as Box<Any + 'static>)
+                    .downcast()
+                    .ok()
+                    .map(|boxed| *boxed)
+            })
+    }
+
+    /// Get a reference to a type previously inserted on this `Extensions`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::Extensions;
+    /// let mut ext = Extensions::new();
+    /// assert!(ext.get::<i32>().is_none());
+    /// ext.insert(5i32);
+    ///
+    /// assert_eq!(ext.get::<i32>(), Some(&5i32));
+    /// ```
+    pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
+        self.map.get(&TypeId::of::<T>())
+            //TODO: we can use unsafe and remove double checking the type id
+            .and_then(|boxed| (&**boxed as &(Any + 'static)).downcast_ref())
+    }
+
+    /// Get a mutable reference to a type previously inserted on this `Extensions`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::Extensions;
+    /// let mut ext = Extensions::new();
+    /// ext.insert(String::from("Hello"));
+    /// ext.get_mut::<String>().unwrap().push_str(" World");
+    ///
+    /// assert_eq!(ext.get::<String>().unwrap(), "Hello World");
+    /// ```
+    pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
+        self.map.get_mut(&TypeId::of::<T>())
+            //TODO: we can use unsafe and remove double checking the type id
+            .and_then(|boxed| (&mut **boxed as &mut (Any + 'static)).downcast_mut())
+    }
+
+
+    /// Remove a type from this `Extensions`.
+    ///
+    /// If a extension of this type existed, it will be returned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::Extensions;
+    /// let mut ext = Extensions::new();
+    /// ext.insert(5i32);
+    /// assert_eq!(ext.remove::<i32>(), Some(5i32));
+    /// assert!(ext.get::<i32>().is_none());
+    /// ```
+    pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
+        self.map.remove(&TypeId::of::<T>())
+            .and_then(|boxed| {
+                //TODO: we can use unsafe and remove double checking the type id
+                (boxed as Box<Any + 'static>)
+                    .downcast()
+                    .ok()
+                    .map(|boxed| *boxed)
+            })
+    }
+
+    /// Clear the `Extensions` of all inserted extensions.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::Extensions;
+    /// let mut ext = Extensions::new();
+    /// ext.insert(5i32);
+    /// ext.clear();
+    ///
+    /// assert!(ext.get::<i32>().is_none());
+    /// ```
+    #[inline]
+    pub fn clear(&mut self) {
+        self.map.clear();
+    }
+}
+
+impl fmt::Debug for Extensions {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Extensions")
+            .finish()
+    }
+}
+
+#[test]
+fn test_extensions() {
+    #[derive(Debug, PartialEq)]
+    struct MyType(i32);
+
+    let mut extensions = Extensions::new();
+
+    extensions.insert(5i32);
+    extensions.insert(MyType(10));
+
+    assert_eq!(extensions.get(), Some(&5i32));
+    assert_eq!(extensions.get_mut(), Some(&mut 5i32));
+
+    assert_eq!(extensions.remove::<i32>(), Some(5i32));
+    assert!(extensions.get::<i32>().is_none());
+
+    assert_eq!(extensions.get::<bool>(), None);
+    assert_eq!(extensions.get(), Some(&MyType(10)));
+}
diff --git a/third_party/http/src/header/map.rs b/third_party/http/src/header/map.rs
new file mode 100644
index 0000000..6130ebb
--- /dev/null
+++ b/third_party/http/src/header/map.rs
@@ -0,0 +1,3231 @@
+use super::HeaderValue;
+use super::name::{HeaderName, HdrName, InvalidHeaderName};
+
+use std::prelude::v1::*;
+use std::{fmt, mem, ops, ptr, vec};
+use std::collections::hash_map::RandomState;
+use std::hash::{BuildHasher, Hasher, Hash};
+use std::iter::FromIterator;
+use std::marker::PhantomData;
+
+pub use self::as_header_name::AsHeaderName;
+pub use self::into_header_name::IntoHeaderName;
+
+/// A set of HTTP headers
+///
+/// `HeaderMap` is an multimap of `HeaderName` to values.
+///
+/// # Examples
+///
+/// Basic usage
+///
+/// ```
+/// # use http::HeaderMap;
+/// # use http::header::{CONTENT_LENGTH, HOST, LOCATION};
+/// let mut headers = HeaderMap::new();
+///
+/// headers.insert(HOST, "example.com".parse().unwrap());
+/// headers.insert(CONTENT_LENGTH, "123".parse().unwrap());
+///
+/// assert!(headers.contains_key(HOST));
+/// assert!(!headers.contains_key(LOCATION));
+///
+/// assert_eq!(headers[HOST], "example.com");
+///
+/// headers.remove(HOST);
+///
+/// assert!(!headers.contains_key(HOST));
+/// ```
+#[derive(Clone)]
+pub struct HeaderMap<T = HeaderValue> {
+    // Used to mask values to get an index
+    mask: Size,
+    indices: Vec<Pos>,
+    entries: Vec<Bucket<T>>,
+    extra_values: Vec<ExtraValue<T>>,
+    danger: Danger,
+}
+
+// # Implementation notes
+//
+// Below, you will find a fairly large amount of code. Most of this is to
+// provide the necessary functions to efficiently manipulate the header
+// multimap. The core hashing table is based on robin hood hashing [1]. While
+// this is the same hashing algorithm used as part of Rust's `HashMap` in
+// stdlib, many implementation details are different. The two primary reasons
+// for this divergence are that `HeaderMap` is a multimap and the structure has
+// been optimized to take advantage of the characteristics of HTTP headers.
+//
+// ## Structure Layout
+//
+// Most of the data contained by `HeaderMap` is *not* stored in the hash table.
+// Instead, pairs of header name and *first* associated header value are stored
+// in the `entries` vector. If the header name has more than one associated
+// header value, then additional values are stored in `extra_values`. The actual
+// hash table (`indices`) only maps hash codes to indices in `entries`. This
+// means that, when an eviction happens, the actual header name and value stay
+// put and only a tiny amount of memory has to be copied.
+//
+// Extra values associated with a header name are tracked using a linked list.
+// Links are formed with offsets into `extra_values` and not pointers.
+//
+// [1]: https://en.wikipedia.org/wiki/Hash_table#Robin_Hood_hashing
+
+/// `HeaderMap` entry iterator.
+///
+/// Yields `(&HeaderName, &value)` tuples. The same header name may be yielded
+/// more than once if it has more than one associated value.
+#[derive(Debug)]
+pub struct Iter<'a, T: 'a> {
+    inner: IterMut<'a, T>,
+}
+
+/// `HeaderMap` mutable entry iterator
+///
+/// Yields `(&HeaderName, &mut value)` tuples. The same header name may be
+/// yielded more than once if it has more than one associated value.
+#[derive(Debug)]
+pub struct IterMut<'a, T: 'a> {
+    map: *mut HeaderMap<T>,
+    entry: usize,
+    cursor: Option<Cursor>,
+    lt: PhantomData<&'a mut HeaderMap<T>>,
+}
+
+/// An owning iterator over the entries of a `HeaderMap`.
+///
+/// This struct is created by the `into_iter` method on `HeaderMap`.
+#[derive(Debug)]
+pub struct IntoIter<T> {
+    // If None, pull from `entries`
+    next: Option<usize>,
+    entries: vec::IntoIter<Bucket<T>>,
+    extra_values: Vec<ExtraValue<T>>,
+}
+
+/// An iterator over `HeaderMap` keys.
+///
+/// Each header name is yielded only once, even if it has more than one
+/// associated value.
+#[derive(Debug)]
+pub struct Keys<'a, T: 'a> {
+    inner: ::std::slice::Iter<'a, Bucket<T>>,
+}
+
+/// `HeaderMap` value iterator.
+///
+/// Each value contained in the `HeaderMap` will be yielded.
+#[derive(Debug)]
+pub struct Values<'a, T: 'a> {
+    inner: Iter<'a, T>,
+}
+
+/// `HeaderMap` mutable value iterator
+#[derive(Debug)]
+pub struct ValuesMut<'a, T: 'a> {
+    inner: IterMut<'a, T>,
+}
+
+/// A drain iterator for `HeaderMap`.
+#[derive(Debug)]
+pub struct Drain<'a, T: 'a> {
+    idx: usize,
+    map: *mut HeaderMap<T>,
+    lt: PhantomData<&'a mut HeaderMap<T>>,
+}
+
+/// A view to all values stored in a single entry.
+///
+/// This struct is returned by `HeaderMap::get_all`.
+#[derive(Debug)]
+pub struct GetAll<'a, T: 'a> {
+    map: &'a HeaderMap<T>,
+    index: Option<usize>,
+}
+
+/// A view into a single location in a `HeaderMap`, which may be vacant or occupied.
+#[derive(Debug)]
+pub enum Entry<'a, T: 'a> {
+    /// An occupied entry
+    Occupied(OccupiedEntry<'a, T>),
+
+    /// A vacant entry
+    Vacant(VacantEntry<'a, T>),
+}
+
+/// A view into a single empty location in a `HeaderMap`.
+///
+/// This struct is returned as part of the `Entry` enum.
+#[derive(Debug)]
+pub struct VacantEntry<'a, T: 'a> {
+    map: &'a mut HeaderMap<T>,
+    key: HeaderName,
+    hash: HashValue,
+    probe: usize,
+    danger: bool,
+}
+
+/// A view into a single occupied location in a `HeaderMap`.
+///
+/// This struct is returned as part of the `Entry` enum.
+#[derive(Debug)]
+pub struct OccupiedEntry<'a, T: 'a> {
+    map: &'a mut HeaderMap<T>,
+    probe: usize,
+    index: usize,
+}
+
+/// An iterator of all values associated with a single header name.
+#[derive(Debug)]
+pub struct ValueIter<'a, T: 'a> {
+    map: &'a HeaderMap<T>,
+    index: usize,
+    front: Option<Cursor>,
+    back: Option<Cursor>,
+}
+
+/// A mutable iterator of all values associated with a single header name.
+#[derive(Debug)]
+pub struct ValueIterMut<'a, T: 'a> {
+    map: *mut HeaderMap<T>,
+    index: usize,
+    front: Option<Cursor>,
+    back: Option<Cursor>,
+    lt: PhantomData<&'a mut HeaderMap<T>>,
+}
+
+/// An drain iterator of all values associated with a single header name.
+#[derive(Debug)]
+pub struct ValueDrain<'a, T: 'a> {
+    map: *mut HeaderMap<T>,
+    first: Option<T>,
+    next: Option<usize>,
+    lt: PhantomData<&'a mut HeaderMap<T>>,
+}
+
+/// Tracks the value iterator state
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+enum Cursor {
+    Head,
+    Values(usize),
+}
+
+/// Type used for representing the size of a HeaderMap value.
+///
+/// 32,768 is more than enough entries for a single header map. Setting this
+/// limit enables using `u16` to represent all offsets, which takes 2 bytes
+/// instead of 8 on 64 bit processors.
+///
+/// Setting this limit is especially benificial for `indices`, making it more
+/// cache friendly. More hash codes can fit in a cache line.
+///
+/// You may notice that `u16` may represent more than 32,768 values. This is
+/// true, but 32,768 should be plenty and it allows us to reserve the top bit
+/// for future usage.
+type Size = usize;
+
+/// This limit falls out from above.
+const MAX_SIZE: usize = (1 << 15);
+
+/// An entry in the hash table. This represents the full hash code for an entry
+/// as well as the position of the entry in the `entries` vector.
+#[derive(Copy, Clone)]
+struct Pos {
+    // Index in the `entries` vec
+    index: Size,
+    // Full hash value for the entry.
+    hash: HashValue,
+}
+
+/// Hash values are limited to u16 as well. While `fast_hash` and `Hasher`
+/// return `usize` hash codes, limiting the effective hash code to the lower 16
+/// bits is fine since we know that the `indices` vector will never grow beyond
+/// that size.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+struct HashValue(usize);
+
+/// Stores the data associated with a `HeaderMap` entry. Only the first value is
+/// included in this struct. If a header name has more than one associated
+/// value, all extra values are stored in the `extra_values` vector. A doubly
+/// linked list of entries is maintained. The doubly linked list is used so that
+/// removing a value is constant time. This also has the nice property of
+/// enabling double ended iteration.
+#[derive(Debug, Clone)]
+struct Bucket<T> {
+    hash: HashValue,
+    key: HeaderName,
+    value: T,
+    links: Option<Links>,
+}
+
+/// The head and tail of the value linked list.
+#[derive(Debug, Copy, Clone)]
+struct Links {
+    next: usize,
+    tail: usize,
+}
+
+/// Node in doubly-linked list of header value entries
+#[derive(Debug, Clone)]
+struct ExtraValue<T> {
+    value: T,
+    prev: Link,
+    next: Link,
+}
+
+/// A header value node is either linked to another node in the `extra_values`
+/// list or it points to an entry in `entries`. The entry in `entries` is the
+/// start of the list and holds the associated header name.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+enum Link {
+    Entry(usize),
+    Extra(usize),
+}
+
+/// Tracks the header map danger level! This relates to the adaptive hashing
+/// algorithm. A HeaderMap starts in the "green" state, when a large number of
+/// collisions are detected, it transitions to the yellow state. At this point,
+/// the header map will either grow and switch back to the green state OR it
+/// will transition to the red state.
+///
+/// When in the red state, a safe hashing algorithm is used and all values in
+/// the header map have to be rehashed.
+#[derive(Clone)]
+enum Danger {
+    Green,
+    Yellow,
+    Red(RandomState),
+}
+
+// The HeaderMap will use a sequential search strategy until the size of the map
+// exceeds this threshold. This tends to be faster for very small header maps.
+// This way all hashing logic can be skipped.
+const SEQ_SEARCH_THRESHOLD: usize = 8;
+
+// Constants related to detecting DOS attacks.
+//
+// Displacement is the number of entries that get shifted when inserting a new
+// value. Forward shift is how far the entry gets stored from the ideal
+// position.
+//
+// The current constant values were picked from another implementation. It could
+// be that there are different values better suited to the header map case.
+const DISPLACEMENT_THRESHOLD: usize = 128;
+const FORWARD_SHIFT_THRESHOLD: usize = 512;
+
+// The default strategy for handling the yellow danger state is to increase the
+// header map capacity in order to (hopefully) reduce the number of collisions.
+// If growing the hash map would cause the load factor to drop bellow this
+// threshold, then instead of growing, the headermap is switched to the red
+// danger state and safe hashing is used instead.
+const LOAD_FACTOR_THRESHOLD: f32 = 0.2;
+
+// Macro used to iterate the hash table starting at a given point, looping when
+// the end is hit.
+macro_rules! probe_loop {
+    ($label:tt: $probe_var: ident < $len: expr, $body: expr) => {
+        debug_assert!($len > 0);
+        $label:
+        loop {
+            if $probe_var < $len {
+                $body
+                $probe_var += 1;
+            } else {
+                $probe_var = 0;
+            }
+        }
+    };
+    ($probe_var: ident < $len: expr, $body: expr) => {
+        debug_assert!($len > 0);
+        loop {
+            if $probe_var < $len {
+                $body
+                $probe_var += 1;
+            } else {
+                $probe_var = 0;
+            }
+        }
+    };
+}
+
+// First part of the robinhood algorithm. Given a key, find the slot in which it
+// will be inserted. This is done by starting at the "ideal" spot. Then scanning
+// until the destination slot is found. A destination slot is either the next
+// empty slot or the next slot that is occupied by an entry that has a lower
+// displacement (displacement is the distance from the ideal spot).
+//
+// This is implemented as a macro instead of a function that takes a closure in
+// order to guarantee that it is "inlined". There is no way to annotate closures
+// to guarantee inlining.
+macro_rules! insert_phase_one {
+    ($map:ident,
+     $key:expr,
+     $probe:ident,
+     $pos:ident,
+     $hash:ident,
+     $danger:ident,
+     $vacant:expr,
+     $occupied:expr,
+     $robinhood:expr) =>
+    {{
+        let $hash = hash_elem_using(&$map.danger, &$key);
+        let mut $probe = desired_pos($map.mask, $hash);
+        let mut dist = 0;
+        let ret;
+
+        // Start at the ideal position, checking all slots
+        probe_loop!('probe: $probe < $map.indices.len(), {
+            if let Some(($pos, entry_hash)) = $map.indices[$probe].resolve() {
+                // The slot is already occupied, but check if it has a lower
+                // displacement.
+                let their_dist = probe_distance($map.mask, entry_hash, $probe);
+
+                if their_dist < dist {
+                    // The new key's distance is larger, so claim this spot and
+                    // displace the current entry.
+                    //
+                    // Check if this insertion is above the danger threshold.
+                    let $danger =
+                        dist >= FORWARD_SHIFT_THRESHOLD && !$map.danger.is_red();
+
+                    ret = $robinhood;
+                    break 'probe;
+                } else if entry_hash == $hash && $map.entries[$pos].key == $key {
+                    // There already is an entry with the same key.
+                    ret = $occupied;
+                    break 'probe;
+                }
+            } else {
+                // The entry is vacant, use it for this key.
+                let $danger =
+                    dist >= FORWARD_SHIFT_THRESHOLD && !$map.danger.is_red();
+
+                ret = $vacant;
+                break 'probe;
+            }
+
+            dist += 1;
+        });
+
+        ret
+    }}
+}
+
+// ===== impl HeaderMap =====
+
+impl HeaderMap {
+    /// Create an empty `HeaderMap`.
+    ///
+    /// The map will be created without any capacity. This function will not
+    /// allocate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// let map = HeaderMap::new();
+    ///
+    /// assert!(map.is_empty());
+    /// assert_eq!(0, map.capacity());
+    /// ```
+    pub fn new() -> Self {
+        HeaderMap::with_capacity(0)
+    }
+}
+
+impl<T> HeaderMap<T> {
+    /// Create an empty `HeaderMap` with the specified capacity.
+    ///
+    /// The returned map will allocate internal storage in order to hold about
+    /// `capacity` elements without reallocating. However, this is a "best
+    /// effort" as there are usage patterns that could cause additional
+    /// allocations before `capacity` headers are stored in the map.
+    ///
+    /// More capacity than requested may be allocated.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// let map: HeaderMap<u32> = HeaderMap::with_capacity(10);
+    ///
+    /// assert!(map.is_empty());
+    /// assert_eq!(12, map.capacity());
+    /// ```
+    pub fn with_capacity(capacity: usize) -> HeaderMap<T> {
+        assert!(capacity <= MAX_SIZE, "requested capacity too large");
+
+        if capacity == 0 {
+            HeaderMap {
+                mask: 0,
+                indices: Vec::new(),
+                entries: Vec::new(),
+                extra_values: Vec::new(),
+                danger: Danger::Green,
+            }
+        } else {
+            // Avoid allocating storage for the hash table if the requested
+            // capacity is below the threshold at which the hash map algorithm
+            // is used.
+            let entries_cap = to_raw_capacity(capacity).next_power_of_two();
+            let indices_cap = if entries_cap > SEQ_SEARCH_THRESHOLD {
+                entries_cap
+            } else {
+                0
+            };
+
+            HeaderMap {
+                mask: entries_cap.wrapping_sub(1) as Size,
+                indices: vec![Pos::none(); indices_cap],
+                entries: Vec::with_capacity(entries_cap),
+                extra_values: Vec::new(),
+                danger: Danger::Green,
+            }
+        }
+    }
+
+    /// Returns the number of headers stored in the map.
+    ///
+    /// This number represents the total number of **values** stored in the map.
+    /// This number can be greater than or equal to the number of **keys**
+    /// stored given that a single key may have more than one associated value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{ACCEPT, HOST};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// assert_eq!(0, map.len());
+    ///
+    /// map.insert(ACCEPT, "text/plain".parse().unwrap());
+    /// map.insert(HOST, "localhost".parse().unwrap());
+    ///
+    /// assert_eq!(2, map.len());
+    ///
+    /// map.append(ACCEPT, "text/html".parse().unwrap());
+    ///
+    /// assert_eq!(3, map.len());
+    /// ```
+    pub fn len(&self) -> usize {
+        self.entries.len() + self.extra_values.len()
+    }
+
+    /// Returns the number of keys stored in the map.
+    ///
+    /// This number will be less than or equal to `len()` as each key may have
+    /// more than one associated value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{ACCEPT, HOST};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// assert_eq!(0, map.keys_len());
+    ///
+    /// map.insert(ACCEPT, "text/plain".parse().unwrap());
+    /// map.insert(HOST, "localhost".parse().unwrap());
+    ///
+    /// assert_eq!(2, map.keys_len());
+    ///
+    /// map.insert(ACCEPT, "text/html".parse().unwrap());
+    ///
+    /// assert_eq!(2, map.keys_len());
+    /// ```
+    pub fn keys_len(&self) -> usize {
+        self.entries.len()
+    }
+
+    /// Returns true if the map contains no elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// assert!(map.is_empty());
+    ///
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    ///
+    /// assert!(!map.is_empty());
+    /// ```
+    pub fn is_empty(&self) -> bool {
+        self.entries.len() == 0
+    }
+
+    /// Clears the map, removing all key-value pairs. Keeps the allocated memory
+    /// for reuse.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    ///
+    /// map.clear();
+    /// assert!(map.is_empty());
+    /// assert!(map.capacity() > 0);
+    /// ```
+    pub fn clear(&mut self) {
+        self.entries.clear();
+        self.extra_values.clear();
+        self.danger = Danger::Green;
+
+        for e in self.indices.iter_mut() {
+            *e = Pos::none();
+        }
+    }
+
+    /// Returns the number of headers the map can hold without reallocating.
+    ///
+    /// This number is an approximation as certain usage patterns could cause
+    /// additional allocations before the returned capacity is filled.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// assert_eq!(0, map.capacity());
+    ///
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    /// assert_eq!(6, map.capacity());
+    /// ```
+    pub fn capacity(&self) -> usize {
+        usable_capacity(self.indices.len())
+    }
+
+    /// Reserves capacity for at least `additional` more headers to be inserted
+    /// into the `HeaderMap`.
+    ///
+    /// The header map may reserve more space to avoid frequent reallocations.
+    /// Like with `with_capacity`, this will be a "best effort" to avoid
+    /// allocations until `additional` more headers are inserted. Certain usage
+    /// patterns could cause additional allocations before the number is
+    /// reached.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new allocation size overflows `usize`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// map.reserve(10);
+    /// # map.insert(HOST, "bar".parse().unwrap());
+    /// ```
+    pub fn reserve(&mut self, additional: usize) {
+        // TODO: This can't overflow if done properly... since the max # of
+        // elements is u16::MAX.
+        let cap = self.entries.len()
+            .checked_add(additional)
+            .expect("reserve overflow");
+
+        if cap > self.indices.len() {
+            let cap = cap.next_power_of_two();
+
+            if self.entries.len() == 0 {
+                self.mask = cap - 1;
+                self.indices = vec![Pos::none(); cap];
+                self.entries = Vec::with_capacity(usable_capacity(cap));
+            } else {
+                self.grow(cap);
+            }
+        }
+    }
+
+    /// Returns a reference to the value associated with the key.
+    ///
+    /// If there are multiple values associated with the key, then the first one
+    /// is returned. Use `get_all` to get all values associated with a given
+    /// key. Returns `None` if there are no values associated with the key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// assert!(map.get("host").is_none());
+    ///
+    /// map.insert(HOST, "hello".parse().unwrap());
+    /// assert_eq!(map.get(HOST).unwrap(), &"hello");
+    /// assert_eq!(map.get("host").unwrap(), &"hello");
+    ///
+    /// map.append(HOST, "world".parse().unwrap());
+    /// assert_eq!(map.get("host").unwrap(), &"hello");
+    /// ```
+    pub fn get<K>(&self, key: K) -> Option<&T>
+        where K: AsHeaderName
+    {
+        match key.find(self) {
+            Some((_, found)) => {
+                let entry = &self.entries[found];
+                Some(&entry.value)
+            }
+            None => None,
+        }
+    }
+
+    /// Returns a mutable reference to the value associated with the key.
+    ///
+    /// If there are multiple values associated with the key, then the first one
+    /// is returned. Use `entry` to get all values associated with a given
+    /// key. Returns `None` if there are no values associated with the key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::default();
+    /// map.insert(HOST, "hello".to_string());
+    /// map.get_mut("host").unwrap().push_str("-world");
+    ///
+    /// assert_eq!(map.get(HOST).unwrap(), &"hello-world");
+    /// ```
+    pub fn get_mut<K>(&mut self, key: K) -> Option<&mut T>
+        where K: AsHeaderName
+    {
+        match key.find(self) {
+            Some((_, found)) => {
+                let entry = &mut self.entries[found];
+                Some(&mut entry.value)
+            }
+            None => None,
+        }
+    }
+
+    /// Returns a view of all values associated with a key.
+    ///
+    /// The returned view does not incur any allocations and allows iterating
+    /// the values associated with the key.  See [`GetAll`] for more details.
+    /// Returns `None` if there are no values associated with the key.
+    ///
+    /// [`GetAll`]: struct.GetAll.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// map.insert(HOST, "hello".parse().unwrap());
+    /// map.append(HOST, "goodbye".parse().unwrap());
+    ///
+    /// let view = map.get_all("host");
+    ///
+    /// let mut iter = view.iter();
+    /// assert_eq!(&"hello", iter.next().unwrap());
+    /// assert_eq!(&"goodbye", iter.next().unwrap());
+    /// assert!(iter.next().is_none());
+    /// ```
+    pub fn get_all<K>(&self, key: K) -> GetAll<T>
+        where K: AsHeaderName
+    {
+        GetAll {
+            map: self,
+            index: key.find(self).map(|(_, i)| i),
+        }
+    }
+
+    /// Returns true if the map contains a value for the specified key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// assert!(!map.contains_key(HOST));
+    ///
+    /// map.insert(HOST, "world".parse().unwrap());
+    /// assert!(map.contains_key("host"));
+    /// ```
+    pub fn contains_key<K>(&self, key: K) -> bool
+        where K: AsHeaderName
+    {
+        key.find(self).is_some()
+    }
+
+    /// An iterator visiting all key-value pairs.
+    ///
+    /// The iteration order is arbitrary, but consistent across platforms for
+    /// the same crate version. Each key will be yielded once per associated
+    /// value. So, if a key has 3 associated values, it will be yielded 3 times.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{CONTENT_LENGTH, HOST};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// map.insert(HOST, "hello".parse().unwrap());
+    /// map.append(HOST, "goodbye".parse().unwrap());
+    /// map.insert(CONTENT_LENGTH, "123".parse().unwrap());
+    ///
+    /// for (key, value) in map.iter() {
+    ///     println!("{:?}: {:?}", key, value);
+    /// }
+    /// ```
+    pub fn iter(&self) -> Iter<T> {
+        Iter {
+            inner: IterMut {
+                map: self as *const _ as *mut _,
+                entry: 0,
+                cursor: self.entries.first().map(|_| Cursor::Head),
+                lt: PhantomData,
+            }
+        }
+    }
+
+    /// An iterator visiting all key-value pairs, with mutable value references.
+    ///
+    /// The iterator order is arbitrary, but consistent across platforms for the
+    /// same crate version. Each key will be yielded once per associated value,
+    /// so if a key has 3 associated values, it will be yielded 3 times.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{CONTENT_LENGTH, HOST};
+    /// let mut map = HeaderMap::default();
+    ///
+    /// map.insert(HOST, "hello".to_string());
+    /// map.append(HOST, "goodbye".to_string());
+    /// map.insert(CONTENT_LENGTH, "123".to_string());
+    ///
+    /// for (key, value) in map.iter_mut() {
+    ///     value.push_str("-boop");
+    /// }
+    /// ```
+    pub fn iter_mut(&mut self) -> IterMut<T> {
+        IterMut {
+            map: self as *mut _,
+            entry: 0,
+            cursor: self.entries.first().map(|_| Cursor::Head),
+            lt: PhantomData,
+        }
+    }
+
+    /// An iterator visiting all keys.
+    ///
+    /// The iteration order is arbitrary, but consistent across platforms for
+    /// the same crate version. Each key will be yielded only once even if it
+    /// has multiple associated values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{CONTENT_LENGTH, HOST};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// map.insert(HOST, "hello".parse().unwrap());
+    /// map.append(HOST, "goodbye".parse().unwrap());
+    /// map.insert(CONTENT_LENGTH, "123".parse().unwrap());
+    ///
+    /// for key in map.keys() {
+    ///     println!("{:?}", key);
+    /// }
+    /// ```
+    pub fn keys(&self) -> Keys<T> {
+        Keys { inner: self.entries.iter() }
+    }
+
+    /// An iterator visiting all values.
+    ///
+    /// The iteration order is arbitrary, but consistent across platforms for
+    /// the same crate version.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{CONTENT_LENGTH, HOST};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// map.insert(HOST, "hello".parse().unwrap());
+    /// map.append(HOST, "goodbye".parse().unwrap());
+    /// map.insert(CONTENT_LENGTH, "123".parse().unwrap());
+    ///
+    /// for value in map.values() {
+    ///     println!("{:?}", value);
+    /// }
+    /// ```
+    pub fn values(&self) -> Values<T> {
+        Values { inner: self.iter() }
+    }
+
+    /// An iterator visiting all values mutably.
+    ///
+    /// The iteration order is arbitrary, but consistent across platforms for
+    /// the same crate version.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{CONTENT_LENGTH, HOST};
+    /// let mut map = HeaderMap::default();
+    ///
+    /// map.insert(HOST, "hello".to_string());
+    /// map.append(HOST, "goodbye".to_string());
+    /// map.insert(CONTENT_LENGTH, "123".to_string());
+    ///
+    /// for value in map.values_mut() {
+    ///     value.push_str("-boop");
+    /// }
+    /// ```
+    pub fn values_mut(&mut self) -> ValuesMut<T> {
+        ValuesMut { inner: self.iter_mut() }
+    }
+
+    /// Clears the map, returning all entries as an iterator.
+    ///
+    /// The internal memory is kept for reuse.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::{CONTENT_LENGTH, HOST};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// map.insert(HOST, "hello".parse().unwrap());
+    /// map.append(HOST, "goodbye".parse().unwrap());
+    /// map.insert(CONTENT_LENGTH, "123".parse().unwrap());
+    ///
+    /// let mut drain = map.drain();
+    ///
+    /// let (key, mut vals) = drain.next().unwrap();
+    ///
+    /// assert_eq!("host", key);
+    /// assert_eq!("hello", vals.next().unwrap());
+    /// assert_eq!("goodbye", vals.next().unwrap());
+    /// assert!(vals.next().is_none());
+    ///
+    /// let (key, mut vals) = drain.next().unwrap();
+    ///
+    /// assert_eq!("content-length", key);
+    /// assert_eq!("123", vals.next().unwrap());
+    /// assert!(vals.next().is_none());
+    /// ```
+    pub fn drain(&mut self) -> Drain<T> {
+        for i in &mut self.indices {
+            *i = Pos::none();
+        }
+
+        Drain {
+            idx: 0,
+            map: self as *mut _,
+            lt: PhantomData,
+        }
+    }
+
+    fn value_iter(&self, idx: Option<usize>) -> ValueIter<T> {
+        use self::Cursor::*;
+
+        if let Some(idx) = idx {
+            let back = {
+                let entry = &self.entries[idx];
+
+                entry.links
+                    .map(|l| Values(l.tail))
+                    .unwrap_or(Head)
+            };
+
+            ValueIter {
+                map: self,
+                index: idx,
+                front: Some(Head),
+                back: Some(back),
+            }
+        } else {
+            ValueIter {
+                map: self,
+                index: ::std::usize::MAX,
+                front: None,
+                back: None,
+            }
+        }
+    }
+
+    fn value_iter_mut(&mut self, idx: usize) -> ValueIterMut<T> {
+        use self::Cursor::*;
+
+        let back = {
+            let entry = &self.entries[idx];
+
+            entry.links
+                .map(|l| Values(l.tail))
+                .unwrap_or(Head)
+        };
+
+        ValueIterMut {
+            map: self as *mut _,
+            index: idx,
+            front: Some(Head),
+            back: Some(back),
+            lt: PhantomData,
+        }
+    }
+
+    /// Gets the given key's corresponding entry in the map for in-place
+    /// manipulation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// let mut map: HeaderMap<u32> = HeaderMap::default();
+    ///
+    /// let headers = &[
+    ///     "content-length",
+    ///     "x-hello",
+    ///     "Content-Length",
+    ///     "x-world",
+    /// ];
+    ///
+    /// for &header in headers {
+    ///     let counter = map.entry(header).unwrap().or_insert(0);
+    ///     *counter += 1;
+    /// }
+    ///
+    /// assert_eq!(map["content-length"], 2);
+    /// assert_eq!(map["x-hello"], 1);
+    /// ```
+    pub fn entry<K>(&mut self, key: K) -> Result<Entry<T>, InvalidHeaderName>
+        where K: AsHeaderName,
+    {
+        key.entry(self)
+    }
+
+    fn entry2<K>(&mut self, key: K) -> Entry<T>
+        where K: Hash + Into<HeaderName>,
+              HeaderName: PartialEq<K>,
+    {
+        // Ensure that there is space in the map
+        self.reserve_one();
+
+        insert_phase_one!(
+            self,
+            key,
+            probe,
+            pos,
+            hash,
+            danger,
+            Entry::Vacant(VacantEntry {
+                map: self,
+                hash: hash,
+                key: key.into(),
+                probe: probe,
+                danger: danger,
+            }),
+            Entry::Occupied(OccupiedEntry {
+                map: self,
+                index: pos,
+                probe: probe,
+            }),
+            Entry::Vacant(VacantEntry {
+                map: self,
+                hash: hash,
+                key: key.into(),
+                probe: probe,
+                danger: danger,
+            }))
+    }
+
+    /// Inserts a key-value pair into the map.
+    ///
+    /// If the map did not previously have this key present, then `None` is
+    /// returned.
+    ///
+    /// If the map did have this key present, the new value is associated with
+    /// the key and all previous values are removed. **Note** that only a single
+    /// one of the previous values is returned. If there are multiple values
+    /// that have been previously associated with the key, then the first one is
+    /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns
+    /// all values.
+    ///
+    /// The key is not updated, though; this matters for types that can be `==`
+    /// without being identical.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
+    /// assert!(!map.is_empty());
+    ///
+    /// let mut prev = map.insert(HOST, "earth".parse().unwrap()).unwrap();
+    /// assert_eq!("world", prev);
+    /// ```
+    pub fn insert<K>(&mut self, key: K, val: T) -> Option<T>
+        where K: IntoHeaderName,
+    {
+        key.insert(self, val)
+    }
+
+    #[inline]
+    fn insert2<K>(&mut self, key: K, value: T) -> Option<T>
+        where K: Hash + Into<HeaderName>,
+              HeaderName: PartialEq<K>,
+    {
+        self.reserve_one();
+
+        insert_phase_one!(
+            self, key, probe, pos, hash, danger,
+            // Vacant
+            {
+                drop(danger); // Make lint happy
+                let index = self.entries.len();
+                self.insert_entry(hash, key.into(), value);
+                self.indices[probe] = Pos::new(index, hash);
+                None
+            },
+            // Occupied
+            Some(self.insert_occupied(pos, value)),
+            // Robinhood
+            {
+                self.insert_phase_two(
+                    key.into(),
+                    value,
+                    hash,
+                    probe,
+                    danger);
+                None
+            })
+    }
+
+    /// Set an occupied bucket to the given value
+    #[inline]
+    fn insert_occupied(&mut self, index: usize, value: T) -> T {
+        if let Some(links) = self.entries[index].links {
+            self.remove_all_extra_values(links.next);
+        }
+
+        let entry = &mut self.entries[index];
+        mem::replace(&mut entry.value, value)
+    }
+
+    fn insert_occupied_mult(&mut self, index: usize, value: T) -> ValueDrain<T> {
+        let old;
+        let links;
+
+        {
+            let entry = &mut self.entries[index];
+
+            old = mem::replace(&mut entry.value, value);
+            links = entry.links.take();
+        }
+
+        ValueDrain {
+            map: self as *mut _,
+            first: Some(old),
+            next: links.map(|l| l.next),
+            lt: PhantomData,
+        }
+    }
+
+    /// Inserts a key-value pair into the map.
+    ///
+    /// If the map did not previously have this key present, then `false` is
+    /// returned.
+    ///
+    /// If the map did have this key present, the new value is pushed to the end
+    /// of the list of values currently associated with the key. The key is not
+    /// updated, though; this matters for types that can be `==` without being
+    /// identical.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none());
+    /// assert!(!map.is_empty());
+    ///
+    /// map.append(HOST, "earth".parse().unwrap());
+    ///
+    /// let values = map.get_all("host");
+    /// let mut i = values.iter();
+    /// assert_eq!("world", *i.next().unwrap());
+    /// assert_eq!("earth", *i.next().unwrap());
+    /// ```
+    pub fn append<K>(&mut self, key: K, value: T) -> bool
+        where K: IntoHeaderName,
+    {
+        key.append(self, value)
+    }
+
+    #[inline]
+    fn append2<K>(&mut self, key: K, value: T) -> bool
+        where K: Hash + Into<HeaderName>,
+              HeaderName: PartialEq<K>,
+    {
+        self.reserve_one();
+
+        insert_phase_one!(
+            self, key, probe, pos, hash, danger,
+            // Vacant
+            {
+                drop(danger);
+                let index = self.entries.len();
+                self.insert_entry(hash, key.into(), value);
+                self.indices[probe] = Pos::new(index, hash);
+                false
+            },
+            // Occupied
+            {
+                append_value(pos, &mut self.entries[pos], &mut self.extra_values, value);
+                true
+            },
+            // Robinhood
+            {
+                self.insert_phase_two(
+                    key.into(),
+                    value,
+                    hash,
+                    probe,
+                    danger);
+
+                false
+            })
+    }
+
+    #[inline]
+    fn find<K: ?Sized>(&self, key: &K) -> Option<(usize, usize)>
+        where K: Hash + Into<HeaderName>,
+              HeaderName: PartialEq<K>,
+    {
+        if self.entries.is_empty() {
+            return None;
+        }
+
+        let hash = hash_elem_using(&self.danger, key);
+        let mask = self.mask;
+        let mut probe = desired_pos(mask, hash);
+        let mut dist = 0;
+
+        probe_loop!(probe < self.indices.len(), {
+            if let Some((i, entry_hash)) = self.indices[probe].resolve() {
+                if dist > probe_distance(mask, entry_hash, probe) {
+                    // give up when probe distance is too long
+                    return None;
+                } else if entry_hash == hash && self.entries[i].key == *key {
+                    return Some((probe, i));
+                }
+            } else {
+                return None;
+            }
+
+            dist += 1;
+        });
+    }
+
+    /// phase 2 is post-insert where we forward-shift `Pos` in the indices.
+    ///
+    /// This phase only needs to happen if currently in hashed mode
+    #[inline]
+    fn insert_phase_two(&mut self,
+                        key: HeaderName,
+                        value: T,
+                        hash: HashValue,
+                        probe: usize,
+                        danger: bool) -> usize
+    {
+        // Push the value and get the index
+        let index = self.entries.len();
+        self.insert_entry(hash, key, value);
+
+        let num_displaced = do_insert_phase_two(
+            &mut self.indices,
+            probe,
+            Pos::new(index, hash));
+
+        if danger || num_displaced >= DISPLACEMENT_THRESHOLD {
+            // Increase danger level
+            self.danger.to_yellow();
+        }
+
+        index
+    }
+
+    /// Removes a key from the map, returning the value associated with the key.
+    ///
+    /// Returns `None` if the map does not contain the key. If there are
+    /// multiple values associated with the key, then the first one is returned.
+    /// See `remove_entry_mult` on `OccupiedEntry` for an API that yields all
+    /// values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    ///
+    /// let prev = map.remove(HOST).unwrap();
+    /// assert_eq!("hello.world", prev);
+    ///
+    /// assert!(map.remove(HOST).is_none());
+    /// ```
+    pub fn remove<K>(&mut self, key: K) -> Option<T>
+        where K: AsHeaderName
+    {
+        match key.find(self) {
+            Some((probe, idx)) => {
+                if let Some(links) = self.entries[idx].links {
+                    self.remove_all_extra_values(links.next);
+                }
+
+                let entry = self.remove_found(probe, idx);
+
+                Some(entry.value)
+            }
+            None => None,
+        }
+    }
+
+    /// Remove an entry from the map while in hashed mode
+    #[inline]
+    fn remove_found(&mut self, probe: usize, found: usize) -> Bucket<T> {
+        // index `probe` and entry `found` is to be removed
+        // use swap_remove, but then we need to update the index that points
+        // to the other entry that has to move
+        self.indices[probe] = Pos::none();
+        let entry = self.entries.swap_remove(found);
+
+        // correct index that points to the entry that had to swap places
+        if let Some(entry) = self.entries.get(found) {
+            // was not last element
+            // examine new element in `found` and find it in indices
+            let mut probe = desired_pos(self.mask, entry.hash);
+
+            probe_loop!(probe < self.indices.len(), {
+                if let Some((i, _)) = self.indices[probe].resolve() {
+                    if i >= self.entries.len() {
+                        // found it
+                        self.indices[probe] = Pos::new(found, entry.hash);
+                        break;
+                    }
+                }
+            });
+
+            // Update links
+            if let Some(links) = entry.links {
+                self.extra_values[links.next].prev = Link::Entry(found);
+                self.extra_values[links.tail].next = Link::Entry(found);
+            }
+        }
+
+        // backward shift deletion in self.indices
+        // after probe, shift all non-ideally placed indices backward
+        if self.entries.len() > 0 {
+            let mut last_probe = probe;
+            let mut probe = probe + 1;
+
+            probe_loop!(probe < self.indices.len(), {
+                if let Some((_, entry_hash)) = self.indices[probe].resolve() {
+                    if probe_distance(self.mask, entry_hash, probe) > 0 {
+                        self.indices[last_probe] = self.indices[probe];
+                        self.indices[probe] = Pos::none();
+                    } else {
+                        break;
+                    }
+                } else {
+                    break;
+                }
+
+                last_probe = probe;
+            });
+        }
+
+        entry
+    }
+
+    /// Removes the `ExtraValue` at the given index.
+    #[inline]
+    fn remove_extra_value(&mut self, idx: usize) -> ExtraValue<T> {
+        let prev;
+        let next;
+
+        {
+            debug_assert!(self.extra_values.len() > idx);
+            let extra = &self.extra_values[idx];
+            prev = extra.prev;
+            next = extra.next;
+        }
+
+        // First unlink the extra value
+        match (prev, next) {
+            (Link::Entry(prev), Link::Entry(next)) => {
+                debug_assert_eq!(prev, next);
+                debug_assert!(self.entries.len() > prev);
+
+                self.entries[prev].links = None;
+            }
+            (Link::Entry(prev), Link::Extra(next)) => {
+                debug_assert!(self.entries.len() > prev);
+                debug_assert!(self.entries[prev].links.is_some());
+
+                self.entries[prev].links.as_mut().unwrap()
+                    .next = next;
+
+                debug_assert!(self.extra_values.len() > next);
+                self.extra_values[next].prev = Link::Entry(prev);
+            }
+            (Link::Extra(prev), Link::Entry(next)) => {
+                debug_assert!(self.entries.len() > next);
+                debug_assert!(self.entries[next].links.is_some());
+
+                self.entries[next].links.as_mut().unwrap()
+                    .tail = prev;
+
+                debug_assert!(self.extra_values.len() > prev);
+                self.extra_values[prev].next = Link::Entry(next);
+            }
+            (Link::Extra(prev), Link::Extra(next)) => {
+                debug_assert!(self.extra_values.len() > next);
+                debug_assert!(self.extra_values.len() > prev);
+
+                self.extra_values[prev].next = Link::Extra(next);
+                self.extra_values[next].prev = Link::Extra(prev);
+            }
+        }
+
+        // Remove the extra value
+        let mut extra = self.extra_values.swap_remove(idx);
+
+        // This is the index of the value that was moved (possibly `extra`)
+        let old_idx = self.extra_values.len();
+
+        // Update the links
+        if extra.prev == Link::Extra(old_idx) {
+            extra.prev = Link::Extra(idx);
+        }
+
+        if extra.next == Link::Extra(old_idx) {
+            extra.next = Link::Extra(idx);
+        }
+
+        // Check if another entry was displaced. If it was, then the links
+        // need to be fixed.
+        if idx != old_idx {
+            let next;
+            let prev;
+
+            {
+                debug_assert!(self.extra_values.len() > idx);
+                let moved = &self.extra_values[idx];
+                next = moved.next;
+                prev = moved.prev;
+            }
+
+            // An entry was moved, we have to the links
+            match prev {
+                Link::Entry(entry_idx) => {
+                    // It is critical that we do not attempt to read the
+                    // header name or value as that memory may have been
+                    // "released" already.
+                    debug_assert!(self.entries.len() > entry_idx);
+                    debug_assert!(self.entries[entry_idx].links.is_some());
+
+                    let links = self.entries[entry_idx].links.as_mut().unwrap();
+                    links.next = idx;
+                }
+                Link::Extra(extra_idx) => {
+                    debug_assert!(self.extra_values.len() > extra_idx);
+                    self.extra_values[extra_idx].next = Link::Extra(idx);
+                }
+            }
+
+            match next {
+                Link::Entry(entry_idx) => {
+                    debug_assert!(self.entries.len() > entry_idx);
+                    debug_assert!(self.entries[entry_idx].links.is_some());
+
+                    let links = self.entries[entry_idx].links.as_mut().unwrap();
+                    links.tail = idx;
+                }
+                Link::Extra(extra_idx) => {
+                    debug_assert!(self.extra_values.len() > extra_idx);
+                    self.extra_values[extra_idx].prev = Link::Extra(idx);
+                }
+            }
+        }
+
+        debug_assert!({
+            for v in &self.extra_values {
+                assert!(v.next != Link::Extra(old_idx));
+                assert!(v.prev != Link::Extra(old_idx));
+            }
+
+            true
+        });
+
+        extra
+    }
+
+    fn remove_all_extra_values(&mut self, mut head: usize) {
+        loop {
+            let extra = self.remove_extra_value(head);
+
+            if let Link::Extra(idx) = extra.next {
+                head = idx;
+            } else {
+                break;
+            }
+        }
+    }
+
+    #[inline]
+    fn insert_entry(&mut self, hash: HashValue, key: HeaderName, value: T) {
+        assert!(self.entries.len() < MAX_SIZE, "header map at capacity");
+
+        self.entries.push(Bucket {
+            hash: hash,
+            key: key,
+            value: value,
+            links: None,
+        });
+    }
+
+    fn rebuild(&mut self) {
+        // Loop over all entries and re-insert them into the map
+        'outer:
+        for (index, entry) in self.entries.iter_mut().enumerate() {
+            let hash = hash_elem_using(&self.danger, &entry.key);
+            let mut probe = desired_pos(self.mask, hash);
+            let mut dist = 0;
+
+            // Update the entry's hash code
+            entry.hash = hash;
+
+            probe_loop!(probe < self.indices.len(), {
+                if let Some((_, entry_hash)) = self.indices[probe].resolve() {
+                    // if existing element probed less than us, swap
+                    let their_dist = probe_distance(self.mask, entry_hash, probe);
+
+                    if their_dist < dist {
+                        // Robinhood
+                        break;
+                    }
+                } else {
+                    // Vacant slot
+                    self.indices[probe] = Pos::new(index, hash);
+                    continue 'outer;
+                }
+
+                dist += 1;
+            });
+
+            do_insert_phase_two(
+                &mut self.indices,
+                probe,
+                Pos::new(index, hash));
+        }
+    }
+
+    fn reinsert_entry_in_order(&mut self, pos: Pos) {
+        if let Some((_, entry_hash)) = pos.resolve() {
+            // Find first empty bucket and insert there
+            let mut probe = desired_pos(self.mask, entry_hash);
+
+            probe_loop!(probe < self.indices.len(), {
+                if self.indices[probe].resolve().is_none() {
+                    // empty bucket, insert here
+                    self.indices[probe] = pos;
+                    return;
+                }
+            });
+        }
+    }
+
+    fn reserve_one(&mut self) {
+        let len = self.entries.len();
+
+        if self.danger.is_yellow() {
+            let load_factor = self.entries.len() as f32 / self.indices.len() as f32;
+
+            if load_factor >= LOAD_FACTOR_THRESHOLD {
+                // Transition back to green danger level
+                self.danger.to_green();
+
+                // Double the capacity
+                let new_cap = self.indices.len() * 2;
+
+                // Grow the capacity
+                self.grow(new_cap);
+            } else {
+                self.danger.to_red();
+
+                // Rebuild hash table
+                for index in &mut self.indices {
+                    *index = Pos::none();
+                }
+
+                self.rebuild();
+            }
+        } else if len == self.capacity() {
+            if len == 0 {
+                let new_raw_cap = 8;
+                self.mask = 8 - 1;
+                self.indices = vec![Pos::none(); new_raw_cap];
+                self.entries = Vec::with_capacity(usable_capacity(new_raw_cap));
+            } else {
+                let raw_cap = self.indices.len();
+                self.grow(raw_cap << 1);
+            }
+        }
+    }
+
+    #[inline]
+    fn grow(&mut self, new_raw_cap: usize) {
+        // This path can never be reached when handling the first allocation in
+        // the map.
+
+        // find first ideally placed element -- start of cluster
+        let mut first_ideal = 0;
+
+        for (i, pos) in self.indices.iter().enumerate() {
+            if let Some((_, entry_hash)) = pos.resolve() {
+                if 0 == probe_distance(self.mask, entry_hash, i) {
+                    first_ideal = i;
+                    break;
+                }
+            }
+        }
+
+        // visit the entries in an order where we can simply reinsert them
+        // into self.indices without any bucket stealing.
+        let old_indices = mem::replace(&mut self.indices, vec![Pos::none(); new_raw_cap]);
+        self.mask = new_raw_cap.wrapping_sub(1) as Size;
+
+        for &pos in &old_indices[first_ideal..] {
+            self.reinsert_entry_in_order(pos);
+        }
+
+        for &pos in &old_indices[..first_ideal] {
+            self.reinsert_entry_in_order(pos);
+        }
+
+        // Reserve additional entry slots
+        let more = self.capacity() - self.entries.len();
+        self.entries.reserve_exact(more);
+    }
+}
+
+impl<'a, T> IntoIterator for &'a HeaderMap<T> {
+    type Item = (&'a HeaderName, &'a T);
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Iter<'a, T> {
+        self.iter()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a mut HeaderMap<T> {
+    type Item = (&'a HeaderName, &'a mut T);
+    type IntoIter = IterMut<'a, T>;
+
+    fn into_iter(self) -> IterMut<'a, T> {
+        self.iter_mut()
+    }
+}
+
+impl<T> IntoIterator for HeaderMap<T> {
+    type Item = (Option<HeaderName>, T);
+    type IntoIter = IntoIter<T>;
+
+    /// Creates a consuming iterator, that is, one that moves keys and values
+    /// out of the map in arbitary order. The map cannot be used after calling
+    /// this.
+    ///
+    /// For each yielded item that has `None` provided for the `HeaderName`,
+    /// then the associated header name is the same as that of the previously
+    /// yielded item. The first yielded item will have `HeaderName` set.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage.
+    ///
+    /// ```
+    /// # use http::header;
+    /// # use http::header::*;
+    /// let mut map = HeaderMap::new();
+    /// map.insert(header::CONTENT_LENGTH, "123".parse().unwrap());
+    /// map.insert(header::CONTENT_TYPE, "json".parse().unwrap());
+    ///
+    /// let mut iter = map.into_iter();
+    /// assert_eq!(iter.next(), Some((Some(header::CONTENT_LENGTH), "123".parse().unwrap())));
+    /// assert_eq!(iter.next(), Some((Some(header::CONTENT_TYPE), "json".parse().unwrap())));
+    /// assert!(iter.next().is_none());
+    /// ```
+    ///
+    /// Multiple values per key.
+    ///
+    /// ```
+    /// # use http::header;
+    /// # use http::header::*;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// map.append(header::CONTENT_LENGTH, "123".parse().unwrap());
+    /// map.append(header::CONTENT_LENGTH, "456".parse().unwrap());
+    ///
+    /// map.append(header::CONTENT_TYPE, "json".parse().unwrap());
+    /// map.append(header::CONTENT_TYPE, "html".parse().unwrap());
+    /// map.append(header::CONTENT_TYPE, "xml".parse().unwrap());
+    ///
+    /// let mut iter = map.into_iter();
+    ///
+    /// assert_eq!(iter.next(), Some((Some(header::CONTENT_LENGTH), "123".parse().unwrap())));
+    /// assert_eq!(iter.next(), Some((None, "456".parse().unwrap())));
+    ///
+    /// assert_eq!(iter.next(), Some((Some(header::CONTENT_TYPE), "json".parse().unwrap())));
+    /// assert_eq!(iter.next(), Some((None, "html".parse().unwrap())));
+    /// assert_eq!(iter.next(), Some((None, "xml".parse().unwrap())));
+    /// assert!(iter.next().is_none());
+    /// ```
+    fn into_iter(self) -> IntoIter<T> {
+        IntoIter {
+            next: None,
+            entries: self.entries.into_iter(),
+            extra_values: self.extra_values,
+        }
+    }
+}
+
+impl<T> FromIterator<(HeaderName, T)> for HeaderMap<T>
+{
+    fn from_iter<I>(iter: I) -> Self
+        where I: IntoIterator<Item = (HeaderName, T)>
+    {
+       let mut map = HeaderMap::default();
+       map.extend(iter);
+       map
+    }
+}
+
+impl<T> Extend<(Option<HeaderName>, T)> for HeaderMap<T> {
+    /// Extend a `HeaderMap` with the contents of another `HeaderMap`.
+    ///
+    /// This function expects the yielded items to follow the same structure as
+    /// `IntoIter`.
+    ///
+    /// # Panics
+    ///
+    /// This panics if the first yielded item does not have a `HeaderName`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::*;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// map.insert(ACCEPT, "text/plain".parse().unwrap());
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    ///
+    /// let mut extra = HeaderMap::new();
+    ///
+    /// extra.insert(HOST, "foo.bar".parse().unwrap());
+    /// extra.insert(COOKIE, "hello".parse().unwrap());
+    /// extra.append(COOKIE, "world".parse().unwrap());
+    ///
+    /// map.extend(extra);
+    ///
+    /// assert_eq!(map["host"], "foo.bar");
+    /// assert_eq!(map["accept"], "text/plain");
+    /// assert_eq!(map["cookie"], "hello");
+    ///
+    /// let v = map.get_all("host");
+    /// assert_eq!(1, v.iter().count());
+    ///
+    /// let v = map.get_all("cookie");
+    /// assert_eq!(2, v.iter().count());
+    /// ```
+    fn extend<I: IntoIterator<Item = (Option<HeaderName>, T)>>(&mut self, iter: I) {
+        let mut iter = iter.into_iter();
+
+        // The structure of this is a bit weird, but it is mostly to make the
+        // borrow checker happy.
+        let (mut key, mut val) = match iter.next() {
+            Some((Some(key), val)) => (key, val),
+            Some((None, _)) => panic!("expected a header name, but got None"),
+            None => return,
+        };
+
+        'outer:
+        loop {
+            let mut entry = match self.entry(key).expect("HeaderName is always OK") {
+                Entry::Occupied(mut e) => {
+                    // Replace all previous values while maintaining a handle to
+                    // the entry.
+                    e.insert(val);
+                    e
+                }
+                Entry::Vacant(e) => {
+                    e.insert_entry(val)
+                }
+            };
+
+            // As long as `HeaderName` is none, keep inserting the value into
+            // the current entry
+            'inner:
+            loop {
+                match iter.next() {
+                    Some((Some(k), v)) => {
+                        key = k;
+                        val = v;
+                        continue 'outer;
+                    }
+                    Some((None, v)) => {
+                        entry.append(v);
+                    }
+                    None => {
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl<T> Extend<(HeaderName, T)> for HeaderMap<T>
+{
+    fn extend<I: IntoIterator<Item = (HeaderName, T)>>(&mut self, iter: I) {
+        // Keys may be already present or show multiple times in the iterator.
+        // Reserve the entire hint lower bound if the map is empty.
+        // Otherwise reserve half the hint (rounded up), so the map
+        // will only resize twice in the worst case.
+        let iter = iter.into_iter();
+
+        let reserve = if self.is_empty() {
+            iter.size_hint().0
+        } else {
+            (iter.size_hint().0 + 1) / 2
+        };
+
+        self.reserve(reserve);
+
+        for (k, v) in iter {
+            self.append(k, v);
+        }
+    }
+}
+
+impl<T: PartialEq> PartialEq for HeaderMap<T> {
+    fn eq(&self, other: &HeaderMap<T>) -> bool {
+        if self.len() != other.len() {
+            return false;
+        }
+
+        self.keys().all(|key| {
+            self.get_all(key) == other.get_all(key)
+        })
+    }
+}
+
+impl<T: Eq> Eq for HeaderMap<T> {}
+
+impl<T: fmt::Debug> fmt::Debug for HeaderMap<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_map().entries(self.iter()).finish()
+    }
+}
+
+impl<T> Default for HeaderMap<T> {
+    fn default() -> Self {
+        HeaderMap::with_capacity(0)
+    }
+}
+
+impl<'a, K, T> ops::Index<K> for HeaderMap<T>
+    where K: AsHeaderName,
+{
+    type Output = T;
+
+    #[inline]
+    fn index(&self, index: K) -> &T {
+        self.get(index).expect("no entry found for key")
+    }
+}
+
+/// phase 2 is post-insert where we forward-shift `Pos` in the indices.
+///
+/// returns the number of displaced elements
+#[inline]
+fn do_insert_phase_two(indices: &mut Vec<Pos>,
+          mut probe: usize,
+          mut old_pos: Pos)
+    -> usize
+{
+    let mut num_displaced = 0;
+
+    probe_loop!(probe < indices.len(), {
+        let pos = &mut indices[probe];
+
+        if pos.is_none() {
+            *pos = old_pos;
+            break;
+        } else {
+            num_displaced += 1;
+            old_pos = mem::replace(pos, old_pos);
+        }
+    });
+
+    num_displaced
+}
+
+#[inline]
+fn append_value<T>(entry_idx: usize,
+                   entry: &mut Bucket<T>,
+                   extra: &mut Vec<ExtraValue<T>>,
+                   value: T)
+{
+    match entry.links {
+        Some(links) => {
+            let idx = extra.len();
+            extra.push(ExtraValue {
+                value: value,
+                prev: Link::Extra(links.tail),
+                next: Link::Entry(entry_idx),
+            });
+
+            extra[links.tail].next = Link::Extra(idx);
+
+            entry.links = Some(Links {
+                tail: idx,
+                .. links
+            });
+        }
+        None => {
+            let idx = extra.len();
+            extra.push(ExtraValue {
+                value: value,
+                prev: Link::Entry(entry_idx),
+                next: Link::Entry(entry_idx),
+            });
+
+            entry.links = Some(Links {
+                next: idx,
+                tail: idx,
+            });
+        }
+    }
+}
+
+// ===== impl Iter =====
+
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = (&'a HeaderName, &'a T);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner.next_unsafe().map(|(key, ptr)| {
+            (key, unsafe { &*ptr })
+        })
+    }
+}
+
+unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {}
+unsafe impl<'a, T: Sync> Send for Iter<'a, T> {}
+
+// ===== impl IterMut =====
+
+impl<'a, T> IterMut<'a, T> {
+    fn next_unsafe(&mut self) -> Option<(&'a HeaderName, *mut T)> {
+        use self::Cursor::*;
+
+        if self.cursor.is_none() {
+            if (self.entry + 1) >= unsafe { &*self.map }.entries.len() {
+                return None;
+            }
+
+            self.entry += 1;
+            self.cursor = Some(Cursor::Head);
+        }
+
+        let entry = unsafe { &(*self.map).entries[self.entry] };
+
+        match self.cursor.unwrap() {
+            Head => {
+                self.cursor = entry.links.map(|l| Values(l.next));
+                Some((&entry.key, &entry.value as *const _ as *mut _))
+            }
+            Values(idx) => {
+                let extra = unsafe { &(*self.map).extra_values[idx] };
+
+                match extra.next {
+                    Link::Entry(_) => self.cursor = None,
+                    Link::Extra(i) => self.cursor = Some(Values(i)),
+                }
+
+                Some((&entry.key, &extra.value as *const _ as *mut _))
+            }
+        }
+    }
+}
+
+impl<'a, T> Iterator for IterMut<'a, T> {
+    type Item = (&'a HeaderName, &'a mut T);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.next_unsafe().map(|(key, ptr)| {
+            (key, unsafe { &mut *ptr })
+        })
+    }
+}
+
+unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {}
+unsafe impl<'a, T: Send> Send for IterMut<'a, T> {}
+
+// ===== impl Keys =====
+
+impl<'a, T> Iterator for Keys<'a, T> {
+    type Item = &'a HeaderName;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner.next().map(|b| &b.key)
+    }
+}
+
+// ===== impl Values ====
+
+impl<'a, T> Iterator for Values<'a, T> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner.next().map(|(_, v)| v)
+    }
+}
+
+// ===== impl ValuesMut ====
+
+impl<'a, T> Iterator for ValuesMut<'a, T> {
+    type Item = &'a mut T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner.next().map(|(_, v)| v)
+    }
+}
+
+// ===== impl Drain =====
+
+impl<'a, T> Iterator for Drain<'a, T> {
+    type Item = (HeaderName, ValueDrain<'a, T>);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let idx = self.idx;
+
+        if idx == unsafe { (*self.map).entries.len() } {
+            return None;
+        }
+
+        self.idx += 1;
+
+        let key;
+        let value;
+        let next;
+
+        unsafe {
+            let entry = &(*self.map).entries[idx];
+
+            // Read the header name
+            key = ptr::read(&entry.key as *const _);
+            value = ptr::read(&entry.value as *const _);
+            next = entry.links.map(|l| l.next);
+        };
+
+        let values = ValueDrain {
+            map: self.map,
+            first: Some(value),
+            next: next,
+            lt: PhantomData,
+        };
+
+        Some((key, values))
+    }
+}
+
+impl<'a, T> Drop for Drain<'a, T> {
+    fn drop(&mut self) {
+        unsafe {
+            let map = &mut *self.map;
+            debug_assert!(map.extra_values.is_empty());
+            map.entries.set_len(0);
+        }
+    }
+}
+
+unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
+unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
+
+// ===== impl Entry =====
+
+impl<'a, T> Entry<'a, T> {
+    /// Ensures a value is in the entry by inserting the default if empty.
+    ///
+    /// Returns a mutable reference to the **first** value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// let mut map: HeaderMap<u32> = HeaderMap::default();
+    ///
+    /// let headers = &[
+    ///     "content-length",
+    ///     "x-hello",
+    ///     "Content-Length",
+    ///     "x-world",
+    /// ];
+    ///
+    /// for &header in headers {
+    ///     let counter = map.entry(header)
+    ///         .expect("valid header names")
+    ///         .or_insert(0);
+    ///     *counter += 1;
+    /// }
+    ///
+    /// assert_eq!(map["content-length"], 2);
+    /// assert_eq!(map["x-hello"], 1);
+    /// ```
+    pub fn or_insert(self, default: T) -> &'a mut T {
+        use self::Entry::*;
+
+        match self {
+            Occupied(e) => e.into_mut(),
+            Vacant(e) => e.insert(default),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting the result of the default
+    /// function if empty.
+    ///
+    /// The default function is not called if the entry exists in the map.
+    /// Returns a mutable reference to the **first** value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage.
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// let res = map.entry("x-hello").unwrap()
+    ///     .or_insert_with(|| "world".parse().unwrap());
+    ///
+    /// assert_eq!(res, "world");
+    /// ```
+    ///
+    /// The default function is not called if the entry exists in the map.
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "world".parse().unwrap());
+    ///
+    /// let res = map.entry("host")
+    ///     .expect("host is a valid string")
+    ///     .or_insert_with(|| unreachable!());
+    ///
+    ///
+    /// assert_eq!(res, "world");
+    /// ```
+    pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
+        use self::Entry::*;
+
+        match self {
+            Occupied(e) => e.into_mut(),
+            Vacant(e) => e.insert(default()),
+        }
+    }
+
+    /// Returns a reference to the entry's key
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// assert_eq!(map.entry("x-hello").unwrap().key(), "x-hello");
+    /// ```
+    pub fn key(&self) -> &HeaderName {
+        use self::Entry::*;
+
+        match *self {
+            Vacant(ref e) => e.key(),
+            Occupied(ref e) => e.key(),
+        }
+    }
+}
+
+// ===== impl VacantEntry =====
+
+impl<'a, T> VacantEntry<'a, T> {
+    /// Returns a reference to the entry's key
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// assert_eq!(map.entry("x-hello").unwrap().key().as_str(), "x-hello");
+    /// ```
+    pub fn key(&self) -> &HeaderName {
+        &self.key
+    }
+
+    /// Take ownership of the key
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() {
+    ///     assert_eq!(v.into_key().as_str(), "x-hello");
+    /// }
+    /// ```
+    pub fn into_key(self) -> HeaderName {
+        self.key
+    }
+
+    /// Insert the value into the entry.
+    ///
+    /// The value will be associated with this entry's key. A mutable reference
+    /// to the inserted value will be returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry};
+    /// let mut map = HeaderMap::new();
+    ///
+    /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() {
+    ///     v.insert("world".parse().unwrap());
+    /// }
+    ///
+    /// assert_eq!(map["x-hello"], "world");
+    /// ```
+    pub fn insert(self, value: T) -> &'a mut T {
+        // Ensure that there is space in the map
+        let index = self.map.insert_phase_two(
+            self.key,
+            value.into(),
+            self.hash,
+            self.probe,
+            self.danger);
+
+        &mut self.map.entries[index].value
+    }
+
+    /// Insert the value into the entry.
+    ///
+    /// The value will be associated with this entry's key. The new
+    /// `OccupiedEntry` is returned, allowing for further manipulation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::*;
+    /// let mut map = HeaderMap::new();
+    ///
+    /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() {
+    ///     let mut e = v.insert_entry("world".parse().unwrap());
+    ///     e.insert("world2".parse().unwrap());
+    /// }
+    ///
+    /// assert_eq!(map["x-hello"], "world2");
+    /// ```
+    pub fn insert_entry(self, value: T) -> OccupiedEntry<'a, T> {
+        // Ensure that there is space in the map
+        let index = self.map.insert_phase_two(
+            self.key,
+            value.into(),
+            self.hash,
+            self.probe,
+            self.danger);
+
+        OccupiedEntry {
+            map: self.map,
+            index: index,
+            probe: self.probe,
+        }
+    }
+}
+
+
+// ===== impl GetAll =====
+
+impl<'a, T: 'a> GetAll<'a, T> {
+    /// Returns an iterator visiting all values associated with the entry.
+    ///
+    /// Values are iterated in insertion order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::HeaderMap;
+    /// # use http::header::HOST;
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    /// map.append(HOST, "hello.earth".parse().unwrap());
+    ///
+    /// let values = map.get_all("host");
+    /// let mut iter = values.iter();
+    /// assert_eq!(&"hello.world", iter.next().unwrap());
+    /// assert_eq!(&"hello.earth", iter.next().unwrap());
+    /// assert!(iter.next().is_none());
+    /// ```
+    pub fn iter(&self) -> ValueIter<'a, T> {
+        // This creates a new GetAll struct so that the lifetime
+        // isn't bound to &self.
+        GetAll {
+            map: self.map,
+            index: self.index,
+        }.into_iter()
+    }
+}
+
+impl<'a, T: PartialEq> PartialEq for GetAll<'a, T> {
+    fn eq(&self, other: &Self) -> bool {
+        self.iter().eq(other.iter())
+    }
+}
+
+impl<'a, T> IntoIterator for GetAll<'a, T> {
+    type Item = &'a T;
+    type IntoIter = ValueIter<'a, T>;
+
+    fn into_iter(self) -> ValueIter<'a, T> {
+        self.map.value_iter(self.index)
+    }
+}
+
+impl<'a, 'b: 'a, T> IntoIterator for &'b GetAll<'a, T> {
+    type Item = &'a T;
+    type IntoIter = ValueIter<'a, T>;
+
+    fn into_iter(self) -> ValueIter<'a, T> {
+        self.map.value_iter(self.index)
+    }
+}
+
+// ===== impl ValueIter =====
+
+impl<'a, T: 'a> Iterator for ValueIter<'a, T> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        use self::Cursor::*;
+
+
+        match self.front {
+            Some(Head) => {
+                let entry = &self.map.entries[self.index];
+
+                if self.back == Some(Head) {
+                    self.front = None;
+                    self.back = None;
+                } else {
+                    // Update the iterator state
+                    match entry.links {
+                        Some(links) => {
+                            self.front = Some(Values(links.next));
+                        }
+                        None => unreachable!(),
+                    }
+                }
+
+                Some(&entry.value)
+            }
+            Some(Values(idx)) => {
+                let extra = &self.map.extra_values[idx];
+
+                if self.front == self.back {
+                    self.front = None;
+                    self.back = None;
+                } else {
+                    match extra.next {
+                        Link::Entry(_) => self.front = None,
+                        Link::Extra(i) => self.front = Some(Values(i)),
+                    }
+                }
+
+                Some(&extra.value)
+            }
+            None => None,
+        }
+    }
+}
+
+impl<'a, T: 'a> DoubleEndedIterator for ValueIter<'a, T> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        use self::Cursor::*;
+
+
+        match self.back {
+            Some(Head) => {
+                self.front = None;
+                self.back = None;
+                Some(&self.map.entries[self.index].value)
+            }
+            Some(Values(idx)) => {
+                let extra = &self.map.extra_values[idx];
+
+                if self.front == self.back {
+                    self.front = None;
+                    self.back = None;
+                } else {
+                    match extra.prev {
+                        Link::Entry(_) => self.back = Some(Head),
+                        Link::Extra(idx) => self.back = Some(Values(idx)),
+                    }
+                }
+
+                Some(&extra.value)
+            }
+            None => None,
+        }
+    }
+}
+
+// ===== impl ValueIterMut =====
+
+impl<'a, T: 'a> Iterator for ValueIterMut<'a, T> {
+    type Item = &'a mut T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        use self::Cursor::*;
+
+        let entry = unsafe { &mut (*self.map).entries[self.index] };
+
+        match self.front {
+            Some(Head) => {
+                if self.back == Some(Head) {
+                    self.front = None;
+                    self.back = None;
+                } else {
+                    // Update the iterator state
+                    match entry.links {
+                        Some(links) => {
+                            self.front = Some(Values(links.next));
+                        }
+                        None => unreachable!(),
+                    }
+                }
+
+                Some(&mut entry.value)
+            }
+            Some(Values(idx)) => {
+                let extra = unsafe { &mut (*self.map).extra_values[idx] };
+
+                if self.front == self.back {
+                    self.front = None;
+                    self.back = None;
+                } else {
+                    match extra.next {
+                        Link::Entry(_) => self.front = None,
+                        Link::Extra(i) => self.front = Some(Values(i)),
+                    }
+                }
+
+                Some(&mut extra.value)
+            }
+            None => None,
+        }
+    }
+}
+
+impl<'a, T: 'a> DoubleEndedIterator for ValueIterMut<'a, T> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        use self::Cursor::*;
+
+        let entry = unsafe { &mut (*self.map).entries[self.index] };
+
+        match self.back {
+            Some(Head) => {
+                self.front = None;
+                self.back = None;
+                Some(&mut entry.value)
+            }
+            Some(Values(idx)) => {
+                let extra = unsafe { &mut (*self.map).extra_values[idx] };
+
+                if self.front == self.back {
+                    self.front = None;
+                    self.back = None;
+                } else {
+                    match extra.prev {
+                        Link::Entry(_) => self.back = Some(Head),
+                        Link::Extra(idx) => self.back = Some(Values(idx)),
+                    }
+                }
+
+                Some(&mut extra.value)
+            }
+            None => None,
+        }
+    }
+}
+
+unsafe impl<'a, T: Sync> Sync for ValueIterMut<'a, T> {}
+unsafe impl<'a, T: Send> Send for ValueIterMut<'a, T> {}
+
+// ===== impl IntoIter =====
+
+impl<T> Iterator for IntoIter<T> {
+    type Item = (Option<HeaderName>, T);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(next) = self.next {
+            self.next = match self.extra_values[next].next {
+                Link::Entry(_) => None,
+                Link::Extra(v) => Some(v),
+            };
+
+            let value = unsafe { ptr::read(&self.extra_values[next].value) };
+
+            return Some((None, value));
+        }
+
+        if let Some(bucket) = self.entries.next() {
+            self.next = bucket.links.map(|l| l.next);
+            let name = Some(bucket.key);
+            let value = bucket.value;
+
+            return Some((name, value));
+        }
+
+        None
+    }
+}
+
+impl<T> Drop for IntoIter<T> {
+    fn drop(&mut self) {
+        // Ensure the iterator is consumed
+        for _ in self.by_ref() { }
+
+        // All the values have already been yielded out.
+        unsafe { self.extra_values.set_len(0); }
+    }
+}
+
+// ===== impl OccupiedEntry =====
+
+impl<'a, T> OccupiedEntry<'a, T> {
+    /// Returns a reference to the entry's key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "world".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(e) = map.entry("host").unwrap() {
+    ///     assert_eq!("host", e.key());
+    /// }
+    /// ```
+    pub fn key(&self) -> &HeaderName {
+        &self.map.entries[self.index].key
+    }
+
+    /// Get a reference to the first value in the entry.
+    ///
+    /// Values are stored in insertion order.
+    ///
+    /// # Panics
+    ///
+    /// `get` panics if there are no values associated with the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() {
+    ///     assert_eq!(e.get(), &"hello.world");
+    ///
+    ///     e.append("hello.earth".parse().unwrap());
+    ///
+    ///     assert_eq!(e.get(), &"hello.world");
+    /// }
+    /// ```
+    pub fn get(&self) -> &T {
+        &self.map.entries[self.index].value
+    }
+
+    /// Get a mutable reference to the first value in the entry.
+    ///
+    /// Values are stored in insertion order.
+    ///
+    /// # Panics
+    ///
+    /// `get_mut` panics if there are no values associated with the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::default();
+    /// map.insert(HOST, "hello.world".to_string());
+    ///
+    /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() {
+    ///     e.get_mut().push_str("-2");
+    ///     assert_eq!(e.get(), &"hello.world-2");
+    /// }
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.map.entries[self.index].value
+    }
+
+    /// Converts the `OccupiedEntry` into a mutable reference to the **first**
+    /// value.
+    ///
+    /// The lifetime of the returned reference is bound to the original map.
+    ///
+    /// # Panics
+    ///
+    /// `into_mut` panics if there are no values associated with the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::default();
+    /// map.insert(HOST, "hello.world".to_string());
+    /// map.append(HOST, "hello.earth".to_string());
+    ///
+    /// if let Entry::Occupied(e) = map.entry("host").unwrap() {
+    ///     e.into_mut().push_str("-2");
+    /// }
+    ///
+    /// assert_eq!("hello.world-2", map["host"]);
+    /// ```
+    pub fn into_mut(self) -> &'a mut T {
+        &mut self.map.entries[self.index].value
+    }
+
+    /// Sets the value of the entry.
+    ///
+    /// All previous values associated with the entry are removed and the first
+    /// one is returned. See `insert_mult` for an API that returns all values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "hello.world".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() {
+    ///     let mut prev = e.insert("earth".parse().unwrap());
+    ///     assert_eq!("hello.world", prev);
+    /// }
+    ///
+    /// assert_eq!("earth", map["host"]);
+    /// ```
+    pub fn insert(&mut self, value: T) -> T {
+        self.map.insert_occupied(self.index, value.into())
+    }
+
+    /// Sets the value of the entry.
+    ///
+    /// This function does the same as `insert` except it returns an iterator
+    /// that yields all values previously associated with the key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "world".parse().unwrap());
+    /// map.append(HOST, "world2".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() {
+    ///     let mut prev = e.insert_mult("earth".parse().unwrap());
+    ///     assert_eq!("world", prev.next().unwrap());
+    ///     assert_eq!("world2", prev.next().unwrap());
+    ///     assert!(prev.next().is_none());
+    /// }
+    ///
+    /// assert_eq!("earth", map["host"]);
+    /// ```
+    pub fn insert_mult(&mut self, value: T) -> ValueDrain<T> {
+        self.map.insert_occupied_mult(self.index, value.into())
+    }
+
+    /// Insert the value into the entry.
+    ///
+    /// The new value is appended to the end of the entry's value list. All
+    /// previous values associated with the entry are retained.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "world".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() {
+    ///     e.append("earth".parse().unwrap());
+    /// }
+    ///
+    /// let values = map.get_all("host");
+    /// let mut i = values.iter();
+    /// assert_eq!("world", *i.next().unwrap());
+    /// assert_eq!("earth", *i.next().unwrap());
+    /// ```
+    pub fn append(&mut self, value: T) {
+        let idx = self.index;
+        let entry = &mut self.map.entries[idx];
+        append_value(idx, entry, &mut self.map.extra_values, value.into());
+    }
+
+    /// Remove the entry from the map.
+    ///
+    /// All values associated with the entry are removed and the first one is
+    /// returned. See `remove_entry_mult` for an API that returns all values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "world".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(e) = map.entry("host").unwrap() {
+    ///     let mut prev = e.remove();
+    ///     assert_eq!("world", prev);
+    /// }
+    ///
+    /// assert!(!map.contains_key("host"));
+    /// ```
+    pub fn remove(self) -> T {
+        self.remove_entry().1
+    }
+
+    /// Remove the entry from the map.
+    ///
+    /// The key and all values associated with the entry are removed and the
+    /// first one is returned. See `remove_entry_mult` for an API that returns
+    /// all values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "world".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(e) = map.entry("host").unwrap() {
+    ///     let (key, mut prev) = e.remove_entry();
+    ///     assert_eq!("host", key.as_str());
+    ///     assert_eq!("world", prev);
+    /// }
+    ///
+    /// assert!(!map.contains_key("host"));
+    /// ```
+    pub fn remove_entry(self) -> (HeaderName, T) {
+        let entry = self.map.remove_found(self.probe, self.index);
+
+        if let Some(links) = entry.links {
+            self.map.remove_all_extra_values(links.next);
+        }
+
+        (entry.key, entry.value)
+    }
+
+    /// Remove the entry from the map.
+    ///
+    /// The key and all values associated with the entry are removed and
+    /// returned.
+    pub fn remove_entry_mult(self) -> (HeaderName, ValueDrain<'a, T>) {
+        let entry = self.map.remove_found(self.probe, self.index);
+        let drain = ValueDrain {
+            map: self.map as *mut _,
+            first: Some(entry.value),
+            next: entry.links.map(|l| l.next),
+            lt: PhantomData,
+        };
+        (entry.key, drain)
+    }
+
+    /// Returns an iterator visiting all values associated with the entry.
+    ///
+    /// Values are iterated in insertion order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::new();
+    /// map.insert(HOST, "world".parse().unwrap());
+    /// map.append(HOST, "earth".parse().unwrap());
+    ///
+    /// if let Entry::Occupied(e) = map.entry("host").unwrap() {
+    ///     let mut iter = e.iter();
+    ///     assert_eq!(&"world", iter.next().unwrap());
+    ///     assert_eq!(&"earth", iter.next().unwrap());
+    ///     assert!(iter.next().is_none());
+    /// }
+    /// ```
+    pub fn iter(&self) -> ValueIter<T> {
+        self.map.value_iter(Some(self.index))
+    }
+
+    /// Returns an iterator mutably visiting all values associated with the
+    /// entry.
+    ///
+    /// Values are iterated in insertion order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderMap, Entry, HOST};
+    /// let mut map = HeaderMap::default();
+    /// map.insert(HOST, "world".to_string());
+    /// map.append(HOST, "earth".to_string());
+    ///
+    /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() {
+    ///     for e in e.iter_mut() {
+    ///         e.push_str("-boop");
+    ///     }
+    /// }
+    ///
+    /// let mut values = map.get_all("host");
+    /// let mut i = values.iter();
+    /// assert_eq!(&"world-boop", i.next().unwrap());
+    /// assert_eq!(&"earth-boop", i.next().unwrap());
+    /// ```
+    pub fn iter_mut(&mut self) -> ValueIterMut<T> {
+        self.map.value_iter_mut(self.index)
+    }
+}
+
+impl<'a, T> IntoIterator for OccupiedEntry<'a, T> {
+    type Item = &'a mut T;
+    type IntoIter = ValueIterMut<'a, T>;
+
+    fn into_iter(self) -> ValueIterMut<'a, T> {
+        self.map.value_iter_mut(self.index)
+    }
+}
+
+impl<'a, 'b: 'a, T> IntoIterator for &'b OccupiedEntry<'a, T> {
+    type Item = &'a T;
+    type IntoIter = ValueIter<'a, T>;
+
+    fn into_iter(self) -> ValueIter<'a, T> {
+        self.iter()
+    }
+}
+
+impl<'a, 'b: 'a, T> IntoIterator for &'b mut OccupiedEntry<'a, T> {
+    type Item = &'a mut T;
+    type IntoIter = ValueIterMut<'a, T>;
+
+    fn into_iter(self) -> ValueIterMut<'a, T> {
+        self.iter_mut()
+    }
+}
+
+// ===== impl ValueDrain =====
+
+impl<'a, T> Iterator for ValueDrain<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        if self.first.is_some() {
+            self.first.take()
+        } else if let Some(next) = self.next {
+            // Remove the extra value
+            let extra = unsafe { &mut (*self.map) }.remove_extra_value(next);
+
+            match extra.next {
+                Link::Extra(idx) => self.next = Some(idx),
+                Link::Entry(_) => self.next = None,
+            }
+
+            Some(extra.value)
+        } else {
+            None
+        }
+    }
+}
+
+impl<'a, T> Drop for ValueDrain<'a, T> {
+    fn drop(&mut self) {
+        while let Some(_) = self.next() {
+        }
+    }
+}
+
+unsafe impl<'a, T: Sync> Sync for ValueDrain<'a, T> {}
+unsafe impl<'a, T: Send> Send for ValueDrain<'a, T> {}
+
+// ===== impl Pos =====
+
+impl Pos {
+    #[inline]
+    fn new(index: usize, hash: HashValue) -> Self {
+        Pos {
+            index: index as Size,
+            hash: hash,
+        }
+    }
+
+    #[inline]
+    fn none() -> Self {
+        Pos {
+            index: !0,
+            hash: HashValue(0),
+        }
+    }
+
+    #[inline]
+    fn is_some(&self) -> bool {
+        !self.is_none()
+    }
+
+    #[inline]
+    fn is_none(&self) -> bool {
+        self.index == !0
+    }
+
+    #[inline]
+    fn resolve(&self) -> Option<(usize, HashValue)> {
+        if self.is_some() {
+            Some((self.index, self.hash))
+        } else {
+            None
+        }
+    }
+}
+
+impl Danger {
+    fn is_red(&self) -> bool {
+        match *self {
+            Danger::Red(_) => true,
+            _ => false,
+        }
+    }
+
+    fn to_red(&mut self) {
+        debug_assert!(self.is_yellow());
+        *self = Danger::Red(RandomState::new());
+    }
+
+    fn is_yellow(&self) -> bool {
+        match *self {
+            Danger::Yellow => true,
+            _ => false,
+        }
+    }
+
+    fn to_yellow(&mut self) {
+        match *self {
+            Danger::Green => {
+                *self = Danger::Yellow;
+            }
+            _ => {}
+        }
+    }
+
+    fn to_green(&mut self) {
+        debug_assert!(self.is_yellow());
+        *self = Danger::Green;
+    }
+}
+
+// ===== impl Utils =====
+
+#[inline]
+fn usable_capacity(cap: usize) -> usize {
+    cap - cap / 4
+}
+
+#[inline]
+fn to_raw_capacity(n: usize) -> usize {
+    n + n / 3
+}
+
+#[inline]
+fn desired_pos(mask: Size, hash: HashValue) -> usize {
+    (hash.0 & mask)
+}
+
+/// The number of steps that `current` is forward of the desired position for hash
+#[inline]
+fn probe_distance(mask: Size, hash: HashValue, current: usize) -> usize {
+    current.wrapping_sub(desired_pos(mask, hash)) & mask
+}
+
+fn hash_elem_using<K: ?Sized>(danger: &Danger, k: &K) -> HashValue
+    where K: Hash
+{
+    use fnv::FnvHasher;
+
+    const MASK: u64 = (MAX_SIZE as u64) - 1;
+
+    let hash = match *danger {
+        // Safe hash
+        Danger::Red(ref hasher) => {
+            let mut h = hasher.build_hasher();
+            k.hash(&mut h);
+            h.finish()
+        }
+        // Fast hash
+        _ => {
+            let mut h = FnvHasher::default();
+            k.hash(&mut h);
+            h.finish()
+        }
+    };
+
+    HashValue((hash & MASK) as usize)
+}
+
+/*
+ *
+ * ===== impl IntoHeaderName / AsHeaderName =====
+ *
+ */
+
+
+mod into_header_name {
+    use super::{HdrName, HeaderMap, HeaderName};
+
+    /// A marker trait used to identify values that can be used as insert keys
+    /// to a `HeaderMap`.
+    pub trait IntoHeaderName: Sealed {}
+
+    // All methods are on this pub(super) trait, instead of `IntoHeaderName`,
+    // so that they aren't publicly exposed to the world.
+    //
+    // Being on the `IntoHeaderName` trait would mean users could call
+    // `"host".insert(&mut map, "localhost")`.
+    //
+    // Ultimately, this allows us to adjust the signatures of these methods
+    // without breaking any external crate.
+    pub trait Sealed {
+        #[doc(hidden)]
+        fn insert<T>(self, map: &mut HeaderMap<T>, val: T) -> Option<T>;
+
+        #[doc(hidden)]
+        fn append<T>(self, map: &mut HeaderMap<T>, val: T) -> bool;
+    }
+
+    // ==== impls ====
+
+    impl Sealed for HeaderName {
+        #[doc(hidden)]
+        #[inline]
+        fn insert<T>(self, map: &mut HeaderMap<T>, val: T) -> Option<T> {
+            map.insert2(self, val)
+        }
+
+        #[doc(hidden)]
+        #[inline]
+        fn append<T>(self, map: &mut HeaderMap<T>, val: T) -> bool {
+            map.append2(self, val)
+        }
+    }
+
+    impl IntoHeaderName for HeaderName {}
+
+    impl<'a> Sealed for &'a HeaderName {
+        #[doc(hidden)]
+        #[inline]
+        fn insert<T>(self, map: &mut HeaderMap<T>, val: T) -> Option<T> {
+            map.insert2(self, val)
+        }
+        #[doc(hidden)]
+        #[inline]
+        fn append<T>(self, map: &mut HeaderMap<T>, val: T) -> bool {
+            map.append2(self, val)
+        }
+    }
+
+    impl<'a> IntoHeaderName for &'a HeaderName {}
+
+    impl Sealed for &'static str {
+        #[doc(hidden)]
+        #[inline]
+        fn insert<T>(self, map: &mut HeaderMap<T>, val: T) -> Option<T> {
+            HdrName::from_static(self, move |hdr| map.insert2(hdr, val))
+        }
+        #[doc(hidden)]
+        #[inline]
+        fn append<T>(self, map: &mut HeaderMap<T>, val: T) -> bool {
+            HdrName::from_static(self, move |hdr| map.append2(hdr, val))
+        }
+    }
+
+    impl IntoHeaderName for &'static str {}
+}
+
+mod as_header_name {
+    use std::prelude::v1::*;
+    use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName};
+
+    /// A marker trait used to identify values that can be used as search keys
+    /// to a `HeaderMap`.
+    pub trait AsHeaderName: Sealed {}
+
+    // All methods are on this pub(super) trait, instead of `AsHeaderName`,
+    // so that they aren't publicly exposed to the world.
+    //
+    // Being on the `AsHeaderName` trait would mean users could call
+    // `"host".find(&map)`.
+    //
+    // Ultimately, this allows us to adjust the signatures of these methods
+    // without breaking any external crate.
+    pub trait Sealed {
+        #[doc(hidden)]
+        fn entry<T>(self, map: &mut HeaderMap<T>) -> Result<Entry<T>, InvalidHeaderName>;
+
+        #[doc(hidden)]
+        fn find<T>(&self, map: &HeaderMap<T>) -> Option<(usize, usize)>;
+    }
+
+    // ==== impls ====
+
+    impl Sealed for HeaderName {
+        #[doc(hidden)]
+        #[inline]
+        fn entry<T>(self, map: &mut HeaderMap<T>) -> Result<Entry<T>, InvalidHeaderName> {
+            Ok(map.entry2(self))
+        }
+
+        #[doc(hidden)]
+        #[inline]
+        fn find<T>(&self, map: &HeaderMap<T>) -> Option<(usize, usize)> {
+            map.find(self)
+        }
+    }
+
+    impl AsHeaderName for HeaderName {}
+
+    impl<'a> Sealed for &'a HeaderName {
+        #[doc(hidden)]
+        #[inline]
+        fn entry<T>(self, map: &mut HeaderMap<T>) -> Result<Entry<T>, InvalidHeaderName> {
+            Ok(map.entry2(self))
+        }
+
+        #[doc(hidden)]
+        #[inline]
+        fn find<T>(&self, map: &HeaderMap<T>) -> Option<(usize, usize)> {
+            map.find(*self)
+        }
+    }
+
+    impl<'a> AsHeaderName for &'a HeaderName {}
+
+    impl<'a> Sealed for &'a str {
+        #[doc(hidden)]
+        #[inline]
+        fn entry<T>(self, map: &mut HeaderMap<T>) -> Result<Entry<T>, InvalidHeaderName> {
+            HdrName::from_bytes(self.as_bytes(), move |hdr| map.entry2(hdr))
+        }
+
+        #[doc(hidden)]
+        #[inline]
+        fn find<T>(&self, map: &HeaderMap<T>) -> Option<(usize, usize)> {
+            HdrName::from_bytes(self.as_bytes(), move |hdr| map.find(&hdr)).unwrap_or(None)
+        }
+    }
+
+    impl<'a> AsHeaderName for &'a str {}
+
+    impl Sealed for String {
+        #[doc(hidden)]
+        #[inline]
+        fn entry<T>(self, map: &mut HeaderMap<T>) -> Result<Entry<T>, InvalidHeaderName> {
+            self.as_str().entry(map)
+        }
+
+        #[doc(hidden)]
+        #[inline]
+        fn find<T>(&self, map: &HeaderMap<T>) -> Option<(usize, usize)> {
+            Sealed::find(&self.as_str(), map)
+        }
+    }
+
+    impl AsHeaderName for String {}
+
+    impl<'a> Sealed for &'a String {
+        #[doc(hidden)]
+        #[inline]
+        fn entry<T>(self, map: &mut HeaderMap<T>) -> Result<Entry<T>, InvalidHeaderName> {
+            self.as_str().entry(map)
+        }
+
+        #[doc(hidden)]
+        #[inline]
+        fn find<T>(&self, map: &HeaderMap<T>) -> Option<(usize, usize)> {
+            Sealed::find(*self, map)
+        }
+    }
+
+    impl<'a> AsHeaderName for &'a String {}
+}
+
+
+#[test]
+fn test_bounds() {
+    fn check_bounds<T: Send + Send>() {}
+
+    check_bounds::<HeaderMap<()>>();
+    check_bounds::<Iter<'static, ()>>();
+    check_bounds::<IterMut<'static, ()>>();
+    check_bounds::<Keys<'static, ()>>();
+    check_bounds::<Values<'static, ()>>();
+    check_bounds::<ValuesMut<'static, ()>>();
+    check_bounds::<Drain<'static, ()>>();
+    check_bounds::<GetAll<'static, ()>>();
+    check_bounds::<Entry<'static, ()>>();
+    check_bounds::<VacantEntry<'static, ()>>();
+    check_bounds::<OccupiedEntry<'static, ()>>();
+    check_bounds::<ValueIter<'static, ()>>();
+    check_bounds::<ValueIterMut<'static, ()>>();
+    check_bounds::<ValueDrain<'static, ()>>();
+}
+
+#[test]
+fn skip_duplicates_during_key_iteration() {
+    let mut map = HeaderMap::new();
+    map.append("a", HeaderValue::from_static("a"));
+    map.append("a", HeaderValue::from_static("b"));
+    assert_eq!(map.keys().count(), map.keys_len());
+}
diff --git a/third_party/http/src/header/mod.rs b/third_party/http/src/header/mod.rs
new file mode 100644
index 0000000..ee80fc7
--- /dev/null
+++ b/third_party/http/src/header/mod.rs
@@ -0,0 +1,194 @@
+//! HTTP header types
+//!
+//! The module provides [`HeaderName`], [`HeaderMap`], and a number of types
+//! used for interacting with `HeaderMap`. These types allow representing both
+//! HTTP/1 and HTTP/2 headers.
+//!
+//! # `HeaderName`
+//!
+//! The `HeaderName` type represents both standard header names as well as
+//! custom header names. The type handles the case insensitive nature of header
+//! names and is used as the key portion of `HeaderMap`. Header names are
+//! normalized to lower case. In other words, when creating a `HeaderName` with
+//! a string, even if upper case characters are included, when getting a string
+//! representation of the `HeaderName`, it will be all lower case. This allows
+//! for faster `HeaderMap` comparison operations.
+//!
+//! The internal representation is optimized to efficiently handle the cases
+//! most commonly encountered when working with HTTP. Standard header names are
+//! special cased and are represented internally as an enum. Short custom
+//! headers will be stored directly in the `HeaderName` struct and will not
+//! incur any allocation overhead, however longer strings will require an
+//! allocation for storage.
+//!
+//! ## Limitations
+//!
+//! `HeaderName` has a max length of 32,768 for header names. Attempting to
+//! parse longer names will result in a panic.
+//!
+//! # `HeaderMap`
+//!
+//! `HeaderMap` is a map structure of header names highly optimized for use
+//! cases common with HTTP. It is a [multimap] structure, where each header name
+//! may have multiple associated header values. Given this, some of the APIs
+//! diverge from [`HashMap`].
+//!
+//! ## Overview
+//!
+//! Just like `HashMap` in Rust's stdlib, `HeaderMap` is based on [Robin Hood
+//! hashing]. This algorithm tends to reduce the worst case search times in the
+//! table and enables high load factors without seriously affecting performance.
+//! Internally, keys and values are stored in vectors. As such, each insertion
+//! will not incur allocation overhead. However, once the underlying vector
+//! storage is full, a larger vector must be allocated and all values copied.
+//!
+//! ## Deterministic ordering
+//!
+//! Unlike Rust's `HashMap`, values in `HeaderMap` are deterministically
+//! ordered. Roughly, values are ordered by insertion. This means that a
+//! function that deterministically operates on a header map can rely on the
+//! iteration order to remain consistent across processes and platforms.
+//!
+//! ## Adaptive hashing
+//!
+//! `HeaderMap` uses an adaptive hashing strategy in order to efficiently handle
+//! most common cases. All standard headers have statically computed hash values
+//! which removes the need to perform any hashing of these headers at runtime.
+//! The default hash function emphasizes performance over robustness. However,
+//! `HeaderMap` detects high collision rates and switches to a secure hash
+//! function in those events. The threshold is set such that only denial of
+//! service attacks should trigger it.
+//!
+//! ## Limitations
+//!
+//! `HeaderMap` can store a maximum of 32,768 headers (header name / value
+//! pairs). Attempting to insert more will result in a panic.
+//!
+//! [`HeaderName`]: struct.HeaderName.html
+//! [`HeaderMap`]: struct.HeaderMap.html
+//! [multimap]: https://en.wikipedia.org/wiki/Multimap
+//! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html
+//! [Robin Hood hashing]: https://en.wikipedia.org/wiki/Hash_table#Robin_Hood_hashing
+
+mod map;
+mod name;
+mod value;
+
+pub use self::map::{
+    HeaderMap,
+    AsHeaderName,
+    IntoHeaderName,
+    Iter,
+    Keys,
+    Values,
+    Drain,
+    GetAll,
+    Entry,
+    VacantEntry,
+    OccupiedEntry,
+    ValueIter,
+    ValueIterMut,
+    ValueDrain,
+    IntoIter,
+};
+pub use self::name::{
+    HeaderName,
+    InvalidHeaderName,
+    InvalidHeaderNameBytes,
+};
+pub use self::value::{
+    HeaderValue,
+    InvalidHeaderValue,
+    InvalidHeaderValueBytes,
+    ToStrError,
+};
+
+// Use header name constants
+pub use self::name::{
+    ACCEPT,
+    ACCEPT_CHARSET,
+    ACCEPT_ENCODING,
+    ACCEPT_LANGUAGE,
+    ACCEPT_RANGES,
+    ACCESS_CONTROL_ALLOW_CREDENTIALS,
+    ACCESS_CONTROL_ALLOW_HEADERS,
+    ACCESS_CONTROL_ALLOW_METHODS,
+    ACCESS_CONTROL_ALLOW_ORIGIN,
+    ACCESS_CONTROL_EXPOSE_HEADERS,
+    ACCESS_CONTROL_MAX_AGE,
+    ACCESS_CONTROL_REQUEST_HEADERS,
+    ACCESS_CONTROL_REQUEST_METHOD,
+    AGE,
+    ALLOW,
+    ALT_SVC,
+    AUTHORIZATION,
+    CACHE_CONTROL,
+    CONNECTION,
+    CONTENT_DISPOSITION,
+    CONTENT_ENCODING,
+    CONTENT_LANGUAGE,
+    CONTENT_LENGTH,
+    CONTENT_LOCATION,
+    CONTENT_RANGE,
+    CONTENT_SECURITY_POLICY,
+    CONTENT_SECURITY_POLICY_REPORT_ONLY,
+    CONTENT_TYPE,
+    COOKIE,
+    DNT,
+    DATE,
+    ETAG,
+    EXPECT,
+    EXPIRES,
+    FORWARDED,
+    FROM,
+    HOST,
+    IF_MATCH,
+    IF_MODIFIED_SINCE,
+    IF_NONE_MATCH,
+    IF_RANGE,
+    IF_UNMODIFIED_SINCE,
+    LAST_MODIFIED,
+    LINK,
+    LOCATION,
+    MAX_FORWARDS,
+    ORIGIN,
+    PRAGMA,
+    PROXY_AUTHENTICATE,
+    PROXY_AUTHORIZATION,
+    PUBLIC_KEY_PINS,
+    PUBLIC_KEY_PINS_REPORT_ONLY,
+    RANGE,
+    REFERER,
+    REFERRER_POLICY,
+    REFRESH,
+    RETRY_AFTER,
+    SEC_WEBSOCKET_ACCEPT,
+    SEC_WEBSOCKET_EXTENSIONS,
+    SEC_WEBSOCKET_KEY,
+    SEC_WEBSOCKET_PROTOCOL,
+    SEC_WEBSOCKET_VERSION,
+    SERVER,
+    SET_COOKIE,
+    STRICT_TRANSPORT_SECURITY,
+    TE,
+    TRAILER,
+    TRANSFER_ENCODING,
+    UPGRADE,
+    UPGRADE_INSECURE_REQUESTS,
+    USER_AGENT,
+    VARY,
+    VIA,
+    WARNING,
+    WWW_AUTHENTICATE,
+    X_CONTENT_TYPE_OPTIONS,
+    X_DNS_PREFETCH_CONTROL,
+    X_FRAME_OPTIONS,
+    X_XSS_PROTECTION,
+};
+
+/// Maximum length of a header name
+///
+/// Generally, 64kb for a header name is WAY too much than would ever be needed
+/// in practice. Restricting it to this size enables using `u16` values to
+/// represent offsets when dealing with header names.
+const MAX_HEADER_NAME_LEN: usize = 1 << 16;
diff --git a/third_party/http/src/header/name.rs b/third_party/http/src/header/name.rs
new file mode 100644
index 0000000..75e93be
--- /dev/null
+++ b/third_party/http/src/header/name.rs
@@ -0,0 +1,2179 @@
+use HttpTryFrom;
+use byte_str::ByteStr;
+use bytes::{Bytes, BytesMut};
+
+use std::{fmt, mem};
+use std::borrow::Borrow;
+use std::hash::{Hash, Hasher};
+use std::str::FromStr;
+use std::error::Error;
+
+/// Represents an HTTP header field name
+///
+/// Header field names identify the header. Header sets may include multiple
+/// headers with the same name. The HTTP specification defines a number of
+/// standard headers, but HTTP messages may include non-standard header names as
+/// well as long as they adhere to the specification.
+///
+/// `HeaderName` is used as the [`HeaderMap`] key. Constants are available for
+/// all standard header names in the [`header`] module.
+///
+/// # Representation
+///
+/// `HeaderName` represents standard header names using an `enum`, as such they
+/// will not require an allocation for storage. All custom header names are
+/// lower cased upon conversion to a `HeaderName` value. This avoids the
+/// overhead of dynamically doing lower case conversion during the hash code
+/// computation and the comparison operation.
+///
+/// [`HeaderMap`]: struct.HeaderMap.html
+/// [`header`]: index.html
+#[derive(Clone, Eq, PartialEq, Hash)]
+pub struct HeaderName {
+    inner: Repr<Custom>,
+}
+
+// Almost a full `HeaderName`
+#[derive(Debug, Hash)]
+pub struct HdrName<'a> {
+    inner: Repr<MaybeLower<'a>>,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+enum Repr<T> {
+    Standard(StandardHeader),
+    Custom(T),
+}
+
+// Used to hijack the Hash impl
+#[derive(Debug, Clone, Eq, PartialEq)]
+struct Custom(ByteStr);
+
+#[derive(Debug, Clone)]
+struct MaybeLower<'a> {
+    buf: &'a [u8],
+    lower: bool,
+}
+
+/// A possible error when converting a `HeaderName` from another type.
+#[derive(Debug)]
+pub struct InvalidHeaderName {
+    _priv: (),
+}
+
+/// A possible error when converting a `HeaderName` from another type.
+#[derive(Debug)]
+pub struct InvalidHeaderNameBytes(InvalidHeaderName) ;
+
+macro_rules! standard_headers {
+    (
+        $(
+            $(#[$docs:meta])*
+            ($konst:ident, $upcase:ident, $name:expr);
+        )+
+    ) => {
+        #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+        enum StandardHeader {
+            $(
+                $konst,
+            )+
+        }
+
+        $(
+            $(#[$docs])*
+            pub const $upcase: HeaderName = HeaderName {
+                inner: Repr::Standard(StandardHeader::$konst),
+            };
+        )+
+
+        impl StandardHeader {
+            #[inline]
+            fn as_str(&self) -> &'static str {
+                match *self {
+                    $(
+                    StandardHeader::$konst => $name,
+                    )+
+                }
+            }
+        }
+
+        #[cfg(test)]
+        const TEST_HEADERS: &'static [(StandardHeader, &'static str)] = &[
+            $(
+            (StandardHeader::$konst, $name),
+            )+
+        ];
+
+        #[test]
+        fn test_parse_standard_headers() {
+            for &(std, name) in TEST_HEADERS {
+                // Test lower case
+                assert_eq!(HeaderName::from_bytes(name.as_bytes()).unwrap(), HeaderName::from(std));
+
+                // Test upper case
+                let upper = name.to_uppercase().to_string();
+                assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), HeaderName::from(std));
+            }
+        }
+
+        #[test]
+        fn test_standard_headers_into_bytes() {
+            for &(std, name) in TEST_HEADERS {
+                let std = HeaderName::from(std);
+                // Test lower case
+                let name_bytes = name.as_bytes();
+                let bytes: Bytes =
+                    HeaderName::from_bytes(name_bytes).unwrap().into();
+                assert_eq!(bytes, name_bytes);
+                assert_eq!(HeaderName::from_bytes(name_bytes).unwrap(), std);
+
+                // Test upper case
+                let upper = name.to_uppercase().to_string();
+                let bytes: Bytes =
+                    HeaderName::from_bytes(upper.as_bytes()).unwrap().into();
+                assert_eq!(bytes, name.as_bytes());
+                assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(),
+                           std);
+
+
+            }
+
+        }
+    }
+}
+
+// Generate constants for all standard HTTP headers. This includes a static hash
+// code for the "fast hash" path. The hash code for static headers *do not* have
+// to match the text representation of those headers. This is because header
+// strings are always converted to the static values (when they match) before
+// being hashed. This means that it is impossible to compare the static hash
+// code of CONTENT_LENGTH with "content-length".
+standard_headers! {
+    /// Advertises which content types the client is able to understand.
+    ///
+    /// The Accept request HTTP header advertises which content types, expressed
+    /// as MIME types, the client is able to understand. Using content
+    /// negotiation, the server then selects one of the proposals, uses it and
+    /// informs the client of its choice with the Content-Type response header.
+    /// Browsers set adequate values for this header depending of the context
+    /// where the request is done: when fetching a CSS stylesheet a different
+    /// value is set for the request than when fetching an image, video or a
+    /// script.
+    (Accept, ACCEPT, "accept");
+
+    /// Advertises which character set the client is able to understand.
+    ///
+    /// The Accept-Charset request HTTP header advertises which character set
+    /// the client is able to understand. Using content negotiation, the server
+    /// then selects one of the proposals, uses it and informs the client of its
+    /// choice within the Content-Type response header. Browsers usually don't
+    /// set this header as the default value for each content type is usually
+    /// correct and transmitting it would allow easier fingerprinting.
+    ///
+    /// If the server cannot serve any matching character set, it can
+    /// theoretically send back a 406 (Not Acceptable) error code. But, for a
+    /// better user experience, this is rarely done and the more common way is
+    /// to ignore the Accept-Charset header in this case.
+    (AcceptCharset, ACCEPT_CHARSET, "accept-charset");
+
+    /// Advertises which content encoding the client is able to understand.
+    ///
+    /// The Accept-Encoding request HTTP header advertises which content
+    /// encoding, usually a compression algorithm, the client is able to
+    /// understand. Using content negotiation, the server selects one of the
+    /// proposals, uses it and informs the client of its choice with the
+    /// Content-Encoding response header.
+    ///
+    /// Even if both the client and the server supports the same compression
+    /// algorithms, the server may choose not to compress the body of a
+    /// response, if the identity value is also acceptable. Two common cases
+    /// lead to this:
+    ///
+    /// * The data to be sent is already compressed and a second compression
+    /// won't lead to smaller data to be transmitted. This may the case with
+    /// some image formats;
+    ///
+    /// * The server is overloaded and cannot afford the computational overhead
+    /// induced by the compression requirement. Typically, Microsoft recommends
+    /// not to compress if a server use more than 80 % of its computational
+    /// power.
+    ///
+    /// As long as the identity value, meaning no encryption, is not explicitly
+    /// forbidden, by an identity;q=0 or a *;q=0 without another explicitly set
+    /// value for identity, the server must never send back a 406 Not Acceptable
+    /// error.
+    (AcceptEncoding, ACCEPT_ENCODING, "accept-encoding");
+
+    /// Advertises which languages the client is able to understand.
+    ///
+    /// The Accept-Language request HTTP header advertises which languages the
+    /// client is able to understand, and which locale variant is preferred.
+    /// Using content negotiation, the server then selects one of the proposals,
+    /// uses it and informs the client of its choice with the Content-Language
+    /// response header. Browsers set adequate values for this header according
+    /// their user interface language and even if a user can change it, this
+    /// happens rarely (and is frown upon as it leads to fingerprinting).
+    ///
+    /// This header is a hint to be used when the server has no way of
+    /// determining the language via another way, like a specific URL, that is
+    /// controlled by an explicit user decision. It is recommended that the
+    /// server never overrides an explicit decision. The content of the
+    /// Accept-Language is often out of the control of the user (like when
+    /// traveling and using an Internet Cafe in a different country); the user
+    /// may also want to visit a page in another language than the locale of
+    /// their user interface.
+    ///
+    /// If the server cannot serve any matching language, it can theoretically
+    /// send back a 406 (Not Acceptable) error code. But, for a better user
+    /// experience, this is rarely done and more common way is to ignore the
+    /// Accept-Language header in this case.
+    (AcceptLanguage, ACCEPT_LANGUAGE, "accept-language");
+
+    /// Marker used by the server to advertise partial request support.
+    ///
+    /// The Accept-Ranges response HTTP header is a marker used by the server to
+    /// advertise its support of partial requests. The value of this field
+    /// indicates the unit that can be used to define a range.
+    ///
+    /// In presence of an Accept-Ranges header, the browser may try to resume an
+    /// interrupted download, rather than to start it from the start again.
+    (AcceptRanges, ACCEPT_RANGES, "accept-ranges");
+
+    /// Preflight response indicating if the response to the request can be
+    /// exposed to the page.
+    ///
+    /// The Access-Control-Allow-Credentials response header indicates whether
+    /// or not the response to the request can be exposed to the page. It can be
+    /// exposed when the true value is returned; it can't in other cases.
+    ///
+    /// Credentials are cookies, authorization headers or TLS client
+    /// certificates.
+    ///
+    /// When used as part of a response to a preflight request, this indicates
+    /// whether or not the actual request can be made using credentials. Note
+    /// that simple GET requests are not preflighted, and so if a request is
+    /// made for a resource with credentials, if this header is not returned
+    /// with the resource, the response is ignored by the browser and not
+    /// returned to web content.
+    ///
+    /// The Access-Control-Allow-Credentials header works in conjunction with
+    /// the XMLHttpRequest.withCredentials property or with the credentials
+    /// option in the Request() constructor of the Fetch API. Credentials must
+    /// be set on both sides (the Access-Control-Allow-Credentials header and in
+    /// the XHR or Fetch request) in order for the CORS request with credentials
+    /// to succeed.
+    (AccessControlAllowCredentials, ACCESS_CONTROL_ALLOW_CREDENTIALS, "access-control-allow-credentials");
+
+    /// Preflight response indicating permitted HTTP headers.
+    ///
+    /// The Access-Control-Allow-Headers response header is used in response to
+    /// a preflight request to indicate which HTTP headers will be available via
+    /// Access-Control-Expose-Headers when making the actual request.
+    ///
+    /// The simple headers, Accept, Accept-Language, Content-Language,
+    /// Content-Type (but only with a MIME type of its parsed value (ignoring
+    /// parameters) of either application/x-www-form-urlencoded,
+    /// multipart/form-data, or text/plain), are always available and don't need
+    /// to be listed by this header.
+    ///
+    /// This header is required if the request has an
+    /// Access-Control-Request-Headers header.
+    (AccessControlAllowHeaders, ACCESS_CONTROL_ALLOW_HEADERS, "access-control-allow-headers");
+
+    /// Preflight header response indicating permitted access methods.
+    ///
+    /// The Access-Control-Allow-Methods response header specifies the method or
+    /// methods allowed when accessing the resource in response to a preflight
+    /// request.
+    (AccessControlAllowMethods, ACCESS_CONTROL_ALLOW_METHODS, "access-control-allow-methods");
+
+    /// Indicates whether the response can be shared with resources with the
+    /// given origin.
+    (AccessControlAllowOrigin, ACCESS_CONTROL_ALLOW_ORIGIN, "access-control-allow-origin");
+
+    /// Indicates which headers can be exposed as part of the response by
+    /// listing their names.
+    (AccessControlExposeHeaders, ACCESS_CONTROL_EXPOSE_HEADERS, "access-control-expose-headers");
+
+    /// Indicates how long the results of a preflight request can be cached.
+    (AccessControlMaxAge, ACCESS_CONTROL_MAX_AGE, "access-control-max-age");
+
+    /// Informs the server which HTTP headers will be used when an actual
+    /// request is made.
+    (AccessControlRequestHeaders, ACCESS_CONTROL_REQUEST_HEADERS, "access-control-request-headers");
+
+    /// Informs the server know which HTTP method will be used when the actual
+    /// request is made.
+    (AccessControlRequestMethod, ACCESS_CONTROL_REQUEST_METHOD, "access-control-request-method");
+
+    /// Indicates the time in seconds the object has been in a proxy cache.
+    ///
+    /// The Age header is usually close to zero. If it is Age: 0, it was
+    /// probably just fetched from the origin server; otherwise It is usually
+    /// calculated as a difference between the proxy's current date and the Date
+    /// general header included in the HTTP response.
+    (Age, AGE, "age");
+
+    /// Lists the set of methods support by a resource.
+    ///
+    /// This header must be sent if the server responds with a 405 Method Not
+    /// Allowed status code to indicate which request methods can be used. An
+    /// empty Allow header indicates that the resource allows no request
+    /// methods, which might occur temporarily for a given resource, for
+    /// example.
+    (Allow, ALLOW, "allow");
+
+    /// Advertises the availability of alternate services to clients.
+    (AltSvc, ALT_SVC, "alt-svc");
+
+    /// Contains the credentials to authenticate a user agent with a server.
+    ///
+    /// Usually this header is included after the server has responded with a
+    /// 401 Unauthorized status and the WWW-Authenticate header.
+    (Authorization, AUTHORIZATION, "authorization");
+
+    /// Specifies directives for caching mechanisms in both requests and
+    /// responses.
+    ///
+    /// Caching directives are unidirectional, meaning that a given directive in
+    /// a request is not implying that the same directive is to be given in the
+    /// response.
+    (CacheControl, CACHE_CONTROL, "cache-control");
+
+    /// Controls whether or not the network connection stays open after the
+    /// current transaction finishes.
+    ///
+    /// If the value sent is keep-alive, the connection is persistent and not
+    /// closed, allowing for subsequent requests to the same server to be done.
+    ///
+    /// Except for the standard hop-by-hop headers (Keep-Alive,
+    /// Transfer-Encoding, TE, Connection, Trailer, Upgrade, Proxy-Authorization
+    /// and Proxy-Authenticate), any hop-by-hop headers used by the message must
+    /// be listed in the Connection header, so that the first proxy knows he has
+    /// to consume them and not to forward them further. Standard hop-by-hop
+    /// headers can be listed too (it is often the case of Keep-Alive, but this
+    /// is not mandatory.
+    (Connection, CONNECTION, "connection");
+
+    /// Indicates if the content is expected to be displayed inline.
+    ///
+    /// In a regular HTTP response, the Content-Disposition response header is a
+    /// header indicating if the content is expected to be displayed inline in
+    /// the browser, that is, as a Web page or as part of a Web page, or as an
+    /// attachment, that is downloaded and saved locally.
+    ///
+    /// In a multipart/form-data body, the HTTP Content-Disposition general
+    /// header is a header that can be used on the subpart of a multipart body
+    /// to give information about the field it applies to. The subpart is
+    /// delimited by the boundary defined in the Content-Type header. Used on
+    /// the body itself, Content-Disposition has no effect.
+    ///
+    /// The Content-Disposition header is defined in the larger context of MIME
+    /// messages for e-mail, but only a subset of the possible parameters apply
+    /// to HTTP forms and POST requests. Only the value form-data, as well as
+    /// the optional directive name and filename, can be used in the HTTP
+    /// context.
+    (ContentDisposition, CONTENT_DISPOSITION, "content-disposition");
+
+    /// Used to compress the media-type.
+    ///
+    /// When present, its value indicates what additional content encoding has
+    /// been applied to the entity-body. It lets the client know, how to decode
+    /// in order to obtain the media-type referenced by the Content-Type header.
+    ///
+    /// It is recommended to compress data as much as possible and therefore to
+    /// use this field, but some types of resources, like jpeg images, are
+    /// already compressed.  Sometimes using additional compression doesn't
+    /// reduce payload size and can even make the payload longer.
+    (ContentEncoding, CONTENT_ENCODING, "content-encoding");
+
+    /// Used to describe the languages intended for the audience.
+    ///
+    /// This header allows a user to differentiate according to the users' own
+    /// preferred language. For example, if "Content-Language: de-DE" is set, it
+    /// says that the document is intended for German language speakers
+    /// (however, it doesn't indicate the document is written in German. For
+    /// example, it might be written in English as part of a language course for
+    /// German speakers).
+    ///
+    /// If no Content-Language is specified, the default is that the content is
+    /// intended for all language audiences. Multiple language tags are also
+    /// possible, as well as applying the Content-Language header to various
+    /// media types and not only to textual documents.
+    (ContentLanguage, CONTENT_LANGUAGE, "content-language");
+
+    /// Indicates the size fo the entity-body.
+    ///
+    /// The header value must be a decimal indicating the number of octets sent
+    /// to the recipient.
+    (ContentLength, CONTENT_LENGTH, "content-length");
+
+    /// Indicates an alternate location for the returned data.
+    ///
+    /// The principal use case is to indicate the URL of the resource
+    /// transmitted as the result of content negotiation.
+    ///
+    /// Location and Content-Location are different: Location indicates the
+    /// target of a redirection (or the URL of a newly created document), while
+    /// Content-Location indicates the direct URL to use to access the resource,
+    /// without the need of further content negotiation. Location is a header
+    /// associated with the response, while Content-Location is associated with
+    /// the entity returned.
+    (ContentLocation, CONTENT_LOCATION, "content-location");
+
+    /// Indicates where in a full body message a partial message belongs.
+    (ContentRange, CONTENT_RANGE, "content-range");
+
+    /// Allows controlling resources the user agent is allowed to load for a
+    /// given page.
+    ///
+    /// With a few exceptions, policies mostly involve specifying server origins
+    /// and script endpoints. This helps guard against cross-site scripting
+    /// attacks (XSS).
+    (ContentSecurityPolicy, CONTENT_SECURITY_POLICY, "content-security-policy");
+
+    /// Allows experimenting with policies by monitoring their effects.
+    ///
+    /// The HTTP Content-Security-Policy-Report-Only response header allows web
+    /// developers to experiment with policies by monitoring (but not enforcing)
+    /// their effects. These violation reports consist of JSON documents sent
+    /// via an HTTP POST request to the specified URI.
+    (ContentSecurityPolicyReportOnly, CONTENT_SECURITY_POLICY_REPORT_ONLY, "content-security-policy-report-only");
+
+    /// Used to indicate the media type of the resource.
+    ///
+    /// In responses, a Content-Type header tells the client what the content
+    /// type of the returned content actually is. Browsers will do MIME sniffing
+    /// in some cases and will not necessarily follow the value of this header;
+    /// to prevent this behavior, the header X-Content-Type-Options can be set
+    /// to nosniff.
+    ///
+    /// In requests, (such as POST or PUT), the client tells the server what
+    /// type of data is actually sent.
+    (ContentType, CONTENT_TYPE, "content-type");
+
+    /// Contains stored HTTP cookies previously sent by the server with the
+    /// Set-Cookie header.
+    ///
+    /// The Cookie header might be omitted entirely, if the privacy setting of
+    /// the browser are set to block them, for example.
+    (Cookie, COOKIE, "cookie");
+
+    /// Indicates the client's tracking preference.
+    ///
+    /// This header lets users indicate whether they would prefer privacy rather
+    /// than personalized content.
+    (Dnt, DNT, "dnt");
+
+    /// Contains the date and time at which the message was originated.
+    (Date, DATE, "date");
+
+    /// Identifier for a specific version of a resource.
+    ///
+    /// This header allows caches to be more efficient, and saves bandwidth, as
+    /// a web server does not need to send a full response if the content has
+    /// not changed. On the other side, if the content has changed, etags are
+    /// useful to help prevent simultaneous updates of a resource from
+    /// overwriting each other ("mid-air collisions").
+    ///
+    /// If the resource at a given URL changes, a new Etag value must be
+    /// generated. Etags are therefore similar to fingerprints and might also be
+    /// used for tracking purposes by some servers. A comparison of them allows
+    /// to quickly determine whether two representations of a resource are the
+    /// same, but they might also be set to persist indefinitely by a tracking
+    /// server.
+    (Etag, ETAG, "etag");
+
+    /// Indicates expectations that need to be fulfilled by the server in order
+    /// to properly handle the request.
+    ///
+    /// The only expectation defined in the specification is Expect:
+    /// 100-continue, to which the server shall respond with:
+    ///
+    /// * 100 if the information contained in the header is sufficient to cause
+    /// an immediate success,
+    ///
+    /// * 417 (Expectation Failed) if it cannot meet the expectation; or any
+    /// other 4xx status otherwise.
+    ///
+    /// For example, the server may reject a request if its Content-Length is
+    /// too large.
+    ///
+    /// No common browsers send the Expect header, but some other clients such
+    /// as cURL do so by default.
+    (Expect, EXPECT, "expect");
+
+    /// Contains the date/time after which the response is considered stale.
+    ///
+    /// Invalid dates, like the value 0, represent a date in the past and mean
+    /// that the resource is already expired.
+    ///
+    /// If there is a Cache-Control header with the "max-age" or "s-max-age"
+    /// directive in the response, the Expires header is ignored.
+    (Expires, EXPIRES, "expires");
+
+    /// Contains information from the client-facing side of proxy servers that
+    /// is altered or lost when a proxy is involved in the path of the request.
+    ///
+    /// The alternative and de-facto standard versions of this header are the
+    /// X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto headers.
+    ///
+    /// This header is used for debugging, statistics, and generating
+    /// location-dependent content and by design it exposes privacy sensitive
+    /// information, such as the IP address of the client. Therefore the user's
+    /// privacy must be kept in mind when deploying this header.
+    (Forwarded, FORWARDED, "forwarded");
+
+    /// Contains an Internet email address for a human user who controls the
+    /// requesting user agent.
+    ///
+    /// If you are running a robotic user agent (e.g. a crawler), the From
+    /// header should be sent, so you can be contacted if problems occur on
+    /// servers, such as if the robot is sending excessive, unwanted, or invalid
+    /// requests.
+    (From, FROM, "from");
+
+    /// Specifies the domain name of the server and (optionally) the TCP port
+    /// number on which the server is listening.
+    ///
+    /// If no port is given, the default port for the service requested (e.g.,
+    /// "80" for an HTTP URL) is implied.
+    ///
+    /// A Host header field must be sent in all HTTP/1.1 request messages. A 400
+    /// (Bad Request) status code will be sent to any HTTP/1.1 request message
+    /// that lacks a Host header field or contains more than one.
+    (Host, HOST, "host");
+
+    /// Makes a request conditional based on the E-Tag.
+    ///
+    /// For GET and HEAD methods, the server will send back the requested
+    /// resource only if it matches one of the listed ETags. For PUT and other
+    /// non-safe methods, it will only upload the resource in this case.
+    ///
+    /// The comparison with the stored ETag uses the strong comparison
+    /// algorithm, meaning two files are considered identical byte to byte only.
+    /// This is weakened when the  W/ prefix is used in front of the ETag.
+    ///
+    /// There are two common use cases:
+    ///
+    /// * For GET and HEAD methods, used in combination with an Range header, it
+    /// can guarantee that the new ranges requested comes from the same resource
+    /// than the previous one. If it doesn't match, then a 416 (Range Not
+    /// Satisfiable) response is returned.
+    ///
+    /// * For other methods, and in particular for PUT, If-Match can be used to
+    /// prevent the lost update problem. It can check if the modification of a
+    /// resource that the user wants to upload will not override another change
+    /// that has been done since the original resource was fetched. If the
+    /// request cannot be fulfilled, the 412 (Precondition Failed) response is
+    /// returned.
+    (IfMatch, IF_MATCH, "if-match");
+
+    /// Makes a request conditional based on the modification date.
+    ///
+    /// The If-Modified-Since request HTTP header makes the request conditional:
+    /// the server will send back the requested resource, with a 200 status,
+    /// only if it has been last modified after the given date. If the request
+    /// has not been modified since, the response will be a 304 without any
+    /// body; the Last-Modified header will contain the date of last
+    /// modification. Unlike If-Unmodified-Since, If-Modified-Since can only be
+    /// used with a GET or HEAD.
+    ///
+    /// When used in combination with If-None-Match, it is ignored, unless the
+    /// server doesn't support If-None-Match.
+    ///
+    /// The most common use case is to update a cached entity that has no
+    /// associated ETag.
+    (IfModifiedSince, IF_MODIFIED_SINCE, "if-modified-since");
+
+    /// Makes a request conditional based on the E-Tag.
+    ///
+    /// The If-None-Match HTTP request header makes the request conditional. For
+    /// GET and HEAD methods, the server will send back the requested resource,
+    /// with a 200 status, only if it doesn't have an ETag matching the given
+    /// ones. For other methods, the request will be processed only if the
+    /// eventually existing resource's ETag doesn't match any of the values
+    /// listed.
+    ///
+    /// When the condition fails for GET and HEAD methods, then the server must
+    /// return HTTP status code 304 (Not Modified). For methods that apply
+    /// server-side changes, the status code 412 (Precondition Failed) is used.
+    /// Note that the server generating a 304 response MUST generate any of the
+    /// following header fields that would have been sent in a 200 (OK) response
+    /// to the same request: Cache-Control, Content-Location, Date, ETag,
+    /// Expires, and Vary.
+    ///
+    /// The comparison with the stored ETag uses the weak comparison algorithm,
+    /// meaning two files are considered identical not only if they are
+    /// identical byte to byte, but if the content is equivalent. For example,
+    /// two pages that would differ only by the date of generation in the footer
+    /// would be considered as identical.
+    ///
+    /// When used in combination with If-Modified-Since, it has precedence (if
+    /// the server supports it).
+    ///
+    /// There are two common use cases:
+    ///
+    /// * For `GET` and `HEAD` methods, to update a cached entity that has an associated ETag.
+    /// * For other methods, and in particular for `PUT`, `If-None-Match` used with
+    /// the `*` value can be used to save a file not known to exist,
+    /// guaranteeing that another upload didn't happen before, losing the data
+    /// of the previous put; this problems is the variation of the lost update
+    /// problem.
+    (IfNoneMatch, IF_NONE_MATCH, "if-none-match");
+
+    /// Makes a request conditional based on range.
+    ///
+    /// The If-Range HTTP request header makes a range request conditional: if
+    /// the condition is fulfilled, the range request will be issued and the
+    /// server sends back a 206 Partial Content answer with the appropriate
+    /// body. If the condition is not fulfilled, the full resource is sent back,
+    /// with a 200 OK status.
+    ///
+    /// This header can be used either with a Last-Modified validator, or with
+    /// an ETag, but not with both.
+    ///
+    /// The most common use case is to resume a download, to guarantee that the
+    /// stored resource has not been modified since the last fragment has been
+    /// received.
+    (IfRange, IF_RANGE, "if-range");
+
+    /// Makes the request conditional based on the last modification date.
+    ///
+    /// The If-Unmodified-Since request HTTP header makes the request
+    /// conditional: the server will send back the requested resource, or accept
+    /// it in the case of a POST or another non-safe method, only if it has not
+    /// been last modified after the given date. If the request has been
+    /// modified after the given date, the response will be a 412 (Precondition
+    /// Failed) error.
+    ///
+    /// There are two common use cases:
+    ///
+    /// * In conjunction non-safe methods, like POST, it can be used to
+    /// implement an optimistic concurrency control, like done by some wikis:
+    /// editions are rejected if the stored document has been modified since the
+    /// original has been retrieved.
+    ///
+    /// * In conjunction with a range request with a If-Range header, it can be
+    /// used to ensure that the new fragment requested comes from an unmodified
+    /// document.
+    (IfUnmodifiedSince, IF_UNMODIFIED_SINCE, "if-unmodified-since");
+
+    /// Content-Types that are acceptable for the response.
+    (LastModified, LAST_MODIFIED, "last-modified");
+
+    /// Allows the server to point an interested client to another resource
+    /// containing metadata about the requested resource.
+    (Link, LINK, "link");
+
+    /// Indicates the URL to redirect a page to.
+    ///
+    /// The Location response header indicates the URL to redirect a page to. It
+    /// only provides a meaning when served with a 3xx status response.
+    ///
+    /// The HTTP method used to make the new request to fetch the page pointed
+    /// to by Location depends of the original method and of the kind of
+    /// redirection:
+    ///
+    /// * If 303 (See Also) responses always lead to the use of a GET method,
+    /// 307 (Temporary Redirect) and 308 (Permanent Redirect) don't change the
+    /// method used in the original request;
+    ///
+    /// * 301 (Permanent Redirect) and 302 (Found) doesn't change the method
+    /// most of the time, though older user-agents may (so you basically don't
+    /// know).
+    ///
+    /// All responses with one of these status codes send a Location header.
+    ///
+    /// Beside redirect response, messages with 201 (Created) status also
+    /// include the Location header. It indicates the URL to the newly created
+    /// resource.
+    ///
+    /// Location and Content-Location are different: Location indicates the
+    /// target of a redirection (or the URL of a newly created resource), while
+    /// Content-Location indicates the direct URL to use to access the resource
+    /// when content negotiation happened, without the need of further content
+    /// negotiation. Location is a header associated with the response, while
+    /// Content-Location is associated with the entity returned.
+    (Location, LOCATION, "location");
+
+    /// Indicates the max number of intermediaries the request should be sent
+    /// through.
+    (MaxForwards, MAX_FORWARDS, "max-forwards");
+
+    /// Indicates where a fetch originates from.
+    ///
+    /// It doesn't include any path information, but only the server name. It is
+    /// sent with CORS requests, as well as with POST requests. It is similar to
+    /// the Referer header, but, unlike this header, it doesn't disclose the
+    /// whole path.
+    (Origin, ORIGIN, "origin");
+
+    /// HTTP/1.0 header usually used for backwards compatibility.
+    ///
+    /// The Pragma HTTP/1.0 general header is an implementation-specific header
+    /// that may have various effects along the request-response chain. It is
+    /// used for backwards compatibility with HTTP/1.0 caches where the
+    /// Cache-Control HTTP/1.1 header is not yet present.
+    (Pragma, PRAGMA, "pragma");
+
+    /// Defines the authentication method that should be used to gain access to
+    /// a proxy.
+    ///
+    /// Unlike `www-authenticate`, the `proxy-authenticate` header field applies
+    /// only to the next outbound client on the response chain. This is because
+    /// only the client that chose a given proxy is likely to have the
+    /// credentials necessary for authentication. However, when multiple proxies
+    /// are used within the same administrative domain, such as office and
+    /// regional caching proxies within a large corporate network, it is common
+    /// for credentials to be generated by the user agent and passed through the
+    /// hierarchy until consumed. Hence, in such a configuration, it will appear
+    /// as if Proxy-Authenticate is being forwarded because each proxy will send
+    /// the same challenge set.
+    ///
+    /// The `proxy-authenticate` header is sent along with a `407 Proxy
+    /// Authentication Required`.
+    (ProxyAuthenticate, PROXY_AUTHENTICATE, "proxy-authenticate");
+
+    /// Contains the credentials to authenticate a user agent to a proxy server.
+    ///
+    /// This header is usually included after the server has responded with a
+    /// 407 Proxy Authentication Required status and the Proxy-Authenticate
+    /// header.
+    (ProxyAuthorization, PROXY_AUTHORIZATION, "proxy-authorization");
+
+    /// Associates a specific cryptographic public key with a certain server.
+    ///
+    /// This decreases the risk of MITM attacks with forged certificates. If one
+    /// or several keys are pinned and none of them are used by the server, the
+    /// browser will not accept the response as legitimate, and will not display
+    /// it.
+    (PublicKeyPins, PUBLIC_KEY_PINS, "public-key-pins");
+
+    /// Sends reports of pinning violation to the report-uri specified in the
+    /// header.
+    ///
+    /// Unlike `Public-Key-Pins`, this header still allows browsers to connect
+    /// to the server if the pinning is violated.
+    (PublicKeyPinsReportOnly, PUBLIC_KEY_PINS_REPORT_ONLY, "public-key-pins-report-only");
+
+    /// Indicates the part of a document that the server should return.
+    ///
+    /// Several parts can be requested with one Range header at once, and the
+    /// server may send back these ranges in a multipart document. If the server
+    /// sends back ranges, it uses the 206 Partial Content for the response. If
+    /// the ranges are invalid, the server returns the 416 Range Not Satisfiable
+    /// error. The server can also ignore the Range header and return the whole
+    /// document with a 200 status code.
+    (Range, RANGE, "range");
+
+    /// Contains the address of the previous web page from which a link to the
+    /// currently requested page was followed.
+    ///
+    /// The Referer header allows servers to identify where people are visiting
+    /// them from and may use that data for analytics, logging, or optimized
+    /// caching, for example.
+    (Referer, REFERER, "referer");
+
+    /// Governs which referrer information should be included with requests
+    /// made.
+    (ReferrerPolicy, REFERRER_POLICY, "referrer-policy");
+
+    /// Informs the web browser that the current page or frame should be
+    /// refreshed.
+    (Refresh, REFRESH, "refresh");
+
+    /// The Retry-After response HTTP header indicates how long the user agent
+    /// should wait before making a follow-up request. There are two main cases
+    /// this header is used:
+    ///
+    /// * When sent with a 503 (Service Unavailable) response, it indicates how
+    /// long the service is expected to be unavailable.
+    ///
+    /// * When sent with a redirect response, such as 301 (Moved Permanently),
+    /// it indicates the minimum time that the user agent is asked to wait
+    /// before issuing the redirected request.
+    (RetryAfter, RETRY_AFTER, "retry-after");
+
+    /// The |Sec-WebSocket-Accept| header field is used in the WebSocket
+    /// opening handshake. It is sent from the server to the client to
+    /// confirm that the server is willing to initiate the WebSocket
+    /// connection.
+    (SecWebSocketAccept, SEC_WEBSOCKET_ACCEPT, "sec-websocket-accept");
+
+    /// The |Sec-WebSocket-Extensions| header field is used in the WebSocket
+    /// opening handshake. It is initially sent from the client to the
+    /// server, and then subsequently sent from the server to the client, to
+    /// agree on a set of protocol-level extensions to use for the duration
+    /// of the connection.
+    (SecWebSocketExtensions, SEC_WEBSOCKET_EXTENSIONS, "sec-websocket-extensions");
+
+    /// The |Sec-WebSocket-Key| header field is used in the WebSocket opening
+    /// handshake. It is sent from the client to the server to provide part
+    /// of the information used by the server to prove that it received a
+    /// valid WebSocket opening handshake. This helps ensure that the server
+    /// does not accept connections from non-WebSocket clients (e.g., HTTP
+    /// clients) that are being abused to send data to unsuspecting WebSocket
+    /// servers.
+    (SecWebSocketKey, SEC_WEBSOCKET_KEY, "sec-websocket-key");
+
+    /// The |Sec-WebSocket-Protocol| header field is used in the WebSocket
+    /// opening handshake. It is sent from the client to the server and back
+    /// from the server to the client to confirm the subprotocol of the
+    /// connection.  This enables scripts to both select a subprotocol and be
+    /// sure that the server agreed to serve that subprotocol.
+    (SecWebSocketProtocol, SEC_WEBSOCKET_PROTOCOL, "sec-websocket-protocol");
+
+    /// The |Sec-WebSocket-Version| header field is used in the WebSocket
+    /// opening handshake.  It is sent from the client to the server to
+    /// indicate the protocol version of the connection.  This enables
+    /// servers to correctly interpret the opening handshake and subsequent
+    /// data being sent from the data, and close the connection if the server
+    /// cannot interpret that data in a safe manner.
+    (SecWebSocketVersion, SEC_WEBSOCKET_VERSION, "sec-websocket-version");
+
+    /// Contains information about the software used by the origin server to
+    /// handle the request.
+    ///
+    /// Overly long and detailed Server values should be avoided as they
+    /// potentially reveal internal implementation details that might make it
+    /// (slightly) easier for attackers to find and exploit known security
+    /// holes.
+    (Server, SERVER, "server");
+
+    /// Used to send cookies from the server to the user agent.
+    (SetCookie, SET_COOKIE, "set-cookie");
+
+    /// Tells the client to communicate with HTTPS instead of using HTTP.
+    (StrictTransportSecurity, STRICT_TRANSPORT_SECURITY, "strict-transport-security");
+
+    /// Informs the server of transfer encodings willing to be accepted as part
+    /// of the response.
+    ///
+    /// See also the Transfer-Encoding response header for more details on
+    /// transfer encodings. Note that chunked is always acceptable for HTTP/1.1
+    /// recipients and you that don't have to specify "chunked" using the TE
+    /// header. However, it is useful for setting if the client is accepting
+    /// trailer fields in a chunked transfer coding using the "trailers" value.
+    (Te, TE, "te");
+
+    /// Allows the sender to include additional fields at the end of chunked
+    /// messages.
+    (Trailer, TRAILER, "trailer");
+
+    /// Specifies the form of encoding used to safely transfer the entity to the
+    /// client.
+    ///
+    /// `transfer-encoding` is a hop-by-hop header, that is applying to a
+    /// message between two nodes, not to a resource itself. Each segment of a
+    /// multi-node connection can use different `transfer-encoding` values. If
+    /// you want to compress data over the whole connection, use the end-to-end
+    /// header `content-encoding` header instead.
+    ///
+    /// When present on a response to a `HEAD` request that has no body, it
+    /// indicates the value that would have applied to the corresponding `GET`
+    /// message.
+    (TransferEncoding, TRANSFER_ENCODING, "transfer-encoding");
+
+    /// Contains a string that allows identifying the requesting client's
+    /// software.
+    (UserAgent, USER_AGENT, "user-agent");
+
+    /// Used as part of the exchange to upgrade the protocol.
+    (Upgrade, UPGRADE, "upgrade");
+
+    /// Sends a signal to the server expressing the client’s preference for an
+    /// encrypted and authenticated response.
+    (UpgradeInsecureRequests, UPGRADE_INSECURE_REQUESTS, "upgrade-insecure-requests");
+
+    /// Determines how to match future requests with cached responses.
+    ///
+    /// The `vary` HTTP response header determines how to match future request
+    /// headers to decide whether a cached response can be used rather than
+    /// requesting a fresh one from the origin server. It is used by the server
+    /// to indicate which headers it used when selecting a representation of a
+    /// resource in a content negotiation algorithm.
+    ///
+    /// The `vary` header should be set on a 304 Not Modified response exactly
+    /// like it would have been set on an equivalent 200 OK response.
+    (Vary, VARY, "vary");
+
+    /// Added by proxies to track routing.
+    ///
+    /// The `via` general header is added by proxies, both forward and reverse
+    /// proxies, and can appear in the request headers and the response headers.
+    /// It is used for tracking message forwards, avoiding request loops, and
+    /// identifying the protocol capabilities of senders along the
+    /// request/response chain.
+    (Via, VIA, "via");
+
+    /// General HTTP header contains information about possible problems with
+    /// the status of the message.
+    ///
+    /// More than one `warning` header may appear in a response. Warning header
+    /// fields can in general be applied to any message, however some warn-codes
+    /// are specific to caches and can only be applied to response messages.
+    (Warning, WARNING, "warning");
+
+    /// Defines the authentication method that should be used to gain access to
+    /// a resource.
+    (WwwAuthenticate, WWW_AUTHENTICATE, "www-authenticate");
+
+    /// Marker used by the server to indicate that the MIME types advertised in
+    /// the `content-type` headers should not be changed and be followed.
+    ///
+    /// This allows to opt-out of MIME type sniffing, or, in other words, it is
+    /// a way to say that the webmasters knew what they were doing.
+    ///
+    /// This header was introduced by Microsoft in IE 8 as a way for webmasters
+    /// to block content sniffing that was happening and could transform
+    /// non-executable MIME types into executable MIME types. Since then, other
+    /// browsers have introduced it, even if their MIME sniffing algorithms were
+    /// less aggressive.
+    ///
+    /// Site security testers usually expect this header to be set.
+    (XContentTypeOptions, X_CONTENT_TYPE_OPTIONS, "x-content-type-options");
+
+    /// Controls DNS prefetching.
+    ///
+    /// The `x-dns-prefetch-control` HTTP response header controls DNS
+    /// prefetching, a feature by which browsers proactively perform domain name
+    /// resolution on both links that the user may choose to follow as well as
+    /// URLs for items referenced by the document, including images, CSS,
+    /// JavaScript, and so forth.
+    ///
+    /// This prefetching is performed in the background, so that the DNS is
+    /// likely to have been resolved by the time the referenced items are
+    /// needed. This reduces latency when the user clicks a link.
+    (XDnsPrefetchControl, X_DNS_PREFETCH_CONTROL, "x-dns-prefetch-control");
+
+    /// Indicates whether or not a browser should be allowed to render a page in
+    /// a frame.
+    ///
+    /// Sites can use this to avoid clickjacking attacks, by ensuring that their
+    /// content is not embedded into other sites.
+    ///
+    /// The added security is only provided if the user accessing the document
+    /// is using a browser supporting `x-frame-options`.
+    (XFrameOptions, X_FRAME_OPTIONS, "x-frame-options");
+
+    /// Stop pages from loading when an XSS attack is detected.
+    ///
+    /// The HTTP X-XSS-Protection response header is a feature of Internet
+    /// Explorer, Chrome and Safari that stops pages from loading when they
+    /// detect reflected cross-site scripting (XSS) attacks. Although these
+    /// protections are largely unnecessary in modern browsers when sites
+    /// implement a strong Content-Security-Policy that disables the use of
+    /// inline JavaScript ('unsafe-inline'), they can still provide protections
+    /// for users of older web browsers that don't yet support CSP.
+    (XXssProtection, X_XSS_PROTECTION, "x-xss-protection");
+}
+
+/// Valid header name characters
+///
+/// ```not_rust
+///       field-name     = token
+///       token          = 1*<any CHAR except CTLs or separators>
+///       separators     = "(" | ")" | "<" | ">" | "@"
+///                      | "," | ";" | ":" | "\" | <">
+///                      | "/" | "[" | "]" | "?" | "="
+///                      | "{" | "}" | SP | HT
+/// ```
+const HEADER_CHARS: [u8; 256] = [
+    //  0      1      2      3      4      5      6      7      8      9
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
+        0,     0,     0,  b'!',  b'"',  b'#',  b'$',  b'%',  b'&', b'\'', //  3x
+        0,     0,  b'*',  b'+',     0,  b'-',  b'.',     0,  b'0',  b'1', //  4x
+     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',     0,     0, //  5x
+        0,     0,     0,     0,     0,  b'a',  b'b',  b'c',  b'd',  b'e', //  6x
+     b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm',  b'n',  b'o', //  7x
+     b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w',  b'x',  b'y', //  8x
+     b'z',     0,     0,     0,     0,  b'_',     0,  b'a',  b'b',  b'c', //  9x
+     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
+     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
+     b'x',  b'y',  b'z',     0,  b'|',     0,  b'~',     0,     0,     0, // 12x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
+        0,     0,     0,     0,     0,     0                              // 25x
+];
+
+const HEADER_CHARS_H2: [u8; 256] = [
+    //  0      1      2      3      4      5      6      7      8      9
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
+        0,     0,     0,  b'!',  b'"',  b'#',  b'$',  b'%',  b'&', b'\'', //  3x
+        0,     0,  b'*',  b'+',     0,  b'-',  b'.',     0,  b'0',  b'1', //  4x
+     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',     0,     0, //  5x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  6x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  7x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  8x
+        0,     0,     0,     0,     0,  b'_',     0,  b'a',  b'b',  b'c', //  9x
+     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
+     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
+     b'x',  b'y',  b'z',     0,  b'|',     0,  b'~',     0,     0,     0, // 12x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
+        0,     0,     0,     0,     0,     0                              // 25x
+];
+
+macro_rules! eq {
+    ($v:ident[$n:expr] == $a:tt) => {
+        $v[$n] == $a
+    };
+    ($v:ident[$n:expr] == $a:tt $($rest:tt)+) => {
+        $v[$n] == $a && eq!($v[($n+1)] == $($rest)+)
+    };
+    ($v:ident == $a:tt $($rest:tt)*) => {
+        $v[0] == $a && eq!($v[1] == $($rest)*)
+    };
+}
+
+fn parse_hdr<'a>(data: &'a [u8], b: &'a mut [u8; 64], table: &[u8; 256])
+    -> Result<HdrName<'a>, InvalidHeaderName>
+{
+    use self::StandardHeader::*;
+
+    let len = data.len();
+
+    let validate = |buf: &'a [u8], len: usize| {
+        let buf = &buf[..len];
+        if buf.iter().any(|&b| b == 0) {
+            Err(InvalidHeaderName::new())
+        } else {
+            Ok(HdrName::custom(buf, true))
+        }
+    };
+
+
+    macro_rules! to_lower {
+        ($d:ident, $src:ident, 1) => { $d[0] = table[$src[0] as usize]; };
+        ($d:ident, $src:ident, 2) => { to_lower!($d, $src, 1); $d[1] = table[$src[1] as usize]; };
+        ($d:ident, $src:ident, 3) => { to_lower!($d, $src, 2); $d[2] = table[$src[2] as usize]; };
+        ($d:ident, $src:ident, 4) => { to_lower!($d, $src, 3); $d[3] = table[$src[3] as usize]; };
+        ($d:ident, $src:ident, 5) => { to_lower!($d, $src, 4); $d[4] = table[$src[4] as usize]; };
+        ($d:ident, $src:ident, 6) => { to_lower!($d, $src, 5); $d[5] = table[$src[5] as usize]; };
+        ($d:ident, $src:ident, 7) => { to_lower!($d, $src, 6); $d[6] = table[$src[6] as usize]; };
+        ($d:ident, $src:ident, 8) => { to_lower!($d, $src, 7); $d[7] = table[$src[7] as usize]; };
+        ($d:ident, $src:ident, 9) => { to_lower!($d, $src, 8); $d[8] = table[$src[8] as usize]; };
+        ($d:ident, $src:ident, 10) => { to_lower!($d, $src, 9); $d[9] = table[$src[9] as usize]; };
+        ($d:ident, $src:ident, 11) => { to_lower!($d, $src, 10); $d[10] = table[$src[10] as usize]; };
+        ($d:ident, $src:ident, 12) => { to_lower!($d, $src, 11); $d[11] = table[$src[11] as usize]; };
+        ($d:ident, $src:ident, 13) => { to_lower!($d, $src, 12); $d[12] = table[$src[12] as usize]; };
+        ($d:ident, $src:ident, 14) => { to_lower!($d, $src, 13); $d[13] = table[$src[13] as usize]; };
+        ($d:ident, $src:ident, 15) => { to_lower!($d, $src, 14); $d[14] = table[$src[14] as usize]; };
+        ($d:ident, $src:ident, 16) => { to_lower!($d, $src, 15); $d[15] = table[$src[15] as usize]; };
+        ($d:ident, $src:ident, 17) => { to_lower!($d, $src, 16); $d[16] = table[$src[16] as usize]; };
+        ($d:ident, $src:ident, 18) => { to_lower!($d, $src, 17); $d[17] = table[$src[17] as usize]; };
+        ($d:ident, $src:ident, 19) => { to_lower!($d, $src, 18); $d[18] = table[$src[18] as usize]; };
+        ($d:ident, $src:ident, 20) => { to_lower!($d, $src, 19); $d[19] = table[$src[19] as usize]; };
+        ($d:ident, $src:ident, 21) => { to_lower!($d, $src, 20); $d[20] = table[$src[20] as usize]; };
+        ($d:ident, $src:ident, 22) => { to_lower!($d, $src, 21); $d[21] = table[$src[21] as usize]; };
+        ($d:ident, $src:ident, 23) => { to_lower!($d, $src, 22); $d[22] = table[$src[22] as usize]; };
+        ($d:ident, $src:ident, 24) => { to_lower!($d, $src, 23); $d[23] = table[$src[23] as usize]; };
+        ($d:ident, $src:ident, 25) => { to_lower!($d, $src, 24); $d[24] = table[$src[24] as usize]; };
+        ($d:ident, $src:ident, 26) => { to_lower!($d, $src, 25); $d[25] = table[$src[25] as usize]; };
+        ($d:ident, $src:ident, 27) => { to_lower!($d, $src, 26); $d[26] = table[$src[26] as usize]; };
+        ($d:ident, $src:ident, 28) => { to_lower!($d, $src, 27); $d[27] = table[$src[27] as usize]; };
+        ($d:ident, $src:ident, 29) => { to_lower!($d, $src, 28); $d[28] = table[$src[28] as usize]; };
+        ($d:ident, $src:ident, 30) => { to_lower!($d, $src, 29); $d[29] = table[$src[29] as usize]; };
+        ($d:ident, $src:ident, 31) => { to_lower!($d, $src, 30); $d[30] = table[$src[30] as usize]; };
+        ($d:ident, $src:ident, 32) => { to_lower!($d, $src, 31); $d[31] = table[$src[31] as usize]; };
+        ($d:ident, $src:ident, 33) => { to_lower!($d, $src, 32); $d[32] = table[$src[32] as usize]; };
+        ($d:ident, $src:ident, 34) => { to_lower!($d, $src, 33); $d[33] = table[$src[33] as usize]; };
+        ($d:ident, $src:ident, 35) => { to_lower!($d, $src, 34); $d[34] = table[$src[34] as usize]; };
+    }
+
+    assert!(len < super::MAX_HEADER_NAME_LEN,
+            "header name too long -- max length is {}",
+            super::MAX_HEADER_NAME_LEN);
+
+    match len {
+        0 => {
+            Err(InvalidHeaderName::new())
+        }
+        2 => {
+            to_lower!(b, data, 2);
+
+            if eq!(b == b't' b'e') {
+                Ok(Te.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        3 => {
+            to_lower!(b, data, 3);
+
+            if eq!(b == b'a' b'g' b'e') {
+                Ok(Age.into())
+            } else if eq!(b == b'v' b'i' b'a') {
+                Ok(Via.into())
+            } else if eq!(b == b'd' b'n' b't') {
+                Ok(Dnt.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        4 => {
+            to_lower!(b, data, 4);
+
+            if eq!(b == b'd' b'a' b't' b'e') {
+                Ok(Date.into())
+            } else if eq!(b == b'e' b't' b'a' b'g') {
+                Ok(Etag.into())
+            } else if eq!(b == b'f' b'r' b'o' b'm') {
+                Ok(From.into())
+            } else if eq!(b == b'h' b'o' b's' b't') {
+                Ok(Host.into())
+            } else if eq!(b == b'l' b'i' b'n' b'k') {
+                Ok(Link.into())
+            } else if eq!(b == b'v' b'a' b'r' b'y') {
+                Ok(Vary.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        5 => {
+            to_lower!(b, data, 5);
+
+            if eq!(b == b'a' b'l' b'l' b'o' b'w') {
+                Ok(Allow.into())
+            } else if eq!(b == b'r' b'a' b'n' b'g' b'e') {
+                Ok(Range.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        6 => {
+            to_lower!(b, data, 6);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b'p' b't') {
+                return Ok(Accept.into())
+            } else if eq!(b == b'c' b'o' b'o' b'k' b'i' b'e') {
+                return Ok(Cookie.into())
+            } else if eq!(b == b'e' b'x' b'p' b'e' b'c' b't') {
+                return Ok(Expect.into())
+            } else if eq!(b == b'o' b'r' b'i' b'g' b'i' b'n') {
+                return Ok(Origin.into())
+            } else if eq!(b == b'p' b'r' b'a' b'g' b'm' b'a') {
+                return Ok(Pragma.into())
+            } else if b[0] == b's' {
+                if eq!(b[1] == b'e' b'r' b'v' b'e' b'r') {
+                    return Ok(Server.into())
+                }
+            }
+
+            validate(b, len)
+        }
+        7 => {
+            to_lower!(b, data, 7);
+
+            if eq!(b == b'a' b'l' b't' b'-' b's' b'v' b'c') {
+                Ok(AltSvc.into())
+            } else if eq!(b == b'e' b'x' b'p' b'i' b'r' b'e' b's') {
+                Ok(Expires.into())
+            } else if eq!(b == b'r' b'e' b'f' b'e' b'r' b'e' b'r') {
+                Ok(Referer.into())
+            } else if eq!(b == b'r' b'e' b'f' b'r' b'e' b's' b'h') {
+                Ok(Refresh.into())
+            } else if eq!(b == b't' b'r' b'a' b'i' b'l' b'e' b'r') {
+                Ok(Trailer.into())
+            } else if eq!(b == b'u' b'p' b'g' b'r' b'a' b'd' b'e') {
+                Ok(Upgrade.into())
+            } else if eq!(b == b'w' b'a' b'r' b'n' b'i' b'n' b'g') {
+                Ok(Warning.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        8 => {
+            to_lower!(b, data, 8);
+
+            if eq!(b == b'i' b'f' b'-') {
+                if eq!(b[3] == b'm' b'a' b't' b'c' b'h') {
+                    return Ok(IfMatch.into())
+                } else if eq!(b[3] == b'r' b'a' b'n' b'g' b'e') {
+                    return Ok(IfRange.into())
+                }
+            } else if eq!(b == b'l' b'o' b'c' b'a' b't' b'i' b'o' b'n') {
+                return Ok(Location.into())
+            }
+
+            validate(b, len)
+        }
+        9 => {
+            to_lower!(b, data, 9);
+
+            if eq!(b == b'f' b'o' b'r' b'w' b'a' b'r' b'd' b'e' b'd') {
+                Ok(Forwarded.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        10 => {
+            to_lower!(b, data, 10);
+
+            if eq!(b == b'c' b'o' b'n' b'n' b'e' b'c' b't' b'i' b'o' b'n') {
+                Ok(Connection.into())
+            } else if eq!(b == b's' b'e' b't' b'-' b'c' b'o' b'o' b'k' b'i' b'e') {
+                Ok(SetCookie.into())
+            } else if eq!(b == b'u' b's' b'e' b'r' b'-' b'a' b'g' b'e' b'n' b't') {
+                Ok(UserAgent.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        11 => {
+            to_lower!(b, data, 11);
+
+            if eq!(b == b'r' b'e' b't' b'r' b'y' b'-' b'a' b'f' b't' b'e' b'r') {
+                Ok(RetryAfter.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        12 => {
+            to_lower!(b, data, 12);
+
+            if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b't' b'y' b'p' b'e') {
+                Ok(ContentType.into())
+            } else if eq!(b == b'm' b'a' b'x' b'-' b'f' b'o' b'r' b'w' b'a' b'r' b'd' b's') {
+                Ok(MaxForwards.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        13 => {
+            to_lower!(b, data, 13);
+
+            if b[0] == b'a' {
+                if eq!(b[1] == b'c' b'c' b'e' b'p' b't' b'-' b'r' b'a' b'n' b'g' b'e' b's') {
+                    return Ok(AcceptRanges.into())
+                } else if eq!(b[1] == b'u' b't' b'h' b'o' b'r' b'i' b'z' b'a' b't' b'i' b'o' b'n') {
+                    return Ok(Authorization.into())
+                }
+            } else if b[0] == b'c' {
+                if eq!(b[1] == b'a' b'c' b'h' b'e' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l') {
+                    return Ok(CacheControl.into())
+                } else if eq!(b[1] == b'o' b'n' b't' b'e' b'n' b't' b'-' b'r' b'a' b'n' b'g' b'e' ) {
+                    return Ok(ContentRange.into())
+                }
+            } else if eq!(b == b'i' b'f' b'-' b'n' b'o' b'n' b'e' b'-' b'm' b'a' b't' b'c' b'h') {
+                return Ok(IfNoneMatch.into())
+            } else if eq!(b == b'l' b'a' b's' b't' b'-' b'm' b'o' b'd' b'i' b'f' b'i' b'e' b'd') {
+                return Ok(LastModified.into())
+            }
+
+            validate(b, len)
+        }
+        14 => {
+            to_lower!(b, data, 14);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b'p' b't' b'-' b'c' b'h' b'a' b'r' b's' b'e' b't') {
+                Ok(AcceptCharset.into())
+            } else if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b'l' b'e' b'n' b'g' b't' b'h') {
+                Ok(ContentLength.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        15 => {
+            to_lower!(b, data, 15);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b'p' b't' b'-') { // accept-
+                if eq!(b[7] == b'e' b'n' b'c' b'o' b'd' b'i' b'n' b'g') {
+                    return Ok(AcceptEncoding.into())
+                } else if eq!(b[7] == b'l' b'a' b'n' b'g' b'u' b'a' b'g' b'e') {
+                    return Ok(AcceptLanguage.into())
+                }
+            } else if eq!(b == b'p' b'u' b'b' b'l' b'i' b'c' b'-' b'k' b'e' b'y' b'-' b'p' b'i' b'n' b's') {
+                return Ok(PublicKeyPins.into())
+            } else if eq!(b == b'x' b'-' b'f' b'r' b'a' b'm' b'e' b'-' b'o' b'p' b't' b'i' b'o' b'n' b's') {
+                return Ok(XFrameOptions.into())
+            }
+            else if eq!(b == b'r' b'e' b'f' b'e' b'r' b'r' b'e' b'r' b'-' b'p' b'o' b'l' b'i' b'c' b'y') {
+                return Ok(ReferrerPolicy.into())
+            }
+
+            validate(b, len)
+        }
+        16 => {
+            to_lower!(b, data, 16);
+
+            if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-') {
+                if eq!(b[8] == b'l' b'a' b'n' b'g' b'u' b'a' b'g' b'e') {
+                    return Ok(ContentLanguage.into())
+                } else if eq!(b[8] == b'l' b'o' b'c' b'a' b't' b'i' b'o' b'n') {
+                    return Ok(ContentLocation.into())
+                } else if eq!(b[8] == b'e' b'n' b'c' b'o' b'd' b'i' b'n' b'g') {
+                    return Ok(ContentEncoding.into())
+                }
+            } else if eq!(b == b'w' b'w' b'w' b'-' b'a' b'u' b't' b'h' b'e' b'n' b't' b'i' b'c' b'a' b't' b'e') {
+                return Ok(WwwAuthenticate.into())
+            } else if eq!(b == b'x' b'-' b'x' b's' b's' b'-' b'p' b'r' b'o' b't' b'e' b'c' b't' b'i' b'o' b'n') {
+                return Ok(XXssProtection.into())
+            }
+
+            validate(b, len)
+        }
+        17 => {
+            to_lower!(b, data, 17);
+
+            if eq!(b == b't' b'r' b'a' b'n' b's' b'f' b'e' b'r' b'-' b'e' b'n' b'c' b'o' b'd' b'i' b'n' b'g') {
+                Ok(TransferEncoding.into())
+            } else if eq!(b == b'i' b'f' b'-' b'm' b'o' b'd' b'i' b'f' b'i' b'e' b'd' b'-' b's' b'i' b'n' b'c' b'e') {
+                Ok(IfModifiedSince.into())
+            } else if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'k' b'e' b'y') {
+                Ok(SecWebSocketKey.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        18 => {
+            to_lower!(b, data, 18);
+
+            if eq!(b == b'p' b'r' b'o' b'x' b'y' b'-' b'a' b'u' b't' b'h' b'e' b'n' b't' b'i' b'c' b'a' b't' b'e') {
+                Ok(ProxyAuthenticate.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        19 => {
+            to_lower!(b, data, 19);
+
+            if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b'd' b'i' b's' b'p' b'o' b's' b'i' b't' b'i' b'o' b'n') {
+                Ok(ContentDisposition.into())
+            } else if eq!(b == b'i' b'f' b'-' b'u' b'n' b'm' b'o' b'd' b'i' b'f' b'i' b'e' b'd' b'-' b's' b'i' b'n' b'c' b'e') {
+                Ok(IfUnmodifiedSince.into())
+            } else if eq!(b == b'p' b'r' b'o' b'x' b'y' b'-' b'a' b'u' b't' b'h' b'o' b'r' b'i' b'z' b'a' b't' b'i' b'o' b'n') {
+                Ok(ProxyAuthorization.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        20 => {
+            to_lower!(b, data, 20);
+
+            if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'a' b'c' b'c' b'e' b'p' b't') {
+                Ok(SecWebSocketAccept.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        21 => {
+            to_lower!(b, data, 21);
+
+            if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'v' b'e' b'r' b's' b'i' b'o' b'n') {
+                Ok(SecWebSocketVersion.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        22 => {
+            to_lower!(b, data, 22);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'm' b'a' b'x' b'-' b'a' b'g' b'e') {
+                Ok(AccessControlMaxAge.into())
+            } else if eq!(b == b'x' b'-' b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b't' b'y' b'p' b'e' b'-' b'o' b'p' b't' b'i' b'o' b'n' b's') {
+                Ok(XContentTypeOptions.into())
+            } else if eq!(b == b'x' b'-' b'd' b'n' b's' b'-' b'p' b'r' b'e' b'f' b'e' b't' b'c' b'h' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l') {
+                Ok(XDnsPrefetchControl.into())
+            } else if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'p' b'r' b'o' b't' b'o' b'c' b'o' b'l') {
+                Ok(SecWebSocketProtocol.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        23 => {
+            to_lower!(b, data, 23);
+
+            if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b's' b'e' b'c' b'u' b'r' b'i' b't' b'y' b'-' b'p' b'o' b'l' b'i' b'c' b'y') {
+                Ok(ContentSecurityPolicy.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        24 => {
+            to_lower!(b, data, 24);
+
+            if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'e' b'x' b't' b'e' b'n' b's' b'i' b'o' b'n' b's') {
+                Ok(SecWebSocketExtensions.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        25 => {
+            to_lower!(b, data, 25);
+
+            if eq!(b == b's' b't' b'r' b'i' b'c' b't' b'-' b't' b'r' b'a' b'n' b's' b'p' b'o' b'r' b't' b'-' b's' b'e' b'c' b'u' b'r' b'i' b't' b'y') {
+                Ok(StrictTransportSecurity.into())
+            } else if eq!(b == b'u' b'p' b'g' b'r' b'a' b'd' b'e' b'-' b'i' b'n' b's' b'e' b'c' b'u' b'r' b'e' b'-' b'r' b'e' b'q' b'u' b'e' b's' b't' b's') {
+                Ok(UpgradeInsecureRequests.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        27 => {
+            to_lower!(b, data, 27);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'a' b'l' b'l' b'o' b'w' b'-' b'o' b'r' b'i' b'g' b'i' b'n') {
+                Ok(AccessControlAllowOrigin.into())
+            } else if eq!(b == b'p' b'u' b'b' b'l' b'i' b'c' b'-' b'k' b'e' b'y' b'-' b'p' b'i' b'n' b's' b'-' b'r' b'e' b'p' b'o' b'r' b't' b'-' b'o' b'n' b'l' b'y') {
+                Ok(PublicKeyPinsReportOnly.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        28 => {
+            to_lower!(b, data, 28);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'a' b'l' b'l' b'o' b'w' b'-') {
+                if eq!(b[21] == b'h' b'e' b'a' b'd' b'e' b'r' b's') {
+                    return Ok(AccessControlAllowHeaders.into())
+                } else if eq!(b[21] == b'm' b'e' b't' b'h' b'o' b'd' b's') {
+                    return Ok(AccessControlAllowMethods.into())
+                }
+            }
+
+            validate(b, len)
+        }
+        29 => {
+            to_lower!(b, data, 29);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-') {
+                if eq!(b[15] == b'e' b'x' b'p' b'o' b's' b'e' b'-' b'h' b'e' b'a' b'd' b'e' b'r' b's') {
+                    return Ok(AccessControlExposeHeaders.into())
+                } else if eq!(b[15] == b'r' b'e' b'q' b'u' b'e' b's' b't' b'-' b'm' b'e' b't' b'h' b'o' b'd') {
+                    return Ok(AccessControlRequestMethod.into())
+                }
+            }
+
+            validate(b, len)
+        }
+        30 => {
+            to_lower!(b, data, 30);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'r' b'e' b'q' b'u' b'e' b's' b't' b'-' b'h' b'e' b'a' b'd' b'e' b'r' b's') {
+                Ok(AccessControlRequestHeaders.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        32 => {
+            to_lower!(b, data, 32);
+
+            if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'a' b'l' b'l' b'o' b'w' b'-' b'c' b'r' b'e' b'd' b'e' b'n' b't' b'i' b'a' b'l' b's') {
+                Ok(AccessControlAllowCredentials.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        35 => {
+            to_lower!(b, data, 35);
+
+            if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b's' b'e' b'c' b'u' b'r' b'i' b't' b'y' b'-' b'p' b'o' b'l' b'i' b'c' b'y' b'-' b'r' b'e' b'p' b'o' b'r' b't' b'-' b'o' b'n' b'l' b'y') {
+                Ok(ContentSecurityPolicyReportOnly.into())
+            } else {
+                validate(b, len)
+            }
+        }
+        _ => {
+            if len < 64 {
+                for i in 0..len {
+                    b[i] = table[data[i] as usize];
+                }
+
+                validate(b, len)
+            } else {
+                Ok(HdrName::custom(data, false))
+            }
+        }
+    }
+}
+
+impl<'a> From<StandardHeader> for HdrName<'a> {
+    fn from(hdr: StandardHeader) -> HdrName<'a> {
+        HdrName { inner: Repr::Standard(hdr) }
+    }
+}
+
+impl HeaderName {
+    /// Converts a slice of bytes to an HTTP header name.
+    ///
+    /// This function normalizes the input.
+    pub fn from_bytes(src: &[u8]) -> Result<HeaderName, InvalidHeaderName> {
+        let mut buf = unsafe { mem::uninitialized() };
+        match parse_hdr(src, &mut buf, &HEADER_CHARS)?.inner {
+            Repr::Standard(std) => Ok(std.into()),
+            Repr::Custom(MaybeLower { buf, lower: true }) => {
+                let buf = Bytes::from(buf);
+                let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
+                Ok(Custom(val).into())
+            }
+            Repr::Custom(MaybeLower { buf, lower: false }) => {
+                use bytes::{BufMut};
+                let mut dst = BytesMut::with_capacity(buf.len());
+
+                for b in buf.iter() {
+                    let b = HEADER_CHARS[*b as usize];
+
+                    if b == 0 {
+                        return Err(InvalidHeaderName::new());
+                    }
+
+                    dst.put(b);
+                }
+
+                let val = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) };
+
+                Ok(Custom(val).into())
+            }
+        }
+    }
+
+    /// Converts a slice of bytes to an HTTP header name.
+    ///
+    /// This function expects the input to only contain lowercase characters.
+    /// This is useful when decoding HTTP/2.0 headers. The HTTP/2.0
+    /// specification requires that all headers be represented in lower case.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::*;
+    ///
+    /// // Parsing a lower case header
+    /// let hdr = HeaderName::from_lowercase(b"content-length").unwrap();
+    /// assert_eq!(CONTENT_LENGTH, hdr);
+    ///
+    /// // Parsing a header that contains uppercase characters
+    /// assert!(HeaderName::from_lowercase(b"Content-Length").is_err());
+    /// ```
+    pub fn from_lowercase(src: &[u8]) -> Result<HeaderName, InvalidHeaderName> {
+        let mut buf = unsafe { mem::uninitialized() };
+        match parse_hdr(src, &mut buf, &HEADER_CHARS_H2)?.inner {
+            Repr::Standard(std) => Ok(std.into()),
+            Repr::Custom(MaybeLower { buf, lower: true }) => {
+                let buf = Bytes::from(buf);
+                let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
+                Ok(Custom(val).into())
+            }
+            Repr::Custom(MaybeLower { buf, lower: false }) => {
+                for &b in buf.iter() {
+                    if b != HEADER_CHARS[b as usize] {
+                        return Err(InvalidHeaderName::new());
+                    }
+                }
+
+                let buf = Bytes::from(buf);
+                let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
+                Ok(Custom(val).into())
+            }
+        }
+    }
+
+    /// Converts a static string to a HTTP header name.
+    ///
+    /// This function panics when the static string is a invalid header.
+    /// 
+    /// This function requires the static string to only contain lowercase 
+    /// characters, numerals and symbols, as per the HTTP/2.0 specification 
+    /// and header names internal representation within this library.
+    /// 
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::*;
+    /// // Parsing a standard header
+    /// let hdr = HeaderName::from_static("content-length");
+    /// assert_eq!(CONTENT_LENGTH, hdr);
+    /// 
+    /// // Parsing a custom header
+    /// let CUSTOM_HEADER: &'static str = "custom-header";
+    /// 
+    /// let a = HeaderName::from_lowercase(b"custom-header").unwrap();
+    /// let b = HeaderName::from_static(CUSTOM_HEADER);
+    /// assert_eq!(a, b);
+    /// ```
+    /// 
+    /// ```should_panic
+    /// # use http::header::*;
+    /// #
+    /// // Parsing a header that contains invalid symbols(s):
+    /// HeaderName::from_static("content{}{}length"); // This line panics!
+    /// 
+    /// // Parsing a header that contains invalid uppercase characters.
+    /// let a = HeaderName::from_static("foobar");
+    /// let b = HeaderName::from_static("FOOBAR"); // This line panics!
+    /// ```
+    pub fn from_static(src: &'static str) -> HeaderName {
+        let bytes = src.as_bytes();
+        let mut buf = unsafe { mem::uninitialized() };
+        match parse_hdr(bytes, &mut buf, &HEADER_CHARS_H2) {
+            Ok(hdr_name) => match hdr_name.inner {
+                Repr::Standard(std) => std.into(),
+                Repr::Custom(MaybeLower { buf: _, lower: true }) => {
+                    let val = ByteStr::from_static(src);
+                    Custom(val).into()
+                },
+                Repr::Custom(MaybeLower { buf: _, lower: false }) => {
+                    // With lower false, the string is left unchecked by
+                    // parse_hdr and must be validated manually.
+                    for &b in bytes.iter() {
+                        if HEADER_CHARS_H2[b as usize] == 0 {
+                            panic!("invalid header name")
+                        }
+                    }
+
+                    let val = ByteStr::from_static(src);
+                    Custom(val).into()
+                }
+            },
+
+            Err(_) => panic!("invalid header name")
+        }
+    }
+
+    /// Returns a `str` representation of the header.
+    ///
+    /// The returned string will always be lower case.
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        match self.inner {
+            Repr::Standard(v) => v.as_str(),
+            Repr::Custom(ref v) => &*v.0,
+        }
+    }
+}
+
+impl FromStr for HeaderName {
+    type Err = InvalidHeaderName;
+
+    fn from_str(s: &str) -> Result<HeaderName, InvalidHeaderName> {
+        HeaderName::from_bytes(s.as_bytes())
+            .map_err(|_| InvalidHeaderName {
+                _priv: (),
+            })
+    }
+}
+
+impl AsRef<str> for HeaderName {
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl AsRef<[u8]> for HeaderName {
+    fn as_ref(&self) -> &[u8] {
+        self.as_str().as_bytes()
+    }
+}
+
+impl Borrow<str> for HeaderName {
+    fn borrow(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl fmt::Debug for HeaderName {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(self.as_str(), fmt)
+    }
+}
+
+impl InvalidHeaderName {
+    fn new() -> InvalidHeaderName {
+        InvalidHeaderName { _priv: () }
+    }
+}
+
+impl<'a> From<&'a HeaderName> for HeaderName {
+    fn from(src: &'a HeaderName) -> HeaderName {
+        src.clone()
+    }
+}
+
+#[doc(hidden)]
+impl<T> From<Repr<T>> for Bytes
+where T: Into<Bytes> {
+    fn from(repr: Repr<T>) -> Bytes {
+        match repr {
+            Repr::Standard(header) =>
+                Bytes::from_static(header.as_str().as_bytes()),
+            Repr::Custom(header) => header.into()
+        }
+    }
+}
+
+impl From<Custom> for Bytes {
+    #[inline]
+    fn from(Custom(inner): Custom) -> Bytes {
+        Bytes::from(inner)
+    }
+}
+
+impl From<HeaderName> for Bytes {
+    #[inline]
+    fn from(name: HeaderName) -> Bytes {
+        name.inner.into()
+    }
+}
+
+impl<'a> HttpTryFrom<&'a str> for HeaderName {
+    type Error = InvalidHeaderName;
+    #[inline]
+    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
+        Self::from_bytes(s.as_bytes())
+    }
+}
+
+impl<'a> HttpTryFrom<&'a [u8]> for HeaderName {
+    type Error = InvalidHeaderName;
+    #[inline]
+    fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
+        Self::from_bytes(s)
+    }
+}
+
+impl HttpTryFrom<Bytes> for HeaderName {
+    type Error = InvalidHeaderNameBytes;
+    #[inline]
+    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
+        Self::from_bytes(bytes.as_ref()).map_err(InvalidHeaderNameBytes)
+    }
+}
+
+#[doc(hidden)]
+impl From<StandardHeader> for HeaderName {
+    fn from(src: StandardHeader) -> HeaderName {
+        HeaderName {
+            inner: Repr::Standard(src),
+        }
+    }
+}
+
+#[doc(hidden)]
+impl From<Custom> for HeaderName {
+    fn from(src: Custom) -> HeaderName {
+        HeaderName { inner: Repr::Custom(src) }
+    }
+}
+
+impl<'a> PartialEq<&'a HeaderName> for HeaderName {
+    #[inline]
+    fn eq(&self, other: &&'a HeaderName) -> bool {
+        *self == **other
+    }
+}
+
+
+impl<'a> PartialEq<HeaderName> for &'a HeaderName {
+    #[inline]
+    fn eq(&self, other: &HeaderName) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialEq<str> for HeaderName {
+    /// Performs a case-insensitive comparison of the string against the header
+    /// name
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use http::header::CONTENT_LENGTH;
+    ///
+    /// assert_eq!(CONTENT_LENGTH, "content-length");
+    /// assert_eq!(CONTENT_LENGTH, "Content-Length");
+    /// assert_ne!(CONTENT_LENGTH, "content length");
+    /// ```
+    #[inline]
+    fn eq(&self, other: &str) -> bool {
+        eq_ignore_ascii_case(self.as_ref(), other.as_bytes())
+    }
+}
+
+
+impl PartialEq<HeaderName> for str {
+    /// Performs a case-insensitive comparison of the string against the header
+    /// name
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use http::header::CONTENT_LENGTH;
+    ///
+    /// assert_eq!(CONTENT_LENGTH, "content-length");
+    /// assert_eq!(CONTENT_LENGTH, "Content-Length");
+    /// assert_ne!(CONTENT_LENGTH, "content length");
+    /// ```
+    #[inline]
+    fn eq(&self, other: &HeaderName) -> bool {
+        *other == *self
+    }
+}
+
+impl<'a> PartialEq<&'a str> for HeaderName {
+    /// Performs a case-insensitive comparison of the string against the header
+    /// name
+    #[inline]
+    fn eq(&self, other: &&'a str) -> bool {
+        *self == **other
+    }
+}
+
+
+impl<'a> PartialEq<HeaderName> for &'a str {
+    /// Performs a case-insensitive comparison of the string against the header
+    /// name
+    #[inline]
+    fn eq(&self, other: &HeaderName) -> bool {
+        *other == *self
+    }
+}
+
+impl fmt::Display for InvalidHeaderName {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.description().fmt(f)
+    }
+}
+
+impl Error for InvalidHeaderName {
+    fn description(&self) -> &str {
+        "invalid HTTP header name"
+    }
+}
+
+impl fmt::Display for InvalidHeaderNameBytes {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl Error for InvalidHeaderNameBytes {
+    fn description(&self) -> &str {
+        self.0.description()
+    }
+}
+
+// ===== HdrName =====
+
+impl<'a> HdrName<'a> {
+    fn custom(buf: &'a [u8], lower: bool) -> HdrName<'a> {
+        HdrName {
+            inner: Repr::Custom(MaybeLower {
+                buf: buf,
+                lower: lower,
+            }),
+        }
+    }
+
+    pub fn from_bytes<F, U>(hdr: &[u8], f: F) -> Result<U, InvalidHeaderName>
+        where F: FnOnce(HdrName) -> U,
+    {
+        let mut buf = unsafe { mem::uninitialized() };
+        let hdr = parse_hdr(hdr, &mut buf, &HEADER_CHARS)?;
+        Ok(f(hdr))
+    }
+
+    pub fn from_static<F, U>(hdr: &'static str, f: F) -> U
+        where F: FnOnce(HdrName) -> U,
+    {
+        let mut buf = unsafe { mem::uninitialized() };
+        let hdr = parse_hdr(hdr.as_bytes(), &mut buf, &HEADER_CHARS)
+            .expect("static str is invalid name");
+        f(hdr)
+    }
+}
+
+#[doc(hidden)]
+impl<'a> From<HdrName<'a>> for HeaderName {
+    fn from(src: HdrName<'a>) -> HeaderName {
+        match src.inner {
+            Repr::Standard(s) => {
+                HeaderName {
+                    inner: Repr::Standard(s),
+                }
+            }
+            Repr::Custom(maybe_lower) => {
+                if maybe_lower.lower {
+                    let buf = Bytes::from(&maybe_lower.buf[..]);
+                    let byte_str = unsafe { ByteStr::from_utf8_unchecked(buf) };
+
+                    HeaderName {
+                        inner: Repr::Custom(Custom(byte_str)),
+                    }
+                } else {
+                    use bytes::{BufMut};
+                    let mut dst = BytesMut::with_capacity(maybe_lower.buf.len());
+
+                    for b in maybe_lower.buf.iter() {
+                        dst.put(HEADER_CHARS[*b as usize]);
+                    }
+
+                    let buf = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) };
+
+                    HeaderName {
+                        inner: Repr::Custom(Custom(buf)),
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[doc(hidden)]
+impl<'a> PartialEq<HdrName<'a>> for HeaderName {
+    #[inline]
+    fn eq(&self, other: &HdrName<'a>) -> bool {
+        match self.inner {
+            Repr::Standard(a) => {
+                match other.inner {
+                    Repr::Standard(b) => a == b,
+                    _ => false,
+                }
+            }
+            Repr::Custom(Custom(ref a)) => {
+                match other.inner {
+                    Repr::Custom(ref b) => {
+                        if b.lower {
+                            a.as_bytes() == b.buf
+                        } else {
+                            eq_ignore_ascii_case(a.as_bytes(), b.buf)
+                        }
+                    }
+                    _ => false,
+                }
+            }
+        }
+    }
+}
+
+// ===== Custom =====
+
+impl Hash for Custom {
+    #[inline]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        hasher.write(self.0.as_bytes())
+    }
+}
+
+// ===== MaybeLower =====
+
+impl<'a> Hash for MaybeLower<'a> {
+    #[inline]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        if self.lower {
+            hasher.write(self.buf);
+        } else {
+            for &b in self.buf {
+                hasher.write(&[HEADER_CHARS[b as usize]]);
+            }
+        }
+    }
+}
+
+// Assumes that the left hand side is already lower case
+#[inline]
+fn eq_ignore_ascii_case(lower: &[u8], s: &[u8]) -> bool {
+    if lower.len() != s.len() {
+        return false;
+    }
+
+    lower.iter().zip(s).all(|(a, b)| {
+        *a == HEADER_CHARS[*b as usize]
+    })
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use self::StandardHeader::Vary;
+
+    #[test]
+    fn test_bounds() {
+        fn check_bounds<T: Sync + Send>() {}
+        check_bounds::<HeaderName>();
+    }
+
+    #[test]
+    fn test_parse_invalid_headers() {
+        for i in 0..128 {
+            let hdr = vec![1u8; i];
+            assert!(HeaderName::from_bytes(&hdr).is_err(), "{} invalid header chars did not fail", i);
+        }
+    }
+
+    #[test]
+    fn test_from_hdr_name() {
+        use self::StandardHeader::Vary;
+
+        let name = HeaderName::from(HdrName {
+            inner: Repr::Standard(Vary),
+        });
+
+        assert_eq!(name.inner, Repr::Standard(Vary));
+
+        let name = HeaderName::from(HdrName {
+            inner: Repr::Custom(MaybeLower {
+                buf: b"hello-world",
+                lower: true,
+            }),
+        });
+
+        assert_eq!(name.inner, Repr::Custom(Custom(ByteStr::from_static("hello-world"))));
+
+        let name = HeaderName::from(HdrName {
+            inner: Repr::Custom(MaybeLower {
+                buf: b"Hello-World",
+                lower: false,
+            }),
+        });
+
+        assert_eq!(name.inner, Repr::Custom(Custom(ByteStr::from_static("hello-world"))));
+    }
+
+    #[test]
+    fn test_eq_hdr_name() {
+        use self::StandardHeader::Vary;
+
+        let a = HeaderName { inner: Repr::Standard(Vary) };
+        let b = HdrName { inner: Repr::Standard(Vary) };
+
+        assert_eq!(a, b);
+
+        let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static("vaary"))) };
+        assert_ne!(a, b);
+
+        let b = HdrName { inner: Repr::Custom(MaybeLower {
+            buf: b"vaary",
+            lower: true,
+        })};
+
+        assert_eq!(a, b);
+
+        let b = HdrName { inner: Repr::Custom(MaybeLower {
+            buf: b"vaary",
+            lower: false,
+        })};
+
+        assert_eq!(a, b);
+
+        let b = HdrName { inner: Repr::Custom(MaybeLower {
+            buf: b"VAARY",
+            lower: false,
+        })};
+
+        assert_eq!(a, b);
+
+        let a = HeaderName { inner: Repr::Standard(Vary) };
+        assert_ne!(a, b);
+    }
+
+    #[test]
+    fn test_from_static_std() {
+        let a = HeaderName { inner: Repr::Standard(Vary) };
+        
+        let b = HeaderName::from_static("vary");
+        assert_eq!(a, b);
+
+        let b = HeaderName::from_static("vaary");
+        assert_ne!(a, b);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_from_static_std_uppercase() {
+        HeaderName::from_static("Vary");
+    } 
+
+    #[test]
+    #[should_panic]
+    fn test_from_static_std_symbol() {
+        HeaderName::from_static("vary{}");
+    } 
+
+    // MaybeLower { lower: true }
+    #[test]
+    fn test_from_static_custom_short() {
+        let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static("customheader"))) };
+        let b = HeaderName::from_static("customheader");
+        assert_eq!(a, b);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_from_static_custom_short_uppercase() {
+        HeaderName::from_static("custom header");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_from_static_custom_short_symbol() {
+        HeaderName::from_static("CustomHeader");
+    }
+
+    // MaybeLower { lower: false }
+    #[test]
+    fn test_from_static_custom_long() {
+        let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static(
+            "longer-than-63--thisheaderislongerthansixtythreecharactersandthushandleddifferent"
+        ))) };
+        let b = HeaderName::from_static(
+            "longer-than-63--thisheaderislongerthansixtythreecharactersandthushandleddifferent"
+        );
+        assert_eq!(a, b);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_from_static_custom_long_uppercase() {
+        HeaderName::from_static(
+            "Longer-Than-63--ThisHeaderIsLongerThanSixtyThreeCharactersAndThusHandledDifferent"
+        );
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_from_static_custom_long_symbol() {
+        HeaderName::from_static(
+            "longer-than-63--thisheader{}{}{}{}islongerthansixtythreecharactersandthushandleddifferent"
+        );
+    }
+
+    #[test]
+    fn test_from_static_custom_single_char() {
+        let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static("a"))) };
+        let b = HeaderName::from_static("a");
+        assert_eq!(a, b);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_from_static_empty() {
+        HeaderName::from_static("");
+    }   
+}
\ No newline at end of file
diff --git a/third_party/http/src/header/value.rs b/third_party/http/src/header/value.rs
new file mode 100644
index 0000000..7813ac8
--- /dev/null
+++ b/third_party/http/src/header/value.rs
@@ -0,0 +1,762 @@
+use bytes::{Bytes, BytesMut};
+
+use std::prelude::v1::*;
+use std::{cmp, fmt, mem, str};
+use std::error::Error;
+use std::str::FromStr;
+
+use ::convert::HttpTryFrom;
+use ::error::Never;
+use header::name::HeaderName;
+
+/// Represents an HTTP header field value.
+///
+/// In practice, HTTP header field values are usually valid ASCII. However, the
+/// HTTP spec allows for a header value to contain opaque bytes as well. In this
+/// case, the header field value is not able to be represented as a string.
+///
+/// To handle this, the `HeaderValue` is useable as a type and can be compared
+/// with strings and implements `Debug`. A `to_str` fn is provided that returns
+/// an `Err` if the header value contains non visible ascii characters.
+#[derive(Clone, Hash)]
+pub struct HeaderValue {
+    inner: Bytes,
+    is_sensitive: bool,
+}
+
+/// A possible error when converting a `HeaderValue` from a string or byte
+/// slice.
+#[derive(Debug)]
+pub struct InvalidHeaderValue {
+    _priv: (),
+}
+
+/// A possible error when converting a `HeaderValue` from a string or byte
+/// slice.
+#[derive(Debug)]
+pub struct InvalidHeaderValueBytes(InvalidHeaderValue);
+
+/// A possible error when converting a `HeaderValue` to a string representation.
+///
+/// Header field values may contain opaque bytes, in which case it is not
+/// possible to represent the value as a string.
+#[derive(Debug)]
+pub struct ToStrError {
+    _priv: (),
+}
+
+impl HeaderValue {
+    /// Convert a static string to a `HeaderValue`.
+    ///
+    /// This function will not perform any copying, however the string is
+    /// checked to ensure that no invalid characters are present. Only visible
+    /// ASCII characters (32-127) are permitted.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if the argument contains invalid header value
+    /// characters.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_static("hello");
+    /// assert_eq!(val, "hello");
+    /// ```
+    #[inline]
+    pub fn from_static(src: &'static str) -> HeaderValue {
+        let bytes = src.as_bytes();
+        for &b in bytes {
+            if !is_visible_ascii(b) {
+                panic!("invalid header value");
+            }
+        }
+
+        HeaderValue {
+            inner: Bytes::from_static(bytes),
+            is_sensitive: false,
+        }
+    }
+
+    /// Attempt to convert a string to a `HeaderValue`.
+    ///
+    /// If the argument contains invalid header value characters, an error is
+    /// returned. Only visible ASCII characters (32-127) are permitted. Use
+    /// `from_bytes` to create a `HeaderValue` that includes opaque octets
+    /// (128-255).
+    ///
+    /// This function is intended to be replaced in the future by a `TryFrom`
+    /// implementation once the trait is stabilized in std.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_str("hello").unwrap();
+    /// assert_eq!(val, "hello");
+    /// ```
+    ///
+    /// An invalid value
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_str("\n");
+    /// assert!(val.is_err());
+    /// ```
+    #[inline]
+    pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
+        HeaderValue::try_from(src)
+    }
+
+    /// Converts a HeaderName into a HeaderValue
+    ///
+    /// Since every valid HeaderName is a valid HeaderValue this is done infallibly.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::{HeaderValue, HeaderName};
+    /// # use http::header::ACCEPT;
+    /// let val = HeaderValue::from_name(ACCEPT);
+    /// assert_eq!(val, HeaderValue::from_bytes(b"accept").unwrap());
+    /// ```
+    #[inline]
+    pub fn from_name(name: HeaderName) -> HeaderValue {
+        name.into()
+    }
+
+    /// Attempt to convert a byte slice to a `HeaderValue`.
+    ///
+    /// If the argument contains invalid header value bytes, an error is
+    /// returned. Only byte values between 32 and 255 (inclusive) are permitted,
+    /// excluding byte 127 (DEL).
+    ///
+    /// This function is intended to be replaced in the future by a `TryFrom`
+    /// implementation once the trait is stabilized in std.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_bytes(b"hello\xfa").unwrap();
+    /// assert_eq!(val, &b"hello\xfa"[..]);
+    /// ```
+    ///
+    /// An invalid value
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_bytes(b"\n");
+    /// assert!(val.is_err());
+    /// ```
+    #[inline]
+    pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
+        HeaderValue::try_from(src)
+    }
+
+    /// Attempt to convert a `Bytes` buffer to a `HeaderValue`.
+    ///
+    /// If the argument contains invalid header value bytes, an error is
+    /// returned. Only byte values between 32 and 255 (inclusive) are permitted,
+    /// excluding byte 127 (DEL).
+    ///
+    /// This function is intended to be replaced in the future by a `TryFrom`
+    /// implementation once the trait is stabilized in std.
+    #[inline]
+    pub fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValueBytes> {
+        HeaderValue::try_from(src).map_err(InvalidHeaderValueBytes)
+    }
+
+    /// Convert a `Bytes` directly into a `HeaderValue` without validating.
+    ///
+    /// This function does NOT validate that illegal bytes are not contained
+    /// within the buffer.
+    #[inline]
+    pub unsafe fn from_shared_unchecked(src: Bytes) -> HeaderValue {
+        HeaderValue {
+            inner: src,
+            is_sensitive: false,
+        }
+    }
+
+    fn try_from<T: AsRef<[u8]> + Into<Bytes>>(src: T) -> Result<HeaderValue, InvalidHeaderValue> {
+        for &b in src.as_ref() {
+            if !is_valid(b) {
+                return Err(InvalidHeaderValue {
+                    _priv: (),
+                });
+            }
+        }
+        Ok(HeaderValue {
+            inner: src.into(),
+            is_sensitive: false,
+        })
+    }
+
+    /// Yields a `&str` slice if the `HeaderValue` only contains visible ASCII
+    /// chars.
+    ///
+    /// This function will perform a scan of the header value, checking all the
+    /// characters.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_static("hello");
+    /// assert_eq!(val.to_str().unwrap(), "hello");
+    /// ```
+    pub fn to_str(&self) -> Result<&str, ToStrError> {
+        let bytes = self.as_ref();
+
+        for &b in bytes {
+            if !is_visible_ascii(b) {
+                return Err(ToStrError { _priv: () });
+            }
+        }
+
+        unsafe { Ok(str::from_utf8_unchecked(bytes)) }
+    }
+
+    /// Returns the length of `self`.
+    ///
+    /// This length is in bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_static("hello");
+    /// assert_eq!(val.len(), 5);
+    /// ```
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.as_ref().len()
+    }
+
+    /// Returns true if the `HeaderValue` has a length of zero bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_static("");
+    /// assert!(val.is_empty());
+    ///
+    /// let val = HeaderValue::from_static("hello");
+    /// assert!(!val.is_empty());
+    /// ```
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Converts a `HeaderValue` to a byte slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let val = HeaderValue::from_static("hello");
+    /// assert_eq!(val.as_bytes(), b"hello");
+    /// ```
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        self.as_ref()
+    }
+
+    /// Mark that the header value represents sensitive information.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let mut val = HeaderValue::from_static("my secret");
+    ///
+    /// val.set_sensitive(true);
+    /// assert!(val.is_sensitive());
+    ///
+    /// val.set_sensitive(false);
+    /// assert!(!val.is_sensitive());
+    /// ```
+    #[inline]
+    pub fn set_sensitive(&mut self, val: bool) {
+        self.is_sensitive = val;
+    }
+
+    /// Returns `true` if the value represents sensitive data.
+    ///
+    /// Sensitive data could represent passwords or other data that should not
+    /// be stored on disk or in memory. This setting can be used by components
+    /// like caches to avoid storing the value. HPACK encoders must set the
+    /// header field to never index when `is_sensitive` returns true.
+    ///
+    /// Note that sensitivity is not factored into equality or ordering.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::header::HeaderValue;
+    /// let mut val = HeaderValue::from_static("my secret");
+    ///
+    /// val.set_sensitive(true);
+    /// assert!(val.is_sensitive());
+    ///
+    /// val.set_sensitive(false);
+    /// assert!(!val.is_sensitive());
+    /// ```
+    #[inline]
+    pub fn is_sensitive(&self) -> bool {
+        self.is_sensitive
+    }
+}
+
+impl AsRef<[u8]> for HeaderValue {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        self.inner.as_ref()
+    }
+}
+
+impl fmt::Debug for HeaderValue {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.is_sensitive {
+            f.write_str("Sensitive")
+        } else {
+            f.write_str("\"")?;
+            let mut from = 0;
+            let bytes = self.as_bytes();
+            for (i, &b) in bytes.iter().enumerate() {
+                if !is_visible_ascii(b) || b == b'"' {
+                    if from != i {
+                        f.write_str(unsafe {
+                            str::from_utf8_unchecked(&bytes[from..i])
+                        })?;
+                    }
+                    if b == b'"' {
+                        f.write_str("\\\"")?;
+                    } else {
+                        write!(f, "\\x{:x}", b)?;
+                    }
+                    from = i + 1;
+                }
+            }
+
+            f.write_str(unsafe {
+                str::from_utf8_unchecked(&bytes[from..])
+            })?;
+            f.write_str("\"")
+        }
+    }
+}
+
+impl From<HeaderName> for HeaderValue {
+    #[inline]
+    fn from(h: HeaderName) -> HeaderValue {
+        HeaderValue {
+            inner: h.into(),
+            is_sensitive: false,
+        }
+    }
+}
+
+macro_rules! from_integers {
+    ($($name:ident: $t:ident => $max_len:expr),*) => {$(
+        impl From<$t> for HeaderValue {
+            fn from(num: $t) -> HeaderValue {
+                let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
+                    // On 32bit platforms, BytesMut max inline size
+                    // is 15 bytes, but the $max_len could be bigger.
+                    //
+                    // The likelihood of the number *actually* being
+                    // that big is very small, so only allocate
+                    // if the number needs that space.
+                    //
+                    // The largest decimal number in 15 digits:
+                    // It wold be 10.pow(15) - 1, but this is a constant
+                    // version.
+                    if num as u64 > 999_999_999_999_999_999 {
+                        BytesMut::with_capacity($max_len)
+                    } else {
+                        // fits inline...
+                        BytesMut::new()
+                    }
+                } else {
+                    // full value fits inline, so don't allocate!
+                    BytesMut::new()
+                };
+                let _ = ::itoa::fmt(&mut buf, num);
+                HeaderValue {
+                    inner: buf.freeze(),
+                    is_sensitive: false,
+                }
+            }
+        }
+
+        impl HttpTryFrom<$t> for HeaderValue {
+            type Error = Never;
+
+            #[inline]
+            fn try_from(num: $t) -> Result<Self, Self::Error> {
+                Ok(num.into())
+            }
+        }
+
+        #[test]
+        fn $name() {
+            let n: $t = 55;
+            let val = HeaderValue::from(n);
+            assert_eq!(val, &n.to_string());
+
+            let n = ::std::$t::MAX;
+            let val = HeaderValue::from(n);
+            assert_eq!(val, &n.to_string());
+        }
+    )*};
+}
+
+from_integers! {
+    // integer type => maximum decimal length
+
+    // u8 purposely left off... HeaderValue::from(b'3') could be confusing
+    from_u16: u16 => 5,
+    from_i16: i16 => 6,
+    from_u32: u32 => 10,
+    from_i32: i32 => 11,
+    from_u64: u64 => 20,
+    from_i64: i64 => 20
+}
+
+#[cfg(target_pointer_width = "16")]
+from_integers! {
+    from_usize: usize => 5,
+    from_isize: isize => 6
+}
+
+#[cfg(target_pointer_width = "32")]
+from_integers! {
+    from_usize: usize => 10,
+    from_isize: isize => 11
+}
+
+#[cfg(target_pointer_width = "64")]
+from_integers! {
+    from_usize: usize => 20,
+    from_isize: isize => 20
+}
+
+#[cfg(test)]
+mod from_header_name_tests {
+    use super::*;
+    use header::map::HeaderMap;
+    use header::name;
+
+    #[test]
+    fn it_can_insert_header_name_as_header_value() {
+        let mut map = HeaderMap::new();
+        map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
+        map.insert(name::ACCEPT, name::HeaderName::from_bytes(b"hello-world").unwrap().into());
+
+        assert_eq!(
+            map.get(name::UPGRADE).unwrap(),
+            HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
+        );
+
+        assert_eq!(
+            map.get(name::ACCEPT).unwrap(),
+            HeaderValue::from_bytes(b"hello-world").unwrap()
+        );
+    }
+}
+
+impl FromStr for HeaderValue {
+    type Err = InvalidHeaderValue;
+
+    #[inline]
+    fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
+        HeaderValue::from_str(s)
+    }
+}
+
+impl From<HeaderValue> for Bytes {
+    #[inline]
+    fn from(value: HeaderValue) -> Bytes {
+        value.inner
+    }
+}
+
+impl<'a> HttpTryFrom<&'a str> for HeaderValue {
+    type Error = InvalidHeaderValue;
+
+    #[inline]
+    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
+        t.parse()
+    }
+}
+
+impl<'a> HttpTryFrom<&'a [u8]> for HeaderValue {
+    type Error = InvalidHeaderValue;
+
+    #[inline]
+    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
+        HeaderValue::from_bytes(t)
+    }
+}
+
+impl HttpTryFrom<Bytes> for HeaderValue {
+    type Error = InvalidHeaderValueBytes;
+
+    #[inline]
+    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
+        HeaderValue::from_shared(bytes)
+    }
+}
+
+impl HttpTryFrom<HeaderName> for HeaderValue {
+    type Error = InvalidHeaderValue;
+
+    #[inline]
+    fn try_from(name: HeaderName) -> Result<Self, Self::Error> {
+        // Infallable as header names have the same validations
+        Ok(name.into())
+    }
+}
+
+#[cfg(test)]
+mod try_from_header_name_tests {
+    use super::*;
+    use header::name;
+
+    #[test]
+    fn it_converts_using_try_from() {
+        assert_eq!(
+            HeaderValue::try_from(name::UPGRADE).unwrap(),
+            HeaderValue::from_bytes(b"upgrade").unwrap()
+        );
+    }
+}
+
+fn is_visible_ascii(b: u8) -> bool {
+    b >= 32 && b < 127
+}
+
+#[inline]
+fn is_valid(b: u8) -> bool {
+    b >= 32 && b != 127
+}
+
+impl fmt::Display for InvalidHeaderValue {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.description().fmt(f)
+    }
+}
+
+impl Error for InvalidHeaderValue {
+    fn description(&self) -> &str {
+        "failed to parse header value"
+    }
+}
+
+impl fmt::Display for InvalidHeaderValueBytes {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl Error for InvalidHeaderValueBytes {
+    fn description(&self) -> &str {
+        self.0.description()
+    }
+}
+
+impl fmt::Display for ToStrError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.description().fmt(f)
+    }
+}
+
+impl Error for ToStrError {
+    fn description(&self) -> &str {
+        "failed to convert header to a str"
+    }
+}
+
+// ===== PartialEq / PartialOrd =====
+
+impl PartialEq for HeaderValue {
+    #[inline]
+    fn eq(&self, other: &HeaderValue) -> bool {
+        self.inner == other.inner
+    }
+}
+
+impl Eq for HeaderValue {}
+
+impl PartialOrd for HeaderValue {
+    #[inline]
+    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+        self.inner.partial_cmp(&other.inner)
+    }
+}
+
+impl Ord for HeaderValue {
+    #[inline]
+    fn cmp(&self, other: &Self) -> cmp::Ordering {
+        self.inner.cmp(&other.inner)
+    }
+}
+
+impl PartialEq<str> for HeaderValue {
+    #[inline]
+    fn eq(&self, other: &str) -> bool {
+        self.inner == other.as_bytes()
+    }
+}
+
+impl PartialEq<[u8]> for HeaderValue {
+    #[inline]
+    fn eq(&self, other: &[u8]) -> bool {
+        self.inner == other
+    }
+}
+
+impl PartialOrd<str> for HeaderValue {
+    #[inline]
+    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+        (*self.inner).partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialOrd<[u8]> for HeaderValue {
+    #[inline]
+    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
+        (*self.inner).partial_cmp(other)
+    }
+}
+
+impl PartialEq<HeaderValue> for str {
+    #[inline]
+    fn eq(&self, other: &HeaderValue) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialEq<HeaderValue> for [u8] {
+    #[inline]
+    fn eq(&self, other: &HeaderValue) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<HeaderValue> for str {
+    #[inline]
+    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+        self.as_bytes().partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialOrd<HeaderValue> for [u8] {
+    #[inline]
+    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+        self.partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialEq<String> for HeaderValue {
+    #[inline]
+    fn eq(&self, other: &String) -> bool {
+        *self == &other[..]
+    }
+}
+
+impl PartialOrd<String> for HeaderValue {
+    #[inline]
+    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
+        self.inner.partial_cmp(other.as_bytes())
+    }
+}
+
+impl PartialEq<HeaderValue> for String {
+    #[inline]
+    fn eq(&self, other: &HeaderValue) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialOrd<HeaderValue> for String {
+    #[inline]
+    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+        self.as_bytes().partial_cmp(other.as_bytes())
+    }
+}
+
+impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
+    #[inline]
+    fn eq(&self, other: &HeaderValue) -> bool {
+        **self == *other
+    }
+}
+
+impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
+    #[inline]
+    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+        (**self).partial_cmp(other)
+    }
+}
+
+impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
+    where HeaderValue: PartialEq<T>
+{
+    #[inline]
+    fn eq(&self, other: &&'a T) -> bool {
+        *self == **other
+    }
+}
+
+impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
+    where HeaderValue: PartialOrd<T>
+{
+    #[inline]
+    fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
+        self.partial_cmp(*other)
+    }
+}
+
+impl<'a> PartialEq<HeaderValue> for &'a str {
+    #[inline]
+    fn eq(&self, other: &HeaderValue) -> bool {
+        *other == *self
+    }
+}
+
+impl<'a> PartialOrd<HeaderValue> for &'a str {
+    #[inline]
+    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+        self.as_bytes().partial_cmp(other.as_bytes())
+    }
+}
+
+#[test]
+fn test_try_from() {
+    HeaderValue::try_from(vec![127]).unwrap_err();
+}
+
+#[test]
+fn test_debug() {
+    let cases = &[
+        ("hello", "\"hello\""),
+        ("hello \"world\"", "\"hello \\\"world\\\"\""),
+        ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
+    ];
+
+    for &(value, expected) in cases {
+        let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
+        let actual = format!("{:?}", val);
+        assert_eq!(expected, actual);
+    }
+
+    let mut sensitive = HeaderValue::from_static("password");
+    sensitive.set_sensitive(true);
+    assert_eq!("Sensitive", format!("{:?}", sensitive));
+}
diff --git a/third_party/http/src/lib.rs b/third_party/http/src/lib.rs
new file mode 100644
index 0000000..987994d
--- /dev/null
+++ b/third_party/http/src/lib.rs
@@ -0,0 +1,211 @@
+#![doc(html_root_url = "https://docs.rs/http/0.1.7")]
+
+//! A general purpose library of common HTTP types
+//!
+//! This crate is a general purpose library for common types found when working
+//! with the HTTP protocol. You'll find `Request` and `Response` types for
+//! working as either a client or a server as well as all of their components.
+//! Notably you'll find `Uri` for what a `Request` is requesting, a `Method`
+//! for how it's being requested, a `StatusCode` for what sort of response came
+//! back, a `Version` for how this was communicated, and
+//! `HeaderName`/`HeaderValue` definitions to get grouped in a `HeaderMap` to
+//! work with request/response headers.
+//!
+//! You will notably *not* find an implementation of sending requests or
+//! spinning up a server in this crate. It's intended that this crate is the
+//! "standard library" for HTTP clients and servers without dictating any
+//! particular implementation. Note that this crate is still early on in its
+//! lifecycle so the support libraries that integrate with the `http` crate are
+//! a work in progress! Stay tuned and we'll be sure to highlight crates here
+//! in the future.
+//!
+//! ## Requests and Responses
+//!
+//! Perhaps the main two types in this crate are the `Request` and `Response`
+//! types. A `Request` could either be constructed to get sent off as a client
+//! or it can also be received to generate a `Response` for a server. Similarly
+//! as a client a `Response` is what you get after sending a `Request`, whereas
+//! on a server you'll be manufacturing a `Response` to send back to the client.
+//!
+//! Each type has a number of accessors for the component fields. For as a
+//! server you might want to inspect a requests URI to dispatch it:
+//!
+//! ```
+//! use http::{Request, Response};
+//!
+//! fn response(req: Request<()>) -> http::Result<Response<()>> {
+//!     match req.uri().path() {
+//!         "/" => index(req),
+//!         "/foo" => foo(req),
+//!         "/bar" => bar(req),
+//!         _ => not_found(req),
+//!     }
+//! }
+//! # fn index(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
+//! # fn foo(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
+//! # fn bar(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
+//! # fn not_found(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
+//! ```
+//!
+//! On a `Request` you'll also find accessors like `method` to return a
+//! `Method` and `headers` to inspect the various headers. A `Response`
+//! has similar methods for headers, the status code, etc.
+//!
+//! In addition to getters, request/response types also have mutable accessors
+//! to edit the request/response:
+//!
+//! ```
+//! use http::{Response, StatusCode};
+//! use http::header::{CONTENT_TYPE, HeaderValue};
+//!
+//! fn add_server_headers<T>(response: &mut Response<T>) {
+//!     response.headers_mut()
+//!         .insert(CONTENT_TYPE, HeaderValue::from_static("text/html"));
+//!     *response.status_mut() = StatusCode::OK;
+//! }
+//! ```
+//!
+//! And finally, one of the most important aspects of requests/responses, the
+//! body! The `Request` and `Response` types in this crate are *generic* in
+//! what their body is. This allows downstream libraries to use different
+//! representations such as `Request<Vec<u8>>`, `Response<impl Read>`,
+//! `Request<impl Stream<Item = Vec<u8>, Error = _>>`, or even
+//! `Response<MyCustomType>` where the custom type was deserialized from JSON.
+//!
+//! The body representation is intentionally flexible to give downstream
+//! libraries maximal flexibility in implementing the body as appropriate.
+//!
+//! ## HTTP Headers
+//!
+//! Another major piece of functionality in this library is HTTP header
+//! interpretation and generation. The `HeaderName` type serves as a way to
+//! define header *names*, or what's to the left of the colon. A `HeaderValue`
+//! conversely is the header *value*, or what's to the right of a colon.
+//!
+//! For example, if you have an HTTP request that looks like:
+//!
+//! ```http
+//! GET /foo HTTP/1.1
+//! Accept: text/html
+//! ```
+//!
+//! Then `"Accept"` is a `HeaderName` while `"text/html"` is a `HeaderValue`.
+//! Each of these is a dedicated type to allow for a number of interesting
+//! optimizations and to also encode the static guarantees of each type. For
+//! example a `HeaderName` is always a valid `&str`, but a `HeaderValue` may
+//! not be valid UTF-8.
+//!
+//! The most common header names are already defined for you as constant values
+//! in the `header` module of this crate. For example:
+//!
+//! ```
+//! use http::header::{self, HeaderName};
+//!
+//! let name: HeaderName = header::ACCEPT;
+//! assert_eq!(name.as_str(), "accept");
+//! ```
+//!
+//! You can, however, also parse header names from strings:
+//!
+//! ```
+//! use http::header::{self, HeaderName};
+//!
+//! let name = "Accept".parse::<HeaderName>().unwrap();
+//! assert_eq!(name, header::ACCEPT);
+//! ```
+//!
+//! Header values can be created from string literals through the `from_static`
+//! function:
+//!
+//! ```
+//! use http::header::HeaderValue;
+//!
+//! let value = HeaderValue::from_static("text/html");
+//! assert_eq!(value.as_bytes(), b"text/html");
+//! ```
+//!
+//! And header values can also be parsed like names:
+//!
+//! ```
+//! use http::header::HeaderValue;
+//!
+//! let value = "text/html";
+//! let value = value.parse::<HeaderValue>().unwrap();
+//! ```
+//!
+//! Most HTTP requests and responses tend to come with more than one header, so
+//! it's not too useful to just work with names and values only! This crate also
+//! provides a `HeaderMap` type which is a specialized hash map for keys as
+//! `HeaderName` and generic values. This type, like header names, is optimized
+//! for common usage but should continue to scale with your needs over time.
+//!
+//! # URIs
+//!
+//! Each HTTP `Request` has an associated URI with it. This may just be a path
+//! like `/index.html` but it could also be an absolute URL such as
+//! `https://www.rust-lang.org/index.html`. A `URI` has a number of accessors to
+//! interpret it:
+//!
+//! ```
+//! use http::Uri;
+//!
+//! let uri = "https://www.rust-lang.org/index.html".parse::<Uri>().unwrap();
+//!
+//! assert_eq!(uri.scheme(), Some("https"));
+//! assert_eq!(uri.host(), Some("www.rust-lang.org"));
+//! assert_eq!(uri.path(), "/index.html");
+//! assert_eq!(uri.query(), None);
+//! ```
+
+#![deny(warnings, missing_docs, missing_debug_implementations)]
+
+#![cfg_attr(not(target_env = "sgx"), no_std)]
+#![feature(rustc_private)]
+#[cfg(not(target_env = "sgx"))]
+#[macro_use]
+extern crate sgx_tstd as std;
+
+extern crate bytes;
+extern crate fnv;
+extern crate itoa;
+
+pub mod header;
+pub mod method;
+pub mod request;
+pub mod response;
+pub mod status;
+pub mod version;
+pub mod uri;
+
+mod byte_str;
+mod convert;
+mod error;
+mod extensions;
+
+pub use convert::HttpTryFrom;
+pub use error::{Error, Result};
+pub use extensions::Extensions;
+pub use header::HeaderMap;
+pub use method::Method;
+pub use request::Request;
+pub use response::Response;
+pub use status::StatusCode;
+pub use uri::Uri;
+pub use version::Version;
+
+fn _assert_types() {
+    fn assert_send<T: Send>() {}
+    fn assert_sync<T: Sync>() {}
+
+    assert_send::<Request<()>>();
+    assert_send::<Response<()>>();
+
+    assert_sync::<Request<()>>();
+    assert_sync::<Response<()>>();
+}
+
+mod sealed {
+    /// Private trait to this crate to prevent traits from being implemented in
+    /// downstream crates.
+    pub trait Sealed {}
+}
diff --git a/third_party/http/src/method.rs b/third_party/http/src/method.rs
new file mode 100644
index 0000000..a1441de
--- /dev/null
+++ b/third_party/http/src/method.rs
@@ -0,0 +1,357 @@
+//! The HTTP request method
+//!
+//! This module contains HTTP-method related structs and errors and such. The
+//! main type of this module, `Method`, is also reexported at the root of the
+//! crate as `http::Method` and is intended for import through that location
+//! primarily.
+//!
+//! # Examples
+//!
+//! ```
+//! use http::Method;
+//!
+//! assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap());
+//! assert!(Method::GET.is_idempotent());
+//! assert_eq!(Method::POST.as_str(), "POST");
+//! ```
+
+use HttpTryFrom;
+use self::Inner::*;
+
+use std::prelude::v1::*;
+use std::{fmt, str};
+use std::convert::AsRef;
+use std::error::Error;
+use std::str::FromStr;
+
+/// The Request Method (VERB)
+///
+/// This type also contains constants for a number of common HTTP methods such
+/// as GET, POST, etc.
+///
+/// Currently includes 8 variants representing the 8 methods defined in
+/// [RFC 7230](https://tools.ietf.org/html/rfc7231#section-4.1), plus PATCH,
+/// and an Extension variant for all extensions.
+///
+/// # Examples
+///
+/// ```
+/// use http::Method;
+///
+/// assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap());
+/// assert!(Method::GET.is_idempotent());
+/// assert_eq!(Method::POST.as_str(), "POST");
+/// ```
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct Method(Inner);
+
+/// A possible error value when converting `Method` from bytes.
+#[derive(Debug)]
+pub struct InvalidMethod {
+    _priv: (),
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+enum Inner {
+    Options,
+    Get,
+    Post,
+    Put,
+    Delete,
+    Head,
+    Trace,
+    Connect,
+    Patch,
+    // If the extension is short enough, store it inline
+    ExtensionInline([u8; MAX_INLINE], u8),
+    // Otherwise, allocate it
+    ExtensionAllocated(Box<[u8]>),
+}
+
+const MAX_INLINE: usize = 15;
+
+// From the HTTP spec section 5.1.1, the HTTP method is case-sensitive and can
+// contain the following characters:
+//
+// ```
+// method = token
+// token = 1*tchar
+// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+//     "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+// ```
+//
+// https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#Method
+//
+const METHOD_CHARS: [u8; 256] = [
+    //  0      1      2      3      4      5      6      7      8      9
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', //   x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', //  1x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', //  2x
+    b'\0', b'\0', b'\0',  b'!', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', //  3x
+    b'\0', b'\0',  b'*',  b'+', b'\0',  b'-',  b'.', b'\0',  b'0',  b'1', //  4x
+     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9', b'\0', b'\0', //  5x
+    b'\0', b'\0', b'\0', b'\0', b'\0',  b'A',  b'B',  b'C',  b'D',  b'E', //  6x
+     b'F',  b'G',  b'H',  b'I',  b'J',  b'K',  b'L',  b'M',  b'N',  b'O', //  7x
+     b'P',  b'Q',  b'R',  b'S',  b'T',  b'U',  b'V',  b'W',  b'X',  b'Y', //  8x
+     b'Z', b'\0', b'\0', b'\0',  b'^',  b'_',  b'`',  b'a',  b'b',  b'c', //  9x
+     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
+     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
+     b'x',  b'y',  b'z', b'\0',  b'|', b'\0',  b'~', b'\0', b'\0', b'\0', // 12x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 13x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 14x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 15x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 16x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 17x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 18x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 19x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 20x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 21x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 22x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 23x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 24x
+    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0'                              // 25x
+];
+
+
+impl Method {
+    /// GET
+    pub const GET: Method = Method(Get);
+
+    /// POST
+    pub const POST: Method = Method(Post);
+
+    /// PUT
+    pub const PUT: Method = Method(Put);
+
+    /// DELETE
+    pub const DELETE: Method = Method(Delete);
+
+    /// HEAD
+    pub const HEAD: Method = Method(Head);
+
+    /// OPTIONS
+    pub const OPTIONS: Method = Method(Options);
+
+    /// CONNECT
+    pub const CONNECT: Method = Method(Connect);
+
+    /// PATCH
+    pub const PATCH: Method = Method(Patch);
+
+    /// TRACE
+    pub const TRACE: Method = Method(Trace);
+
+    /// Converts a slice of bytes to an HTTP method.
+    pub fn from_bytes(src: &[u8]) -> Result<Method, InvalidMethod> {
+        match src.len() {
+            3 => {
+                match src {
+                    b"GET" => Ok(Method(Get)),
+                    b"PUT" => Ok(Method(Put)),
+                    _ => Method::extension_inline(src),
+                }
+            }
+            4 => {
+                match src {
+                    b"POST" => Ok(Method(Post)),
+                    b"HEAD" => Ok(Method(Head)),
+                    _ => Method::extension_inline(src),
+                }
+            }
+            5 => {
+                match src {
+                    b"PATCH" => Ok(Method(Patch)),
+                    b"TRACE" => Ok(Method(Trace)),
+                    _ => Method::extension_inline(src),
+                }
+            }
+            6 => {
+                match src {
+                    b"DELETE" => Ok(Method(Delete)),
+                    _ => Method::extension_inline(src),
+                }
+            }
+            7 => {
+                match src {
+                    b"OPTIONS" => Ok(Method(Options)),
+                    b"CONNECT" => Ok(Method(Connect)),
+                    _ => Method::extension_inline(src),
+                }
+            }
+            _ => {
+                if src.len() < MAX_INLINE {
+                    Method::extension_inline(src)
+                } else {
+                    let mut data: Vec<u8> = vec![0; src.len()];
+
+                    write_checked(src, &mut data)?;
+
+                    Ok(Method(ExtensionAllocated(data.into_boxed_slice())))
+                }
+            }
+        }
+    }
+
+    fn extension_inline(src: &[u8]) -> Result<Method, InvalidMethod> {
+        let mut data: [u8; MAX_INLINE] = Default::default();
+
+        write_checked(src, &mut data)?;
+
+        Ok(Method(ExtensionInline(data, src.len() as u8)))
+    }
+
+    /// Whether a method is considered "safe", meaning the request is
+    /// essentially read-only.
+    ///
+    /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.1)
+    /// for more words.
+    pub fn is_safe(&self) -> bool {
+        match self.0 {
+            Get | Head | Options | Trace => true,
+            _ => false
+        }
+    }
+
+    /// Whether a method is considered "idempotent", meaning the request has
+    /// the same result if executed multiple times.
+    ///
+    /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.2) for
+    /// more words.
+    pub fn is_idempotent(&self) -> bool {
+        if self.is_safe() {
+            true
+        } else {
+            match self.0 {
+                Put | Delete => true,
+                _ => false
+            }
+        }
+    }
+
+    /// Return a &str representation of the HTTP method
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        match self.0 {
+            Options => "OPTIONS",
+            Get => "GET",
+            Post => "POST",
+            Put => "PUT",
+            Delete => "DELETE",
+            Head => "HEAD",
+            Trace => "TRACE",
+            Connect => "CONNECT",
+            Patch => "PATCH",
+            ExtensionInline(ref data, len) => {
+                unsafe {
+                    str::from_utf8_unchecked(&data[..len as usize])
+                }
+            }
+            ExtensionAllocated(ref data) => {
+                unsafe {
+                    str::from_utf8_unchecked(data)
+                }
+            }
+        }
+    }
+}
+
+fn write_checked(src: &[u8], dst: &mut [u8]) -> Result<(), InvalidMethod> {
+    for (i, &b) in src.iter().enumerate() {
+        let b = METHOD_CHARS[b as usize];
+
+        if b == 0 {
+            return Err(InvalidMethod::new());
+        }
+
+        dst[i] = b;
+    }
+
+    Ok(())
+}
+
+impl AsRef<str> for Method {
+    #[inline]
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl PartialEq<str> for Method {
+    #[inline]
+    fn eq(&self, other: &str) -> bool {
+        self.as_ref() == other
+    }
+}
+
+impl<'a> PartialEq<&'a str> for Method {
+    #[inline]
+    fn eq(&self, other: &&'a str) -> bool {
+        self.as_ref() == *other
+    }
+}
+
+impl fmt::Debug for Method {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.as_ref())
+    }
+}
+
+impl fmt::Display for Method {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.write_str(self.as_ref())
+    }
+}
+
+impl Default for Method {
+    #[inline]
+    fn default() -> Method {
+        Method::GET
+    }
+}
+
+impl<'a> HttpTryFrom<&'a [u8]> for Method {
+    type Error = InvalidMethod;
+
+    #[inline]
+    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
+        Method::from_bytes(t)
+    }
+}
+
+impl<'a> HttpTryFrom<&'a str> for Method {
+    type Error = InvalidMethod;
+
+    #[inline]
+    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
+        HttpTryFrom::try_from(t.as_bytes())
+    }
+}
+
+impl FromStr for Method {
+    type Err = InvalidMethod;
+
+    #[inline]
+    fn from_str(t: &str) -> Result<Self, Self::Err> {
+        HttpTryFrom::try_from(t)
+    }
+}
+
+impl InvalidMethod {
+    fn new() -> InvalidMethod {
+        InvalidMethod {
+            _priv: (),
+        }
+    }
+}
+
+impl fmt::Display for InvalidMethod {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.description())
+    }
+}
+
+impl Error for InvalidMethod {
+    fn description(&self) -> &str {
+        "invalid HTTP method"
+    }
+}
diff --git a/third_party/http/src/request.rs b/third_party/http/src/request.rs
new file mode 100644
index 0000000..b71d38e
--- /dev/null
+++ b/third_party/http/src/request.rs
@@ -0,0 +1,961 @@
+//! HTTP request types.
+//!
+//! This module contains structs related to HTTP requests, notably the
+//! `Request` type itself as well as a builder to create requests. Typically
+//! you'll import the `http::Request` type rather than reaching into this
+//! module itself.
+//!
+//! # Examples
+//!
+//! Creating a `Request` to send
+//!
+//! ```no_run
+//! use http::{Request, Response};
+//!
+//! let mut request = Request::builder();
+//! request.uri("https://www.rust-lang.org/")
+//!        .header("User-Agent", "my-awesome-agent/1.0");
+//!
+//! if needs_awesome_header() {
+//!     request.header("Awesome", "yes");
+//! }
+//!
+//! let response = send(request.body(()).unwrap());
+//!
+//! # fn needs_awesome_header() -> bool {
+//! #     true
+//! # }
+//! #
+//! fn send(req: Request<()>) -> Response<()> {
+//!     // ...
+//! # panic!()
+//! }
+//! ```
+//!
+//! Inspecting a request to see what was sent.
+//!
+//! ```
+//! use http::{Request, Response, StatusCode};
+//!
+//! fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
+//!     if req.uri() != "/awesome-url" {
+//!         return Response::builder()
+//!             .status(StatusCode::NOT_FOUND)
+//!             .body(())
+//!     }
+//!
+//!     let has_awesome_header = req.headers().contains_key("Awesome");
+//!     let body = req.body();
+//!
+//!     // ...
+//! # panic!()
+//! }
+//! ```
+
+use std::any::Any;
+use std::fmt;
+
+use {Uri, Error, Result, HttpTryFrom, Extensions};
+use header::{HeaderMap, HeaderName, HeaderValue};
+use method::Method;
+use version::Version;
+
+/// Represents an HTTP request.
+///
+/// An HTTP request consists of a head and a potentially optional body. The body
+/// component is generic, enabling arbitrary types to represent the HTTP body.
+/// For example, the body could be `Vec<u8>`, a `Stream` of byte chunks, or a
+/// value that has been deserialized.
+///
+/// # Examples
+///
+/// Creating a `Request` to send
+///
+/// ```no_run
+/// use http::{Request, Response};
+///
+/// let mut request = Request::builder();
+/// request.uri("https://www.rust-lang.org/")
+///        .header("User-Agent", "my-awesome-agent/1.0");
+///
+/// if needs_awesome_header() {
+///     request.header("Awesome", "yes");
+/// }
+///
+/// let response = send(request.body(()).unwrap());
+///
+/// # fn needs_awesome_header() -> bool {
+/// #     true
+/// # }
+/// #
+/// fn send(req: Request<()>) -> Response<()> {
+///     // ...
+/// # panic!()
+/// }
+/// ```
+///
+/// Inspecting a request to see what was sent.
+///
+/// ```
+/// use http::{Request, Response, StatusCode};
+///
+/// fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
+///     if req.uri() != "/awesome-url" {
+///         return Response::builder()
+///             .status(StatusCode::NOT_FOUND)
+///             .body(())
+///     }
+///
+///     let has_awesome_header = req.headers().contains_key("Awesome");
+///     let body = req.body();
+///
+///     // ...
+/// # panic!()
+/// }
+/// ```
+///
+/// Deserialize a request of bytes via json:
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_json;
+/// # extern crate http;
+/// use http::Request;
+/// use serde::de;
+///
+/// fn deserialize<T>(req: Request<Vec<u8>>) -> serde_json::Result<Request<T>>
+///     where for<'de> T: de::Deserialize<'de>,
+/// {
+///     let (parts, body) = req.into_parts();
+///     let body = serde_json::from_slice(&body)?;
+///     Ok(Request::from_parts(parts, body))
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// Or alternatively, serialize the body of a request to json
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_json;
+/// # extern crate http;
+/// use http::Request;
+/// use serde::ser;
+///
+/// fn serialize<T>(req: Request<T>) -> serde_json::Result<Request<Vec<u8>>>
+///     where T: ser::Serialize,
+/// {
+///     let (parts, body) = req.into_parts();
+///     let body = serde_json::to_vec(&body)?;
+///     Ok(Request::from_parts(parts, body))
+/// }
+/// #
+/// # fn main() {}
+/// ```
+pub struct Request<T> {
+    head: Parts,
+    body: T,
+}
+
+/// Component parts of an HTTP `Request`
+///
+/// The HTTP request head consists of a method, uri, version, and a set of
+/// header fields.
+pub struct Parts {
+    /// The request's method
+    pub method: Method,
+
+    /// The request's URI
+    pub uri: Uri,
+
+    /// The request's version
+    pub version: Version,
+
+    /// The request's headers
+    pub headers: HeaderMap<HeaderValue>,
+
+    /// The request's extensions
+    pub extensions: Extensions,
+
+    _priv: (),
+}
+
+/// An HTTP request builder
+///
+/// This type can be used to construct an instance or `Request`
+/// through a builder-like pattern.
+#[derive(Debug)]
+pub struct Builder {
+    head: Option<Parts>,
+    err: Option<Error>,
+}
+
+impl Request<()> {
+    /// Creates a new builder-style object to manufacture a `Request`
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request = Request::builder()
+    ///     .method("GET")
+    ///     .uri("https://www.rust-lang.org/")
+    ///     .header("X-Custom-Foo", "Bar")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    #[inline]
+    pub fn builder() -> Builder {
+        Builder::new()
+    }
+
+
+    /// Creates a new `Builder` initialized with a GET method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::get("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn get<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::GET).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with a PUT method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::put("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn put<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::PUT).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with a POST method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::post("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn post<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::POST).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with a DELETE method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::delete("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn delete<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::DELETE).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with an OPTIONS method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::options("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// # assert_eq!(*request.method(), Method::OPTIONS);
+    /// ```
+    pub fn options<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::OPTIONS).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with a HEAD method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::head("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn head<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::HEAD).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with a CONNECT method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::connect("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn connect<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::CONNECT).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with a PATCH method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::patch("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn patch<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::PATCH).uri(uri);
+        b
+    }
+
+    /// Creates a new `Builder` initialized with a TRACE method and the given URI.
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Request`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::trace("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn trace<T>(uri: T) -> Builder
+        where Uri: HttpTryFrom<T> {
+        let mut b = Builder::new();
+        b.method(Method::TRACE).uri(uri);
+        b
+    }
+}
+
+impl<T> Request<T> {
+    /// Creates a new blank `Request` with the body
+    ///
+    /// The component ports of this request will be set to their default, e.g.
+    /// the GET method, no headers, etc.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request = Request::new("hello world");
+    ///
+    /// assert_eq!(*request.method(), Method::GET);
+    /// assert_eq!(*request.body(), "hello world");
+    /// ```
+    #[inline]
+    pub fn new(body: T) -> Request<T> {
+        Request {
+            head: Parts::new(),
+            body: body,
+        }
+    }
+
+    /// Creates a new `Request` with the given components parts and body.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request = Request::new("hello world");
+    /// let (mut parts, body) = request.into_parts();
+    /// parts.method = Method::POST;
+    ///
+    /// let request = Request::from_parts(parts, body);
+    /// ```
+    #[inline]
+    pub fn from_parts(parts: Parts, body: T) -> Request<T> {
+        Request {
+            head: parts,
+            body: body,
+        }
+    }
+
+    /// Returns a reference to the associated HTTP method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request: Request<()> = Request::default();
+    /// assert_eq!(*request.method(), Method::GET);
+    /// ```
+    #[inline]
+    pub fn method(&self) -> &Method {
+        &self.head.method
+    }
+
+    /// Returns a mutable reference to the associated HTTP method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let mut request: Request<()> = Request::default();
+    /// *request.method_mut() = Method::PUT;
+    /// assert_eq!(*request.method(), Method::PUT);
+    /// ```
+    #[inline]
+    pub fn method_mut(&mut self) -> &mut Method {
+        &mut self.head.method
+    }
+
+    /// Returns a reference to the associated URI.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request: Request<()> = Request::default();
+    /// assert_eq!(*request.uri(), *"/");
+    /// ```
+    #[inline]
+    pub fn uri(&self) -> &Uri {
+        &self.head.uri
+    }
+
+    /// Returns a mutable reference to the associated URI.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let mut request: Request<()> = Request::default();
+    /// *request.uri_mut() = "/hello".parse().unwrap();
+    /// assert_eq!(*request.uri(), *"/hello");
+    /// ```
+    #[inline]
+    pub fn uri_mut(&mut self) -> &mut Uri {
+        &mut self.head.uri
+    }
+
+    /// Returns the associated version.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request: Request<()> = Request::default();
+    /// assert_eq!(request.version(), Version::HTTP_11);
+    /// ```
+    #[inline]
+    pub fn version(&self) -> Version {
+        self.head.version
+    }
+
+    /// Returns a mutable reference to the associated version.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let mut request: Request<()> = Request::default();
+    /// *request.version_mut() = Version::HTTP_2;
+    /// assert_eq!(request.version(), Version::HTTP_2);
+    /// ```
+    #[inline]
+    pub fn version_mut(&mut self) -> &mut Version {
+        &mut self.head.version
+    }
+
+    /// Returns a reference to the associated header field map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request: Request<()> = Request::default();
+    /// assert!(request.headers().is_empty());
+    /// ```
+    #[inline]
+    pub fn headers(&self) -> &HeaderMap<HeaderValue> {
+        &self.head.headers
+    }
+
+    /// Returns a mutable reference to the associated header field map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// # use http::header::*;
+    /// let mut request: Request<()> = Request::default();
+    /// request.headers_mut().insert(HOST, HeaderValue::from_static("world"));
+    /// assert!(!request.headers().is_empty());
+    /// ```
+    #[inline]
+    pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
+        &mut self.head.headers
+    }
+
+
+    /// Returns a reference to the associated extensions.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request: Request<()> = Request::default();
+    /// assert!(request.extensions().get::<i32>().is_none());
+    /// ```
+    #[inline]
+    pub fn extensions(&self) -> &Extensions {
+        &self.head.extensions
+    }
+
+    /// Returns a mutable reference to the associated extensions.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// # use http::header::*;
+    /// let mut request: Request<()> = Request::default();
+    /// request.extensions_mut().insert("hello");
+    /// assert_eq!(request.extensions().get(), Some(&"hello"));
+    /// ```
+    #[inline]
+    pub fn extensions_mut(&mut self) -> &mut Extensions {
+        &mut self.head.extensions
+    }
+
+    /// Returns a reference to the associated HTTP body.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request: Request<String> = Request::default();
+    /// assert!(request.body().is_empty());
+    /// ```
+    #[inline]
+    pub fn body(&self) -> &T {
+        &self.body
+    }
+
+    /// Returns a mutable reference to the associated HTTP body.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let mut request: Request<String> = Request::default();
+    /// request.body_mut().push_str("hello world");
+    /// assert!(!request.body().is_empty());
+    /// ```
+    #[inline]
+    pub fn body_mut(&mut self) -> &mut T {
+        &mut self.body
+    }
+
+
+    /// Consumes the request, returning just the body.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::Request;
+    /// let request = Request::new(10);
+    /// let body = request.into_body();
+    /// assert_eq!(body, 10);
+    /// ```
+    #[inline]
+    pub fn into_body(self) -> T {
+        self.body
+    }
+
+    /// Consumes the request returning the head and body parts.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request = Request::new(());
+    /// let (parts, body) = request.into_parts();
+    /// assert_eq!(parts.method, Method::GET);
+    /// ```
+    #[inline]
+    pub fn into_parts(self) -> (Parts, T) {
+        (self.head, self.body)
+    }
+
+    /// Consumes the request returning a new request with body mapped to the
+    /// return type of the passed in function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let request = Request::builder().body("some string").unwrap();
+    /// let mapped_request: Request<&[u8]> = request.map(|b| {
+    ///   assert_eq!(b, "some string");
+    ///   b.as_bytes()
+    /// });
+    /// assert_eq!(mapped_request.body(), &"some string".as_bytes());
+    /// ```
+    #[inline]
+    pub fn map<F, U>(self, f: F) -> Request<U>
+        where F: FnOnce(T) -> U
+    {
+        Request { body: f(self.body), head: self.head }
+    }
+}
+
+impl<T: Default> Default for Request<T> {
+    fn default() -> Request<T> {
+        Request::new(T::default())
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for Request<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Request")
+            .field("method", self.method())
+            .field("uri", self.uri())
+            .field("version", &self.version())
+            .field("headers", self.headers())
+            // omits Extensions because not useful
+            .field("body", self.body())
+            .finish()
+    }
+}
+
+impl Parts {
+    /// Creates a new default instance of `Parts`
+    fn new() -> Parts {
+        Parts{
+            method: Method::default(),
+            uri: Uri::default(),
+            version: Version::default(),
+            headers: HeaderMap::default(),
+            extensions: Extensions::default(),
+            _priv: (),
+        }
+    }
+}
+
+impl fmt::Debug for Parts {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Parts")
+            .field("method", &self.method)
+            .field("uri", &self.uri)
+            .field("version", &self.version)
+            .field("headers", &self.headers)
+            // omits Extensions because not useful
+            // omits _priv because not useful
+            .finish()
+    }
+}
+
+impl Builder {
+    /// Creates a new default instance of `Builder` to construct either a
+    /// `Head` or a `Request`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let req = request::Builder::new()
+    ///     .method("POST")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    #[inline]
+    pub fn new() -> Builder {
+        Builder::default()
+    }
+
+    /// Set the HTTP method for this request.
+    ///
+    /// This function will configure the HTTP method of the `Request` that will
+    /// be returned from `Builder::build`.
+    ///
+    /// By default this is `GET`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let req = Request::builder()
+    ///     .method("POST")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn method<T>(&mut self, method: T) -> &mut Builder
+        where Method: HttpTryFrom<T>,
+    {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            match HttpTryFrom::try_from(method) {
+                Ok(s) => head.method = s,
+                Err(e) => self.err = Some(e.into()),
+            }
+        }
+        self
+    }
+
+    /// Set the URI for this request.
+    ///
+    /// This function will configure the URI of the `Request` that will
+    /// be returned from `Builder::build`.
+    ///
+    /// By default this is `/`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let req = Request::builder()
+    ///     .uri("https://www.rust-lang.org/")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn uri<T>(&mut self, uri: T) -> &mut Builder
+        where Uri: HttpTryFrom<T>,
+    {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            match HttpTryFrom::try_from(uri) {
+                Ok(s) => head.uri = s,
+                Err(e) => self.err = Some(e.into()),
+            }
+        }
+        self
+    }
+
+    /// Set the HTTP version for this request.
+    ///
+    /// This function will configure the HTTP version of the `Request` that
+    /// will be returned from `Builder::build`.
+    ///
+    /// By default this is HTTP/1.1
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let req = Request::builder()
+    ///     .version(Version::HTTP_2)
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn version(&mut self, version: Version) -> &mut Builder {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            head.version = version;
+        }
+        self
+    }
+
+    /// Appends a header to this request builder.
+    ///
+    /// This function will append the provided key/value as a header to the
+    /// internal `HeaderMap` being constructed. Essentially this is equivalent
+    /// to calling `HeaderMap::append`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// # use http::header::HeaderValue;
+    ///
+    /// let req = Request::builder()
+    ///     .header("Accept", "text/html")
+    ///     .header("X-Custom-Foo", "bar")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Builder
+        where HeaderName: HttpTryFrom<K>,
+              HeaderValue: HttpTryFrom<V>
+    {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            match <HeaderName as HttpTryFrom<K>>::try_from(key) {
+                Ok(key) => {
+                    match <HeaderValue as HttpTryFrom<V>>::try_from(value) {
+                        Ok(value) => { head.headers.append(key, value); }
+                        Err(e) => self.err = Some(e.into()),
+                    }
+                },
+                Err(e) => self.err = Some(e.into()),
+            };
+        }
+        self
+    }
+
+    /// Adds an extension to this builder
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let req = Request::builder()
+    ///     .extension("My Extension")
+    ///     .body(())
+    ///     .unwrap();
+    ///
+    /// assert_eq!(req.extensions().get::<&'static str>(),
+    ///            Some(&"My Extension"));
+    /// ```
+    pub fn extension<T>(&mut self, extension: T) -> &mut Builder
+        where T: Any + Send + Sync + 'static,
+    {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            head.extensions.insert(extension);
+        }
+        self
+    }
+
+    fn take_parts(&mut self) -> Result<Parts> {
+        let ret = self.head.take().expect("cannot reuse request builder");
+        if let Some(e) = self.err.take() {
+            return Err(e)
+        }
+        Ok(ret)
+    }
+
+    /// "Consumes" this builder, using the provided `body` to return a
+    /// constructed `Request`.
+    ///
+    /// # Errors
+    ///
+    /// This function may return an error if any previously configured argument
+    /// failed to parse or get converted to the internal representation. For
+    /// example if an invalid `head` was specified via `header("Foo",
+    /// "Bar\r\n")` the error will be returned when this function is called
+    /// rather than when `header` was called.
+    ///
+    /// # Panics
+    ///
+    /// This method will panic if the builder is reused. The `body` function can
+    /// only be called once.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let request = Request::builder()
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn body<T>(&mut self, body: T) -> Result<Request<T>> {
+        Ok(Request {
+            head: self.take_parts()?,
+            body: body,
+        })
+    }
+}
+
+fn head<'a>(head: &'a mut Option<Parts>, err: &Option<Error>)
+    -> Option<&'a mut Parts>
+{
+    if err.is_some() {
+        return None
+    }
+    head.as_mut()
+}
+
+impl Default for Builder {
+    #[inline]
+    fn default() -> Builder {
+        Builder {
+            head: Some(Parts::new()),
+            err: None,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn it_can_map_a_body_from_one_type_to_another() {
+        let request= Request::builder().body("some string").unwrap();
+        let mapped_request = request.map(|s| {
+            assert_eq!(s, "some string");
+            123u32
+        });
+        assert_eq!(mapped_request.body(), &123u32);
+    }
+}
diff --git a/third_party/http/src/response.rs b/third_party/http/src/response.rs
new file mode 100644
index 0000000..e628cf6
--- /dev/null
+++ b/third_party/http/src/response.rs
@@ -0,0 +1,730 @@
+//! HTTP response types.
+//!
+//! This module contains structs related to HTTP responses, notably the
+//! `Response` type itself as well as a builder to create responses. Typically
+//! you'll import the `http::Response` type rather than reaching into this
+//! module itself.
+//!
+//! # Examples
+//!
+//! Creating a `Response` to return
+//!
+//! ```
+//! use http::{Request, Response, StatusCode};
+//!
+//! fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
+//!     let mut response = Response::builder();
+//!     response.header("Foo", "Bar")
+//!             .status(StatusCode::OK);
+//!
+//!     if req.headers().contains_key("Another-Header") {
+//!         response.header("Another-Header", "Ack");
+//!     }
+//!
+//!     response.body(())
+//! }
+//! ```
+//!
+//! A simple 404 handler
+//!
+//! ```
+//! use http::{Request, Response, StatusCode};
+//!
+//! fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
+//!     Response::builder()
+//!         .status(StatusCode::NOT_FOUND)
+//!         .body(())
+//! }
+//! ```
+//!
+//! Or otherwise inspecting the result of a request:
+//!
+//! ```no_run
+//! use http::{Request, Response};
+//!
+//! fn get(url: &str) -> http::Result<Response<()>> {
+//!     // ...
+//! # panic!()
+//! }
+//!
+//! let response = get("https://www.rust-lang.org/").unwrap();
+//!
+//! if !response.status().is_success() {
+//!     panic!("failed to get a successful response status!");
+//! }
+//!
+//! if let Some(date) = response.headers().get("Date") {
+//!     // we've got a `Date` header!
+//! }
+//!
+//! let body = response.body();
+//! // ...
+//! ```
+
+use std::any::Any;
+use std::fmt;
+
+use {Error, Result, HttpTryFrom, Extensions};
+use header::{HeaderMap, HeaderName, HeaderValue};
+use status::StatusCode;
+use version::Version;
+
+/// Represents an HTTP response
+///
+/// An HTTP response consists of a head and a potentially optional body. The body
+/// component is generic, enabling arbitrary types to represent the HTTP body.
+/// For example, the body could be `Vec<u8>`, a `Stream` of byte chunks, or a
+/// value that has been deserialized.
+///
+/// Typically you'll work with responses on the client side as the result of
+/// sending a `Request` and on the server you'll be generating a `Request` to
+/// send back to the client.
+///
+/// # Examples
+///
+/// Creating a `Response` to return
+///
+/// ```
+/// use http::{Request, Response, StatusCode};
+///
+/// fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
+///     let mut response = Response::builder();
+///     response.header("Foo", "Bar")
+///             .status(StatusCode::OK);
+///
+///     if req.headers().contains_key("Another-Header") {
+///         response.header("Another-Header", "Ack");
+///     }
+///
+///     response.body(())
+/// }
+/// ```
+///
+/// A simple 404 handler
+///
+/// ```
+/// use http::{Request, Response, StatusCode};
+///
+/// fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
+///     Response::builder()
+///         .status(StatusCode::NOT_FOUND)
+///         .body(())
+/// }
+/// ```
+///
+/// Or otherwise inspecting the result of a request:
+///
+/// ```no_run
+/// use http::{Request, Response};
+///
+/// fn get(url: &str) -> http::Result<Response<()>> {
+///     // ...
+/// # panic!()
+/// }
+///
+/// let response = get("https://www.rust-lang.org/").unwrap();
+///
+/// if !response.status().is_success() {
+///     panic!("failed to get a successful response status!");
+/// }
+///
+/// if let Some(date) = response.headers().get("Date") {
+///     // we've got a `Date` header!
+/// }
+///
+/// let body = response.body();
+/// // ...
+/// ```
+///
+/// Deserialize a response of bytes via json:
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_json;
+/// # extern crate http;
+/// use http::Response;
+/// use serde::de;
+///
+/// fn deserialize<T>(req: Response<Vec<u8>>) -> serde_json::Result<Response<T>>
+///     where for<'de> T: de::Deserialize<'de>,
+/// {
+///     let (parts, body) = req.into_parts();
+///     let body = serde_json::from_slice(&body)?;
+///     Ok(Response::from_parts(parts, body))
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// Or alternatively, serialize the body of a response to json
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_json;
+/// # extern crate http;
+/// use http::Response;
+/// use serde::ser;
+///
+/// fn serialize<T>(req: Response<T>) -> serde_json::Result<Response<Vec<u8>>>
+///     where T: ser::Serialize,
+/// {
+///     let (parts, body) = req.into_parts();
+///     let body = serde_json::to_vec(&body)?;
+///     Ok(Response::from_parts(parts, body))
+/// }
+/// #
+/// # fn main() {}
+/// ```
+pub struct Response<T> {
+    head: Parts,
+    body: T,
+}
+
+/// Component parts of an HTTP `Response`
+///
+/// The HTTP response head consists of a status, version, and a set of
+/// header fields.
+pub struct Parts {
+    /// The response's status
+    pub status: StatusCode,
+
+    /// The response's version
+    pub version: Version,
+
+    /// The response's headers
+    pub headers: HeaderMap<HeaderValue>,
+
+    /// The response's extensions
+    pub extensions: Extensions,
+
+    _priv: (),
+}
+
+/// An HTTP response builder
+///
+/// This type can be used to construct an instance of `Response` through a
+/// builder-like pattern.
+#[derive(Debug)]
+pub struct Builder {
+    head: Option<Parts>,
+    err: Option<Error>,
+}
+
+impl Response<()> {
+    /// Creates a new builder-style object to manufacture a `Response`
+    ///
+    /// This method returns an instance of `Builder` which can be used to
+    /// create a `Response`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response = Response::builder()
+    ///     .status(200)
+    ///     .header("X-Custom-Foo", "Bar")
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    #[inline]
+    pub fn builder() -> Builder {
+        Builder::new()
+    }
+}
+
+impl<T> Response<T> {
+    /// Creates a new blank `Response` with the body
+    ///
+    /// The component ports of this response will be set to their default, e.g.
+    /// the ok status, no headers, etc.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response = Response::new("hello world");
+    ///
+    /// assert_eq!(response.status(), StatusCode::OK);
+    /// assert_eq!(*response.body(), "hello world");
+    /// ```
+    #[inline]
+    pub fn new(body: T) -> Response<T> {
+        Response {
+            head: Parts::new(),
+            body: body,
+        }
+    }
+
+    /// Creates a new `Response` with the given head and body
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response = Response::new("hello world");
+    /// let (mut parts, body) = response.into_parts();
+    ///
+    /// parts.status = StatusCode::BAD_REQUEST;
+    /// let response = Response::from_parts(parts, body);
+    ///
+    /// assert_eq!(response.status(), StatusCode::BAD_REQUEST);
+    /// assert_eq!(*response.body(), "hello world");
+    /// ```
+    #[inline]
+    pub fn from_parts(parts: Parts, body: T) -> Response<T> {
+        Response {
+            head: parts,
+            body: body,
+        }
+    }
+
+    /// Returns the `StatusCode`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response: Response<()> = Response::default();
+    /// assert_eq!(response.status(), StatusCode::OK);
+    /// ```
+    #[inline]
+    pub fn status(&self) -> StatusCode {
+        self.head.status
+    }
+
+    /// Returns a mutable reference to the associated `StatusCode`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let mut response: Response<()> = Response::default();
+    /// *response.status_mut() = StatusCode::CREATED;
+    /// assert_eq!(response.status(), StatusCode::CREATED);
+    /// ```
+    #[inline]
+    pub fn status_mut(&mut self) -> &mut StatusCode {
+        &mut self.head.status
+    }
+
+    /// Returns a reference to the associated version.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response: Response<()> = Response::default();
+    /// assert_eq!(response.version(), Version::HTTP_11);
+    /// ```
+    #[inline]
+    pub fn version(&self) -> Version {
+        self.head.version
+    }
+
+    /// Returns a mutable reference to the associated version.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let mut response: Response<()> = Response::default();
+    /// *response.version_mut() = Version::HTTP_2;
+    /// assert_eq!(response.version(), Version::HTTP_2);
+    /// ```
+    #[inline]
+    pub fn version_mut(&mut self) -> &mut Version {
+        &mut self.head.version
+    }
+
+    /// Returns a reference to the associated header field map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response: Response<()> = Response::default();
+    /// assert!(response.headers().is_empty());
+    /// ```
+    #[inline]
+    pub fn headers(&self) -> &HeaderMap<HeaderValue> {
+        &self.head.headers
+    }
+
+    /// Returns a mutable reference to the associated header field map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// # use http::header::*;
+    /// let mut response: Response<()> = Response::default();
+    /// response.headers_mut().insert(HOST, HeaderValue::from_static("world"));
+    /// assert!(!response.headers().is_empty());
+    /// ```
+    #[inline]
+    pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
+        &mut self.head.headers
+    }
+
+    /// Returns a reference to the associated extensions.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response: Response<()> = Response::default();
+    /// assert!(response.extensions().get::<i32>().is_none());
+    /// ```
+    #[inline]
+    pub fn extensions(&self) -> &Extensions {
+        &self.head.extensions
+    }
+
+    /// Returns a mutable reference to the associated extensions.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// # use http::header::*;
+    /// let mut response: Response<()> = Response::default();
+    /// response.extensions_mut().insert("hello");
+    /// assert_eq!(response.extensions().get(), Some(&"hello"));
+    /// ```
+    #[inline]
+    pub fn extensions_mut(&mut self) -> &mut Extensions {
+        &mut self.head.extensions
+    }
+
+    /// Returns a reference to the associated HTTP body.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response: Response<String> = Response::default();
+    /// assert!(response.body().is_empty());
+    /// ```
+    #[inline]
+    pub fn body(&self) -> &T {
+        &self.body
+    }
+
+    /// Returns a mutable reference to the associated HTTP body.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let mut response: Response<String> = Response::default();
+    /// response.body_mut().push_str("hello world");
+    /// assert!(!response.body().is_empty());
+    /// ```
+    #[inline]
+    pub fn body_mut(&mut self) -> &mut T {
+        &mut self.body
+    }
+
+    /// Consumes the response, returning just the body.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::Response;
+    /// let response = Response::new(10);
+    /// let body = response.into_body();
+    /// assert_eq!(body, 10);
+    /// ```
+    #[inline]
+    pub fn into_body(self) -> T {
+        self.body
+    }
+
+    /// Consumes the response returning the head and body parts.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response: Response<()> = Response::default();
+    /// let (parts, body) = response.into_parts();
+    /// assert_eq!(parts.status, StatusCode::OK);
+    /// ```
+    #[inline]
+    pub fn into_parts(self) -> (Parts, T) {
+        (self.head, self.body)
+    }
+
+    /// Consumes the response returning a new response with body mapped to the
+    /// return type of the passed in function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// let response = Response::builder().body("some string").unwrap();
+    /// let mapped_response: Response<&[u8]> = response.map(|b| {
+    ///   assert_eq!(b, "some string");
+    ///   b.as_bytes()
+    /// });
+    /// assert_eq!(mapped_response.body(), &"some string".as_bytes());
+    /// ```
+    #[inline]
+    pub fn map<F, U>(self, f: F) -> Response<U>
+        where F: FnOnce(T) -> U
+    {
+        Response { body: f(self.body), head: self.head }
+    }
+}
+
+impl<T: Default> Default for Response<T> {
+    #[inline]
+    fn default() -> Response<T> {
+        Response::new(T::default())
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for Response<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Response")
+            .field("status", &self.status())
+            .field("version", &self.version())
+            .field("headers", self.headers())
+            // omits Extensions because not useful
+            .field("body", self.body())
+            .finish()
+    }
+}
+
+impl Parts {
+    /// Creates a new default instance of `Parts`
+    fn new() -> Parts {
+        Parts{
+            status: StatusCode::default(),
+            version: Version::default(),
+            headers: HeaderMap::default(),
+            extensions: Extensions::default(),
+            _priv: (),
+        }
+    }
+}
+
+impl fmt::Debug for Parts {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Parts")
+            .field("status", &self.status)
+            .field("version", &self.version)
+            .field("headers", &self.headers)
+            // omits Extensions because not useful
+            // omits _priv because not useful
+            .finish()
+    }
+}
+
+impl Builder {
+    /// Creates a new default instance of `Builder` to construct either a
+    /// `Head` or a `Response`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let response = response::Builder::new()
+    ///     .status(200)
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    #[inline]
+    pub fn new() -> Builder {
+        Builder::default()
+    }
+
+    /// Set the HTTP status for this response.
+    ///
+    /// This function will configure the HTTP status code of the `Response` that
+    /// will be returned from `Builder::build`.
+    ///
+    /// By default this is `200`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let response = Response::builder()
+    ///     .status(200)
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn status<T>(&mut self, status: T) -> &mut Builder
+        where StatusCode: HttpTryFrom<T>,
+    {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            match HttpTryFrom::try_from(status) {
+                Ok(s) => head.status = s,
+                Err(e) => self.err = Some(e.into()),
+            }
+        }
+        self
+    }
+
+    /// Set the HTTP version for this response.
+    ///
+    /// This function will configure the HTTP version of the `Response` that
+    /// will be returned from `Builder::build`.
+    ///
+    /// By default this is HTTP/1.1
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let response = Response::builder()
+    ///     .version(Version::HTTP_2)
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn version(&mut self, version: Version) -> &mut Builder {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            head.version = version;
+        }
+        self
+    }
+
+    /// Appends a header to this response builder.
+    ///
+    /// This function will append the provided key/value as a header to the
+    /// internal `HeaderMap` being constructed. Essentially this is equivalent
+    /// to calling `HeaderMap::append`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    /// # use http::header::HeaderValue;
+    ///
+    /// let response = Response::builder()
+    ///     .header("Content-Type", "text/html")
+    ///     .header("X-Custom-Foo", "bar")
+    ///     .header("content-length", 0)
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Builder
+        where HeaderName: HttpTryFrom<K>,
+              HeaderValue: HttpTryFrom<V>
+    {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            match <HeaderName as HttpTryFrom<K>>::try_from(key) {
+                Ok(key) => {
+                    match <HeaderValue as HttpTryFrom<V>>::try_from(value) {
+                        Ok(value) => { head.headers.append(key, value); }
+                        Err(e) => self.err = Some(e.into()),
+                    }
+                },
+                Err(e) => self.err = Some(e.into()),
+            };
+        }
+        self
+    }
+
+    /// Adds an extension to this builder
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let response = Response::builder()
+    ///     .extension("My Extension")
+    ///     .body(())
+    ///     .unwrap();
+    ///
+    /// assert_eq!(response.extensions().get::<&'static str>(),
+    ///            Some(&"My Extension"));
+    /// ```
+    pub fn extension<T>(&mut self, extension: T) -> &mut Builder
+        where T: Any + Send + Sync + 'static,
+    {
+        if let Some(head) = head(&mut self.head, &self.err) {
+            head.extensions.insert(extension);
+        }
+        self
+    }
+
+    fn take_parts(&mut self) -> Result<Parts> {
+        let ret = self.head.take().expect("cannot reuse response builder");
+        if let Some(e) = self.err.take() {
+            return Err(e)
+        }
+        Ok(ret)
+    }
+
+    /// "Consumes" this builder, using the provided `body` to return a
+    /// constructed `Response`.
+    ///
+    /// # Errors
+    ///
+    /// This function may return an error if any previously configured argument
+    /// failed to parse or get converted to the internal representation. For
+    /// example if an invalid `head` was specified via `header("Foo",
+    /// "Bar\r\n")` the error will be returned when this function is called
+    /// rather than when `header` was called.
+    ///
+    /// # Panics
+    ///
+    /// This method will panic if the builder is reused. The `body` function can
+    /// only be called once.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::*;
+    ///
+    /// let response = Response::builder()
+    ///     .body(())
+    ///     .unwrap();
+    /// ```
+    pub fn body<T>(&mut self, body: T) -> Result<Response<T>> {
+        Ok(Response {
+            head: self.take_parts()?,
+            body: body,
+        })
+    }
+}
+
+fn head<'a>(head: &'a mut Option<Parts>, err: &Option<Error>)
+    -> Option<&'a mut Parts>
+{
+    if err.is_some() {
+        return None
+    }
+    head.as_mut()
+}
+
+impl Default for Builder {
+    #[inline]
+    fn default() -> Builder {
+        Builder {
+            head: Some(Parts::new()),
+            err: None,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn it_can_map_a_body_from_one_type_to_another() {
+        let response = Response::builder().body("some string").unwrap();
+        let mapped_response = response.map(|s| {
+            assert_eq!(s, "some string");
+            123u32
+        });
+        assert_eq!(mapped_response.body(), &123u32);
+    }
+}
diff --git a/third_party/http/src/status.rs b/third_party/http/src/status.rs
new file mode 100644
index 0000000..100632c
--- /dev/null
+++ b/third_party/http/src/status.rs
@@ -0,0 +1,547 @@
+//! HTTP status codes
+//!
+//! This module contains HTTP-status code related structs an errors. The main
+//! type in this module is `StatusCode` which is not intended to be used through
+//! this module but rather the `http::StatusCode` type.
+//!
+//! # Examples
+//!
+//! ```
+//! use http::StatusCode;
+//!
+//! assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
+//! assert_eq!(StatusCode::NOT_FOUND, 404);
+//! assert!(StatusCode::OK.is_success());
+//! ```
+
+use std::fmt;
+use std::error::Error;
+use std::str::FromStr;
+
+use HttpTryFrom;
+
+/// An HTTP status code (`status-code` in RFC 7230 et al.).
+///
+/// This type contains constants for all common status codes.
+/// It allows status codes in the range [100, 599].
+///
+/// IANA maintain the [Hypertext Transfer Protocol (HTTP) Status Code
+/// Registry](http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml) which is
+/// the source for this enum (with one exception, 418 I'm a teapot, which is
+/// inexplicably not in the register).
+///
+/// # Examples
+///
+/// ```
+/// use http::StatusCode;
+///
+/// assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
+/// assert_eq!(StatusCode::NOT_FOUND.as_u16(), 404);
+/// assert!(StatusCode::OK.is_success());
+/// ```
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct StatusCode(u16);
+
+/// A possible error value when converting a `StatusCode` from a `u16` or `&str`
+///
+/// This error indicates that the supplied input was not a valid number, was less
+/// than 100, or was greater than 599.
+#[derive(Debug)]
+pub struct InvalidStatusCode {
+    _priv: (),
+}
+
+impl StatusCode {
+    /// Converts a u16 to a status code.
+    ///
+    /// The function validates the correctness of the supplied u16. It must be
+    /// greater or equal to 100 but less than 600.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use http::StatusCode;
+    ///
+    /// let ok = StatusCode::from_u16(200).unwrap();
+    /// assert_eq!(ok, StatusCode::OK);
+    ///
+    /// let err = StatusCode::from_u16(99);
+    /// assert!(err.is_err());
+    /// ```
+    #[inline]
+    pub fn from_u16(src: u16) -> Result<StatusCode, InvalidStatusCode> {
+        if src < 100 || src >= 600 {
+            return Err(InvalidStatusCode::new());
+        }
+
+        Ok(StatusCode(src))
+    }
+
+    /// Converts a &[u8] to a status code
+    pub fn from_bytes(src: &[u8]) -> Result<StatusCode, InvalidStatusCode> {
+        if src.len() != 3 {
+            return Err(InvalidStatusCode::new());
+        }
+
+        let a = src[0].wrapping_sub(b'0') as u16;
+        let b = src[1].wrapping_sub(b'0') as u16;
+        let c = src[2].wrapping_sub(b'0') as u16;
+
+        if a == 0 || a > 5 || b > 9 || c > 9 {
+            return Err(InvalidStatusCode::new());
+        }
+
+        let status = (a * 100) + (b * 10) + c;
+        Ok(StatusCode(status))
+    }
+
+    /// Returns the `u16` corresponding to this `StatusCode`.
+    ///
+    /// # Note
+    ///
+    /// This is the same as the `From<StatusCode>` implementation, but
+    /// included as an inherent method because that implementation doesn't
+    /// appear in rustdocs, as well as a way to force the type instead of
+    /// relying on inference.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let status = http::StatusCode::OK;
+    /// assert_eq!(status.as_u16(), 200);
+    /// ```
+    #[inline]
+    pub fn as_u16(&self) -> u16 {
+        (*self).into()
+    }
+
+    /// Returns a &str representation of the `StatusCode`
+    ///
+    /// The return value only includes a numerical representation of the
+    /// status code. The canonical reason is not included.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let status = http::StatusCode::OK;
+    /// assert_eq!(status.as_str(), "200");
+    /// ```
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        CODES_AS_STR[(self.0 - 100) as usize]
+    }
+
+    /// Get the standardised `reason-phrase` for this status code.
+    ///
+    /// This is mostly here for servers writing responses, but could potentially have application
+    /// at other times.
+    ///
+    /// The reason phrase is defined as being exclusively for human readers. You should avoid
+    /// deriving any meaning from it at all costs.
+    ///
+    /// Bear in mind also that in HTTP/2.0 the reason phrase is abolished from transmission, and so
+    /// this canonical reason phrase really is the only reason phrase you’ll find.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let status = http::StatusCode::OK;
+    /// assert_eq!(status.canonical_reason(), Some("OK"));
+    /// ```
+    pub fn canonical_reason(&self) -> Option<&'static str> {
+        canonical_reason(self.0)
+    }
+
+
+    /// Check if status is within 100-199.
+    #[inline]
+    pub fn is_informational(&self) -> bool {
+        200 > self.0 && self.0 >= 100
+    }
+
+    /// Check if status is within 200-299.
+    #[inline]
+    pub fn is_success(&self) -> bool {
+        300 > self.0 && self.0 >= 200
+    }
+
+    /// Check if status is within 300-399.
+    #[inline]
+    pub fn is_redirection(&self) -> bool {
+        400 > self.0 && self.0 >= 300
+    }
+
+    /// Check if status is within 400-499.
+    #[inline]
+    pub fn is_client_error(&self) -> bool {
+        500 > self.0 && self.0 >= 400
+    }
+
+    /// Check if status is within 500-599.
+    #[inline]
+    pub fn is_server_error(&self) -> bool {
+        600 > self.0 && self.0 >= 500
+    }
+}
+
+impl fmt::Debug for StatusCode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.0, f)
+    }
+}
+
+/// Formats the status code, *including* the canonical reason.
+///
+/// # Example
+///
+/// ```
+/// # use http::StatusCode;
+/// assert_eq!(format!("{}", StatusCode::OK), "200 OK");
+/// ```
+impl fmt::Display for StatusCode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{} {}", u16::from(*self),
+               self.canonical_reason().unwrap_or("<unknown status code>"))
+    }
+}
+
+impl Default for StatusCode {
+    #[inline]
+    fn default() -> StatusCode {
+        StatusCode::OK
+    }
+}
+
+impl PartialEq<u16> for StatusCode {
+    #[inline]
+    fn eq(&self, other: &u16) -> bool {
+        self.as_u16() == *other
+    }
+}
+
+impl PartialEq<StatusCode> for u16 {
+    #[inline]
+    fn eq(&self, other: &StatusCode) -> bool {
+        *self == other.as_u16()
+    }
+}
+
+impl From<StatusCode> for u16 {
+    #[inline]
+    fn from(status: StatusCode) -> u16 {
+        status.0
+    }
+}
+
+impl FromStr for StatusCode {
+    type Err = InvalidStatusCode;
+
+    fn from_str(s: &str) -> Result<StatusCode, InvalidStatusCode> {
+        StatusCode::from_bytes(s.as_ref())
+    }
+}
+
+impl<'a> HttpTryFrom<&'a [u8]> for StatusCode {
+    type Error = InvalidStatusCode;
+
+    #[inline]
+    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
+        StatusCode::from_bytes(t)
+    }
+}
+
+impl<'a> HttpTryFrom<&'a str> for StatusCode {
+    type Error = InvalidStatusCode;
+
+    #[inline]
+    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
+        t.parse()
+    }
+}
+
+impl HttpTryFrom<u16> for StatusCode {
+    type Error = InvalidStatusCode;
+
+    #[inline]
+    fn try_from(t: u16) -> Result<Self, Self::Error> {
+        StatusCode::from_u16(t)
+    }
+}
+
+impl InvalidStatusCode {
+    fn new() -> InvalidStatusCode {
+        InvalidStatusCode {
+            _priv: (),
+        }
+    }
+}
+
+macro_rules! status_codes {
+    (
+        $(
+            $(#[$docs:meta])*
+            ($num:expr, $konst:ident, $phrase:expr);
+        )+
+    ) => {
+        impl StatusCode {
+        $(
+            $(#[$docs])*
+            pub const $konst: StatusCode = StatusCode($num);
+        )+
+
+        }
+
+        fn canonical_reason(num: u16) -> Option<&'static str> {
+            match num {
+                $(
+                $num => Some($phrase),
+                )+
+                _ => None
+            }
+        }
+    }
+}
+
+status_codes! {
+    /// 100 Continue
+    /// [[RFC7231, Section 6.2.1](https://tools.ietf.org/html/rfc7231#section-6.2.1)]
+    (100, CONTINUE, "Continue");
+    /// 101 Switching Protocols
+    /// [[RFC7231, Section 6.2.2](https://tools.ietf.org/html/rfc7231#section-6.2.2)]
+    (101, SWITCHING_PROTOCOLS, "Switching Protocols");
+    /// 102 Processing
+    /// [[RFC2518](https://tools.ietf.org/html/rfc2518)]
+    (102, PROCESSING, "Processing");
+
+    /// 200 OK
+    /// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)]
+    (200, OK, "OK");
+    /// 201 Created
+    /// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)]
+    (201, CREATED, "Created");
+    /// 202 Accepted
+    /// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)]
+    (202, ACCEPTED, "Accepted");
+    /// 203 Non-Authoritative Information
+    /// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)]
+    (203, NON_AUTHORITATIVE_INFORMATION, "Non Authoritative Information");
+    /// 204 No Content
+    /// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)]
+    (204, NO_CONTENT, "No Content");
+    /// 205 Reset Content
+    /// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)]
+    (205, RESET_CONTENT, "Reset Content");
+    /// 206 Partial Content
+    /// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)]
+    (206, PARTIAL_CONTENT, "Partial Content");
+    /// 207 Multi-Status
+    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
+    (207, MULTI_STATUS, "Multi-Status");
+    /// 208 Already Reported
+    /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
+    (208, ALREADY_REPORTED, "Already Reported");
+
+    /// 226 IM Used
+    /// [[RFC3229](https://tools.ietf.org/html/rfc3229)]
+    (226, IM_USED, "IM Used");
+
+    /// 300 Multiple Choices
+    /// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)]
+    (300, MULTIPLE_CHOICES, "Multiple Choices");
+    /// 301 Moved Permanently
+    /// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)]
+    (301, MOVED_PERMANENTLY, "Moved Permanently");
+    /// 302 Found
+    /// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)]
+    (302, FOUND, "Found");
+    /// 303 See Other
+    /// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)]
+    (303, SEE_OTHER, "See Other");
+    /// 304 Not Modified
+    /// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)]
+    (304, NOT_MODIFIED, "Not Modified");
+    /// 305 Use Proxy
+    /// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)]
+    (305, USE_PROXY, "Use Proxy");
+    /// 307 Temporary Redirect
+    /// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)]
+    (307, TEMPORARY_REDIRECT, "Temporary Redirect");
+    /// 308 Permanent Redirect
+    /// [[RFC7238](https://tools.ietf.org/html/rfc7238)]
+    (308, PERMANENT_REDIRECT, "Permanent Redirect");
+
+    /// 400 Bad Request
+    /// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)]
+    (400, BAD_REQUEST, "Bad Request");
+    /// 401 Unauthorized
+    /// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)]
+    (401, UNAUTHORIZED, "Unauthorized");
+    /// 402 Payment Required
+    /// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)]
+    (402, PAYMENT_REQUIRED, "Payment Required");
+    /// 403 Forbidden
+    /// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)]
+    (403, FORBIDDEN, "Forbidden");
+    /// 404 Not Found
+    /// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)]
+    (404, NOT_FOUND, "Not Found");
+    /// 405 Method Not Allowed
+    /// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)]
+    (405, METHOD_NOT_ALLOWED, "Method Not Allowed");
+    /// 406 Not Acceptable
+    /// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)]
+    (406, NOT_ACCEPTABLE, "Not Acceptable");
+    /// 407 Proxy Authentication Required
+    /// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)]
+    (407, PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required");
+    /// 408 Request Timeout
+    /// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)]
+    (408, REQUEST_TIMEOUT, "Request Timeout");
+    /// 409 Conflict
+    /// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)]
+    (409, CONFLICT, "Conflict");
+    /// 410 Gone
+    /// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)]
+    (410, GONE, "Gone");
+    /// 411 Length Required
+    /// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)]
+    (411, LENGTH_REQUIRED, "Length Required");
+    /// 412 Precondition Failed
+    /// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)]
+    (412, PRECONDITION_FAILED, "Precondition Failed");
+    /// 413 Payload Too Large
+    /// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)]
+    (413, PAYLOAD_TOO_LARGE, "Payload Too Large");
+    /// 414 URI Too Long
+    /// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)]
+    (414, URI_TOO_LONG, "URI Too Long");
+    /// 415 Unsupported Media Type
+    /// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)]
+    (415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
+    /// 416 Range Not Satisfiable
+    /// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)]
+    (416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable");
+    /// 417 Expectation Failed
+    /// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)]
+    (417, EXPECTATION_FAILED, "Expectation Failed");
+    /// 418 I'm a teapot
+    /// [curiously not registered by IANA but [RFC2324](https://tools.ietf.org/html/rfc2324)]
+    (418, IM_A_TEAPOT, "I'm a teapot");
+
+    /// 421 Misdirected Request
+    /// [RFC7540, Section 9.1.2](http://tools.ietf.org/html/rfc7540#section-9.1.2)
+    (421, MISDIRECTED_REQUEST, "Misdirected Request");
+    /// 422 Unprocessable Entity
+    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
+    (422, UNPROCESSABLE_ENTITY, "Unprocessable Entity");
+    /// 423 Locked
+    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
+    (423, LOCKED, "Locked");
+    /// 424 Failed Dependency
+    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
+    (424, FAILED_DEPENDENCY, "Failed Dependency");
+
+    /// 426 Upgrade Required
+    /// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)]
+    (426, UPGRADE_REQUIRED, "Upgrade Required");
+
+    /// 428 Precondition Required
+    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
+    (428, PRECONDITION_REQUIRED, "Precondition Required");
+    /// 429 Too Many Requests
+    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
+    (429, TOO_MANY_REQUESTS, "Too Many Requests");
+
+    /// 431 Request Header Fields Too Large
+    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
+    (431, REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large");
+
+    /// 451 Unavailable For Legal Reasons
+    /// [[RFC7725](http://tools.ietf.org/html/rfc7725)]
+    (451, UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons");
+
+    /// 500 Internal Server Error
+    /// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)]
+    (500, INTERNAL_SERVER_ERROR, "Internal Server Error");
+    /// 501 Not Implemented
+    /// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)]
+    (501, NOT_IMPLEMENTED, "Not Implemented");
+    /// 502 Bad Gateway
+    /// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)]
+    (502, BAD_GATEWAY, "Bad Gateway");
+    /// 503 Service Unavailable
+    /// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)]
+    (503, SERVICE_UNAVAILABLE, "Service Unavailable");
+    /// 504 Gateway Timeout
+    /// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)]
+    (504, GATEWAY_TIMEOUT, "Gateway Timeout");
+    /// 505 HTTP Version Not Supported
+    /// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)]
+    (505, HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported");
+    /// 506 Variant Also Negotiates
+    /// [[RFC2295](https://tools.ietf.org/html/rfc2295)]
+    (506, VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates");
+    /// 507 Insufficient Storage
+    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
+    (507, INSUFFICIENT_STORAGE, "Insufficient Storage");
+    /// 508 Loop Detected
+    /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
+    (508, LOOP_DETECTED, "Loop Detected");
+
+    /// 510 Not Extended
+    /// [[RFC2774](https://tools.ietf.org/html/rfc2774)]
+    (510, NOT_EXTENDED, "Not Extended");
+    /// 511 Network Authentication Required
+    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
+    (511, NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required");
+}
+
+impl fmt::Display for InvalidStatusCode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.description())
+    }
+}
+
+impl Error for InvalidStatusCode {
+    fn description(&self) -> &str {
+        "invalid status code"
+    }
+}
+
+macro_rules! status_code_strs {
+    ($($num:expr,)+) => {
+        const CODES_AS_STR: [&'static str; 500] = [ $( stringify!($num), )+ ];
+    }
+}
+
+status_code_strs!(
+    100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+    120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+    140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+    160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+    180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+
+    200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+    240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259,
+    260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279,
+    280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
+
+    300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
+    320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
+    340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
+    360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379,
+    380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
+
+    400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419,
+    420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439,
+    440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
+    460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
+    480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499,
+
+    500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519,
+    520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539,
+    540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559,
+    560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579,
+    580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599,
+    );
diff --git a/third_party/http/src/uri/authority.rs b/third_party/http/src/uri/authority.rs
new file mode 100644
index 0000000..d14cf2a
--- /dev/null
+++ b/third_party/http/src/uri/authority.rs
@@ -0,0 +1,523 @@
+// Deprecated in 1.26, needed until our minimum version is >=1.23.
+#[allow(unused, deprecated)]
+use std::ascii::AsciiExt;
+use std::{cmp, fmt, str};
+use std::hash::{Hash, Hasher};
+use std::str::FromStr;
+use std::prelude::v1::*;
+
+use bytes::Bytes;
+
+use byte_str::ByteStr;
+use super::{ErrorKind, InvalidUri, InvalidUriBytes, URI_CHARS};
+
+/// Represents the authority component of a URI.
+#[derive(Clone)]
+pub struct Authority {
+    pub(super) data: ByteStr,
+}
+
+impl Authority {
+    pub(super) fn empty() -> Self {
+        Authority { data: ByteStr::new() }
+    }
+
+    /// Attempt to convert an `Authority` from `Bytes`.
+    ///
+    /// This function will be replaced by a `TryFrom` implementation once the
+    /// trait lands in stable.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # extern crate http;
+    /// # use http::uri::*;
+    /// extern crate bytes;
+    ///
+    /// use bytes::Bytes;
+    ///
+    /// # pub fn main() {
+    /// let bytes = Bytes::from("example.com");
+    /// let authority = Authority::from_shared(bytes).unwrap();
+    ///
+    /// assert_eq!(authority.host(), "example.com");
+    /// # }
+    /// ```
+    pub fn from_shared(s: Bytes) -> Result<Self, InvalidUriBytes> {
+        let authority_end = Authority::parse_non_empty(&s[..]).map_err(InvalidUriBytes)?;
+
+        if authority_end != s.len() {
+            return Err(ErrorKind::InvalidUriChar.into());
+        }
+
+        Ok(Authority {
+            data: unsafe { ByteStr::from_utf8_unchecked(s) },
+        })
+    }
+
+    /// Attempt to convert an `Authority` from a static string.
+    ///
+    /// This function will not perform any copying, and the string will be
+    /// checked if it is empty or contains an invalid character.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if the argument contains invalid characters or
+    /// is empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::uri::Authority;
+    /// let authority = Authority::from_static("example.com");
+    /// assert_eq!(authority.host(), "example.com");
+    /// ```
+    pub fn from_static(src: &'static str) -> Self {
+        let s = src.as_bytes();
+        let b = Bytes::from_static(s);
+        let authority_end = Authority::parse_non_empty(&b[..]).expect("static str is not valid authority");
+
+        if authority_end != b.len() {
+            panic!("static str is not valid authority");
+        }
+
+        Authority {
+            data: unsafe { ByteStr::from_utf8_unchecked(b) },
+        }
+    }
+
+    // Note: this may return an *empty* Authority. You might want `parse_non_empty`.
+    pub(super) fn parse(s: &[u8]) -> Result<usize, InvalidUri> {
+        let mut colon_cnt = 0;
+        let mut start_bracket = false;
+        let mut end_bracket = false;
+        let mut end = s.len();
+
+        for (i, &b) in s.iter().enumerate() {
+            match URI_CHARS[b as usize] {
+                b'/' | b'?' | b'#' => {
+                    end = i;
+                    break;
+                }
+                b':' => {
+                    colon_cnt += 1;
+                },
+                b'[' => {
+                    start_bracket = true;
+                }
+                b']' => {
+                    end_bracket = true;
+
+                    // Those were part of an IPv6 hostname, so forget them...
+                    colon_cnt = 0;
+                }
+                b'@' => {
+                    // Those weren't a port colon, but part of the
+                    // userinfo, so it needs to be forgotten.
+                    colon_cnt = 0;
+                }
+                0 => {
+                    return Err(ErrorKind::InvalidUriChar.into());
+                }
+                _ => {}
+            }
+        }
+
+        if start_bracket ^ end_bracket {
+            return Err(ErrorKind::InvalidAuthority.into());
+        }
+
+        if colon_cnt > 1 {
+            // Things like 'localhost:8080:3030' are rejected.
+            return Err(ErrorKind::InvalidAuthority.into());
+        }
+
+        Ok(end)
+    }
+
+    // Parse bytes as an Authority, not allowing an empty string.
+    //
+    // This should be used by functions that allow a user to parse
+    // an `Authority` by itself.
+    fn parse_non_empty(s: &[u8]) -> Result<usize, InvalidUri> {
+        if s.is_empty() {
+            return Err(ErrorKind::Empty.into());
+        }
+        Authority::parse(s)
+    }
+
+    /// Get the host of this `Authority`.
+    ///
+    /// The host subcomponent of authority is identified by an IP literal
+    /// encapsulated within square brackets, an IPv4 address in dotted- decimal
+    /// form, or a registered name.  The host subcomponent is **case-insensitive**.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                         |---------|
+    ///                              |
+    ///                             host
+    /// ```
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let authority: Authority = "example.org:80".parse().unwrap();
+    ///
+    /// assert_eq!(authority.host(), "example.org");
+    /// ```
+    #[inline]
+    pub fn host(&self) -> &str {
+        host(self.as_str())
+    }
+
+    /// Get the port of this `Authority`.
+    ///
+    /// The port subcomponent of authority is designated by an optional port
+    /// number in decimal following the host and delimited from it by a single
+    /// colon (":") character. A value is only returned if one is specified in
+    /// the URI string, i.e., default port values are **not** returned.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                                     |-|
+    ///                                      |
+    ///                                     port
+    /// ```
+    ///
+    /// # Examples
+    ///
+    /// Authority with port
+    ///
+    /// ```
+    /// # use http::uri::Authority;
+    /// let authority: Authority = "example.org:80".parse().unwrap();
+    ///
+    /// assert_eq!(authority.port(), Some(80));
+    /// ```
+    ///
+    /// Authority without port
+    ///
+    /// ```
+    /// # use http::uri::Authority;
+    /// let authority: Authority = "example.org".parse().unwrap();
+    ///
+    /// assert!(authority.port().is_none());
+    /// ```
+    pub fn port(&self) -> Option<u16> {
+        let s = self.as_str();
+        s.rfind(":").and_then(|i| {
+            u16::from_str(&s[i+1..]).ok()
+        })
+    }
+
+    /// Return a str representation of the authority
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        &self.data[..]
+    }
+
+    /// Converts this `Authority` back to a sequence of bytes
+    #[inline]
+    pub fn into_bytes(self) -> Bytes {
+        self.into()
+    }
+}
+
+impl AsRef<str> for Authority {
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl PartialEq for Authority {
+    fn eq(&self, other: &Authority) -> bool {
+        self.data.eq_ignore_ascii_case(&other.data)
+    }
+}
+
+impl Eq for Authority {}
+
+/// Case-insensitive equality
+///
+/// # Examples
+///
+/// ```
+/// # use http::uri::Authority;
+/// let authority: Authority = "HELLO.com".parse().unwrap();
+/// assert_eq!(authority, "hello.coM");
+/// assert_eq!("hello.com", authority);
+/// ```
+impl PartialEq<str> for Authority {
+    fn eq(&self, other: &str) -> bool {
+        self.data.eq_ignore_ascii_case(other)
+    }
+}
+
+impl PartialEq<Authority> for str {
+    fn eq(&self, other: &Authority) -> bool {
+        self.eq_ignore_ascii_case(other.as_str())
+    }
+}
+
+impl<'a> PartialEq<Authority> for &'a str {
+    fn eq(&self, other: &Authority) -> bool {
+        self.eq_ignore_ascii_case(other.as_str())
+    }
+}
+
+impl<'a> PartialEq<&'a str> for Authority {
+    fn eq(&self, other: &&'a str) -> bool {
+        self.data.eq_ignore_ascii_case(other)
+    }
+}
+
+impl PartialEq<String> for Authority {
+    fn eq(&self, other: &String) -> bool {
+        self.data.eq_ignore_ascii_case(other.as_str())
+    }
+}
+
+impl PartialEq<Authority> for String {
+    fn eq(&self, other: &Authority) -> bool {
+        self.as_str().eq_ignore_ascii_case(other.as_str())
+    }
+}
+
+/// Case-insensitive ordering
+///
+/// # Examples
+///
+/// ```
+/// # use http::uri::Authority;
+/// let authority: Authority = "DEF.com".parse().unwrap();
+/// assert!(authority < "ghi.com");
+/// assert!(authority > "abc.com");
+/// ```
+impl PartialOrd for Authority {
+    fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
+        let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        left.partial_cmp(right)
+    }
+}
+
+impl PartialOrd<str> for Authority {
+    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+        let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        left.partial_cmp(right)
+    }
+}
+
+impl PartialOrd<Authority> for str {
+    fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
+        let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        left.partial_cmp(right)
+    }
+}
+
+impl<'a> PartialOrd<Authority> for &'a str {
+    fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
+        let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        left.partial_cmp(right)
+    }
+}
+
+impl<'a> PartialOrd<&'a str> for Authority {
+    fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
+        let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        left.partial_cmp(right)
+    }
+}
+
+impl PartialOrd<String> for Authority {
+    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
+        let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        left.partial_cmp(right)
+    }
+}
+
+impl PartialOrd<Authority> for String {
+    fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
+        let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
+        left.partial_cmp(right)
+    }
+}
+
+/// Case-insensitive hashing
+///
+/// # Examples
+///
+/// ```
+/// # use http::uri::Authority;
+/// # use std::hash::{Hash, Hasher};
+/// # use std::collections::hash_map::DefaultHasher;
+///
+/// let a: Authority = "HELLO.com".parse().unwrap();
+/// let b: Authority = "hello.coM".parse().unwrap();
+///
+/// let mut s = DefaultHasher::new();
+/// a.hash(&mut s);
+/// let a = s.finish();
+///
+/// let mut s = DefaultHasher::new();
+/// b.hash(&mut s);
+/// let b = s.finish();
+///
+/// assert_eq!(a, b);
+/// ```
+impl Hash for Authority {
+    fn hash<H>(&self, state: &mut H) where H: Hasher {
+        self.data.len().hash(state);
+        for &b in self.data.as_bytes() {
+            state.write_u8(b.to_ascii_lowercase());
+        }
+    }
+}
+
+impl FromStr for Authority {
+    type Err = InvalidUri;
+
+    fn from_str(s: &str) -> Result<Self, InvalidUri> {
+        let end = Authority::parse_non_empty(s.as_bytes())?;
+
+        if end != s.len() {
+            return Err(ErrorKind::InvalidAuthority.into());
+        }
+
+        Ok(Authority { data: s.into() })
+    }
+}
+
+impl From<Authority> for Bytes {
+    #[inline]
+    fn from(src: Authority) -> Bytes {
+        src.data.into()
+    }
+}
+
+impl fmt::Debug for Authority {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
+impl fmt::Display for Authority {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
+fn host(auth: &str) -> &str {
+    let host_port = auth.rsplitn(2, '@')
+        .next()
+        .expect("split always has at least 1 item");
+    if host_port.as_bytes()[0] == b'[' {
+        let i = host_port.find(']')
+            .expect("parsing should validate brackets");
+        &host_port[1..i]
+    } else {
+        host_port.split(':')
+            .next()
+            .expect("split always has at least 1 item")
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parse_empty_string_is_error() {
+        let err = Authority::parse_non_empty(b"").unwrap_err();
+        assert_eq!(err.0, ErrorKind::Empty);
+    }
+
+    #[test]
+    fn equal_to_self_of_same_authority() {
+        let authority1: Authority = "example.com".parse().unwrap();
+        let authority2: Authority = "EXAMPLE.COM".parse().unwrap();
+        assert_eq!(authority1, authority2);
+        assert_eq!(authority2, authority1);
+    }
+
+    #[test]
+    fn not_equal_to_self_of_different_authority() {
+        let authority1: Authority = "example.com".parse().unwrap();
+        let authority2: Authority = "test.com".parse().unwrap();
+        assert_ne!(authority1, authority2);
+        assert_ne!(authority2, authority1);
+    }
+
+    #[test]
+    fn equates_with_a_str() {
+        let authority: Authority = "example.com".parse().unwrap();
+        assert_eq!(&authority, "EXAMPLE.com");
+        assert_eq!("EXAMPLE.com", &authority);
+        assert_eq!(authority, "EXAMPLE.com");
+        assert_eq!("EXAMPLE.com", authority);
+    }
+
+    #[test]
+    fn not_equal_with_a_str_of_a_different_authority() {
+        let authority: Authority = "example.com".parse().unwrap();
+        assert_ne!(&authority, "test.com");
+        assert_ne!("test.com", &authority);
+        assert_ne!(authority, "test.com");
+        assert_ne!("test.com", authority);
+    }
+
+    #[test]
+    fn equates_with_a_string() {
+        let authority: Authority = "example.com".parse().unwrap();
+        assert_eq!(authority, "EXAMPLE.com".to_string());
+        assert_eq!("EXAMPLE.com".to_string(), authority);
+    }
+
+    #[test]
+    fn equates_with_a_string_of_a_different_authority() {
+        let authority: Authority = "example.com".parse().unwrap();
+        assert_ne!(authority, "test.com".to_string());
+        assert_ne!("test.com".to_string(), authority);
+    }
+
+    #[test]
+    fn compares_to_self() {
+        let authority1: Authority = "abc.com".parse().unwrap();
+        let authority2: Authority = "def.com".parse().unwrap();
+        assert!(authority1 < authority2);
+        assert!(authority2 > authority1);
+    }
+
+    #[test]
+    fn compares_with_a_str() {
+        let authority: Authority = "def.com".parse().unwrap();
+        // with ref
+        assert!(&authority < "ghi.com");
+        assert!("ghi.com" > &authority);
+        assert!(&authority > "abc.com");
+        assert!("abc.com" < &authority);
+
+        // no ref
+        assert!(authority < "ghi.com");
+        assert!("ghi.com" > authority);
+        assert!(authority > "abc.com");
+        assert!("abc.com" < authority);
+    }
+
+    #[test]
+    fn compares_with_a_string() {
+        let authority: Authority = "def.com".parse().unwrap();
+        assert!(authority < "ghi.com".to_string());
+        assert!("ghi.com".to_string() > authority);
+        assert!(authority > "abc.com".to_string());
+        assert!("abc.com".to_string() < authority);
+    }
+}
diff --git a/third_party/http/src/uri/mod.rs b/third_party/http/src/uri/mod.rs
new file mode 100644
index 0000000..cab4c7d
--- /dev/null
+++ b/third_party/http/src/uri/mod.rs
@@ -0,0 +1,1044 @@
+//! URI component of request and response lines
+//!
+//! This module primarily contains the `Uri` type which is a component of all
+//! HTTP requests and also reexports this type at the root of the crate. A URI
+//! is not always a "full URL" in the sense of something you'd type into a web
+//! browser, but HTTP requests may only have paths on servers but may have full
+//! schemes and hostnames on clients.
+//!
+//! # Examples
+//!
+//! ```
+//! use http::Uri;
+//!
+//! let uri = "/foo/bar?baz".parse::<Uri>().unwrap();
+//! assert_eq!(uri.path(), "/foo/bar");
+//! assert_eq!(uri.query(), Some("baz"));
+//! assert_eq!(uri.host(), None);
+//!
+//! let uri = "https://www.rust-lang.org/install.html".parse::<Uri>().unwrap();
+//! assert_eq!(uri.scheme_part().map(|s| s.as_str()), Some("https"));
+//! assert_eq!(uri.host(), Some("www.rust-lang.org"));
+//! assert_eq!(uri.path(), "/install.html");
+//! ```
+
+use HttpTryFrom;
+use byte_str::ByteStr;
+
+use bytes::Bytes;
+
+use std::prelude::v1::*;
+use std::{fmt, u8, u16};
+// Deprecated in 1.26, needed until our minimum version is >=1.23.
+#[allow(unused, deprecated)]
+use std::ascii::AsciiExt;
+use std::hash::{Hash, Hasher};
+use std::str::{self, FromStr};
+use std::error::Error;
+
+use self::scheme::Scheme2;
+
+pub use self::authority::Authority;
+pub use self::path::PathAndQuery;
+pub use self::scheme::Scheme;
+
+mod authority;
+mod path;
+mod scheme;
+#[cfg(test)]
+mod tests;
+
+/// The URI component of a request.
+///
+/// For HTTP 1, this is included as part of the request line. From Section 5.3,
+/// Request Target:
+///
+/// > Once an inbound connection is obtained, the client sends an HTTP
+/// > request message (Section 3) with a request-target derived from the
+/// > target URI.  There are four distinct formats for the request-target,
+/// > depending on both the method being requested and whether the request
+/// > is to a proxy.
+/// >
+/// > ```notrust
+/// > request-target = origin-form
+/// >                / absolute-form
+/// >                / authority-form
+/// >                / asterisk-form
+/// > ```
+///
+/// The URI is structured as follows:
+///
+/// ```notrust
+/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+/// |-|   |-------------------------------||--------| |-------------------| |-----|
+///  |                  |                       |               |              |
+/// scheme          authority                 path            query         fragment
+/// ```
+///
+/// For HTTP 2.0, the URI is encoded using pseudoheaders.
+///
+/// # Examples
+///
+/// ```
+/// use http::Uri;
+///
+/// let uri = "/foo/bar?baz".parse::<Uri>().unwrap();
+/// assert_eq!(uri.path(), "/foo/bar");
+/// assert_eq!(uri.query(), Some("baz"));
+/// assert_eq!(uri.host(), None);
+///
+/// let uri = "https://www.rust-lang.org/install.html".parse::<Uri>().unwrap();
+/// assert_eq!(uri.scheme_part().map(|s| s.as_str()), Some("https"));
+/// assert_eq!(uri.host(), Some("www.rust-lang.org"));
+/// assert_eq!(uri.path(), "/install.html");
+/// ```
+#[derive(Clone)]
+pub struct Uri {
+    scheme: Scheme,
+    authority: Authority,
+    path_and_query: PathAndQuery,
+}
+
+/// The various parts of a URI.
+///
+/// This struct is used to provide to and retrieve from a URI.
+#[derive(Debug, Default)]
+pub struct Parts {
+    /// The scheme component of a URI
+    pub scheme: Option<Scheme>,
+
+    /// The authority component of a URI
+    pub authority: Option<Authority>,
+
+    /// The origin-form component of a URI
+    pub path_and_query: Option<PathAndQuery>,
+
+    /// Allow extending in the future
+    _priv: (),
+}
+
+/// An error resulting from a failed attempt to construct a URI.
+#[derive(Debug)]
+pub struct InvalidUri(ErrorKind);
+
+/// An error resulting from a failed attempt to construct a URI.
+#[derive(Debug)]
+pub struct InvalidUriBytes(InvalidUri);
+
+/// An error resulting from a failed attempt to construct a URI.
+#[derive(Debug)]
+pub struct InvalidUriParts(InvalidUri);
+
+#[derive(Debug, Eq, PartialEq)]
+enum ErrorKind {
+    InvalidUriChar,
+    InvalidScheme,
+    InvalidAuthority,
+    InvalidFormat,
+    SchemeMissing,
+    AuthorityMissing,
+    PathAndQueryMissing,
+    TooLong,
+    Empty,
+    SchemeTooLong,
+}
+
+// u16::MAX is reserved for None
+const MAX_LEN: usize = (u16::MAX - 1) as usize;
+
+const URI_CHARS: [u8; 256] = [
+    //  0      1      2      3      4      5      6      7      8      9
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
+        0,     0,     0,  b'!',     0,  b'#',  b'$',     0,  b'&', b'\'', //  3x
+     b'(',  b')',  b'*',  b'+',  b',',  b'-',  b'.',  b'/',  b'0',  b'1', //  4x
+     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',  b':',  b';', //  5x
+        0,  b'=',     0,  b'?',  b'@',  b'A',  b'B',  b'C',  b'D',  b'E', //  6x
+     b'F',  b'G',  b'H',  b'I',  b'J',  b'K',  b'L',  b'M',  b'N',  b'O', //  7x
+     b'P',  b'Q',  b'R',  b'S',  b'T',  b'U',  b'V',  b'W',  b'X',  b'Y', //  8x
+     b'Z',  b'[',     0,  b']',     0,  b'_',     0,  b'a',  b'b',  b'c', //  9x
+     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
+     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
+     b'x',  b'y',  b'z',     0,     0,     0,  b'~',     0,     0,     0, // 12x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
+        0,     0,     0,     0,     0,     0                              // 25x
+];
+
+impl Uri {
+    /// Attempt to convert a `Uri` from `Parts`
+    pub fn from_parts(src: Parts) -> Result<Uri, InvalidUriParts> {
+        if src.scheme.is_some() {
+            if src.authority.is_none() {
+                return Err(ErrorKind::AuthorityMissing.into());
+            }
+
+            if src.path_and_query.is_none() {
+                return Err(ErrorKind::PathAndQueryMissing.into());
+            }
+        } else {
+            if src.authority.is_some() && src.path_and_query.is_some() {
+                return Err(ErrorKind::SchemeMissing.into());
+            }
+        }
+
+        let scheme = match src.scheme {
+            Some(scheme) => scheme,
+            None => Scheme { inner: Scheme2::None },
+        };
+
+        let authority = match src.authority {
+            Some(authority) => authority,
+            None => Authority::empty(),
+        };
+
+        let path_and_query = match src.path_and_query {
+            Some(path_and_query) => path_and_query,
+            None => PathAndQuery::empty(),
+        };
+
+        Ok(Uri {
+            scheme: scheme,
+            authority: authority,
+            path_and_query: path_and_query,
+        })
+    }
+
+    /// Attempt to convert a `Uri` from `Bytes`
+    ///
+    /// This function will be replaced by a `TryFrom` implementation once the
+    /// trait lands in stable.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # extern crate http;
+    /// # use http::uri::*;
+    /// extern crate bytes;
+    ///
+    /// use bytes::Bytes;
+    ///
+    /// # pub fn main() {
+    /// let bytes = Bytes::from("http://example.com/foo");
+    /// let uri = Uri::from_shared(bytes).unwrap();
+    ///
+    /// assert_eq!(uri.host().unwrap(), "example.com");
+    /// assert_eq!(uri.path(), "/foo");
+    /// # }
+    /// ```
+    pub fn from_shared(s: Bytes) -> Result<Uri, InvalidUriBytes> {
+        use self::ErrorKind::*;
+
+        if s.len() > MAX_LEN {
+            return Err(TooLong.into());
+        }
+
+        match s.len() {
+            0 => {
+                return Err(Empty.into());
+            }
+            1 => {
+                match s[0] {
+                    b'/' => {
+                        return Ok(Uri {
+                            scheme: Scheme::empty(),
+                            authority: Authority::empty(),
+                            path_and_query: PathAndQuery::slash(),
+                        });
+                    }
+                    b'*' => {
+                        return Ok(Uri {
+                            scheme: Scheme::empty(),
+                            authority: Authority::empty(),
+                            path_and_query: PathAndQuery::star(),
+                        });
+                    }
+                    _ => {
+                        let authority = Authority::from_shared(s)?;
+
+                        return Ok(Uri {
+                            scheme: Scheme::empty(),
+                            authority: authority,
+                            path_and_query: PathAndQuery::empty(),
+                        });
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        if s[0] == b'/' {
+            return Ok(Uri {
+                scheme: Scheme::empty(),
+                authority: Authority::empty(),
+                path_and_query: PathAndQuery::from_shared(s)?,
+            });
+        }
+
+        parse_full(s)
+    }
+
+    /// Convert a `Uri` into `Parts`.
+    ///
+    /// # Note
+    ///
+    /// This is just an inherent method providing the same functionality as
+    /// `let parts: Parts = uri.into()`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let uri: Uri = "/foo".parse().unwrap();
+    ///
+    /// let parts = uri.into_parts();
+    ///
+    /// assert_eq!(parts.path_and_query.unwrap(), "/foo");
+    ///
+    /// assert!(parts.scheme.is_none());
+    /// assert!(parts.authority.is_none());
+    /// ```
+    #[inline]
+    pub fn into_parts(self) -> Parts {
+        self.into()
+    }
+
+    /// Returns the path & query components of the Uri
+    #[inline]
+    pub fn path_and_query(&self) -> Option<&PathAndQuery> {
+        if !self.scheme.inner.is_none() || self.authority.data.is_empty() {
+            Some(&self.path_and_query)
+        } else {
+            None
+        }
+    }
+
+    /// Get the path of this `Uri`.
+    ///
+    /// Both relative and absolute URIs contain a path component, though it
+    /// might be the empty string. The path component is **case sensitive**.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                                        |--------|
+    ///                                             |
+    ///                                           path
+    /// ```
+    ///
+    /// If the URI is `*` then the path component is equal to `*`.
+    ///
+    /// # Examples
+    ///
+    /// A relative URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    ///
+    /// let uri: Uri = "/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(uri.path(), "/hello/world");
+    /// ```
+    ///
+    /// An absolute URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(uri.path(), "/hello/world");
+    /// ```
+    #[inline]
+    pub fn path(&self) -> &str {
+        if self.has_path() {
+            self.path_and_query.path()
+        } else {
+            ""
+        }
+    }
+
+    /// Get the scheme of this `Uri`.
+    ///
+    /// The URI scheme refers to a specification for assigning identifiers
+    /// within that scheme. Only absolute URIs contain a scheme component, but
+    /// not all absolute URIs will contain a scheme component.  Although scheme
+    /// names are case-insensitive, the canonical form is lowercase.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    /// |-|
+    ///  |
+    /// scheme
+    /// ```
+    ///
+    /// # Examples
+    ///
+    /// Absolute URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(uri.scheme_part().map(|s| s.as_str()), Some("http"));
+    /// ```
+    ///
+    ///
+    /// Relative URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "/hello/world".parse().unwrap();
+    ///
+    /// assert!(uri.scheme_part().is_none());
+    /// ```
+    #[inline]
+    pub fn scheme_part(&self) -> Option<&Scheme> {
+        if self.scheme.inner.is_none() {
+            None
+        } else {
+            Some(&self.scheme)
+        }
+    }
+
+    #[deprecated(since = "0.1.2", note = "use scheme_part instead")]
+    #[doc(hidden)]
+    #[inline]
+    pub fn scheme(&self) -> Option<&str> {
+        if self.scheme.inner.is_none() {
+            None
+        } else {
+            Some(self.scheme.as_str())
+        }
+    }
+
+    /// Get the authority of this `Uri`.
+    ///
+    /// The authority is a hierarchical element for naming authority such that
+    /// the remainder of the URI is delegated to that authority. For HTTP, the
+    /// authority consists of the host and port. The host portion of the
+    /// authority is **case-insensitive**.
+    ///
+    /// The authority also includes a `username:password` component, however
+    /// the use of this is deprecated and should be avoided.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///       |-------------------------------|
+    ///                     |
+    ///                 authority
+    /// ```
+    ///
+    /// This function will be renamed to `authority` in the next semver release.
+    ///
+    /// # Examples
+    ///
+    /// Absolute URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(uri.authority_part().map(|a| a.as_str()), Some("example.org:80"));
+    /// ```
+    ///
+    ///
+    /// Relative URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "/hello/world".parse().unwrap();
+    ///
+    /// assert!(uri.authority_part().is_none());
+    /// ```
+    #[inline]
+    pub fn authority_part(&self) -> Option<&Authority> {
+        if self.authority.data.is_empty() {
+            None
+        } else {
+            Some(&self.authority)
+        }
+    }
+
+    #[deprecated(since = "0.1.1", note = "use authority_part instead")]
+    #[doc(hidden)]
+    #[inline]
+    pub fn authority(&self) -> Option<&str> {
+        if self.authority.data.is_empty() {
+            None
+        } else {
+            Some(self.authority.as_str())
+        }
+    }
+
+    /// Get the host of this `Uri`.
+    ///
+    /// The host subcomponent of authority is identified by an IP literal
+    /// encapsulated within square brackets, an IPv4 address in dotted- decimal
+    /// form, or a registered name.  The host subcomponent is **case-insensitive**.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                         |---------|
+    ///                              |
+    ///                             host
+    /// ```
+    ///
+    /// # Examples
+    ///
+    /// Absolute URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(uri.host(), Some("example.org"));
+    /// ```
+    ///
+    ///
+    /// Relative URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "/hello/world".parse().unwrap();
+    ///
+    /// assert!(uri.host().is_none());
+    /// ```
+    #[inline]
+    pub fn host(&self) -> Option<&str> {
+        self.authority_part().map(|a| a.host())
+    }
+
+    /// Get the port of this `Uri`.
+    ///
+    /// The port subcomponent of authority is designated by an optional port
+    /// number in decimal following the host and delimited from it by a single
+    /// colon (":") character. A value is only returned if one is specified in
+    /// the URI string, i.e., default port values are **not** returned.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                                     |-|
+    ///                                      |
+    ///                                     port
+    /// ```
+    ///
+    /// # Examples
+    ///
+    /// Absolute URI with port
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(uri.port(), Some(80));
+    /// ```
+    ///
+    /// Absolute URI without port
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
+    ///
+    /// assert!(uri.port().is_none());
+    /// ```
+    ///
+    /// Relative URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "/hello/world".parse().unwrap();
+    ///
+    /// assert!(uri.port().is_none());
+    /// ```
+    pub fn port(&self) -> Option<u16> {
+        self.authority_part()
+            .and_then(|a| a.port())
+    }
+
+    /// Get the query string of this `Uri`, starting after the `?`.
+    ///
+    /// The query component contains non-hierarchical data that, along with data
+    /// in the path component, serves to identify a resource within the scope of
+    /// the URI's scheme and naming authority (if any). The query component is
+    /// indicated by the first question mark ("?") character and terminated by a
+    /// number sign ("#") character or by the end of the URI.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                                                   |-------------------|
+    ///                                                             |
+    ///                                                           query
+    /// ```
+    ///
+    /// # Examples
+    ///
+    /// Absolute URI
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "http://example.org/hello/world?key=value".parse().unwrap();
+    ///
+    /// assert_eq!(uri.query(), Some("key=value"));
+    /// ```
+    ///
+    /// Relative URI with a query string component
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "/hello/world?key=value&foo=bar".parse().unwrap();
+    ///
+    /// assert_eq!(uri.query(), Some("key=value&foo=bar"));
+    /// ```
+    ///
+    /// Relative URI without a query string component
+    ///
+    /// ```
+    /// # use http::Uri;
+    /// let uri: Uri = "/hello/world".parse().unwrap();
+    ///
+    /// assert!(uri.query().is_none());
+    /// ```
+    #[inline]
+    pub fn query(&self) -> Option<&str> {
+        self.path_and_query.query()
+    }
+
+    fn has_path(&self) -> bool {
+        !self.path_and_query.data.is_empty() || !self.scheme.inner.is_none()
+    }
+}
+
+impl<'a> HttpTryFrom<&'a str> for Uri {
+    type Error = InvalidUri;
+
+    #[inline]
+    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
+        t.parse()
+    }
+}
+
+impl<'a> HttpTryFrom<&'a String> for Uri {
+    type Error = InvalidUri;
+
+    #[inline]
+    fn try_from(t: &'a String) -> Result<Self, Self::Error> {
+        t.parse()
+    }
+}
+
+impl HttpTryFrom<String> for Uri {
+    type Error = InvalidUriBytes;
+
+    #[inline]
+    fn try_from(t: String) -> Result<Self, Self::Error> {
+        Uri::from_shared(Bytes::from(t))
+    }
+}
+
+impl HttpTryFrom<Bytes> for Uri {
+    type Error = InvalidUriBytes;
+
+    #[inline]
+    fn try_from(t: Bytes) -> Result<Self, Self::Error> {
+        Uri::from_shared(t)
+    }
+}
+
+impl HttpTryFrom<Parts> for Uri {
+    type Error = InvalidUriParts;
+
+    #[inline]
+    fn try_from(src: Parts) -> Result<Self, Self::Error> {
+        Uri::from_parts(src)
+    }
+}
+
+impl<'a> HttpTryFrom<&'a Uri> for Uri {
+    type Error = ::Error;
+
+    #[inline]
+    fn try_from(src: &'a Uri) -> Result<Self, Self::Error> {
+        Ok(src.clone())
+    }
+}
+
+/// Convert a `Uri` from parts
+///
+/// # Examples
+///
+/// Relative URI
+///
+/// ```
+/// # use http::uri::*;
+/// let mut parts = Parts::default();
+/// parts.path_and_query = Some("/foo".parse().unwrap());
+///
+/// let uri = Uri::from_parts(parts).unwrap();
+///
+/// assert_eq!(uri.path(), "/foo");
+///
+/// assert!(uri.scheme_part().is_none());
+/// assert!(uri.authority().is_none());
+/// ```
+///
+/// Absolute URI
+///
+/// ```
+/// # use http::uri::*;
+/// let mut parts = Parts::default();
+/// parts.scheme = Some("http".parse().unwrap());
+/// parts.authority = Some("foo.com".parse().unwrap());
+/// parts.path_and_query = Some("/foo".parse().unwrap());
+///
+/// let uri = Uri::from_parts(parts).unwrap();
+///
+/// assert_eq!(uri.scheme_part().unwrap().as_str(), "http");
+/// assert_eq!(uri.authority().unwrap(), "foo.com");
+/// assert_eq!(uri.path(), "/foo");
+/// ```
+impl From<Uri> for Parts {
+    fn from(src: Uri) -> Self {
+        let path_and_query = if src.has_path() {
+            Some(src.path_and_query)
+        } else {
+            None
+        };
+
+        let scheme = match src.scheme.inner {
+            Scheme2::None => None,
+            _ => Some(src.scheme),
+        };
+
+        let authority = if src.authority.data.is_empty() {
+            None
+        } else {
+            Some(src.authority)
+        };
+
+        Parts {
+            scheme: scheme,
+            authority: authority,
+            path_and_query: path_and_query,
+            _priv: (),
+        }
+    }
+}
+
+fn parse_full(mut s: Bytes) -> Result<Uri, InvalidUriBytes> {
+    // Parse the scheme
+    let scheme = match Scheme2::parse(&s[..]).map_err(InvalidUriBytes)? {
+        Scheme2::None => Scheme2::None,
+        Scheme2::Standard(p) => {
+            // TODO: use truncate
+            let _ = s.split_to(p.len() + 3);
+            Scheme2::Standard(p)
+        }
+        Scheme2::Other(n) => {
+            // Grab the protocol
+            let mut scheme = s.split_to(n + 3);
+
+            // Strip ://, TODO: truncate
+            let _ = scheme.split_off(n);
+
+            // Allocate the ByteStr
+            let val = unsafe { ByteStr::from_utf8_unchecked(scheme) };
+
+            Scheme2::Other(Box::new(val))
+        }
+    };
+
+    // Find the end of the authority. The scheme will already have been
+    // extracted.
+    let authority_end = Authority::parse(&s[..]).map_err(InvalidUriBytes)?;
+
+    if scheme.is_none() {
+        if authority_end != s.len() {
+            return Err(ErrorKind::InvalidFormat.into());
+        }
+
+        let authority = Authority {
+            data: unsafe { ByteStr::from_utf8_unchecked(s) },
+        };
+
+        return Ok(Uri {
+            scheme: scheme.into(),
+            authority: authority,
+            path_and_query: PathAndQuery::empty(),
+        });
+    }
+
+    // Authority is required when absolute
+    if authority_end == 0 {
+        return Err(ErrorKind::InvalidFormat.into());
+    }
+
+    let authority = s.split_to(authority_end);
+    let authority = Authority {
+        data: unsafe { ByteStr::from_utf8_unchecked(authority) },
+    };
+
+    Ok(Uri {
+        scheme: scheme.into(),
+        authority: authority,
+        path_and_query: PathAndQuery::from_shared(s)?,
+    })
+}
+
+impl FromStr for Uri {
+    type Err = InvalidUri;
+
+    #[inline]
+    fn from_str(s: &str) -> Result<Uri, InvalidUri> {
+        Uri::from_shared(s.into()).map_err(|e| e.0)
+    }
+}
+
+impl PartialEq for Uri {
+    fn eq(&self, other: &Uri) -> bool {
+        if self.scheme_part() != other.scheme_part() {
+            return false;
+        }
+
+        if self.authority_part() != other.authority_part() {
+            return false;
+        }
+
+        if self.path() != other.path() {
+            return false;
+        }
+
+        if self.query() != other.query() {
+            return false;
+        }
+
+        true
+    }
+}
+
+impl PartialEq<str> for Uri {
+    fn eq(&self, other: &str) -> bool {
+        let mut other = other.as_bytes();
+        let mut absolute = false;
+
+        if let Some(scheme) = self.scheme_part() {
+            let scheme = scheme.as_str().as_bytes();
+            absolute = true;
+
+            if other.len() < scheme.len() + 3 {
+                return false;
+            }
+
+            if !scheme.eq_ignore_ascii_case(&other[..scheme.len()]) {
+                return false;
+            }
+
+            other = &other[scheme.len()..];
+
+            if &other[..3] != b"://" {
+                return false;
+            }
+
+            other = &other[3..];
+        }
+
+        if let Some(auth) = self.authority_part() {
+            let len = auth.data.len();
+            absolute = true;
+
+            if other.len() < len {
+                return false;
+            }
+
+            if !auth.data.as_bytes().eq_ignore_ascii_case(&other[..len]) {
+                return false;
+            }
+
+            other = &other[len..];
+        }
+
+        let path = self.path();
+
+        if other.len() < path.len() || path.as_bytes() != &other[..path.len()] {
+            if absolute && path == "/" {
+                // PathAndQuery can be ommitted, fall through
+            } else {
+                return false;
+            }
+        } else {
+            other = &other[path.len()..];
+        }
+
+        if let Some(query) = self.query() {
+            if other[0] != b'?' {
+                return false;
+            }
+
+            other = &other[1..];
+
+            if other.len() < query.len() {
+                return false;
+            }
+
+            if query.as_bytes() != &other[..query.len()] {
+                return false;
+            }
+
+            other = &other[query.len()..];
+        }
+
+        other.is_empty() || other[0] == b'#'
+    }
+}
+
+impl PartialEq<Uri> for str {
+    fn eq(&self, uri: &Uri) -> bool {
+        uri == self
+    }
+}
+
+impl<'a> PartialEq<&'a str> for Uri {
+    fn eq(&self, other: & &'a str) -> bool {
+        self == *other
+    }
+}
+
+impl<'a> PartialEq<Uri> for &'a str {
+    fn eq(&self, uri: &Uri) -> bool {
+        uri == *self
+    }
+}
+
+impl Eq for Uri {}
+
+/// Returns a `Uri` representing `/`
+impl Default for Uri {
+    #[inline]
+    fn default() -> Uri {
+        Uri {
+            scheme: Scheme::empty(),
+            authority: Authority::empty(),
+            path_and_query: PathAndQuery::slash(),
+        }
+    }
+}
+
+impl fmt::Display for Uri {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if let Some(scheme) = self.scheme_part() {
+            write!(f, "{}://", scheme)?;
+        }
+
+        if let Some(authority) = self.authority_part() {
+            write!(f, "{}", authority)?;
+        }
+
+        write!(f, "{}", self.path())?;
+
+        if let Some(query) = self.query() {
+            write!(f, "?{}", query)?;
+        }
+
+        Ok(())
+    }
+}
+
+impl fmt::Debug for Uri {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
+impl From<ErrorKind> for InvalidUri {
+    fn from(src: ErrorKind) -> InvalidUri {
+        InvalidUri(src)
+    }
+}
+
+impl From<ErrorKind> for InvalidUriBytes {
+    fn from(src: ErrorKind) -> InvalidUriBytes {
+        InvalidUriBytes(src.into())
+    }
+}
+
+impl From<ErrorKind> for InvalidUriParts {
+    fn from(src: ErrorKind) -> InvalidUriParts {
+        InvalidUriParts(src.into())
+    }
+}
+
+impl fmt::Display for InvalidUri {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.description().fmt(f)
+    }
+}
+
+impl Error for InvalidUri {
+    fn description(&self) -> &str {
+        match self.0 {
+            ErrorKind::InvalidUriChar => "invalid uri character",
+            ErrorKind::InvalidScheme => "invalid scheme",
+            ErrorKind::InvalidAuthority => "invalid authority",
+            ErrorKind::InvalidFormat => "invalid format",
+            ErrorKind::SchemeMissing => "scheme missing",
+            ErrorKind::AuthorityMissing => "authority missing",
+            ErrorKind::PathAndQueryMissing => "path missing",
+            ErrorKind::TooLong => "uri too long",
+            ErrorKind::Empty => "empty string",
+            ErrorKind::SchemeTooLong => "scheme too long",
+        }
+    }
+}
+
+impl fmt::Display for InvalidUriBytes {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl fmt::Display for InvalidUriParts {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl Error for InvalidUriBytes {
+    fn description(&self) -> &str {
+        self.0.description()
+    }
+}
+
+impl Error for InvalidUriParts {
+    fn description(&self) -> &str {
+        self.0.description()
+    }
+}
+
+impl Hash for Uri {
+    fn hash<H>(&self, state: &mut H) where H: Hasher {
+        if !self.scheme.inner.is_none() {
+            self.scheme.hash(state);
+            state.write_u8(0xff);
+        }
+
+        if let Some(auth) = self.authority_part() {
+            auth.hash(state);
+        }
+
+        Hash::hash_slice(self.path().as_bytes(), state);
+
+        if let Some(query) = self.query() {
+            b'?'.hash(state);
+            Hash::hash_slice(query.as_bytes(), state);
+        }
+    }
+}
diff --git a/third_party/http/src/uri/path.rs b/third_party/http/src/uri/path.rs
new file mode 100644
index 0000000..a3bbb09
--- /dev/null
+++ b/third_party/http/src/uri/path.rs
@@ -0,0 +1,508 @@
+use std::prelude::v1::*;
+use std::{cmp, fmt, str};
+use std::str::FromStr;
+
+use bytes::Bytes;
+
+use byte_str::ByteStr;
+use super::{ErrorKind, InvalidUri, InvalidUriBytes, URI_CHARS};
+
+/// Represents the path component of a URI
+#[derive(Clone)]
+pub struct PathAndQuery {
+    pub(super) data: ByteStr,
+    pub(super) query: u16,
+}
+
+const NONE: u16 = ::std::u16::MAX;
+
+impl PathAndQuery {
+    /// Attempt to convert a `PathAndQuery` from `Bytes`.
+    ///
+    /// This function will be replaced by a `TryFrom` implementation once the
+    /// trait lands in stable.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # extern crate http;
+    /// # use http::uri::*;
+    /// extern crate bytes;
+    ///
+    /// use bytes::Bytes;
+    ///
+    /// # pub fn main() {
+    /// let bytes = Bytes::from("/hello?world");
+    /// let path_and_query = PathAndQuery::from_shared(bytes).unwrap();
+    ///
+    /// assert_eq!(path_and_query.path(), "/hello");
+    /// assert_eq!(path_and_query.query(), Some("world"));
+    /// # }
+    /// ```
+    pub fn from_shared(mut src: Bytes) -> Result<Self, InvalidUriBytes> {
+        let mut query = NONE;
+
+        let mut i = 0;
+
+        while i < src.len() {
+            let b = src[i];
+
+            match URI_CHARS[b as usize] {
+                0 => {
+                    if b == b'%' {
+                        // Check that there are enough chars for a percent
+                        // encoded char
+                        let perc_encoded =
+                            i + 3 <= src.len() && // enough capacity
+                            HEX_DIGIT[src[i + 1] as usize] != 0 &&
+                            HEX_DIGIT[src[i + 2] as usize] != 0;
+
+                        if !perc_encoded {
+                            return Err(ErrorKind::InvalidUriChar.into());
+                        }
+
+                        i += 3;
+                        continue;
+                    } else {
+                        return Err(ErrorKind::InvalidUriChar.into());
+                    }
+                }
+                b'?' => {
+                    if query == NONE {
+                        query = i as u16;
+                    }
+                }
+                b'#' => {
+                    // TODO: truncate
+                    src.split_off(i);
+                    break;
+                }
+                _ => {}
+            }
+
+            i += 1;
+        }
+
+        Ok(PathAndQuery {
+            data: unsafe { ByteStr::from_utf8_unchecked(src) },
+            query: query,
+        })
+    }
+
+    /// Convert a `PathAndQuery` from a static string.
+    ///
+    /// This function will not perform any copying, however the string is
+    /// checked to ensure that it is valid.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if the argument is an invalid path and query.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let v = PathAndQuery::from_static("/hello?world");
+    ///
+    /// assert_eq!(v.path(), "/hello");
+    /// assert_eq!(v.query(), Some("world"));
+    /// ```
+    #[inline]
+    pub fn from_static(src: &'static str) -> Self {
+        let src = Bytes::from_static(src.as_bytes());
+
+        PathAndQuery::from_shared(src)
+            .unwrap()
+    }
+
+    pub(super) fn empty() -> Self {
+        PathAndQuery {
+            data: ByteStr::new(),
+            query: NONE,
+        }
+    }
+
+    pub(super) fn slash() -> Self {
+        PathAndQuery {
+            data: ByteStr::from_static("/"),
+            query: NONE,
+        }
+    }
+
+    pub(super) fn star() -> Self {
+        PathAndQuery {
+            data: ByteStr::from_static("*"),
+            query: NONE,
+        }
+    }
+
+    /// Returns the path component
+    ///
+    /// The path component is **case sensitive**.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                                        |--------|
+    ///                                             |
+    ///                                           path
+    /// ```
+    ///
+    /// If the URI is `*` then the path component is equal to `*`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::uri::*;
+    ///
+    /// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(path_and_query.path(), "/hello/world");
+    /// ```
+    #[inline]
+    pub fn path(&self) -> &str {
+        let ret = if self.query == NONE {
+            &self.data[..]
+        } else {
+            &self.data[..self.query as usize]
+        };
+
+        if ret.is_empty() {
+            return "/";
+        }
+
+        ret
+    }
+
+    /// Returns the query string component
+    ///
+    /// The query component contains non-hierarchical data that, along with data
+    /// in the path component, serves to identify a resource within the scope of
+    /// the URI's scheme and naming authority (if any). The query component is
+    /// indicated by the first question mark ("?") character and terminated by a
+    /// number sign ("#") character or by the end of the URI.
+    ///
+    /// ```notrust
+    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
+    ///                                                   |-------------------|
+    ///                                                             |
+    ///                                                           query
+    /// ```
+    ///
+    /// # Examples
+    ///
+    /// With a query string component
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap();
+    ///
+    /// assert_eq!(path_and_query.query(), Some("key=value&foo=bar"));
+    /// ```
+    ///
+    /// Without a query string component
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
+    ///
+    /// assert!(path_and_query.query().is_none());
+    /// ```
+    #[inline]
+    pub fn query(&self) -> Option<&str> {
+        if self.query == NONE {
+            None
+        } else {
+            let i = self.query + 1;
+            Some(&self.data[i as usize..])
+        }
+    }
+
+    /// Returns the path and query as a string component.
+    ///
+    /// # Examples
+    ///
+    /// With a query string component
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap();
+    ///
+    /// assert_eq!(path_and_query.as_str(), "/hello/world?key=value&foo=bar");
+    /// ```
+    ///
+    /// Without a query string component
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
+    ///
+    /// assert_eq!(path_and_query.as_str(), "/hello/world");
+    /// ```
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        let ret = &self.data[..];
+        if ret.is_empty() {
+            return "/";
+        }
+        ret
+    }
+
+    /// Converts this `PathAndQuery` back to a sequence of bytes
+    #[inline]
+    pub fn into_bytes(self) -> Bytes {
+        self.into()
+    }
+}
+
+impl FromStr for PathAndQuery {
+    type Err = InvalidUri;
+
+    fn from_str(s: &str) -> Result<Self, InvalidUri> {
+        PathAndQuery::from_shared(s.into()).map_err(|e| e.0)
+    }
+}
+
+impl From<PathAndQuery> for Bytes {
+    fn from(src: PathAndQuery) -> Bytes {
+        src.data.into()
+    }
+}
+
+impl fmt::Debug for PathAndQuery {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
+impl fmt::Display for PathAndQuery {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        if !self.data.is_empty() {
+            match self.data.as_bytes()[0] {
+                b'/' | b'*' => write!(fmt, "{}", &self.data[..]),
+                _ => write!(fmt, "/{}", &self.data[..]),
+            }
+        } else {
+            write!(fmt, "/")
+        }
+    }
+}
+
+// ===== PartialEq / PartialOrd =====
+
+impl PartialEq for PathAndQuery {
+    #[inline]
+    fn eq(&self, other: &PathAndQuery) -> bool {
+        self.data == other.data
+    }
+}
+
+impl Eq for PathAndQuery {}
+
+impl PartialEq<str> for PathAndQuery {
+    #[inline]
+    fn eq(&self, other: &str) -> bool {
+        self.as_str() == other
+    }
+}
+
+impl<'a> PartialEq<PathAndQuery> for &'a str {
+    #[inline]
+    fn eq(&self, other: &PathAndQuery) -> bool {
+        self == &other.as_str()
+    }
+}
+
+impl<'a> PartialEq<&'a str> for PathAndQuery {
+    #[inline]
+    fn eq(&self, other: &&'a str) -> bool {
+        self.as_str() == *other
+    }
+}
+
+impl PartialEq<PathAndQuery> for str {
+    #[inline]
+    fn eq(&self, other: &PathAndQuery) -> bool {
+        self == other.as_str()
+    }
+}
+
+impl PartialEq<String> for PathAndQuery {
+    #[inline]
+    fn eq(&self, other: &String) -> bool {
+        self.as_str() == other.as_str()
+    }
+}
+
+impl PartialEq<PathAndQuery> for String {
+    #[inline]
+    fn eq(&self, other: &PathAndQuery) -> bool {
+        self.as_str() == other.as_str()
+    }
+}
+
+impl PartialOrd for PathAndQuery {
+    #[inline]
+    fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
+        self.as_str().partial_cmp(other.as_str())
+    }
+}
+
+impl PartialOrd<str> for PathAndQuery {
+    #[inline]
+    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+        self.as_str().partial_cmp(other)
+    }
+}
+
+impl PartialOrd<PathAndQuery> for str {
+    #[inline]
+    fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
+        self.partial_cmp(other.as_str())
+    }
+}
+
+impl<'a> PartialOrd<&'a str> for PathAndQuery {
+    #[inline]
+    fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
+        self.as_str().partial_cmp(*other)
+    }
+}
+
+impl<'a> PartialOrd<PathAndQuery> for &'a str {
+    #[inline]
+    fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
+        self.partial_cmp(&other.as_str())
+    }
+}
+
+impl PartialOrd<String> for PathAndQuery {
+    #[inline]
+    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
+        self.as_str().partial_cmp(other.as_str())
+    }
+}
+
+impl PartialOrd<PathAndQuery> for String {
+    #[inline]
+    fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
+        self.as_str().partial_cmp(other.as_str())
+    }
+}
+
+const HEX_DIGIT: [u8; 256] = [
+    //  0      1      2      3      4      5      6      7      8      9
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  3x
+        0,     0,     0,     0,     0,     0,     0,     0,  b'0',  b'1', //  4x
+     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',     0,     0, //  5x
+        0,     0,     0,     0,     0,  b'A',  b'B',  b'C',  b'D',  b'E', //  6x
+     b'F',  b'G',  b'H',  b'I',  b'J',  b'K',  b'L',  b'M',  b'N',  b'O', //  7x
+     b'P',  b'Q',  b'R',  b'S',  b'T',  b'U',  b'V',  b'W',  b'X',  b'Y', //  8x
+     b'Z',     0,     0,     0,     0,     0,     0,  b'a',  b'b',  b'c', //  9x
+     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
+     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
+     b'x',  b'y',  b'z',     0,     0,     0,  b'~',     0,     0,     0, // 12x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
+        0,     0,     0,     0,     0,     0                              // 25x
+];
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn equal_to_self_of_same_path() {
+        let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
+        let p2: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
+        assert_eq!(p1, p2);
+        assert_eq!(p2, p1);
+    }
+
+    #[test]
+    fn not_equal_to_self_of_different_path() {
+        let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
+        let p2: PathAndQuery = "/world&foo=bar".parse().unwrap();
+        assert_ne!(p1, p2);
+        assert_ne!(p2, p1);
+    }
+
+    #[test]
+    fn equates_with_a_str() {
+        let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
+        assert_eq!(&path_and_query, "/hello/world&foo=bar");
+        assert_eq!("/hello/world&foo=bar", &path_and_query);
+        assert_eq!(path_and_query, "/hello/world&foo=bar");
+        assert_eq!("/hello/world&foo=bar", path_and_query);
+    }
+
+    #[test]
+    fn not_equal_with_a_str_of_a_different_path() {
+        let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
+        // as a reference
+        assert_ne!(&path_and_query, "/hello&foo=bar");
+        assert_ne!("/hello&foo=bar", &path_and_query);
+        // without reference
+        assert_ne!(path_and_query, "/hello&foo=bar");
+        assert_ne!("/hello&foo=bar", path_and_query);
+    }
+
+    #[test]
+    fn equates_with_a_string() {
+        let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
+        assert_eq!(path_and_query, "/hello/world&foo=bar".to_string());
+        assert_eq!("/hello/world&foo=bar".to_string(), path_and_query);
+    }
+
+    #[test]
+    fn not_equal_with_a_string_of_a_different_path() {
+        let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
+        assert_ne!(path_and_query, "/hello&foo=bar".to_string());
+        assert_ne!("/hello&foo=bar".to_string(), path_and_query);
+    }
+
+    #[test]
+    fn compares_to_self() {
+        let p1: PathAndQuery = "/a/world&foo=bar".parse().unwrap();
+        let p2: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
+        assert!(p1 < p2);
+        assert!(p2 > p1);
+    }
+
+    #[test]
+    fn compares_with_a_str() {
+        let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
+        // by ref
+        assert!(&path_and_query < "/c/world&foo=bar");
+        assert!("/c/world&foo=bar" > &path_and_query);
+        assert!(&path_and_query > "/a/world&foo=bar");
+        assert!("/a/world&foo=bar" < &path_and_query);
+
+        // by val
+        assert!(path_and_query < "/c/world&foo=bar");
+        assert!("/c/world&foo=bar" > path_and_query);
+        assert!(path_and_query > "/a/world&foo=bar");
+        assert!("/a/world&foo=bar" < path_and_query);
+    }
+
+    #[test]
+    fn compares_with_a_string() {
+        let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
+        assert!(path_and_query < "/c/world&foo=bar".to_string());
+        assert!("/c/world&foo=bar".to_string() > path_and_query);
+        assert!(path_and_query > "/a/world&foo=bar".to_string());
+        assert!("/a/world&foo=bar".to_string() < path_and_query);
+    }
+}
diff --git a/third_party/http/src/uri/scheme.rs b/third_party/http/src/uri/scheme.rs
new file mode 100644
index 0000000..9e5b1f8
--- /dev/null
+++ b/third_party/http/src/uri/scheme.rs
@@ -0,0 +1,362 @@
+// Deprecated in 1.26, needed until our minimum version is >=1.23.
+#[allow(unused, deprecated)]
+use std::ascii::AsciiExt;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::str::FromStr;
+use std::prelude::v1::*;
+
+use bytes::Bytes;
+
+use byte_str::ByteStr;
+use super::{ErrorKind, InvalidUri, InvalidUriBytes};
+
+/// Represents the scheme component of a URI
+#[derive(Clone)]
+pub struct Scheme {
+    pub(super) inner: Scheme2,
+}
+
+#[derive(Clone, Debug)]
+pub(super) enum Scheme2<T = Box<ByteStr>> {
+    None,
+    Standard(Protocol),
+    Other(T),
+}
+
+#[derive(Copy, Clone, Debug)]
+pub(super) enum Protocol {
+    Http,
+    Https,
+}
+
+impl Scheme {
+    /// HTTP protocol scheme
+    pub const HTTP: Scheme = Scheme {
+        inner: Scheme2::Standard(Protocol::Http),
+    };
+
+    /// HTTP protocol over TLS.
+    pub const HTTPS: Scheme = Scheme {
+        inner: Scheme2::Standard(Protocol::Https),
+    };
+
+    /// Attempt to convert a `Scheme` from `Bytes`
+    ///
+    /// This function will be replaced by a `TryFrom` implementation once the
+    /// trait lands in stable.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # extern crate http;
+    /// # use http::uri::*;
+    /// extern crate bytes;
+    ///
+    /// use bytes::Bytes;
+    ///
+    /// # pub fn main() {
+    /// let bytes = Bytes::from("http");
+    /// let scheme = Scheme::from_shared(bytes).unwrap();
+    ///
+    /// assert_eq!(scheme.as_str(), "http");
+    /// # }
+    /// ```
+    pub fn from_shared(s: Bytes) -> Result<Self, InvalidUriBytes> {
+        use self::Scheme2::*;
+
+        match Scheme2::parse_exact(&s[..]).map_err(InvalidUriBytes)? {
+            None => Err(ErrorKind::InvalidScheme.into()),
+            Standard(p) => Ok(Standard(p).into()),
+            Other(_) => {
+                let b = unsafe { ByteStr::from_utf8_unchecked(s) };
+                Ok(Other(Box::new(b)).into())
+            }
+        }
+    }
+
+    pub(super) fn empty() -> Self {
+        Scheme {
+            inner: Scheme2::None,
+        }
+    }
+
+    /// Return a str representation of the scheme
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use http::uri::*;
+    /// let scheme: Scheme = "http".parse().unwrap();
+    /// assert_eq!(scheme.as_str(), "http");
+    /// ```
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        use self::Scheme2::*;
+        use self::Protocol::*;
+
+        match self.inner {
+            Standard(Http) => "http",
+            Standard(Https) => "https",
+            Other(ref v) => &v[..],
+            None => unreachable!(),
+        }
+    }
+
+    /// Converts this `Scheme` back to a sequence of bytes
+    #[inline]
+    pub fn into_bytes(self) -> Bytes {
+        self.into()
+    }
+}
+
+impl FromStr for Scheme {
+    type Err = InvalidUri;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        use self::Scheme2::*;
+
+        match Scheme2::parse_exact(s.as_bytes())? {
+            None => Err(ErrorKind::InvalidScheme.into()),
+            Standard(p) => Ok(Standard(p).into()),
+            Other(_) => {
+                Ok(Other(Box::new(s.into())).into())
+            }
+        }
+    }
+}
+
+impl From<Scheme> for Bytes {
+    #[inline]
+    fn from(src: Scheme) -> Self {
+        use self::Scheme2::*;
+        use self::Protocol::*;
+
+        match src.inner {
+            None => Bytes::new(),
+            Standard(Http) => Bytes::from_static(b"http"),
+            Standard(Https) => Bytes::from_static(b"https"),
+            Other(v) => (*v).into(),
+        }
+    }
+}
+
+impl fmt::Debug for Scheme {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(self.as_str(), f)
+    }
+}
+
+impl fmt::Display for Scheme {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
+impl AsRef<str> for Scheme {
+    #[inline]
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl PartialEq for Scheme {
+    fn eq(&self, other: &Scheme) -> bool {
+        use self::Protocol::*;
+        use self::Scheme2::*;
+
+        match (&self.inner, &other.inner) {
+            (&Standard(Http), &Standard(Http)) => true,
+            (&Standard(Https), &Standard(Https)) => true,
+            (&Other(ref a), &Other(ref b)) => a.eq_ignore_ascii_case(b),
+            (&None, _) | (_, &None) => unreachable!(),
+            _ => false,
+        }
+    }
+}
+
+impl Eq for Scheme {}
+
+/// Case-insensitive equality
+///
+/// # Examples
+///
+/// ```
+/// # use http::uri::Scheme;
+/// let scheme: Scheme = "HTTP".parse().unwrap();
+/// assert_eq!(scheme, *"http");
+/// ```
+impl PartialEq<str> for Scheme {
+    fn eq(&self, other: &str) -> bool {
+        self.as_str().eq_ignore_ascii_case(other)
+    }
+}
+
+/// Case-insensitive equality
+impl PartialEq<Scheme> for str {
+    fn eq(&self, other: &Scheme) -> bool {
+        other == self
+    }
+}
+
+/// Case-insensitive hashing
+impl Hash for Scheme {
+    fn hash<H>(&self, state: &mut H) where H: Hasher {
+        match self.inner {
+            Scheme2::None => (),
+            Scheme2::Standard(Protocol::Http) => state.write_u8(1),
+            Scheme2::Standard(Protocol::Https) => state.write_u8(2),
+            Scheme2::Other(ref other) => {
+                other.len().hash(state);
+                for &b in other.as_bytes() {
+                    state.write_u8(b.to_ascii_lowercase());
+                }
+            }
+        }
+    }
+}
+
+impl<T> Scheme2<T> {
+    pub(super) fn is_none(&self) -> bool {
+        match *self {
+            Scheme2::None => true,
+            _ => false,
+        }
+    }
+}
+
+// Require the scheme to not be too long in order to enable further
+// optimizations later.
+const MAX_SCHEME_LEN: usize = 64;
+
+// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+//
+const SCHEME_CHARS: [u8; 256] = [
+    //  0      1      2      3      4      5      6      7      8      9
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  3x
+        0,     0,     0,  b'+',     0,  b'-',  b'.',     0,  b'0',  b'1', //  4x
+     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',  b':',     0, //  5x
+        0,     0,     0,     0,     0,  b'A',  b'B',  b'C',  b'D',  b'E', //  6x
+     b'F',  b'G',  b'H',  b'I',  b'J',  b'K',  b'L',  b'M',  b'N',  b'O', //  7x
+     b'P',  b'Q',  b'R',  b'S',  b'T',  b'U',  b'V',  b'W',  b'X',  b'Y', //  8x
+     b'Z',     0,     0,     0,     0,     0,     0,  b'a',  b'b',  b'c', //  9x
+     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
+     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
+     b'x',  b'y',  b'z',     0,     0,     0,  b'~',     0,     0,     0, // 12x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
+        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
+        0,     0,     0,     0,     0,     0                              // 25x
+];
+
+impl Scheme2<usize> {
+    fn parse_exact(s: &[u8]) -> Result<Scheme2<()>, InvalidUri> {
+        match s {
+            b"http" => Ok(Protocol::Http.into()),
+            b"https" => Ok(Protocol::Https.into()),
+            _ => {
+                if s.len() > MAX_SCHEME_LEN {
+                    return Err(ErrorKind::SchemeTooLong.into());
+                }
+
+                for &b in s {
+                    match SCHEME_CHARS[b as usize] {
+                        b':' => {
+                            // Don't want :// here
+                            return Err(ErrorKind::InvalidScheme.into());
+                        }
+                        0 => {
+                            return Err(ErrorKind::InvalidScheme.into());
+                        }
+                        _ => {}
+                    }
+                }
+
+                Ok(Scheme2::Other(()))
+            }
+        }
+    }
+
+    pub(super) fn parse(s: &[u8]) -> Result<Scheme2<usize>, InvalidUri> {
+        if s.len() >= 7 {
+            // Check for HTTP
+            if s[..7].eq_ignore_ascii_case(b"http://") {
+                // Prefix will be striped
+                return Ok(Protocol::Http.into());
+            }
+        }
+
+        if s.len() >= 8 {
+            // Check for HTTPs
+            if s[..8].eq_ignore_ascii_case(b"https://") {
+                return Ok(Protocol::Https.into());
+            }
+        }
+
+        if s.len() > 3 {
+            for i in 0..s.len() {
+                let b = s[i];
+
+                if i == MAX_SCHEME_LEN {
+                    return Err(ErrorKind::SchemeTooLong.into());
+                }
+
+                match SCHEME_CHARS[b as usize] {
+                    b':' => {
+                        // Not enough data remaining
+                        if s.len() < i + 3 {
+                            break;
+                        }
+
+                        // Not a scheme
+                        if &s[i+1..i+3] != b"//" {
+                            break;
+                        }
+
+                        // Return scheme
+                        return Ok(Scheme2::Other(i));
+                    }
+                    // Invald scheme character, abort
+                    0 => break,
+                    _ => {}
+                }
+            }
+        }
+
+        Ok(Scheme2::None)
+    }
+}
+
+impl Protocol {
+    pub(super) fn len(&self) -> usize {
+        match *self {
+            Protocol::Http => 4,
+            Protocol::Https => 5,
+        }
+    }
+}
+
+impl<T> From<Protocol> for Scheme2<T> {
+    fn from(src: Protocol) -> Self {
+        Scheme2::Standard(src)
+    }
+}
+
+#[doc(hidden)]
+impl From<Scheme2> for Scheme {
+    fn from(src: Scheme2) -> Self {
+        Scheme { inner: src }
+    }
+}
diff --git a/third_party/http/src/uri/tests.rs b/third_party/http/src/uri/tests.rs
new file mode 100644
index 0000000..08b32ea
--- /dev/null
+++ b/third_party/http/src/uri/tests.rs
@@ -0,0 +1,447 @@
+use std::str::FromStr;
+
+use super::{ErrorKind, InvalidUri, Uri, URI_CHARS};
+
+#[test]
+fn test_char_table() {
+    for (i, &v) in URI_CHARS.iter().enumerate() {
+        if v != 0 {
+            assert_eq!(i, v as usize);
+        }
+    }
+}
+
+macro_rules! part {
+    ($s:expr) => (
+        Some(&$s.parse().unwrap())
+    )
+}
+
+macro_rules! test_parse {
+    (
+        $test_name:ident,
+        $str:expr,
+        $alt:expr,
+        $($method:ident = $value:expr,)*
+    ) => (
+        #[test]
+        fn $test_name() {
+            let orig_str = $str;
+            let uri = Uri::from_str(orig_str).unwrap();
+            $(
+            assert_eq!(uri.$method(), $value, "{}: uri = {:?}", stringify!($method), uri);
+            )+
+            assert_eq!(uri, orig_str, "partial eq to original str");
+            assert_eq!(uri, uri.clone(), "clones are equal");
+
+            let new_str = uri.to_string();
+            let new_uri = Uri::from_str(&new_str).expect("to_string output parses again as a Uri");
+            assert_eq!(new_uri, orig_str, "round trip still equals original str");
+
+            const ALT: &'static [&'static str] = &$alt;
+
+            for &alt in ALT.iter() {
+                let other: Uri = alt.parse().unwrap();
+                assert_eq!(uri, *alt);
+                assert_eq!(uri, other);
+            }
+        }
+    );
+}
+
+test_parse! {
+    test_uri_parse_path_and_query,
+    "/some/path/here?and=then&hello#and-bye",
+    [],
+
+    scheme_part = None,
+    authority_part = None,
+    path = "/some/path/here",
+    query = Some("and=then&hello"),
+    host = None,
+}
+
+test_parse! {
+    test_uri_parse_absolute_form,
+    "http://127.0.0.1:61761/chunks",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("127.0.0.1:61761"),
+    path = "/chunks",
+    query = None,
+    host = Some("127.0.0.1"),
+    port = Some(61761),
+}
+
+test_parse! {
+    test_uri_parse_absolute_form_without_path,
+    "https://127.0.0.1:61761",
+    ["https://127.0.0.1:61761/"],
+
+    scheme_part = part!("https"),
+    authority_part = part!("127.0.0.1:61761"),
+    path = "/",
+    query = None,
+    port = Some(61761),
+    host = Some("127.0.0.1"),
+}
+
+test_parse! {
+    test_uri_parse_asterisk_form,
+    "*",
+    [],
+
+    scheme_part = None,
+    authority_part = None,
+    path = "*",
+    query = None,
+    host = None,
+}
+
+test_parse! {
+    test_uri_parse_authority_no_port,
+    "localhost",
+    ["LOCALHOST", "LocaLHOSt"],
+
+    scheme_part = None,
+    authority_part = part!("localhost"),
+    path = "",
+    query = None,
+    port = None,
+    host = Some("localhost"),
+}
+
+test_parse! {
+    test_uri_authority_only_one_character_issue_197,
+    "S",
+    [],
+
+    scheme_part = None,
+    authority_part = part!("S"),
+    path = "",
+    query = None,
+    port = None,
+    host = Some("S"),
+}
+
+test_parse! {
+    test_uri_parse_authority_form,
+    "localhost:3000",
+    ["localhosT:3000"],
+
+    scheme_part = None,
+    authority_part = part!("localhost:3000"),
+    path = "",
+    query = None,
+    host = Some("localhost"),
+    port = Some(3000),
+}
+
+
+test_parse! {
+    test_uri_parse_absolute_with_default_port_http,
+    "http://127.0.0.1:80",
+    ["http://127.0.0.1:80/"],
+
+    scheme_part = part!("http"),
+    authority_part = part!("127.0.0.1:80"),
+    host = Some("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = Some(80),
+}
+
+test_parse! {
+    test_uri_parse_absolute_with_default_port_https,
+    "https://127.0.0.1:443",
+    ["https://127.0.0.1:443/"],
+
+    scheme_part = part!("https"),
+    authority_part = part!("127.0.0.1:443"),
+    host = Some("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = Some(443),
+}
+
+test_parse! {
+    test_uri_parse_fragment_questionmark,
+    "http://127.0.0.1/#?",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("127.0.0.1"),
+    host = Some("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_uri_parse_path_with_terminating_questionmark,
+    "http://127.0.0.1/path?",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("127.0.0.1"),
+    path = "/path",
+    query = Some(""),
+    port = None,
+}
+
+test_parse! {
+    test_uri_parse_absolute_form_with_empty_path_and_nonempty_query,
+    "http://127.0.0.1?foo=bar",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("127.0.0.1"),
+    path = "/",
+    query = Some("foo=bar"),
+    port = None,
+}
+
+test_parse! {
+    test_uri_parse_absolute_form_with_empty_path_and_fragment_with_slash,
+    "http://127.0.0.1#foo/bar",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_uri_parse_absolute_form_with_empty_path_and_fragment_with_questionmark,
+    "http://127.0.0.1#foo?bar",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_userinfo1,
+    "http://a:b@127.0.0.1:1234/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("a:b@127.0.0.1:1234"),
+    host = Some("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = Some(1234),
+}
+
+test_parse! {
+    test_userinfo2,
+    "http://a:b@127.0.0.1/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("a:b@127.0.0.1"),
+    host = Some("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_userinfo3,
+    "http://a@127.0.0.1/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("a@127.0.0.1"),
+    host = Some("127.0.0.1"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_userinfo_with_port,
+    "user@localhost:3000",
+    [],
+
+    scheme_part = None,
+    authority_part = part!("user@localhost:3000"),
+    path = "",
+    query = None,
+    host = Some("localhost"),
+    port = Some(3000),
+}
+
+test_parse! {
+    test_userinfo_pass_with_port,
+    "user:pass@localhost:3000",
+    [],
+
+    scheme_part = None,
+    authority_part = part!("user:pass@localhost:3000"),
+    path = "",
+    query = None,
+    host = Some("localhost"),
+    port = Some(3000),
+}
+
+test_parse! {
+    test_ipv6,
+    "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
+    host = Some("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_ipv6_shorthand,
+    "http://[::1]/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("[::1]"),
+    host = Some("::1"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_ipv6_shorthand2,
+    "http://[::]/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("[::]"),
+    host = Some("::"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_ipv6_shorthand3,
+    "http://[2001:db8::2:1]/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("[2001:db8::2:1]"),
+    host = Some("2001:db8::2:1"),
+    path = "/",
+    query = None,
+    port = None,
+}
+
+test_parse! {
+    test_ipv6_with_port,
+    "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008/",
+    [],
+
+    scheme_part = part!("http"),
+    authority_part = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008"),
+    host = Some("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
+    path = "/",
+    query = None,
+    port = Some(8008),
+}
+
+test_parse! {
+    test_percentage_encoded_path,
+    "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478",
+    [],
+
+    scheme_part = None,
+    authority_part = None,
+    host = None,
+    path = "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478",
+    query = None,
+    port = None,
+}
+
+#[test]
+fn test_uri_parse_error() {
+    fn err(s: &str) {
+        Uri::from_str(s).unwrap_err();
+    }
+
+    err("http://");
+    err("htt:p//host");
+    err("hyper.rs/");
+    err("hyper.rs?key=val");
+    err("?key=val");
+    err("localhost/");
+    err("localhost?key=val");
+    err("\0");
+    err("http://[::1");
+    err("http://::1]");
+    err("localhost:8080:3030");
+}
+
+#[test]
+fn test_max_uri_len() {
+    let mut uri = vec![];
+    uri.extend(b"http://localhost/");
+    uri.extend(vec![b'a'; 70 * 1024]);
+
+    let uri = String::from_utf8(uri).unwrap();
+    let res: Result<Uri, InvalidUri> = uri.parse();
+
+    assert_eq!(res.unwrap_err().0, ErrorKind::TooLong);
+}
+
+#[test]
+fn test_long_scheme() {
+    let mut uri = vec![];
+    uri.extend(vec![b'a'; 256]);
+    uri.extend(b"://localhost/");
+
+    let uri = String::from_utf8(uri).unwrap();
+    let res: Result<Uri, InvalidUri> = uri.parse();
+
+    assert_eq!(res.unwrap_err().0, ErrorKind::SchemeTooLong);
+}
+
+#[test]
+fn test_uri_to_path_and_query() {
+    let cases = vec![
+        ("/", "/"),
+        ("/foo?bar", "/foo?bar"),
+        ("/foo?bar#nope", "/foo?bar"),
+        ("http://hyper.rs", "/"),
+        ("http://hyper.rs/", "/"),
+        ("http://hyper.rs/path", "/path"),
+        ("http://hyper.rs?query", "/?query"),
+        ("*", "*"),
+    ];
+
+    for case in cases {
+        let uri = Uri::from_str(case.0).unwrap();
+        let s = uri.path_and_query().unwrap().to_string();
+
+        assert_eq!(s, case.1);
+    }
+}
+
+#[test]
+fn test_authority_uri_parts_round_trip() {
+    let s = "hyper.rs";
+    let uri = Uri::from_str(s).expect("first parse");
+    assert_eq!(uri, s);
+    assert_eq!(uri.to_string(), s);
+
+    let parts = uri.into_parts();
+    let uri2 = Uri::from_parts(parts).expect("from_parts");
+    assert_eq!(uri2, s);
+    assert_eq!(uri2.to_string(), s);
+}
diff --git a/third_party/http/src/version.rs b/third_party/http/src/version.rs
new file mode 100644
index 0000000..3229dc3
--- /dev/null
+++ b/third_party/http/src/version.rs
@@ -0,0 +1,68 @@
+//! HTTP version
+//!
+//! This module contains a definition of the `Version` type. The `Version`
+//! type is intended to be accessed through the root of the crate
+//! (`http::Version`) rather than this module.
+//!
+//! The `Version` type contains constants that represent the various versions
+//! of the HTTP protocol.
+//!
+//! # Examples
+//!
+//! ```
+//! use http::Version;
+//!
+//! let http11 = Version::HTTP_11;
+//! let http2 = Version::HTTP_2;
+//! assert!(http11 != http2);
+//!
+//! println!("{:?}", http2);
+//! ```
+
+use std::fmt;
+
+/// Represents a version of the HTTP spec.
+#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)]
+pub struct Version(Http);
+
+impl Version {
+    /// `HTTP/0.9`
+    pub const HTTP_09: Version = Version(Http::Http09);
+
+    /// `HTTP/1.0`
+    pub const HTTP_10: Version = Version(Http::Http10);
+
+    /// `HTTP/1.1`
+    pub const HTTP_11: Version = Version(Http::Http11);
+
+    /// `HTTP/2.0`
+    pub const HTTP_2: Version = Version(Http::H2);
+}
+
+#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)]
+enum Http {
+    Http09,
+    Http10,
+    Http11,
+    H2,
+}
+
+impl Default for Version {
+    #[inline]
+    fn default() -> Version {
+        Version::HTTP_11
+    }
+}
+
+impl fmt::Debug for Version {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Http::*;
+
+        f.write_str(match self.0 {
+            Http09 => "HTTP/0.9",
+            Http10 => "HTTP/1.0",
+            Http11 => "HTTP/1.1",
+            H2     => "HTTP/2.0",
+        })
+    }
+}
diff --git a/third_party/http/tests/header_map.rs b/third_party/http/tests/header_map.rs
new file mode 100644
index 0000000..2fbb95e
--- /dev/null
+++ b/third_party/http/tests/header_map.rs
@@ -0,0 +1,321 @@
+extern crate http;
+
+use http::*;
+use http::header::*;
+
+#[test]
+fn smoke() {
+    let mut headers = HeaderMap::new();
+
+    assert!(headers.get("hello").is_none());
+
+    let name: HeaderName = "hello".parse().unwrap();
+
+    match headers.entry(&name).unwrap() {
+        Entry::Vacant(e) => {
+            e.insert("world".parse().unwrap());
+        }
+        _ => panic!(),
+    }
+
+    assert!(headers.get("hello").is_some());
+
+    match headers.entry(&name).unwrap() {
+        Entry::Occupied(mut e) => {
+            assert_eq!(e.get(), &"world");
+
+            // Push another value
+            e.append("zomg".parse().unwrap());
+
+            let mut i = e.iter();
+
+            assert_eq!(*i.next().unwrap(), "world");
+            assert_eq!(*i.next().unwrap(), "zomg");
+            assert!(i.next().is_none());
+        }
+        _ => panic!(),
+    }
+}
+
+#[test]
+fn drain() {
+    let mut headers = HeaderMap::new();
+
+    // Insert a single value
+    let name: HeaderName = "hello".parse().unwrap();
+    headers.insert(name, "world".parse().unwrap());
+
+    {
+        let mut iter = headers.drain();
+        let (name, values) = iter.next().unwrap();
+        assert_eq!(name.as_str(), "hello");
+
+        let values: Vec<_> = values.collect();
+        assert_eq!(values.len(), 1);
+        assert_eq!(values[0], "world");
+
+        assert!(iter.next().is_none());
+    }
+
+    assert!(headers.is_empty());
+
+    // Insert two sequential values
+    headers.insert("hello".parse::<HeaderName>().unwrap(), "world".parse().unwrap());
+    headers.insert("zomg".parse::<HeaderName>().unwrap(), "bar".parse().unwrap());
+    headers.append("hello".parse::<HeaderName>().unwrap(), "world2".parse().unwrap());
+
+    // Drain...
+    {
+        let mut iter = headers.drain();
+        let (name, values) = iter.next().unwrap();
+        assert_eq!(name.as_str(), "hello");
+
+        let values: Vec<_> = values.collect();
+        assert_eq!(values.len(), 2);
+        assert_eq!(values[0], "world");
+        assert_eq!(values[1], "world2");
+
+        let (name, values) = iter.next().unwrap();
+        assert_eq!(name.as_str(), "zomg");
+
+        let values: Vec<_> = values.collect();
+        assert_eq!(values.len(), 1);
+        assert_eq!(values[0], "bar");
+
+        assert!(iter.next().is_none());
+    }
+}
+
+#[test]
+fn drain_entry() {
+    let mut headers = HeaderMap::new();
+
+    headers.insert("hello".parse::<HeaderName>().unwrap(), "world".parse().unwrap());
+    headers.insert("zomg".parse::<HeaderName>().unwrap(), "foo".parse().unwrap());
+    headers.append("hello".parse::<HeaderName>().unwrap(), "world2".parse().unwrap());
+    headers.insert("more".parse::<HeaderName>().unwrap(), "words".parse().unwrap());
+    headers.append("more".parse::<HeaderName>().unwrap(), "insertions".parse().unwrap());
+
+    // Using insert
+    {
+        let mut e = match headers.entry("hello").unwrap() {
+            Entry::Occupied(e) => e,
+            _ => panic!(),
+        };
+
+        let vals: Vec<_> = e.insert_mult("wat".parse().unwrap()).collect();
+        assert_eq!(2, vals.len());
+        assert_eq!(vals[0], "world");
+        assert_eq!(vals[1], "world2");
+    }
+}
+
+#[test]
+fn eq() {
+    let mut a = HeaderMap::new();
+    let mut b = HeaderMap::new();
+
+    assert_eq!(a, b);
+
+    a.insert("hello".parse::<HeaderName>().unwrap(), "world".parse().unwrap());
+    assert_ne!(a, b);
+
+    b.insert("hello".parse::<HeaderName>().unwrap(), "world".parse().unwrap());
+    assert_eq!(a, b);
+
+    a.insert("foo".parse::<HeaderName>().unwrap(), "bar".parse().unwrap());
+    a.append("foo".parse::<HeaderName>().unwrap(), "baz".parse().unwrap());
+    assert_ne!(a, b);
+
+    b.insert("foo".parse::<HeaderName>().unwrap(), "bar".parse().unwrap());
+    assert_ne!(a, b);
+
+    b.append("foo".parse::<HeaderName>().unwrap(), "baz".parse().unwrap());
+    assert_eq!(a, b);
+
+    a.append("a".parse::<HeaderName>().unwrap(), "a".parse().unwrap());
+    a.append("a".parse::<HeaderName>().unwrap(), "b".parse().unwrap());
+    b.append("a".parse::<HeaderName>().unwrap(), "b".parse().unwrap());
+    b.append("a".parse::<HeaderName>().unwrap(), "a".parse().unwrap());
+
+    assert_ne!(a, b);
+}
+
+#[test]
+fn into_header_name() {
+    let mut m = HeaderMap::new();
+    m.insert(HOST, "localhost".parse().unwrap());
+    m.insert(&ACCEPT, "*/*".parse().unwrap());
+    m.insert("connection", "keep-alive".parse().unwrap());
+
+    m.append(LOCATION, "/".parse().unwrap());
+    m.append(&VIA, "bob".parse().unwrap());
+    m.append("transfer-encoding", "chunked".parse().unwrap());
+
+    assert_eq!(m.len(), 6);
+}
+
+#[test]
+fn as_header_name() {
+    let mut m = HeaderMap::new();
+    let v: HeaderValue = "localhost".parse().unwrap();
+    m.insert(HOST, v.clone());
+
+    let expected = Some(&v);
+
+    assert_eq!(m.get("host"), expected);
+    assert_eq!(m.get(&HOST), expected);
+
+    let s = String::from("host");
+    assert_eq!(m.get(&s), expected);
+    assert_eq!(m.get(s.as_str()), expected);
+}
+
+#[test]
+fn insert_all_std_headers() {
+    let mut m = HeaderMap::new();
+
+    for (i, hdr) in STD.iter().enumerate() {
+        m.insert(hdr.clone(), hdr.as_str().parse().unwrap());
+
+        for j in 0..(i+1) {
+            assert_eq!(m[&STD[j]], STD[j].as_str());
+        }
+
+        if i != 0 {
+            for j in (i+1)..STD.len() {
+                assert!(m.get(&STD[j]).is_none(), "contained {}; j={}", STD[j].as_str(), j);
+            }
+        }
+    }
+}
+
+#[test]
+fn insert_79_custom_std_headers() {
+    let mut h = HeaderMap::new();
+    let hdrs = custom_std(79);
+
+    for (i, hdr) in hdrs.iter().enumerate() {
+        h.insert(hdr.clone(), hdr.as_str().parse().unwrap());
+
+        for j in 0..(i+1) {
+            assert_eq!(h[&hdrs[j]], hdrs[j].as_str());
+        }
+
+        for j in (i+1)..hdrs.len() {
+            assert!(h.get(&hdrs[j]).is_none());
+        }
+    }
+}
+
+#[test]
+fn append_multiple_values() {
+    let mut map = HeaderMap::new();
+
+    map.append(header::CONTENT_TYPE, "json".parse().unwrap());
+    map.append(header::CONTENT_TYPE, "html".parse().unwrap());
+    map.append(header::CONTENT_TYPE, "xml".parse().unwrap());
+
+    let vals = map.get_all(&header::CONTENT_TYPE)
+        .iter()
+        .collect::<Vec<_>>();
+
+    assert_eq!(&vals, &[&"json", &"html", &"xml"]);
+}
+
+fn custom_std(n: usize) -> Vec<HeaderName> {
+    (0..n).map(|i| {
+        let s = format!("{}-{}", STD[i % STD.len()].as_str(), i);
+        s.parse().unwrap()
+    }).collect()
+}
+
+const STD: &'static [HeaderName] = &[
+    ACCEPT,
+    ACCEPT_CHARSET,
+    ACCEPT_ENCODING,
+    ACCEPT_LANGUAGE,
+    ACCEPT_RANGES,
+    ACCESS_CONTROL_ALLOW_CREDENTIALS,
+    ACCESS_CONTROL_ALLOW_HEADERS,
+    ACCESS_CONTROL_ALLOW_METHODS,
+    ACCESS_CONTROL_ALLOW_ORIGIN,
+    ACCESS_CONTROL_EXPOSE_HEADERS,
+    ACCESS_CONTROL_MAX_AGE,
+    ACCESS_CONTROL_REQUEST_HEADERS,
+    ACCESS_CONTROL_REQUEST_METHOD,
+    AGE,
+    ALLOW,
+    ALT_SVC,
+    AUTHORIZATION,
+    CACHE_CONTROL,
+    CONNECTION,
+    CONTENT_DISPOSITION,
+    CONTENT_ENCODING,
+    CONTENT_LANGUAGE,
+    CONTENT_LENGTH,
+    CONTENT_LOCATION,
+    CONTENT_RANGE,
+    CONTENT_SECURITY_POLICY,
+    CONTENT_SECURITY_POLICY_REPORT_ONLY,
+    CONTENT_TYPE,
+    COOKIE,
+    DNT,
+    DATE,
+    ETAG,
+    EXPECT,
+    EXPIRES,
+    FORWARDED,
+    FROM,
+    HOST,
+    IF_MATCH,
+    IF_MODIFIED_SINCE,
+    IF_NONE_MATCH,
+    IF_RANGE,
+    IF_UNMODIFIED_SINCE,
+    LAST_MODIFIED,
+    LINK,
+    LOCATION,
+    MAX_FORWARDS,
+    ORIGIN,
+    PRAGMA,
+    PROXY_AUTHENTICATE,
+    PROXY_AUTHORIZATION,
+    PUBLIC_KEY_PINS,
+    PUBLIC_KEY_PINS_REPORT_ONLY,
+    RANGE,
+    REFERER,
+    REFERRER_POLICY,
+    RETRY_AFTER,
+    SERVER,
+    SET_COOKIE,
+    STRICT_TRANSPORT_SECURITY,
+    TE,
+    TRAILER,
+    TRANSFER_ENCODING,
+    USER_AGENT,
+    UPGRADE,
+    UPGRADE_INSECURE_REQUESTS,
+    VARY,
+    VIA,
+    WARNING,
+    WWW_AUTHENTICATE,
+    X_CONTENT_TYPE_OPTIONS,
+    X_DNS_PREFETCH_CONTROL,
+    X_FRAME_OPTIONS,
+    X_XSS_PROTECTION,
+];
+
+#[test]
+fn get_invalid() {
+    let mut headers = HeaderMap::new();
+    headers.insert("foo", "bar".parse().unwrap());
+    assert!(headers.get("Evil\r\nKey").is_none());
+}
+
+#[test]
+#[should_panic]
+fn insert_invalid() {
+    let mut headers = HeaderMap::new();
+    headers.insert("evil\r\nfoo", "bar".parse().unwrap());
+}
diff --git a/third_party/http/tests/header_map_fuzz.rs b/third_party/http/tests/header_map_fuzz.rs
new file mode 100644
index 0000000..b3b6588
--- /dev/null
+++ b/third_party/http/tests/header_map_fuzz.rs
@@ -0,0 +1,365 @@
+extern crate http;
+extern crate rand;
+extern crate quickcheck;
+
+use http::*;
+use http::header::*;
+
+use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
+use rand::{StdRng, SeedableRng, Rng};
+
+use std::collections::HashMap;
+
+#[test]
+fn header_map_fuzz() {
+    fn prop(fuzz: Fuzz) -> TestResult {
+        fuzz.run();
+        TestResult::from_bool(true)
+    }
+
+    QuickCheck::new()
+        .quickcheck(prop as fn(Fuzz) -> TestResult)
+}
+
+#[derive(Debug, Clone)]
+struct Fuzz {
+    // The magic seed that makes the test case reproducible
+    seed: [usize; 4],
+
+    // Actions to perform
+    steps: Vec<Step>,
+
+    // Number of steps to drop
+    reduce: usize,
+}
+
+#[derive(Debug)]
+struct Weight {
+    insert: usize,
+    remove: usize,
+    append: usize,
+}
+
+#[derive(Debug, Clone)]
+struct Step {
+    action: Action,
+    expect: AltMap,
+}
+
+#[derive(Debug, Clone)]
+enum Action {
+    Insert {
+        name: HeaderName, // Name to insert
+        val: HeaderValue, // Value to insert
+        old: Option<HeaderValue>, // Old value
+    },
+    Append {
+        name: HeaderName,
+        val: HeaderValue,
+        ret: bool,
+    },
+    Remove {
+        name: HeaderName, // Name to remove
+        val: Option<HeaderValue>, // Value to get
+    },
+}
+
+// An alternate implementation of HeaderMap backed by HashMap
+#[derive(Debug, Clone, Default)]
+struct AltMap {
+    map: HashMap<HeaderName, Vec<HeaderValue>>,
+}
+
+impl Fuzz {
+    fn new(seed: [usize; 4]) -> Fuzz {
+        // Seed the RNG
+        let mut rng = StdRng::from_seed(&seed);
+
+        let mut steps = vec![];
+        let mut expect = AltMap::default();
+        let num = rng.gen_range(5, 500);
+
+        let weight = Weight {
+            insert: rng.gen_range(1, 10),
+            remove: rng.gen_range(1, 10),
+            append: rng.gen_range(1, 10),
+        };
+
+        while steps.len() < num {
+            steps.push(expect.gen_step(&weight, &mut rng));
+        }
+
+        Fuzz {
+            seed: seed,
+            steps: steps,
+            reduce: 0,
+        }
+    }
+
+    fn run(self) {
+        // Create a new header map
+        let mut map = HeaderMap::new();
+
+        // Number of steps to perform
+        let take = self.steps.len() - self.reduce;
+
+        for step in self.steps.into_iter().take(take) {
+            step.action.apply(&mut map);
+
+            step.expect.assert_identical(&map);
+        }
+    }
+}
+
+impl Arbitrary for Fuzz {
+    fn arbitrary<G: Gen>(g: &mut G) -> Self {
+        Fuzz::new(quickcheck::Rng::gen(g))
+    }
+}
+
+impl AltMap {
+    fn gen_step(&mut self, weight: &Weight, rng: &mut StdRng) -> Step {
+        let action = self.gen_action(weight, rng);
+
+        Step {
+            action: action,
+            expect: self.clone(),
+        }
+    }
+
+    /// This will also apply the action against `self`
+    fn gen_action(&mut self, weight: &Weight, rng: &mut StdRng) -> Action {
+        let sum = weight.insert +
+            weight.remove +
+            weight.append;
+
+        let mut num = rng.gen_range(0, sum);
+
+        if num < weight.insert {
+            return self.gen_insert(rng);
+        }
+
+        num -= weight.insert;
+
+        if num < weight.remove {
+            return self.gen_remove(rng);
+        }
+
+        num -= weight.remove;
+
+        if num < weight.append {
+            return self.gen_append(rng);
+        }
+
+        unreachable!();
+    }
+
+    fn gen_insert(&mut self, rng: &mut StdRng) -> Action {
+        let name = self.gen_name(4, rng);
+        let val = gen_header_value(rng);
+        let old = self.insert(name.clone(), val.clone());
+
+        Action::Insert {
+            name: name,
+            val: val,
+            old: old,
+        }
+    }
+
+    fn gen_remove(&mut self, rng: &mut StdRng) -> Action {
+        let name = self.gen_name(-4, rng);
+        let val = self.remove(&name);
+
+        Action::Remove {
+            name: name,
+            val: val,
+        }
+    }
+
+    fn gen_append(&mut self, rng: &mut StdRng) -> Action {
+        let name = self.gen_name(-5, rng);
+        let val = gen_header_value(rng);
+
+        let vals = self.map.entry(name.clone())
+            .or_insert(vec![]);
+
+        let ret = !vals.is_empty();
+        vals.push(val.clone());
+
+        Action::Append {
+            name: name,
+            val: val,
+            ret: ret,
+        }
+    }
+
+    /// Negative numbers weigh finding an existing header higher
+    fn gen_name(&self, weight: i32, rng: &mut StdRng) -> HeaderName {
+        let mut existing = rng.gen_weighted_bool(weight.abs() as u32);
+
+        if weight < 0 {
+            existing = !existing;
+        }
+
+        if existing {
+            // Existing header
+            if let Some(name) = self.find_random_name(rng) {
+                name
+            } else {
+                gen_header_name(rng)
+            }
+        } else {
+            gen_header_name(rng)
+        }
+    }
+
+    fn find_random_name(&self, rng: &mut StdRng) -> Option<HeaderName> {
+        if self.map.is_empty() {
+            None
+        } else {
+            let n = rng.gen_range(0, self.map.len());
+            self.map.keys().nth(n).map(Clone::clone)
+        }
+    }
+
+    fn insert(&mut self, name: HeaderName, val: HeaderValue) -> Option<HeaderValue> {
+        let old = self.map.insert(name, vec![val]);
+        old.and_then(|v| v.into_iter().next())
+    }
+
+    fn remove(&mut self, name: &HeaderName) -> Option<HeaderValue> {
+        self.map.remove(name).and_then(|v| v.into_iter().next())
+    }
+
+    fn assert_identical(&self, other: &HeaderMap<HeaderValue>) {
+        assert_eq!(self.map.len(), other.keys_len());
+
+        for (key, val) in &self.map {
+            // Test get
+            assert_eq!(other.get(key), val.get(0));
+
+            // Test get_all
+            let vals = other.get_all(key);
+            let actual: Vec<_> = vals.iter().collect();
+            assert_eq!(&actual[..], &val[..]);
+        }
+    }
+}
+
+impl Action {
+    fn apply(self, map: &mut HeaderMap<HeaderValue>) {
+        match self {
+            Action::Insert { name, val, old } => {
+                let actual = map.insert(name, val);
+                assert_eq!(actual, old);
+            }
+            Action::Remove { name, val } => {
+                // Just to help track the state, load all associated values.
+                map.get_all(&name).iter().collect::<Vec<_>>();
+
+                let actual = map.remove(&name);
+                assert_eq!(actual, val);
+            }
+            Action::Append { name, val, ret } => {
+                assert_eq!(ret, map.append(name, val));
+            }
+        }
+    }
+}
+
+fn gen_header_name(g: &mut StdRng) -> HeaderName {
+    if g.gen_weighted_bool(2) {
+        g.choose(&[
+            header::ACCEPT,
+            header::ACCEPT_CHARSET,
+            header::ACCEPT_ENCODING,
+            header::ACCEPT_LANGUAGE,
+            header::ACCEPT_RANGES,
+            header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
+            header::ACCESS_CONTROL_ALLOW_HEADERS,
+            header::ACCESS_CONTROL_ALLOW_METHODS,
+            header::ACCESS_CONTROL_ALLOW_ORIGIN,
+            header::ACCESS_CONTROL_EXPOSE_HEADERS,
+            header::ACCESS_CONTROL_MAX_AGE,
+            header::ACCESS_CONTROL_REQUEST_HEADERS,
+            header::ACCESS_CONTROL_REQUEST_METHOD,
+            header::AGE,
+            header::ALLOW,
+            header::ALT_SVC,
+            header::AUTHORIZATION,
+            header::CACHE_CONTROL,
+            header::CONNECTION,
+            header::CONTENT_DISPOSITION,
+            header::CONTENT_ENCODING,
+            header::CONTENT_LANGUAGE,
+            header::CONTENT_LENGTH,
+            header::CONTENT_LOCATION,
+            header::CONTENT_RANGE,
+            header::CONTENT_SECURITY_POLICY,
+            header::CONTENT_SECURITY_POLICY_REPORT_ONLY,
+            header::CONTENT_TYPE,
+            header::COOKIE,
+            header::DNT,
+            header::DATE,
+            header::ETAG,
+            header::EXPECT,
+            header::EXPIRES,
+            header::FORWARDED,
+            header::FROM,
+            header::HOST,
+            header::IF_MATCH,
+            header::IF_MODIFIED_SINCE,
+            header::IF_NONE_MATCH,
+            header::IF_RANGE,
+            header::IF_UNMODIFIED_SINCE,
+            header::LAST_MODIFIED,
+            header::LINK,
+            header::LOCATION,
+            header::MAX_FORWARDS,
+            header::ORIGIN,
+            header::PRAGMA,
+            header::PROXY_AUTHENTICATE,
+            header::PROXY_AUTHORIZATION,
+            header::PUBLIC_KEY_PINS,
+            header::PUBLIC_KEY_PINS_REPORT_ONLY,
+            header::RANGE,
+            header::REFERER,
+            header::REFERRER_POLICY,
+            header::RETRY_AFTER,
+            header::SERVER,
+            header::SET_COOKIE,
+            header::STRICT_TRANSPORT_SECURITY,
+            header::TE,
+            header::TRAILER,
+            header::TRANSFER_ENCODING,
+            header::USER_AGENT,
+            header::UPGRADE,
+            header::UPGRADE_INSECURE_REQUESTS,
+            header::VARY,
+            header::VIA,
+            header::WARNING,
+            header::WWW_AUTHENTICATE,
+            header::X_CONTENT_TYPE_OPTIONS,
+            header::X_DNS_PREFETCH_CONTROL,
+            header::X_FRAME_OPTIONS,
+            header::X_XSS_PROTECTION,
+        ]).unwrap().clone()
+    } else {
+        let value = gen_string(g, 1, 25);
+        HeaderName::from_bytes(value.as_bytes()).unwrap()
+    }
+}
+
+fn gen_header_value(g: &mut StdRng) -> HeaderValue {
+    let value = gen_string(g, 0, 70);
+    HeaderValue::from_bytes(value.as_bytes()).unwrap()
+}
+
+fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {
+    let bytes: Vec<_> = (min..max).map(|_| {
+        // Chars to pick from
+        g.choose(b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----").unwrap().clone()
+    }).collect();
+
+    String::from_utf8(bytes).unwrap()
+}
diff --git a/third_party/http/tests/status_code.rs b/third_party/http/tests/status_code.rs
new file mode 100644
index 0000000..72ba810
--- /dev/null
+++ b/third_party/http/tests/status_code.rs
@@ -0,0 +1,67 @@
+extern crate http;
+
+use http::*;
+
+#[test]
+fn from_bytes() {
+    for ok in &["100", "101", "199", "200", "250", "299", "321", "399", "499", "599"] {
+        assert!(StatusCode::from_bytes(ok.as_bytes()).is_ok());
+    }
+
+    for not_ok in &["0", "00", "10", "40", "99", "000", "010", "099", "600", "610", "999"] {
+        assert!(StatusCode::from_bytes(not_ok.as_bytes()).is_err());
+    }
+}
+
+#[test]
+fn equates_with_u16() {
+    let status = StatusCode::from_u16(200u16).unwrap();
+    assert_eq!(200u16, status);
+    assert_eq!(status, 200u16);
+}
+
+macro_rules! test_round_trip {
+    ($($num:expr,)+) => {
+        #[test]
+        fn roundtrip() {
+            $(
+                let status = StatusCode::from_bytes(stringify!($num).as_bytes()).unwrap();
+                let expect = $num;
+
+                assert_eq!(u16::from(status), expect);
+            )+
+        }
+    }
+}
+
+test_round_trip!(
+    100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+    120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+    140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+    160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+    180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+
+    200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+    240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259,
+    260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279,
+    280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
+
+    300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
+    320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
+    340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
+    360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379,
+    380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
+
+    400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419,
+    420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439,
+    440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
+    460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
+    480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499,
+
+    500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519,
+    520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539,
+    540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559,
+    560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579,
+    580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599,
+    );
diff --git a/third_party/http/util/Cargo.toml b/third_party/http/util/Cargo.toml
new file mode 100644
index 0000000..94e285c
--- /dev/null
+++ b/third_party/http/util/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "gen"
+version = "0.1.0"
+authors = ["Carl Lerche <me@carllerche.com>"]
diff --git a/third_party/http/util/README.md b/third_party/http/util/README.md
new file mode 100644
index 0000000..608a38f
--- /dev/null
+++ b/third_party/http/util/README.md
@@ -0,0 +1 @@
+Generates standard header code
diff --git a/third_party/http/util/src/main.rs b/third_party/http/util/src/main.rs
new file mode 100644
index 0000000..fccf5da
--- /dev/null
+++ b/third_party/http/util/src/main.rs
@@ -0,0 +1,1040 @@
+macro_rules! standard_headers {
+    (
+        $(
+            $doc:expr,
+            $name:expr;
+        )+
+    ) => {
+        const HEADERS: &[(&'static str, &'static str)] = &[
+            $(
+                ($doc, $name),
+            )+
+        ];
+    }
+}
+
+standard_headers! {
+    r#"
+    /// Advertises which content types the client is able to understand.
+    ///
+    /// The Accept request HTTP header advertises which content types, expressed
+    /// as MIME types, the client is able to understand. Using content
+    /// negotiation, the server then selects one of the proposals, uses it and
+    /// informs the client of its choice with the Content-Type response header.
+    /// Browsers set adequate values for this header depending of the context
+    /// where the request is done: when fetching a CSS stylesheet a different
+    /// value is set for the request than when fetching an image, video or a
+    /// script.
+    "#,
+    "accept";
+
+    r#"
+    /// Advertises which character set the client is able to understand.
+    ///
+    /// The Accept-Charset request HTTP header advertises which character set
+    /// the client is able to understand. Using content negotiation, the server
+    /// then selects one of the proposals, uses it and informs the client of its
+    /// choice within the Content-Type response header. Browsers usually don't
+    /// set this header as the default value for each content type is usually
+    /// correct and transmitting it would allow easier fingerprinting.
+    ///
+    /// If the server cannot serve any matching character set, it can
+    /// theoretically send back a 406 (Not Acceptable) error code. But, for a
+    /// better user experience, this is rarely done and the more common way is
+    /// to ignore the Accept-Charset header in this case.
+    "#,
+    "accept-charset";
+
+    r#"
+    /// Advertises which content encoding the client is able to understand.
+    ///
+    /// The Accept-Encoding request HTTP header advertises which content
+    /// encoding, usually a compression algorithm, the client is able to
+    /// understand. Using content negotiation, the server selects one of the
+    /// proposals, uses it and informs the client of its choice with the
+    /// Content-Encoding response header.
+    ///
+    /// Even if both the client and the server supports the same compression
+    /// algorithms, the server may choose not to compress the body of a
+    /// response, if the identity value is also acceptable. Two common cases
+    /// lead to this:
+    ///
+    /// * The data to be sent is already compressed and a second compression
+    /// won't lead to smaller data to be transmitted. This may the case with
+    /// some image formats;
+    ///
+    /// * The server is overloaded and cannot afford the computational overhead
+    /// induced by the compression requirement. Typically, Microsoft recommends
+    /// not to compress if a server use more than 80 % of its computational
+    /// power.
+    ///
+    /// As long as the identity value, meaning no encryption, is not explicitly
+    /// forbidden, by an identity;q=0 or a *;q=0 without another explicitly set
+    /// value for identity, the server must never send back a 406 Not Acceptable
+    /// error.
+    "#,
+    "accept-encoding";
+
+    r#"
+    /// Advertises which languages the client is able to understand.
+    ///
+    /// The Accept-Language request HTTP header advertises which languages the
+    /// client is able to understand, and which locale variant is preferred.
+    /// Using content negotiation, the server then selects one of the proposals,
+    /// uses it and informs the client of its choice with the Content-Language
+    /// response header. Browsers set adequate values for this header according
+    /// their user interface language and even if a user can change it, this
+    /// happens rarely (and is frown upon as it leads to fingerprinting).
+    ///
+    /// This header is a hint to be used when the server has no way of
+    /// determining the language via another way, like a specific URL, that is
+    /// controlled by an explicit user decision. It is recommended that the
+    /// server never overrides an explicit decision. The content of the
+    /// Accept-Language is often out of the control of the user (like when
+    /// traveling and using an Internet Cafe in a different country); the user
+    /// may also want to visit a page in another language than the locale of
+    /// their user interface.
+    ///
+    /// If the server cannot serve any matching language, it can theoretically
+    /// send back a 406 (Not Acceptable) error code. But, for a better user
+    /// experience, this is rarely done and more common way is to ignore the
+    /// Accept-Language header in this case.
+    "#,
+    "accept-language";
+
+    r#"
+    /// Advertises which patch formats the server is able to understand.
+    ///
+    /// Accept-Patch should appear in the OPTIONS response for any resource that
+    /// supports the use of the PATCH method. The presence of the
+    /// Accept-Patch header in response to any method is an implicit indication
+    /// that PATCH is allowed on the resource identified by the URI. The
+    /// presence of a specific patch document format in this header indicates
+    /// that that specific format is allowed on the resource identified by the
+    /// URI.
+    "#,
+    "accept-patch";
+
+    r#"
+    /// Marker used by the server to advertise partial request support.
+    ///
+    /// The Accept-Ranges response HTTP header is a marker used by the server to
+    /// advertise its support of partial requests. The value of this field
+    /// indicates the unit that can be used to define a range.
+    ///
+    /// In presence of an Accept-Ranges header, the browser may try to resume an
+    /// interrupted download, rather than to start it from the start again.
+    "#,
+    "accept-ranges";
+
+    r#"
+    /// Preflight response indicating if the response to the request can be
+    /// exposed to the page.
+    ///
+    /// The Access-Control-Allow-Credentials response header indicates whether
+    /// or not the response to the request can be exposed to the page. It can be
+    /// exposed when the true value is returned; it can't in other cases.
+    ///
+    /// Credentials are cookies, authorization headers or TLS client
+    /// certificates.
+    ///
+    /// When used as part of a response to a preflight request, this indicates
+    /// whether or not the actual request can be made using credentials. Note
+    /// that simple GET requests are not preflighted, and so if a request is
+    /// made for a resource with credentials, if this header is not returned
+    /// with the resource, the response is ignored by the browser and not
+    /// returned to web content.
+    ///
+    /// The Access-Control-Allow-Credentials header works in conjunction with
+    /// the XMLHttpRequest.withCredentials property or with the credentials
+    /// option in the Request() constructor of the Fetch API. Credentials must
+    /// be set on both sides (the Access-Control-Allow-Credentials header and in
+    /// the XHR or Fetch request) in order for the CORS request with credentials
+    /// to succeed.
+    "#,
+    "access-control-allow-credentials";
+
+    r#"
+    /// Preflight response indicating permitted HTTP headers.
+    ///
+    /// The Access-Control-Allow-Headers response header is used in response to
+    /// a preflight request to indicate which HTTP headers will be available via
+    /// Access-Control-Expose-Headers when making the actual request.
+    ///
+    /// The simple headers, Accept, Accept-Language, Content-Language,
+    /// Content-Type (but only with a MIME type of its parsed value (ignoring
+    /// parameters) of either application/x-www-form-urlencoded,
+    /// multipart/form-data, or text/plain), are always available and don't need
+    /// to be listed by this header.
+    ///
+    /// This header is required if the request has an
+    /// Access-Control-Request-Headers header.
+    "#,
+    "access-control-allow-headers";
+
+    r#"
+    /// Preflight header response indicating permitted access methods.
+    ///
+    /// The Access-Control-Allow-Methods response header specifies the method or
+    /// methods allowed when accessing the resource in response to a preflight
+    /// request.
+    "#,
+    "access-control-allow-methods";
+
+
+    r#"
+    /// Indicates whether the response can be shared with resources with the
+    /// given origin.
+    "#,
+    "access-control-allow-origin";
+
+    r#"
+    /// Indicates which headers can be exposed as part of the response by
+    /// listing their names.
+    "#,
+    "access-control-expose-headers";
+
+    r#"
+    /// Indicates how long the results of a preflight request can be cached.
+    "#,
+    "access-control-max-age";
+
+    r#"
+    /// Informs the server which HTTP headers will be used when an actual
+    /// request is made.
+    "#,
+    "access-control-request-headers";
+
+    r#"
+    /// Informs the server know which HTTP method will be used when the actual
+    /// request is made.
+    "#,
+    "access-control-request-method";
+
+    r#"
+    /// Indicates the time in seconds the object has been in a proxy cache.
+    ///
+    /// The Age header is usually close to zero. If it is Age: 0, it was
+    /// probably just fetched from the origin server; otherwise It is usually
+    /// calculated as a difference between the proxy's current date and the Date
+    /// general header included in the HTTP response.
+    "#,
+    "age";
+
+    r#"
+    /// Lists the set of methods support by a resource.
+    ///
+    /// This header must be sent if the server responds with a 405 Method Not
+    /// Allowed status code to indicate which request methods can be used. An
+    /// empty Allow header indicates that the resource allows no request
+    /// methods, which might occur temporarily for a given resource, for
+    /// example.
+    "#,
+    "allow";
+
+    r#"
+    /// Advertises the availability of alternate services to clients.
+    "#,
+    "alt-svc";
+
+    r#"
+    /// Contains the credentials to authenticate a user agent with a server.
+    ///
+    /// Usually this header is included after the server has responded with a
+    /// 401 Unauthorized status and the WWW-Authenticate header.
+    "#,
+    "authorization";
+
+    r#"
+    /// Specifies directives for caching mechanisms in both requests and
+    /// responses.
+    ///
+    /// Caching directives are unidirectional, meaning that a given directive in
+    /// a request is not implying that the same directive is to be given in the
+    /// response.
+    "#,
+    "cache-control";
+
+    r#"
+    /// Controls whether or not the network connection stays open after the
+    /// current transaction finishes.
+    ///
+    /// If the value sent is keep-alive, the connection is persistent and not
+    /// closed, allowing for subsequent requests to the same server to be done.
+    ///
+    /// Except for the standard hop-by-hop headers (Keep-Alive,
+    /// Transfer-Encoding, TE, Connection, Trailer, Upgrade, Proxy-Authorization
+    /// and Proxy-Authenticate), any hop-by-hop headers used by the message must
+    /// be listed in the Connection header, so that the first proxy knows he has
+    /// to consume them and not to forward them further. Standard hop-by-hop
+    /// headers can be listed too (it is often the case of Keep-Alive, but this
+    /// is not mandatory.
+    "#,
+    "connection";
+
+    r#"
+    /// Indicates if the content is expected to be displayed inline.
+    ///
+    /// In a regular HTTP response, the Content-Disposition response header is a
+    /// header indicating if the content is expected to be displayed inline in
+    /// the browser, that is, as a Web page or as part of a Web page, or as an
+    /// attachment, that is downloaded and saved locally.
+    ///
+    /// In a multipart/form-data body, the HTTP Content-Disposition general
+    /// header is a header that can be used on the subpart of a multipart body
+    /// to give information about the field it applies to. The subpart is
+    /// delimited by the boundary defined in the Content-Type header. Used on
+    /// the body itself, Content-Disposition has no effect.
+    ///
+    /// The Content-Disposition header is defined in the larger context of MIME
+    /// messages for e-mail, but only a subset of the possible parameters apply
+    /// to HTTP forms and POST requests. Only the value form-data, as well as
+    /// the optional directive name and filename, can be used in the HTTP
+    /// context.
+    "#,
+    "content-disposition";
+
+    r#"
+    /// Used to compress the media-type.
+    ///
+    /// When present, its value indicates what additional content encoding has
+    /// been applied to the entity-body. It lets the client know, how to decode
+    /// in order to obtain the media-type referenced by the Content-Type header.
+    ///
+    /// It is recommended to compress data as much as possible and therefore to
+    /// use this field, but some types of resources, like jpeg images, are
+    /// already compressed.  Sometimes using additional compression doesn't
+    /// reduce payload size and can even make the payload longer.
+    "#,
+    "content-encoding";
+
+    r#"
+    /// Used to describe the languages intended for the audience.
+    ///
+    /// This header allows a user to differentiate according to the users' own
+    /// preferred language. For example, if "Content-Language: de-DE" is set, it
+    /// says that the document is intended for German language speakers
+    /// (however, it doesn't indicate the document is written in German. For
+    /// example, it might be written in English as part of a language course for
+    /// German speakers).
+    ///
+    /// If no Content-Language is specified, the default is that the content is
+    /// intended for all language audiences. Multiple language tags are also
+    /// possible, as well as applying the Content-Language header to various
+    /// media types and not only to textual documents.
+    "#,
+    "content-language";
+
+    r#"
+    /// Indicates the size fo the entity-body.
+    ///
+    /// The header value must be a decimal indicating the number of octets sent
+    /// to the recipient.
+    "#,
+    "content-length";
+
+    r#"
+    /// Indicates an alternate location for the returned data.
+    ///
+    /// The principal use case is to indicate the URL of the resource
+    /// transmitted as the result of content negotiation.
+    ///
+    /// Location and Content-Location are different: Location indicates the
+    /// target of a redirection (or the URL of a newly created document), while
+    /// Content-Location indicates the direct URL to use to access the resource,
+    /// without the need of further content negotiation. Location is a header
+    /// associated with the response, while Content-Location is associated with
+    /// the entity returned.
+    "#,
+    "content-location";
+
+    r#"
+    /// Contains the MD5 digest of the entity-body.
+    ///
+    /// The Content-MD5 entity-header field, as defined in RFC 1864 [23], is an
+    /// MD5 digest of the entity-body for the purpose of providing an end-to-end
+    /// message integrity check (MIC) of the entity-body. (Note: a MIC is good
+    /// for detecting accidental modification of the entity-body in transit, but
+    /// is not proof against malicious attacks.)
+    "#,
+    "content-md5";
+
+    r#"
+    /// Indicates where in a full body message a partial message belongs.
+    "#,
+    "content-range";
+
+    r#"
+    /// Allows controlling resources the user agent is allowed to load for a
+    /// given page.
+    ///
+    /// With a few exceptions, policies mostly involve specifying server origins
+    /// and script endpoints. This helps guard against cross-site scripting
+    /// attacks (XSS).
+    "#,
+    "content-security-policy";
+
+    r#"
+    /// Allows experimenting with policies by monitoring their effects.
+    ///
+    /// The HTTP Content-Security-Policy-Report-Only response header allows web
+    /// developers to experiment with policies by monitoring (but not enforcing)
+    /// their effects. These violation reports consist of JSON documents sent
+    /// via an HTTP POST request to the specified URI.
+    "#,
+    "content-security-policy-report-only";
+
+    r#"
+    /// Used to indicate the media type of the resource.
+    ///
+    /// In responses, a Content-Type header tells the client what the content
+    /// type of the returned content actually is. Browsers will do MIME sniffing
+    /// in some cases and will not necessarily follow the value of this header;
+    /// to prevent this behavior, the header X-Content-Type-Options can be set
+    /// to nosniff.
+    ///
+    /// In requests, (such as POST or PUT), the client tells the server what
+    /// type of data is actually sent.
+    "#,
+    "content-type";
+
+    r#"
+    /// Contains stored HTTP cookies previously sent by the server with the
+    /// Set-Cookie header.
+    ///
+    /// The Cookie header might be omitted entirely, if the privacy setting of
+    /// the browser are set to block them, for example.
+    "#,
+    "cookie";
+
+    r#"
+    /// Indicates the client's tracking preference.
+    ///
+    /// This header lets users indicate whether they would prefer privacy rather
+    /// than personalized content.
+    "#,
+    "dnt";
+
+    r#"
+    /// Contains the date and time at which the message was originated.
+    "#,
+    "date";
+
+    r#"
+    /// Identifier for a specific version of a resource.
+    ///
+    /// This header allows caches to be more efficient, and saves bandwidth, as
+    /// a web server does not need to send a full response if the content has
+    /// not changed. On the other side, if the content has changed, etags are
+    /// useful to help prevent simultaneous updates of a resource from
+    /// overwriting each other ("mid-air collisions").
+    ///
+    /// If the resource at a given URL changes, a new Etag value must be
+    /// generated. Etags are therefore similar to fingerprints and might also be
+    /// used for tracking purposes by some servers. A comparison of them allows
+    /// to quickly determine whether two representations of a resource are the
+    /// same, but they might also be set to persist indefinitely by a tracking
+    /// server.
+    "#,
+    "etag";
+
+    r#"
+    /// Indicates expectations that need to be fulfilled by the server in order
+    /// to properly handle the request.
+    ///
+    /// The only expectation defined in the specification is Expect:
+    /// 100-continue, to which the server shall respond with:
+    ///
+    /// * 100 if the information contained in the header is sufficient to cause
+    /// an immediate success,
+    ///
+    /// * 417 (Expectation Failed) if it cannot meet the expectation; or any
+    /// other 4xx status otherwise.
+    ///
+    /// For example, the server may reject a request if its Content-Length is
+    /// too large.
+    ///
+    /// No common browsers send the Expect header, but some other clients such
+    /// as cURL do so by default.
+    "#,
+    "expect";
+
+    r#"
+    /// Contains the date/time after which the response is considered stale.
+    ///
+    /// Invalid dates, like the value 0, represent a date in the past and mean
+    /// that the resource is already expired.
+    ///
+    /// If there is a Cache-Control header with the "max-age" or "s-max-age"
+    /// directive in the response, the Expires header is ignored.
+    "#,
+    "expires";
+
+    r#"
+    /// Contains information from the client-facing side of proxy servers that
+    /// is altered or lost when a proxy is involved in the path of the request.
+    ///
+    /// The alternative and de-facto standard versions of this header are the
+    /// X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto headers.
+    ///
+    /// This header is used for debugging, statistics, and generating
+    /// location-dependent content and by design it exposes privacy sensitive
+    /// information, such as the IP address of the client. Therefore the user's
+    /// privacy must be kept in mind when deploying this header.
+    "#,
+    "forwarded";
+
+    r#"
+    /// Contains an Internet email address for a human user who controls the
+    /// requesting user agent.
+    ///
+    /// If you are running a robotic user agent (e.g. a crawler), the From
+    /// header should be sent, so you can be contacted if problems occur on
+    /// servers, such as if the robot is sending excessive, unwanted, or invalid
+    /// requests.
+    "#,
+    "from";
+
+    r#"
+    /// Specifies the domain name of the server and (optionally) the TCP port
+    /// number on which the server is listening.
+    ///
+    /// If no port is given, the default port for the service requested (e.g.,
+    /// "80" for an HTTP URL) is implied.
+    ///
+    /// A Host header field must be sent in all HTTP/1.1 request messages. A 400
+    /// (Bad Request) status code will be sent to any HTTP/1.1 request message
+    /// that lacks a Host header field or contains more than one.
+    "#,
+    "host";
+
+    r#"
+    /// Makes a request conditional based on the E-Tag.
+    ///
+    /// For GET and HEAD methods, the server will send back the requested
+    /// resource only if it matches one of the listed ETags. For PUT and other
+    /// non-safe methods, it will only upload the resource in this case.
+    ///
+    /// The comparison with the stored ETag uses the strong comparison
+    /// algorithm, meaning two files are considered identical byte to byte only.
+    /// This is weakened when the  W/ prefix is used in front of the ETag.
+    ///
+    /// There are two common use cases:
+    ///
+    /// * For GET and HEAD methods, used in combination with an Range header, it
+    /// can guarantee that the new ranges requested comes from the same resource
+    /// than the previous one. If it doesn't match, then a 416 (Range Not
+    /// Satisfiable) response is returned.
+    ///
+    /// * For other methods, and in particular for PUT, If-Match can be used to
+    /// prevent the lost update problem. It can check if the modification of a
+    /// resource that the user wants to upload will not override another change
+    /// that has been done since the original resource was fetched. If the
+    /// request cannot be fulfilled, the 412 (Precondition Failed) response is
+    /// returned.
+    "#,
+    "if-match";
+
+    r#"
+    /// Makes a request conditional based on the modification date.
+    ///
+    /// The If-Modified-Since request HTTP header makes the request conditional:
+    /// the server will send back the requested resource, with a 200 status,
+    /// only if it has been last modified after the given date. If the request
+    /// has not been modified since, the response will be a 304 without any
+    /// body; the Last-Modified header will contain the date of last
+    /// modification. Unlike If-Unmodified-Since, If-Modified-Since can only be
+    /// used with a GET or HEAD.
+    ///
+    /// When used in combination with If-None-Match, it is ignored, unless the
+    /// server doesn't support If-None-Match.
+    ///
+    /// The most common use case is to update a cached entity that has no
+    /// associated ETag.
+    "#,
+    "if-modified-since";
+
+    r#"
+    /// Makes a request conditional based on the E-Tag.
+    ///
+    /// The If-None-Match HTTP request header makes the request conditional. For
+    /// GET and HEAD methods, the server will send back the requested resource,
+    /// with a 200 status, only if it doesn't have an ETag matching the given
+    /// ones. For other methods, the request will be processed only if the
+    /// eventually existing resource's ETag doesn't match any of the values
+    /// listed.
+    ///
+    /// When the condition fails for GET and HEAD methods, then the server must
+    /// return HTTP status code 304 (Not Modified). For methods that apply
+    /// server-side changes, the status code 412 (Precondition Failed) is used.
+    /// Note that the server generating a 304 response MUST generate any of the
+    /// following header fields that would have been sent in a 200 (OK) response
+    /// to the same request: Cache-Control, Content-Location, Date, ETag,
+    /// Expires, and Vary.
+    ///
+    /// The comparison with the stored ETag uses the weak comparison algorithm,
+    /// meaning two files are considered identical not only if they are
+    /// identical byte to byte, but if the content is equivalent. For example,
+    /// two pages that would differ only by the date of generation in the footer
+    /// would be considered as identical.
+    ///
+    /// When used in combination with If-Modified-Since, it has precedence (if
+    /// the server supports it).
+    ///
+    /// There are two common use cases:
+    ///
+    /// * For `GET` and `HEAD` methods, to update a cached entity that has an associated ETag.
+    /// * For other methods, and in particular for `PUT`, `If-None-Match` used with
+    /// the `*` value can be used to save a file not known to exist,
+    /// guaranteeing that another upload didn't happen before, losing the data
+    /// of the previous put; this problems is the variation of the lost update
+    /// problem.
+    "#,
+    "if-none-match";
+
+    r#"
+    /// Makes a request conditional based on range.
+    ///
+    /// The If-Range HTTP request header makes a range request conditional: if
+    /// the condition is fulfilled, the range request will be issued and the
+    /// server sends back a 206 Partial Content answer with the appropriate
+    /// body. If the condition is not fulfilled, the full resource is sent back,
+    /// with a 200 OK status.
+    ///
+    /// This header can be used either with a Last-Modified validator, or with
+    /// an ETag, but not with both.
+    ///
+    /// The most common use case is to resume a download, to guarantee that the
+    /// stored resource has not been modified since the last fragment has been
+    /// received.
+    "#,
+    "if-range";
+
+    r#"
+    /// Makes the request conditional based on the last modification date.
+    ///
+    /// The If-Unmodified-Since request HTTP header makes the request
+    /// conditional: the server will send back the requested resource, or accept
+    /// it in the case of a POST or another non-safe method, only if it has not
+    /// been last modified after the given date. If the request has been
+    /// modified after the given date, the response will be a 412 (Precondition
+    /// Failed) error.
+    ///
+    /// There are two common use cases:
+    ///
+    /// * In conjunction non-safe methods, like POST, it can be used to
+    /// implement an optimistic concurrency control, like done by some wikis:
+    /// editions are rejected if the stored document has been modified since the
+    /// original has been retrieved.
+    ///
+    /// * In conjunction with a range request with a If-Range header, it can be
+    /// used to ensure that the new fragment requested comes from an unmodified
+    /// document.
+    "#,
+    "if-unmodified-since";
+
+    r#"
+    /// Content-Types that are acceptable for the response.
+    "#,
+    "last-modified";
+
+    r#"
+    /// Hint about how the connection and may be used to set a timeout and a
+    /// maximum amount of requests.
+    "#,
+    "keep-alive";
+
+    r#"
+    /// Allows the server to point an interested client to another resource
+    /// containing metadata about the requested resource.
+    "#,
+    "link";
+
+    r#"
+    /// Indicates the URL to redirect a page to.
+    ///
+    /// The Location response header indicates the URL to redirect a page to. It
+    /// only provides a meaning when served with a 3xx status response.
+    ///
+    /// The HTTP method used to make the new request to fetch the page pointed
+    /// to by Location depends of the original method and of the kind of
+    /// redirection:
+    ///
+    /// * If 303 (See Also) responses always lead to the use of a GET method,
+    /// 307 (Temporary Redirect) and 308 (Permanent Redirect) don't change the
+    /// method used in the original request;
+    ///
+    /// * 301 (Permanent Redirect) and 302 (Found) doesn't change the method
+    /// most of the time, though older user-agents may (so you basically don't
+    /// know).
+    ///
+    /// All responses with one of these status codes send a Location header.
+    ///
+    /// Beside redirect response, messages with 201 (Created) status also
+    /// include the Location header. It indicates the URL to the newly created
+    /// resource.
+    ///
+    /// Location and Content-Location are different: Location indicates the
+    /// target of a redirection (or the URL of a newly created resource), while
+    /// Content-Location indicates the direct URL to use to access the resource
+    /// when content negotiation happened, without the need of further content
+    /// negotiation. Location is a header associated with the response, while
+    /// Content-Location is associated with the entity returned.
+    "#,
+    "location";
+
+    r#"
+    /// Indicates the max number of intermediaries the request should be sent
+    /// through.
+    "#,
+    "max-forwards";
+
+    r#"
+    /// Indicates where a fetch originates from.
+    ///
+    /// It doesn't include any path information, but only the server name. It is
+    /// sent with CORS requests, as well as with POST requests. It is similar to
+    /// the Referer header, but, unlike this header, it doesn't disclose the
+    /// whole path.
+    "#,
+    "origin";
+
+    r#"
+    /// HTTP/1.0 header usually used for backwards compatibility.
+    ///
+    /// The Pragma HTTP/1.0 general header is an implementation-specific header
+    /// that may have various effects along the request-response chain. It is
+    /// used for backwards compatibility with HTTP/1.0 caches where the
+    /// Cache-Control HTTP/1.1 header is not yet present.
+    "#,
+    "pragma";
+
+    r#"
+    /// Defines the authentication method that should be used to gain access to
+    /// a proxy.
+    ///
+    /// Unlike `www-authenticate`, the `proxy-authenticate` header field applies
+    /// only to the next outbound client on the response chain. This is because
+    /// only the client that chose a given proxy is likely to have the
+    /// credentials necessary for authentication. However, when multiple proxies
+    /// are used within the same administrative domain, such as office and
+    /// regional caching proxies within a large corporate network, it is common
+    /// for credentials to be generated by the user agent and passed through the
+    /// hierarchy until consumed. Hence, in such a configuration, it will appear
+    /// as if Proxy-Authenticate is being forwarded because each proxy will send
+    /// the same challenge set.
+    ///
+    /// The `proxy-authenticate` header is sent along with a `407 Proxy
+    /// Authentication Required`.
+    "#,
+    "proxy-authenticate";
+
+    r#"
+    /// Contains the credentials to authenticate a user agent to a proxy server.
+    ///
+    /// This header is usually included after the server has responded with a
+    /// 407 Proxy Authentication Required status and the Proxy-Authenticate
+    /// header.
+    "#,
+    "proxy-authorization";
+
+    r#"
+    /// Associates a specific cryptographic public key with a certain server.
+    ///
+    /// This decreases the risk of MITM attacks with forged certificates. If one
+    /// or several keys are pinned and none of them are used by the server, the
+    /// browser will not accept the response as legitimate, and will not display
+    /// it.
+    "#,
+    "public-key-pins";
+
+    r#"
+    /// Sends reports of pinning violation to the report-uri specified in the
+    /// header.
+    ///
+    /// Unlike `Public-Key-Pins`, this header still allows browsers to connect
+    /// to the server if the pinning is violated.
+    "#,
+    "public-key-pins-report-only";
+
+    r#"
+    /// Indicates the part of a document that the server should return.
+    ///
+    /// Several parts can be requested with one Range header at once, and the
+    /// server may send back these ranges in a multipart document. If the server
+    /// sends back ranges, it uses the 206 Partial Content for the response. If
+    /// the ranges are invalid, the server returns the 416 Range Not Satisfiable
+    /// error. The server can also ignore the Range header and return the whole
+    /// document with a 200 status code.
+    "#,
+    "range";
+
+    r#"
+    /// Contains the address of the previous web page from which a link to the
+    /// currently requested page was followed.
+    ///
+    /// The Referer header allows servers to identify where people are visiting
+    /// them from and may use that data for analytics, logging, or optimized
+    /// caching, for example.
+    "#,
+    "referer";
+
+    r#"
+    /// Governs which referrer information should be included with requests
+    /// made.
+    "#,
+    "referrer-policy";
+
+    r#"
+    /// Informs the web browser that the current page or frame should be
+    /// refreshed.
+    "#,
+    "refresh";
+
+    r#"
+    /// The Retry-After response HTTP header indicates how long the user agent
+    /// should wait before making a follow-up request. There are two main cases
+    /// this header is used:
+    ///
+    /// * When sent with a 503 (Service Unavailable) response, it indicates how
+    /// long the service is expected to be unavailable.
+    ///
+    /// * When sent with a redirect response, such as 301 (Moved Permanently),
+    /// it indicates the minimum time that the user agent is asked to wait
+    /// before issuing the redirected request.
+    "#,
+    "retry-after";
+
+    r#"
+    /// Contains information about the software used by the origin server to
+    /// handle the request.
+    ///
+    /// Overly long and detailed Server values should be avoided as they
+    /// potentially reveal internal implementation details that might make it
+    /// (slightly) easier for attackers to find and exploit known security
+    /// holes.
+    "#,
+    "server";
+
+    r#"
+    /// Used to send cookies from the server to the user agent.
+    "#,
+    "set-cookie";
+
+    r#"
+    /// Tells the client to communicate with HTTPS instead of using HTTP.
+    "#,
+    "strict-transport-security";
+
+    r#"
+    /// Informs the server of transfer encodings willing to be accepted as part
+    /// of the response.
+    ///
+    /// See also the Transfer-Encoding response header for more details on
+    /// transfer encodings. Note that chunked is always acceptable for HTTP/1.1
+    /// recipients and you that don't have to specify "chunked" using the TE
+    /// header. However, it is useful for setting if the client is accepting
+    /// trailer fields in a chunked transfer coding using the "trailers" value.
+    "#,
+    "te";
+
+    r#"
+    /// Indicates the tracking status that applied to the corresponding request.
+    "#,
+    "tk";
+
+    r#"
+    /// Allows the sender to include additional fields at the end of chunked
+    /// messages.
+    "#,
+    "trailer";
+
+    r#"
+    /// Specifies the form of encoding used to safely transfer the entity to the
+    /// client.
+    ///
+    /// `transfer-encoding` is a hop-by-hop header, that is applying to a
+    /// message between two nodes, not to a resource itself. Each segment of a
+    /// multi-node connection can use different `transfer-encoding` values. If
+    /// you want to compress data over the whole connection, use the end-to-end
+    /// header `content-encoding` header instead.
+    ///
+    /// When present on a response to a `HEAD` request that has no body, it
+    /// indicates the value that would have applied to the corresponding `GET`
+    /// message.
+    "#,
+    "transfer-encoding";
+
+    r#"
+    /// A response to the client's tracking preference.
+    ///
+    /// A tracking status value (TSV) is a single character response to the
+    /// user's tracking preference with regard to data collected via the
+    /// designated resource. For a site-wide tracking status resource, the
+    /// designated resource is any resource on the same origin server. For a Tk
+    /// response header field, the target resource of the corresponding request
+    /// is the designated resource, and remains so for any subsequent
+    /// request-specific tracking status resource referred to by the Tk field
+    /// value.
+    "#,
+    "tsv";
+
+    r#"
+    /// Contains a string that allows identifying the requesting client's
+    /// software.
+    "#,
+    "user-agent";
+
+    r#"
+    /// Used as part of the exchange to upgrade the protocol.
+    "#,
+    "upgrade";
+
+    r#"
+    /// Sends a signal to the server expressing the client’s preference for an
+    /// encrypted and authenticated response.
+    "#,
+    "upgrade-insecure-requests";
+
+    r#"
+    /// Determines how to match future requests with cached responses.
+    ///
+    /// The `vary` HTTP response header determines how to match future request
+    /// headers to decide whether a cached response can be used rather than
+    /// requesting a fresh one from the origin server. It is used by the server
+    /// to indicate which headers it used when selecting a representation of a
+    /// resource in a content negotiation algorithm.
+    ///
+    /// The `vary` header should be set on a 304 Not Modified response exactly
+    /// like it would have been set on an equivalent 200 OK response.
+    "#,
+    "vary";
+
+    r#"
+    /// Added by proxies to track routing.
+    ///
+    /// The `via` general header is added by proxies, both forward and reverse
+    /// proxies, and can appear in the request headers and the response headers.
+    /// It is used for tracking message forwards, avoiding request loops, and
+    /// identifying the protocol capabilities of senders along the
+    /// request/response chain.
+    "#,
+    "via";
+
+    r#"
+    /// General HTTP header contains information about possible problems with
+    /// the status of the message.
+    ///
+    /// More than one `warning` header may appear in a response. Warning header
+    /// fields can in general be applied to any message, however some warn-codes
+    /// are specific to caches and can only be applied to response messages.
+    "#,
+    "warning";
+
+    r#"
+    /// Defines the authentication method that should be used to gain access to
+    /// a resource.
+    "#,
+    "www-authenticate";
+
+    r#"
+    /// Marker used by the server to indicate that the MIME types advertised in
+    /// the `content-type` headers should not be changed and be followed.
+    ///
+    /// This allows to opt-out of MIME type sniffing, or, in other words, it is
+    /// a way to say that the webmasters knew what they were doing.
+    ///
+    /// This header was introduced by Microsoft in IE 8 as a way for webmasters
+    /// to block content sniffing that was happening and could transform
+    /// non-executable MIME types into executable MIME types. Since then, other
+    /// browsers have introduced it, even if their MIME sniffing algorithms were
+    /// less aggressive.
+    ///
+    /// Site security testers usually expect this header to be set.
+    "#,
+    "x-content-type-options";
+
+    r#"
+    /// Controls DNS prefetching.
+    ///
+    /// The `x-dns-prefetch-control` HTTP response header controls DNS
+    /// prefetching, a feature by which browsers proactively perform domain name
+    /// resolution on both links that the user may choose to follow as well as
+    /// URLs for items referenced by the document, including images, CSS,
+    /// JavaScript, and so forth.
+    ///
+    /// This prefetching is performed in the background, so that the DNS is
+    /// likely to have been resolved by the time the referenced items are
+    /// needed. This reduces latency when the user clicks a link.
+    "#,
+    "x-dns-prefetch-control";
+
+    r#"
+    /// Indicates whether or not a browser should be allowed to render a page in
+    /// a frame.
+    ///
+    /// Sites can use this to avoid clickjacking attacks, by ensuring that their
+    /// content is not embedded into other sites.
+    ///
+    /// The added security is only provided if the user accessing the document
+    /// is using a browser supporting `x-frame-options`.
+    "#,
+    "x-frame-options";
+
+    r#"
+    /// Stop pages from loading when an XSS attack is detected.
+    ///
+    /// The HTTP X-XSS-Protection response header is a feature of Internet
+    /// Explorer, Chrome and Safari that stops pages from loading when they
+    /// detect reflected cross-site scripting (XSS) attacks. Although these
+    /// protections are largely unnecessary in modern browsers when sites
+    /// implement a strong Content-Security-Policy that disables the use of
+    /// inline JavaScript ('unsafe-inline'), they can still provide protections
+    /// for users of older web browsers that don't yet support CSP.
+    "#,
+    "x-xss-protection";
+}
+
+fn constantize(s: &str) -> String {
+    let parts = s.split("-").map(|s| {
+        s.chars().enumerate().map(|(n, c)| {
+            if n == 0 {
+                c.to_uppercase().to_string()
+            } else {
+                c.to_string()
+            }
+        })
+    });
+
+    let mut res = String::new();
+
+    for part in parts {
+        res.extend(part);
+    }
+
+    res
+}
+
+fn upcase(s: &str) -> String {
+    let mut ret = String::new();
+
+    for ch in s.chars() {
+        if ch == '-' {
+            ret.push('_');
+        } else {
+            for ch in ch.to_uppercase() {
+                ret.push(ch);
+            }
+        }
+    }
+
+    ret
+}
+
+pub fn main() {
+    for &(doc, string) in HEADERS.iter() {
+        println!("{}", &doc[1..doc.len()-5]);
+        println!("    ({}, {}, {:?});", constantize(string), upcase(string), string);
+        println!("");
+    }
+}
diff --git a/third_party/http/x86_64-unknown-linux-sgx.json b/third_party/http/x86_64-unknown-linux-sgx.json
new file mode 100644
index 0000000..6cbb524
--- /dev/null
+++ b/third_party/http/x86_64-unknown-linux-sgx.json
@@ -0,0 +1,31 @@
+{
+  "arch": "x86_64",
+  "cpu": "x86-64",
+  "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
+  "dynamic-linking": true,
+  "env": "sgx",
+  "exe-allocation-crate": "alloc_system",
+  "executables": true,
+  "has-elf-tls": true,
+  "has-rpath": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-unknown-linux-gnu",
+  "max-atomic-width": 64,
+  "os": "linux",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relro-level": "full",
+  "stack-probes": true,
+  "target-c-int-width": "32",
+  "target-endian": "little",
+  "target-family": "unix",
+  "target-pointer-width": "64",
+  "vendor": "unknown"
+}
diff --git a/third_party/iovec/.gitignore b/third_party/iovec/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/third_party/iovec/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/third_party/iovec/.travis.yml b/third_party/iovec/.travis.yml
new file mode 100644
index 0000000..f76806b
--- /dev/null
+++ b/third_party/iovec/.travis.yml
@@ -0,0 +1,25 @@
+---
+language: rust
+sudo: false
+
+matrix:
+  include:
+    # Oldest supported Rust (this should track Mio)
+    - rust: 1.9.0
+    - rust: stable
+    # OS X support
+    - rust: stable
+      os: osx
+    # WebAssembly support.
+    - rust: beta
+      script:
+        - rustup target add wasm32-unknown-unknown
+        - cargo build --target=wasm32-unknown-unknown
+
+script:
+  - cargo build
+  - cargo test
+
+notifications:
+  email:
+    on_success: never
diff --git a/third_party/iovec/CHANGELOG.md b/third_party/iovec/CHANGELOG.md
new file mode 100644
index 0000000..0e2dfa3
--- /dev/null
+++ b/third_party/iovec/CHANGELOG.md
@@ -0,0 +1,11 @@
+# 0.1.2 (January 26th, 2018)
+
+* Add support for non-windows/unix targets (#10)
+
+# 0.1.1 (October 5th, 2017)
+
+* Fix soundness bug: Assert slice lengths are always > 0 (#5)
+
+# 0.1.0 (March 14th, 2017)
+
+* Initial release
diff --git a/third_party/iovec/Cargo.toml b/third_party/iovec/Cargo.toml
new file mode 100644
index 0000000..8db6704
--- /dev/null
+++ b/third_party/iovec/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "iovec"
+version = "0.1.2"
+authors = ["Carl Lerche <me@carllerche.com>"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+keywords = ["scatter", "gather", "vectored", "io", "networking"]
+repository = "https://github.com/carllerche/iovec"
+homepage = "https://github.com/carllerche/iovec"
+documentation = "https://docs.rs/iovec"
+description = """
+Portable buffer type for scatter/gather I/O operations
+"""
+categories = ["network-programming", "api-bindings"]
+
+[target.'cfg(not(target_env = "sgx"))'.dependencies]
+sgx_tstd = { path =  "../../sgx_tstd" }
+sgx_trts = { path =  "../../sgx_trts" }
diff --git a/third_party/iovec/LICENSE-APACHE b/third_party/iovec/LICENSE-APACHE
new file mode 100644
index 0000000..87d73e7
--- /dev/null
+++ b/third_party/iovec/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright 2017 Carl Lerche
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/iovec/LICENSE-MIT b/third_party/iovec/LICENSE-MIT
new file mode 100644
index 0000000..6c296be
--- /dev/null
+++ b/third_party/iovec/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017 Carl Lerche
+
+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/third_party/iovec/README.md b/third_party/iovec/README.md
new file mode 100644
index 0000000..6d2ea7b
--- /dev/null
+++ b/third_party/iovec/README.md
@@ -0,0 +1,35 @@
+# IoVec
+
+A specialized byte slice type for performing vectored I/O operations.
+
+[![Crates.io](https://img.shields.io/crates/v/iovec.svg?maxAge=2592000)](https://crates.io/crates/iovec)
+[![Build Status](https://travis-ci.org/carllerche/iovec.svg?branch=master)](https://travis-ci.org/carllerche/iovec)
+
+[Documentation](https://docs.rs/iovec)
+
+## Usage
+
+To use `iovec`, first add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+iovec = "0.1"
+```
+
+Next, add this to your crate:
+
+```rust
+extern crate iovec;
+
+use iovec::IoVec;
+```
+
+For more detail, see [documentation](https://docs.rs/iovec).
+
+# License
+
+`iovec` is primarily distributed under the terms of both the MIT license and the
+Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
diff --git a/third_party/iovec/Xargo.toml b/third_party/iovec/Xargo.toml
new file mode 100644
index 0000000..48ad024
--- /dev/null
+++ b/third_party/iovec/Xargo.toml
@@ -0,0 +1,20 @@
+[dependencies]
+alloc = {}
+panic_unwind = {}
+panic_abort = {}
+
+[dependencies.std]
+path = "../../xargo/sgx_tstd"
+stage = 1
+
+[dependencies.sgx_rand]
+path = "../../xargo/sgx_rand"
+stage = 2
+
+[dependencies.sgx_serialize]
+path = "../../xargo/sgx_serialize"
+stage = 2
+
+[dependencies.sgx_tunittest]
+path = "../../xargo/sgx_tunittest"
+stage = 2
\ No newline at end of file
diff --git a/third_party/iovec/appveyor.yml b/third_party/iovec/appveyor.yml
new file mode 100644
index 0000000..4428146
--- /dev/null
+++ b/third_party/iovec/appveyor.yml
@@ -0,0 +1,16 @@
+environment:
+  matrix:
+  - TARGET: x86_64-pc-windows-msvc
+
+install:
+  - curl -sSf -o rustup-init.exe https://win.rustup.rs/
+  - rustup-init.exe -y --default-host %TARGET%
+  - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+  - rustc -V
+  - cargo -V
+
+build: false
+
+test_script:
+  - cargo build
+  - cargo test
diff --git a/third_party/iovec/src/lib.rs b/third_party/iovec/src/lib.rs
new file mode 100644
index 0000000..ecf143a
--- /dev/null
+++ b/third_party/iovec/src/lib.rs
@@ -0,0 +1,166 @@
+//! A specialized byte slice type for performing vectored I/O operations.
+//!
+//! For more detail, see [`IoVec`] documentation.
+//!
+//! [`IoVec`]: struct.IoVec.html
+
+#![cfg_attr(not(target_env = "sgx"), no_std)]
+#![cfg_attr(target_env = "sgx", feature(rustc_private))]
+
+#[cfg(not(target_env = "sgx"))]
+#[macro_use]
+extern crate sgx_tstd as std;
+
+extern crate sgx_trts;
+
+mod sys;
+
+use std::{ops, mem};
+
+pub mod unix;
+
+/// Max length of an `IoVec` slice.
+///
+/// Attempts to convert slices longer than this value will result in a panic.
+pub const MAX_LENGTH: usize = sys::MAX_LENGTH;
+
+/// A specialized byte slice type for performing vectored I/O operations.
+///
+/// On all systems, the types needed to perform vectored I/O systems have the
+/// same size as Rust's [`slice`]. However, the layout is not necessarily the
+/// same. `IoVec` provides a portable compatibility layer.
+///
+/// The `IoVec` behaves like a Rust [`slice`], providing the same functions.
+/// It also provides conversion functions to and from the OS specific vectored
+/// types.
+///
+/// [`slice`]: https://doc.rust-lang.org/std/primitive.slice.html
+///
+/// # Examples
+///
+/// ```
+/// use iovec::IoVec;
+///
+/// let mut data = vec![];
+/// data.extend_from_slice(b"hello");
+///
+/// let iovec: &IoVec = data.as_slice().into();
+///
+/// assert_eq!(&iovec[..], &b"hello"[..]);
+/// ```
+///
+/// # Panics
+///
+/// Attempting to convert a zero-length slice or a slice longer than
+/// [`MAX_LENGTH`] to an `IoVec` will result in a panic.
+///
+/// [`MAX_LENGTH`]: constant.MAX_LENGTH.html
+pub struct IoVec {
+    sys: sys::IoVec,
+}
+
+impl IoVec {
+    pub fn from_bytes(slice: &[u8]) -> Option<&IoVec> {
+        if slice.len() == 0 {
+            return None
+        }
+        unsafe {
+            let iovec: &sys::IoVec = slice.into();
+            Some(mem::transmute(iovec))
+        }
+    }
+
+    pub fn from_bytes_mut(slice: &mut [u8]) -> Option<&mut IoVec> {
+        if slice.len() == 0 {
+            return None
+        }
+        unsafe {
+            let iovec: &mut sys::IoVec = slice.into();
+            Some(mem::transmute(iovec))
+        }
+    }
+
+    #[deprecated(since = "0.1.0", note = "deref instead")]
+    #[doc(hidden)]
+    pub fn as_bytes(&self) -> &[u8] {
+        &**self
+    }
+
+    #[deprecated(since = "0.1.0", note = "deref instead")]
+    #[doc(hidden)]
+    pub fn as_mut_bytes(&mut self) -> &mut [u8] {
+        &mut **self
+    }
+}
+
+impl ops::Deref for IoVec {
+    type Target = [u8];
+
+    fn deref(&self) -> &[u8] {
+        &self.sys.as_ref()
+    }
+}
+
+impl ops::DerefMut for IoVec {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        self.sys.as_mut()
+    }
+}
+
+#[doc(hidden)]
+impl<'a> From<&'a [u8]> for &'a IoVec {
+    fn from(bytes: &'a [u8]) -> &'a IoVec {
+        IoVec::from_bytes(bytes)
+            .expect("this crate accidentally accepted 0-sized slices \
+                     originally but this was since discovered as a soundness \
+                     hole, it's recommended to use the `from_bytes` \
+                     function instead")
+    }
+}
+
+#[doc(hidden)]
+impl<'a> From<&'a mut [u8]> for &'a mut IoVec {
+    fn from(bytes: &'a mut [u8]) -> &'a mut IoVec {
+        IoVec::from_bytes_mut(bytes)
+            .expect("this crate accidentally accepted 0-sized slices \
+                     originally but this was since discovered as a soundness \
+                     hole, it's recommended to use the `from_bytes_mut` \
+                     function instead")
+    }
+}
+
+#[doc(hidden)]
+impl<'a> Default for &'a IoVec {
+    fn default() -> Self {
+        panic!("this implementation was accidentally provided but is \
+                unfortunately unsound, it's recommended to stop using \
+                `IoVec::default` or construct a vector with a nonzero length");
+    }
+}
+
+#[doc(hidden)]
+impl<'a> Default for &'a mut IoVec {
+    fn default() -> Self {
+        panic!("this implementation was accidentally provided but is \
+                unfortunately unsound, it's recommended to stop using \
+                `IoVec::default` or construct a vector with a nonzero length");
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::IoVec;
+
+    #[test]
+    fn convert_ref() {
+        let buf: &IoVec = (&b"hello world"[..]).into();
+        assert_eq!(buf[..], b"hello world"[..]);
+    }
+
+    #[test]
+    fn convert_mut() {
+        let mut buf: Vec<u8> = b"hello world".to_vec();
+        let buf: &mut IoVec = (&mut buf[..]).into();
+        assert_eq!(buf[..], b"hello world"[..]);
+    }
+}
diff --git a/third_party/iovec/src/sys/mod.rs b/third_party/iovec/src/sys/mod.rs
new file mode 100644
index 0000000..c07ba04
--- /dev/null
+++ b/third_party/iovec/src/sys/mod.rs
@@ -0,0 +1,6 @@
+mod unix;
+
+pub use self::unix::{
+    IoVec,
+    MAX_LENGTH,
+};
diff --git a/third_party/iovec/src/sys/unix.rs b/third_party/iovec/src/sys/unix.rs
new file mode 100644
index 0000000..b33d89a
--- /dev/null
+++ b/third_party/iovec/src/sys/unix.rs
@@ -0,0 +1,52 @@
+use sgx_trts::libc;
+use std::{mem, slice, usize};
+
+pub struct IoVec {
+    inner: [u8],
+}
+
+pub const MAX_LENGTH: usize = usize::MAX;
+
+impl IoVec {
+    pub fn as_ref(&self) -> &[u8] {
+        unsafe {
+            let vec = self.iovec();
+            slice::from_raw_parts(vec.iov_base as *const u8, vec.iov_len)
+        }
+    }
+
+    pub fn as_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            let vec = self.iovec();
+            slice::from_raw_parts_mut(vec.iov_base as *mut u8, vec.iov_len)
+        }
+    }
+
+    unsafe fn iovec(&self) -> libc::iovec {
+        mem::transmute(&self.inner)
+    }
+}
+
+impl<'a> From<&'a [u8]> for &'a IoVec {
+    fn from(src: &'a [u8]) -> Self {
+        assert!(src.len() > 0);
+        unsafe {
+            mem::transmute(libc::iovec {
+                iov_base: src.as_ptr() as *mut _,
+                iov_len: src.len(),
+            })
+        }
+    }
+}
+
+impl<'a> From<&'a mut [u8]> for &'a mut IoVec {
+    fn from(src: &'a mut [u8]) -> Self {
+        assert!(src.len() > 0);
+        unsafe {
+            mem::transmute(libc::iovec {
+                iov_base: src.as_ptr() as *mut _,
+                iov_len: src.len(),
+            })
+        }
+    }
+}
diff --git a/third_party/iovec/src/sys/unknown.rs b/third_party/iovec/src/sys/unknown.rs
new file mode 100644
index 0000000..37acedd
--- /dev/null
+++ b/third_party/iovec/src/sys/unknown.rs
@@ -0,0 +1,57 @@
+use std::{mem, slice, usize};
+
+#[derive(Clone)]
+pub struct WasmIoVec {
+    ptr: *const u8,
+    len: usize,
+}
+
+pub struct IoVec {
+    inner: [u8],
+}
+
+pub const MAX_LENGTH: usize = usize::MAX;
+
+impl IoVec {
+    pub fn as_ref(&self) -> &[u8] {
+        unsafe {
+            let vec = self.iovec();
+            slice::from_raw_parts(vec.ptr as *const u8, vec.len)
+        }
+    }
+
+    pub fn as_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            let vec = self.iovec();
+            slice::from_raw_parts_mut(vec.ptr as *mut u8, vec.len)
+        }
+    }
+
+    unsafe fn iovec(&self) -> WasmIoVec {
+        mem::transmute(&self.inner)
+    }
+}
+
+impl<'a> From<&'a [u8]> for &'a IoVec {
+    fn from(src: &'a [u8]) -> Self {
+        assert!(src.len() > 0);
+        unsafe {
+            mem::transmute(WasmIoVec {
+                ptr: src.as_ptr() as *mut _,
+                len: src.len(),
+            })
+        }
+    }
+}
+
+impl<'a> From<&'a mut [u8]> for &'a mut IoVec {
+    fn from(src: &'a mut [u8]) -> Self {
+        assert!(src.len() > 0);
+        unsafe {
+            mem::transmute(WasmIoVec {
+                ptr: src.as_ptr() as *mut _,
+                len: src.len(),
+            })
+        }
+    }
+}
diff --git a/third_party/iovec/src/sys/windows.rs b/third_party/iovec/src/sys/windows.rs
new file mode 100644
index 0000000..ccc5f35
--- /dev/null
+++ b/third_party/iovec/src/sys/windows.rs
@@ -0,0 +1,56 @@
+use winapi::{WSABUF, DWORD};
+use std::{mem, slice, u32};
+
+pub struct IoVec {
+    inner: [u8],
+}
+
+pub const MAX_LENGTH: usize = u32::MAX as usize;
+
+impl IoVec {
+    pub fn as_ref(&self) -> &[u8] {
+        unsafe {
+            let vec = self.wsabuf();
+            slice::from_raw_parts(vec.buf as *const u8, vec.len as usize)
+        }
+    }
+
+    pub fn as_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            let vec = self.wsabuf();
+            slice::from_raw_parts_mut(vec.buf as *mut u8, vec.len as usize)
+        }
+    }
+
+    unsafe fn wsabuf(&self) -> WSABUF {
+        mem::transmute(&self.inner)
+    }
+}
+
+impl<'a> From<&'a [u8]> for &'a IoVec {
+    fn from(src: &'a [u8]) -> Self {
+        assert!(src.len() > 0);
+        assert!(src.len() <= MAX_LENGTH);
+
+        unsafe {
+            mem::transmute(WSABUF {
+                buf: src.as_ptr() as *mut _,
+                len: src.len() as DWORD,
+            })
+        }
+    }
+}
+
+impl<'a> From<&'a mut [u8]> for &'a mut IoVec {
+    fn from(src: &'a mut [u8]) -> Self {
+        assert!(src.len() > 0);
+        assert!(src.len() <= MAX_LENGTH);
+
+        unsafe {
+            mem::transmute(WSABUF {
+                buf: src.as_ptr() as *mut _,
+                len: src.len() as DWORD,
+            })
+        }
+    }
+}
diff --git a/third_party/iovec/src/unix.rs b/third_party/iovec/src/unix.rs
new file mode 100644
index 0000000..0eafa4e
--- /dev/null
+++ b/third_party/iovec/src/unix.rs
@@ -0,0 +1,68 @@
+//! IoVec extensions for Unix platforms.
+//!
+//! These functions provide conversions to unix specific representations of the
+//! vectored data.
+//!
+//! # Examples
+//!
+//! ```
+//! use iovec::IoVec;
+//! use iovec::unix;
+//!
+//! let a = b"hello".to_vec();
+//! let b = b"world".to_vec();
+//!
+//! let bufs: &[&IoVec] = &[(&a[..]).into(), (&b[..]).into()];
+//! let os_bufs = unix::as_os_slice(&bufs[..]);
+//!
+//! // Use the `os_bufs` slice with `writev`.
+//! ```
+
+use IoVec;
+use sgx_trts::libc;
+
+use std::mem;
+
+/// Convert a slice of `IoVec` refs to a slice of `libc::iovec`.
+///
+/// The return value can be passed to `writev` bindings.
+///
+/// # Examples
+///
+/// ```
+/// use iovec::IoVec;
+/// use iovec::unix;
+///
+/// let a = b"hello".to_vec();
+/// let b = b"world".to_vec();
+///
+/// let bufs: &[&IoVec] = &[a[..].into(), b[..].into()];
+/// let os_bufs = unix::as_os_slice(bufs);
+///
+/// // Use the `os_bufs` slice with `writev`.
+/// ```
+pub fn as_os_slice<'a>(iov: &'a [&IoVec]) -> &'a [libc::iovec] {
+    unsafe { mem::transmute(iov) }
+}
+
+/// Convert a mutable slice of `IoVec` refs to a mutable slice of `libc::iovec`.
+///
+/// The return value can be passed to `readv` bindings.
+///
+/// # Examples
+///
+/// ```
+/// use iovec::IoVec;
+/// use iovec::unix;
+///
+/// let mut a = [0; 10];
+/// let mut b = [0; 10];
+///
+/// let bufs: &mut [&mut IoVec] = &mut [(&mut a[..]).into(), (&mut b[..]).into()];
+/// let os_bufs = unix::as_os_slice_mut(bufs);
+///
+/// // Use the `os_bufs` slice with `readv`.
+/// ```
+pub fn as_os_slice_mut<'a>(iov: &'a mut [&mut IoVec]) -> &'a mut [libc::iovec] {
+    unsafe { mem::transmute(iov) }
+}
diff --git a/third_party/iovec/src/windows.rs b/third_party/iovec/src/windows.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/iovec/src/windows.rs
diff --git a/third_party/iovec/x86_64-unknown-linux-sgx.json b/third_party/iovec/x86_64-unknown-linux-sgx.json
new file mode 100644
index 0000000..6cbb524
--- /dev/null
+++ b/third_party/iovec/x86_64-unknown-linux-sgx.json
@@ -0,0 +1,31 @@
+{
+  "arch": "x86_64",
+  "cpu": "x86-64",
+  "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
+  "dynamic-linking": true,
+  "env": "sgx",
+  "exe-allocation-crate": "alloc_system",
+  "executables": true,
+  "has-elf-tls": true,
+  "has-rpath": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-unknown-linux-gnu",
+  "max-atomic-width": 64,
+  "os": "linux",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relro-level": "full",
+  "stack-probes": true,
+  "target-c-int-width": "32",
+  "target-endian": "little",
+  "target-family": "unix",
+  "target-pointer-width": "64",
+  "vendor": "unknown"
+}
diff --git a/third_party/itoa/Cargo.toml b/third_party/itoa/Cargo.toml
index f36dc3f..df21d92 100644
--- a/third_party/itoa/Cargo.toml
+++ b/third_party/itoa/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "itoa"
-version = "0.3.4" # remember to update html_root_url
+version = "0.4.1" # remember to update html_root_url
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 license = "MIT/Apache-2.0"
 description = "Fast functions for printing integer primitives to an io::Write"
diff --git a/third_party/itoa/README.md b/third_party/itoa/README.md
index 524957b..759be9d 100644
--- a/third_party/itoa/README.md
+++ b/third_party/itoa/README.md
@@ -5,7 +5,8 @@
 [![Latest Version](https://img.shields.io/crates/v/itoa.svg)](https://crates.io/crates/itoa)
 
 This crate provides fast functions for printing integer primitives to an
-[`io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html). The
+[`io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html) or a
+[`fmt::Write`](https://doc.rust-lang.org/core/fmt/trait.Write.html). The
 implementation comes straight from
 [libcore](https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254)
 but avoids the performance penalty of going through
@@ -32,12 +33,19 @@
 let mut bytes = [b'\0'; 20];
 let n = itoa::write(&mut bytes[..], 128u64)?;
 println!("{:?}", &bytes[..n]);
+
+// write to a String
+let mut s = String::new();
+itoa::fmt(&mut s, 128u64)?;
+println!("{}", s);
 ```
 
-The function signature is:
+The function signatures are:
 
 ```rust
-fn write<W: io::Write, V: itoa::Integer>(writer: W, value: V) -> io::Result<usize>
+fn write<W: io::Write, V: itoa::Integer>(writer: W, value: V) -> io::Result<usize>;
+
+fn fmt<W: fmt::Write, V: itoa::Integer>(writer: W, value: V) -> fmt::Result;
 ```
 
 where `itoa::Integer` is implemented for `i8`, `u8`, `i16`, `u16`, `i32`, `u32`,
@@ -45,6 +53,9 @@
 only available with the nightly compiler when the `i128` feature is enabled for
 this crate. The return value gives the number of bytes written.
 
+The `write` function is only available when the `std` feature is enabled
+(default is enabled).
+
 ## Dependency
 
 Itoa is available on [crates.io](https://crates.io/crates/itoa). Use the
@@ -52,7 +63,7 @@
 
 ```toml
 [dependencies]
-itoa = "0.3"
+itoa = "0.4"
 ```
 
 ## License
diff --git a/third_party/itoa/benches/bench.rs b/third_party/itoa/benches/bench.rs
index 815b5a3..7e6ca82 100644
--- a/third_party/itoa/benches/bench.rs
+++ b/third_party/itoa/benches/bench.rs
@@ -15,7 +15,7 @@
             $name:ident($value:expr)
         ),*
     ) => {
-        mod bench_itoa {
+        mod bench_itoa_write {
             use test::{Bencher, black_box};
             $(
                 $(#[$attr])*
@@ -33,7 +33,25 @@
             )*
         }
 
-        mod bench_fmt {
+        mod bench_itoa_fmt {
+            use test::{Bencher, black_box};
+            $(
+                $(#[$attr])*
+                #[bench]
+                fn $name(b: &mut Bencher) {
+                    use itoa;
+
+                    let mut buf = String::with_capacity(40);
+
+                    b.iter(|| {
+                        buf.clear();
+                        itoa::fmt(&mut buf, black_box($value)).unwrap()
+                    });
+                }
+            )*
+        }
+
+        mod bench_std_fmt {
             use test::{Bencher, black_box};
             $(
                 $(#[$attr])*
diff --git a/third_party/itoa/src/lib.rs b/third_party/itoa/src/lib.rs
index ba9e7b8..d089246 100644
--- a/third_party/itoa/src/lib.rs
+++ b/third_party/itoa/src/lib.rs
@@ -6,14 +6,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![doc(html_root_url = "https://docs.rs/itoa/0.3.4")]
-
-#![cfg_attr(feature = "i128", feature(i128_type, i128))]
-
-#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless, unreadable_literal))]
+#![doc(html_root_url = "https://docs.rs/itoa/0.4.1")]
 
 #![cfg_attr(not(target_env = "sgx"), no_std)]
 #![cfg_attr(target_env = "sgx", feature(rustc_private))]
+#![cfg_attr(feature = "i128", feature(i128_type, i128))]
+#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless, unreadable_literal))]
 
 #[cfg(not(target_env = "sgx"))]
 extern crate sgx_tstd as std;
@@ -21,19 +19,40 @@
 #[cfg(feature = "i128")]
 mod udiv128;
 
-use std::{io, mem, ptr, slice};
+use std::{fmt, io, mem, ptr, slice, str};
 
+/// Write integer to an `io::Write`.
 #[inline]
 pub fn write<W: io::Write, V: Integer>(wr: W, value: V) -> io::Result<usize> {
     value.write(wr)
 }
 
-pub trait Integer {
-    fn write<W: io::Write>(self, W) -> io::Result<usize>;
+/// Write integer to an `fmt::Write`.
+#[inline]
+pub fn fmt<W: fmt::Write, V: Integer>(wr: W, value: V) -> fmt::Result {
+    value.fmt(wr)
 }
 
-trait IntegerPrivate {
-    fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8];
+// Seal to prevent downstream implementations of the Integer trait.
+mod private {
+    pub trait Sealed {}
+}
+
+/// An integer that can be formatted by `itoa::write` and `itoa::fmt`.
+///
+/// This trait is sealed and cannot be implemented for types outside of itoa.
+pub trait Integer: private::Sealed {
+    // Not public API.
+    #[doc(hidden)]
+    fn write<W: io::Write>(self, W) -> io::Result<usize>;
+
+    // Not public API.
+    #[doc(hidden)]
+    fn fmt<W: fmt::Write>(self, W) -> fmt::Result;
+}
+
+trait IntegerPrivate<B> {
+    fn write_to(self, buf: &mut B) -> &[u8];
 }
 
 const DEC_DIGITS_LUT: &'static[u8] =
@@ -43,24 +62,39 @@
       6061626364656667686970717273747576777879\
       8081828384858687888990919293949596979899";
 
-const MAX_LEN: usize = 40; // i128::MIN (including minus sign)
-
 // Adaptation of the original implementation at
 // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266
-macro_rules! impl_Integer {
-    ($($t:ident),* as $conv_fn:ident) => {$(
+macro_rules! impl_IntegerCommon {
+    ($max_len:expr, $t:ident) => {
         impl Integer for $t {
+            #[inline]
             fn write<W: io::Write>(self, mut wr: W) -> io::Result<usize> {
-                let mut buf = unsafe { mem::uninitialized() };
+                let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() };
                 let bytes = self.write_to(&mut buf);
                 try!(wr.write_all(bytes));
                 Ok(bytes.len())
             }
+
+            #[inline]
+            fn fmt<W: fmt::Write>(self, mut wr: W) -> fmt::Result {
+                let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() };
+                let bytes = self.write_to(&mut buf);
+                wr.write_str(unsafe { str::from_utf8_unchecked(bytes) })
+            }
         }
 
-        impl IntegerPrivate for $t {
+        impl private::Sealed for $t {}
+    };
+}
+
+macro_rules! impl_Integer {
+    ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$(
+        impl_IntegerCommon!($max_len, $t);
+
+        impl IntegerPrivate<[u8; $max_len]> for $t {
             #[allow(unused_comparisons)]
-            fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8] {
+            #[inline]
+            fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] {
                 let is_nonnegative = self >= 0;
                 let mut n = if is_nonnegative {
                     self as $conv_fn
@@ -122,30 +156,44 @@
     )*};
 }
 
-impl_Integer!(i8, u8, i16, u16, i32, u32 as u32);
-impl_Integer!(i64, u64 as u64);
+const I8_MAX_LEN: usize = 4;
+const U8_MAX_LEN: usize = 3;
+const I16_MAX_LEN: usize = 6;
+const U16_MAX_LEN: usize = 5;
+const I32_MAX_LEN: usize = 11;
+const U32_MAX_LEN: usize = 10;
+const I64_MAX_LEN: usize = 20;
+const U64_MAX_LEN: usize = 20;
+
+impl_Integer!(
+    I8_MAX_LEN => i8,
+    U8_MAX_LEN => u8,
+    I16_MAX_LEN => i16,
+    U16_MAX_LEN => u16,
+    I32_MAX_LEN => i32,
+    U32_MAX_LEN => u32 
+    as u32);
+
+impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64);
+
 #[cfg(target_pointer_width = "16")]
-impl_Integer!(isize, usize as u16);
+impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16);
+
 #[cfg(target_pointer_width = "32")]
-impl_Integer!(isize, usize as u32);
+impl_Integer!(I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32);
+
 #[cfg(target_pointer_width = "64")]
-impl_Integer!(isize, usize as u64);
+impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64);
 
 #[cfg(all(feature = "i128"))]
 macro_rules! impl_Integer128 {
-    ($($t:ident),*) => {$(
-        impl Integer for $t {
-            fn write<W: io::Write>(self, mut wr: W) -> io::Result<usize> {
-                let mut buf = unsafe { mem::uninitialized() };
-                let bytes = self.write_to(&mut buf);
-                try!(wr.write_all(bytes));
-                Ok(bytes.len())
-            }
-        }
+    ($($max_len:expr => $t:ident),*) => {$(
+        impl_IntegerCommon!($max_len, $t);
 
-        impl IntegerPrivate for $t {
+        impl IntegerPrivate<[u8; $max_len]> for $t {
             #[allow(unused_comparisons)]
-            fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8] {
+            #[inline]
+            fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] {
                 let is_nonnegative = self >= 0;
                 let n = if is_nonnegative {
                     self as u128
@@ -159,7 +207,8 @@
                 unsafe {
                     // Divide by 10^19 which is the highest power less than 2^64.
                     let (n, rem) = udiv128::udivmod_1e19(n);
-                    curr -= rem.write_to(buf).len() as isize;
+                    let buf1 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN];
+                    curr -= rem.write_to(&mut *buf1).len() as isize;
 
                     if n != 0 {
                         // Memset the base10 leading zeros of rem.
@@ -169,7 +218,7 @@
 
                         // Divide by 10^19 again.
                         let (n, rem) = udiv128::udivmod_1e19(n);
-                        let buf2 = buf_ptr.offset(curr - buf.len() as isize) as *mut _;
+                        let buf2 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN];
                         curr -= rem.write_to(&mut *buf2).len() as isize;
 
                         if n != 0 {
@@ -199,4 +248,9 @@
 }
 
 #[cfg(all(feature = "i128"))]
-impl_Integer128!(i128, u128);
+const U128_MAX_LEN: usize = 39;
+#[cfg(all(feature = "i128"))]
+const I128_MAX_LEN: usize = 40;
+
+#[cfg(all(feature = "i128"))]
+impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128);
diff --git a/third_party/itoa/src/udiv128.rs b/third_party/itoa/src/udiv128.rs
index 24233c6..70fffc6 100644
--- a/third_party/itoa/src/udiv128.rs
+++ b/third_party/itoa/src/udiv128.rs
@@ -21,6 +21,7 @@
 // (https://github.com/rust-lang/rust/issues/44545) and to allow function
 // inlining which doesn’t happen with the intrinsic.
 
+#[inline]
 pub fn udivmod_1e19(n: u128) -> (u128, u64) {
     let d = 10_000_000_000_000_000_000_u64; // 10^19
 
diff --git a/third_party/itoa/tests/test.rs b/third_party/itoa/tests/test.rs
index a360293..ad7c3d7 100644
--- a/third_party/itoa/tests/test.rs
+++ b/third_party/itoa/tests/test.rs
@@ -17,9 +17,16 @@
             $(#[$attr])*
             #[test]
             fn $name() {
-                let mut buf = [b'\0'; 40];
-                let len = itoa::write(&mut buf[..], $value).unwrap();
-                assert_eq!(&buf[0..len], $expected.as_bytes());
+                #[cfg(feature = "std")]
+                {
+                    let mut buf = [b'\0'; 40];
+                    let len = itoa::write(&mut buf[..], $value).unwrap();
+                    assert_eq!(&buf[0..len], $expected.as_bytes());
+                }
+
+                let mut s = String::new();
+                itoa::fmt(&mut s, $value).unwrap();
+                assert_eq!(s, $expected);
             }
         )*
     }
diff --git a/third_party/json-rust/src/parser.rs b/third_party/json-rust/src/parser.rs
index 29236e7..867be9e 100755
--- a/third_party/json-rust/src/parser.rs
+++ b/third_party/json-rust/src/parser.rs
@@ -632,7 +632,7 @@
             }
         }
 
-        Ok(unsafe { Number::from_parts_unchecked(true, num, (big_e.saturating_add(e * sign))) })
+        Ok(unsafe { Number::from_parts_unchecked(true, num, big_e.saturating_add(e * sign)) })
     }
 
     // Parse away!
diff --git a/third_party/log/Cargo.toml b/third_party/log/Cargo.toml
index 10a261e..89aeda9 100644
--- a/third_party/log/Cargo.toml
+++ b/third_party/log/Cargo.toml
@@ -18,10 +18,6 @@
 [package.metadata.docs.rs]
 features = ["std", "serde"]
 
-[[test]]
-name = "filters"
-harness = false
-
 [features]
 max_level_off   = []
 max_level_error = []
diff --git a/third_party/num/integer/Cargo.toml b/third_party/num/integer/Cargo.toml
index 41a1902..dcb3cb3 100644
--- a/third_party/num/integer/Cargo.toml
+++ b/third_party/num/integer/Cargo.toml
@@ -15,4 +15,3 @@
 
 [dependencies.num-traits]
 path = "../traits"
-version = "0.1.32"
diff --git a/third_party/num/iter/Cargo.toml b/third_party/num/iter/Cargo.toml
index e95984f..b31ce9b 100644
--- a/third_party/num/iter/Cargo.toml
+++ b/third_party/num/iter/Cargo.toml
@@ -21,4 +21,3 @@
 [dependencies.num-traits]
 optional = false
 path = "../traits"
-version = "0.1.32"
diff --git a/third_party/num/traits/Cargo.toml b/third_party/num/traits/Cargo.toml
index 837ca44..0c7b53b 100644
--- a/third_party/num/traits/Cargo.toml
+++ b/third_party/num/traits/Cargo.toml
@@ -8,7 +8,12 @@
 license = "MIT/Apache-2.0"
 repository = "https://github.com/rust-num/num"
 name = "num-traits"
-version = "0.1.40"
+version = "0.2.5"
 
 [target.'cfg(not(target_env = "sgx"))'.dependencies]
 sgx_tstd = { path =  "../../../sgx_tstd" }
+
+[features]
+default = ["std"]
+std = []
+i128 = []
diff --git a/third_party/num/traits/src/bounds.rs b/third_party/num/traits/src/bounds.rs
index 83fdd0f..744c5ba 100644
--- a/third_party/num/traits/src/bounds.rs
+++ b/third_party/num/traits/src/bounds.rs
@@ -1,7 +1,9 @@
-use std::{usize, u8, u16, u32, u64};
-use std::{isize, i8, i16, i32, i64};
-use std::{f32, f64};
-use std::num::Wrapping;
+use core::{usize, u8, u16, u32, u64};
+use core::{isize, i8, i16, i32, i64};
+use core::{f32, f64};
+use core::num::Wrapping;
+#[cfg(has_i128)]
+use core::{i128, u128};
 
 /// Numbers which have upper and lower bounds
 pub trait Bounded {
@@ -29,12 +31,16 @@
 bounded_impl!(u16,   u16::MIN,   u16::MAX);
 bounded_impl!(u32,   u32::MIN,   u32::MAX);
 bounded_impl!(u64,   u64::MIN,   u64::MAX);
+#[cfg(has_i128)]
+bounded_impl!(u128,  u128::MIN,  u128::MAX);
 
 bounded_impl!(isize, isize::MIN, isize::MAX);
 bounded_impl!(i8,    i8::MIN,    i8::MAX);
 bounded_impl!(i16,   i16::MIN,   i16::MAX);
 bounded_impl!(i32,   i32::MIN,   i32::MAX);
 bounded_impl!(i64,   i64::MIN,   i64::MAX);
+#[cfg(has_i128)]
+bounded_impl!(i128,  i128::MIN,  i128::MAX);
 
 impl<T: Bounded> Bounded for Wrapping<T> {
     fn min_value() -> Self { Wrapping(T::min_value()) }
@@ -91,6 +97,21 @@
     test_wrapping_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
 }
 
+#[cfg(has_i128)]
+#[test]
+fn wrapping_bounded_i128() {
+    macro_rules! test_wrapping_bounded {
+        ($($t:ty)+) => {
+            $(
+                assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
+                assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
+            )+
+        };
+    }
+
+    test_wrapping_bounded!(u128 i128);
+}
+
 #[test]
 fn wrapping_is_bounded() {
     fn require_bounded<T: Bounded>(_: &T) {}
diff --git a/third_party/num/traits/src/cast.rs b/third_party/num/traits/src/cast.rs
index 62e6bf6..c692df8 100644
--- a/third_party/num/traits/src/cast.rs
+++ b/third_party/num/traits/src/cast.rs
@@ -1,136 +1,163 @@
-use std::mem::size_of;
-use std::num::Wrapping;
+use core::{i8, i16, i32, i64, isize};
+use core::{u8, u16, u32, u64, usize};
+use core::{f32, f64};
+use core::mem::size_of;
+use core::num::Wrapping;
+#[cfg(has_i128)]
+use core::{i128, u128};
 
-use identities::Zero;
-use bounds::Bounded;
+use float::FloatCore;
 
 /// A generic trait for converting a value to a number.
 pub trait ToPrimitive {
     /// Converts the value of `self` to an `isize`.
     #[inline]
     fn to_isize(&self) -> Option<isize> {
-        self.to_i64().and_then(|x| x.to_isize())
+        self.to_i64().as_ref().and_then(ToPrimitive::to_isize)
     }
 
     /// Converts the value of `self` to an `i8`.
     #[inline]
     fn to_i8(&self) -> Option<i8> {
-        self.to_i64().and_then(|x| x.to_i8())
+        self.to_i64().as_ref().and_then(ToPrimitive::to_i8)
     }
 
     /// Converts the value of `self` to an `i16`.
     #[inline]
     fn to_i16(&self) -> Option<i16> {
-        self.to_i64().and_then(|x| x.to_i16())
+        self.to_i64().as_ref().and_then(ToPrimitive::to_i16)
     }
 
     /// Converts the value of `self` to an `i32`.
     #[inline]
     fn to_i32(&self) -> Option<i32> {
-        self.to_i64().and_then(|x| x.to_i32())
+        self.to_i64().as_ref().and_then(ToPrimitive::to_i32)
     }
 
     /// Converts the value of `self` to an `i64`.
     fn to_i64(&self) -> Option<i64>;
 
+    /// Converts the value of `self` to an `i128`.
+    ///
+    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
+    ///
+    /// The default implementation converts through `to_i64()`.  Types implementing
+    /// this trait should override this method if they can represent a greater range.
+    #[inline]
+    #[cfg(has_i128)]
+    fn to_i128(&self) -> Option<i128> {
+        self.to_i64().map(From::from)
+    }
+
     /// Converts the value of `self` to a `usize`.
     #[inline]
     fn to_usize(&self) -> Option<usize> {
-        self.to_u64().and_then(|x| x.to_usize())
+        self.to_u64().as_ref().and_then(ToPrimitive::to_usize)
     }
 
     /// Converts the value of `self` to an `u8`.
     #[inline]
     fn to_u8(&self) -> Option<u8> {
-        self.to_u64().and_then(|x| x.to_u8())
+        self.to_u64().as_ref().and_then(ToPrimitive::to_u8)
     }
 
     /// Converts the value of `self` to an `u16`.
     #[inline]
     fn to_u16(&self) -> Option<u16> {
-        self.to_u64().and_then(|x| x.to_u16())
+        self.to_u64().as_ref().and_then(ToPrimitive::to_u16)
     }
 
     /// Converts the value of `self` to an `u32`.
     #[inline]
     fn to_u32(&self) -> Option<u32> {
-        self.to_u64().and_then(|x| x.to_u32())
+        self.to_u64().as_ref().and_then(ToPrimitive::to_u32)
     }
 
     /// Converts the value of `self` to an `u64`.
     #[inline]
     fn to_u64(&self) -> Option<u64>;
 
+    /// Converts the value of `self` to an `u128`.
+    ///
+    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
+    ///
+    /// The default implementation converts through `to_u64()`.  Types implementing
+    /// this trait should override this method if they can represent a greater range.
+    #[inline]
+    #[cfg(has_i128)]
+    fn to_u128(&self) -> Option<u128> {
+        self.to_u64().map(From::from)
+    }
+
     /// Converts the value of `self` to an `f32`.
     #[inline]
     fn to_f32(&self) -> Option<f32> {
-        self.to_f64().and_then(|x| x.to_f32())
+        self.to_f64().as_ref().and_then(ToPrimitive::to_f32)
     }
 
     /// Converts the value of `self` to an `f64`.
     #[inline]
     fn to_f64(&self) -> Option<f64> {
-        self.to_i64().and_then(|x| x.to_f64())
+        match self.to_i64() {
+            Some(i) => i.to_f64(),
+            None => self.to_u64().as_ref().and_then(ToPrimitive::to_f64),
+        }
     }
 }
 
 macro_rules! impl_to_primitive_int_to_int {
-    ($SrcT:ty, $DstT:ty, $slf:expr) => (
-        {
-            if size_of::<$SrcT>() <= size_of::<$DstT>() {
-                Some($slf as $DstT)
-            } else {
-                let n = $slf as i64;
-                let min_value: $DstT = Bounded::min_value();
-                let max_value: $DstT = Bounded::max_value();
-                if min_value as i64 <= n && n <= max_value as i64 {
-                    Some($slf as $DstT)
-                } else {
-                    None
-                }
-            }
-        }
-    )
-}
-
-macro_rules! impl_to_primitive_int_to_uint {
-    ($SrcT:ty, $DstT:ty, $slf:expr) => (
-        {
-            let zero: $SrcT = Zero::zero();
-            let max_value: $DstT = Bounded::max_value();
-            if zero <= $slf && $slf as u64 <= max_value as u64 {
-                Some($slf as $DstT)
+    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(&self) -> Option<$DstT> {
+            let min = $DstT::MIN as $SrcT;
+            let max = $DstT::MAX as $SrcT;
+            if size_of::<$SrcT>() <= size_of::<$DstT>() || (min <= *self && *self <= max) {
+                Some(*self as $DstT)
             } else {
                 None
             }
         }
-    )
+    )*}
+}
+
+macro_rules! impl_to_primitive_int_to_uint {
+    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(&self) -> Option<$DstT> {
+            let max = $DstT::MAX as $SrcT;
+            if 0 <= *self && (size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max) {
+                Some(*self as $DstT)
+            } else {
+                None
+            }
+        }
+    )*}
 }
 
 macro_rules! impl_to_primitive_int {
-    ($T:ty) => (
+    ($T:ident) => (
         impl ToPrimitive for $T {
-            #[inline]
-            fn to_isize(&self) -> Option<isize> { impl_to_primitive_int_to_int!($T, isize, *self) }
-            #[inline]
-            fn to_i8(&self) -> Option<i8> { impl_to_primitive_int_to_int!($T, i8, *self) }
-            #[inline]
-            fn to_i16(&self) -> Option<i16> { impl_to_primitive_int_to_int!($T, i16, *self) }
-            #[inline]
-            fn to_i32(&self) -> Option<i32> { impl_to_primitive_int_to_int!($T, i32, *self) }
-            #[inline]
-            fn to_i64(&self) -> Option<i64> { impl_to_primitive_int_to_int!($T, i64, *self) }
+            impl_to_primitive_int_to_int! { $T:
+                fn to_isize -> isize;
+                fn to_i8 -> i8;
+                fn to_i16 -> i16;
+                fn to_i32 -> i32;
+                fn to_i64 -> i64;
+                #[cfg(has_i128)]
+                fn to_i128 -> i128;
+            }
 
-            #[inline]
-            fn to_usize(&self) -> Option<usize> { impl_to_primitive_int_to_uint!($T, usize, *self) }
-            #[inline]
-            fn to_u8(&self) -> Option<u8> { impl_to_primitive_int_to_uint!($T, u8, *self) }
-            #[inline]
-            fn to_u16(&self) -> Option<u16> { impl_to_primitive_int_to_uint!($T, u16, *self) }
-            #[inline]
-            fn to_u32(&self) -> Option<u32> { impl_to_primitive_int_to_uint!($T, u32, *self) }
-            #[inline]
-            fn to_u64(&self) -> Option<u64> { impl_to_primitive_int_to_uint!($T, u64, *self) }
+            impl_to_primitive_int_to_uint! { $T:
+                fn to_usize -> usize;
+                fn to_u8 -> u8;
+                fn to_u16 -> u16;
+                fn to_u32 -> u32;
+                fn to_u64 -> u64;
+                #[cfg(has_i128)]
+                fn to_u128 -> u128;
+            }
 
             #[inline]
             fn to_f32(&self) -> Option<f32> { Some(*self as f32) }
@@ -145,64 +172,61 @@
 impl_to_primitive_int!(i16);
 impl_to_primitive_int!(i32);
 impl_to_primitive_int!(i64);
+#[cfg(has_i128)]
+impl_to_primitive_int!(i128);
 
 macro_rules! impl_to_primitive_uint_to_int {
-    ($DstT:ty, $slf:expr) => (
-        {
-            let max_value: $DstT = Bounded::max_value();
-            if $slf as u64 <= max_value as u64 {
-                Some($slf as $DstT)
+    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(&self) -> Option<$DstT> {
+            let max = $DstT::MAX as $SrcT;
+            if size_of::<$SrcT>() < size_of::<$DstT>() || *self <= max {
+                Some(*self as $DstT)
             } else {
                 None
             }
         }
-    )
+    )*}
 }
 
 macro_rules! impl_to_primitive_uint_to_uint {
-    ($SrcT:ty, $DstT:ty, $slf:expr) => (
-        {
-            if size_of::<$SrcT>() <= size_of::<$DstT>() {
-                Some($slf as $DstT)
+    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(&self) -> Option<$DstT> {
+            let max = $DstT::MAX as $SrcT;
+            if size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max {
+                Some(*self as $DstT)
             } else {
-                let zero: $SrcT = Zero::zero();
-                let max_value: $DstT = Bounded::max_value();
-                if zero <= $slf && $slf as u64 <= max_value as u64 {
-                    Some($slf as $DstT)
-                } else {
-                    None
-                }
+                None
             }
         }
-    )
+    )*}
 }
 
 macro_rules! impl_to_primitive_uint {
-    ($T:ty) => (
+    ($T:ident) => (
         impl ToPrimitive for $T {
-            #[inline]
-            fn to_isize(&self) -> Option<isize> { impl_to_primitive_uint_to_int!(isize, *self) }
-            #[inline]
-            fn to_i8(&self) -> Option<i8> { impl_to_primitive_uint_to_int!(i8, *self) }
-            #[inline]
-            fn to_i16(&self) -> Option<i16> { impl_to_primitive_uint_to_int!(i16, *self) }
-            #[inline]
-            fn to_i32(&self) -> Option<i32> { impl_to_primitive_uint_to_int!(i32, *self) }
-            #[inline]
-            fn to_i64(&self) -> Option<i64> { impl_to_primitive_uint_to_int!(i64, *self) }
-
-            #[inline]
-            fn to_usize(&self) -> Option<usize> {
-                impl_to_primitive_uint_to_uint!($T, usize, *self)
+            impl_to_primitive_uint_to_int! { $T:
+                fn to_isize -> isize;
+                fn to_i8 -> i8;
+                fn to_i16 -> i16;
+                fn to_i32 -> i32;
+                fn to_i64 -> i64;
+                #[cfg(has_i128)]
+                fn to_i128 -> i128;
             }
-            #[inline]
-            fn to_u8(&self) -> Option<u8> { impl_to_primitive_uint_to_uint!($T, u8, *self) }
-            #[inline]
-            fn to_u16(&self) -> Option<u16> { impl_to_primitive_uint_to_uint!($T, u16, *self) }
-            #[inline]
-            fn to_u32(&self) -> Option<u32> { impl_to_primitive_uint_to_uint!($T, u32, *self) }
-            #[inline]
-            fn to_u64(&self) -> Option<u64> { impl_to_primitive_uint_to_uint!($T, u64, *self) }
+
+            impl_to_primitive_uint_to_uint! { $T:
+                fn to_usize -> usize;
+                fn to_u8 -> u8;
+                fn to_u16 -> u16;
+                fn to_u32 -> u32;
+                fn to_u64 -> u64;
+                #[cfg(has_i128)]
+                fn to_u128 -> u128;
+            }
 
             #[inline]
             fn to_f32(&self) -> Option<f32> { Some(*self as f32) }
@@ -217,54 +241,110 @@
 impl_to_primitive_uint!(u16);
 impl_to_primitive_uint!(u32);
 impl_to_primitive_uint!(u64);
+#[cfg(has_i128)]
+impl_to_primitive_uint!(u128);
 
 macro_rules! impl_to_primitive_float_to_float {
-    ($SrcT:ident, $DstT:ident, $slf:expr) => (
-        if size_of::<$SrcT>() <= size_of::<$DstT>() {
-            Some($slf as $DstT)
-        } else {
-            // Make sure the value is in range for the cast.
-            // NaN and +-inf are cast as they are.
-            let n = $slf as f64;
-            let max_value: $DstT = ::std::$DstT::MAX;
-            if !n.is_finite() || (-max_value as f64 <= n && n <= max_value as f64) {
-                Some($slf as $DstT)
-            } else {
-                None
+    ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
+        #[inline]
+        fn $method(&self) -> Option<$DstT> {
+            // Only finite values that are reducing size need to worry about overflow.
+            if size_of::<$SrcT>() > size_of::<$DstT>() && FloatCore::is_finite(*self) {
+                let n = *self as f64;
+                if n < $DstT::MIN as f64 || n > $DstT::MAX as f64 {
+                    return None;
+                }
             }
+            // We can safely cast NaN, +-inf, and finite values in range.
+            Some(*self as $DstT)
         }
-    )
+    )*}
+}
+
+macro_rules! impl_to_primitive_float_to_signed_int {
+    ($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(&self) -> Option<$i> {
+            // Float as int truncates toward zero, so we want to allow values
+            // in the exclusive range `(MIN-1, MAX+1)`.
+            if size_of::<$f>() > size_of::<$i>() {
+                // With a larger size, we can represent the range exactly.
+                const MIN_M1: $f = $i::MIN as $f - 1.0;
+                const MAX_P1: $f = $i::MAX as $f + 1.0;
+                if *self > MIN_M1 && *self < MAX_P1 {
+                    return Some(*self as $i);
+                }
+            } else {
+                // We can't represent `MIN-1` exactly, but there's no fractional part
+                // at this magnitude, so we can just use a `MIN` inclusive boundary.
+                const MIN: $f = $i::MIN as $f;
+                // We can't represent `MAX` exactly, but it will round up to exactly
+                // `MAX+1` (a power of two) when we cast it.
+                const MAX_P1: $f = $i::MAX as $f;
+                if *self >= MIN && *self < MAX_P1 {
+                    return Some(*self as $i);
+                }
+            }
+            None
+        }
+    )*}
+}
+
+macro_rules! impl_to_primitive_float_to_unsigned_int {
+    ($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $u:ident ; )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(&self) -> Option<$u> {
+            // Float as int truncates toward zero, so we want to allow values
+            // in the exclusive range `(-1, MAX+1)`.
+            if size_of::<$f>() > size_of::<$u>() {
+                // With a larger size, we can represent the range exactly.
+                const MAX_P1: $f = $u::MAX as $f + 1.0;
+                if *self > -1.0 && *self < MAX_P1 {
+                    return Some(*self as $u);
+                }
+            } else {
+                // We can't represent `MAX` exactly, but it will round up to exactly
+                // `MAX+1` (a power of two) when we cast it.
+                // (`u128::MAX as f32` is infinity, but this is still ok.)
+                const MAX_P1: $f = $u::MAX as $f;
+                if *self > -1.0 && *self < MAX_P1 {
+                    return Some(*self as $u);
+                }
+            }
+            None
+        }
+    )*}
 }
 
 macro_rules! impl_to_primitive_float {
     ($T:ident) => (
         impl ToPrimitive for $T {
-            #[inline]
-            fn to_isize(&self) -> Option<isize> { Some(*self as isize) }
-            #[inline]
-            fn to_i8(&self) -> Option<i8> { Some(*self as i8) }
-            #[inline]
-            fn to_i16(&self) -> Option<i16> { Some(*self as i16) }
-            #[inline]
-            fn to_i32(&self) -> Option<i32> { Some(*self as i32) }
-            #[inline]
-            fn to_i64(&self) -> Option<i64> { Some(*self as i64) }
+            impl_to_primitive_float_to_signed_int! { $T:
+                fn to_isize -> isize;
+                fn to_i8 -> i8;
+                fn to_i16 -> i16;
+                fn to_i32 -> i32;
+                fn to_i64 -> i64;
+                #[cfg(has_i128)]
+                fn to_i128 -> i128;
+            }
 
-            #[inline]
-            fn to_usize(&self) -> Option<usize> { Some(*self as usize) }
-            #[inline]
-            fn to_u8(&self) -> Option<u8> { Some(*self as u8) }
-            #[inline]
-            fn to_u16(&self) -> Option<u16> { Some(*self as u16) }
-            #[inline]
-            fn to_u32(&self) -> Option<u32> { Some(*self as u32) }
-            #[inline]
-            fn to_u64(&self) -> Option<u64> { Some(*self as u64) }
+            impl_to_primitive_float_to_unsigned_int! { $T:
+                fn to_usize -> usize;
+                fn to_u8 -> u8;
+                fn to_u16 -> u16;
+                fn to_u32 -> u32;
+                fn to_u64 -> u64;
+                #[cfg(has_i128)]
+                fn to_u128 -> u128;
+            }
 
-            #[inline]
-            fn to_f32(&self) -> Option<f32> { impl_to_primitive_float_to_float!($T, f32, *self) }
-            #[inline]
-            fn to_f64(&self) -> Option<f64> { impl_to_primitive_float_to_float!($T, f64, *self) }
+            impl_to_primitive_float_to_float! { $T:
+                fn to_f32 -> f32;
+                fn to_f64 -> f64;
+            }
         }
     )
 }
@@ -275,81 +355,110 @@
 /// A generic trait for converting a number to a value.
 pub trait FromPrimitive: Sized {
     /// Convert an `isize` to return an optional value of this type. If the
-    /// value cannot be represented by this value, the `None` is returned.
+    /// value cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_isize(n: isize) -> Option<Self> {
-        FromPrimitive::from_i64(n as i64)
+        n.to_i64().and_then(FromPrimitive::from_i64)
     }
 
     /// Convert an `i8` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_i8(n: i8) -> Option<Self> {
-        FromPrimitive::from_i64(n as i64)
+        FromPrimitive::from_i64(From::from(n))
     }
 
     /// Convert an `i16` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_i16(n: i16) -> Option<Self> {
-        FromPrimitive::from_i64(n as i64)
+        FromPrimitive::from_i64(From::from(n))
     }
 
     /// Convert an `i32` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_i32(n: i32) -> Option<Self> {
-        FromPrimitive::from_i64(n as i64)
+        FromPrimitive::from_i64(From::from(n))
     }
 
     /// Convert an `i64` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     fn from_i64(n: i64) -> Option<Self>;
 
+    /// Convert an `i128` to return an optional value of this type. If the
+    /// type cannot be represented by this value, then `None` is returned.
+    ///
+    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
+    ///
+    /// The default implementation converts through `from_i64()`.  Types implementing
+    /// this trait should override this method if they can represent a greater range.
+    #[inline]
+    #[cfg(has_i128)]
+    fn from_i128(n: i128) -> Option<Self> {
+        n.to_i64().and_then(FromPrimitive::from_i64)
+    }
+
     /// Convert a `usize` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_usize(n: usize) -> Option<Self> {
-        FromPrimitive::from_u64(n as u64)
+        n.to_u64().and_then(FromPrimitive::from_u64)
     }
 
     /// Convert an `u8` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_u8(n: u8) -> Option<Self> {
-        FromPrimitive::from_u64(n as u64)
+        FromPrimitive::from_u64(From::from(n))
     }
 
     /// Convert an `u16` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_u16(n: u16) -> Option<Self> {
-        FromPrimitive::from_u64(n as u64)
+        FromPrimitive::from_u64(From::from(n))
     }
 
     /// Convert an `u32` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_u32(n: u32) -> Option<Self> {
-        FromPrimitive::from_u64(n as u64)
+        FromPrimitive::from_u64(From::from(n))
     }
 
     /// Convert an `u64` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     fn from_u64(n: u64) -> Option<Self>;
 
+    /// Convert an `u128` to return an optional value of this type. If the
+    /// type cannot be represented by this value, then `None` is returned.
+    ///
+    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
+    ///
+    /// The default implementation converts through `from_u64()`.  Types implementing
+    /// this trait should override this method if they can represent a greater range.
+    #[inline]
+    #[cfg(has_i128)]
+    fn from_u128(n: u128) -> Option<Self> {
+        n.to_u64().and_then(FromPrimitive::from_u64)
+    }
+
     /// Convert a `f32` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_f32(n: f32) -> Option<Self> {
-        FromPrimitive::from_f64(n as f64)
+        FromPrimitive::from_f64(From::from(n))
     }
 
     /// Convert a `f64` to return an optional value of this type. If the
-    /// type cannot be represented by this value, the `None` is returned.
+    /// type cannot be represented by this value, then `None` is returned.
     #[inline]
     fn from_f64(n: f64) -> Option<Self> {
-        FromPrimitive::from_i64(n as i64)
+        match n.to_i64() {
+            Some(i) => FromPrimitive::from_i64(i),
+            None => n.to_u64().and_then(FromPrimitive::from_u64),
+        }
     }
 }
 
@@ -357,15 +466,21 @@
     ($T:ty, $to_ty:ident) => (
         #[allow(deprecated)]
         impl FromPrimitive for $T {
+            #[inline] fn from_isize(n: isize) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_i8(n: i8) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_i16(n: i16) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_i32(n: i32) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_i64(n: i64) -> Option<$T> { n.$to_ty() }
+            #[cfg(has_i128)]
+            #[inline] fn from_i128(n: i128) -> Option<$T> { n.$to_ty() }
 
+            #[inline] fn from_usize(n: usize) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_u8(n: u8) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_u16(n: u16) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_u32(n: u32) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_u64(n: u64) -> Option<$T> { n.$to_ty() }
+            #[cfg(has_i128)]
+            #[inline] fn from_u128(n: u128) -> Option<$T> { n.$to_ty() }
 
             #[inline] fn from_f32(n: f32) -> Option<$T> { n.$to_ty() }
             #[inline] fn from_f64(n: f64) -> Option<$T> { n.$to_ty() }
@@ -378,22 +493,83 @@
 impl_from_primitive!(i16,   to_i16);
 impl_from_primitive!(i32,   to_i32);
 impl_from_primitive!(i64,   to_i64);
+#[cfg(has_i128)]
+impl_from_primitive!(i128,  to_i128);
 impl_from_primitive!(usize, to_usize);
 impl_from_primitive!(u8,    to_u8);
 impl_from_primitive!(u16,   to_u16);
 impl_from_primitive!(u32,   to_u32);
 impl_from_primitive!(u64,   to_u64);
+#[cfg(has_i128)]
+impl_from_primitive!(u128,  to_u128);
 impl_from_primitive!(f32,   to_f32);
 impl_from_primitive!(f64,   to_f64);
 
 
-impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
-    fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
-    fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
+macro_rules! impl_to_primitive_wrapping {
+    ($( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(&self) -> Option<$i> {
+            (self.0).$method()
+        }
+    )*}
 }
+
+impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
+    impl_to_primitive_wrapping! {
+        fn to_isize -> isize;
+        fn to_i8 -> i8;
+        fn to_i16 -> i16;
+        fn to_i32 -> i32;
+        fn to_i64 -> i64;
+        #[cfg(has_i128)]
+        fn to_i128 -> i128;
+
+        fn to_usize -> usize;
+        fn to_u8 -> u8;
+        fn to_u16 -> u16;
+        fn to_u32 -> u32;
+        fn to_u64 -> u64;
+        #[cfg(has_i128)]
+        fn to_u128 -> u128;
+
+        fn to_f32 -> f32;
+        fn to_f64 -> f64;
+    }
+}
+
+macro_rules! impl_from_primitive_wrapping {
+    ($( $(#[$cfg:meta])* fn $method:ident ( $i:ident ); )*) => {$(
+        #[inline]
+        $(#[$cfg])*
+        fn $method(n: $i) -> Option<Self> {
+            T::$method(n).map(Wrapping)
+        }
+    )*}
+}
+
 impl<T: FromPrimitive> FromPrimitive for Wrapping<T> {
-    fn from_u64(n: u64) -> Option<Self> { T::from_u64(n).map(Wrapping) }
-    fn from_i64(n: i64) -> Option<Self> { T::from_i64(n).map(Wrapping) }
+    impl_from_primitive_wrapping! {
+        fn from_isize(isize);
+        fn from_i8(i8);
+        fn from_i16(i16);
+        fn from_i32(i32);
+        fn from_i64(i64);
+        #[cfg(has_i128)]
+        fn from_i128(i128);
+
+        fn from_usize(usize);
+        fn from_u8(u8);
+        fn from_u16(u16);
+        fn from_u32(u32);
+        fn from_u64(u64);
+        #[cfg(has_i128)]
+        fn from_u128(u128);
+
+        fn from_f32(f32);
+        fn from_f64(f64);
+    }
 }
 
 
@@ -437,11 +613,15 @@
 impl_num_cast!(u16,   to_u16);
 impl_num_cast!(u32,   to_u32);
 impl_num_cast!(u64,   to_u64);
+#[cfg(has_i128)]
+impl_num_cast!(u128,  to_u128);
 impl_num_cast!(usize, to_usize);
 impl_num_cast!(i8,    to_i8);
 impl_num_cast!(i16,   to_i16);
 impl_num_cast!(i32,   to_i32);
 impl_num_cast!(i64,   to_i64);
+#[cfg(has_i128)]
+impl_num_cast!(i128,  to_i128);
 impl_num_cast!(isize, to_isize);
 impl_num_cast!(f32,   to_f32);
 impl_num_cast!(f64,   to_f64);
@@ -452,60 +632,84 @@
     }
 }
 
-#[test]
-fn to_primitive_float() {
-    use std::f32;
-    use std::f64;
-
-    let f32_toolarge = 1e39f64;
-    assert_eq!(f32_toolarge.to_f32(), None);
-    assert_eq!((f32::MAX as f64).to_f32(), Some(f32::MAX));
-    assert_eq!((-f32::MAX as f64).to_f32(), Some(-f32::MAX));
-    assert_eq!(f64::INFINITY.to_f32(), Some(f32::INFINITY));
-    assert_eq!((f64::NEG_INFINITY).to_f32(), Some(f32::NEG_INFINITY));
-    assert!((f64::NAN).to_f32().map_or(false, |f| f.is_nan()));
+/// A generic interface for casting between machine scalars with the
+/// `as` operator, which admits narrowing and precision loss.
+/// Implementers of this trait AsPrimitive should behave like a primitive
+/// numeric type (e.g. a newtype around another primitive), and the
+/// intended conversion must never fail.
+///
+/// # Examples
+///
+/// ```
+/// # use num_traits::AsPrimitive;
+/// let three: i32 = (3.14159265f32).as_();
+/// assert_eq!(three, 3);
+/// ```
+/// 
+/// # Safety
+/// 
+/// Currently, some uses of the `as` operator are not entirely safe.
+/// In particular, it is undefined behavior if:
+/// 
+/// - A truncated floating point value cannot fit in the target integer
+///   type ([#10184](https://github.com/rust-lang/rust/issues/10184));
+/// 
+/// ```ignore
+/// # use num_traits::AsPrimitive;
+/// let x: u8 = (1.04E+17).as_(); // UB
+/// ```
+/// 
+/// - Or a floating point value does not fit in another floating
+///   point type ([#15536](https://github.com/rust-lang/rust/issues/15536)).
+///
+/// ```ignore
+/// # use num_traits::AsPrimitive;
+/// let x: f32 = (1e300f64).as_(); // UB
+/// ```
+/// 
+pub trait AsPrimitive<T>: 'static + Copy
+where
+    T: 'static + Copy
+{
+    /// Convert a value to another, using the `as` operator.
+    fn as_(self) -> T;
 }
 
-#[test]
-fn wrapping_to_primitive() {
-    macro_rules! test_wrapping_to_primitive {
-        ($($t:ty)+) => {
-            $({
-                let i: $t = 0;
-                let w = Wrapping(i);
-                assert_eq!(i.to_u8(),    w.to_u8());
-                assert_eq!(i.to_u16(),   w.to_u16());
-                assert_eq!(i.to_u32(),   w.to_u32());
-                assert_eq!(i.to_u64(),   w.to_u64());
-                assert_eq!(i.to_usize(), w.to_usize());
-                assert_eq!(i.to_i8(),    w.to_i8());
-                assert_eq!(i.to_i16(),   w.to_i16());
-                assert_eq!(i.to_i32(),   w.to_i32());
-                assert_eq!(i.to_i64(),   w.to_i64());
-                assert_eq!(i.to_isize(), w.to_isize());
-                assert_eq!(i.to_f32(),   w.to_f32());
-                assert_eq!(i.to_f64(),   w.to_f64());
-            })+
-        };
-    }
-
-    test_wrapping_to_primitive!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
+macro_rules! impl_as_primitive {
+    (@ $T: ty => $(#[$cfg:meta])* impl $U: ty ) => {
+        $(#[$cfg])*
+        impl AsPrimitive<$U> for $T {
+            #[inline] fn as_(self) -> $U { self as $U }
+        }
+    };
+    (@ $T: ty => { $( $U: ty ),* } ) => {$(
+        impl_as_primitive!(@ $T => impl $U);
+    )*};
+    ($T: ty => { $( $U: ty ),* } ) => {
+        impl_as_primitive!(@ $T => { $( $U ),* });
+        impl_as_primitive!(@ $T => { u8, u16, u32, u64, usize });
+        impl_as_primitive!(@ $T => #[cfg(has_i128)] impl u128);
+        impl_as_primitive!(@ $T => { i8, i16, i32, i64, isize });
+        impl_as_primitive!(@ $T => #[cfg(has_i128)] impl i128);
+    };
 }
 
-#[test]
-fn wrapping_is_toprimitive() {
-    fn require_toprimitive<T: ToPrimitive>(_: &T) {}
-    require_toprimitive(&Wrapping(42));
-}
+impl_as_primitive!(u8 => { char, f32, f64 });
+impl_as_primitive!(i8 => { f32, f64 });
+impl_as_primitive!(u16 => { f32, f64 });
+impl_as_primitive!(i16 => { f32, f64 });
+impl_as_primitive!(u32 => { f32, f64 });
+impl_as_primitive!(i32 => { f32, f64 });
+impl_as_primitive!(u64 => { f32, f64 });
+impl_as_primitive!(i64 => { f32, f64 });
+#[cfg(has_i128)]
+impl_as_primitive!(u128 => { f32, f64 });
+#[cfg(has_i128)]
+impl_as_primitive!(i128 => { f32, f64 });
+impl_as_primitive!(usize => { f32, f64 });
+impl_as_primitive!(isize => { f32, f64 });
+impl_as_primitive!(f32 => { f32, f64 });
+impl_as_primitive!(f64 => { f32, f64 });
+impl_as_primitive!(char => { char });
+impl_as_primitive!(bool => {});
 
-#[test]
-fn wrapping_is_fromprimitive() {
-    fn require_fromprimitive<T: FromPrimitive>(_: &T) {}
-    require_fromprimitive(&Wrapping(42));
-}
-
-#[test]
-fn wrapping_is_numcast() {
-    fn require_numcast<T: NumCast>(_: &T) {}
-    require_numcast(&Wrapping(42));
-}
diff --git a/third_party/num/traits/src/float.rs b/third_party/num/traits/src/float.rs
index 3c8779a..c05a7ad 100644
--- a/third_party/num/traits/src/float.rs
+++ b/third_party/num/traits/src/float.rs
@@ -1,15 +1,828 @@
-use std::mem;
-use std::ops::Neg;
-use std::num::FpCategory;
+use core::mem;
+use core::ops::Neg;
+use core::num::FpCategory;
 
-// Used for default implementation of `epsilon`
-use std::f32;
+use core::f32;
+use core::f64;
 
-use {Num, NumCast};
+use {Num, NumCast, ToPrimitive};
+
+/// Generic trait for floating point numbers that works with `no_std`.
+///
+/// This trait implements a subset of the `Float` trait.
+pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
+    /// Returns positive infinity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T) {
+    ///     assert!(T::infinity() == x);
+    /// }
+    ///
+    /// check(f32::INFINITY);
+    /// check(f64::INFINITY);
+    /// ```
+    fn infinity() -> Self;
+
+    /// Returns negative infinity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T) {
+    ///     assert!(T::neg_infinity() == x);
+    /// }
+    ///
+    /// check(f32::NEG_INFINITY);
+    /// check(f64::NEG_INFINITY);
+    /// ```
+    fn neg_infinity() -> Self;
+
+    /// Returns NaN.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    ///
+    /// fn check<T: FloatCore>() {
+    ///     let n = T::nan();
+    ///     assert!(n != n);
+    /// }
+    ///
+    /// check::<f32>();
+    /// check::<f64>();
+    /// ```
+    fn nan() -> Self;
+
+    /// Returns `-0.0`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(n: T) {
+    ///     let z = T::neg_zero();
+    ///     assert!(z.is_zero());
+    ///     assert!(T::one() / z == n);
+    /// }
+    ///
+    /// check(f32::NEG_INFINITY);
+    /// check(f64::NEG_INFINITY);
+    /// ```
+    fn neg_zero() -> Self;
+
+    /// Returns the smallest finite value that this type can represent.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T) {
+    ///     assert!(T::min_value() == x);
+    /// }
+    ///
+    /// check(f32::MIN);
+    /// check(f64::MIN);
+    /// ```
+    fn min_value() -> Self;
+
+    /// Returns the smallest positive, normalized value that this type can represent.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T) {
+    ///     assert!(T::min_positive_value() == x);
+    /// }
+    ///
+    /// check(f32::MIN_POSITIVE);
+    /// check(f64::MIN_POSITIVE);
+    /// ```
+    fn min_positive_value() -> Self;
+
+    /// Returns epsilon, a small positive value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T) {
+    ///     assert!(T::epsilon() == x);
+    /// }
+    ///
+    /// check(f32::EPSILON);
+    /// check(f64::EPSILON);
+    /// ```
+    fn epsilon() -> Self;
+
+    /// Returns the largest finite value that this type can represent.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T) {
+    ///     assert!(T::max_value() == x);
+    /// }
+    ///
+    /// check(f32::MAX);
+    /// check(f64::MAX);
+    /// ```
+    fn max_value() -> Self;
+
+    /// Returns `true` if the number is NaN.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, p: bool) {
+    ///     assert!(x.is_nan() == p);
+    /// }
+    ///
+    /// check(f32::NAN, true);
+    /// check(f32::INFINITY, false);
+    /// check(f64::NAN, true);
+    /// check(0.0f64, false);
+    /// ```
+    #[inline]
+    fn is_nan(self) -> bool {
+        self != self
+    }
+
+    /// Returns `true` if the number is infinite.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, p: bool) {
+    ///     assert!(x.is_infinite() == p);
+    /// }
+    ///
+    /// check(f32::INFINITY, true);
+    /// check(f32::NEG_INFINITY, true);
+    /// check(f32::NAN, false);
+    /// check(f64::INFINITY, true);
+    /// check(f64::NEG_INFINITY, true);
+    /// check(0.0f64, false);
+    /// ```
+    #[inline]
+    fn is_infinite(self) -> bool {
+        self == Self::infinity() || self == Self::neg_infinity()
+    }
+
+    /// Returns `true` if the number is neither infinite or NaN.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, p: bool) {
+    ///     assert!(x.is_finite() == p);
+    /// }
+    ///
+    /// check(f32::INFINITY, false);
+    /// check(f32::MAX, true);
+    /// check(f64::NEG_INFINITY, false);
+    /// check(f64::MIN_POSITIVE, true);
+    /// check(f64::NAN, false);
+    /// ```
+    #[inline]
+    fn is_finite(self) -> bool {
+        !(self.is_nan() || self.is_infinite())
+    }
+
+    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, p: bool) {
+    ///     assert!(x.is_normal() == p);
+    /// }
+    ///
+    /// check(f32::INFINITY, false);
+    /// check(f32::MAX, true);
+    /// check(f64::NEG_INFINITY, false);
+    /// check(f64::MIN_POSITIVE, true);
+    /// check(0.0f64, false);
+    /// ```
+    #[inline]
+    fn is_normal(self) -> bool {
+        self.classify() == FpCategory::Normal
+    }
+
+    /// Returns the floating point category of the number. If only one property
+    /// is going to be tested, it is generally faster to use the specific
+    /// predicate instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    /// use std::num::FpCategory;
+    ///
+    /// fn check<T: FloatCore>(x: T, c: FpCategory) {
+    ///     assert!(x.classify() == c);
+    /// }
+    ///
+    /// check(f32::INFINITY, FpCategory::Infinite);
+    /// check(f32::MAX, FpCategory::Normal);
+    /// check(f64::NAN, FpCategory::Nan);
+    /// check(f64::MIN_POSITIVE, FpCategory::Normal);
+    /// check(f64::MIN_POSITIVE / 2.0, FpCategory::Subnormal);
+    /// check(0.0f64, FpCategory::Zero);
+    /// ```
+    fn classify(self) -> FpCategory;
+
+    /// Returns the largest integer less than or equal to a number.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.floor() == y);
+    /// }
+    ///
+    /// check(f32::INFINITY, f32::INFINITY);
+    /// check(0.9f32, 0.0);
+    /// check(1.0f32, 1.0);
+    /// check(1.1f32, 1.0);
+    /// check(-0.0f64, 0.0);
+    /// check(-0.9f64, -1.0);
+    /// check(-1.0f64, -1.0);
+    /// check(-1.1f64, -2.0);
+    /// check(f64::MIN, f64::MIN);
+    /// ```
+    #[inline]
+    fn floor(self) -> Self {
+        let f = self.fract();
+        if f.is_nan() || f.is_zero() {
+            self
+        } else if self < Self::zero() {
+            self - f - Self::one()
+        } else {
+            self - f
+        }
+    }
+
+    /// Returns the smallest integer greater than or equal to a number.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.ceil() == y);
+    /// }
+    ///
+    /// check(f32::INFINITY, f32::INFINITY);
+    /// check(0.9f32, 1.0);
+    /// check(1.0f32, 1.0);
+    /// check(1.1f32, 2.0);
+    /// check(-0.0f64, 0.0);
+    /// check(-0.9f64, -0.0);
+    /// check(-1.0f64, -1.0);
+    /// check(-1.1f64, -1.0);
+    /// check(f64::MIN, f64::MIN);
+    /// ```
+    #[inline]
+    fn ceil(self) -> Self {
+        let f = self.fract();
+        if f.is_nan() || f.is_zero() {
+            self
+        } else if self > Self::zero() {
+            self - f + Self::one()
+        } else {
+            self - f
+        }
+    }
+
+    /// Returns the nearest integer to a number. Round half-way cases away from `0.0`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.round() == y);
+    /// }
+    ///
+    /// check(f32::INFINITY, f32::INFINITY);
+    /// check(0.4f32, 0.0);
+    /// check(0.5f32, 1.0);
+    /// check(0.6f32, 1.0);
+    /// check(-0.4f64, 0.0);
+    /// check(-0.5f64, -1.0);
+    /// check(-0.6f64, -1.0);
+    /// check(f64::MIN, f64::MIN);
+    /// ```
+    #[inline]
+    fn round(self) -> Self {
+        let one = Self::one();
+        let h = Self::from(0.5).expect("Unable to cast from 0.5");
+        let f = self.fract();
+        if f.is_nan() || f.is_zero() {
+            self
+        } else if self > Self::zero() {
+            if f < h {
+                self - f
+            } else {
+                self - f + one
+            }
+        } else {
+            if -f < h {
+                self - f
+            } else {
+                self - f - one
+            }
+        }
+    }
+
+    /// Return the integer part of a number.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.trunc() == y);
+    /// }
+    ///
+    /// check(f32::INFINITY, f32::INFINITY);
+    /// check(0.9f32, 0.0);
+    /// check(1.0f32, 1.0);
+    /// check(1.1f32, 1.0);
+    /// check(-0.0f64, 0.0);
+    /// check(-0.9f64, -0.0);
+    /// check(-1.0f64, -1.0);
+    /// check(-1.1f64, -1.0);
+    /// check(f64::MIN, f64::MIN);
+    /// ```
+    #[inline]
+    fn trunc(self) -> Self {
+        let f = self.fract();
+        if f.is_nan() {
+            self
+        } else {
+            self - f
+        }
+    }
+
+    /// Returns the fractional part of a number.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.fract() == y);
+    /// }
+    ///
+    /// check(f32::MAX, 0.0);
+    /// check(0.75f32, 0.75);
+    /// check(1.0f32, 0.0);
+    /// check(1.25f32, 0.25);
+    /// check(-0.0f64, 0.0);
+    /// check(-0.75f64, -0.75);
+    /// check(-1.0f64, 0.0);
+    /// check(-1.25f64, -0.25);
+    /// check(f64::MIN, 0.0);
+    /// ```
+    #[inline]
+    fn fract(self) -> Self {
+        if self.is_zero() {
+            Self::zero()
+        } else {
+            self % Self::one()
+        }
+    }
+
+    /// Computes the absolute value of `self`. Returns `FloatCore::nan()` if the
+    /// number is `FloatCore::nan()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.abs() == y);
+    /// }
+    ///
+    /// check(f32::INFINITY, f32::INFINITY);
+    /// check(1.0f32, 1.0);
+    /// check(0.0f64, 0.0);
+    /// check(-0.0f64, 0.0);
+    /// check(-1.0f64, 1.0);
+    /// check(f64::MIN, f64::MAX);
+    /// ```
+    #[inline]
+    fn abs(self) -> Self {
+        if self.is_sign_positive() {
+            return self;
+        }
+        if self.is_sign_negative() {
+            return -self;
+        }
+        Self::nan()
+    }
+
+    /// Returns a number that represents the sign of `self`.
+    ///
+    /// - `1.0` if the number is positive, `+0.0` or `FloatCore::infinity()`
+    /// - `-1.0` if the number is negative, `-0.0` or `FloatCore::neg_infinity()`
+    /// - `FloatCore::nan()` if the number is `FloatCore::nan()`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.signum() == y);
+    /// }
+    ///
+    /// check(f32::INFINITY, 1.0);
+    /// check(3.0f32, 1.0);
+    /// check(0.0f32, 1.0);
+    /// check(-0.0f64, -1.0);
+    /// check(-3.0f64, -1.0);
+    /// check(f64::MIN, -1.0);
+    /// ```
+    #[inline]
+    fn signum(self) -> Self {
+        if self.is_nan() {
+            Self::nan()
+        } else if self.is_sign_negative() {
+            -Self::one()
+        } else {
+            Self::one()
+        }
+    }
+
+    /// Returns `true` if `self` is positive, including `+0.0` and
+    /// `FloatCore::infinity()`, and since Rust 1.20 also
+    /// `FloatCore::nan()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, p: bool) {
+    ///     assert!(x.is_sign_positive() == p);
+    /// }
+    ///
+    /// check(f32::INFINITY, true);
+    /// check(f32::MAX, true);
+    /// check(0.0f32, true);
+    /// check(-0.0f64, false);
+    /// check(f64::NEG_INFINITY, false);
+    /// check(f64::MIN_POSITIVE, true);
+    /// check(-f64::NAN, false);
+    /// ```
+    #[inline]
+    fn is_sign_positive(self) -> bool {
+        !self.is_sign_negative()
+    }
+
+    /// Returns `true` if `self` is negative, including `-0.0` and
+    /// `FloatCore::neg_infinity()`, and since Rust 1.20 also
+    /// `-FloatCore::nan()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, p: bool) {
+    ///     assert!(x.is_sign_negative() == p);
+    /// }
+    ///
+    /// check(f32::INFINITY, false);
+    /// check(f32::MAX, false);
+    /// check(0.0f32, false);
+    /// check(-0.0f64, true);
+    /// check(f64::NEG_INFINITY, true);
+    /// check(f64::MIN_POSITIVE, false);
+    /// check(f64::NAN, false);
+    /// ```
+    #[inline]
+    fn is_sign_negative(self) -> bool {
+        let (_, _, sign) = self.integer_decode();
+        sign < 0
+    }
+
+    /// Returns the minimum of the two numbers.
+    ///
+    /// If one of the arguments is NaN, then the other argument is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T, min: T) {
+    ///     assert!(x.min(y) == min);
+    /// }
+    ///
+    /// check(1.0f32, 2.0, 1.0);
+    /// check(f32::NAN, 2.0, 2.0);
+    /// check(1.0f64, -2.0, -2.0);
+    /// check(1.0f64, f64::NAN, 1.0);
+    /// ```
+    #[inline]
+    fn min(self, other: Self) -> Self {
+        if self.is_nan() {
+            return other;
+        }
+        if other.is_nan() {
+            return self;
+        }
+        if self < other { self } else { other }
+    }
+
+    /// Returns the maximum of the two numbers.
+    ///
+    /// If one of the arguments is NaN, then the other argument is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T, min: T) {
+    ///     assert!(x.max(y) == min);
+    /// }
+    ///
+    /// check(1.0f32, 2.0, 2.0);
+    /// check(1.0f32, f32::NAN, 1.0);
+    /// check(-1.0f64, 2.0, 2.0);
+    /// check(-1.0f64, f64::NAN, -1.0);
+    /// ```
+    #[inline]
+    fn max(self, other: Self) -> Self {
+        if self.is_nan() {
+            return other;
+        }
+        if other.is_nan() {
+            return self;
+        }
+        if self > other { self } else { other }
+    }
+
+    /// Returns the reciprocal (multiplicative inverse) of the number.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, y: T) {
+    ///     assert!(x.recip() == y);
+    ///     assert!(y.recip() == x);
+    /// }
+    ///
+    /// check(f32::INFINITY, 0.0);
+    /// check(2.0f32, 0.5);
+    /// check(-0.25f64, -4.0);
+    /// check(-0.0f64, f64::NEG_INFINITY);
+    /// ```
+    #[inline]
+    fn recip(self) -> Self {
+        Self::one() / self
+    }
+
+    /// Raise a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    ///
+    /// fn check<T: FloatCore>(x: T, exp: i32, powi: T) {
+    ///     assert!(x.powi(exp) == powi);
+    /// }
+    ///
+    /// check(9.0f32, 2, 81.0);
+    /// check(1.0f32, -2, 1.0);
+    /// check(10.0f64, 20, 1e20);
+    /// check(4.0f64, -2, 0.0625);
+    /// check(-1.0f64, std::i32::MIN, 1.0);
+    /// ```
+    #[inline]
+    fn powi(mut self, mut exp: i32) -> Self {
+        if exp < 0 {
+            exp = exp.wrapping_neg();
+            self = self.recip();
+        }
+        // It should always be possible to convert a positive `i32` to a `usize`.
+        // Note, `i32::MIN` will wrap and still be negative, so we need to convert
+        // to `u32` without sign-extension before growing to `usize`.
+        super::pow(self, (exp as u32).to_usize().unwrap())
+    }
+
+    /// Converts to degrees, assuming the number is in radians.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(rad: T, deg: T) {
+    ///     assert!(rad.to_degrees() == deg);
+    /// }
+    ///
+    /// check(0.0f32, 0.0);
+    /// check(f32::consts::PI, 180.0);
+    /// check(f64::consts::FRAC_PI_4, 45.0);
+    /// check(f64::INFINITY, f64::INFINITY);
+    /// ```
+    fn to_degrees(self) -> Self;
+
+    /// Converts to radians, assuming the number is in degrees.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(deg: T, rad: T) {
+    ///     assert!(deg.to_radians() == rad);
+    /// }
+    ///
+    /// check(0.0f32, 0.0);
+    /// check(180.0, f32::consts::PI);
+    /// check(45.0, f64::consts::FRAC_PI_4);
+    /// check(f64::INFINITY, f64::INFINITY);
+    /// ```
+    fn to_radians(self) -> Self;
+
+    /// Returns the mantissa, base 2 exponent, and sign as integers, respectively.
+    /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::{f32, f64};
+    ///
+    /// fn check<T: FloatCore>(x: T, m: u64, e: i16, s:i8) {
+    ///     let (mantissa, exponent, sign) = x.integer_decode();
+    ///     assert_eq!(mantissa, m);
+    ///     assert_eq!(exponent, e);
+    ///     assert_eq!(sign, s);
+    /// }
+    ///
+    /// check(2.0f32, 1 << 23, -22, 1);
+    /// check(-2.0f32, 1 << 23, -22, -1);
+    /// check(f32::INFINITY, 1 << 23, 105, 1);
+    /// check(f64::NEG_INFINITY, 1 << 52, 972, -1);
+    /// ```
+    fn integer_decode(self) -> (u64, i16, i8);
+}
+
+impl FloatCore for f32 {
+    constant! {
+        infinity() -> f32::INFINITY;
+        neg_infinity() -> f32::NEG_INFINITY;
+        nan() -> f32::NAN;
+        neg_zero() -> -0.0;
+        min_value() -> f32::MIN;
+        min_positive_value() -> f32::MIN_POSITIVE;
+        epsilon() -> f32::EPSILON;
+        max_value() -> f32::MAX;
+    }
+
+    #[inline]
+    fn integer_decode(self) -> (u64, i16, i8) {
+        integer_decode_f322(self)
+    }
+
+    forward! {
+        Self::is_nan(self) -> bool;
+        Self::is_infinite(self) -> bool;
+        Self::is_finite(self) -> bool;
+        Self::is_normal(self) -> bool;
+        Self::classify(self) -> FpCategory;
+        Self::floor(self) -> Self;
+        Self::ceil(self) -> Self;
+        Self::round(self) -> Self;
+        Self::trunc(self) -> Self;
+        Self::fract(self) -> Self;
+        Self::abs(self) -> Self;
+        Self::signum(self) -> Self;
+        Self::is_sign_positive(self) -> bool;
+        Self::is_sign_negative(self) -> bool;
+        Self::min(self, other: Self) -> Self;
+        Self::max(self, other: Self) -> Self;
+        Self::recip(self) -> Self;
+        Self::powi(self, n: i32) -> Self;
+        Self::to_degrees(self) -> Self;
+        Self::to_radians(self) -> Self;
+    }
+}
+
+impl FloatCore for f64 {
+    constant! {
+        infinity() -> f64::INFINITY;
+        neg_infinity() -> f64::NEG_INFINITY;
+        nan() -> f64::NAN;
+        neg_zero() -> -0.0;
+        min_value() -> f64::MIN;
+        min_positive_value() -> f64::MIN_POSITIVE;
+        epsilon() -> f64::EPSILON;
+        max_value() -> f64::MAX;
+    }
+
+    #[inline]
+    fn integer_decode(self) -> (u64, i16, i8) {
+        integer_decode_f64(self)
+    }
+
+    forward! {
+        Self::is_nan(self) -> bool;
+        Self::is_infinite(self) -> bool;
+        Self::is_finite(self) -> bool;
+        Self::is_normal(self) -> bool;
+        Self::classify(self) -> FpCategory;
+        Self::floor(self) -> Self;
+        Self::ceil(self) -> Self;
+        Self::round(self) -> Self;
+        Self::trunc(self) -> Self;
+        Self::fract(self) -> Self;
+        Self::abs(self) -> Self;
+        Self::signum(self) -> Self;
+        Self::is_sign_positive(self) -> bool;
+        Self::is_sign_negative(self) -> bool;
+        Self::min(self, other: Self) -> Self;
+        Self::max(self, other: Self) -> Self;
+        Self::recip(self) -> Self;
+        Self::powi(self, n: i32) -> Self;
+        Self::to_degrees(self) -> Self;
+        Self::to_radians(self) -> Self;
+    }
+}
 
 // FIXME: these doctests aren't actually helpful, because they're using and
 // testing the inherent methods directly, not going through `Float`.
 
+/// Generic trait for floating point numbers
+///
+/// This trait is only available with the `std` feature.
 pub trait Float
     : Num
     + Copy
@@ -324,7 +1137,7 @@
     fn signum(self) -> Self;
 
     /// Returns `true` if `self` is positive, including `+0.0`,
-    /// `Float::infinity()`, and with newer versions of Rust `f64::NAN`.
+    /// `Float::infinity()`, and since Rust 1.20 also `Float::nan()`.
     ///
     /// ```
     /// use num_traits::Float;
@@ -342,7 +1155,7 @@
     fn is_sign_positive(self) -> bool;
 
     /// Returns `true` if `self` is negative, including `-0.0`,
-    /// `Float::neg_infinity()`, and with newer versions of Rust `-f64::NAN`.
+    /// `Float::neg_infinity()`, and since Rust 1.20 also `-Float::nan()`.
     ///
     /// ```
     /// use num_traits::Float;
@@ -360,8 +1173,10 @@
     fn is_sign_negative(self) -> bool;
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` can be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction.
     ///
     /// ```
     /// use num_traits::Float;
@@ -601,7 +1416,7 @@
     /// assert!(abs_difference_x < 1e-10);
     /// assert!(abs_difference_y < 1e-10);
     /// ```
-    fn abs_sub(self, other: Self) -> Self;
+    //fn abs_sub(self, other: Self) -> Self;
 
     /// Take the cubic root of a number.
     ///
@@ -901,7 +1716,6 @@
 
     /// Returns the mantissa, base 2 exponent, and sign as integers, respectively.
     /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`.
-    /// The floating point encoding is documented in the [Reference][floating-point].
     ///
     /// ```
     /// use num_traits::Float;
@@ -919,307 +1733,88 @@
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
-    /// [floating-point]: ../../../../../reference.html#machine-types
     fn integer_decode(self) -> (u64, i16, i8);
 }
 
 macro_rules! float_impl {
     ($T:ident $decode:ident) => (
         impl Float for $T {
-            #[inline]
-            fn nan() -> Self {
-                ::std::$T::NAN
+            constant! {
+                nan() -> $T::NAN;
+                infinity() -> $T::INFINITY;
+                neg_infinity() -> $T::NEG_INFINITY;
+                neg_zero() -> -0.0;
+                min_value() -> $T::MIN;
+                min_positive_value() -> $T::MIN_POSITIVE;
+                epsilon() -> $T::EPSILON;
+                max_value() -> $T::MAX;
             }
 
-            #[inline]
-            fn infinity() -> Self {
-                ::std::$T::INFINITY
-            }
-
-            #[inline]
-            fn neg_infinity() -> Self {
-                ::std::$T::NEG_INFINITY
-            }
-
-            #[inline]
-            fn neg_zero() -> Self {
-                -0.0
-            }
-
-            #[inline]
-            fn min_value() -> Self {
-                ::std::$T::MIN
-            }
-
-            #[inline]
-            fn min_positive_value() -> Self {
-                ::std::$T::MIN_POSITIVE
-            }
-
-            #[inline]
-            fn epsilon() -> Self {
-                ::std::$T::EPSILON
-            }
-
-            #[inline]
-            fn max_value() -> Self {
-                ::std::$T::MAX
-            }
-
-            #[inline]
-            fn is_nan(self) -> bool {
-                <$T>::is_nan(self)
-            }
-
-            #[inline]
-            fn is_infinite(self) -> bool {
-                <$T>::is_infinite(self)
-            }
-
-            #[inline]
-            fn is_finite(self) -> bool {
-                <$T>::is_finite(self)
-            }
-
-            #[inline]
-            fn is_normal(self) -> bool {
-                <$T>::is_normal(self)
-            }
-
-            #[inline]
-            fn classify(self) -> FpCategory {
-                <$T>::classify(self)
-            }
-
-            #[inline]
-            fn floor(self) -> Self {
-                <$T>::floor(self)
-            }
-
-            #[inline]
-            fn ceil(self) -> Self {
-                <$T>::ceil(self)
-            }
-
-            #[inline]
-            fn round(self) -> Self {
-                <$T>::round(self)
-            }
-
-            #[inline]
-            fn trunc(self) -> Self {
-                <$T>::trunc(self)
-            }
-
-            #[inline]
-            fn fract(self) -> Self {
-                <$T>::fract(self)
-            }
-
-            #[inline]
-            fn abs(self) -> Self {
-                <$T>::abs(self)
-            }
-
-            #[inline]
-            fn signum(self) -> Self {
-                <$T>::signum(self)
-            }
-
-            #[inline]
-            fn is_sign_positive(self) -> bool {
-                <$T>::is_sign_positive(self)
-            }
-
-            #[inline]
-            fn is_sign_negative(self) -> bool {
-                <$T>::is_sign_negative(self)
-            }
-
-            #[inline]
-            fn mul_add(self, a: Self, b: Self) -> Self {
-                <$T>::mul_add(self, a, b)
-            }
-
-            #[inline]
-            fn recip(self) -> Self {
-                <$T>::recip(self)
-            }
-
-            #[inline]
-            fn powi(self, n: i32) -> Self {
-                <$T>::powi(self, n)
-            }
-
-            #[inline]
-            fn powf(self, n: Self) -> Self {
-                <$T>::powf(self, n)
-            }
-
-            #[inline]
-            fn sqrt(self) -> Self {
-                <$T>::sqrt(self)
-            }
-
-            #[inline]
-            fn exp(self) -> Self {
-                <$T>::exp(self)
-            }
-
-            #[inline]
-            fn exp2(self) -> Self {
-                <$T>::exp2(self)
-            }
-
-            #[inline]
-            fn ln(self) -> Self {
-                <$T>::ln(self)
-            }
-
-            #[inline]
-            fn log(self, base: Self) -> Self {
-                <$T>::log(self, base)
-            }
-
-            #[inline]
-            fn log2(self) -> Self {
-                <$T>::log2(self)
-            }
-
-            #[inline]
-            fn log10(self) -> Self {
-                <$T>::log10(self)
-            }
-
-            #[inline]
-            fn to_degrees(self) -> Self {
-                // NB: `f32` didn't stabilize this until 1.7
-                // <$T>::to_degrees(self)
-                self * (180. / ::std::$T::consts::PI)
-            }
-
-            #[inline]
-            fn to_radians(self) -> Self {
-                // NB: `f32` didn't stabilize this until 1.7
-                // <$T>::to_radians(self)
-                self * (::std::$T::consts::PI / 180.)
-            }
-
-            #[inline]
-            fn max(self, other: Self) -> Self {
-                <$T>::max(self, other)
-            }
-
-            #[inline]
-            fn min(self, other: Self) -> Self {
-                <$T>::min(self, other)
-            }
-
-            #[inline]
-            #[allow(deprecated)]
-            fn abs_sub(self, other: Self) -> Self {
-                <$T>::abs_sub(self, other)
-            }
-
-            #[inline]
-            fn cbrt(self) -> Self {
-                <$T>::cbrt(self)
-            }
-
-            #[inline]
-            fn hypot(self, other: Self) -> Self {
-                <$T>::hypot(self, other)
-            }
-
-            #[inline]
-            fn sin(self) -> Self {
-                <$T>::sin(self)
-            }
-
-            #[inline]
-            fn cos(self) -> Self {
-                <$T>::cos(self)
-            }
-
-            #[inline]
-            fn tan(self) -> Self {
-                <$T>::tan(self)
-            }
-
-            #[inline]
-            fn asin(self) -> Self {
-                <$T>::asin(self)
-            }
-
-            #[inline]
-            fn acos(self) -> Self {
-                <$T>::acos(self)
-            }
-
-            #[inline]
-            fn atan(self) -> Self {
-                <$T>::atan(self)
-            }
-
-            #[inline]
-            fn atan2(self, other: Self) -> Self {
-                <$T>::atan2(self, other)
-            }
-
-            #[inline]
-            fn sin_cos(self) -> (Self, Self) {
-                <$T>::sin_cos(self)
-            }
-
-            #[inline]
-            fn exp_m1(self) -> Self {
-                <$T>::exp_m1(self)
-            }
-
-            #[inline]
-            fn ln_1p(self) -> Self {
-                <$T>::ln_1p(self)
-            }
-
-            #[inline]
-            fn sinh(self) -> Self {
-                <$T>::sinh(self)
-            }
-
-            #[inline]
-            fn cosh(self) -> Self {
-                <$T>::cosh(self)
-            }
-
-            #[inline]
-            fn tanh(self) -> Self {
-                <$T>::tanh(self)
-            }
-
-            #[inline]
-            fn asinh(self) -> Self {
-                <$T>::asinh(self)
-            }
-
-            #[inline]
-            fn acosh(self) -> Self {
-                <$T>::acosh(self)
-            }
-
-            #[inline]
-            fn atanh(self) -> Self {
-                <$T>::atanh(self)
-            }
+            //#[inline]
+            //#[allow(deprecated)]
+            //fn abs_sub(self, other: Self) -> Self {
+            //    <$T>::abs_sub(self, other)
+            //}
 
             #[inline]
             fn integer_decode(self) -> (u64, i16, i8) {
                 $decode(self)
             }
+
+            forward! {
+                Self::is_nan(self) -> bool;
+                Self::is_infinite(self) -> bool;
+                Self::is_finite(self) -> bool;
+                Self::is_normal(self) -> bool;
+                Self::classify(self) -> FpCategory;
+                Self::floor(self) -> Self;
+                Self::ceil(self) -> Self;
+                Self::round(self) -> Self;
+                Self::trunc(self) -> Self;
+                Self::fract(self) -> Self;
+                Self::abs(self) -> Self;
+                Self::signum(self) -> Self;
+                Self::is_sign_positive(self) -> bool;
+                Self::is_sign_negative(self) -> bool;
+                Self::mul_add(self, a: Self, b: Self) -> Self;
+                Self::recip(self) -> Self;
+                Self::powi(self, n: i32) -> Self;
+                Self::powf(self, n: Self) -> Self;
+                Self::sqrt(self) -> Self;
+                Self::exp(self) -> Self;
+                Self::exp2(self) -> Self;
+                Self::ln(self) -> Self;
+                Self::log(self, base: Self) -> Self;
+                Self::log2(self) -> Self;
+                Self::log10(self) -> Self;
+                Self::to_degrees(self) -> Self;
+                Self::to_radians(self) -> Self;
+                Self::max(self, other: Self) -> Self;
+                Self::min(self, other: Self) -> Self;
+                Self::cbrt(self) -> Self;
+                Self::hypot(self, other: Self) -> Self;
+                Self::sin(self) -> Self;
+                Self::cos(self) -> Self;
+                Self::tan(self) -> Self;
+                Self::asin(self) -> Self;
+                Self::acos(self) -> Self;
+                Self::atan(self) -> Self;
+                Self::atan2(self, other: Self) -> Self;
+                Self::sin_cos(self) -> (Self, Self);
+                Self::exp_m1(self) -> Self;
+                Self::ln_1p(self) -> Self;
+                Self::sinh(self) -> Self;
+                Self::cosh(self) -> Self;
+                Self::tanh(self) -> Self;
+                Self::asinh(self) -> Self;
+                Self::acosh(self) -> Self;
+                Self::atanh(self) -> Self;
+            }
         }
     )
 }
 
-fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
+fn integer_decode_f322(f: f32) -> (u64, i16, i8) {
     let bits: u32 = unsafe { mem::transmute(f) };
     let sign: i8 = if bits >> 31 == 0 {
         1
@@ -1255,7 +1850,7 @@
     (mantissa, exponent, sign)
 }
 
-float_impl!(f32 integer_decode_f32);
+float_impl!(f32 integer_decode_f322);
 float_impl!(f64 integer_decode_f64);
 
 macro_rules! float_const_impl {
@@ -1269,12 +1864,9 @@
     );
     (@float $T:ident, $($constant:ident,)+) => (
         impl FloatConst for $T {
-            $(
-                #[inline]
-                fn $constant() -> Self {
-                    ::std::$T::consts::$constant
-                }
-            )+
+            constant! {
+                $( $constant() -> $T::consts::$constant; )+
+            }
         }
     );
 }
@@ -1313,32 +1905,3 @@
     #[doc = "Return `sqrt(2.0)`."]
     SQRT_2,
 }
-
-#[cfg(test)]
-mod tests {
-    use Float;
-
-    #[test]
-    fn convert_deg_rad() {
-        use std::f64::consts;
-
-        const DEG_RAD_PAIRS: [(f64, f64); 7] = [
-            (0.0, 0.),
-            (22.5, consts::FRAC_PI_8),
-            (30.0, consts::FRAC_PI_6),
-            (45.0, consts::FRAC_PI_4),
-            (60.0, consts::FRAC_PI_3),
-            (90.0, consts::FRAC_PI_2),
-            (180.0, consts::PI),
-        ];
-
-        for &(deg, rad) in &DEG_RAD_PAIRS {
-            assert!((Float::to_degrees(rad) - deg).abs() < 1e-6);
-            assert!((Float::to_radians(deg) - rad).abs() < 1e-6);
-
-            let (deg, rad) = (deg as f32, rad as f32);
-            assert!((Float::to_degrees(rad) - deg).abs() < 1e-6);
-            assert!((Float::to_radians(deg) - rad).abs() < 1e-6);
-        }
-    }
-}
diff --git a/third_party/num/traits/src/identities.rs b/third_party/num/traits/src/identities.rs
index 79882ed..8ef9ff1 100644
--- a/third_party/num/traits/src/identities.rs
+++ b/third_party/num/traits/src/identities.rs
@@ -1,5 +1,5 @@
-use std::ops::{Add, Mul};
-use std::num::Wrapping;
+use core::ops::{Add, Mul};
+use core::num::Wrapping;
 
 /// Defines an additive identity element for `Self`.
 pub trait Zero: Sized + Add<Self, Output = Self> {
@@ -17,7 +17,7 @@
     /// This function should return the same result at all times regardless of
     /// external mutable state, for example values stored in TLS or in
     /// `static mut`s.
-    // FIXME (#5527): This should be an associated constant
+    // This cannot be an associated constant, because of bignums.
     fn zero() -> Self;
 
     /// Returns `true` if `self` is equal to the additive identity.
@@ -36,20 +36,24 @@
     }
 }
 
-zero_impl!(usize, 0usize);
-zero_impl!(u8,    0u8);
-zero_impl!(u16,   0u16);
-zero_impl!(u32,   0u32);
-zero_impl!(u64,   0u64);
+zero_impl!(usize, 0);
+zero_impl!(u8,    0);
+zero_impl!(u16,   0);
+zero_impl!(u32,   0);
+zero_impl!(u64,   0);
+#[cfg(has_i128)]
+zero_impl!(u128,  0);
 
-zero_impl!(isize, 0isize);
-zero_impl!(i8,    0i8);
-zero_impl!(i16,   0i16);
-zero_impl!(i32,   0i32);
-zero_impl!(i64,   0i64);
+zero_impl!(isize, 0);
+zero_impl!(i8,    0);
+zero_impl!(i16,   0);
+zero_impl!(i32,   0);
+zero_impl!(i64,   0);
+#[cfg(has_i128)]
+zero_impl!(i128,  0);
 
-zero_impl!(f32, 0.0f32);
-zero_impl!(f64, 0.0f64);
+zero_impl!(f32, 0.0);
+zero_impl!(f64, 0.0);
 
 impl<T: Zero> Zero for Wrapping<T> where Wrapping<T>: Add<Output=Wrapping<T>> {
     fn is_zero(&self) -> bool {
@@ -77,8 +81,18 @@
     /// This function should return the same result at all times regardless of
     /// external mutable state, for example values stored in TLS or in
     /// `static mut`s.
-    // FIXME (#5527): This should be an associated constant
+    // This cannot be an associated constant, because of bignums.
     fn one() -> Self;
+
+    /// Returns `true` if `self` is equal to the multiplicative identity.
+    ///
+    /// For performance reasons, it's best to implement this manually.
+    /// After a semver bump, this method will be required, and the
+    /// `where Self: PartialEq` bound will be removed.
+    #[inline]
+    fn is_one(&self) -> bool where Self: PartialEq {
+        *self == Self::one()
+    }
 }
 
 macro_rules! one_impl {
@@ -90,20 +104,24 @@
     }
 }
 
-one_impl!(usize, 1usize);
-one_impl!(u8,    1u8);
-one_impl!(u16,   1u16);
-one_impl!(u32,   1u32);
-one_impl!(u64,   1u64);
+one_impl!(usize, 1);
+one_impl!(u8,    1);
+one_impl!(u16,   1);
+one_impl!(u32,   1);
+one_impl!(u64,   1);
+#[cfg(has_i128)]
+one_impl!(u128,   1);
 
-one_impl!(isize, 1isize);
-one_impl!(i8,    1i8);
-one_impl!(i16,   1i16);
-one_impl!(i32,   1i32);
-one_impl!(i64,   1i64);
+one_impl!(isize, 1);
+one_impl!(i8,    1);
+one_impl!(i16,   1);
+one_impl!(i32,   1);
+one_impl!(i64,   1);
+#[cfg(has_i128)]
+one_impl!(i128,   1);
 
-one_impl!(f32, 1.0f32);
-one_impl!(f64, 1.0f64);
+one_impl!(f32, 1.0);
+one_impl!(f64, 1.0);
 
 impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
     fn one() -> Self {
diff --git a/third_party/num/traits/src/int.rs b/third_party/num/traits/src/int.rs
index 4f9221f..1e8275f 100644
--- a/third_party/num/traits/src/int.rs
+++ b/third_party/num/traits/src/int.rs
@@ -1,4 +1,4 @@
-use std::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
+use core::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
 
 use {Num, NumCast};
 use bounds::Bounded;
@@ -368,9 +368,13 @@
 prim_int_impl!(u16,   i16,   u16);
 prim_int_impl!(u32,   i32,   u32);
 prim_int_impl!(u64,   i64,   u64);
+#[cfg(has_i128)]
+prim_int_impl!(u128,  i128,  u128);
 prim_int_impl!(usize, isize, usize);
 prim_int_impl!(i8,    i8,    u8);
 prim_int_impl!(i16,   i16,   u16);
 prim_int_impl!(i32,   i32,   u32);
 prim_int_impl!(i64,   i64,   u64);
+#[cfg(has_i128)]
+prim_int_impl!(i128,  i128,  u128);
 prim_int_impl!(isize, isize, usize);
diff --git a/third_party/num/traits/src/lib.rs b/third_party/num/traits/src/lib.rs
index 3751d42..26792da 100644
--- a/third_party/num/traits/src/lib.rs
+++ b/third_party/num/traits/src/lib.rs
@@ -9,37 +9,56 @@
 // except according to those terms.
 
 //! Numeric traits for generic mathematics
-#![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
-       html_favicon_url = "https://rust-num.github.io/num/favicon.ico",
-       html_root_url = "https://rust-num.github.io/num/",
-       html_playground_url = "http://play.integer32.com/")]
+//!
+//! ## Compatibility
+//!
+//! The `num-traits` crate is tested for rustc 1.8 and greater.
+
+#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
+
+#![allow(unconditional_recursion)]
 
 #![cfg_attr(not(target_env = "sgx"), no_std)]
 #![cfg_attr(target_env = "sgx", feature(rustc_private))]
 
+#[cfg(all(target_env = "sgx", feature = "std"))]
+extern crate core;
+
 #[cfg(not(target_env = "sgx"))]
 extern crate sgx_tstd as std;
 
-use std::ops::{Add, Sub, Mul, Div, Rem};
-use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
-use std::num::Wrapping;
+use core::ops::{Add, Sub, Mul, Div, Rem};
+use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
+use core::num::Wrapping;
+use core::fmt;
 
 pub use bounds::Bounded;
-pub use float::{Float, FloatConst};
+//#[cfg(feature = "std")]
+pub use float::Float;
+pub use float::FloatConst;
+// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
 pub use identities::{Zero, One, zero, one};
-pub use ops::checked::*;
-pub use ops::wrapping::*;
+pub use ops::inv::Inv;
+pub use ops::checked::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
+                       CheckedRem, CheckedNeg, CheckedShl, CheckedShr};
+pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub};
+pub use ops::mul_add::{MulAdd, MulAddAssign};
 pub use ops::saturating::Saturating;
 pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
-pub use cast::*;
+pub use cast::{AsPrimitive, FromPrimitive, ToPrimitive, NumCast, cast};
 pub use int::PrimInt;
-pub use pow::{pow, checked_pow};
+pub use pow::{Pow, pow, checked_pow};
+
+#[macro_use]
+mod macros;
 
 pub mod identities;
 pub mod sign;
 pub mod ops;
 pub mod bounds;
 pub mod float;
+//#[cfg(feature = "std")]
+pub mod real;
 pub mod cast;
 pub mod int;
 pub mod pow;
@@ -135,10 +154,10 @@
 macro_rules! int_trait_impl {
     ($name:ident for $($t:ty)*) => ($(
         impl $name for $t {
-            type FromStrRadixErr = ::std::num::ParseIntError;
+            type FromStrRadixErr = ::core::num::ParseIntError;
             #[inline]
             fn from_str_radix(s: &str, radix: u32)
-                              -> Result<Self, ::std::num::ParseIntError>
+                              -> Result<Self, ::core::num::ParseIntError>
             {
                 <$t>::from_str_radix(s, radix)
             }
@@ -146,6 +165,8 @@
     )*)
 }
 int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
+#[cfg(has_i128)]
+int_trait_impl!(Num for u128 i128);
 
 impl<T: Num> Num for Wrapping<T>
     where Wrapping<T>:
@@ -164,18 +185,29 @@
     Empty,
     Invalid,
 }
-// FIXME: std::num::ParseFloatError is stable in 1.0, but opaque to us,
+// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us,
 // so there's not really any way for us to reuse it.
 #[derive(Debug)]
 pub struct ParseFloatError {
     pub kind: FloatErrorKind,
 }
 
+impl fmt::Display for ParseFloatError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let description = match self.kind {
+            FloatErrorKind::Empty => "cannot parse float from empty string",
+            FloatErrorKind::Invalid => "invalid float literal",
+        };
+
+        description.fmt(f)
+    }
+}
+
 // FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
 // with this implementation ourselves until we want to make a breaking change.
 // (would have to drop it from `Num` though)
 macro_rules! float_trait_impl {
-    ($name:ident for $($t:ty)*) => ($(
+    ($name:ident for $($t:ident)*) => ($(
         impl $name for $t {
             type FromStrRadixErr = ParseFloatError;
 
@@ -187,9 +219,9 @@
 
                 // Special values
                 match src {
-                    "inf"   => return Ok(Float::infinity()),
-                    "-inf"  => return Ok(Float::neg_infinity()),
-                    "NaN"   => return Ok(Float::nan()),
+                    "inf"   => return Ok(core::$t::INFINITY),
+                    "-inf"  => return Ok(core::$t::NEG_INFINITY),
+                    "NaN"   => return Ok(core::$t::NAN),
                     _       => {},
                 }
 
@@ -230,15 +262,15 @@
                             // if we've not seen any non-zero digits.
                             if prev_sig != 0.0 {
                                 if is_positive && sig <= prev_sig
-                                    { return Ok(Float::infinity()); }
+                                    { return Ok(core::$t::INFINITY); }
                                 if !is_positive && sig >= prev_sig
-                                    { return Ok(Float::neg_infinity()); }
+                                    { return Ok(core::$t::NEG_INFINITY); }
 
                                 // Detect overflow by reversing the shift-and-add process
                                 if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
-                                    { return Ok(Float::infinity()); }
+                                    { return Ok(core::$t::INFINITY); }
                                 if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
-                                    { return Ok(Float::neg_infinity()); }
+                                    { return Ok(core::$t::NEG_INFINITY); }
                             }
                             prev_sig = sig;
                         },
@@ -274,9 +306,9 @@
                                 };
                                 // Detect overflow by comparing to last value
                                 if is_positive && sig < prev_sig
-                                    { return Ok(Float::infinity()); }
+                                    { return Ok(core::$t::INFINITY); }
                                 if !is_positive && sig > prev_sig
-                                    { return Ok(Float::neg_infinity()); }
+                                    { return Ok(core::$t::NEG_INFINITY); }
                                 prev_sig = sig;
                             },
                             None => match c {
@@ -310,9 +342,15 @@
                             None             => return Err(PFE { kind: Invalid }),
                         };
 
+                        //#[cfg(feature = "std")]
+                        fn pow(base: $t, exp: usize) -> $t {
+                            Float::powi(base, exp as i32)
+                        }
+                        // otherwise uses the generic `pow` from the root
+
                         match (is_positive, exp) {
-                            (true,  Ok(exp)) => base.powi(exp as i32),
-                            (false, Ok(exp)) => 1.0 / base.powi(exp as i32),
+                            (true,  Ok(exp)) => pow(base, exp),
+                            (false, Ok(exp)) => 1.0 / pow(base, exp),
                             (_, Err(_))      => return Err(PFE { kind: Invalid }),
                         }
                     },
diff --git a/third_party/num/traits/src/macros.rs b/third_party/num/traits/src/macros.rs
new file mode 100644
index 0000000..4330cdf
--- /dev/null
+++ b/third_party/num/traits/src/macros.rs
@@ -0,0 +1,37 @@
+// not all are used in all features configurations
+#![allow(unused)]
+
+/// Forward a method to an inherent method or a base trait method.
+macro_rules! forward {
+    ($( Self :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
+        => {$(
+            #[inline]
+            fn $method(self $( , $arg : $ty )* ) -> $ret {
+                Self::$method(self $( , $arg )* )
+            }
+        )*};
+    ($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
+        => {$(
+            #[inline]
+            fn $method(self $( , $arg : $ty )* ) -> $ret {
+                <Self as $base>::$method(self $( , $arg )* )
+            }
+        )*};
+    ($( $base:ident :: $method:ident ( $( $arg:ident : $ty:ty ),* ) -> $ret:ty ; )*)
+        => {$(
+            #[inline]
+            fn $method( $( $arg : $ty ),* ) -> $ret {
+                <Self as $base>::$method( $( $arg ),* )
+            }
+        )*}
+}
+
+macro_rules! constant {
+    ($( $method:ident () -> $ret:expr ; )*)
+        => {$(
+            #[inline]
+            fn $method() -> Self {
+                $ret
+            }
+        )*};
+}
diff --git a/third_party/num/traits/src/ops/checked.rs b/third_party/num/traits/src/ops/checked.rs
index 45e6716..1c2b2f5 100644
--- a/third_party/num/traits/src/ops/checked.rs
+++ b/third_party/num/traits/src/ops/checked.rs
@@ -1,4 +1,4 @@
-use std::ops::{Add, Sub, Mul, Div};
+use core::ops::{Add, Sub, Mul, Div, Rem, Shl, Shr};
 
 /// Performs addition that returns `None` instead of wrapping around on
 /// overflow.
@@ -24,12 +24,16 @@
 checked_impl!(CheckedAdd, checked_add, u32);
 checked_impl!(CheckedAdd, checked_add, u64);
 checked_impl!(CheckedAdd, checked_add, usize);
+#[cfg(has_i128)]
+checked_impl!(CheckedAdd, checked_add, u128);
 
 checked_impl!(CheckedAdd, checked_add, i8);
 checked_impl!(CheckedAdd, checked_add, i16);
 checked_impl!(CheckedAdd, checked_add, i32);
 checked_impl!(CheckedAdd, checked_add, i64);
 checked_impl!(CheckedAdd, checked_add, isize);
+#[cfg(has_i128)]
+checked_impl!(CheckedAdd, checked_add, i128);
 
 /// Performs subtraction that returns `None` instead of wrapping around on underflow.
 pub trait CheckedSub: Sized + Sub<Self, Output=Self> {
@@ -43,12 +47,16 @@
 checked_impl!(CheckedSub, checked_sub, u32);
 checked_impl!(CheckedSub, checked_sub, u64);
 checked_impl!(CheckedSub, checked_sub, usize);
+#[cfg(has_i128)]
+checked_impl!(CheckedSub, checked_sub, u128);
 
 checked_impl!(CheckedSub, checked_sub, i8);
 checked_impl!(CheckedSub, checked_sub, i16);
 checked_impl!(CheckedSub, checked_sub, i32);
 checked_impl!(CheckedSub, checked_sub, i64);
 checked_impl!(CheckedSub, checked_sub, isize);
+#[cfg(has_i128)]
+checked_impl!(CheckedSub, checked_sub, i128);
 
 /// Performs multiplication that returns `None` instead of wrapping around on underflow or
 /// overflow.
@@ -63,12 +71,16 @@
 checked_impl!(CheckedMul, checked_mul, u32);
 checked_impl!(CheckedMul, checked_mul, u64);
 checked_impl!(CheckedMul, checked_mul, usize);
+#[cfg(has_i128)]
+checked_impl!(CheckedMul, checked_mul, u128);
 
 checked_impl!(CheckedMul, checked_mul, i8);
 checked_impl!(CheckedMul, checked_mul, i16);
 checked_impl!(CheckedMul, checked_mul, i32);
 checked_impl!(CheckedMul, checked_mul, i64);
 checked_impl!(CheckedMul, checked_mul, isize);
+#[cfg(has_i128)]
+checked_impl!(CheckedMul, checked_mul, i128);
 
 /// Performs division that returns `None` instead of panicking on division by zero and instead of
 /// wrapping around on underflow and overflow.
@@ -83,10 +95,181 @@
 checked_impl!(CheckedDiv, checked_div, u32);
 checked_impl!(CheckedDiv, checked_div, u64);
 checked_impl!(CheckedDiv, checked_div, usize);
+#[cfg(has_i128)]
+checked_impl!(CheckedDiv, checked_div, u128);
 
 checked_impl!(CheckedDiv, checked_div, i8);
 checked_impl!(CheckedDiv, checked_div, i16);
 checked_impl!(CheckedDiv, checked_div, i32);
 checked_impl!(CheckedDiv, checked_div, i64);
 checked_impl!(CheckedDiv, checked_div, isize);
+#[cfg(has_i128)]
+checked_impl!(CheckedDiv, checked_div, i128);
 
+/// Performs an integral remainder that returns `None` instead of panicking on division by zero and
+/// instead of wrapping around on underflow and overflow.
+pub trait CheckedRem: Sized + Rem<Self, Output = Self> {
+    /// Finds the remainder of dividing two numbers, checking for underflow, overflow and division
+    /// by zero. If any of that happens, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::CheckedRem;
+    /// use std::i32::MIN;
+    ///
+    /// assert_eq!(CheckedRem::checked_rem(&10, &7), Some(3));
+    /// assert_eq!(CheckedRem::checked_rem(&10, &-7), Some(3));
+    /// assert_eq!(CheckedRem::checked_rem(&-10, &7), Some(-3));
+    /// assert_eq!(CheckedRem::checked_rem(&-10, &-7), Some(-3));
+    ///
+    /// assert_eq!(CheckedRem::checked_rem(&10, &0), None);
+    ///
+    /// assert_eq!(CheckedRem::checked_rem(&MIN, &1), Some(0));
+    /// assert_eq!(CheckedRem::checked_rem(&MIN, &-1), None);
+    /// ```
+    fn checked_rem(&self, v: &Self) -> Option<Self>;
+}
+
+checked_impl!(CheckedRem, checked_rem, u8);
+checked_impl!(CheckedRem, checked_rem, u16);
+checked_impl!(CheckedRem, checked_rem, u32);
+checked_impl!(CheckedRem, checked_rem, u64);
+checked_impl!(CheckedRem, checked_rem, usize);
+#[cfg(has_i128)]
+checked_impl!(CheckedRem, checked_rem, u128);
+
+checked_impl!(CheckedRem, checked_rem, i8);
+checked_impl!(CheckedRem, checked_rem, i16);
+checked_impl!(CheckedRem, checked_rem, i32);
+checked_impl!(CheckedRem, checked_rem, i64);
+checked_impl!(CheckedRem, checked_rem, isize);
+#[cfg(has_i128)]
+checked_impl!(CheckedRem, checked_rem, i128);
+
+macro_rules! checked_impl_unary {
+    ($trait_name:ident, $method:ident, $t:ty) => {
+        impl $trait_name for $t {
+            #[inline]
+            fn $method(&self) -> Option<$t> {
+                <$t>::$method(*self)
+            }
+        }
+    }
+}
+
+/// Performs negation that returns `None` if the result can't be represented.
+pub trait CheckedNeg: Sized {
+    /// Negates a number, returning `None` for results that can't be represented, like signed `MIN`
+    /// values that can't be positive, or non-zero unsigned values that can't be negative.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::CheckedNeg;
+    /// use std::i32::MIN;
+    ///
+    /// assert_eq!(CheckedNeg::checked_neg(&1_i32), Some(-1));
+    /// assert_eq!(CheckedNeg::checked_neg(&-1_i32), Some(1));
+    /// assert_eq!(CheckedNeg::checked_neg(&MIN), None);
+    ///
+    /// assert_eq!(CheckedNeg::checked_neg(&0_u32), Some(0));
+    /// assert_eq!(CheckedNeg::checked_neg(&1_u32), None);
+    /// ```
+    fn checked_neg(&self) -> Option<Self>;
+}
+
+checked_impl_unary!(CheckedNeg, checked_neg, u8);
+checked_impl_unary!(CheckedNeg, checked_neg, u16);
+checked_impl_unary!(CheckedNeg, checked_neg, u32);
+checked_impl_unary!(CheckedNeg, checked_neg, u64);
+checked_impl_unary!(CheckedNeg, checked_neg, usize);
+#[cfg(has_i128)]
+checked_impl_unary!(CheckedNeg, checked_neg, u128);
+
+checked_impl_unary!(CheckedNeg, checked_neg, i8);
+checked_impl_unary!(CheckedNeg, checked_neg, i16);
+checked_impl_unary!(CheckedNeg, checked_neg, i32);
+checked_impl_unary!(CheckedNeg, checked_neg, i64);
+checked_impl_unary!(CheckedNeg, checked_neg, isize);
+#[cfg(has_i128)]
+checked_impl_unary!(CheckedNeg, checked_neg, i128);
+
+/// Performs a left shift that returns `None` on overflow.
+pub trait CheckedShl: Sized + Shl<u32, Output=Self> {
+    /// Shifts a number to the left, checking for overflow. If overflow happens,
+    /// `None` is returned.
+    ///
+    /// ```
+    /// use num_traits::CheckedShl;
+    ///
+    /// let x: u16 = 0x0001;
+    ///
+    /// assert_eq!(CheckedShl::checked_shl(&x, 0),  Some(0x0001));
+    /// assert_eq!(CheckedShl::checked_shl(&x, 1),  Some(0x0002));
+    /// assert_eq!(CheckedShl::checked_shl(&x, 15), Some(0x8000));
+    /// assert_eq!(CheckedShl::checked_shl(&x, 16), None);
+    /// ```
+    fn checked_shl(&self, rhs: u32) -> Option<Self>;
+}
+
+macro_rules! checked_shift_impl {
+    ($trait_name:ident, $method:ident, $t:ty) => {
+        impl $trait_name for $t {
+            #[inline]
+            fn $method(&self, rhs: u32) -> Option<$t> {
+                <$t>::$method(*self, rhs)
+            }
+        }
+    }
+}
+
+checked_shift_impl!(CheckedShl, checked_shl, u8);
+checked_shift_impl!(CheckedShl, checked_shl, u16);
+checked_shift_impl!(CheckedShl, checked_shl, u32);
+checked_shift_impl!(CheckedShl, checked_shl, u64);
+checked_shift_impl!(CheckedShl, checked_shl, usize);
+#[cfg(has_i128)]
+checked_shift_impl!(CheckedShl, checked_shl, u128);
+
+checked_shift_impl!(CheckedShl, checked_shl, i8);
+checked_shift_impl!(CheckedShl, checked_shl, i16);
+checked_shift_impl!(CheckedShl, checked_shl, i32);
+checked_shift_impl!(CheckedShl, checked_shl, i64);
+checked_shift_impl!(CheckedShl, checked_shl, isize);
+#[cfg(has_i128)]
+checked_shift_impl!(CheckedShl, checked_shl, i128);
+
+/// Performs a right shift that returns `None` on overflow.
+pub trait CheckedShr: Sized + Shr<u32, Output=Self> {
+    /// Shifts a number to the left, checking for overflow. If overflow happens,
+    /// `None` is returned.
+    ///
+    /// ```
+    /// use num_traits::CheckedShr;
+    ///
+    /// let x: u16 = 0x8000;
+    ///
+    /// assert_eq!(CheckedShr::checked_shr(&x, 0),  Some(0x8000));
+    /// assert_eq!(CheckedShr::checked_shr(&x, 1),  Some(0x4000));
+    /// assert_eq!(CheckedShr::checked_shr(&x, 15), Some(0x0001));
+    /// assert_eq!(CheckedShr::checked_shr(&x, 16), None);
+    /// ```
+    fn checked_shr(&self, rhs: u32) -> Option<Self>;
+}
+
+checked_shift_impl!(CheckedShr, checked_shr, u8);
+checked_shift_impl!(CheckedShr, checked_shr, u16);
+checked_shift_impl!(CheckedShr, checked_shr, u32);
+checked_shift_impl!(CheckedShr, checked_shr, u64);
+checked_shift_impl!(CheckedShr, checked_shr, usize);
+#[cfg(has_i128)]
+checked_shift_impl!(CheckedShr, checked_shr, u128);
+
+checked_shift_impl!(CheckedShr, checked_shr, i8);
+checked_shift_impl!(CheckedShr, checked_shr, i16);
+checked_shift_impl!(CheckedShr, checked_shr, i32);
+checked_shift_impl!(CheckedShr, checked_shr, i64);
+checked_shift_impl!(CheckedShr, checked_shr, isize);
+#[cfg(has_i128)]
+checked_shift_impl!(CheckedShr, checked_shr, i128);
diff --git a/third_party/num/traits/src/ops/inv.rs b/third_party/num/traits/src/ops/inv.rs
new file mode 100644
index 0000000..38e89ea
--- /dev/null
+++ b/third_party/num/traits/src/ops/inv.rs
@@ -0,0 +1,39 @@
+/// Unary operator for retrieving the multiplicative inverse, or reciprocal, of a value.
+pub trait Inv {
+    /// The result after applying the operator.
+    type Output;
+
+    /// Returns the multiplicative inverse of `self`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::f64::INFINITY;
+    /// use num_traits::Inv;
+    ///
+    /// assert_eq!(7.0.inv() * 7.0, 1.0);
+    /// assert_eq!((-0.0).inv(), -INFINITY);
+    /// ```
+    fn inv(self) -> Self::Output;
+}
+
+impl Inv for f32 {
+    type Output = f32;
+    #[inline]
+    fn inv(self) -> f32 { 1.0 / self }
+}
+impl Inv for f64 {
+    type Output = f64;
+    #[inline]
+    fn inv(self) -> f64 { 1.0 / self }
+}
+impl<'a> Inv for &'a f32 {
+    type Output = f32;
+    #[inline]
+    fn inv(self) -> f32 { 1.0 / *self }
+}
+impl<'a> Inv for &'a f64 {
+    type Output = f64;
+    #[inline]
+    fn inv(self) -> f64 { 1.0 / *self }
+}
diff --git a/third_party/num/traits/src/ops/mod.rs b/third_party/num/traits/src/ops/mod.rs
index ec9edeb..93b5195 100644
--- a/third_party/num/traits/src/ops/mod.rs
+++ b/third_party/num/traits/src/ops/mod.rs
@@ -1,3 +1,5 @@
 pub mod saturating;
 pub mod checked;
 pub mod wrapping;
+pub mod inv;
+pub mod mul_add;
diff --git a/third_party/num/traits/src/ops/mul_add.rs b/third_party/num/traits/src/ops/mul_add.rs
new file mode 100644
index 0000000..9f0ae1e
--- /dev/null
+++ b/third_party/num/traits/src/ops/mul_add.rs
@@ -0,0 +1,98 @@
+/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+/// error, yielding a more accurate result than an unfused multiply-add.
+///
+/// Using `mul_add` can be more performant than an unfused multiply-add if
+/// the target architecture has a dedicated `fma` CPU instruction.
+///
+/// Note that `A` and `B` are `Self` by default, but this is not mandatory.
+///
+/// # Example
+///
+/// ```
+/// use std::f32;
+///
+/// let m = 10.0_f32;
+/// let x = 4.0_f32;
+/// let b = 60.0_f32;
+///
+/// // 100.0
+/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
+///
+/// assert!(abs_difference <= f32::EPSILON);
+/// ```
+pub trait MulAdd<A = Self, B = Self> {
+    /// The resulting type after applying the fused multiply-add.
+    type Output;
+
+    /// Performs the fused multiply-add operation.
+    fn mul_add(self, a: A, b: B) -> Self::Output;
+}
+
+/// The fused multiply-add assignment operation.
+pub trait MulAddAssign<A = Self, B = Self> {
+    /// Performs the fused multiply-add operation.
+    fn mul_add_assign(&mut self, a: A, b: B);
+}
+
+impl MulAdd<f32, f32> for f32 {
+    type Output = Self;
+
+    #[inline]
+    fn mul_add(self, a: Self, b: Self) -> Self::Output {
+        f32::mul_add(self, a, b)
+    }
+}
+
+impl MulAdd<f64, f64> for f64 {
+    type Output = Self;
+
+    #[inline]
+    fn mul_add(self, a: Self, b: Self) -> Self::Output {
+        f64::mul_add(self, a, b)
+    }
+}
+
+macro_rules! mul_add_impl {
+    ($trait_name:ident for $($t:ty)*) => {$(
+        impl $trait_name for $t {
+            type Output = Self;
+
+            #[inline]
+            fn mul_add(self, a: Self, b: Self) -> Self::Output {
+                (self * a) + b
+            }
+        }
+    )*}
+}
+
+mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
+mul_add_impl!(MulAdd for i128 u128);
+
+impl MulAddAssign<f32, f32> for f32 {
+    #[inline]
+    fn mul_add_assign(&mut self, a: Self, b: Self) {
+        *self = f32::mul_add(*self, a, b)
+    }
+}
+
+impl MulAddAssign<f64, f64> for f64 {
+    #[inline]
+    fn mul_add_assign(&mut self, a: Self, b: Self) {
+        *self = f64::mul_add(*self, a, b)
+    }
+}
+
+macro_rules! mul_add_assign_impl {
+    ($trait_name:ident for $($t:ty)*) => {$(
+        impl $trait_name for $t {
+            #[inline]
+            fn mul_add_assign(&mut self, a: Self, b: Self) {
+                *self = (*self * a) + b
+            }
+        }
+    )*}
+}
+
+mul_add_assign_impl!(MulAddAssign for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
+mul_add_assign_impl!(MulAddAssign for i128 u128);
+
diff --git a/third_party/num/traits/src/ops/saturating.rs b/third_party/num/traits/src/ops/saturating.rs
index e9db749..fdce189 100644
--- a/third_party/num/traits/src/ops/saturating.rs
+++ b/third_party/num/traits/src/ops/saturating.rs
@@ -26,3 +26,5 @@
 }
 
 saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
+#[cfg(has_i128)]
+saturating_impl!(Saturating for i128 u128);
diff --git a/third_party/num/traits/src/ops/wrapping.rs b/third_party/num/traits/src/ops/wrapping.rs
index f989058..b6bd136 100644
--- a/third_party/num/traits/src/ops/wrapping.rs
+++ b/third_party/num/traits/src/ops/wrapping.rs
@@ -1,5 +1,5 @@
-use std::ops::{Add, Sub, Mul};
-use std::num::Wrapping;
+use core::ops::{Add, Sub, Mul};
+use core::num::Wrapping;
 
 macro_rules! wrapping_impl {
     ($trait_name:ident, $method:ident, $t:ty) => {
@@ -32,12 +32,16 @@
 wrapping_impl!(WrappingAdd, wrapping_add, u32);
 wrapping_impl!(WrappingAdd, wrapping_add, u64);
 wrapping_impl!(WrappingAdd, wrapping_add, usize);
+#[cfg(has_i128)]
+wrapping_impl!(WrappingAdd, wrapping_add, u128);
 
 wrapping_impl!(WrappingAdd, wrapping_add, i8);
 wrapping_impl!(WrappingAdd, wrapping_add, i16);
 wrapping_impl!(WrappingAdd, wrapping_add, i32);
 wrapping_impl!(WrappingAdd, wrapping_add, i64);
 wrapping_impl!(WrappingAdd, wrapping_add, isize);
+#[cfg(has_i128)]
+wrapping_impl!(WrappingAdd, wrapping_add, i128);
 
 /// Performs subtraction that wraps around on overflow.
 pub trait WrappingSub: Sized + Sub<Self, Output=Self> {
@@ -51,12 +55,16 @@
 wrapping_impl!(WrappingSub, wrapping_sub, u32);
 wrapping_impl!(WrappingSub, wrapping_sub, u64);
 wrapping_impl!(WrappingSub, wrapping_sub, usize);
+#[cfg(has_i128)]
+wrapping_impl!(WrappingSub, wrapping_sub, u128);
 
 wrapping_impl!(WrappingSub, wrapping_sub, i8);
 wrapping_impl!(WrappingSub, wrapping_sub, i16);
 wrapping_impl!(WrappingSub, wrapping_sub, i32);
 wrapping_impl!(WrappingSub, wrapping_sub, i64);
 wrapping_impl!(WrappingSub, wrapping_sub, isize);
+#[cfg(has_i128)]
+wrapping_impl!(WrappingSub, wrapping_sub, i128);
 
 /// Performs multiplication that wraps around on overflow.
 pub trait WrappingMul: Sized + Mul<Self, Output=Self> {
@@ -70,12 +78,16 @@
 wrapping_impl!(WrappingMul, wrapping_mul, u32);
 wrapping_impl!(WrappingMul, wrapping_mul, u64);
 wrapping_impl!(WrappingMul, wrapping_mul, usize);
+#[cfg(has_i128)]
+wrapping_impl!(WrappingMul, wrapping_mul, u128);
 
 wrapping_impl!(WrappingMul, wrapping_mul, i8);
 wrapping_impl!(WrappingMul, wrapping_mul, i16);
 wrapping_impl!(WrappingMul, wrapping_mul, i32);
 wrapping_impl!(WrappingMul, wrapping_mul, i64);
 wrapping_impl!(WrappingMul, wrapping_mul, isize);
+#[cfg(has_i128)]
+wrapping_impl!(WrappingMul, wrapping_mul, i128);
 
 // Well this is a bit funny, but all the more appropriate.
 impl<T: WrappingAdd> WrappingAdd for Wrapping<T> where Wrapping<T>: Add<Output = Wrapping<T>> {
diff --git a/third_party/num/traits/src/pow.rs b/third_party/num/traits/src/pow.rs
index b250ad4..10f13db 100644
--- a/third_party/num/traits/src/pow.rs
+++ b/third_party/num/traits/src/pow.rs
@@ -1,6 +1,176 @@
-use std::ops::Mul;
+use core::ops::Mul;
+use core::num::Wrapping;
 use {One, CheckedMul};
 
+/// Binary operator for raising a value to a power.
+pub trait Pow<RHS> {
+    /// The result after applying the operator.
+    type Output;
+
+    /// Returns `self` to the power `rhs`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::Pow;
+    /// assert_eq!(Pow::pow(10u32, 2u32), 100);
+    /// ```
+    fn pow(self, rhs: RHS) -> Self::Output;
+}
+
+macro_rules! pow_impl {
+    ($t:ty) => {
+        pow_impl!($t, u8);
+        pow_impl!($t, usize);
+
+        // FIXME: these should be possible
+        // pow_impl!($t, u16);
+        // pow_impl!($t, u32);
+        // pow_impl!($t, u64);
+    };
+    ($t:ty, $rhs:ty) => {
+        pow_impl!($t, $rhs, usize, pow);
+    };
+    ($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => {
+        impl Pow<$rhs> for $t {
+            type Output = $t;
+            #[inline]
+            fn pow(self, rhs: $rhs) -> $t {
+                ($method)(self, <$desired_rhs>::from(rhs))
+            }
+        }
+
+        impl<'a> Pow<&'a $rhs> for $t {
+            type Output = $t;
+            #[inline]
+            fn pow(self, rhs: &'a $rhs) -> $t {
+                ($method)(self, <$desired_rhs>::from(*rhs))
+            }
+        }
+
+        impl<'a> Pow<$rhs> for &'a $t {
+            type Output = $t;
+            #[inline]
+            fn pow(self, rhs: $rhs) -> $t {
+                ($method)(*self, <$desired_rhs>::from(rhs))
+            }
+        }
+
+        impl<'a, 'b> Pow<&'a $rhs> for &'b $t {
+            type Output = $t;
+            #[inline]
+            fn pow(self, rhs: &'a $rhs) -> $t {
+                ($method)(*self, <$desired_rhs>::from(*rhs))
+            }
+        }
+    };
+}
+
+pow_impl!(u8, u8, u32, u8::pow);
+pow_impl!(u8, u16, u32, u8::pow);
+pow_impl!(u8, u32, u32, u8::pow);
+pow_impl!(u8, usize);
+pow_impl!(i8, u8, u32, i8::pow);
+pow_impl!(i8, u16, u32, i8::pow);
+pow_impl!(i8, u32, u32, i8::pow);
+pow_impl!(i8, usize);
+pow_impl!(u16, u8, u32, u16::pow);
+pow_impl!(u16, u16, u32, u16::pow);
+pow_impl!(u16, u32, u32, u16::pow);
+pow_impl!(u16, usize);
+pow_impl!(i16, u8, u32, i16::pow);
+pow_impl!(i16, u16, u32, i16::pow);
+pow_impl!(i16, u32, u32, i16::pow);
+pow_impl!(i16, usize);
+pow_impl!(u32, u8, u32, u32::pow);
+pow_impl!(u32, u16, u32, u32::pow);
+pow_impl!(u32, u32, u32, u32::pow);
+pow_impl!(u32, usize);
+pow_impl!(i32, u8, u32, i32::pow);
+pow_impl!(i32, u16, u32, i32::pow);
+pow_impl!(i32, u32, u32, i32::pow);
+pow_impl!(i32, usize);
+pow_impl!(u64, u8, u32, u64::pow);
+pow_impl!(u64, u16, u32, u64::pow);
+pow_impl!(u64, u32, u32, u64::pow);
+pow_impl!(u64, usize);
+pow_impl!(i64, u8, u32, i64::pow);
+pow_impl!(i64, u16, u32, i64::pow);
+pow_impl!(i64, u32, u32, i64::pow);
+pow_impl!(i64, usize);
+
+#[cfg(has_i128)]
+pow_impl!(u128, u8, u32, u128::pow);
+#[cfg(has_i128)]
+pow_impl!(u128, u16, u32, u128::pow);
+#[cfg(has_i128)]
+pow_impl!(u128, u32, u32, u128::pow);
+#[cfg(has_i128)]
+pow_impl!(u128, usize);
+
+#[cfg(has_i128)]
+pow_impl!(i128, u8, u32, i128::pow);
+#[cfg(has_i128)]
+pow_impl!(i128, u16, u32, i128::pow);
+#[cfg(has_i128)]
+pow_impl!(i128, u32, u32, i128::pow);
+#[cfg(has_i128)]
+pow_impl!(i128, usize);
+
+pow_impl!(usize, u8, u32, usize::pow);
+pow_impl!(usize, u16, u32, usize::pow);
+pow_impl!(usize, u32, u32, usize::pow);
+pow_impl!(usize, usize);
+pow_impl!(isize, u8, u32, isize::pow);
+pow_impl!(isize, u16, u32, isize::pow);
+pow_impl!(isize, u32, u32, isize::pow);
+pow_impl!(isize, usize);
+pow_impl!(Wrapping<u8>);
+pow_impl!(Wrapping<i8>);
+pow_impl!(Wrapping<u16>);
+pow_impl!(Wrapping<i16>);
+pow_impl!(Wrapping<u32>);
+pow_impl!(Wrapping<i32>);
+pow_impl!(Wrapping<u64>);
+pow_impl!(Wrapping<i64>);
+#[cfg(has_i128)]
+pow_impl!(Wrapping<u128>);
+#[cfg(has_i128)]
+pow_impl!(Wrapping<i128>);
+pow_impl!(Wrapping<usize>);
+pow_impl!(Wrapping<isize>);
+
+// FIXME: these should be possible
+// pow_impl!(u8, u64);
+// pow_impl!(i16, u64);
+// pow_impl!(i8, u64);
+// pow_impl!(u16, u64);
+// pow_impl!(u32, u64);
+// pow_impl!(i32, u64);
+// pow_impl!(u64, u64);
+// pow_impl!(i64, u64);
+// pow_impl!(usize, u64);
+// pow_impl!(isize, u64);
+
+//#[cfg(feature = "std")]
+mod float_impls {
+    use super::Pow;
+
+    pow_impl!(f32, i8, i32, f32::powi);
+    pow_impl!(f32, u8, i32, f32::powi);
+    pow_impl!(f32, i16, i32, f32::powi);
+    pow_impl!(f32, u16, i32, f32::powi);
+    pow_impl!(f32, i32, i32, f32::powi);
+    pow_impl!(f64, i8, i32, f64::powi);
+    pow_impl!(f64, u8, i32, f64::powi);
+    pow_impl!(f64, i16, i32, f64::powi);
+    pow_impl!(f64, u16, i32, f64::powi);
+    pow_impl!(f64, i32, i32, f64::powi);
+    pow_impl!(f32, f32, f32, f32::powf);
+    pow_impl!(f64, f32, f64, f64::powf);
+    pow_impl!(f64, f64, f64, f64::powf);
+}
+
 /// Raises a value to the power of exp, using exponentiation by squaring.
 ///
 /// # Example
diff --git a/third_party/num/traits/src/real.rs b/third_party/num/traits/src/real.rs
new file mode 100644
index 0000000..d45edf2
--- /dev/null
+++ b/third_party/num/traits/src/real.rs
@@ -0,0 +1,838 @@
+use std::ops::Neg;
+
+use {Num, NumCast, Float};
+
+// NOTE: These doctests have the same issue as those in src/float.rs.
+// They're testing the inherent methods directly, and not those of `Real`.
+
+/// A trait for real number types that do not necessarily have
+/// floating-point-specific characteristics such as NaN and infinity.
+///
+/// See [this Wikipedia article](https://en.wikipedia.org/wiki/Real_data_type)
+/// for a list of data types that could meaningfully implement this trait.
+///
+/// This trait is only available with the `std` feature.
+pub trait Real
+    : Num
+    + Copy
+    + NumCast
+    + PartialOrd
+    + Neg<Output = Self>
+{
+    /// Returns the smallest finite value that this type can represent.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x: f64 = Real::min_value();
+    ///
+    /// assert_eq!(x, f64::MIN);
+    /// ```
+    fn min_value() -> Self;
+
+    /// Returns the smallest positive, normalized value that this type can represent.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x: f64 = Real::min_positive_value();
+    ///
+    /// assert_eq!(x, f64::MIN_POSITIVE);
+    /// ```
+    fn min_positive_value() -> Self;
+
+    /// Returns epsilon, a small positive value.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x: f64 = Real::epsilon();
+    ///
+    /// assert_eq!(x, f64::EPSILON);
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// The default implementation will panic if `f32::EPSILON` cannot
+    /// be cast to `Self`.
+    fn epsilon() -> Self;
+
+    /// Returns the largest finite value that this type can represent.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x: f64 = Real::max_value();
+    /// assert_eq!(x, f64::MAX);
+    /// ```
+    fn max_value() -> Self;
+
+    /// Returns the largest integer less than or equal to a number.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let f = 3.99;
+    /// let g = 3.0;
+    ///
+    /// assert_eq!(f.floor(), 3.0);
+    /// assert_eq!(g.floor(), 3.0);
+    /// ```
+    fn floor(self) -> Self;
+
+    /// Returns the smallest integer greater than or equal to a number.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let f = 3.01;
+    /// let g = 4.0;
+    ///
+    /// assert_eq!(f.ceil(), 4.0);
+    /// assert_eq!(g.ceil(), 4.0);
+    /// ```
+    fn ceil(self) -> Self;
+
+    /// Returns the nearest integer to a number. Round half-way cases away from
+    /// `0.0`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let f = 3.3;
+    /// let g = -3.3;
+    ///
+    /// assert_eq!(f.round(), 3.0);
+    /// assert_eq!(g.round(), -3.0);
+    /// ```
+    fn round(self) -> Self;
+
+    /// Return the integer part of a number.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let f = 3.3;
+    /// let g = -3.7;
+    ///
+    /// assert_eq!(f.trunc(), 3.0);
+    /// assert_eq!(g.trunc(), -3.0);
+    /// ```
+    fn trunc(self) -> Self;
+
+    /// Returns the fractional part of a number.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 3.5;
+    /// let y = -3.5;
+    /// let abs_difference_x = (x.fract() - 0.5).abs();
+    /// let abs_difference_y = (y.fract() - (-0.5)).abs();
+    ///
+    /// assert!(abs_difference_x < 1e-10);
+    /// assert!(abs_difference_y < 1e-10);
+    /// ```
+    fn fract(self) -> Self;
+
+    /// Computes the absolute value of `self`. Returns `Float::nan()` if the
+    /// number is `Float::nan()`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x = 3.5;
+    /// let y = -3.5;
+    ///
+    /// let abs_difference_x = (x.abs() - x).abs();
+    /// let abs_difference_y = (y.abs() - (-y)).abs();
+    ///
+    /// assert!(abs_difference_x < 1e-10);
+    /// assert!(abs_difference_y < 1e-10);
+    ///
+    /// assert!(::num_traits::Float::is_nan(f64::NAN.abs()));
+    /// ```
+    fn abs(self) -> Self;
+
+    /// Returns a number that represents the sign of `self`.
+    ///
+    /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
+    /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
+    /// - `Float::nan()` if the number is `Float::nan()`
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let f = 3.5;
+    ///
+    /// assert_eq!(f.signum(), 1.0);
+    /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0);
+    ///
+    /// assert!(f64::NAN.signum().is_nan());
+    /// ```
+    fn signum(self) -> Self;
+
+    /// Returns `true` if `self` is positive, including `+0.0`,
+    /// `Float::infinity()`, and with newer versions of Rust `f64::NAN`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let neg_nan: f64 = -f64::NAN;
+    ///
+    /// let f = 7.0;
+    /// let g = -7.0;
+    ///
+    /// assert!(f.is_sign_positive());
+    /// assert!(!g.is_sign_positive());
+    /// assert!(!neg_nan.is_sign_positive());
+    /// ```
+    fn is_sign_positive(self) -> bool;
+
+    /// Returns `true` if `self` is negative, including `-0.0`,
+    /// `Float::neg_infinity()`, and with newer versions of Rust `-f64::NAN`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let nan: f64 = f64::NAN;
+    ///
+    /// let f = 7.0;
+    /// let g = -7.0;
+    ///
+    /// assert!(!f.is_sign_negative());
+    /// assert!(g.is_sign_negative());
+    /// assert!(!nan.is_sign_negative());
+    /// ```
+    fn is_sign_negative(self) -> bool;
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` can be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let m = 10.0;
+    /// let x = 4.0;
+    /// let b = 60.0;
+    ///
+    /// // 100.0
+    /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn mul_add(self, a: Self, b: Self) -> Self;
+
+    /// Take the reciprocal (inverse) of a number, `1/x`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 2.0;
+    /// let abs_difference = (x.recip() - (1.0/x)).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn recip(self) -> Self;
+
+    /// Raise a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 2.0;
+    /// let abs_difference = (x.powi(2) - x*x).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn powi(self, n: i32) -> Self;
+
+    /// Raise a number to a real number power.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 2.0;
+    /// let abs_difference = (x.powf(2.0) - x*x).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn powf(self, n: Self) -> Self;
+
+    /// Take the square root of a number.
+    ///
+    /// Returns NaN if `self` is a negative floating-point number.  
+    ///
+    /// # Panics
+    ///
+    /// If the implementing type doesn't support NaN, this method should panic if `self < 0`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let positive = 4.0;
+    /// let negative = -4.0;
+    ///
+    /// let abs_difference = (positive.sqrt() - 2.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// assert!(::num_traits::Float::is_nan(negative.sqrt()));
+    /// ```
+    fn sqrt(self) -> Self;
+
+    /// Returns `e^(self)`, (the exponential function).
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let one = 1.0;
+    /// // e^1
+    /// let e = one.exp();
+    ///
+    /// // ln(e) - 1 == 0
+    /// let abs_difference = (e.ln() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn exp(self) -> Self;
+
+    /// Returns `2^(self)`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let f = 2.0;
+    ///
+    /// // 2^2 - 4 == 0
+    /// let abs_difference = (f.exp2() - 4.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn exp2(self) -> Self;
+
+    /// Returns the natural logarithm of the number.
+    ///
+    /// # Panics
+    ///
+    /// If `self <= 0` and this type does not support a NaN representation, this function should panic.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let one = 1.0;
+    /// // e^1
+    /// let e = one.exp();
+    ///
+    /// // ln(e) - 1 == 0
+    /// let abs_difference = (e.ln() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn ln(self) -> Self;
+
+    /// Returns the logarithm of the number with respect to an arbitrary base.
+    ///
+    /// # Panics
+    ///
+    /// If `self <= 0` and this type does not support a NaN representation, this function should panic.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let ten = 10.0;
+    /// let two = 2.0;
+    ///
+    /// // log10(10) - 1 == 0
+    /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs();
+    ///
+    /// // log2(2) - 1 == 0
+    /// let abs_difference_2 = (two.log(2.0) - 1.0).abs();
+    ///
+    /// assert!(abs_difference_10 < 1e-10);
+    /// assert!(abs_difference_2 < 1e-10);
+    /// ```
+    fn log(self, base: Self) -> Self;
+
+    /// Returns the base 2 logarithm of the number.
+    ///
+    /// # Panics
+    ///
+    /// If `self <= 0` and this type does not support a NaN representation, this function should panic.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let two = 2.0;
+    ///
+    /// // log2(2) - 1 == 0
+    /// let abs_difference = (two.log2() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn log2(self) -> Self;
+
+    /// Returns the base 10 logarithm of the number.
+    ///
+    /// # Panics
+    ///
+    /// If `self <= 0` and this type does not support a NaN representation, this function should panic.
+    ///
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let ten = 10.0;
+    ///
+    /// // log10(10) - 1 == 0
+    /// let abs_difference = (ten.log10() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn log10(self) -> Self;
+
+    /// Converts radians to degrees.
+    ///
+    /// ```
+    /// use std::f64::consts;
+    ///
+    /// let angle = consts::PI;
+    ///
+    /// let abs_difference = (angle.to_degrees() - 180.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn to_degrees(self) -> Self;
+
+    /// Converts degrees to radians.
+    ///
+    /// ```
+    /// use std::f64::consts;
+    ///
+    /// let angle = 180.0_f64;
+    ///
+    /// let abs_difference = (angle.to_radians() - consts::PI).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn to_radians(self) -> Self;
+
+    /// Returns the maximum of the two numbers.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 1.0;
+    /// let y = 2.0;
+    ///
+    /// assert_eq!(x.max(y), y);
+    /// ```
+    fn max(self, other: Self) -> Self;
+
+    /// Returns the minimum of the two numbers.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 1.0;
+    /// let y = 2.0;
+    ///
+    /// assert_eq!(x.min(y), x);
+    /// ```
+    fn min(self, other: Self) -> Self;
+
+    /// The positive difference of two numbers.
+    ///
+    /// * If `self <= other`: `0:0`
+    /// * Else: `self - other`
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 3.0;
+    /// let y = -3.0;
+    ///
+    /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
+    /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
+    ///
+    /// assert!(abs_difference_x < 1e-10);
+    /// assert!(abs_difference_y < 1e-10);
+    /// ```
+    //fn abs_sub(self, other: Self) -> Self;
+
+    /// Take the cubic root of a number.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 8.0;
+    ///
+    /// // x^(1/3) - 2 == 0
+    /// let abs_difference = (x.cbrt() - 2.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn cbrt(self) -> Self;
+
+    /// Calculate the length of the hypotenuse of a right-angle triangle given
+    /// legs of length `x` and `y`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 2.0;
+    /// let y = 3.0;
+    ///
+    /// // sqrt(x^2 + y^2)
+    /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn hypot(self, other: Self) -> Self;
+
+    /// Computes the sine of a number (in radians).
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x = f64::consts::PI/2.0;
+    ///
+    /// let abs_difference = (x.sin() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn sin(self) -> Self;
+
+    /// Computes the cosine of a number (in radians).
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x = 2.0*f64::consts::PI;
+    ///
+    /// let abs_difference = (x.cos() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn cos(self) -> Self;
+
+    /// Computes the tangent of a number (in radians).
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x = f64::consts::PI/4.0;
+    /// let abs_difference = (x.tan() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-14);
+    /// ```
+    fn tan(self) -> Self;
+
+    /// Computes the arcsine of a number. Return value is in radians in
+    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
+    /// [-1, 1].
+    ///
+    /// # Panics
+    ///
+    /// If this type does not support a NaN representation, this function should panic
+    /// if the number is outside the range [-1, 1].
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let f = f64::consts::PI / 2.0;
+    ///
+    /// // asin(sin(pi/2))
+    /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn asin(self) -> Self;
+
+    /// Computes the arccosine of a number. Return value is in radians in
+    /// the range [0, pi] or NaN if the number is outside the range
+    /// [-1, 1].
+    ///
+    /// # Panics
+    ///
+    /// If this type does not support a NaN representation, this function should panic
+    /// if the number is outside the range [-1, 1].
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let f = f64::consts::PI / 4.0;
+    ///
+    /// // acos(cos(pi/4))
+    /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn acos(self) -> Self;
+
+    /// Computes the arctangent of a number. Return value is in radians in the
+    /// range [-pi/2, pi/2];
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let f = 1.0;
+    ///
+    /// // atan(tan(1))
+    /// let abs_difference = (f.tan().atan() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn atan(self) -> Self;
+
+    /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`).
+    ///
+    /// * `x = 0`, `y = 0`: `0`
+    /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
+    /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
+    /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let pi = f64::consts::PI;
+    /// // All angles from horizontal right (+x)
+    /// // 45 deg counter-clockwise
+    /// let x1 = 3.0;
+    /// let y1 = -3.0;
+    ///
+    /// // 135 deg clockwise
+    /// let x2 = -3.0;
+    /// let y2 = 3.0;
+    ///
+    /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs();
+    /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs();
+    ///
+    /// assert!(abs_difference_1 < 1e-10);
+    /// assert!(abs_difference_2 < 1e-10);
+    /// ```
+    fn atan2(self, other: Self) -> Self;
+
+    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
+    /// `(sin(x), cos(x))`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x = f64::consts::PI/4.0;
+    /// let f = x.sin_cos();
+    ///
+    /// let abs_difference_0 = (f.0 - x.sin()).abs();
+    /// let abs_difference_1 = (f.1 - x.cos()).abs();
+    ///
+    /// assert!(abs_difference_0 < 1e-10);
+    /// assert!(abs_difference_0 < 1e-10);
+    /// ```
+    fn sin_cos(self) -> (Self, Self);
+
+    /// Returns `e^(self) - 1` in a way that is accurate even if the
+    /// number is close to zero.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 7.0;
+    ///
+    /// // e^(ln(7)) - 1
+    /// let abs_difference = (x.ln().exp_m1() - 6.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn exp_m1(self) -> Self;
+
+    /// Returns `ln(1+n)` (natural logarithm) more accurately than if
+    /// the operations were performed separately.
+    ///
+    /// # Panics
+    ///
+    /// If this type does not support a NaN representation, this function should panic
+    /// if `self-1 <= 0`.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let x = f64::consts::E - 1.0;
+    ///
+    /// // ln(1 + (e - 1)) == ln(e) == 1
+    /// let abs_difference = (x.ln_1p() - 1.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn ln_1p(self) -> Self;
+
+    /// Hyperbolic sine function.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let e = f64::consts::E;
+    /// let x = 1.0;
+    ///
+    /// let f = x.sinh();
+    /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
+    /// let g = (e*e - 1.0)/(2.0*e);
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    fn sinh(self) -> Self;
+
+    /// Hyperbolic cosine function.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let e = f64::consts::E;
+    /// let x = 1.0;
+    /// let f = x.cosh();
+    /// // Solving cosh() at 1 gives this result
+    /// let g = (e*e + 1.0)/(2.0*e);
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// // Same result
+    /// assert!(abs_difference < 1.0e-10);
+    /// ```
+    fn cosh(self) -> Self;
+
+    /// Hyperbolic tangent function.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let e = f64::consts::E;
+    /// let x = 1.0;
+    ///
+    /// let f = x.tanh();
+    /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
+    /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2));
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// assert!(abs_difference < 1.0e-10);
+    /// ```
+    fn tanh(self) -> Self;
+
+    /// Inverse hyperbolic sine function.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 1.0;
+    /// let f = x.sinh().asinh();
+    ///
+    /// let abs_difference = (f - x).abs();
+    ///
+    /// assert!(abs_difference < 1.0e-10);
+    /// ```
+    fn asinh(self) -> Self;
+
+    /// Inverse hyperbolic cosine function.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    ///
+    /// let x = 1.0;
+    /// let f = x.cosh().acosh();
+    ///
+    /// let abs_difference = (f - x).abs();
+    ///
+    /// assert!(abs_difference < 1.0e-10);
+    /// ```
+    fn acosh(self) -> Self;
+
+    /// Inverse hyperbolic tangent function.
+    ///
+    /// ```
+    /// use num_traits::real::Real;
+    /// use std::f64;
+    ///
+    /// let e = f64::consts::E;
+    /// let f = e.tanh().atanh();
+    ///
+    /// let abs_difference = (f - e).abs();
+    ///
+    /// assert!(abs_difference < 1.0e-10);
+    /// ```
+    fn atanh(self) -> Self;
+}
+
+impl<T: Float> Real for T {
+    forward! {
+        Float::min_value() -> Self;
+        Float::min_positive_value() -> Self;
+        Float::epsilon() -> Self;
+        Float::max_value() -> Self;
+    }
+    forward! {
+        Float::floor(self) -> Self;
+        Float::ceil(self) -> Self;
+        Float::round(self) -> Self;
+        Float::trunc(self) -> Self;
+        Float::fract(self) -> Self;
+        Float::abs(self) -> Self;
+        Float::signum(self) -> Self;
+        Float::is_sign_positive(self) -> bool;
+        Float::is_sign_negative(self) -> bool;
+        Float::mul_add(self, a: Self, b: Self) -> Self;
+        Float::recip(self) -> Self;
+        Float::powi(self, n: i32) -> Self;
+        Float::powf(self, n: Self) -> Self;
+        Float::sqrt(self) -> Self;
+        Float::exp(self) -> Self;
+        Float::exp2(self) -> Self;
+        Float::ln(self) -> Self;
+        Float::log(self, base: Self) -> Self;
+        Float::log2(self) -> Self;
+        Float::log10(self) -> Self;
+        Float::to_degrees(self) -> Self;
+        Float::to_radians(self) -> Self;
+        Float::max(self, other: Self) -> Self;
+        Float::min(self, other: Self) -> Self;
+        //Float::abs_sub(self, other: Self) -> Self;
+        Float::cbrt(self) -> Self;
+        Float::hypot(self, other: Self) -> Self;
+        Float::sin(self) -> Self;
+        Float::cos(self) -> Self;
+        Float::tan(self) -> Self;
+        Float::asin(self) -> Self;
+        Float::acos(self) -> Self;
+        Float::atan(self) -> Self;
+        Float::atan2(self, other: Self) -> Self;
+        Float::sin_cos(self) -> (Self, Self);
+        Float::exp_m1(self) -> Self;
+        Float::ln_1p(self) -> Self;
+        Float::sinh(self) -> Self;
+        Float::cosh(self) -> Self;
+        Float::tanh(self) -> Self;
+        Float::asinh(self) -> Self;
+        Float::acosh(self) -> Self;
+        Float::atanh(self) -> Self;
+    }
+}
diff --git a/third_party/num/traits/src/sign.rs b/third_party/num/traits/src/sign.rs
index 4b43c89..779d058 100644
--- a/third_party/num/traits/src/sign.rs
+++ b/third_party/num/traits/src/sign.rs
@@ -1,8 +1,8 @@
-use std::ops::Neg;
-use std::{f32, f64};
-use std::num::Wrapping;
+use core::ops::Neg;
+use core::num::Wrapping;
 
 use Num;
+use float::FloatCore;
 
 /// Useful functions for signed numbers (i.e. numbers that can be negative).
 pub trait Signed: Sized + Num + Neg<Output = Self> {
@@ -74,6 +74,9 @@
 
 signed_impl!(isize i8 i16 i32 i64);
 
+#[cfg(has_i128)]
+signed_impl!(i128);
+
 impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapping<T>>
 {
     #[inline]
@@ -99,21 +102,20 @@
 }
 
 macro_rules! signed_float_impl {
-    ($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => {
+    ($t:ty) => {
         impl Signed for $t {
             /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
             #[inline]
             fn abs(&self) -> $t {
-                <$t>::abs(*self)
+                FloatCore::abs(*self)
             }
 
             /// The positive difference of two numbers. Returns `0.0` if the number is
             /// less than or equal to `other`, otherwise the difference between`self`
             /// and `other` is returned.
             #[inline]
-            #[allow(deprecated)]
             fn abs_sub(&self, other: &$t) -> $t {
-                <$t>::abs_sub(*self, *other)
+                if *self <= *other { 0. } else { *self - *other }
             }
 
             /// # Returns
@@ -123,22 +125,22 @@
             /// - `NAN` if the number is NaN
             #[inline]
             fn signum(&self) -> $t {
-                <$t>::signum(*self)
+                FloatCore::signum(*self)
             }
 
             /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
             #[inline]
-            fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf }
+            fn is_positive(&self) -> bool { FloatCore::is_sign_positive(*self) }
 
             /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
             #[inline]
-            fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == $neg_inf }
+            fn is_negative(&self) -> bool { FloatCore::is_sign_negative(*self) }
         }
     }
 }
 
-signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY);
-signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY);
+signed_float_impl!(f32);
+signed_float_impl!(f64);
 
 /// Computes the absolute value.
 ///
@@ -184,6 +186,8 @@
 }
 
 empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
+#[cfg(has_i128)]
+empty_trait_impl!(Unsigned for u128);
 
 impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
 
diff --git a/third_party/rust-crypto/CHANGELOG.md b/third_party/rust-crypto/CHANGELOG.md
new file mode 100644
index 0000000..37cb8d5
--- /dev/null
+++ b/third_party/rust-crypto/CHANGELOG.md
@@ -0,0 +1,10 @@
+Version v0.2.35 (4/4/2016)
+==========================
+
+* Improve cross compiling from GCC to msvc.
+* Fix BCrypt algorithm when using a cost of 31.
+* Improve building on OpenBSD.
+* Add implementation of SHA3 digest function.
+* Fix errors in Blake2b that could lead to incorrect output. The Blake2b
+  initialization functions are modified to take parameters by value instead of
+  by reference, which may break users of the interfaces.
diff --git a/third_party/rust-crypto/Cargo.toml b/third_party/rust-crypto/Cargo.toml
new file mode 100644
index 0000000..8149f2b
--- /dev/null
+++ b/third_party/rust-crypto/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rust-crypto"
+version = "0.2.36"
+authors = ["The Rust-Crypto Project Developers"]
+license = "MIT/Apache-2.0"
+homepage = "https://github.com/DaGenix/rust-crypto/"
+repository = "https://github.com/DaGenix/rust-crypto/"
+description = "A (mostly) pure-Rust implementation of various common cryptographic algorithms."
+keywords = [ "Crypto", "MD5", "Sha1", "Sha2", "AES" ]
+readme = "README.md"
+build = "build.rs"
+
+[lib]
+name = "crypto"
+
+[features]
+with-bench = []
+
+[build-dependencies]
+gcc = "^0.3"
+
+[target.'cfg(not(target_env = "sgx"))'.dependencies]
+sgx_trts= { path = "../../sgx_trts" }
+sgx_tstd = { path = "../../sgx_tstd" }
+sgx_rand = { path = "../../sgx_rand" }
+
+[dependencies]
+rustc-serialize = { path = "../rustc-serialize" }
diff --git a/third_party/rust-crypto/LICENSE-APACHE b/third_party/rust-crypto/LICENSE-APACHE
new file mode 100644
index 0000000..78173fa
--- /dev/null
+++ b/third_party/rust-crypto/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust-crypto/LICENSE-MIT b/third_party/rust-crypto/LICENSE-MIT
new file mode 100644
index 0000000..1da3a5f
--- /dev/null
+++ b/third_party/rust-crypto/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright (c) 2006-2009 Graydon Hoare
+Copyright (c) 2009-2013 Mozilla Foundation
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust-crypto/README.md b/third_party/rust-crypto/README.md
new file mode 100644
index 0000000..a24d25d
--- /dev/null
+++ b/third_party/rust-crypto/README.md
@@ -0,0 +1,75 @@
+# Rust-Crypto
+
+[![Build Status](https://travis-ci.org/DaGenix/rust-crypto.png?branch=master)](https://travis-ci.org/DaGenix/rust-crypto)
+
+A (mostly) pure-Rust implementation of various common cryptographic algorithms.
+
+Rust-Crypto seeks to create practical, auditable, pure-Rust implementations of common cryptographic
+algorithms with a minimum amount of assembly code where appropriate. The x86-64, x86, and
+ARM architectures are supported, although the x86-64 architecture receives the most testing.
+
+Rust-Crypto targets the current, stable build of Rust.
+If you are having issues while using an older version, please try upgrading to the latest stable.
+
+Rust-Crypto has not been thoroughly
+audited for correctness, so any use where security is important is not recommended at this time.
+
+## Usage
+
+To use Rust-Crypto, add the following to your Cargo.toml:
+
+```toml
+[dependencies]
+rust-crypto = "^0.2"
+```
+
+and the following to your crate root:
+
+```rust
+extern crate crypto;
+```
+
+## Contributions
+
+Contributions are extremely welcome. The most significant needs are help
+adding documentation, implementing new algorithms,
+and general cleanup and improvement of the code. By submitting a pull request you are agreeing to
+make you work available under the license
+terms of the Rust-Crypto project.
+
+## License
+
+Rust-Crypto is dual licensed under the MIT and Apache 2.0 licenses, the same licenses
+as the Rust compiler.
+
+## Algorithms
+
+Rust-Crypto already supports a significant number of algorithms and with your help
+it will support even more in the future. Currently supported algorithms include:
+
+* AES
+* Bcrypt
+* BLAKE2b
+* BLAKE2s
+* Blowfish
+* ChaCha20
+* Curve25519
+* ECB, CBC, and CTR block cipher modes
+* Ed25519
+* Fortuna
+* Ghash
+* HC128
+* HMAC
+* MD5
+* PBKDF2
+* PKCS padding for CBC block cipher mode
+* Poly1305
+* RC4
+* RIPEMD-160
+* Salsa20 and XSalsa20
+* Scrypt
+* Sha1
+* Sha2 (All fixed output size variants)
+* Sha3
+* Sosemanuk
+* Whirlpool
diff --git a/third_party/rust-crypto/Xargo.toml b/third_party/rust-crypto/Xargo.toml
new file mode 100644
index 0000000..48ad024
--- /dev/null
+++ b/third_party/rust-crypto/Xargo.toml
@@ -0,0 +1,20 @@
+[dependencies]
+alloc = {}
+panic_unwind = {}
+panic_abort = {}
+
+[dependencies.std]
+path = "../../xargo/sgx_tstd"
+stage = 1
+
+[dependencies.sgx_rand]
+path = "../../xargo/sgx_rand"
+stage = 2
+
+[dependencies.sgx_serialize]
+path = "../../xargo/sgx_serialize"
+stage = 2
+
+[dependencies.sgx_tunittest]
+path = "../../xargo/sgx_tunittest"
+stage = 2
\ No newline at end of file
diff --git a/third_party/rust-crypto/appveyor.yml b/third_party/rust-crypto/appveyor.yml
new file mode 100644
index 0000000..1184d4c
--- /dev/null
+++ b/third_party/rust-crypto/appveyor.yml
@@ -0,0 +1,52 @@
+clone_depth: 50
+environment:
+  matrix:
+  - TARGET: nightly-x86_64-pc-windows-msvc
+  - TARGET: nightly-i686-pc-windows-msvc
+  - TARGET: nightly-x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: nightly-i686-pc-windows-gnu
+    MSYS_BITS: 32
+  - TARGET: beta-x86_64-pc-windows-msvc
+  - TARGET: beta-i686-pc-windows-msvc
+  - TARGET: beta-x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: beta-i686-pc-windows-gnu
+    MSYS_BITS: 32
+  - TARGET: 1.8.0-x86_64-pc-windows-msvc
+  - TARGET: 1.8.0-i686-pc-windows-msvc
+  - TARGET: 1.8.0-x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: 1.8.0-i686-pc-windows-gnu
+    MSYS_BITS: 32
+  - TARGET: 1.7.0-x86_64-pc-windows-msvc
+  - TARGET: 1.7.0-x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: 1.7.0-i686-pc-windows-gnu
+    MSYS_BITS: 32
+  - TARGET: 1.6.0-x86_64-pc-windows-msvc
+  - TARGET: 1.6.0-x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: 1.6.0-i686-pc-windows-gnu
+    MSYS_BITS: 32
+  - TARGET: 1.5.0-x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: 1.5.0-i686-pc-windows-gnu
+    MSYS_BITS: 32
+  - TARGET: 1.4.0-x86_64-pc-windows-gnu
+    MSYS_BITS: 64
+  - TARGET: 1.4.0-i686-pc-windows-gnu
+    MSYS_BITS: 32
+install:
+  - git submodule update --init --recursive
+  - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust-install.exe"
+  - ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null
+  - ps: $env:PATH="$env:PATH;C:\rust\bin"
+  - if defined MSYS_BITS set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH%
+  - rustc -vV
+  - cargo -vV
+build_script:
+  - cargo build
+  - cargo package
+test_script:
+  - cargo test
diff --git a/third_party/rust-crypto/build.rs b/third_party/rust-crypto/build.rs
new file mode 100644
index 0000000..bdd4acd
--- /dev/null
+++ b/third_party/rust-crypto/build.rs
@@ -0,0 +1,41 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate gcc;
+
+use std::env;
+use std::path::Path;
+
+fn main() {
+    let target = env::var("TARGET").unwrap();
+    let host = env::var("HOST").unwrap();
+    if target.contains("msvc") && host.contains("windows") {
+        let mut config = gcc::Build::new();
+        config.file("src/util_helpers.asm");
+        config.file("src/aesni_helpers.asm");
+        if target.contains("x86_64") {
+            config.define("X64", None);
+        }
+        config.compile("lib_rust_crypto_helpers.a");
+    }
+    else {
+        let mut cfg = gcc::Build::new();
+        cfg.file("src/util_helpers.c");
+        cfg.file("src/aesni_helpers.c");
+        if env::var_os("CC").is_none() {
+            if host.contains("openbsd") {
+                // Use clang on openbsd since there have been reports that
+                // GCC doesn't like some of the assembly that we use on that
+                // platform.
+                cfg.compiler(Path::new("clang"));
+            } else if target == host {
+                cfg.compiler(Path::new("cc"));
+            }
+        }
+        cfg.compile("lib_rust_crypto_helpers.a");
+    }
+}
+
diff --git a/third_party/rust-crypto/examples/symmetriccipher.rs b/third_party/rust-crypto/examples/symmetriccipher.rs
new file mode 100644
index 0000000..8f559f5
--- /dev/null
+++ b/third_party/rust-crypto/examples/symmetriccipher.rs
@@ -0,0 +1,126 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate crypto;
+extern crate rand;
+
+use crypto::{ symmetriccipher, buffer, aes, blockmodes };
+use crypto::buffer::{ ReadBuffer, WriteBuffer, BufferResult };
+
+use rand::{ Rng, OsRng };
+
+// Encrypt a buffer with the given key and iv using
+// AES-256/CBC/Pkcs encryption.
+fn encrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>, symmetriccipher::SymmetricCipherError> {
+
+    // Create an encryptor instance of the best performing
+    // type available for the platform.
+    let mut encryptor = aes::cbc_encryptor(
+            aes::KeySize::KeySize256,
+            key,
+            iv,
+            blockmodes::PkcsPadding);
+
+    // Each encryption operation encrypts some data from
+    // an input buffer into an output buffer. Those buffers
+    // must be instances of RefReaderBuffer and RefWriteBuffer
+    // (respectively) which keep track of how much data has been
+    // read from or written to them.
+    let mut final_result = Vec::<u8>::new();
+    let mut read_buffer = buffer::RefReadBuffer::new(data);
+    let mut buffer = [0; 4096];
+    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);
+
+    // Each encryption operation will "make progress". "Making progress"
+    // is a bit loosely defined, but basically, at the end of each operation
+    // either BufferUnderflow or BufferOverflow will be returned (unless
+    // there was an error). If the return value is BufferUnderflow, it means
+    // that the operation ended while wanting more input data. If the return
+    // value is BufferOverflow, it means that the operation ended because it
+    // needed more space to output data. As long as the next call to the encryption
+    // operation provides the space that was requested (either more input data
+    // or more output space), the operation is guaranteed to get closer to
+    // completing the full operation - ie: "make progress".
+    //
+    // Here, we pass the data to encrypt to the enryptor along with a fixed-size
+    // output buffer. The 'true' flag indicates that the end of the data that
+    // is to be encrypted is included in the input buffer (which is true, since
+    // the input data includes all the data to encrypt). After each call, we copy
+    // any output data to our result Vec. If we get a BufferOverflow, we keep
+    // going in the loop since it means that there is more work to do. We can
+    // complete as soon as we get a BufferUnderflow since the encryptor is telling
+    // us that it stopped processing data due to not having any more data in the
+    // input buffer.
+    loop {
+        let result = try!(encryptor.encrypt(&mut read_buffer, &mut write_buffer, true));
+
+        // "write_buffer.take_read_buffer().take_remaining()" means:
+        // from the writable buffer, create a new readable buffer which
+        // contains all data that has been written, and then access all
+        // of that data as a slice.
+        final_result.extend(write_buffer.take_read_buffer().take_remaining().iter().map(|&i| i));
+
+        match result {
+            BufferResult::BufferUnderflow => break,
+            BufferResult::BufferOverflow => { }
+        }
+    }
+
+    Ok(final_result)
+}
+
+// Decrypts a buffer with the given key and iv using
+// AES-256/CBC/Pkcs encryption.
+//
+// This function is very similar to encrypt(), so, please reference
+// comments in that function. In non-example code, if desired, it is possible to
+// share much of the implementation using closures to hide the operation
+// being performed. However, such code would make this example less clear.
+fn decrypt(encrypted_data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>, symmetriccipher::SymmetricCipherError> {
+    let mut decryptor = aes::cbc_decryptor(
+            aes::KeySize::KeySize256,
+            key,
+            iv,
+            blockmodes::PkcsPadding);
+
+    let mut final_result = Vec::<u8>::new();
+    let mut read_buffer = buffer::RefReadBuffer::new(encrypted_data);
+    let mut buffer = [0; 4096];
+    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);
+
+    loop {
+        let result = try!(decryptor.decrypt(&mut read_buffer, &mut write_buffer, true));
+        final_result.extend(write_buffer.take_read_buffer().take_remaining().iter().map(|&i| i));
+        match result {
+            BufferResult::BufferUnderflow => break,
+            BufferResult::BufferOverflow => { }
+        }
+    }
+
+    Ok(final_result)
+}
+
+fn main() {
+    let message = "Hello World!";
+
+    let mut key: [u8; 32] = [0; 32];
+    let mut iv: [u8; 16] = [0; 16];
+
+    // In a real program, the key and iv may be determined
+    // using some other mechanism. If a password is to be used
+    // as a key, an algorithm like PBKDF2, Bcrypt, or Scrypt (all
+    // supported by Rust-Crypto!) would be a good choice to derive
+    // a password. For the purposes of this example, the key and
+    // iv are just random values.
+    let mut rng = OsRng::new().ok().unwrap();
+    rng.fill_bytes(&mut key);
+    rng.fill_bytes(&mut iv);
+
+    let encrypted_data = encrypt(message.as_bytes(), &key, &iv).ok().unwrap();
+    let decrypted_data = decrypt(&encrypted_data[..], &key, &iv).ok().unwrap();
+
+    assert!(message.as_bytes() == &decrypted_data[..]);
+}
diff --git a/third_party/rust-crypto/src/aead.rs b/third_party/rust-crypto/src/aead.rs
new file mode 100644
index 0000000..4f4f3b7
--- /dev/null
+++ b/third_party/rust-crypto/src/aead.rs
@@ -0,0 +1,15 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait AeadEncryptor {
+
+	fn encrypt(&mut self, input: &[u8], output: &mut [u8], tag: &mut [u8]);
+}
+
+pub trait AeadDecryptor {
+
+	fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool;
+}
\ No newline at end of file
diff --git a/third_party/rust-crypto/src/aes.rs b/third_party/rust-crypto/src/aes.rs
new file mode 100644
index 0000000..91c4899
--- /dev/null
+++ b/third_party/rust-crypto/src/aes.rs
@@ -0,0 +1,791 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+use aesni;
+
+use std::prelude::v1::*;
+use aessafe;
+use blockmodes::{PaddingProcessor, EcbEncryptor, EcbDecryptor, CbcEncryptor, CbcDecryptor, CtrMode,};
+    //CtrModeX8};
+use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher};
+use util;
+
+/// AES key size
+#[derive(Clone, Copy)]
+pub enum KeySize {
+    KeySize128,
+    KeySize192,
+    KeySize256
+}
+
+/// Get the best implementation of an EcbEncryptor
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub fn ecb_encryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        padding: X) -> Box<Encryptor> {
+    if util::supports_aesni() {
+        let aes_enc = aesni::AesNiEncryptor::new(key_size, key);
+        let enc = Box::new(EcbEncryptor::new(aes_enc, padding));
+        enc
+    } else {
+        match key_size {
+            KeySize::KeySize128 => {
+                let aes_enc = aessafe::AesSafe128Encryptor::new(key);
+                let enc = Box::new(EcbEncryptor::new(aes_enc, padding));
+                enc
+            }
+            KeySize::KeySize192 => {
+                let aes_enc = aessafe::AesSafe192Encryptor::new(key);
+                let enc = Box::new(EcbEncryptor::new(aes_enc, padding));
+                enc
+            }
+            KeySize::KeySize256 => {
+                let aes_enc = aessafe::AesSafe256Encryptor::new(key);
+                let enc = Box::new(EcbEncryptor::new(aes_enc, padding));
+                enc
+            }
+        }
+    }
+}
+
+/// Get the best implementation of an EcbEncryptor
+#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+pub fn ecb_encryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        padding: X) -> Box<Encryptor> {
+    match key_size {
+        KeySize::KeySize128 => {
+            let aes_enc = aessafe::AesSafe128Encryptor::new(key);
+            let enc = Box::new(EcbEncryptor::new(aes_enc, padding));
+            enc
+        }
+        KeySize::KeySize192 => {
+            let aes_enc = aessafe::AesSafe192Encryptor::new(key);
+            let enc = Box::new(EcbEncryptor::new(aes_enc, padding));
+            enc
+        }
+        KeySize::KeySize256 => {
+            let aes_enc = aessafe::AesSafe256Encryptor::new(key);
+            let enc = Box::new(EcbEncryptor::new(aes_enc, padding));
+            enc
+        }
+    }
+}
+
+/// Get the best implementation of an EcbDecryptor
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub fn ecb_decryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        padding: X) -> Box<Decryptor> {
+    if util::supports_aesni() {
+        let aes_dec = aesni::AesNiDecryptor::new(key_size, key);
+        let dec = Box::new(EcbDecryptor::new(aes_dec, padding));
+        dec
+    } else {
+        match key_size {
+            KeySize::KeySize128 => {
+                let aes_dec = aessafe::AesSafe128Decryptor::new(key);
+                let dec = Box::new(EcbDecryptor::new(aes_dec, padding));
+                dec
+            }
+            KeySize::KeySize192 => {
+                let aes_dec = aessafe::AesSafe192Decryptor::new(key);
+                let dec = Box::new(EcbDecryptor::new(aes_dec, padding));
+                dec
+            }
+            KeySize::KeySize256 => {
+                let aes_dec = aessafe::AesSafe256Decryptor::new(key);
+                let dec = Box::new(EcbDecryptor::new(aes_dec, padding));
+                dec
+            }
+        }
+    }
+}
+
+/// Get the best implementation of an EcbDecryptor
+#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+pub fn ecb_decryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        padding: X) -> Box<Decryptor> {
+    match key_size {
+        KeySize::KeySize128 => {
+            let aes_dec = aessafe::AesSafe128Decryptor::new(key);
+            let dec = Box::new(EcbDecryptor::new(aes_dec, padding));
+            dec
+        }
+        KeySize::KeySize192 => {
+            let aes_dec = aessafe::AesSafe192Decryptor::new(key);
+            let dec = Box::new(EcbDecryptor::new(aes_dec, padding));
+            dec
+        }
+        KeySize::KeySize256 => {
+            let aes_dec = aessafe::AesSafe256Decryptor::new(key);
+            let dec = Box::new(EcbDecryptor::new(aes_dec, padding));
+            dec
+        }
+    }
+}
+
+/// Get the best implementation of a CbcEncryptor
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub fn cbc_encryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        iv: &[u8],
+        padding: X) -> Box<Encryptor + 'static> {
+    if util::supports_aesni() {
+        let aes_enc = aesni::AesNiEncryptor::new(key_size, key);
+        let enc = Box::new(CbcEncryptor::new(aes_enc, padding, iv.to_vec()));
+        enc
+    } else {
+        match key_size {
+            KeySize::KeySize128 => {
+                let aes_enc = aessafe::AesSafe128Encryptor::new(key);
+                let enc = Box::new(CbcEncryptor::new(aes_enc, padding, iv.to_vec()));
+                enc
+            }
+            KeySize::KeySize192 => {
+                let aes_enc = aessafe::AesSafe192Encryptor::new(key);
+                let enc = Box::new(CbcEncryptor::new(aes_enc, padding, iv.to_vec()));
+                enc
+            }
+            KeySize::KeySize256 => {
+                let aes_enc = aessafe::AesSafe256Encryptor::new(key);
+                let enc = Box::new(CbcEncryptor::new(aes_enc, padding, iv.to_vec()));
+                enc
+            }
+        }
+    }
+}
+
+/// Get the best implementation of a CbcEncryptor
+#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+pub fn cbc_encryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        iv: &[u8],
+        padding: X) -> Box<Encryptor + 'static> {
+    match key_size {
+        KeySize::KeySize128 => {
+            let aes_enc = aessafe::AesSafe128Encryptor::new(key);
+            let enc = Box::new(CbcEncryptor::new(aes_enc, padding, iv.to_vec()));
+            enc
+        }
+        KeySize::KeySize192 => {
+            let aes_enc = aessafe::AesSafe192Encryptor::new(key);
+            let enc = Box::new(CbcEncryptor::new(aes_enc, padding, iv.to_vec()));
+            enc
+        }
+        KeySize::KeySize256 => {
+            let aes_enc = aessafe::AesSafe256Encryptor::new(key);
+            let enc = Box::new(CbcEncryptor::new(aes_enc, padding, iv.to_vec()));
+            enc
+        }
+    }
+}
+
+/// Get the best implementation of a CbcDecryptor
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub fn cbc_decryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        iv: &[u8],
+        padding: X) -> Box<Decryptor + 'static> {
+    if util::supports_aesni() {
+        let aes_dec = aesni::AesNiDecryptor::new(key_size, key);
+        let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec()));
+        dec
+    } else {
+        match key_size {
+            KeySize::KeySize128 => {
+                let aes_dec = aessafe::AesSafe128Decryptor::new(key);
+                let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec()));
+                dec
+            }
+            KeySize::KeySize192 => {
+                let aes_dec = aessafe::AesSafe192Decryptor::new(key);
+                let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec()));
+                dec
+            }
+            KeySize::KeySize256 => {
+                let aes_dec = aessafe::AesSafe256Decryptor::new(key);
+                let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec()));
+                dec
+            }
+        }
+    }
+}
+
+/// Get the best implementation of a CbcDecryptor
+#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+pub fn cbc_decryptor<X: PaddingProcessor + Send + 'static>(
+        key_size: KeySize,
+        key: &[u8],
+        iv: &[u8],
+        padding: X) -> Box<Decryptor + 'static> {
+    match key_size {
+        KeySize::KeySize128 => {
+            let aes_dec = aessafe::AesSafe128Decryptor::new(key);
+            let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec()));
+            dec as Box<Decryptor + 'static>
+        }
+        KeySize::KeySize192 => {
+            let aes_dec = aessafe::AesSafe192Decryptor::new(key);
+            let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec()));
+            dec as Box<Decryptor + 'static>
+        }
+        KeySize::KeySize256 => {
+            let aes_dec = aessafe::AesSafe256Decryptor::new(key);
+            let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec()));
+            dec as Box<Decryptor + 'static>
+        }
+    }
+}
+
+/// Get the best implementation of a Ctr
+//#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub fn ctr(
+        key_size: KeySize,
+        key: &[u8],
+        iv: &[u8]) -> Box<SynchronousStreamCipher + 'static> {
+    //println!("enter ctr");
+    //if util::supports_aesni() {
+    //    println!("supports_aesni");
+        let aes_dec = aesni::AesNiEncryptor::new(key_size, key);
+        let dec = Box::new(CtrMode::new(aes_dec, iv.to_vec()));
+        dec
+    //} else {
+    //    println!("not supports_aesni");
+    //    match key_size {
+    //        KeySize::KeySize128 => {
+    //            let aes_dec = aessafe::AesSafe128EncryptorX8::new(key);
+    //            let dec = Box::new(CtrModeX8::new(aes_dec, iv));
+    //            dec
+    //        }
+    //        KeySize::KeySize192 => {
+    //            let aes_dec = aessafe::AesSafe192EncryptorX8::new(key);
+    //            let dec = Box::new(CtrModeX8::new(aes_dec, iv));
+    //            dec
+    //        }
+    //        KeySize::KeySize256 => {
+    //            let aes_dec = aessafe::AesSafe256EncryptorX8::new(key);
+    //            let dec = Box::new(CtrModeX8::new(aes_dec, iv));
+    //            dec
+    //        }
+    //    }
+    //}
+}
+
+/// Get the best implementation of a Ctr
+//#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+//pub fn ctr(
+//        key_size: KeySize,
+//        key: &[u8],
+//        iv: &[u8]) -> Box<SynchronousStreamCipher + 'static> {
+//    match key_size {
+//        KeySize::KeySize128 => {
+//            let aes_dec = aessafe::AesSafe128EncryptorX8::new(key);
+//            let dec = Box::new(CtrModeX8::new(aes_dec, iv));
+//            dec as Box<SynchronousStreamCipher>
+//        }
+//        KeySize::KeySize192 => {
+//            let aes_dec = aessafe::AesSafe192EncryptorX8::new(key);
+//            let dec = Box::new(CtrModeX8::new(aes_dec, iv));
+//            dec as Box<SynchronousStreamCipher>
+//        }
+//        KeySize::KeySize256 => {
+//            let aes_dec = aessafe::AesSafe256EncryptorX8::new(key);
+//            let dec = Box::new(CtrModeX8::new(aes_dec, iv));
+//            dec as Box<SynchronousStreamCipher>
+//        }
+//    }
+//}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    use aesni;
+
+    use aessafe;
+    use symmetriccipher::{BlockEncryptor, BlockDecryptor, BlockEncryptorX8, BlockDecryptorX8,
+            SynchronousStreamCipher};
+    use util;
+    use aes;
+    use aes::KeySize::{KeySize128, KeySize192, KeySize256};
+
+    // Test vectors from:
+    // http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors
+
+    struct Test {
+        key: Vec<u8>,
+        data: Vec<TestData>
+    }
+
+    struct TestData {
+        plain: Vec<u8>,
+        cipher: Vec<u8>
+    }
+
+    fn tests128() -> Vec<Test> {
+        vec![
+            Test {
+                key: vec![0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+                       0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c],
+                data: vec![
+                    TestData {
+                        plain:  vec![0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                                 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a],
+                        cipher: vec![0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
+                                 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97]
+                    },
+                    TestData {
+                        plain:  vec![0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                                 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51],
+                        cipher: vec![0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d,
+                                 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf]
+                    },
+                    TestData {
+                        plain:  vec![0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                                 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef],
+                        cipher: vec![0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23,
+                                 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88]
+                    },
+                    TestData {
+                        plain:  vec![0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                                 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10],
+                        cipher: vec![0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f,
+                                 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4]
+                    }
+                ]
+            }
+        ]
+    }
+
+    fn tests192() -> Vec<Test> {
+        vec![
+            Test {
+                key: vec![0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b,
+                       0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b],
+                data: vec![
+                    TestData {
+                        plain:  vec![0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                                  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a],
+                        cipher: vec![0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f,
+                                  0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc]
+                    },
+                    TestData {
+                        plain:  vec![0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                                  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51],
+                        cipher: vec![0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad,
+                                  0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef]
+                    },
+                    TestData {
+                        plain:  vec![0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                                  0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef],
+                        cipher: vec![0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a,
+                                  0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e]
+                    },
+                    TestData {
+                        plain:  vec![0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                                  0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10],
+                        cipher: vec![0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72,
+                                  0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e]
+                    }
+                ]
+            }
+        ]
+    }
+
+    fn tests256() -> Vec<Test> {
+        vec![
+            Test {
+                key: vec![0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+                       0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+                       0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+                       0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4],
+                data: vec![
+                    TestData {
+                        plain:  vec![0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+                                  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a],
+                        cipher: vec![0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c,
+                                  0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8]
+                    },
+                    TestData {
+                        plain:  vec![0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+                                  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51],
+                        cipher: vec![0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26,
+                                  0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70]
+                    },
+                    TestData {
+                        plain:  vec![0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+                                  0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef],
+                        cipher: vec![0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9,
+                                  0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d]
+                    },
+                    TestData {
+                        plain:  vec![0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+                                  0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10],
+                        cipher: vec![0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff,
+                                  0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7]
+                    }
+                ]
+            }
+        ]
+    }
+
+    struct CtrTest {
+        key: Vec<u8>,
+        ctr: Vec<u8>,
+        plain: Vec<u8>,
+        cipher: Vec<u8>
+    }
+
+    fn aes_ctr_tests() -> Vec<CtrTest> {
+        vec![
+            CtrTest {
+                key: repeat(1).take(16).collect(),
+                ctr: repeat(3).take(16).collect(),
+                plain: repeat(2).take(33).collect(),
+                cipher: vec![
+                    0x64, 0x3e, 0x05, 0x19, 0x79, 0x78, 0xd7, 0x45,
+                    0xa9, 0x10, 0x5f, 0xd8, 0x4c, 0xd7, 0xe6, 0xb1,
+                    0x5f, 0x66, 0xc6, 0x17, 0x4b, 0x25, 0xea, 0x24,
+                    0xe6, 0xf9, 0x19, 0x09, 0xb7, 0xdd, 0x84, 0xfb,
+                    0x86 ]
+            }
+        ]
+    }
+
+    fn run_test<E: BlockEncryptor, D: BlockDecryptor>(enc: &mut E, dec: &mut D, test: &Test) {
+        let mut tmp = [0u8; 16];
+        for data in test.data.iter() {
+            enc.encrypt_block(&data.plain[..], &mut tmp);
+            assert!(tmp[..] == data.cipher[..]);
+            dec.decrypt_block(&data.cipher[..], &mut tmp);
+            assert!(tmp[..] == data.plain[..]);
+        }
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[test]
+    fn test_aesni_128() {
+        if util::supports_aesni() {
+            let tests = tests128();
+            for t in tests.iter() {
+                let mut enc = aesni::AesNiEncryptor::new(KeySize128, &t.key[..]);
+                let mut dec = aesni::AesNiDecryptor::new(KeySize128, &t.key[..]);
+                run_test(&mut enc, &mut dec, t);
+            }
+        }
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[test]
+    fn test_aesni_192() {
+        if util::supports_aesni() {
+            let tests = tests192();
+            for t in tests.iter() {
+                let mut enc = aesni::AesNiEncryptor::new(KeySize192, &t.key[..]);
+                let mut dec = aesni::AesNiDecryptor::new(KeySize192, &t.key[..]);
+                run_test(&mut enc, &mut dec, t);
+            }
+        }
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[test]
+    fn test_aesni_256() {
+        if util::supports_aesni() {
+            let tests = tests256();
+            for t in tests.iter() {
+                let mut enc = aesni::AesNiEncryptor::new(KeySize256, &t.key[..]);
+                let mut dec = aesni::AesNiDecryptor::new(KeySize256, &t.key[..]);
+                run_test(&mut enc, &mut dec, t);
+            }
+        }
+    }
+
+    #[test]
+    fn test_aessafe_128() {
+        let tests = tests128();
+        for t in tests.iter() {
+            let mut enc = aessafe::AesSafe128Encryptor::new(&t.key[..]);
+            let mut dec = aessafe::AesSafe128Decryptor::new(&t.key[..]);
+            run_test(&mut enc, &mut dec, t);
+        }
+    }
+
+    #[test]
+    fn test_aessafe_192() {
+        let tests = tests192();
+        for t in tests.iter() {
+            let mut enc = aessafe::AesSafe192Encryptor::new(&t.key[..]);
+            let mut dec = aessafe::AesSafe192Decryptor::new(&t.key[..]);
+            run_test(&mut enc, &mut dec, t);
+        }
+    }
+
+    #[test]
+    fn test_aessafe_256() {
+        let tests = tests256();
+        for t in tests.iter() {
+            let mut enc = aessafe::AesSafe256Encryptor::new(&t.key[..]);
+            let mut dec = aessafe::AesSafe256Decryptor::new(&t.key[..]);
+            run_test(&mut enc, &mut dec, t);
+        }
+    }
+
+    // The following test vectors are all from NIST SP 800-38A
+
+    #[test]
+    fn test_aessafe_128_x8() {
+        let key: [u8; 16] = [
+            0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+            0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c ];
+        let plain: [u8; 128] = [
+            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ];
+        let cipher: [u8; 128] = [
+            0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
+            0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
+            0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d,
+            0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
+            0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23,
+            0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
+            0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f,
+            0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4,
+            0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
+            0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
+            0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d,
+            0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
+            0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23,
+            0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
+            0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f,
+            0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4 ];
+
+        let enc = aessafe::AesSafe128EncryptorX8::new(&key);
+        let dec = aessafe::AesSafe128DecryptorX8::new(&key);
+        let mut tmp = [0u8; 128];
+        enc.encrypt_block_x8(&plain, &mut tmp);
+        assert!(tmp[..] == cipher[..]);
+        dec.decrypt_block_x8(&cipher, &mut tmp);
+        assert!(tmp[..] == plain[..]);
+    }
+
+    #[test]
+    fn test_aessafe_192_x8() {
+        let key: [u8; 24] = [
+            0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b,
+            0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b ];
+        let plain: [u8; 128] = [
+            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ];
+        let cipher: [u8; 128] = [
+            0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f,
+            0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
+            0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad,
+            0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef,
+            0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a,
+            0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e,
+            0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72,
+            0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e,
+            0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f,
+            0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
+            0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad,
+            0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef,
+            0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a,
+            0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e,
+            0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72,
+            0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e ];
+
+        let enc = aessafe::AesSafe192EncryptorX8::new(&key);
+        let dec = aessafe::AesSafe192DecryptorX8::new(&key);
+        let mut tmp = [0u8; 128];
+        enc.encrypt_block_x8(&plain, &mut tmp);
+        assert!(tmp[..] == cipher[..]);
+        dec.decrypt_block_x8(&cipher, &mut tmp);
+        assert!(tmp[..] == plain[..]);
+    }
+
+    #[test]
+    fn test_aessafe_256_x8() {
+        let key: [u8; 32] = [
+            0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+            0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+            0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+            0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ];
+        let plain: [u8; 128] = [
+            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+            0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+            0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+            0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+            0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+            0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+            0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+            0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+            0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ];
+        let cipher: [u8; 128] = [
+            0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c,
+            0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
+            0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26,
+            0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
+            0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9,
+            0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
+            0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff,
+            0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7,
+            0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c,
+            0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
+            0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26,
+            0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
+            0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9,
+            0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
+            0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff,
+            0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7 ];
+
+        let enc = aessafe::AesSafe256EncryptorX8::new(&key);
+        let dec = aessafe::AesSafe256DecryptorX8::new(&key);
+        let mut tmp = [0u8; 128];
+        enc.encrypt_block_x8(&plain, &mut tmp);
+        assert!(tmp[..] == cipher[..]);
+        dec.decrypt_block_x8(&cipher, &mut tmp);
+        assert!(tmp[..] == plain[..]);
+    }
+
+    #[test]
+    fn aes_ctr_box() {
+        let tests = aes_ctr_tests();
+        for test in tests.iter() {
+            let mut aes_enc = aes::ctr(aes::KeySize::KeySize128, &test.key[..], &test.ctr[..]);
+            let mut result: Vec<u8> = repeat(0).take(test.plain.len()).collect();
+            aes_enc.process(&test.plain[..], &mut result[..]);
+            let res: &[u8] = result.as_ref();
+            assert!(res == &test.cipher[..]);
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    use aesni;
+
+    use aessafe;
+    use symmetriccipher::{BlockEncryptor, BlockEncryptorX8};
+    use util;
+    use aes::KeySize::{self, KeySize128, KeySize192, KeySize256};
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[bench]
+    pub fn aesni_128_bench(bh: &mut Bencher) {
+        aesni_bench(bh, KeySize128);
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[bench]
+    pub fn aesni_192_bench(bh: &mut Bencher) {
+        aesni_bench(bh, KeySize192);
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[bench]
+    pub fn aesni_256_bench(bh: &mut Bencher) {
+        aesni_bench(bh, KeySize256);
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn aesni_bench(bh: &mut Bencher, key_size: KeySize) {
+        if util::supports_aesni() {
+            let key: [u8; 16] = [1u8; 16];
+            let plain: [u8; 16] = [2u8; 16];
+
+            let a = aesni::AesNiEncryptor::new(key_size, &key);
+
+            let mut tmp = [0u8; 16];
+
+            bh.iter( || {
+                a.encrypt_block(&plain, &mut tmp);
+            });
+
+            bh.bytes = (plain.len()) as u64;
+        }
+    }
+
+    #[bench]
+    pub fn aes_safe_bench(bh: &mut Bencher) {
+        let key: [u8; 16] = [1u8; 16];
+        let plain: [u8; 16] = [2u8; 16];
+
+        let a = aessafe::AesSafe128Encryptor::new(&key);
+
+        let mut tmp = [0u8; 16];
+
+        bh.iter( || {
+            a.encrypt_block(&plain, &mut tmp);
+        });
+
+        bh.bytes = (plain.len()) as u64;
+    }
+
+    #[bench]
+    pub fn aes_safe_x8_bench(bh: &mut Bencher) {
+        let key: [u8; 16] = [1u8; 16];
+        let plain: [u8; 128] = [2u8; 128];
+
+        let a = aessafe::AesSafe128EncryptorX8::new(&key);
+
+        let mut tmp = [0u8; 128];
+
+        bh.iter( || {
+            a.encrypt_block_x8(&plain, &mut tmp);
+        });
+
+        bh.bytes = (plain.len()) as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/aes_gcm.rs b/third_party/rust-crypto/src/aes_gcm.rs
new file mode 100644
index 0000000..7b7cdb0
--- /dev/null
+++ b/third_party/rust-crypto/src/aes_gcm.rs
@@ -0,0 +1,275 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::prelude::v1::*;
+use aes::{ctr, KeySize};
+use aead::{AeadEncryptor,AeadDecryptor};
+use cryptoutil::copy_memory;
+use symmetriccipher::SynchronousStreamCipher;
+use ghash::{Ghash};
+use util::fixed_time_eq;
+
+pub struct AesGcm<'a> {
+    cipher: Box<SynchronousStreamCipher + 'a>,
+    mac: Ghash,
+    finished: bool,
+    end_tag: [u8; 16]
+}
+
+impl<'a> AesGcm<'a> {
+    pub fn new (key_size: KeySize, key: &[u8], nonce: &[u8], aad: &[u8]) -> AesGcm<'a> {
+        assert!(key.len() == 16 || key.len() == 24 || key.len() == 32);
+        assert!(nonce.len() == 12);
+
+        // GCM technically differs from CTR mode in how role overs are handled
+        // GCM only touches the right most 4 bytes while CTR roles all 16 over
+        // when the iv is only 96 bits (12 bytes) then 4 bytes of zeros are
+        // appended to it meaning you have to encrypt 2^37 bytes (256 gigabytes)
+        // of data before a difference crops up.
+        // The GCM handles nonces of other lengths by hashing them once with ghash
+        // this would cause the roleover behavior to potentially be triggered much
+        // earlier preventing the use of generic CTR mode.
+
+        let mut iv = [0u8; 16];
+        copy_memory(nonce, &mut iv);
+        iv[15] = 1u8;
+        let mut cipher = ctr(key_size,key,&iv);
+        let temp_block = [0u8; 16];
+        let mut final_block = [0u8; 16];
+        cipher.process(&temp_block, &mut final_block);
+        let mut hash_key =  [0u8; 16];
+        let mut encryptor = ctr(key_size,key,&temp_block);
+        encryptor.process(&temp_block, &mut hash_key);
+        AesGcm {
+            cipher: cipher,
+            mac:  Ghash::new(&hash_key).input_a(aad),
+            finished: false,
+            end_tag: final_block
+        }
+    }
+    
+}
+
+impl<'a> AeadEncryptor for AesGcm<'static> {
+    fn encrypt(&mut self, input: &[u8], output: &mut [u8], tag: &mut [u8]) {
+        assert!(input.len() == output.len());
+        assert!(!self.finished);
+        self.cipher.process(input, output);
+        let result = self.mac.input_c(output).result();
+        self.finished = true;
+        for i in 0..16 {
+            tag[i] = result[i] ^ self.end_tag[i];
+        }
+    }
+}
+
+impl<'a> AeadDecryptor for AesGcm<'static> {
+    fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8])  -> bool {
+        assert!(input.len() == output.len());
+        assert!(!self.finished);
+        self.finished = true;
+        let mut calc_tag = self.mac.input_c(input).result();
+        for i in 0..16 {
+            calc_tag[i] ^= self.end_tag[i];
+        }
+        if fixed_time_eq(&calc_tag, tag) {
+            self.cipher.process(input, output);
+            true
+        } else {
+            false
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use aes::KeySize;
+    use aes_gcm::AesGcm;
+    use aead::{AeadEncryptor, AeadDecryptor};
+    use serialize::hex::FromHex;
+    use std::iter::repeat;
+    fn hex_to_bytes(raw_hex: &str) -> Vec<u8> {
+        raw_hex.from_hex().ok().unwrap()
+    }
+    struct TestVector {
+                key:  Vec<u8>,
+                iv:  Vec<u8>,
+                plain_text: Vec<u8>,
+                cipher_text:  Vec<u8>,
+                aad: Vec<u8>,
+                tag:  Vec<u8>,
+            }
+
+    fn get_test_vectors()-> [TestVector; 5]{
+      [
+        TestVector {
+                key: hex_to_bytes("00000000000000000000000000000000"),
+                iv: hex_to_bytes("000000000000000000000000"),
+                plain_text: hex_to_bytes(""),
+                cipher_text: hex_to_bytes(""),
+                aad: hex_to_bytes(""),
+                tag: hex_to_bytes("58e2fccefa7e3061367f1d57a4e7455a")
+            },
+            TestVector {
+                key: hex_to_bytes("00000000000000000000000000000000"),
+                iv: hex_to_bytes("000000000000000000000000"),
+                plain_text: hex_to_bytes("00000000000000000000000000000000"),
+                cipher_text: hex_to_bytes("0388dace60b6a392f328c2b971b2fe78"),
+                aad: hex_to_bytes(""),
+                tag: hex_to_bytes("ab6e47d42cec13bdf53a67b21257bddf")
+            },
+            TestVector {
+                key: hex_to_bytes("feffe9928665731c6d6a8f9467308308"),
+                iv: hex_to_bytes("cafebabefacedbaddecaf888"),
+                plain_text: hex_to_bytes("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39"),
+                cipher_text: hex_to_bytes("42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091"),
+                aad: hex_to_bytes("feedfacedeadbeeffeedfacedeadbeefabaddad2"),
+                tag: hex_to_bytes("5bc94fbc3221a5db94fae95ae7121a47")
+            },
+            TestVector {
+                key: hex_to_bytes("feffe9928665731c6d6a8f9467308308feffe9928665731c"),
+                iv: hex_to_bytes("cafebabefacedbaddecaf888"),
+                plain_text: hex_to_bytes("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39"),
+                cipher_text: hex_to_bytes("3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710"),
+                aad: hex_to_bytes("feedfacedeadbeeffeedfacedeadbeefabaddad2"),
+                tag: hex_to_bytes("2519498e80f1478f37ba55bd6d27618c")
+            },
+            TestVector {
+                key: hex_to_bytes("feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308"),
+                iv: hex_to_bytes("cafebabefacedbaddecaf888"),
+                plain_text: hex_to_bytes("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39"),
+                cipher_text: hex_to_bytes("522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662"),
+                aad: hex_to_bytes("feedfacedeadbeeffeedfacedeadbeefabaddad2"),
+                tag: hex_to_bytes("76fc6ece0f4e1768cddf8853bb2d551b")
+            },
+    ]
+}
+    #[test]
+    fn aes_gcm_test() {
+            
+        for item in get_test_vectors().iter() {
+            let key_size = match item.key.len() {
+                16 => KeySize::KeySize128,
+                24 => KeySize::KeySize192,
+                32 => KeySize::KeySize256,
+                _ => unreachable!()
+            };
+            let mut cipher = AesGcm::new(key_size, &item.key[..], &item.iv[..], &item.aad[..]);
+            let mut out: Vec<u8> = repeat(0).take(item.plain_text.len()).collect();
+            
+            let mut out_tag: Vec<u8> = repeat(0).take(16).collect();
+            
+            cipher.encrypt(&item.plain_text[..], &mut out[..],&mut out_tag[..]);
+            assert_eq!(out, item.cipher_text);
+            assert_eq!(out_tag, item.tag);
+        }
+    }
+
+    #[test]
+    fn aes_gcm_decrypt_test() {
+            
+        for item in get_test_vectors().iter() {
+            let key_size = match item.key.len() {
+                16 => KeySize::KeySize128,
+                24 => KeySize::KeySize192,
+                32 => KeySize::KeySize256,
+                _ => unreachable!()
+            };
+            let mut decipher = AesGcm::new(key_size, &item.key[..], &item.iv[..], &item.aad[..]);
+            let mut out: Vec<u8> = repeat(0).take(item.plain_text.len()).collect();
+                        
+            let result = decipher.decrypt(&item.cipher_text[..], &mut out[..], &item.tag[..]);
+            assert_eq!(out, item.plain_text);
+            assert!(result);
+        }
+    }
+    #[test]
+    fn aes_gcm_decrypt_fail_test() {
+            
+        for item in get_test_vectors().iter() {
+            let key_size = match item.key.len() {
+                16 => KeySize::KeySize128,
+                24 => KeySize::KeySize192,
+                32 => KeySize::KeySize256,
+                _ => unreachable!()
+            };
+            let mut decipher = AesGcm::new(key_size, &item.key[..], &item.iv[..], &item.aad[..]);
+            let tag: Vec<u8> = repeat(0).take(16).collect();
+            let mut out1: Vec<u8> = repeat(0).take(item.plain_text.len()).collect();
+            let out2: Vec<u8> = repeat(0).take(item.plain_text.len()).collect();
+            let result = decipher.decrypt(&item.cipher_text[..], &mut out1[..], &tag[..]);
+            assert_eq!(out1, out2);
+            assert!(!result);
+        }
+    }
+
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use aes::KeySize;
+    use aes_gcm::AesGcm;
+    use aead::{AeadEncryptor, AeadDecryptor};
+
+    #[bench]
+    pub fn gsm_10(bh: & mut Bencher) {
+    	let input = [1u8; 10];
+    	let aad = [3u8; 10];
+    	bh.iter( || {
+	        let mut cipher = AesGcm::new(KeySize::KeySize256, &[0; 32], &[0; 12], &aad);
+	        let mut decipher = AesGcm::new(KeySize::KeySize256, &[0; 32], &[0; 12], &aad);
+	        
+	        let mut output = [0u8; 10];
+	        let mut tag = [0u8; 16];
+	        let mut output2 = [0u8; 10];
+            cipher.encrypt(&input, &mut output, &mut tag);
+            decipher.decrypt(&output, &mut output2, &tag);
+            
+        });
+        bh.bytes = 10u64;
+    }
+        
+
+    #[bench]
+    pub fn gsm_1k(bh: & mut Bencher) {
+    	let input = [1u8; 1024];
+    	let aad = [3u8; 1024];
+    	bh.iter( || {
+        let mut cipher = AesGcm::new(KeySize::KeySize256, &[0; 32], &[0; 12], &aad);
+        let mut decipher = AesGcm::new(KeySize::KeySize256, &[0; 32], &[0; 12], &aad);
+        
+        let mut output = [0u8; 1024];
+        let mut tag = [0u8; 16];
+        let mut output2 = [0u8; 1024];
+        
+            cipher.encrypt(&input, &mut output, &mut tag);
+            decipher.decrypt(&output, &mut output2, &tag);
+        });
+    	bh.bytes = 1024u64;
+        
+    }
+
+    #[bench]
+    pub fn gsm_64k(bh: & mut Bencher) {
+    	let input = [1u8; 65536];
+    	let aad = [3u8; 65536];
+    	  bh.iter( || {
+        let mut cipher = AesGcm::new(KeySize::KeySize256, &[0; 32], &[0; 12], &aad);
+        let mut decipher = AesGcm::new(KeySize::KeySize256, &[0; 32], &[0; 12], &aad);
+        
+        let mut output = [0u8; 65536];
+        let mut tag = [0u8; 16];
+        let mut output2 = [0u8; 65536];
+      
+            cipher.encrypt(&input, &mut output, &mut tag);
+            decipher.decrypt(&output, &mut output2, &tag);
+
+        });
+    	   bh.bytes = 65536u64;
+        
+    }
+}
diff --git a/third_party/rust-crypto/src/aesni.rs b/third_party/rust-crypto/src/aesni.rs
new file mode 100644
index 0000000..6edbb87
--- /dev/null
+++ b/third_party/rust-crypto/src/aesni.rs
@@ -0,0 +1,180 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use aes::KeySize;
+use aes::KeySize::{KeySize128, KeySize192, KeySize256};
+use symmetriccipher::{BlockEncryptor, BlockDecryptor};
+//use util::supports_aesni;
+
+#[derive(Copy)]
+pub struct AesNiEncryptor {
+    rounds: u8,
+    round_keys: [u8; 240]
+}
+
+impl Clone for AesNiEncryptor { fn clone(&self) -> AesNiEncryptor { *self } }
+
+#[derive(Copy)]
+pub struct AesNiDecryptor {
+    rounds: u8,
+    round_keys: [u8; 240]
+}
+
+impl Clone for AesNiDecryptor { fn clone(&self) -> AesNiDecryptor { *self } }
+
+/// The number of rounds as well as a function to setup an appropriately sized key.
+type RoundSetupInfo = (u8, fn(&[u8], KeyType, &mut [u8]));
+
+impl AesNiEncryptor {
+    pub fn new(key_size: KeySize, key: &[u8]) -> AesNiEncryptor {
+        //if !supports_aesni() {
+        //    panic!("AES-NI not supported on this architecture. If you are \
+        //        using the MSVC toolchain, this is because the AES-NI method's \
+        //        have not been ported, yet");
+        //}
+        //println!("enter AesNiEncryptor new");
+        let (rounds, setup_function): RoundSetupInfo = match key_size {
+            KeySize128 => (10, setup_working_key_aesni_128),
+            KeySize192 => (12, setup_working_key_aesni_192),
+            KeySize256 => (14, setup_working_key_aesni_256)
+        };
+        let mut e = AesNiEncryptor {
+            rounds: rounds,
+            round_keys: [0u8; 240]
+        };
+        setup_function(key, KeyType::Encryption, &mut e.round_keys[0..size(e.rounds)]);
+        e
+    }
+}
+
+impl AesNiDecryptor {
+    pub fn new(key_size: KeySize, key: &[u8]) -> AesNiDecryptor {
+        //if !supports_aesni() {
+        //    panic!("AES-NI not supported on this architecture. If you are \
+        //        using the MSVC toolchain, this is because the AES-NI method's \
+        //        have not been ported, yet");
+        //}
+        let (rounds, setup_function): RoundSetupInfo = match key_size {
+            KeySize128 => (10, setup_working_key_aesni_128),
+            KeySize192 => (12, setup_working_key_aesni_192),
+            KeySize256 => (14, setup_working_key_aesni_256)
+        };
+        let mut d = AesNiDecryptor {
+            rounds: rounds,
+            round_keys: [0u8; 240]
+        };
+        setup_function(key, KeyType::Decryption, &mut d.round_keys[0..size(d.rounds)]);
+        d
+    }
+
+}
+
+impl BlockEncryptor for AesNiEncryptor {
+    fn block_size(&self) -> usize { 16 }
+    fn encrypt_block(&self, input: &[u8], output: &mut [u8]) {
+        encrypt_block_aesni(self.rounds, input, &self.round_keys[0..size(self.rounds)], output);
+    }
+}
+
+impl BlockDecryptor for AesNiDecryptor {
+    fn block_size(&self) -> usize { 16 }
+    fn decrypt_block(&self, input: &[u8], output: &mut [u8]) {
+        decrypt_block_aesni(self.rounds, input, &self.round_keys[0..size(self.rounds)], output);
+    }
+}
+
+enum KeyType {
+    Encryption,
+    Decryption
+}
+
+#[inline(always)]
+fn size(rounds: u8) -> usize { 16 * ((rounds as usize) + 1) }
+
+extern {
+    fn rust_crypto_aesni_aesimc(round_keys: *mut u8);
+    fn rust_crypto_aesni_setup_working_key_128(key: *const u8, round_key: *mut u8);
+    fn rust_crypto_aesni_setup_working_key_192(key: *const u8, round_key: *mut u8);
+    fn rust_crypto_aesni_setup_working_key_256(key: *const u8, round_key: *mut u8);
+    fn rust_crypto_aesni_encrypt_block(
+            rounds: u8,
+            input: *const u8,
+            round_keys: *const u8,
+            output: *mut u8);
+    fn rust_crypto_aesni_decrypt_block(
+            rounds: u8,
+            input: *const u8,
+            round_keys: *const u8,
+            output: *mut u8);
+}
+
+fn setup_working_key_aesni_128(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
+    unsafe {
+        rust_crypto_aesni_setup_working_key_128(key.as_ptr(), round_key.as_mut_ptr());
+
+        match key_type {
+            KeyType::Decryption => {
+                // range of rounds keys from #1 to #9; skip the first and last key
+                for i in 1..10 {
+                    rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
+                }
+            }
+            KeyType::Encryption => { /* nothing more to do */ }
+        }
+    }
+}
+
+fn setup_working_key_aesni_192(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
+    unsafe {
+        rust_crypto_aesni_setup_working_key_192(key.as_ptr(), round_key.as_mut_ptr());
+
+        match key_type {
+            KeyType::Decryption => {
+                // range of rounds keys from #1 to #11; skip the first and last key
+                for i in 1..12 {
+                    rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
+                }
+            }
+            KeyType::Encryption => { /* nothing more to do */ }
+        }
+    }
+}
+
+fn setup_working_key_aesni_256(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
+    unsafe {
+        rust_crypto_aesni_setup_working_key_256(key.as_ptr(), round_key.as_mut_ptr());
+
+        match key_type {
+            KeyType::Decryption => {
+                // range of rounds keys from #1 to #13; skip the first and last key
+                for i in 1..14 {
+                    rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
+                }
+            }
+            KeyType::Encryption => { /* nothing more to do */ }
+        }
+    }
+}
+
+fn encrypt_block_aesni(rounds: u8, input: &[u8], round_keys: &[u8], output: &mut [u8]) {
+    unsafe {
+        rust_crypto_aesni_encrypt_block(
+                rounds,
+                input.as_ptr(),
+                round_keys.as_ptr(),
+                output.as_mut_ptr());
+    }
+}
+
+fn decrypt_block_aesni(rounds: u8, input: &[u8], round_keys: &[u8], output: &mut [u8]) {
+    unsafe {
+        rust_crypto_aesni_decrypt_block(
+                rounds as u8,
+                input.as_ptr(),
+                round_keys.get_unchecked(round_keys.len() - 16),
+                output.as_mut_ptr());
+    }
+}
diff --git a/third_party/rust-crypto/src/aesni_helpers.asm b/third_party/rust-crypto/src/aesni_helpers.asm
new file mode 100755
index 0000000..ce5fa0e
--- /dev/null
+++ b/third_party/rust-crypto/src/aesni_helpers.asm
@@ -0,0 +1,34 @@
+ifndef X64
+.686p
+.XMM
+.model flat, C
+endif
+
+.code
+
+rust_crypto_aesni_aesimc PROC public
+  ret
+rust_crypto_aesni_aesimc ENDP
+
+rust_crypto_aesni_setup_working_key_128 PROC public
+  ret
+rust_crypto_aesni_setup_working_key_128 ENDP
+
+rust_crypto_aesni_setup_working_key_192 PROC public
+  ret
+rust_crypto_aesni_setup_working_key_192 ENDP
+
+rust_crypto_aesni_setup_working_key_256 PROC public
+  ret
+rust_crypto_aesni_setup_working_key_256 ENDP
+
+rust_crypto_aesni_encrypt_block PROC public
+  ret
+rust_crypto_aesni_encrypt_block ENDP
+
+rust_crypto_aesni_decrypt_block PROC public
+  ret
+rust_crypto_aesni_decrypt_block ENDP
+
+end
+
diff --git a/third_party/rust-crypto/src/aesni_helpers.c b/third_party/rust-crypto/src/aesni_helpers.c
new file mode 100644
index 0000000..fa49290
--- /dev/null
+++ b/third_party/rust-crypto/src/aesni_helpers.c
@@ -0,0 +1,360 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(__i386__) || defined(__x86_64__)
+
+void rust_crypto_aesni_aesimc(uint8_t* round_keys) {
+    #ifdef __SSE__
+    asm volatile(
+        " \
+            movdqu (%0), %%xmm1; \
+            aesimc %%xmm1, %%xmm1; \
+            movdqu %%xmm1, (%0); \
+        "
+    : // outputs
+    : "r" (round_keys) // inputs
+    : "xmm1", "memory" // clobbers
+    );
+    #else
+    exit(1);
+    #endif
+}
+
+void rust_crypto_aesni_setup_working_key_128(
+        uint8_t* key,
+        uint8_t* round_key) {
+    #ifdef __SSE__
+    asm volatile(
+        " \
+            movdqu (%1), %%xmm1; \
+            movdqu %%xmm1, (%0); \
+            add $0x10, %0; \
+            \
+            aeskeygenassist $0x01, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x02, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x04, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x08, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x10, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x20, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x40, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x80, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x1b, %%xmm1, %%xmm2; \
+            call 1f; \
+            aeskeygenassist $0x36, %%xmm1, %%xmm2; \
+            call 1f; \
+            \
+            jmp 2f; \
+            \
+            1: \
+            pshufd $0xff, %%xmm2, %%xmm2; \
+            vpslldq $0x04, %%xmm1, %%xmm3; \
+            pxor %%xmm3, %%xmm1; \
+            vpslldq $0x4, %%xmm1, %%xmm3; \
+            pxor %%xmm3, %%xmm1; \
+            vpslldq $0x04, %%xmm1, %%xmm3; \
+            pxor %%xmm3, %%xmm1; \
+            pxor %%xmm2, %%xmm1; \
+            movdqu %%xmm1, (%0); \
+            add $0x10, %0; \
+            ret; \
+            \
+            2: \
+        "
+    : "+r" (round_key)
+    : "r" (key)
+    : "xmm1", "xmm2", "xmm3", "memory"
+    );
+    #else
+    exit(1);
+    #endif
+}
+
+void rust_crypto_aesni_setup_working_key_192(
+        uint8_t* key,
+        uint8_t* round_key) {
+    #ifdef __SSE__
+    asm volatile(
+        " \
+            movdqu (%1), %%xmm1; \
+            movdqu 16(%1), %%xmm3; \
+            movdqu %%xmm1, (%0); \
+            movdqa %%xmm3, %%xmm5; \
+            \
+            aeskeygenassist $0x1, %%xmm3, %%xmm2; \
+            call 1f; \
+            shufpd $0, %%xmm1, %%xmm5; \
+            movdqu %%xmm5, 16(%0); \
+            movdqa %%xmm1, %%xmm6; \
+            shufpd $1, %%xmm3, %%xmm6; \
+            movdqu %%xmm6, 32(%0); \
+            \
+            aeskeygenassist $0x2, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 48(%0); \
+            movdqa %%xmm3, %%xmm5; \
+            \
+            aeskeygenassist $0x4, %%xmm3, %%xmm2; \
+            call 1f; \
+            shufpd $0, %%xmm1, %%xmm5; \
+            movdqu %%xmm5, 64(%0); \
+            movdqa %%xmm1, %%xmm6; \
+            shufpd $1, %%xmm3, %%xmm6; \
+            movdqu %%xmm6, 80(%0); \
+            \
+            aeskeygenassist $0x8, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 96(%0); \
+            movdqa %%xmm3, %%xmm5; \
+            \
+            aeskeygenassist $0x10, %%xmm3, %%xmm2; \
+            call 1f; \
+            shufpd $0, %%xmm1, %%xmm5; \
+            movdqu %%xmm5, 112(%0); \
+            movdqa %%xmm1, %%xmm6; \
+            shufpd $1, %%xmm3, %%xmm6; \
+            movdqu %%xmm6, 128(%0); \
+            \
+            aeskeygenassist $0x20, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 144(%0); \
+            movdqa %%xmm3, %%xmm5; \
+            \
+            aeskeygenassist $0x40, %%xmm3, %%xmm2; \
+            call 1f; \
+            shufpd $0, %%xmm1, %%xmm5; \
+            movdqu %%xmm5, 160(%0); \
+            movdqa %%xmm1, %%xmm6; \
+            shufpd $1, %%xmm3, %%xmm6; \
+            movdqu %%xmm6, 176(%0); \
+            \
+            aeskeygenassist $0x80, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 192(%0); \
+            \
+            jmp 2f; \
+            \
+            1: \
+            pshufd $0x55, %%xmm2, %%xmm2; \
+            movdqu %%xmm1, %%xmm4; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm1; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm1; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm1; \
+            pxor %%xmm2, %%xmm1; \
+            pshufd $0xff, %%xmm1, %%xmm2; \
+            movdqu %%xmm3, %%xmm4; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm3; \
+            pxor %%xmm2, %%xmm3; \
+            ret; \
+            \
+            2: \
+        "
+    : "+r" (round_key)
+    : "r" (key)
+    : "xmm1", "xmm2", "xmm3", "memory"
+    );
+    #else
+    exit(1);
+    #endif
+}
+
+void rust_crypto_aesni_setup_working_key_256(
+        uint8_t* key,
+        uint8_t* round_key) {
+    #ifdef __SSE__
+    asm volatile(
+        " \
+            movdqu (%1), %%xmm1; \
+            movdqu 16(%1), %%xmm3; \
+            movdqu %%xmm1, (%0); \
+            movdqu %%xmm3, 16(%0); \
+            \
+            aeskeygenassist $0x1, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 32(%0); \
+            \
+            aeskeygenassist $0x0, %%xmm1, %%xmm2; \
+            call 2f; \
+            movdqu %%xmm3, 48(%0); \
+            \
+            aeskeygenassist $0x2, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 64(%0); \
+            \
+            aeskeygenassist $0x0, %%xmm1, %%xmm2; \
+            call 2f; \
+            movdqu %%xmm3, 80(%0); \
+            \
+            aeskeygenassist $0x4, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 96(%0); \
+            \
+            aeskeygenassist $0x0, %%xmm1, %%xmm2; \
+            call 2f; \
+            movdqu %%xmm3, 112(%0); \
+            \
+            aeskeygenassist $0x8, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 128(%0); \
+            \
+            aeskeygenassist $0x0, %%xmm1, %%xmm2; \
+            call 2f; \
+            movdqu %%xmm3, 144(%0); \
+            \
+            aeskeygenassist $0x10, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 160(%0); \
+            \
+            aeskeygenassist $0x0, %%xmm1, %%xmm2; \
+            call 2f; \
+            movdqu %%xmm3, 176(%0); \
+            \
+            aeskeygenassist $0x20, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 192(%0); \
+            \
+            aeskeygenassist $0x0, %%xmm1, %%xmm2; \
+            call 2f; \
+            movdqu %%xmm3, 208(%0); \
+            \
+            aeskeygenassist $0x40, %%xmm3, %%xmm2; \
+            call 1f; \
+            movdqu %%xmm1, 224(%0); \
+            \
+            jmp 3f; \
+            \
+            1: \
+            pshufd $0xff, %%xmm2, %%xmm2; \
+            movdqa %%xmm1, %%xmm4; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm1; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm1; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm1; \
+            pxor %%xmm2, %%xmm1; \
+            ret; \
+            \
+            2: \
+            pshufd $0xaa, %%xmm2, %%xmm2; \
+            movdqa %%xmm3, %%xmm4; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm3; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm3; \
+            pslldq $4, %%xmm4; \
+            pxor %%xmm4, %%xmm3; \
+            pxor %%xmm2, %%xmm3; \
+            ret; \
+            \
+            3: \
+        "
+    : "+r" (round_key)
+    : "r" (key)
+    : "xmm1", "xmm2", "xmm3", "memory"
+    );
+    #else
+    exit(1);
+    #endif
+}
+
+void rust_crypto_aesni_encrypt_block(
+            uint8_t rounds,
+            uint8_t* input,
+            uint8_t* round_keys,
+            uint8_t* output) {
+    #ifdef __SSE__
+    asm volatile(
+    " \
+        /* Copy the data to encrypt to xmm1 */ \
+        movdqu (%2), %%xmm1; \
+        \
+        /* Perform round 0 - the whitening step */ \
+        movdqu (%1), %%xmm0; \
+        add $0x10, %1; \
+        pxor %%xmm0, %%xmm1; \
+        \
+        /* Perform all remaining rounds (except the final one) */ \
+        1: \
+        movdqu (%1), %%xmm0; \
+        add $0x10, %1; \
+        aesenc %%xmm0, %%xmm1; \
+        sub $0x01, %0; \
+        cmp $0x01, %0; \
+        jne 1b; \
+        \
+        /* Perform the last round */ \
+        movdqu (%1), %%xmm0; \
+        aesenclast %%xmm0, %%xmm1; \
+        \
+        /* Finally, move the result from xmm1 to outp */ \
+        movdqu %%xmm1, (%3); \
+    "
+    : "+&r" (rounds), "+&r" (round_keys) // outputs
+    : "r" (input), "r" (output) // inputs
+    : "xmm0", "xmm1", "memory", "cc" // clobbers
+    );
+    #else
+    exit(1);
+    #endif
+}
+
+void rust_crypto_aesni_decrypt_block(
+            uint8_t rounds,
+            uint8_t* input,
+            uint8_t* round_keys,
+            uint8_t* output) {
+    #ifdef __SSE__
+    asm volatile(
+        " \
+            /* Copy the data to decrypt to xmm1 */ \
+            movdqu (%2), %%xmm1; \
+            \
+            /* Perform round 0 - the whitening step */ \
+            movdqu (%1), %%xmm0; \
+            sub $0x10, %1; \
+            pxor %%xmm0, %%xmm1; \
+            \
+            /* Perform all remaining rounds (except the final one) */ \
+            1: \
+            movdqu (%1), %%xmm0; \
+            sub $0x10, %1; \
+            aesdec %%xmm0, %%xmm1; \
+            sub $0x01, %0; \
+            cmp $0x01, %0; \
+            jne 1b; \
+            \
+            /* Perform the last round */ \
+            movdqu (%1), %%xmm0; \
+            aesdeclast %%xmm0, %%xmm1; \
+            \
+            /* Finally, move the result from xmm1 to outp */ \
+            movdqu %%xmm1, (%3); \
+        "
+    : "+&r" (rounds), "+&r" (round_keys) // outputs
+    : "r" (input), "r" (output) // inputs
+    : "xmm0", "xmm1", "memory", "cc" // clobbers
+    );
+    #else
+    exit(1);
+    #endif
+}
+
+#endif
diff --git a/third_party/rust-crypto/src/aessafe.rs b/third_party/rust-crypto/src/aessafe.rs
new file mode 100644
index 0000000..82fda89
--- /dev/null
+++ b/third_party/rust-crypto/src/aessafe.rs
@@ -0,0 +1,1231 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+
+The `aessafe` module implements the AES algorithm completely in software without using any table
+lookups or other timing dependant mechanisms. This module actually contains two seperate
+implementations - an implementation that works on a single block at a time and a second
+implementation that processes 8 blocks in parallel. Some block encryption modes really only work if
+you are processing a single blocks (CFB, OFB, and CBC encryption for example) while other modes
+are trivially parallelizable (CTR and CBC decryption). Processing more blocks at once allows for
+greater efficiency, especially when using wide registers, such as the XMM registers available in
+x86 processors.
+
+## AES Algorithm
+
+There are lots of places to go to on the internet for an involved description of how AES works. For
+the purposes of this description, it sufficies to say that AES is just a block cipher that takes
+a key of 16, 24, or 32 bytes and uses that to either encrypt or decrypt a block of 16 bytes. An
+encryption or decryption operation consists of a number of rounds which involve some combination of
+the following 4 basic operations:
+
+* ShiftRows
+* MixColumns
+* SubBytes
+* AddRoundKey
+
+## Timing problems
+
+Most software implementations of AES use a large set of lookup tables - generally at least the
+SubBytes step is implemented via lookup tables; faster implementations generally implement the
+MixColumns step this way as well. This is largely a design flaw in the AES implementation as it was
+not realized during the NIST standardization process that table lookups can lead to security
+problems [1]. The issue is that not all table lookups occur in constant time - an address that was
+recently used is looked up much faster than one that hasn't been used in a while. A careful
+adversary can measure the amount of time that each AES operation takes and use that information to
+help determine the secret key or plain text information. More specifically, its not table lookups
+that lead to these types of timing attacks - the issue is table lookups that use secret information
+as part of the address to lookup. A table lookup that is performed the exact same way every time
+regardless of the key or plaintext doesn't leak any information. This implementation uses no data
+dependant table lookups.
+
+## Bit Slicing
+
+Bit Slicing is a technique that is basically a software emulation of hardware implementation
+techniques. One of the earliest implementations of this technique was for a DES implementation [4].
+In hardware, table lookups do not present the same timing problems as they do in software, however
+they present other problems - namely that a 256 byte S-box table takes up a huge amount of space on
+a chip. Hardware implementations, thus, tend to avoid table lookups and instead calculate the
+contents of the S-Boxes as part of every operation. So, the key to an efficient Bit Sliced software
+implementation is to re-arrange all of the bits of data to process into a form that can easily be
+applied in much the same way that it would be in hardeware. It is fortunate, that AES was designed
+such that these types of hardware implementations could be very efficient - the contents of the
+S-boxes are defined by a mathematical formula.
+
+A hardware implementation works on single bits at a time. Unlike adding variables in software,
+however, that occur generally one at a time, hardware implementations are extremely parallel and
+operate on many, many bits at once. Bit Slicing emulates that by moving all "equivalent" bits into
+common registers and then operating on large groups of bits all at once. Calculating the S-box value
+for a single bit is extremely expensive, but its much cheaper when you can amortize that cost over
+128 bits (as in an XMM register). This implementation follows the same strategy as in [5] and that
+is an excellent source for more specific details. However, a short description follows.
+
+The input data is simply a collection of bytes. Each byte is comprised of 8 bits, a low order bit
+(bit 0) through a high order bit (bit 7). Bit slicing the input data simply takes all of the low
+order bits (bit 0) from the input data, and moves them into a single register (eg: XMM0). Next, all
+of them 2nd lowest bits are moved into their own register (eg: XMM1), and so on. After completion,
+we're left with 8 variables, each of which contains an equivalent set of bits. The exact order of
+those bits is irrevent for the implementation of the SubBytes step, however, it is very important
+for the MixColumns step. Again, see [5] for details. Due to the design of AES, its them possible to
+execute the entire AES operation using just bitwise exclusive ors and rotates once we have Bit
+Sliced the input data. After the completion of the AES operation, we then un-Bit Slice the data
+to give us our output. Clearly, the more bits that we can process at once, the faster this will go -
+thus, the version that processes 8 blocks at once is roughly 8 times faster than processing just a
+single block at a time.
+
+The ShiftRows step is fairly straight-forward to implement on the Bit Sliced state. The MixColumns
+and especially the SubBytes steps are more complicated. This implementation draws heavily on the
+formulas from [5], [6], and [7] to implement these steps.
+
+## Implementation
+
+Both implementations work basically the same way and share pretty much all of their code. The key
+is first processed to create all of the round keys where each round key is just a 16 byte chunk of
+data that is combined into the AES state by the AddRoundKey step as part of each encryption or
+decryption round. Processing the round key can be expensive, so this is done before encryption or
+decryption. Before encrypting or decrypting data, the data to be processed by be Bit Sliced into 8
+seperate variables where each variable holds equivalent bytes from the state. This Bit Sliced state
+is stored as a Bs8State<T>, where T is the type that stores each set of bits. The first
+implementation stores these bits in a u32 which permits up to 8 * 32 = 1024 bits of data to be
+processed at once. This implementation only processes a single block at a time, so, in reality, only
+512 bits are processed at once and the remaining 512 bits of the variables are unused. The 2nd
+implementation uses u32x4s - vectors of 4 u32s. Thus, we can process 8 * 128 = 4096 bits at once,
+which corresponds exactly to 8 blocks.
+
+The Bs8State struct implements the AesOps trait, which contains methods for each of the 4 main steps
+of the AES algorithm. The types, T, each implement the AesBitValueOps trait, which containts methods
+necessary for processing a collection or bit values and the AesOps trait relies heavily on this
+trait to perform its operations.
+
+The Bs4State and Bs2State struct implement operations of various subfields of the full GF(2^8)
+finite field which allows for efficient computation of the AES S-Boxes. See [7] for details.
+
+## References
+
+[1] - "Cache-Collision Timing Attacks Against AES". Joseph Bonneau and Ilya Mironov.
+      http://www.jbonneau.com/doc/BM06-CHES-aes_cache_timing.pdf
+[2] - "Software mitigations to hedge AES against cache-based software side channel vulnerabilities".
+      Ernie Brickell, et al. http://eprint.iacr.org/2006/052.pdf.
+[3] - "Cache Attacks and Countermeasures: the Case of AES (Extended Version)".
+      Dag Arne Osvik, et al. tau.ac.il/~tromer/papers/cache.pdf‎.
+[4] - "A Fast New DES Implementation in Software". Eli Biham.
+      http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.52.5429&rep=rep1&type=pdf.
+[5] - "Faster and Timing-Attack Resistant AES-GCM". Emilia K ̈asper and Peter Schwabe.
+      http://www.chesworkshop.org/ches2009/presentations/01_Session_1/CHES2009_ekasper.pdf.
+[6] - "FAST AES DECRYPTION". Vinit Azad. http://webcache.googleusercontent.com/
+      search?q=cache:ld_f8pSgURcJ:csusdspace.calstate.edu/bitstream/handle/10211.9/1224/
+      Vinit_Azad_MS_Report.doc%3Fsequence%3D2+&cd=4&hl=en&ct=clnk&gl=us&client=ubuntu.
+[7] - "A Very Compact Rijndael S-box". D. Canright.
+      http://www.dtic.mil/cgi-bin/GetTRDoc?AD=ADA434781.
+*/
+
+use std::ops::{BitAnd, BitXor, Not};
+use std::default::Default;
+
+use cryptoutil::{read_u32v_le, write_u32_le};
+use simd::u32x4;
+use step_by::RangeExt;
+use symmetriccipher::{BlockEncryptor, BlockEncryptorX8, BlockDecryptor, BlockDecryptorX8};
+
+const U32X4_0: u32x4 = u32x4(0, 0, 0, 0);
+const U32X4_1: u32x4 = u32x4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
+
+macro_rules! define_aes_struct(
+    (
+        $name:ident,
+        $rounds:expr
+    ) => (
+        #[derive(Clone, Copy)]
+        pub struct $name {
+            sk: [Bs8State<u16>; ($rounds + 1)]
+        }
+    )
+);
+
+macro_rules! define_aes_impl(
+    (
+        $name:ident,
+        $mode:ident,
+        $rounds:expr,
+        $key_size:expr
+    ) => (
+        impl $name {
+            pub fn new(key: &[u8]) -> $name {
+                let mut a =  $name {
+                    sk: [Bs8State(0, 0, 0, 0, 0, 0, 0, 0); ($rounds + 1)]
+                };
+                let mut tmp = [[0u32; 4]; ($rounds + 1)];
+                create_round_keys(key, KeyType::$mode, &mut tmp);
+                for i in 0..$rounds + 1 {
+                    a.sk[i] = bit_slice_4x4_with_u16(tmp[i][0], tmp[i][1], tmp[i][2], tmp[i][3]);
+                }
+                a
+            }
+        }
+    )
+);
+
+macro_rules! define_aes_enc(
+    (
+        $name:ident,
+        $rounds:expr
+    ) => (
+        impl BlockEncryptor for $name {
+            fn block_size(&self) -> usize { 16 }
+            fn encrypt_block(&self, input: &[u8], output: &mut [u8]) {
+                let mut bs = bit_slice_1x16_with_u16(input);
+                bs = encrypt_core(&bs, &self.sk);
+                un_bit_slice_1x16_with_u16(&bs, output);
+            }
+        }
+    )
+);
+
+macro_rules! define_aes_dec(
+    (
+        $name:ident,
+        $rounds:expr
+    ) => (
+        impl BlockDecryptor for $name {
+            fn block_size(&self) -> usize { 16 }
+            fn decrypt_block(&self, input: &[u8], output: &mut [u8]) {
+                let mut bs = bit_slice_1x16_with_u16(input);
+                bs = decrypt_core(&bs, &self.sk);
+                un_bit_slice_1x16_with_u16(&bs, output);
+            }
+        }
+    )
+);
+
+define_aes_struct!(AesSafe128Encryptor, 10);
+define_aes_struct!(AesSafe128Decryptor, 10);
+define_aes_impl!(AesSafe128Encryptor, Encryption, 10, 16);
+define_aes_impl!(AesSafe128Decryptor, Decryption, 10, 16);
+define_aes_enc!(AesSafe128Encryptor, 10);
+define_aes_dec!(AesSafe128Decryptor, 10);
+
+define_aes_struct!(AesSafe192Encryptor, 12);
+define_aes_struct!(AesSafe192Decryptor, 12);
+define_aes_impl!(AesSafe192Encryptor, Encryption, 12, 24);
+define_aes_impl!(AesSafe192Decryptor, Decryption, 12, 24);
+define_aes_enc!(AesSafe192Encryptor, 12);
+define_aes_dec!(AesSafe192Decryptor, 12);
+
+define_aes_struct!(AesSafe256Encryptor, 14);
+define_aes_struct!(AesSafe256Decryptor, 14);
+define_aes_impl!(AesSafe256Encryptor, Encryption, 14, 32);
+define_aes_impl!(AesSafe256Decryptor, Decryption, 14, 32);
+define_aes_enc!(AesSafe256Encryptor, 14);
+define_aes_dec!(AesSafe256Decryptor, 14);
+
+macro_rules! define_aes_struct_x8(
+    (
+        $name:ident,
+        $rounds:expr
+    ) => (
+        #[derive(Clone, Copy)]
+        pub struct $name {
+            sk: [Bs8State<u32x4>; ($rounds + 1)]
+        }
+    )
+);
+
+macro_rules! define_aes_impl_x8(
+    (
+        $name:ident,
+        $mode:ident,
+        $rounds:expr,
+        $key_size:expr
+    ) => (
+        impl $name {
+            pub fn new(key: &[u8]) -> $name {
+                let mut a =  $name {
+                    sk: [
+                        Bs8State(
+                            U32X4_0,
+                            U32X4_0,
+                            U32X4_0,
+                            U32X4_0,
+                            U32X4_0,
+                            U32X4_0,
+                            U32X4_0,
+                            U32X4_0);
+                        ($rounds + 1)]
+                };
+                let mut tmp = [[0u32; 4]; ($rounds + 1)];
+                create_round_keys(key, KeyType::$mode, &mut tmp);
+                for i in 0..$rounds + 1 {
+                    a.sk[i] = bit_slice_fill_4x4_with_u32x4(
+                        tmp[i][0],
+                        tmp[i][1],
+                        tmp[i][2],
+                        tmp[i][3]);
+                }
+                a
+            }
+        }
+    )
+);
+
+macro_rules! define_aes_enc_x8(
+    (
+        $name:ident,
+        $rounds:expr
+    ) => (
+        impl BlockEncryptorX8 for $name {
+            fn block_size(&self) -> usize { 16 }
+            fn encrypt_block_x8(&self, input: &[u8], output: &mut [u8]) {
+                let bs = bit_slice_1x128_with_u32x4(input);
+                let bs2 = encrypt_core(&bs, &self.sk);
+                un_bit_slice_1x128_with_u32x4(bs2, output);
+            }
+        }
+    )
+);
+
+macro_rules! define_aes_dec_x8(
+    (
+        $name:ident,
+        $rounds:expr
+    ) => (
+        impl BlockDecryptorX8 for $name {
+            fn block_size(&self) -> usize { 16 }
+            fn decrypt_block_x8(&self, input: &[u8], output: &mut [u8]) {
+                let bs = bit_slice_1x128_with_u32x4(input);
+                let bs2 = decrypt_core(&bs, &self.sk);
+                un_bit_slice_1x128_with_u32x4(bs2, output);
+            }
+        }
+    )
+);
+
+define_aes_struct_x8!(AesSafe128EncryptorX8, 10);
+define_aes_struct_x8!(AesSafe128DecryptorX8, 10);
+define_aes_impl_x8!(AesSafe128EncryptorX8, Encryption, 10, 16);
+define_aes_impl_x8!(AesSafe128DecryptorX8, Decryption, 10, 16);
+define_aes_enc_x8!(AesSafe128EncryptorX8, 10);
+define_aes_dec_x8!(AesSafe128DecryptorX8, 10);
+
+define_aes_struct_x8!(AesSafe192EncryptorX8, 12);
+define_aes_struct_x8!(AesSafe192DecryptorX8, 12);
+define_aes_impl_x8!(AesSafe192EncryptorX8, Encryption, 12, 24);
+define_aes_impl_x8!(AesSafe192DecryptorX8, Decryption, 12, 24);
+define_aes_enc_x8!(AesSafe192EncryptorX8, 12);
+define_aes_dec_x8!(AesSafe192DecryptorX8, 12);
+
+define_aes_struct_x8!(AesSafe256EncryptorX8, 14);
+define_aes_struct_x8!(AesSafe256DecryptorX8, 14);
+define_aes_impl_x8!(AesSafe256EncryptorX8, Encryption, 14, 32);
+define_aes_impl_x8!(AesSafe256DecryptorX8, Decryption, 14, 32);
+define_aes_enc_x8!(AesSafe256EncryptorX8, 14);
+define_aes_dec_x8!(AesSafe256DecryptorX8, 14);
+
+fn ffmulx(x: u32) -> u32 {
+    let m1: u32 = 0x80808080;
+    let m2: u32 = 0x7f7f7f7f;
+    let m3: u32 = 0x0000001b;
+    ((x & m2) << 1) ^ (((x & m1) >> 7) * m3)
+}
+
+fn inv_mcol(x: u32) -> u32 {
+    let f2 = ffmulx(x);
+    let f4 = ffmulx(f2);
+    let f8 = ffmulx(f4);
+    let f9 = x ^ f8;
+
+    f2 ^ f4 ^ f8 ^ (f2 ^ f9).rotate_right(8) ^ (f4 ^ f9).rotate_right(16) ^ f9.rotate_right(24)
+}
+
+fn sub_word(x: u32) -> u32 {
+    let bs = bit_slice_4x1_with_u16(x).sub_bytes();
+    un_bit_slice_4x1_with_u16(&bs)
+}
+
+enum KeyType {
+    Encryption,
+    Decryption
+}
+
+// This array is not accessed in any key-dependant way, so there are no timing problems inherent in
+// using it.
+static RCON: [u32; 10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
+
+// The round keys are created without bit-slicing the key data. The individual implementations bit
+// slice the round keys returned from this function. This function, and the few functions above, are
+// derived from the BouncyCastle AES implementation.
+fn create_round_keys(key: &[u8], key_type: KeyType, round_keys: &mut [[u32; 4]]) {
+    let (key_words, rounds) = match key.len() {
+        16 => (4, 10),
+        24 => (6, 12),
+        32 => (8, 14),
+        _ => panic!("Invalid AES key size.")
+    };
+
+    // The key is copied directly into the first few round keys
+    let mut j = 0;
+    for i in (0..key.len()).step_up(4) {
+        round_keys[j / 4][j % 4] =
+            (key[i] as u32) |
+            ((key[i+1] as u32) << 8) |
+            ((key[i+2] as u32) << 16) |
+            ((key[i+3] as u32) << 24);
+        j += 1;
+    };
+
+    // Calculate the rest of the round keys
+    for i in key_words..(rounds + 1) * 4 {
+        let mut tmp = round_keys[(i - 1) / 4][(i - 1) % 4];
+        if (i % key_words) == 0 {
+            tmp = sub_word(tmp.rotate_right(8)) ^ RCON[(i / key_words) - 1];
+        } else if (key_words == 8) && ((i % key_words) == 4) {
+            // This is only necessary for AES-256 keys
+            tmp = sub_word(tmp);
+        }
+        round_keys[i / 4][i % 4] = round_keys[(i - key_words) / 4][(i - key_words) % 4] ^ tmp;
+    }
+
+    // Decryption round keys require extra processing
+    match key_type {
+        KeyType::Decryption => {
+            for j in 1..rounds {
+                for i in 0..4 {
+                    round_keys[j][i] = inv_mcol(round_keys[j][i]);
+                }
+            }
+        },
+        KeyType::Encryption => { }
+    }
+}
+
+// This trait defines all of the operations needed for a type to be processed as part of an AES
+// encryption or decryption operation.
+trait AesOps {
+    fn sub_bytes(self) -> Self;
+    fn inv_sub_bytes(self) -> Self;
+    fn shift_rows(self) -> Self;
+    fn inv_shift_rows(self) -> Self;
+    fn mix_columns(self) -> Self;
+    fn inv_mix_columns(self) -> Self;
+    fn add_round_key(self, rk: &Self) -> Self;
+}
+
+fn encrypt_core<S: AesOps + Copy>(state: &S, sk: &[S]) -> S {
+    // Round 0 - add round key
+    let mut tmp = state.add_round_key(&sk[0]);
+
+    // Remaining rounds (except last round)
+    for i in 1..sk.len() - 1 {
+        tmp = tmp.sub_bytes();
+        tmp = tmp.shift_rows();
+        tmp = tmp.mix_columns();
+        tmp = tmp.add_round_key(&sk[i]);
+    }
+
+    // Last round
+    tmp = tmp.sub_bytes();
+    tmp = tmp.shift_rows();
+    tmp = tmp.add_round_key(&sk[sk.len() - 1]);
+
+    tmp
+}
+
+fn decrypt_core<S: AesOps + Copy>(state: &S, sk: &[S]) -> S {
+    // Round 0 - add round key
+    let mut tmp = state.add_round_key(&sk[sk.len() - 1]);
+
+    // Remaining rounds (except last round)
+    for i in 1..sk.len() - 1 {
+        tmp = tmp.inv_sub_bytes();
+        tmp = tmp.inv_shift_rows();
+        tmp = tmp.inv_mix_columns();
+        tmp = tmp.add_round_key(&sk[sk.len() - 1 - i]);
+    }
+
+    // Last round
+    tmp = tmp.inv_sub_bytes();
+    tmp = tmp.inv_shift_rows();
+    tmp = tmp.add_round_key(&sk[0]);
+
+    tmp
+}
+
+#[derive(Clone, Copy)]
+struct Bs8State<T>(T, T, T, T, T, T, T, T);
+
+impl <T: Copy> Bs8State<T> {
+    fn split(self) -> (Bs4State<T>, Bs4State<T>) {
+        let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self;
+        (Bs4State(x0, x1, x2, x3), Bs4State(x4, x5, x6, x7))
+    }
+}
+
+impl <T: BitXor<Output = T> + Copy> Bs8State<T> {
+    fn xor(self, rhs: Bs8State<T>) -> Bs8State<T> {
+        let Bs8State(a0, a1, a2, a3, a4, a5, a6, a7) = self;
+        let Bs8State(b0, b1, b2, b3, b4, b5, b6, b7) = rhs;
+        Bs8State(a0 ^ b0, a1 ^ b1, a2 ^ b2, a3 ^ b3, a4 ^ b4, a5 ^ b5, a6 ^ b6, a7 ^ b7)
+    }
+
+    // We need to be able to convert a Bs8State to and from a polynomial basis and a normal
+    // basis. That transformation could be done via pseudocode that roughly looks like the
+    // following:
+    //
+    // for x in 0..8 {
+    //     for y in 0..8 {
+    //         result.x ^= input.y & MATRIX[7 - y][x]
+    //     }
+    // }
+    //
+    // Where the MATRIX is one of the following depending on the conversion being done.
+    // (The affine transformation step is included in all of these matrices):
+    //
+    // A2X = [
+    //     [ 0,  0,  0, -1, -1,  0,  0, -1],
+    //     [-1, -1,  0,  0, -1, -1, -1, -1],
+    //     [ 0, -1,  0,  0, -1, -1, -1, -1],
+    //     [ 0,  0,  0, -1,  0,  0, -1,  0],
+    //     [-1,  0,  0, -1,  0,  0,  0,  0],
+    //     [-1,  0,  0,  0,  0,  0,  0, -1],
+    //     [-1,  0,  0, -1,  0, -1,  0, -1],
+    //     [-1, -1, -1, -1, -1, -1, -1, -1]
+    // ];
+    //
+    // X2A = [
+    //     [ 0,  0, -1,  0,  0, -1, -1,  0],
+    //     [ 0,  0,  0, -1, -1, -1, -1,  0],
+    //     [ 0, -1, -1, -1,  0, -1, -1,  0],
+    //     [ 0,  0, -1, -1,  0,  0,  0, -1],
+    //     [ 0,  0,  0, -1,  0, -1, -1,  0],
+    //     [-1,  0,  0, -1,  0, -1,  0,  0],
+    //     [ 0, -1, -1, -1, -1,  0, -1, -1],
+    //     [ 0,  0,  0,  0,  0, -1, -1,  0],
+    // ];
+    //
+    // X2S = [
+    //     [ 0,  0,  0, -1, -1,  0, -1,  0],
+    //     [-1,  0, -1, -1,  0, -1,  0,  0],
+    //     [ 0, -1, -1, -1, -1,  0,  0, -1],
+    //     [-1, -1,  0, -1,  0,  0,  0,  0],
+    //     [ 0,  0, -1, -1, -1,  0, -1, -1],
+    //     [ 0,  0, -1,  0,  0,  0,  0,  0],
+    //     [-1, -1,  0,  0,  0,  0,  0,  0],
+    //     [ 0,  0, -1,  0,  0, -1,  0,  0],
+    // ];
+    //
+    // S2X = [
+    //     [ 0,  0, -1, -1,  0,  0,  0, -1],
+    //     [-1,  0,  0, -1, -1, -1, -1,  0],
+    //     [-1,  0, -1,  0,  0,  0,  0,  0],
+    //     [-1, -1,  0, -1,  0, -1, -1, -1],
+    //     [ 0, -1,  0,  0, -1,  0,  0,  0],
+    //     [ 0,  0, -1,  0,  0,  0,  0,  0],
+    //     [-1,  0,  0,  0, -1,  0, -1,  0],
+    //     [-1, -1,  0,  0, -1,  0, -1,  0],
+    // ];
+    //
+    // Looking at the pseudocode implementation, we see that there is no point
+    // in processing any of the elements in those matrices that have zero values
+    // since a logical AND with 0 will produce 0 which will have no effect when it
+    // is XORed into the result.
+    //
+    // LLVM doesn't appear to be able to fully unroll the loops in the pseudocode
+    // above and to eliminate processing of the 0 elements. So, each transformation is
+    // implemented independently directly in fully unrolled form with the 0 elements
+    // removed.
+    //
+    // As an optimization, elements that are XORed together multiple times are
+    // XORed just once and then used multiple times. I wrote a simple program that
+    // greedily looked for terms to combine to create the implementations below.
+    // It is likely that this could be optimized more.
+
+    fn change_basis_a2x(&self) -> Bs8State<T> {
+        let t06 = self.6 ^ self.0;
+        let t056 = self.5 ^ t06;
+        let t0156 = t056 ^ self.1;
+        let t13 = self.1 ^ self.3;
+
+        let x0 = self.2 ^ t06 ^ t13;
+        let x1 = t056;
+        let x2 = self.0;
+        let x3 = self.0 ^ self.4 ^ self.7 ^ t13;
+        let x4 = self.7 ^ t056;
+        let x5 = t0156;
+        let x6 = self.4 ^ t056;
+        let x7 = self.2 ^ self.7 ^ t0156;
+
+        Bs8State(x0, x1, x2, x3, x4, x5, x6, x7)
+    }
+
+    fn change_basis_x2s(&self) -> Bs8State<T> {
+        let t46 = self.4 ^ self.6;
+        let t35 = self.3 ^ self.5;
+        let t06 = self.0 ^ self.6;
+        let t357 = t35 ^ self.7;
+
+        let x0 = self.1 ^ t46;
+        let x1 = self.1 ^ self.4 ^ self.5;
+        let x2 = self.2 ^ t35 ^ t06;
+        let x3 = t46 ^ t357;
+        let x4 = t357;
+        let x5 = t06;
+        let x6 = self.3 ^ self.7;
+        let x7 = t35;
+
+        Bs8State(x0, x1, x2, x3, x4, x5, x6, x7)
+    }
+
+    fn change_basis_x2a(&self) -> Bs8State<T> {
+        let t15 = self.1 ^ self.5;
+        let t36 = self.3 ^ self.6;
+        let t1356 = t15 ^ t36;
+        let t07 = self.0 ^ self.7;
+
+        let x0 = self.2;
+        let x1 = t15;
+        let x2 = self.4 ^ self.7 ^ t15;
+        let x3 = self.2 ^ self.4 ^ t1356;
+        let x4 = self.1 ^ self.6;
+        let x5 = self.2 ^ self.5 ^ t36 ^ t07;
+        let x6 = t1356 ^ t07;
+        let x7 = self.1 ^ self.4;
+
+        Bs8State(x0, x1, x2, x3, x4, x5, x6, x7)
+    }
+
+    fn change_basis_s2x(&self) -> Bs8State<T> {
+        let t46 = self.4 ^ self.6;
+        let t01 = self.0 ^ self.1;
+        let t0146 = t01 ^ t46;
+
+        let x0 = self.5 ^ t0146;
+        let x1 = self.0 ^ self.3 ^ self.4;
+        let x2 = self.2 ^ self.5 ^ self.7;
+        let x3 = self.7 ^ t46;
+        let x4 = self.3 ^ self.6 ^ t01;
+        let x5 = t46;
+        let x6 = t0146;
+        let x7 = self.4 ^ self.7;
+
+        Bs8State(x0, x1, x2, x3, x4, x5, x6, x7)
+    }
+}
+
+impl <T: Not<Output = T> + Copy> Bs8State<T> {
+    // The special value "x63" is used as part of the sub_bytes and inv_sub_bytes
+    // steps. It is conceptually a Bs8State value where the 0th, 1st, 5th, and 6th
+    // elements are all 1s and the other elements are all 0s. The only thing that
+    // we do with the "x63" value is to XOR a Bs8State with it. We optimize that XOR
+    // below into just inverting 4 of the elements and leaving the other 4 elements
+    // untouched.
+    fn xor_x63(self) -> Bs8State<T> {
+        Bs8State (
+            !self.0,
+            !self.1,
+            self.2,
+            self.3,
+            self.4,
+            !self.5,
+            !self.6,
+            self.7)
+    }
+}
+
+#[derive(Clone, Copy)]
+struct Bs4State<T>(T, T, T, T);
+
+impl <T: Copy> Bs4State<T> {
+    fn split(self) -> (Bs2State<T>, Bs2State<T>) {
+        let Bs4State(x0, x1, x2, x3) = self;
+        (Bs2State(x0, x1), Bs2State(x2, x3))
+    }
+
+    fn join(self, rhs: Bs4State<T>) -> Bs8State<T> {
+        let Bs4State(a0, a1, a2, a3) = self;
+        let Bs4State(b0, b1, b2, b3) = rhs;
+        Bs8State(a0, a1, a2, a3, b0, b1, b2, b3)
+    }
+}
+
+impl <T: BitXor<Output = T> + Copy> Bs4State<T> {
+    fn xor(self, rhs: Bs4State<T>) -> Bs4State<T> {
+        let Bs4State(a0, a1, a2, a3) = self;
+        let Bs4State(b0, b1, b2, b3) = rhs;
+        Bs4State(a0 ^ b0, a1 ^ b1, a2 ^ b2, a3 ^ b3)
+    }
+}
+
+#[derive(Clone, Copy)]
+struct Bs2State<T>(T, T);
+
+impl <T> Bs2State<T> {
+    fn split(self) -> (T, T) {
+        let Bs2State(x0, x1) = self;
+        (x0, x1)
+    }
+
+    fn join(self, rhs: Bs2State<T>) -> Bs4State<T> {
+        let Bs2State(a0, a1) = self;
+        let Bs2State(b0, b1) = rhs;
+        Bs4State(a0, a1, b0, b1)
+    }
+}
+
+impl <T: BitXor<Output = T> + Copy> Bs2State<T> {
+    fn xor(self, rhs: Bs2State<T>) -> Bs2State<T> {
+        let Bs2State(a0, a1) = self;
+        let Bs2State(b0, b1) = rhs;
+        Bs2State(a0 ^ b0, a1 ^ b1)
+    }
+}
+
+// Bit Slice data in the form of 4 u32s in column-major order
+fn bit_slice_4x4_with_u16(a: u32, b: u32, c: u32, d: u32) -> Bs8State<u16> {
+    fn pb(x: u32, bit: u32, shift: u32) -> u16 {
+        (((x >> bit) & 1) as u16) << shift
+    }
+
+    fn construct(a: u32, b: u32, c: u32, d: u32, bit: u32) -> u16 {
+        pb(a, bit, 0)       | pb(b, bit, 1)       | pb(c, bit, 2)       | pb(d, bit, 3)       |
+        pb(a, bit + 8, 4)   | pb(b, bit + 8, 5)   | pb(c, bit + 8, 6)   | pb(d, bit + 8, 7)   |
+        pb(a, bit + 16, 8)  | pb(b, bit + 16, 9)  | pb(c, bit + 16, 10) | pb(d, bit + 16, 11) |
+        pb(a, bit + 24, 12) | pb(b, bit + 24, 13) | pb(c, bit + 24, 14) | pb(d, bit + 24, 15)
+    }
+
+    let x0 = construct(a, b, c, d, 0);
+    let x1 = construct(a, b, c, d, 1);
+    let x2 = construct(a, b, c, d, 2);
+    let x3 = construct(a, b, c, d, 3);
+    let x4 = construct(a, b, c, d, 4);
+    let x5 = construct(a, b, c, d, 5);
+    let x6 = construct(a, b, c, d, 6);
+    let x7 = construct(a, b, c, d, 7);
+
+    Bs8State(x0, x1, x2, x3, x4, x5, x6, x7)
+}
+
+// Bit slice a single u32 value - this is used to calculate the SubBytes step when creating the
+// round keys.
+fn bit_slice_4x1_with_u16(a: u32) -> Bs8State<u16> {
+    bit_slice_4x4_with_u16(a, 0, 0, 0)
+}
+
+// Bit slice a 16 byte array in column major order
+fn bit_slice_1x16_with_u16(data: &[u8]) -> Bs8State<u16> {
+    let mut n = [0u32; 4];
+    read_u32v_le(&mut n, data);
+
+    let a = n[0];
+    let b = n[1];
+    let c = n[2];
+    let d = n[3];
+
+    bit_slice_4x4_with_u16(a, b, c, d)
+}
+
+// Un Bit Slice into a set of 4 u32s
+fn un_bit_slice_4x4_with_u16(bs: &Bs8State<u16>) -> (u32, u32, u32, u32) {
+    fn pb(x: u16, bit: u32, shift: u32) -> u32 {
+        (((x >> bit) & 1) as u32) << shift
+    }
+
+    fn deconstruct(bs: &Bs8State<u16>, bit: u32) -> u32 {
+        let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = *bs;
+
+        pb(x0, bit, 0) | pb(x1, bit, 1) | pb(x2, bit, 2) | pb(x3, bit, 3) |
+        pb(x4, bit, 4) | pb(x5, bit, 5) | pb(x6, bit, 6) | pb(x7, bit, 7) |
+
+        pb(x0, bit + 4, 8)  | pb(x1, bit + 4, 9)  | pb(x2, bit + 4, 10) | pb(x3, bit + 4, 11) |
+        pb(x4, bit + 4, 12) | pb(x5, bit + 4, 13) | pb(x6, bit + 4, 14) | pb(x7, bit + 4, 15) |
+
+        pb(x0, bit + 8, 16) | pb(x1, bit + 8, 17) | pb(x2, bit + 8, 18) | pb(x3, bit + 8, 19) |
+        pb(x4, bit + 8, 20) | pb(x5, bit + 8, 21) | pb(x6, bit + 8, 22) | pb(x7, bit + 8, 23) |
+
+        pb(x0, bit + 12, 24) | pb(x1, bit + 12, 25) | pb(x2, bit + 12, 26) | pb(x3, bit + 12, 27) |
+        pb(x4, bit + 12, 28) | pb(x5, bit + 12, 29) | pb(x6, bit + 12, 30) | pb(x7, bit + 12, 31)
+    }
+
+    let a = deconstruct(bs, 0);
+    let b = deconstruct(bs, 1);
+    let c = deconstruct(bs, 2);
+    let d = deconstruct(bs, 3);
+
+    (a, b, c, d)
+}
+
+// Un Bit Slice into a single u32. This is used when creating the round keys.
+fn un_bit_slice_4x1_with_u16(bs: &Bs8State<u16>) -> u32 {
+    let (a, _, _, _) = un_bit_slice_4x4_with_u16(bs);
+    a
+}
+
+// Un Bit Slice into a 16 byte array
+fn un_bit_slice_1x16_with_u16(bs: &Bs8State<u16>, output: &mut [u8]) {
+    let (a, b, c, d) = un_bit_slice_4x4_with_u16(bs);
+
+    write_u32_le(&mut output[0..4], a);
+    write_u32_le(&mut output[4..8], b);
+    write_u32_le(&mut output[8..12], c);
+    write_u32_le(&mut output[12..16], d);
+}
+
+// Bit Slice a 128 byte array of eight 16 byte blocks. Each block is in column major order.
+fn bit_slice_1x128_with_u32x4(data: &[u8]) -> Bs8State<u32x4> {
+    let bit0 = u32x4(0x01010101, 0x01010101, 0x01010101, 0x01010101);
+    let bit1 = u32x4(0x02020202, 0x02020202, 0x02020202, 0x02020202);
+    let bit2 = u32x4(0x04040404, 0x04040404, 0x04040404, 0x04040404);
+    let bit3 = u32x4(0x08080808, 0x08080808, 0x08080808, 0x08080808);
+    let bit4 = u32x4(0x10101010, 0x10101010, 0x10101010, 0x10101010);
+    let bit5 = u32x4(0x20202020, 0x20202020, 0x20202020, 0x20202020);
+    let bit6 = u32x4(0x40404040, 0x40404040, 0x40404040, 0x40404040);
+    let bit7 = u32x4(0x80808080, 0x80808080, 0x80808080, 0x80808080);
+
+    fn read_row_major(data: &[u8]) -> u32x4 {
+        u32x4(
+            (data[0] as u32) |
+            ((data[4] as u32) << 8) |
+            ((data[8] as u32) << 16) |
+            ((data[12] as u32) << 24),
+            (data[1] as u32) |
+            ((data[5] as u32) << 8) |
+            ((data[9] as u32) << 16) |
+            ((data[13] as u32) << 24),
+            (data[2] as u32) |
+            ((data[6] as u32) << 8) |
+            ((data[10] as u32) << 16) |
+            ((data[14] as u32) << 24),
+            (data[3] as u32) |
+            ((data[7] as u32) << 8) |
+            ((data[11] as u32) << 16) |
+            ((data[15] as u32) << 24))
+    }
+
+    let t0 = read_row_major(&data[0..16]);
+    let t1 = read_row_major(&data[16..32]);
+    let t2 = read_row_major(&data[32..48]);
+    let t3 = read_row_major(&data[48..64]);
+    let t4 = read_row_major(&data[64..80]);
+    let t5 = read_row_major(&data[80..96]);
+    let t6 = read_row_major(&data[96..112]);
+    let t7 = read_row_major(&data[112..128]);
+
+    let x0 = (t0 & bit0) | (t1.lsh(1) & bit1) | (t2.lsh(2) & bit2) | (t3.lsh(3) & bit3) |
+        (t4.lsh(4) & bit4) | (t5.lsh(5) & bit5) | (t6.lsh(6) & bit6) | (t7.lsh(7) & bit7);
+    let x1 = (t0.rsh(1) & bit0) | (t1 & bit1) | (t2.lsh(1) & bit2) | (t3.lsh(2) & bit3) |
+        (t4.lsh(3) & bit4) | (t5.lsh(4) & bit5) | (t6.lsh(5) & bit6) | (t7.lsh(6) & bit7);
+    let x2 = (t0.rsh(2) & bit0) | (t1.rsh(1) & bit1) | (t2 & bit2) | (t3.lsh(1) & bit3) |
+        (t4.lsh(2) & bit4) | (t5.lsh(3) & bit5) | (t6.lsh(4) & bit6) | (t7.lsh(5) & bit7);
+    let x3 = (t0.rsh(3) & bit0) | (t1.rsh(2) & bit1) | (t2.rsh(1) & bit2) | (t3 & bit3) |
+        (t4.lsh(1) & bit4) | (t5.lsh(2) & bit5) | (t6.lsh(3) & bit6) | (t7.lsh(4) & bit7);
+    let x4 = (t0.rsh(4) & bit0) | (t1.rsh(3) & bit1) | (t2.rsh(2) & bit2) | (t3.rsh(1) & bit3) |
+        (t4 & bit4) | (t5.lsh(1) & bit5) | (t6.lsh(2) & bit6) | (t7.lsh(3) & bit7);
+    let x5 = (t0.rsh(5) & bit0) | (t1.rsh(4) & bit1) | (t2.rsh(3) & bit2) | (t3.rsh(2) & bit3) |
+        (t4.rsh(1) & bit4) | (t5 & bit5) | (t6.lsh(1) & bit6) | (t7.lsh(2) & bit7);
+    let x6 = (t0.rsh(6) & bit0) | (t1.rsh(5) & bit1) | (t2.rsh(4) & bit2) | (t3.rsh(3) & bit3) |
+        (t4.rsh(2) & bit4) | (t5.rsh(1) & bit5) | (t6 & bit6) | (t7.lsh(1) & bit7);
+    let x7 = (t0.rsh(7) & bit0) | (t1.rsh(6) & bit1) | (t2.rsh(5) & bit2) | (t3.rsh(4) & bit3) |
+        (t4.rsh(3) & bit4) | (t5.rsh(2) & bit5) | (t6.rsh(1) & bit6) | (t7 & bit7);
+
+    Bs8State(x0, x1, x2, x3, x4, x5, x6, x7)
+}
+
+// Bit slice a set of 4 u32s by filling a full 128 byte data block with those repeated values. This
+// is used as part of bit slicing the round keys.
+fn bit_slice_fill_4x4_with_u32x4(a: u32, b: u32, c: u32, d: u32) -> Bs8State<u32x4> {
+    let mut tmp = [0u8; 128];
+    for i in 0..8 {
+        write_u32_le(&mut tmp[i * 16..i * 16 + 4], a);
+        write_u32_le(&mut tmp[i * 16 + 4..i * 16 + 8], b);
+        write_u32_le(&mut tmp[i * 16 + 8..i * 16 + 12], c);
+        write_u32_le(&mut tmp[i * 16 + 12..i * 16 + 16], d);
+    }
+    bit_slice_1x128_with_u32x4(&tmp)
+}
+
+// Un bit slice into a 128 byte buffer.
+fn un_bit_slice_1x128_with_u32x4(bs: Bs8State<u32x4>, output: &mut [u8]) {
+    let Bs8State(t0, t1, t2, t3, t4, t5, t6, t7) = bs;
+
+    let bit0 = u32x4(0x01010101, 0x01010101, 0x01010101, 0x01010101);
+    let bit1 = u32x4(0x02020202, 0x02020202, 0x02020202, 0x02020202);
+    let bit2 = u32x4(0x04040404, 0x04040404, 0x04040404, 0x04040404);
+    let bit3 = u32x4(0x08080808, 0x08080808, 0x08080808, 0x08080808);
+    let bit4 = u32x4(0x10101010, 0x10101010, 0x10101010, 0x10101010);
+    let bit5 = u32x4(0x20202020, 0x20202020, 0x20202020, 0x20202020);
+    let bit6 = u32x4(0x40404040, 0x40404040, 0x40404040, 0x40404040);
+    let bit7 = u32x4(0x80808080, 0x80808080, 0x80808080, 0x80808080);
+
+    // decode the individual blocks, in row-major order
+    // TODO: this is identical to the same block in bit_slice_1x128_with_u32x4
+    let x0 = (t0 & bit0) | (t1.lsh(1) & bit1) | (t2.lsh(2) & bit2) | (t3.lsh(3) & bit3) |
+        (t4.lsh(4) & bit4) | (t5.lsh(5) & bit5) | (t6.lsh(6) & bit6) | (t7.lsh(7) & bit7);
+    let x1 = (t0.rsh(1) & bit0) | (t1 & bit1) | (t2.lsh(1) & bit2) | (t3.lsh(2) & bit3) |
+        (t4.lsh(3) & bit4) | (t5.lsh(4) & bit5) | (t6.lsh(5) & bit6) | (t7.lsh(6) & bit7);
+    let x2 = (t0.rsh(2) & bit0) | (t1.rsh(1) & bit1) | (t2 & bit2) | (t3.lsh(1) & bit3) |
+        (t4.lsh(2) & bit4) | (t5.lsh(3) & bit5) | (t6.lsh(4) & bit6) | (t7.lsh(5) & bit7);
+    let x3 = (t0.rsh(3) & bit0) | (t1.rsh(2) & bit1) | (t2.rsh(1) & bit2) | (t3 & bit3) |
+        (t4.lsh(1) & bit4) | (t5.lsh(2) & bit5) | (t6.lsh(3) & bit6) | (t7.lsh(4) & bit7);
+    let x4 = (t0.rsh(4) & bit0) | (t1.rsh(3) & bit1) | (t2.rsh(2) & bit2) | (t3.rsh(1) & bit3) |
+        (t4 & bit4) | (t5.lsh(1) & bit5) | (t6.lsh(2) & bit6) | (t7.lsh(3) & bit7);
+    let x5 = (t0.rsh(5) & bit0) | (t1.rsh(4) & bit1) | (t2.rsh(3) & bit2) | (t3.rsh(2) & bit3) |
+        (t4.rsh(1) & bit4) | (t5 & bit5) | (t6.lsh(1) & bit6) | (t7.lsh(2) & bit7);
+    let x6 = (t0.rsh(6) & bit0) | (t1.rsh(5) & bit1) | (t2.rsh(4) & bit2) | (t3.rsh(3) & bit3) |
+        (t4.rsh(2) & bit4) | (t5.rsh(1) & bit5) | (t6 & bit6) | (t7.lsh(1) & bit7);
+    let x7 = (t0.rsh(7) & bit0) | (t1.rsh(6) & bit1) | (t2.rsh(5) & bit2) | (t3.rsh(4) & bit3) |
+        (t4.rsh(3) & bit4) | (t5.rsh(2) & bit5) | (t6.rsh(1) & bit6) | (t7 & bit7);
+
+    fn write_row_major(block: u32x4, output: &mut [u8]) {
+        let u32x4(a0, a1, a2, a3) = block;
+        output[0] = a0 as u8;
+        output[1] = a1 as u8;
+        output[2] = a2 as u8;
+        output[3] = a3 as u8;
+        output[4] = (a0 >> 8) as u8;
+        output[5] = (a1 >> 8) as u8;
+        output[6] = (a2 >> 8) as u8;
+        output[7] = (a3 >> 8) as u8;
+        output[8] = (a0 >> 16) as u8;
+        output[9] = (a1 >> 16) as u8;
+        output[10] = (a2 >> 16) as u8;
+        output[11] = (a3 >> 16) as u8;
+        output[12] = (a0 >> 24) as u8;
+        output[13] = (a1 >> 24) as u8;
+        output[14] = (a2 >> 24) as u8;
+        output[15] = (a3 >> 24) as u8;
+    }
+
+    write_row_major(x0, &mut output[0..16]);
+    write_row_major(x1, &mut output[16..32]);
+    write_row_major(x2, &mut output[32..48]);
+    write_row_major(x3, &mut output[48..64]);
+    write_row_major(x4, &mut output[64..80]);
+    write_row_major(x5, &mut output[80..96]);
+    write_row_major(x6, &mut output[96..112]);
+    write_row_major(x7, &mut output[112..128])
+}
+
+// The Gf2Ops, Gf4Ops, and Gf8Ops traits specify the functions needed to calculate the AES S-Box
+// values. This particuar implementation of those S-Box values is taken from [7], so that is where
+// to look for details on how all that all works. This includes the transformations matrices defined
+// below for the change_basis operation on the u32 and u32x4 types.
+
+// Operations in GF(2^2) using normal basis (Omega^2,Omega)
+trait Gf2Ops {
+    // multiply
+    fn mul(self, y: Self) -> Self;
+
+    // scale by N = Omega^2
+    fn scl_n(self) -> Self;
+
+    // scale by N^2 = Omega
+    fn scl_n2(self) -> Self;
+
+    // square
+    fn sq(self) -> Self;
+
+    // Same as sqaure
+    fn inv(self) -> Self;
+}
+
+impl <T: BitXor<Output = T> + BitAnd<Output = T> + Copy> Gf2Ops for Bs2State<T> {
+    fn mul(self, y: Bs2State<T>) -> Bs2State<T> {
+        let (b, a) = self.split();
+        let (d, c) = y.split();
+        let e = (a ^ b) & (c ^ d);
+        let p = (a & c) ^ e;
+        let q = (b & d) ^ e;
+        Bs2State(q, p)
+    }
+
+    fn scl_n(self) -> Bs2State<T> {
+        let (b, a) = self.split();
+        let q = a ^ b;
+        Bs2State(q, b)
+    }
+
+    fn scl_n2(self) -> Bs2State<T> {
+        let (b, a) = self.split();
+        let p = a ^ b;
+        let q = a;
+        Bs2State(q, p)
+    }
+
+    fn sq(self) -> Bs2State<T> {
+        let (b, a) = self.split();
+        Bs2State(a, b)
+    }
+
+    fn inv(self) -> Bs2State<T> {
+        self.sq()
+    }
+}
+
+// Operations in GF(2^4) using normal basis (alpha^8,alpha^2)
+trait Gf4Ops {
+    // multiply
+    fn mul(self, y: Self) -> Self;
+
+    // square & scale by nu
+    // nu = beta^8 = N^2*alpha^2, N = w^2
+    fn sq_scl(self) -> Self;
+
+    // inverse
+    fn inv(self) -> Self;
+}
+
+impl <T: BitXor<Output = T> + BitAnd<Output = T> + Copy> Gf4Ops for Bs4State<T> {
+    fn mul(self, y: Bs4State<T>) -> Bs4State<T> {
+        let (b, a) = self.split();
+        let (d, c) = y.split();
+        let f = c.xor(d);
+        let e = a.xor(b).mul(f).scl_n();
+        let p = a.mul(c).xor(e);
+        let q = b.mul(d).xor(e);
+        q.join(p)
+    }
+
+    fn sq_scl(self) -> Bs4State<T> {
+        let (b, a) = self.split();
+        let p = a.xor(b).sq();
+        let q = b.sq().scl_n2();
+        q.join(p)
+    }
+
+    fn inv(self) -> Bs4State<T> {
+        let (b, a) = self.split();
+        let c = a.xor(b).sq().scl_n();
+        let d = a.mul(b);
+        let e = c.xor(d).inv();
+        let p = e.mul(b);
+        let q = e.mul(a);
+        q.join(p)
+    }
+}
+
+// Operations in GF(2^8) using normal basis (d^16,d)
+trait Gf8Ops {
+    // inverse
+    fn inv(&self) -> Self;
+}
+
+impl <T: BitXor<Output = T> + BitAnd<Output = T> + Copy + Default> Gf8Ops for Bs8State<T> {
+    fn inv(&self) -> Bs8State<T> {
+        let (b, a) = self.split();
+        let c = a.xor(b).sq_scl();
+        let d = a.mul(b);
+        let e = c.xor(d).inv();
+        let p = e.mul(b);
+        let q = e.mul(a);
+        q.join(p)
+    }
+}
+
+impl <T: AesBitValueOps + Copy + 'static> AesOps for Bs8State<T> {
+    fn sub_bytes(self) -> Bs8State<T> {
+        let nb: Bs8State<T> = self.change_basis_a2x();
+        let inv = nb.inv();
+        let nb2: Bs8State<T> = inv.change_basis_x2s();
+        nb2.xor_x63()
+    }
+
+    fn inv_sub_bytes(self) -> Bs8State<T> {
+        let t = self.xor_x63();
+        let nb: Bs8State<T> = t.change_basis_s2x();
+        let inv = nb.inv();
+        inv.change_basis_x2a()
+    }
+
+    fn shift_rows(self) -> Bs8State<T> {
+        let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self;
+        Bs8State(
+            x0.shift_row(),
+            x1.shift_row(),
+            x2.shift_row(),
+            x3.shift_row(),
+            x4.shift_row(),
+            x5.shift_row(),
+            x6.shift_row(),
+            x7.shift_row())
+    }
+
+    fn inv_shift_rows(self) -> Bs8State<T> {
+        let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self;
+        Bs8State(
+            x0.inv_shift_row(),
+            x1.inv_shift_row(),
+            x2.inv_shift_row(),
+            x3.inv_shift_row(),
+            x4.inv_shift_row(),
+            x5.inv_shift_row(),
+            x6.inv_shift_row(),
+            x7.inv_shift_row())
+    }
+
+    // Formula from [5]
+    fn mix_columns(self) -> Bs8State<T> {
+        let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self;
+
+        let x0out = x7 ^ x7.ror1() ^ x0.ror1() ^ (x0 ^ x0.ror1()).ror2();
+        let x1out = x0 ^ x0.ror1() ^ x7 ^ x7.ror1() ^ x1.ror1() ^ (x1 ^ x1.ror1()).ror2();
+        let x2out = x1 ^ x1.ror1() ^ x2.ror1() ^ (x2 ^ x2.ror1()).ror2();
+        let x3out = x2 ^ x2.ror1() ^ x7 ^ x7.ror1() ^ x3.ror1() ^ (x3 ^ x3.ror1()).ror2();
+        let x4out = x3 ^ x3.ror1() ^ x7 ^ x7.ror1() ^ x4.ror1() ^ (x4 ^ x4.ror1()).ror2();
+        let x5out = x4 ^ x4.ror1() ^ x5.ror1() ^ (x5 ^ x5.ror1()).ror2();
+        let x6out = x5 ^ x5.ror1() ^ x6.ror1() ^ (x6 ^ x6.ror1()).ror2();
+        let x7out = x6 ^ x6.ror1() ^ x7.ror1() ^ (x7 ^ x7.ror1()).ror2();
+
+        Bs8State(x0out, x1out, x2out, x3out, x4out, x5out, x6out, x7out)
+    }
+
+    // Formula from [6]
+    fn inv_mix_columns(self) -> Bs8State<T> {
+        let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self;
+
+        let x0out = x5 ^ x6 ^ x7 ^
+            (x5 ^ x7 ^ x0).ror1() ^
+            (x0 ^ x5 ^ x6).ror2() ^
+            (x5 ^ x0).ror3();
+        let x1out = x5 ^ x0 ^
+            (x6 ^ x5 ^ x0 ^ x7 ^ x1).ror1() ^
+            (x1 ^ x7 ^ x5).ror2() ^
+            (x6 ^ x5 ^ x1).ror3();
+        let x2out = x6 ^ x0 ^ x1 ^
+            (x7 ^ x6 ^ x1 ^ x2).ror1() ^
+            (x0 ^ x2 ^ x6).ror2() ^
+            (x7 ^ x6 ^ x2).ror3();
+        let x3out = x0 ^ x5 ^ x1 ^ x6 ^ x2 ^
+            (x0 ^ x5 ^ x2 ^ x3).ror1() ^
+            (x0 ^ x1 ^ x3 ^ x5 ^ x6 ^ x7).ror2() ^
+            (x0 ^ x5 ^ x7 ^ x3).ror3();
+        let x4out = x1 ^ x5 ^ x2 ^ x3 ^
+            (x1 ^ x6 ^ x5 ^ x3 ^ x7 ^ x4).ror1() ^
+            (x1 ^ x2 ^ x4 ^ x5 ^ x7).ror2() ^
+            (x1 ^ x5 ^ x6 ^ x4).ror3();
+        let x5out = x2 ^ x6 ^ x3 ^ x4 ^
+            (x2 ^ x7 ^ x6 ^ x4 ^ x5).ror1() ^
+            (x2 ^ x3 ^ x5 ^ x6).ror2() ^
+            (x2 ^ x6 ^ x7 ^ x5).ror3();
+        let x6out =  x3 ^ x7 ^ x4 ^ x5 ^
+            (x3 ^ x7 ^ x5 ^ x6).ror1() ^
+            (x3 ^ x4 ^ x6 ^ x7).ror2() ^
+            (x3 ^ x7 ^ x6).ror3();
+        let x7out = x4 ^ x5 ^ x6 ^
+            (x4 ^ x6 ^ x7).ror1() ^
+            (x4 ^ x5 ^ x7).ror2() ^
+            (x4 ^ x7).ror3();
+
+        Bs8State(x0out, x1out, x2out, x3out, x4out, x5out, x6out, x7out)
+    }
+
+    fn add_round_key(self, rk: &Bs8State<T>) -> Bs8State<T> {
+        self.xor(*rk)
+    }
+}
+
+trait AesBitValueOps: BitXor<Output = Self> + BitAnd<Output = Self> + Not<Output = Self> + Default + Sized {
+    fn shift_row(self) -> Self;
+    fn inv_shift_row(self) -> Self;
+    fn ror1(self) -> Self;
+    fn ror2(self) -> Self;
+    fn ror3(self) -> Self;
+}
+
+impl AesBitValueOps for u16 {
+    fn shift_row(self) -> u16 {
+        // first 4 bits represent first row - don't shift
+        (self & 0x000f) |
+        // next 4 bits represent 2nd row - left rotate 1 bit
+        ((self & 0x00e0) >> 1) | ((self & 0x0010) << 3) |
+        // next 4 bits represent 3rd row - left rotate 2 bits
+        ((self & 0x0c00) >> 2) | ((self & 0x0300) << 2) |
+        // next 4 bits represent 4th row - left rotate 3 bits
+        ((self & 0x8000) >> 3) | ((self & 0x7000) << 1)
+    }
+
+    fn inv_shift_row(self) -> u16 {
+        // first 4 bits represent first row - don't shift
+        (self & 0x000f) |
+        // next 4 bits represent 2nd row - right rotate 1 bit
+        ((self & 0x0080) >> 3) | ((self & 0x0070) << 1) |
+        // next 4 bits represent 3rd row - right rotate 2 bits
+        ((self & 0x0c00) >> 2) | ((self & 0x0300) << 2) |
+        // next 4 bits represent 4th row - right rotate 3 bits
+        ((self & 0xe000) >> 1) | ((self & 0x1000) << 3)
+    }
+
+    fn ror1(self) -> u16 {
+        self >> 4 | self << 12
+    }
+
+    fn ror2(self) -> u16 {
+        self >> 8 | self << 8
+    }
+
+    fn ror3(self) -> u16 {
+        self >> 12 | self << 4
+    }
+}
+
+impl u32x4 {
+    fn lsh(self, s: u32) -> u32x4 {
+        let u32x4(a0, a1, a2, a3) = self;
+        u32x4(
+            a0 << s,
+            (a1 << s) | (a0 >> (32 - s)),
+            (a2 << s) | (a1 >> (32 - s)),
+            (a3 << s) | (a2 >> (32 - s)))
+    }
+
+    fn rsh(self, s: u32) -> u32x4 {
+        let u32x4(a0, a1, a2, a3) = self;
+        u32x4(
+            (a0 >> s) | (a1 << (32 - s)),
+            (a1 >> s) | (a2 << (32 - s)),
+            (a2 >> s) | (a3 << (32 - s)),
+            a3 >> s)
+    }
+}
+
+impl Not for u32x4 {
+    type Output = u32x4;
+
+    fn not(self) -> u32x4 {
+        self ^ U32X4_1
+    }
+}
+
+impl Default for u32x4 {
+    fn default() -> u32x4 {
+        u32x4(0, 0, 0, 0)
+    }
+}
+
+impl AesBitValueOps for u32x4 {
+    fn shift_row(self) -> u32x4 {
+        let u32x4(a0, a1, a2, a3) = self;
+        u32x4(a0, a1 >> 8 | a1 << 24, a2 >> 16 | a2 << 16, a3 >> 24 | a3 << 8)
+    }
+
+    fn inv_shift_row(self) -> u32x4 {
+        let u32x4(a0, a1, a2, a3) = self;
+        u32x4(a0, a1 >> 24 | a1 << 8, a2 >> 16 | a2 << 16, a3 >> 8 | a3 << 24)
+    }
+
+    fn ror1(self) -> u32x4 {
+        let u32x4(a0, a1, a2, a3) = self;
+        u32x4(a1, a2, a3, a0)
+    }
+
+    fn ror2(self) -> u32x4 {
+        let u32x4(a0, a1, a2, a3) = self;
+        u32x4(a2, a3, a0, a1)
+    }
+
+    fn ror3(self) -> u32x4 {
+        let u32x4(a0, a1, a2, a3) = self;
+        u32x4(a3, a0, a1, a2)
+    }
+}
diff --git a/third_party/rust-crypto/src/bcrypt.rs b/third_party/rust-crypto/src/bcrypt.rs
new file mode 100644
index 0000000..55b5767
--- /dev/null
+++ b/third_party/rust-crypto/src/bcrypt.rs
@@ -0,0 +1,164 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use blowfish::Blowfish;
+use cryptoutil::{write_u32_be};
+use step_by::RangeExt;
+
+fn setup(cost: u32, salt: &[u8], key: &[u8]) -> Blowfish {
+    assert!(cost < 32);
+    let mut state = Blowfish::init_state();
+    
+    state.salted_expand_key(salt, key);
+    for _ in 0..1u32 << cost {
+        state.expand_key(key);
+        state.expand_key(salt);
+    }
+
+    state
+}
+
+pub fn bcrypt(cost: u32, salt: &[u8], password: &[u8], output: &mut [u8]) {
+    assert!(salt.len() == 16);
+    assert!(0 < password.len() && password.len() <= 72);
+    assert!(output.len() == 24);
+
+    let state = setup(cost, salt, password);
+    // OrpheanBeholderScryDoubt
+    let mut ctext = [0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274];
+    for i in (0..6).step_up(2) {
+        for _ in 0..64 {
+            let (l, r) = state.encrypt(ctext[i], ctext[i+1]);
+            ctext[i] = l;
+            ctext[i+1] = r;
+        }
+        write_u32_be(&mut output[i*4..(i+1)*4], ctext[i]);
+        write_u32_be(&mut output[(i+1)*4..(i+2)*4], ctext[i+1]);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use bcrypt::bcrypt;
+
+    struct Test {
+        cost: u32,
+        salt: Vec<u8>,
+        input: Vec<u8>,
+        output: Vec<u8>
+    }
+
+    // These are $2y$ versions of the test vectors. $2x$ is broken and $2a$ does weird bit-twiddling
+    // when it encounters a 0xFF byte.
+    fn openwall_test_vectors() -> Vec<Test> {
+        vec![
+            Test {
+                input: vec![0x55u8, 0x2Au8, 0x55u8, 0x00u8],
+                cost: 5,
+                salt: vec![0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8],
+                output: vec![0x1Bu8, 0xB6u8, 0x91u8, 0x43u8, 0xF9u8, 0xA8u8, 0xD3u8, 0x04u8, 0xC8u8, 0xD2u8, 0x3Du8, 0x99u8, 0xABu8, 0x04u8, 0x9Au8, 0x77u8, 0xA6u8, 0x8Eu8, 0x2Cu8, 0xCCu8, 0x74u8, 0x42u8, 0x06u8]
+            },
+            Test {
+                input: vec![0x55u8, 0x2Au8, 0x55u8, 0x2Au8, 0x00u8],
+                cost: 5,
+                salt: vec![0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8],
+                output: vec![0x5Cu8, 0x84u8, 0x35u8, 0x0Bu8, 0xDFu8, 0xBAu8, 0xA9u8, 0x6Au8, 0xC1u8, 0x6Fu8, 0x61u8, 0x5Au8, 0xE7u8, 0x9Fu8, 0x35u8, 0xCFu8, 0xDAu8, 0xCDu8, 0x68u8, 0x2Du8, 0x36u8, 0x9Fu8, 0x23u8]
+            },
+            Test {
+                input: vec![0x55u8, 0x2Au8, 0x55u8, 0x2Au8, 0x55u8, 0x00u8],
+                cost: 5,
+                salt: vec![0x65u8, 0x96u8, 0x59u8, 0x65u8, 0x96u8, 0x59u8, 0x65u8, 0x96u8, 0x59u8, 0x65u8, 0x96u8, 0x59u8, 0x65u8, 0x96u8, 0x59u8, 0x65u8],
+                output: vec![0x09u8, 0xE6u8, 0x73u8, 0xA3u8, 0xF9u8, 0xA5u8, 0x44u8, 0x81u8, 0x8Eu8, 0xB8u8, 0xDDu8, 0x69u8, 0xA8u8, 0xCBu8, 0x28u8, 0xB3u8, 0x2Fu8, 0x6Fu8, 0x7Bu8, 0xE6u8, 0x04u8, 0xCFu8, 0xA7u8]
+            },
+            Test {
+                input: vec![0x30u8, 0x31u8, 0x32u8, 0x33u8, 0x34u8, 0x35u8, 0x36u8, 0x37u8, 0x38u8, 0x39u8, 0x61u8, 0x62u8, 0x63u8, 0x64u8, 0x65u8, 0x66u8, 0x67u8, 0x68u8, 0x69u8, 0x6Au8, 0x6Bu8, 0x6Cu8, 0x6Du8, 0x6Eu8, 0x6Fu8, 0x70u8, 0x71u8, 0x72u8, 0x73u8, 0x74u8, 0x75u8, 0x76u8, 0x77u8, 0x78u8, 0x79u8, 0x7Au8, 0x41u8, 0x42u8, 0x43u8, 0x44u8, 0x45u8, 0x46u8, 0x47u8, 0x48u8, 0x49u8, 0x4Au8, 0x4Bu8, 0x4Cu8, 0x4Du8, 0x4Eu8, 0x4Fu8, 0x50u8, 0x51u8, 0x52u8, 0x53u8, 0x54u8, 0x55u8, 0x56u8, 0x57u8, 0x58u8, 0x59u8, 0x5Au8, 0x30u8, 0x31u8, 0x32u8, 0x33u8, 0x34u8, 0x35u8, 0x36u8, 0x37u8, 0x38u8, 0x39u8],
+                cost: 5,
+                salt: vec![0x71u8, 0xD7u8, 0x9Fu8, 0x82u8, 0x18u8, 0xA3u8, 0x92u8, 0x59u8, 0xA7u8, 0xA2u8, 0x9Au8, 0xABu8, 0xB2u8, 0xDBu8, 0xAFu8, 0xC3u8],
+                output: vec![0xEEu8, 0xEEu8, 0x31u8, 0xF8u8, 0x09u8, 0x19u8, 0x92u8, 0x04u8, 0x25u8, 0x88u8, 0x10u8, 0x02u8, 0xD1u8, 0x40u8, 0xD5u8, 0x55u8, 0xB2u8, 0x8Au8, 0x5Cu8, 0x72u8, 0xE0u8, 0x0Fu8, 0x09u8]
+            },
+            Test {
+                input: vec![0xFFu8, 0xFFu8, 0xA3u8, 0x00u8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0x10u8, 0x6Eu8, 0xE0u8, 0x9Cu8, 0x97u8, 0x1Cu8, 0x43u8, 0xA1u8, 0x9Du8, 0x8Au8, 0x25u8, 0xC5u8, 0x95u8, 0xDFu8, 0x91u8, 0xDFu8, 0xF4u8, 0xF0u8, 0x9Bu8, 0x56u8, 0x54u8, 0x3Bu8, 0x98u8]
+            },
+            Test {
+                input: vec![0xA3u8, 0x00u8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0x51u8, 0xCFu8, 0x6Eu8, 0x8Du8, 0xDAu8, 0x3Au8, 0x01u8, 0x0Du8, 0x4Cu8, 0xAFu8, 0x11u8, 0xE9u8, 0x67u8, 0x7Au8, 0xD2u8, 0x36u8, 0x84u8, 0x98u8, 0xFFu8, 0xCAu8, 0x96u8, 0x9Cu8, 0x4Bu8]
+            },
+            Test {
+                input: vec![0xFFu8, 0xA3u8, 0x33u8, 0x34u8, 0xFFu8, 0xFFu8, 0xFFu8, 0xA3u8, 0x33u8, 0x34u8, 0x35u8, 0x00u8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0xA8u8, 0x00u8, 0x69u8, 0xE3u8, 0xB6u8, 0x57u8, 0x86u8, 0x9Fu8, 0x2Au8, 0x09u8, 0x17u8, 0x16u8, 0xC4u8, 0x98u8, 0x00u8, 0x12u8, 0xE9u8, 0xBAu8, 0xD5u8, 0x38u8, 0x6Eu8, 0x69u8, 0x19u8]
+            },
+            Test {
+                input: vec![0xFFu8, 0xA3u8, 0x33u8, 0x34u8, 0x35u8, 0x00u8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0xA5u8, 0x38u8, 0xEFu8, 0xE2u8, 0x70u8, 0x49u8, 0x4Eu8, 0x3Bu8, 0x7Cu8, 0xD6u8, 0x81u8, 0x2Bu8, 0xFFu8, 0x16u8, 0x96u8, 0xC7u8, 0x1Bu8, 0xACu8, 0xD2u8, 0x98u8, 0x67u8, 0x87u8, 0xF8u8]
+            },
+            Test {
+                input: vec![0xA3u8, 0x61u8, 0x62u8, 0x00u8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0xF0u8, 0xA8u8, 0x67u8, 0x4Au8, 0x62u8, 0xF4u8, 0xBEu8, 0xA4u8, 0xD7u8, 0x7Bu8, 0x7Du8, 0x30u8, 0x70u8, 0xFBu8, 0xC9u8, 0x86u8, 0x4Cu8, 0x2Cu8, 0x00u8, 0x74u8, 0xE7u8, 0x50u8, 0xA5u8]
+            },
+            Test {
+                input: vec![0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8, 0xAAu8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0xBBu8, 0x24u8, 0x90u8, 0x2Bu8, 0x59u8, 0x50u8, 0x90u8, 0xBFu8, 0xC8u8, 0x24u8, 0x64u8, 0x70u8, 0x8Cu8, 0x69u8, 0xB1u8, 0xB2u8, 0xD5u8, 0xB4u8, 0xC5u8, 0x88u8, 0xC6u8, 0x3Bu8, 0x3Fu8]
+            },
+            Test {
+                input: vec![0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8, 0xAAu8, 0x55u8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0x4Fu8, 0xFCu8, 0xEDu8, 0x16u8, 0x59u8, 0x34u8, 0x7Bu8, 0x33u8, 0x9Du8, 0x48u8, 0x6Eu8, 0x1Du8, 0xACu8, 0x0Cu8, 0x62u8, 0xB2u8, 0x76u8, 0xABu8, 0x63u8, 0xBCu8, 0xB3u8, 0xE3u8, 0x4Du8]
+            },
+            Test {
+                input: vec![0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8, 0x55u8, 0xAAu8, 0xFFu8],
+                cost: 5,
+                salt: vec![0x05u8, 0x03u8, 0x00u8, 0x85u8, 0xD5u8, 0xEDu8, 0x4Cu8, 0x17u8, 0x6Bu8, 0x2Au8, 0xC3u8, 0xCBu8, 0xEEu8, 0x47u8, 0x29u8, 0x1Cu8],
+                output: vec![0xFEu8, 0xF4u8, 0x9Bu8, 0xD5u8, 0xE2u8, 0xE1u8, 0xA3u8, 0x9Cu8, 0x25u8, 0xE0u8, 0xFCu8, 0x4Bu8, 0x06u8, 0x9Eu8, 0xF3u8, 0x9Au8, 0x3Au8, 0xECu8, 0x36u8, 0xD3u8, 0xABu8, 0x60u8, 0x48u8]
+            },
+            Test {
+                input: vec![0x00u8],
+                cost: 5,
+                salt: vec![0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8, 0x41u8, 0x04u8, 0x10u8],
+                output: vec![0xF7u8, 0x02u8, 0x36u8, 0x5Cu8, 0x4Du8, 0x4Au8, 0xE1u8, 0xD5u8, 0x3Du8, 0x97u8, 0xCDu8, 0x28u8, 0xB0u8, 0xB9u8, 0x3Fu8, 0x11u8, 0xF7u8, 0x9Fu8, 0xCEu8, 0x44u8, 0xD5u8, 0x60u8, 0xFDu8]
+            }
+        ]
+    }
+
+    #[test]
+    fn test_openwall_test_vectors() {
+        let tests = openwall_test_vectors();
+        let mut output = [0u8; 24];
+        for test in tests.iter() {
+            bcrypt(test.cost, &test.salt[..], &test.input[..], &mut output[..]);
+            assert!(output[0..23] == test.output[..]);
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use bcrypt::bcrypt;
+
+    #[bench]
+    pub fn bcrypt_16_5(bh: & mut Bencher) {
+        let pass = [0u8; 16];
+        let salt = [0u8; 16];
+        let mut out  = [0u8; 24];
+        bh.iter( || {
+            bcrypt(5, &salt, &pass, &mut out);
+        });
+    }
+}
diff --git a/third_party/rust-crypto/src/bcrypt_pbkdf.rs b/third_party/rust-crypto/src/bcrypt_pbkdf.rs
new file mode 100644
index 0000000..afaeb3b
--- /dev/null
+++ b/third_party/rust-crypto/src/bcrypt_pbkdf.rs
@@ -0,0 +1,283 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use blowfish::Blowfish;
+use cryptoutil::{read_u32v_be, write_u32_be, write_u32_le};
+use sha2::Sha512;
+use digest::Digest;
+use step_by::RangeExt;
+
+fn bcrypt_hash(hpass: &[u8], hsalt: &[u8], output: &mut [u8; 32]) {
+    let mut bf = Blowfish::init_state();
+    bf.salted_expand_key(hsalt, hpass);
+
+    for _ in 0..64 {
+        bf.expand_key(hsalt);
+        bf.expand_key(hpass);
+    }
+
+    let mut buf = [0u32; 8];
+    read_u32v_be(&mut buf, b"OxychromaticBlowfishSwatDynamite");
+
+    for i in (0..8).step_up(2) {
+        for _ in 0..64 {
+            let (l, r) = bf.encrypt(buf[i], buf[i+1]);
+            buf[i] = l;
+            buf[i+1] = r;
+        }
+    }
+
+    for i in 0..8 {
+        write_u32_le(&mut output[i*4..(i+1)*4], buf[i]);
+    }
+}
+
+pub fn bcrypt_pbkdf(password: &[u8], salt: &[u8], rounds: u32, output: &mut [u8]) {
+    let mut hpass = [0u8; 64];
+
+    assert!(password.len() > 0);
+    assert!(salt.len() > 0);
+    assert!(rounds > 0);
+    assert!(output.len() > 0);
+    assert!(output.len() <= 1024);
+
+    let nblocks = (output.len() + 31) / 32;
+
+    let mut h = Sha512::new();
+    h.input(password);
+    h.result(&mut hpass);
+
+    for block in 1..(nblocks+1) {
+        let mut count = [0u8; 4];
+        let mut hsalt = [0u8; 64];
+        let mut out   = [0u8; 32];
+        write_u32_be(&mut count, block as u32);
+
+        h.reset();
+        h.input(salt);
+        h.input(&count);
+        h.result(&mut hsalt);
+
+        bcrypt_hash(&hpass, &hsalt, &mut out);
+        let mut tmp = out;
+
+        for _ in 1..rounds {
+            h.reset();
+            h.input(&tmp);
+            h.result(&mut hsalt);
+
+            bcrypt_hash(&hpass, &hsalt, &mut tmp);
+            for i in 0..out.len() {
+                out[i] ^= tmp[i];
+            }
+
+            for i in 0..out.len() {
+                let idx = i * nblocks + (block-1);
+                if idx < output.len() {
+                    output[idx] = out[i];
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use bcrypt_pbkdf::{bcrypt_pbkdf, bcrypt_hash};
+
+    #[test]
+    fn test_bcrypt_hash() {
+        struct Test {
+            hpass: [u8; 64],
+            hsalt: [u8; 64],
+            out:   [u8; 32],
+        }
+
+        let tests = vec!(
+            Test{
+                hpass: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                hsalt: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                out: [
+                    0x46, 0x02, 0x86, 0xe9, 0x72, 0xfa, 0x83, 0x3f, 0x8b, 0x12, 0x83, 0xad, 0x8f, 0xa9, 0x19, 0xfa,
+                    0x29, 0xbd, 0xe2, 0x0e, 0x23, 0x32, 0x9e, 0x77, 0x4d, 0x84, 0x22, 0xba, 0xc0, 0xa7, 0x92, 0x6c, ],
+            }, Test{
+                hpass: [
+                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f ],
+                hsalt: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                out: [
+                    0xb0, 0xb2, 0x29, 0xdb, 0xc6, 0xba, 0xde, 0xf0, 0xe1, 0xda, 0x25, 0x27, 0x47, 0x4a, 0x8b, 0x28,
+                    0x88, 0x8f, 0x8b, 0x06, 0x14, 0x76, 0xfe, 0x80, 0xc3, 0x22, 0x56, 0xe1, 0x14, 0x2d, 0xd0, 0x0d ],
+            }, Test{
+                hpass: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                hsalt: [
+                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f ],
+                out: [
+                    0xb6, 0x2b, 0x4e, 0x36, 0x7d, 0x31, 0x57, 0xf5, 0xc3, 0x1e, 0x4d, 0x2c, 0xba, 0xfb, 0x29, 0x31,
+                    0x49, 0x4d, 0x9d, 0x3b, 0xdd, 0x17, 0x1d, 0x55, 0xcf, 0x79, 0x9f, 0xa4, 0x41, 0x60, 0x42, 0xe2 ],
+            }, Test{
+                hpass: [
+                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f ],
+                hsalt: [
+                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f ],
+                out: [
+                    0xc6, 0xa9, 0x5f, 0xe6, 0x41, 0x31, 0x15, 0xfb, 0x57, 0xe9, 0x9f, 0x75, 0x74, 0x98, 0xe8, 0x5d,
+                    0xa3, 0xc6, 0xe1, 0xdf, 0x0c, 0x3c, 0x93, 0xaa, 0x97, 0x5c, 0x54, 0x8a, 0x34, 0x43, 0x26, 0xf8 ],
+            },
+        );
+
+        for t in tests.iter() {
+            let mut out = [0u8; 32];
+            bcrypt_hash(&t.hpass, &t.hsalt, &mut out);
+            assert!(out == t.out);
+        }
+    }
+
+    #[test]
+    fn test_openbsd_vectors() {
+        struct Test{
+            password: Vec<u8>,
+            salt: Vec<u8>,
+            rounds: u32,
+            out: Vec<u8>,
+        }
+
+        let tests = vec!(
+            Test{
+                password: b"password".to_vec(),
+                salt: b"salt".to_vec(),
+                rounds: 4,
+                out: vec![
+                    0x5b, 0xbf, 0x0c, 0xc2, 0x93, 0x58, 0x7f, 0x1c, 0x36, 0x35, 0x55, 0x5c, 0x27, 0x79, 0x65, 0x98,
+                    0xd4, 0x7e, 0x57, 0x90, 0x71, 0xbf, 0x42, 0x7e, 0x9d, 0x8f, 0xbe, 0x84, 0x2a, 0xba, 0x34, 0xd9],
+            }, Test{
+                password: b"password".to_vec(),
+                salt: vec![0],
+                rounds: 4,
+                out: vec![0xc1, 0x2b, 0x56, 0x62, 0x35, 0xee, 0xe0, 0x4c, 0x21, 0x25, 0x98, 0x97, 0x0a, 0x57, 0x9a, 0x67],
+            }, Test{
+                password: vec![0],
+                salt: b"salt".to_vec(),
+                rounds: 4,
+                out: vec![0x60, 0x51, 0xbe, 0x18, 0xc2, 0xf4, 0xf8, 0x2c, 0xbf, 0x0e, 0xfe, 0xe5, 0x47, 0x1b, 0x4b, 0xb9],
+            }, Test{
+                password: b"password\x00".to_vec(),
+                salt: b"salt\x00".to_vec(),
+                rounds: 4,
+                out: vec![
+                    0x74, 0x10, 0xe4, 0x4c, 0xf4, 0xfa, 0x07, 0xbf, 0xaa, 0xc8, 0xa9, 0x28, 0xb1, 0x72, 0x7f, 0xac,
+                    0x00, 0x13, 0x75, 0xe7, 0xbf, 0x73, 0x84, 0x37, 0x0f, 0x48, 0xef, 0xd1, 0x21, 0x74, 0x30, 0x50],
+            }, Test{
+                password: b"pass\x00wor".to_vec(),
+                salt: b"sa\x00l".to_vec(),
+                rounds: 4,
+                out: vec![0xc2, 0xbf, 0xfd, 0x9d, 0xb3, 0x8f, 0x65, 0x69, 0xef, 0xef, 0x43, 0x72, 0xf4, 0xde, 0x83, 0xc0],
+            }, Test{
+                password: b"pass\x00word".to_vec(),
+                salt: b"sa\x00lt".to_vec(),
+                rounds: 4,
+                out: vec![0x4b, 0xa4, 0xac, 0x39, 0x25, 0xc0, 0xe8, 0xd7, 0xf0, 0xcd, 0xb6, 0xbb, 0x16, 0x84, 0xa5, 0x6f],
+            }, Test{
+                password: b"password".to_vec(),
+                salt: b"salt".to_vec(),
+                rounds: 8,
+                out: vec![
+                    0xe1, 0x36, 0x7e, 0xc5, 0x15, 0x1a, 0x33, 0xfa, 0xac, 0x4c, 0xc1, 0xc1, 0x44, 0xcd, 0x23, 0xfa,
+                    0x15, 0xd5, 0x54, 0x84, 0x93, 0xec, 0xc9, 0x9b, 0x9b, 0x5d, 0x9c, 0x0d, 0x3b, 0x27, 0xbe, 0xc7,
+                    0x62, 0x27, 0xea, 0x66, 0x08, 0x8b, 0x84, 0x9b, 0x20, 0xab, 0x7a, 0xa4, 0x78, 0x01, 0x02, 0x46,
+                    0xe7, 0x4b, 0xba, 0x51, 0x72, 0x3f, 0xef, 0xa9, 0xf9, 0x47, 0x4d, 0x65, 0x08, 0x84, 0x5e, 0x8d],
+            }, Test{
+                password: b"password".to_vec(),
+                salt: b"salt".to_vec(),
+                rounds: 42,
+                out: vec![0x83, 0x3c, 0xf0, 0xdc, 0xf5, 0x6d, 0xb6, 0x56, 0x08, 0xe8, 0xf0, 0xdc, 0x0c, 0xe8, 0x82, 0xbd],
+            }, Test{
+                password: b"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.".to_vec(),
+                salt: b"salis\x00".to_vec(),
+                rounds: 8,
+                out: vec![0x10, 0x97, 0x8b, 0x07, 0x25, 0x3d, 0xf5, 0x7f, 0x71, 0xa1, 0x62, 0xeb, 0x0e, 0x8a, 0xd3, 0x0a],
+            }, Test{
+                password: vec![0x0d, 0xb3, 0xac, 0x94, 0xb3, 0xee, 0x53, 0x28, 0x4f, 0x4a, 0x22, 0x89, 0x3b, 0x3c, 0x24, 0xae],
+                salt: vec![0x3a, 0x62, 0xf0, 0xf0, 0xdb, 0xce, 0xf8, 0x23, 0xcf, 0xcc, 0x85, 0x48, 0x56, 0xea, 0x10, 0x28],
+                rounds: 8,
+                out: vec![0x20, 0x44, 0x38, 0x17, 0x5e, 0xee, 0x7c, 0xe1, 0x36, 0xc9, 0x1b, 0x49, 0xa6, 0x79, 0x23, 0xff],
+            }, Test{
+                password: vec![0x0d, 0xb3, 0xac, 0x94, 0xb3, 0xee, 0x53, 0x28, 0x4f, 0x4a, 0x22, 0x89, 0x3b, 0x3c, 0x24, 0xae],
+                salt: vec![0x3a, 0x62, 0xf0, 0xf0, 0xdb, 0xce, 0xf8, 0x23, 0xcf, 0xcc, 0x85, 0x48, 0x56, 0xea, 0x10, 0x28],
+                rounds: 8,
+                out: vec![
+                    0x20, 0x54, 0xb9, 0xff, 0xf3, 0x4e, 0x37, 0x21, 0x44, 0x03, 0x34, 0x74, 0x68, 0x28, 0xe9, 0xed,
+                    0x38, 0xde, 0x4b, 0x72, 0xe0, 0xa6, 0x9a, 0xdc, 0x17, 0x0a, 0x13, 0xb5, 0xe8, 0xd6, 0x46, 0x38,
+                    0x5e, 0xa4, 0x03, 0x4a, 0xe6, 0xd2, 0x66, 0x00, 0xee, 0x23, 0x32, 0xc5, 0xed, 0x40, 0xad, 0x55,
+                    0x7c, 0x86, 0xe3, 0x40, 0x3f, 0xbb, 0x30, 0xe4, 0xe1, 0xdc, 0x1a, 0xe0, 0x6b, 0x99, 0xa0, 0x71,
+                    0x36, 0x8f, 0x51, 0x8d, 0x2c, 0x42, 0x66, 0x51, 0xc9, 0xe7, 0xe4, 0x37, 0xfd, 0x6c, 0x91, 0x5b,
+                    0x1b, 0xbf, 0xc3, 0xa4, 0xce, 0xa7, 0x14, 0x91, 0x49, 0x0e, 0xa7, 0xaf, 0xb7, 0xdd, 0x02, 0x90,
+                    0xa6, 0x78, 0xa4, 0xf4, 0x41, 0x12, 0x8d, 0xb1, 0x79, 0x2e, 0xab, 0x27, 0x76, 0xb2, 0x1e, 0xb4,
+                    0x23, 0x8e, 0x07, 0x15, 0xad, 0xd4, 0x12, 0x7d, 0xff, 0x44, 0xe4, 0xb3, 0xe4, 0xcc, 0x4c, 0x4f,
+                    0x99, 0x70, 0x08, 0x3f, 0x3f, 0x74, 0xbd, 0x69, 0x88, 0x73, 0xfd, 0xf6, 0x48, 0x84, 0x4f, 0x75,
+                    0xc9, 0xbf, 0x7f, 0x9e, 0x0c, 0x4d, 0x9e, 0x5d, 0x89, 0xa7, 0x78, 0x39, 0x97, 0x49, 0x29, 0x66,
+                    0x61, 0x67, 0x07, 0x61, 0x1c, 0xb9, 0x01, 0xde, 0x31, 0xa1, 0x97, 0x26, 0xb6, 0xe0, 0x8c, 0x3a,
+                    0x80, 0x01, 0x66, 0x1f, 0x2d, 0x5c, 0x9d, 0xcc, 0x33, 0xb4, 0xaa, 0x07, 0x2f, 0x90, 0xdd, 0x0b,
+                    0x3f, 0x54, 0x8d, 0x5e, 0xeb, 0xa4, 0x21, 0x13, 0x97, 0xe2, 0xfb, 0x06, 0x2e, 0x52, 0x6e, 0x1d,
+                    0x68, 0xf4, 0x6a, 0x4c, 0xe2, 0x56, 0x18, 0x5b, 0x4b, 0xad, 0xc2, 0x68, 0x5f, 0xbe, 0x78, 0xe1,
+                    0xc7, 0x65, 0x7b, 0x59, 0xf8, 0x3a, 0xb9, 0xab, 0x80, 0xcf, 0x93, 0x18, 0xd6, 0xad, 0xd1, 0xf5,
+                    0x93, 0x3f, 0x12, 0xd6, 0xf3, 0x61, 0x82, 0xc8, 0xe8, 0x11, 0x5f, 0x68, 0x03, 0x0a, 0x12, 0x44],
+            },
+        );
+
+        for t in tests.iter() {
+            let mut out: Vec<u8> = repeat(0).take(t.out.len()).collect();
+            bcrypt_pbkdf(&t.password[..], &t.salt[..], t.rounds, &mut out[..]);
+            assert_eq!(out, t.out);
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use bcrypt_pbkdf::bcrypt_pbkdf;
+
+    #[bench]
+    fn bench_bcrypt_pbkdf_5_32(b: &mut Bencher) {
+        let pass = [0u8; 16];
+        let salt = [0u8; 16];
+        let mut out  = [0u8; 32];
+
+        b.iter(|| {
+            bcrypt_pbkdf(&pass, &salt, 5, &mut out);
+        });
+    }
+}
diff --git a/third_party/rust-crypto/src/blake2b.rs b/third_party/rust-crypto/src/blake2b.rs
new file mode 100644
index 0000000..5ba19df
--- /dev/null
+++ b/third_party/rust-crypto/src/blake2b.rs
@@ -0,0 +1,563 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::prelude::v1::*;
+use std::iter::repeat;
+use cryptoutil::{copy_memory, read_u64v_le, write_u64v_le};
+use digest::Digest;
+use mac::{Mac, MacResult};
+use util::secure_memset;
+
+static IV : [u64; 8] = [
+  0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
+  0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
+  0x510e527fade682d1, 0x9b05688c2b3e6c1f,
+  0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
+];
+
+static SIGMA : [[usize; 16]; 12] = [
+  [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 ],
+  [ 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 ],
+  [ 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 ],
+  [  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 ],
+  [  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 ],
+  [  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 ],
+  [ 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 ],
+  [ 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 ],
+  [  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 ],
+  [ 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 ],
+  [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 ],
+  [ 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 ],
+];
+
+const BLAKE2B_BLOCKBYTES : usize = 128;
+const BLAKE2B_OUTBYTES : usize = 64;
+const BLAKE2B_KEYBYTES : usize = 64;
+const BLAKE2B_SALTBYTES : usize = 16;
+const BLAKE2B_PERSONALBYTES : usize = 16;
+
+#[derive(Copy)]
+pub struct Blake2b {
+    h: [u64; 8],
+    t: [u64; 2],
+    f: [u64; 2],
+    buf: [u8; 2*BLAKE2B_BLOCKBYTES],
+    buflen: usize,
+    key: [u8; BLAKE2B_KEYBYTES],
+    key_length: u8,
+    last_node: u8,
+    digest_length: u8,
+    computed: bool, // whether the final digest has been computed
+    param: Blake2bParam
+}
+
+impl Clone for Blake2b { fn clone(&self) -> Blake2b { *self } }
+
+#[derive(Copy, Clone)]
+struct Blake2bParam {
+    digest_length: u8,
+    key_length: u8,
+    fanout: u8,
+    depth: u8,
+    leaf_length: u32,
+    node_offset: u64,
+    node_depth: u8,
+    inner_length: u8,
+    reserved: [u8; 14],
+    salt: [u8; BLAKE2B_SALTBYTES],
+    personal: [u8; BLAKE2B_PERSONALBYTES],
+}
+
+macro_rules! G( ($r:expr, $i:expr, $a:expr, $b:expr, $c:expr, $d:expr, $m:expr) => ({
+    $a = $a.wrapping_add($b).wrapping_add($m[SIGMA[$r][2*$i+0]]);
+    $d = ($d ^ $a).rotate_right(32);
+    $c = $c.wrapping_add($d);
+    $b = ($b ^ $c).rotate_right(24);
+    $a = $a.wrapping_add($b).wrapping_add($m[SIGMA[$r][2*$i+1]]);
+    $d = ($d ^ $a).rotate_right(16);
+    $c = $c .wrapping_add($d);
+    $b = ($b ^ $c).rotate_right(63);
+}));
+
+macro_rules! round( ($r:expr, $v:expr, $m:expr) => ( {
+    G!($r,0,$v[ 0],$v[ 4],$v[ 8],$v[12], $m);
+    G!($r,1,$v[ 1],$v[ 5],$v[ 9],$v[13], $m);
+    G!($r,2,$v[ 2],$v[ 6],$v[10],$v[14], $m);
+    G!($r,3,$v[ 3],$v[ 7],$v[11],$v[15], $m);
+    G!($r,4,$v[ 0],$v[ 5],$v[10],$v[15], $m);
+    G!($r,5,$v[ 1],$v[ 6],$v[11],$v[12], $m);
+    G!($r,6,$v[ 2],$v[ 7],$v[ 8],$v[13], $m);
+    G!($r,7,$v[ 3],$v[ 4],$v[ 9],$v[14], $m);
+  }
+));
+
+impl Blake2b {
+    fn set_lastnode(&mut self) {
+        self.f[1] = 0xFFFFFFFFFFFFFFFF;
+    }
+
+    fn set_lastblock(&mut self) {
+        if self.last_node!=0 {
+            self.set_lastnode();
+        }
+        self.f[0] = 0xFFFFFFFFFFFFFFFF;
+    }
+
+    fn increment_counter(&mut self, inc : u64) {
+        self.t[0] += inc;
+        self.t[1] += if self.t[0] < inc { 1 } else { 0 };
+    }
+
+    fn init0(param: Blake2bParam, digest_length: u8, key: &[u8]) -> Blake2b {
+        assert!(key.len() <= BLAKE2B_KEYBYTES);
+        let mut b = Blake2b {
+            h: IV,
+            t: [0,0],
+            f: [0,0],
+            buf: [0; 2*BLAKE2B_BLOCKBYTES],
+            buflen: 0,
+            last_node: 0,
+            digest_length: digest_length,
+            computed: false,
+            key: [0; BLAKE2B_KEYBYTES],
+            key_length: key.len() as u8,
+            param: param
+        };
+        copy_memory(key, &mut b.key);
+        b
+    }
+
+    fn apply_param(&mut self) {
+        use std::io::Write;
+        use cryptoutil::WriteExt;
+
+        let mut param_bytes : [u8; 64] = [0; 64];
+        {
+            let mut writer: &mut [u8] = &mut param_bytes;
+            writer.write_u8(self.param.digest_length).unwrap();
+            writer.write_u8(self.param.key_length).unwrap();
+            writer.write_u8(self.param.fanout).unwrap();
+            writer.write_u8(self.param.depth).unwrap();
+            writer.write_u32_le(self.param.leaf_length).unwrap();
+            writer.write_u64_le(self.param.node_offset).unwrap();
+            writer.write_u8(self.param.node_depth).unwrap();
+            writer.write_u8(self.param.inner_length).unwrap();
+            writer.write_all(&self.param.reserved).unwrap();
+            writer.write_all(&self.param.salt).unwrap();
+            writer.write_all(&self.param.personal).unwrap();
+        }
+
+        let mut param_words : [u64; 8] = [0; 8];
+        read_u64v_le(&mut param_words, &param_bytes);
+        for (h, param_word) in self.h.iter_mut().zip(param_words.iter()) {
+            *h = *h ^ *param_word;
+        }
+    }
+
+
+    // init xors IV with input parameter block
+    fn init_param( p: Blake2bParam, key: &[u8] ) -> Blake2b {
+        let mut b = Blake2b::init0(p, p.digest_length, key);
+        b.apply_param();
+        b
+    }
+
+    fn default_param(outlen: u8) -> Blake2bParam {
+        Blake2bParam {
+            digest_length: outlen,
+            key_length: 0,
+            fanout: 1,
+            depth: 1,
+            leaf_length: 0,
+            node_offset: 0,
+            node_depth: 0,
+            inner_length: 0,
+            reserved: [0; 14],
+            salt: [0; BLAKE2B_SALTBYTES],
+            personal: [0; BLAKE2B_PERSONALBYTES],
+        }
+    }
+
+    pub fn new(outlen: usize) -> Blake2b {
+        assert!(outlen > 0 && outlen <= BLAKE2B_OUTBYTES);
+        Blake2b::init_param(Blake2b::default_param(outlen as u8), &[])
+    }
+
+    fn apply_key(&mut self) {
+        let mut block : [u8; BLAKE2B_BLOCKBYTES] = [0; BLAKE2B_BLOCKBYTES];
+        copy_memory(&self.key[..self.key_length as usize], &mut block);
+        self.update(&block);
+        secure_memset(&mut block[..], 0);
+    }
+
+    pub fn new_keyed(outlen: usize, key: &[u8] ) -> Blake2b {
+        assert!(outlen > 0 && outlen <= BLAKE2B_OUTBYTES);
+        assert!(key.len() > 0 && key.len() <= BLAKE2B_KEYBYTES);
+
+        let param = Blake2bParam {
+            digest_length: outlen as u8,
+            key_length: key.len() as u8,
+            fanout: 1,
+            depth: 1,
+            leaf_length: 0,
+            node_offset: 0,
+            node_depth: 0,
+            inner_length: 0,
+            reserved: [0; 14],
+            salt: [0; BLAKE2B_SALTBYTES],
+            personal: [0; BLAKE2B_PERSONALBYTES],
+        };
+
+        let mut b = Blake2b::init_param(param, key);
+        b.apply_key();
+        b
+    }
+
+    fn compress(&mut self) {
+        let mut ms: [u64; 16] = [0; 16];
+        let mut vs: [u64; 16] = [0; 16];
+
+        read_u64v_le(&mut ms, &self.buf[0..BLAKE2B_BLOCKBYTES]);
+
+        for (v, h) in vs.iter_mut().zip(self.h.iter()) {
+            *v = *h;
+        }
+
+        vs[ 8] = IV[0];
+        vs[ 9] = IV[1];
+        vs[10] = IV[2];
+        vs[11] = IV[3];
+        vs[12] = self.t[0] ^ IV[4];
+        vs[13] = self.t[1] ^ IV[5];
+        vs[14] = self.f[0] ^ IV[6];
+        vs[15] = self.f[1] ^ IV[7];
+        round!(  0, vs, ms );
+        round!(  1, vs, ms );
+        round!(  2, vs, ms );
+        round!(  3, vs, ms );
+        round!(  4, vs, ms );
+        round!(  5, vs, ms );
+        round!(  6, vs, ms );
+        round!(  7, vs, ms );
+        round!(  8, vs, ms );
+        round!(  9, vs, ms );
+        round!( 10, vs, ms );
+        round!( 11, vs, ms );
+
+        for (h_elem, (v_low, v_high)) in self.h.iter_mut().zip( vs[0..8].iter().zip(vs[8..16].iter()) ) {
+            *h_elem = *h_elem ^ *v_low ^ *v_high;
+        }
+    }
+
+    fn update( &mut self, mut input: &[u8] ) {
+        while input.len() > 0 {
+            let left = self.buflen;
+            let fill = 2 * BLAKE2B_BLOCKBYTES - left;
+
+            if input.len() > fill {
+                copy_memory(&input[0..fill], &mut self.buf[left..]); // Fill buffer
+                self.buflen += fill;
+                self.increment_counter( BLAKE2B_BLOCKBYTES as u64);
+                self.compress();
+
+                let mut halves = self.buf.chunks_mut(BLAKE2B_BLOCKBYTES);
+                let first_half = halves.next().unwrap();
+                let second_half = halves.next().unwrap();
+                copy_memory(second_half, first_half);
+
+                self.buflen -= BLAKE2B_BLOCKBYTES;
+                input = &input[fill..input.len()];
+            } else { // inlen <= fill
+                copy_memory(input, &mut self.buf[left..]);
+                self.buflen += input.len();
+                break;
+            }
+        }
+    }
+
+    fn finalize( &mut self, out: &mut [u8] ) {
+        assert!(out.len() == self.digest_length as usize);
+        if !self.computed {
+            if self.buflen > BLAKE2B_BLOCKBYTES {
+                self.increment_counter(BLAKE2B_BLOCKBYTES as u64);
+                self.compress();
+                self.buflen -= BLAKE2B_BLOCKBYTES;
+
+                let mut halves = self.buf.chunks_mut(BLAKE2B_BLOCKBYTES);
+                let first_half = halves.next().unwrap();
+                let second_half = halves.next().unwrap();
+                copy_memory(second_half, first_half);
+            }
+
+            let incby = self.buflen as u64;
+            self.increment_counter(incby);
+            self.set_lastblock();
+            for b in self.buf[self.buflen..].iter_mut() {
+                *b = 0;
+            }
+            self.compress();
+
+            write_u64v_le(&mut self.buf[0..64], &self.h);
+            self.computed = true;
+        }
+        let outlen = out.len();
+        copy_memory(&self.buf[0..outlen], out);
+    }
+
+    pub fn reset(&mut self) {
+        for (h_elem, iv_elem) in self.h.iter_mut().zip(IV.iter()) {
+            *h_elem = *iv_elem;
+        }
+        for t_elem in self.t.iter_mut() {
+            *t_elem = 0;
+        }
+        for f_elem in self.f.iter_mut() {
+            *f_elem = 0;
+        }
+        for b in self.buf.iter_mut() {
+            *b = 0;
+        }
+        self.buflen = 0;
+        self.last_node = 0;
+        self.computed = false;
+        self.apply_param();
+        if self.key_length > 0 {
+            self.apply_key();
+        }
+    }
+
+    pub fn blake2b(out: &mut[u8], input: &[u8], key: &[u8]) {
+        let mut hasher : Blake2b = if key.len() > 0 { Blake2b::new_keyed(out.len(), key) } else { Blake2b::new(out.len()) };
+
+        hasher.update(input);
+        hasher.finalize(out);
+    }
+}
+
+impl Digest for Blake2b {
+    fn reset(&mut self) { Blake2b::reset(self); }
+    fn input(&mut self, msg: &[u8]) { self.update(msg); }
+    fn result(&mut self, out: &mut [u8]) { self.finalize(out); }
+    fn output_bits(&self) -> usize { 8 * (self.digest_length as usize) }
+    fn block_size(&self) -> usize { 8 * BLAKE2B_BLOCKBYTES }
+}
+
+impl Mac for Blake2b {
+    /**
+     * Process input data.
+     *
+     * # Arguments
+     * * data - The input data to process.
+     *
+     */
+    fn input(&mut self, data: &[u8]) {
+        self.update(data);
+    }
+
+    /**
+     * Reset the Mac state to begin processing another input stream.
+     */
+    fn reset(&mut self) {
+        Blake2b::reset(self);
+    }
+
+    /**
+     * Obtain the result of a Mac computation as a MacResult.
+     */
+    fn result(&mut self) -> MacResult {
+        let mut mac: Vec<u8> = repeat(0).take(self.digest_length as usize).collect();
+        self.raw_result(&mut mac);
+        MacResult::new_from_owned(mac)
+    }
+
+    /**
+     * Obtain the result of a Mac computation as [u8]. This method should be used very carefully
+     * since incorrect use of the Mac code could result in permitting a timing attack which defeats
+     * the security provided by a Mac function.
+     */
+    fn raw_result(&mut self, output: &mut [u8]) {
+        self.finalize(output);
+    }
+
+    /**
+     * Get the size of the Mac code, in bytes.
+     */
+    fn output_bytes(&self) -> usize { self.digest_length as usize }
+}
+
+#[cfg(test)]
+mod digest_tests {
+    //use cryptoutil::test::test_digest_1million_random;
+    use blake2b::Blake2b;
+    use digest::Digest;
+    use serialize::hex::FromHex;
+
+
+    struct Test {
+        input: Vec<u8>,
+        output: Vec<u8>,
+        key: Option<Vec<u8>>,
+    }
+
+    fn test_hash(tests: &[Test]) {
+        for t in tests {
+            let mut sh = match t.key {
+                Some(ref key) => Blake2b::new_keyed(64, &key),
+                None => Blake2b::new(64)
+            };
+
+            // Test that it works when accepting the message all at once
+            sh.input(&t.input[..]);
+
+            let mut out = [0u8; 64];
+            sh.result(&mut out);
+            assert!(&out[..] == &t.output[..]);
+
+            sh.reset();
+
+            // Test that it works when accepting the message in pieces
+            let len = t.input.len();
+            let mut left = len;
+            while left > 0 {
+                let take = (left + 1) / 2;
+                sh.input(&t.input[len - left..take + len - left]);
+                left -= take;
+            }
+
+            let mut out = [0u8; 64];
+            sh.result(&mut out);
+            assert!(&out[..] == &t.output[..]);
+
+            sh.reset();
+        }
+    }
+
+    #[test]
+    fn test_blake2b_digest() {
+        let tests = vec![
+            // Examples from wikipedia
+            Test {
+                input: vec![],
+                output: "786a02f742015903c6c6fd852552d272\
+                         912f4740e15847618a86e217f71f5419\
+                         d25e1031afee585313896444934eb04b\
+                         903a685b1448b755d56f701afe9be2ce".from_hex().unwrap(),
+                key: None
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog".as_bytes().to_vec(),
+                output: "a8add4bdddfd93e4877d2746e62817b1\
+                         16364a1fa7bc148d95090bc7333b3673\
+                         f82401cf7aa2e4cb1ecd90296e3f14cb\
+                         5413f8ed77be73045b13914cdcd6a918".from_hex().unwrap(),
+                key: None
+            },
+            // from: https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2b-test.txt
+            Test {
+                input: vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+                            0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+                            0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                            0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+                            0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+                            0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+                            0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+                            0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+                            0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+                            0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+                            0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+                            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
+                            0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+                            0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
+                            0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+                            0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
+                            0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+                            0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
+                            0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+                            0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
+                            0xfc, 0xfd, 0xfe],
+                output: vec![0x14, 0x27, 0x09, 0xd6, 0x2e, 0x28, 0xfc, 0xcc, 0xd0, 0xaf, 0x97,
+                             0xfa, 0xd0, 0xf8, 0x46, 0x5b, 0x97, 0x1e, 0x82, 0x20, 0x1d, 0xc5,
+                             0x10, 0x70, 0xfa, 0xa0, 0x37, 0x2a, 0xa4, 0x3e, 0x92, 0x48, 0x4b,
+                             0xe1, 0xc1, 0xe7, 0x3b, 0xa1, 0x09, 0x06, 0xd5, 0xd1, 0x85, 0x3d,
+                             0xb6, 0xa4, 0x10, 0x6e, 0x0a, 0x7b, 0xf9, 0x80, 0x0d, 0x37, 0x3d,
+                             0x6d, 0xee, 0x2d, 0x46, 0xd6, 0x2e, 0xf2, 0xa4, 0x61],
+                key: Some(vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+                               0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+                               0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+                               0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+                               0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+                               0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f])
+            },
+        ];
+
+        test_hash(&tests[..]);
+    }
+}
+
+
+#[cfg(test)]
+mod mac_tests {
+    use blake2b::Blake2b;
+    use mac::Mac;
+
+    #[test]
+    fn test_blake2b_mac() {
+        let key: Vec<u8> = (0..64).map(|i| i).collect();
+        let mut m = Blake2b::new_keyed(64, &key[..]);
+        m.input(&[1,2,4,8]);
+        let expected = [
+            0x8e, 0xc6, 0xcb, 0x71, 0xc4, 0x5c, 0x3c, 0x90,
+            0x91, 0xd0, 0x8a, 0x37, 0x1e, 0xa8, 0x5d, 0xc1,
+            0x22, 0xb5, 0xc8, 0xe2, 0xd9, 0xe5, 0x71, 0x42,
+            0xbf, 0xef, 0xce, 0x42, 0xd7, 0xbc, 0xf8, 0x8b,
+            0xb0, 0x31, 0x27, 0x88, 0x2e, 0x51, 0xa9, 0x21,
+            0x44, 0x62, 0x08, 0xf6, 0xa3, 0x58, 0xa9, 0xe0,
+            0x7d, 0x35, 0x3b, 0xd3, 0x1c, 0x41, 0x70, 0x15,
+            0x62, 0xac, 0xd5, 0x39, 0x4e, 0xee, 0x73, 0xae,
+        ];
+        assert_eq!(m.result().code().to_vec(), expected.to_vec());
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+
+    use digest::Digest;
+    use blake2b::Blake2b;
+
+
+    #[bench]
+    pub fn blake2b_10(bh: & mut Bencher) {
+        let mut sh = Blake2b::new(64);
+        let bytes = [1u8; 10];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn blake2b_1k(bh: & mut Bencher) {
+        let mut sh = Blake2b::new(64);
+        let bytes = [1u8; 1024];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn blake2b_64k(bh: & mut Bencher) {
+        let mut sh = Blake2b::new(64);
+        let bytes = [1u8; 65536];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/blake2s.rs b/third_party/rust-crypto/src/blake2s.rs
new file mode 100644
index 0000000..b5cb9bf
--- /dev/null
+++ b/third_party/rust-crypto/src/blake2s.rs
@@ -0,0 +1,525 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::prelude::v1::*;
+use std::iter::repeat;
+use cryptoutil::{copy_memory, read_u32v_le, write_u32v_le};
+use digest::Digest;
+use mac::{Mac, MacResult};
+use util::secure_memset;
+
+static IV : [u32; 8] = [
+  0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+  0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
+];
+
+static SIGMA : [[usize; 16]; 10] = [
+  [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 ],
+  [ 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 ],
+  [ 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 ],
+  [  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 ],
+  [  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 ],
+  [  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 ],
+  [ 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 ],
+  [ 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 ],
+  [  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 ],
+  [ 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 ]
+];
+
+const BLAKE2S_BLOCKBYTES : usize = 64;
+const BLAKE2S_OUTBYTES : usize = 32;
+const BLAKE2S_KEYBYTES : usize = 32;
+const BLAKE2S_SALTBYTES : usize = 8;
+const BLAKE2S_PERSONALBYTES : usize = 8;
+
+#[derive(Copy)]
+pub struct Blake2s {
+    h: [u32; 8],
+    t: [u32; 2],
+    f: [u32; 2],
+    buf: [u8; 2*BLAKE2S_BLOCKBYTES],
+    buflen: usize,
+    key: [u8; BLAKE2S_KEYBYTES],
+    key_length: u8,
+    last_node: u8,
+    digest_length: u8,
+    computed: bool, // whether the final digest has been computed
+    param: Blake2sParam
+}
+
+impl Clone for Blake2s { fn clone(&self) -> Blake2s { *self } }
+
+#[derive(Copy, Clone)]
+struct Blake2sParam {
+    digest_length: u8,
+    key_length: u8,
+    fanout: u8,
+    depth: u8,
+    leaf_length: u32,
+    node_offset: [u8; 6],
+    node_depth: u8,
+    inner_length: u8,
+    salt: [u8; BLAKE2S_SALTBYTES],
+    personal: [u8; BLAKE2S_PERSONALBYTES],
+}
+
+macro_rules! G( ($r:expr, $i:expr, $a:expr, $b:expr, $c:expr, $d:expr, $m:expr) => ({
+    $a = $a.wrapping_add($b).wrapping_add($m[SIGMA[$r][2*$i+0]]);
+    $d = ($d ^ $a).rotate_right(16);
+    $c = $c.wrapping_add($d);
+    $b = ($b ^ $c).rotate_right(12);
+    $a = $a.wrapping_add($b).wrapping_add($m[SIGMA[$r][2*$i+1]]);
+    $d = ($d ^ $a).rotate_right(8);
+    $c = $c.wrapping_add($d);
+    $b = ($b ^ $c).rotate_right(7);
+}));
+
+macro_rules! round( ($r:expr, $v:expr, $m:expr) => ( {
+    G!($r,0,$v[ 0],$v[ 4],$v[ 8],$v[12], $m);
+    G!($r,1,$v[ 1],$v[ 5],$v[ 9],$v[13], $m);
+    G!($r,2,$v[ 2],$v[ 6],$v[10],$v[14], $m);
+    G!($r,3,$v[ 3],$v[ 7],$v[11],$v[15], $m);
+    G!($r,4,$v[ 0],$v[ 5],$v[10],$v[15], $m);
+    G!($r,5,$v[ 1],$v[ 6],$v[11],$v[12], $m);
+    G!($r,6,$v[ 2],$v[ 7],$v[ 8],$v[13], $m);
+    G!($r,7,$v[ 3],$v[ 4],$v[ 9],$v[14], $m);
+  }
+));
+
+impl Blake2s {
+    fn set_lastnode(&mut self) {
+        self.f[1] = 0xFFFFFFFF;
+    }
+
+    fn set_lastblock(&mut self) {
+        if self.last_node!=0 {
+            self.set_lastnode();
+        }
+        self.f[0] = 0xFFFFFFFF;
+    }
+
+    fn increment_counter(&mut self, inc : u32) {
+        self.t[0] += inc;
+        self.t[1] += if self.t[0] < inc { 1 } else { 0 };
+    }
+
+    fn init0(param: Blake2sParam, digest_length: u8, key: &[u8]) -> Blake2s {
+        assert!(key.len() <= BLAKE2S_KEYBYTES);
+        let mut b = Blake2s {
+            h: IV,
+            t: [0,0],
+            f: [0,0],
+            buf: [0; 2*BLAKE2S_BLOCKBYTES],
+            buflen: 0,
+            last_node: 0,
+            digest_length: digest_length,
+            computed: false,
+            key: [0; BLAKE2S_KEYBYTES],
+            key_length: key.len() as u8,
+            param: param
+        };
+        copy_memory(key, &mut b.key);
+        b
+    }
+
+    fn apply_param(&mut self) {
+        use std::io::Write;
+        use cryptoutil::WriteExt;
+
+        let mut param_bytes : [u8; 32] = [0; 32];
+        {
+            let mut writer: &mut [u8] = &mut param_bytes;
+            writer.write_u8(self.param.digest_length).unwrap();
+            writer.write_u8(self.param.key_length).unwrap();
+            writer.write_u8(self.param.fanout).unwrap();
+            writer.write_u8(self.param.depth).unwrap();
+            writer.write_u32_le(self.param.leaf_length).unwrap();
+            writer.write_all(&self.param.node_offset).unwrap();
+            writer.write_u8(self.param.node_depth).unwrap();
+            writer.write_u8(self.param.inner_length).unwrap();
+            writer.write_all(&self.param.salt).unwrap();
+            writer.write_all(&self.param.personal).unwrap();
+        }
+
+        let mut param_words : [u32; 8] = [0; 8];
+        read_u32v_le(&mut param_words, &param_bytes);
+        for (h, param_word) in self.h.iter_mut().zip(param_words.iter()) {
+            *h = *h ^ *param_word;
+        }
+    }
+
+
+    // init xors IV with input parameter block
+    fn init_param( p: Blake2sParam, key: &[u8] ) -> Blake2s {
+        let mut b = Blake2s::init0(p, p.digest_length, key);
+        b.apply_param();
+        b
+    }
+
+    fn default_param(outlen: u8) -> Blake2sParam {
+        Blake2sParam {
+            digest_length: outlen,
+            key_length: 0,
+            fanout: 1,
+            depth: 1,
+            leaf_length: 0,
+            node_offset: [0; 6],
+            node_depth: 0,
+            inner_length: 0,
+            salt: [0; BLAKE2S_SALTBYTES],
+            personal: [0; BLAKE2S_PERSONALBYTES],
+        }
+    }
+
+    pub fn new(outlen: usize) -> Blake2s {
+        assert!(outlen > 0 && outlen <= BLAKE2S_OUTBYTES);
+        Blake2s::init_param(Blake2s::default_param(outlen as u8), &[])
+    }
+
+    fn apply_key(&mut self) {
+        let mut block : [u8; BLAKE2S_BLOCKBYTES] = [0; BLAKE2S_BLOCKBYTES];
+        copy_memory(&self.key[..self.key_length as usize], &mut block);
+        self.update(&block);
+        secure_memset(&mut block[..], 0);
+    }
+
+    pub fn new_keyed(outlen: usize, key: &[u8] ) -> Blake2s {
+        assert!(outlen > 0 && outlen <= BLAKE2S_OUTBYTES);
+        assert!(key.len() > 0 && key.len() <= BLAKE2S_KEYBYTES);
+
+        let param = Blake2sParam {
+            digest_length: outlen as u8,
+            key_length: key.len() as u8,
+            fanout: 1,
+            depth: 1,
+            leaf_length: 0,
+            node_offset: [0; 6],
+            node_depth: 0,
+            inner_length: 0,
+            salt: [0; BLAKE2S_SALTBYTES],
+            personal: [0; BLAKE2S_PERSONALBYTES],
+        };
+
+        let mut b = Blake2s::init_param(param, key);
+        b.apply_key();
+        b
+    }
+
+    fn compress(&mut self) {
+        let mut ms: [u32; 16] = [0; 16];
+        let mut vs: [u32; 16] = [0; 16];
+
+        read_u32v_le(&mut ms, &self.buf[0..BLAKE2S_BLOCKBYTES]);
+
+        for (v, h) in vs.iter_mut().zip(self.h.iter()) {
+            *v = *h;
+        }
+
+        vs[ 8] = IV[0];
+        vs[ 9] = IV[1];
+        vs[10] = IV[2];
+        vs[11] = IV[3];
+        vs[12] = self.t[0] ^ IV[4];
+        vs[13] = self.t[1] ^ IV[5];
+        vs[14] = self.f[0] ^ IV[6];
+        vs[15] = self.f[1] ^ IV[7];
+        round!(  0, vs, ms );
+        round!(  1, vs, ms );
+        round!(  2, vs, ms );
+        round!(  3, vs, ms );
+        round!(  4, vs, ms );
+        round!(  5, vs, ms );
+        round!(  6, vs, ms );
+        round!(  7, vs, ms );
+        round!(  8, vs, ms );
+        round!(  9, vs, ms );
+
+        for (h_elem, (v_low, v_high)) in self.h.iter_mut().zip( vs[0..8].iter().zip(vs[8..16].iter()) ) {
+            *h_elem = *h_elem ^ *v_low ^ *v_high;
+        }
+    }
+
+    fn update( &mut self, mut input: &[u8] ) {
+        while input.len() > 0 {
+            let left = self.buflen;
+            let fill = 2 * BLAKE2S_BLOCKBYTES - left;
+
+            if input.len() > fill {
+                copy_memory(&input[0..fill], &mut self.buf[left..]); // Fill buffer
+                self.buflen += fill;
+                self.increment_counter( BLAKE2S_BLOCKBYTES as u32);
+                self.compress();
+
+                let mut halves = self.buf.chunks_mut(BLAKE2S_BLOCKBYTES);
+                let first_half = halves.next().unwrap();
+                let second_half = halves.next().unwrap();
+                copy_memory(second_half, first_half);
+
+                self.buflen -= BLAKE2S_BLOCKBYTES;
+                input = &input[fill..input.len()];
+            } else { // inlen <= fill
+                copy_memory(input, &mut self.buf[left..]);
+                self.buflen += input.len();
+                break;
+            }
+        }
+    }
+
+    fn finalize( &mut self, out: &mut [u8] ) {
+        assert!(out.len() == self.digest_length as usize);
+        if !self.computed {
+            if self.buflen > BLAKE2S_BLOCKBYTES {
+                self.increment_counter(BLAKE2S_BLOCKBYTES as u32);
+                self.compress();
+                self.buflen -= BLAKE2S_BLOCKBYTES;
+
+                let mut halves = self.buf.chunks_mut(BLAKE2S_BLOCKBYTES);
+                let first_half = halves.next().unwrap();
+                let second_half = halves.next().unwrap();
+                copy_memory(second_half, first_half);
+            }
+
+            let incby = self.buflen as u32;
+            self.increment_counter(incby);
+            self.set_lastblock();
+            for b in self.buf[self.buflen..].iter_mut() {
+                *b = 0;
+            }
+            self.compress();
+
+            write_u32v_le(&mut self.buf[0..32], &self.h);
+            self.computed = true;
+        }
+        let outlen = out.len();
+        copy_memory(&self.buf[0..outlen], out);
+    }
+
+    pub fn reset(&mut self) {
+        for (h_elem, iv_elem) in self.h.iter_mut().zip(IV.iter()) {
+            *h_elem = *iv_elem;
+        }
+        for t_elem in self.t.iter_mut() {
+            *t_elem = 0;
+        }
+        for f_elem in self.f.iter_mut() {
+            *f_elem = 0;
+        }
+        for b in self.buf.iter_mut() {
+            *b = 0;
+        }
+        self.buflen = 0;
+        self.last_node = 0;
+        self.computed = false;
+        self.apply_param();
+        if self.key_length > 0 {
+            self.apply_key();
+        }
+    }
+
+    pub fn blake2s(out: &mut[u8], input: &[u8], key: &[u8]) {
+        let mut hasher : Blake2s = if key.len() > 0 { Blake2s::new_keyed(out.len(), key) } else { Blake2s::new(out.len()) };
+
+        hasher.update(input);
+        hasher.finalize(out);
+    }
+}
+
+impl Digest for Blake2s {
+    fn reset(&mut self) { Blake2s::reset(self); }
+    fn input(&mut self, msg: &[u8]) { self.update(msg); }
+    fn result(&mut self, out: &mut [u8]) { self.finalize(out); }
+    fn output_bits(&self) -> usize { 8 * (self.digest_length as usize) }
+    fn block_size(&self) -> usize { 8 * BLAKE2S_BLOCKBYTES }
+}
+
+impl Mac for Blake2s {
+    /**
+     * Process input data.
+     *
+     * # Arguments
+     * * data - The input data to process.
+     *
+     */
+    fn input(&mut self, data: &[u8]) {
+        self.update(data);
+    }
+
+    /**
+     * Reset the Mac state to begin processing another input stream.
+     */
+    fn reset(&mut self) {
+        Blake2s::reset(self);
+    }
+
+    /**
+     * Obtain the result of a Mac computation as a MacResult.
+     */
+    fn result(&mut self) -> MacResult {
+        let mut mac: Vec<u8> = repeat(0).take(self.digest_length as usize).collect();
+        self.raw_result(&mut mac);
+        MacResult::new_from_owned(mac)
+    }
+
+    /**
+     * Obtain the result of a Mac computation as [u8]. This method should be used very carefully
+     * since incorrect use of the Mac code could result in permitting a timing attack which defeats
+     * the security provided by a Mac function.
+     */
+    fn raw_result(&mut self, output: &mut [u8]) {
+        self.finalize(output);
+    }
+
+    /**
+     * Get the size of the Mac code, in bytes.
+     */
+    fn output_bytes(&self) -> usize { self.digest_length as usize }
+}
+
+#[cfg(test)]
+mod digest_tests {
+    //use cryptoutil::test::test_digest_1million_random;
+    use blake2s::Blake2s;
+    use digest::Digest;
+
+
+    struct Test {
+        input: Vec<u8>,
+        output: Vec<u8>,
+        key: Option<Vec<u8>>,
+    }
+
+    fn test_hash(tests: &[Test]) {
+        for t in tests {
+            let mut sh = match t.key {
+                Some(ref key) => Blake2s::new_keyed(32, &key),
+                None => Blake2s::new(32)
+            };
+
+            // Test that it works when accepting the message all at once
+            sh.input(&t.input[..]);
+
+            let mut out = [0u8; 32];
+            sh.result(&mut out);
+            assert!(&out[..] == &t.output[..]);
+
+            sh.reset();
+
+            // Test that it works when accepting the message in pieces
+            let len = t.input.len();
+            let mut left = len;
+            while left > 0 {
+                let take = (left + 1) / 2;
+                sh.input(&t.input[len - left..take + len - left]);
+                left -= take;
+            }
+
+            let mut out = [0u8; 32];
+            sh.result(&mut out);
+            assert!(&out[..] == &t.output[..]);
+
+            sh.reset();
+        }
+    }
+
+    #[test]
+    fn test_blake2s_digest() {
+        let tests = vec![
+            // from: https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2s-test.txt
+            Test {
+                input: vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+                            0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+                            0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                            0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+                            0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+                            0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+                            0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+                            0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+                            0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+                            0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+                            0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+                            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
+                            0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+                            0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
+                            0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+                            0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
+                            0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+                            0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
+                            0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+                            0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
+                            0xfc, 0xfd, 0xfe],
+                output: vec![0x3f, 0xb7, 0x35, 0x06, 0x1a, 0xbc, 0x51, 0x9d, 0xfe, 0x97, 0x9e,
+                             0x54, 0xc1, 0xee, 0x5b, 0xfa, 0xd0, 0xa9, 0xd8, 0x58, 0xb3, 0x31,
+                             0x5b, 0xad, 0x34, 0xbd, 0xe9, 0x99, 0xef, 0xd7, 0x24, 0xdd],
+                key: Some(vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+                               0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+                               0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f])
+            },
+        ];
+
+        test_hash(&tests[..]);
+    }
+}
+
+
+#[cfg(test)]
+mod mac_tests {
+    use blake2s::Blake2s;
+    use mac::Mac;
+
+    #[test]
+    fn test_blake2s_mac() {
+        let key: Vec<u8> = (0..32).map(|i| i).collect();
+        let mut m = Blake2s::new_keyed(32, &key[..]);
+        m.input(&[1,2,4,8]);
+        let expected = [
+            0x0e, 0x88, 0xf6, 0x8a, 0xaa, 0x5c, 0x4e, 0xd8,
+            0xf7, 0xed, 0x28, 0xf8, 0x04, 0x45, 0x01, 0x9c,
+            0x7e, 0xf9, 0x76, 0x2b, 0x4f, 0xf1, 0xad, 0x7e,
+            0x05, 0x5b, 0xa8, 0xc8, 0x82, 0x9e, 0xe2, 0x49
+        ];
+        assert_eq!(m.result().code().to_vec(), expected.to_vec());
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+
+    use digest::Digest;
+    use blake2s::Blake2s;
+
+
+    #[bench]
+    pub fn blake2s_10(bh: & mut Bencher) {
+        let mut sh = Blake2s::new(32);
+        let bytes = [1u8; 10];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn blake2s_1k(bh: & mut Bencher) {
+        let mut sh = Blake2s::new(32);
+        let bytes = [1u8; 1024];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn blake2s_64k(bh: & mut Bencher) {
+        let mut sh = Blake2s::new(32);
+        let bytes = [1u8; 65536];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/blockmodes.rs b/third_party/rust-crypto/src/blockmodes.rs
new file mode 100644
index 0000000..29e2a51
--- /dev/null
+++ b/third_party/rust-crypto/src/blockmodes.rs
@@ -0,0 +1,1438 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// TODO - Optimize the XORs
+// TODO - Maybe use macros to specialize BlockEngine for encryption or decryption?
+// TODO - I think padding could be done better. Maybe macros for BlockEngine would help this too.
+
+use std::prelude::v1::*;
+use std::cmp;
+use std::iter::repeat;
+
+use buffer::{ReadBuffer, WriteBuffer, OwnedReadBuffer, OwnedWriteBuffer, BufferResult,
+    RefReadBuffer, RefWriteBuffer};
+use buffer::BufferResult::{BufferUnderflow, BufferOverflow};
+use cryptoutil::{self, symm_enc_or_dec};
+use symmetriccipher::{BlockEncryptor, BlockEncryptorX8, Encryptor, BlockDecryptor, Decryptor,
+    SynchronousStreamCipher, SymmetricCipherError};
+use symmetriccipher::SymmetricCipherError::{InvalidPadding, InvalidLength};
+
+/// The BlockProcessor trait is used to implement modes that require processing complete blocks of
+/// data. The methods of this trait are called by the BlockEngine which is in charge of properly
+/// buffering input data.
+trait BlockProcessor {
+    /// Process a block of data. The in_hist and out_hist parameters represent the input and output
+    /// when the last block was processed. These values are necessary for certain modes.
+    fn process_block(&mut self, in_hist: &[u8], out_hist: &[u8], input: &[u8], output: &mut [u8]);
+}
+
+/// A PaddingProcessor handles adding or removing padding
+pub trait PaddingProcessor {
+    /// Add padding to the last block of input data
+    /// If the mode can't handle a non-full block, it signals that error by simply leaving the block
+    /// as it is which will be detected as an InvalidLength error.
+    fn pad_input<W: WriteBuffer>(&mut self, input_buffer: &mut W);
+
+    /// Remove padding from the last block of output data
+    /// If false is returned, the processing fails
+    fn strip_output<R: ReadBuffer>(&mut self, output_buffer: &mut R) -> bool;
+}
+
+/// The BlockEngine is implemented as a state machine with the following states. See comments in the
+/// BlockEngine code for more information on the states.
+#[derive(Clone, Copy)]
+enum BlockEngineState {
+    FastMode,
+    NeedInput,
+    NeedOutput,
+    LastInput,
+    LastInput2,
+    Finished,
+    Error(SymmetricCipherError)
+}
+
+/// BlockEngine buffers input and output data and handles sending complete block of data to the
+/// Processor object. Additionally, BlockEngine handles logic necessary to add or remove padding by
+/// calling the appropriate methods on the Processor object.
+struct BlockEngine<P, X> {
+    /// The block sized expected by the Processor
+    block_size: usize,
+
+    /// in_hist and out_hist keep track of data that was input to and output from the last
+    /// invocation of the process_block() method of the Processor. Depending on the mode, these may
+    /// be empty vectors if history is not needed.
+    in_hist: Vec<u8>,
+    out_hist: Vec<u8>,
+
+    /// If some input data is supplied, but not a complete blocks worth, it is stored in this buffer
+    /// until enough arrives that it can be passed to the process_block() method of the Processor.
+    in_scratch: OwnedWriteBuffer,
+
+    /// If input data is processed but there isn't enough space in the output buffer to store it,
+    /// it is written into out_write_scratch. OwnedWriteBuffer's may be converted into
+    /// OwnedReaderBuffers without re-allocating, so, after being written, out_write_scratch is
+    /// turned into out_read_scratch. After that, if is written to the output as more output becomes
+    /// available. The main point is - only out_write_scratch or out_read_scratch contains a value
+    /// at any given time; never both.
+    out_write_scratch: Option<OwnedWriteBuffer>,
+    out_read_scratch: Option<OwnedReadBuffer>,
+
+    /// The processor that implements the particular block mode.
+    processor: P,
+
+    /// The padding processor
+    padding: X,
+
+    /// The current state of the operation.
+    state: BlockEngineState
+}
+
+fn update_history(in_hist: &mut [u8], out_hist: &mut [u8], last_in: &[u8], last_out: &[u8]) {
+    let in_hist_len = in_hist.len();
+    if in_hist_len > 0 {
+        cryptoutil::copy_memory(
+            &last_in[last_in.len() - in_hist_len..],
+            in_hist);
+    }
+    let out_hist_len = out_hist.len();
+    if out_hist_len > 0 {
+        cryptoutil::copy_memory(
+            &last_out[last_out.len() - out_hist_len..],
+            out_hist);
+    }
+}
+
+impl <P: BlockProcessor, X: PaddingProcessor> BlockEngine<P, X> {
+    /// Create a new BlockProcessor instance with the given processor and block_size. No history
+    /// will be saved.
+    fn new(processor: P, padding: X, block_size: usize) -> BlockEngine<P, X> {
+        BlockEngine {
+            block_size: block_size,
+            in_hist: Vec::new(),
+            out_hist: Vec::new(),
+            in_scratch: OwnedWriteBuffer::new(repeat(0).take(block_size).collect()),
+            out_write_scratch: Some(OwnedWriteBuffer::new(repeat(0).take(block_size).collect())),
+            out_read_scratch: None,
+            processor: processor,
+            padding: padding,
+            state: BlockEngineState::FastMode
+        }
+    }
+
+    /// Create a new BlockProcessor instance with the given processor, block_size, and initial input
+    /// and output history.
+    fn new_with_history(
+            processor: P,
+            padding: X,
+            block_size: usize,
+            in_hist: Vec<u8>,
+            out_hist: Vec<u8>) -> BlockEngine<P, X> {
+        BlockEngine {
+            in_hist: in_hist,
+            out_hist: out_hist,
+            ..BlockEngine::new(processor, padding, block_size)
+        }
+    }
+
+    /// This implements the FastMode state. Ideally, the encryption or decryption operation should
+    /// do the bulk of its work in FastMode. Significantly, FastMode avoids doing copies as much as
+    /// possible. The FastMode state does not handle the final block of data.
+    fn fast_mode<R: ReadBuffer, W: WriteBuffer>(
+            &mut self,
+            input: &mut R,
+            output: &mut W) -> BlockEngineState {
+        fn has_next<R: ReadBuffer, W: WriteBuffer>(
+                input: &mut R,
+                output: &mut W,
+                block_size: usize) -> bool {
+            // Not the greater than - very important since this method must never process the last
+            // block.
+            let enough_input = input.remaining() > block_size;
+            let enough_output = output.remaining() >= block_size;
+            enough_input && enough_output
+        };
+        fn split_at<'a>(vec: &'a [u8], at: usize) -> (&'a [u8], &'a [u8]) {
+            (&vec[..at], &vec[at..])
+        }
+
+        // First block processing. We have to retrieve the history information from self.in_hist and
+        // self.out_hist.
+        if !has_next(input, output, self.block_size) {
+            if input.is_empty() {
+                return BlockEngineState::FastMode;
+            } else {
+                return BlockEngineState::NeedInput;
+            }
+        } else {
+            let next_in = input.take_next(self.block_size);
+            let next_out = output.take_next(self.block_size);
+            self.processor.process_block(
+                &self.in_hist[..],
+                &self.out_hist[..],
+                next_in,
+                next_out);
+        }
+
+        // Process all remaing blocks. We can pull the history out of the buffers without having to
+        // do any copies
+        let next_in_size = self.in_hist.len() + self.block_size;
+        let next_out_size = self.out_hist.len() + self.block_size;
+        while has_next(input, output, self.block_size) {
+            input.rewind(self.in_hist.len());
+            let (in_hist, next_in) = split_at(input.take_next(next_in_size), self.in_hist.len());
+            output.rewind(self.out_hist.len());
+            let (out_hist, next_out) = output.take_next(next_out_size).split_at_mut(
+                self.out_hist.len());
+            self.processor.process_block(
+                in_hist,
+                out_hist,
+                next_in,
+                next_out);
+        }
+
+        // Save the history and then transition to the next state
+        {
+            input.rewind(self.in_hist.len());
+            let last_in = input.take_next(self.in_hist.len());
+            output.rewind(self.out_hist.len());
+            let last_out = output.take_next(self.out_hist.len());
+            update_history(
+                &mut self.in_hist,
+                &mut self.out_hist,
+                last_in,
+                last_out);
+        }
+        if input.is_empty() {
+            BlockEngineState::FastMode
+        } else {
+            BlockEngineState::NeedInput
+        }
+    }
+
+    /// This method implements the BlockEngine state machine.
+    fn process<R: ReadBuffer, W: WriteBuffer>(
+            &mut self,
+            input: &mut R,
+            output: &mut W,
+            eof: bool) -> Result<BufferResult, SymmetricCipherError> {
+        // Process a block of data from in_scratch and write the result to out_write_scratch.
+        // Finally, convert out_write_scratch into out_read_scratch.
+        fn process_scratch<P: BlockProcessor, X: PaddingProcessor>(me: &mut BlockEngine<P, X>) {
+            let mut rin = me.in_scratch.take_read_buffer();
+            let mut wout = me.out_write_scratch.take().unwrap();
+
+            {
+                let next_in = rin.take_remaining();
+                let next_out = wout.take_remaining();
+                me.processor.process_block(
+                    &me.in_hist[..],
+                    &me.out_hist[..],
+                    next_in,
+                    next_out);
+                update_history(
+                    &mut me.in_hist,
+                    &mut me.out_hist,
+                    next_in,
+                    next_out);
+            }
+
+            let rb = wout.into_read_buffer();
+            me.out_read_scratch = Some(rb);
+        };
+
+        loop {
+            match self.state {
+                // FastMode tries to process as much data as possible while minimizing copies.
+                // FastMode doesn't make use of the scratch buffers and only updates the history
+                // just before exiting.
+                BlockEngineState::FastMode => {
+                    self.state = self.fast_mode(input, output);
+                    match self.state {
+                        BlockEngineState::FastMode => {
+                            // If FastMode completes but stays in the FastMode state, it means that
+                            // we've run out of input data.
+                            return Ok(BufferUnderflow);
+                        }
+                        _ => {}
+                    }
+                }
+
+                // The NeedInput mode is entered when there isn't enough data to run in FastMode
+                // anymore. Input data is buffered in in_scratch until there is a full block or eof
+                // occurs. IF eof doesn't occur, the data is processed and then we go to the
+                // NeedOutput state. Otherwise, we go to the LastInput state. This state always
+                // writes all available data into in_scratch before transitioning to the next state.
+                BlockEngineState::NeedInput => {
+                    input.push_to(&mut self.in_scratch);
+                    if !input.is_empty() {
+                        // !is_empty() guarantees two things - in_scratch is full and its not the
+                        // last block. This state must never process the last block.
+                        process_scratch(self);
+                        self.state = BlockEngineState::NeedOutput;
+                    } else {
+                        if eof {
+                            self.state = BlockEngineState::LastInput;
+                        } else {
+                            return Ok(BufferUnderflow);
+                        }
+                    }
+                }
+
+                // The NeedOutput state just writes buffered processed data to the output stream
+                // until all of it has been written.
+                BlockEngineState::NeedOutput => {
+                    let mut rout = self.out_read_scratch.take().unwrap();
+                    rout.push_to(output);
+                    if rout.is_empty() {
+                        self.out_write_scratch = Some(rout.into_write_buffer());
+                        self.state = BlockEngineState::FastMode;
+                    } else {
+                        self.out_read_scratch = Some(rout);
+                        return Ok(BufferOverflow);
+                    }
+                }
+
+                // None of the other states are allowed to process the last block of data since
+                // last block handling is a little tricky due to modes have special needs regarding
+                // padding. When the last block of data is detected, this state is transitioned to
+                // for handling.
+                BlockEngineState::LastInput => {
+                    // We we arrive in this state, we know that all input data that is going to be
+                    // supplied has been suplied and that that data has been written to in_scratch
+                    // by the NeedInput state. Furthermore, we know that one of three things must be
+                    // true about in_scratch:
+                    // 1) It is empty. This only occurs if the input is zero length. We can do last
+                    //    block processing by executing the pad_input() method of the processor
+                    //    which may either pad out to a full block or leave it empty, process the
+                    //    data if it was padded out to a full block, and then pass it to
+                    //    strip_output().
+                    // 2) It is partially filled. This will occur if the input data was not a
+                    //    multiple of the block size. Processing proceeds identically to case #1.
+                    // 3) It is full. This case occurs when the input data was a multiple of the
+                    //    block size. This case is a little trickier, since, depending on the mode,
+                    //    we might actually have 2 blocks worth of data to process - the last user
+                    //    supplied block (currently in in_scratch) and then another block that could
+                    //    be added as padding. Processing proceeds by first processing the data in
+                    //    in_scratch and writing it to out_scratch. Then, the now-empty in_scratch
+                    //    buffer is passed to pad_input() which may leave it empty or write a block
+                    //    of padding to it. If no padding is added, processing proceeds as in cases
+                    //    #1 and #2. However, if padding is added, now have data in in_scratch and
+                    //    also in out_scratch meaning that we can't immediately process the padding
+                    //    data since we have nowhere to put it. So, we transition to the LastInput2
+                    //    state which will first write out the last non-padding block, then process
+                    //    the padding block (in in_scratch) and write it to the now-empty
+                    //    out_scratch.
+                    if !self.in_scratch.is_full() {
+                        self.padding.pad_input(&mut self.in_scratch);
+                        if self.in_scratch.is_full() {
+                            process_scratch(self);
+                            if self.padding.strip_output(self.out_read_scratch.as_mut().unwrap()) {
+                                self.state = BlockEngineState::Finished;
+                            } else {
+                                self.state = BlockEngineState::Error(InvalidPadding);
+                            }
+                        } else if self.in_scratch.is_empty() {
+                            self.state = BlockEngineState::Finished;
+                        } else {
+                            self.state = BlockEngineState::Error(InvalidLength);
+                        }
+                    } else {
+                        process_scratch(self);
+                        self.padding.pad_input(&mut self.in_scratch);
+                        if self.in_scratch.is_full() {
+                            self.state = BlockEngineState::LastInput2;
+                        } else if self.in_scratch.is_empty() {
+                            if self.padding.strip_output(self.out_read_scratch.as_mut().unwrap()) {
+                                self.state = BlockEngineState::Finished;
+                            } else {
+                                self.state = BlockEngineState::Error(InvalidPadding);
+                            }
+                        } else {
+                            self.state = BlockEngineState::Error(InvalidLength);
+                        }
+                    }
+                }
+
+                // See the comments on LastInput for more details. This state handles final blocks
+                // of data in the case that the input was a multiple of the block size and the mode
+                // decided to add a full extra block of padding.
+                BlockEngineState::LastInput2 => {
+                    let mut rout = self.out_read_scratch.take().unwrap();
+                    rout.push_to(output);
+                    if rout.is_empty() {
+                        self.out_write_scratch = Some(rout.into_write_buffer());
+                        process_scratch(self);
+                        if self.padding.strip_output(self.out_read_scratch.as_mut().unwrap()) {
+                            self.state = BlockEngineState::Finished;
+                        } else {
+                            self.state = BlockEngineState::Error(InvalidPadding);
+                        }
+                    } else {
+                        self.out_read_scratch = Some(rout);
+                        return Ok(BufferOverflow);
+                    }
+                }
+
+                // The Finished mode just writes the data in out_scratch to the output until there
+                // is no more data left.
+                BlockEngineState::Finished => {
+                    match self.out_read_scratch {
+                        Some(ref mut rout) => {
+                            rout.push_to(output);
+                            if rout.is_empty() {
+                                return Ok(BufferUnderflow);
+                            } else {
+                                return Ok(BufferOverflow);
+                            }
+                        }
+                        None => { return Ok(BufferUnderflow); }
+                    }
+                }
+
+                // The Error state is used to store error information.
+                BlockEngineState::Error(err) => {
+                    return Err(err);
+                }
+            }
+        }
+    }
+    fn reset(&mut self) {
+        self.state = BlockEngineState::FastMode;
+        self.in_scratch.reset();
+        if self.out_read_scratch.is_some() {
+            let ors = self.out_read_scratch.take().unwrap();
+            let ows = ors.into_write_buffer();
+            self.out_write_scratch = Some(ows);
+        } else {
+            self.out_write_scratch.as_mut().unwrap().reset();
+        }
+    }
+    fn reset_with_history(&mut self, in_hist: &[u8], out_hist: &[u8]) {
+        self.reset();
+        cryptoutil::copy_memory(in_hist, &mut self.in_hist);
+        cryptoutil::copy_memory(out_hist, &mut self.out_hist);
+    }
+}
+
+/// No padding mode for ECB and CBC encryption
+#[derive(Clone, Copy)]
+pub struct NoPadding;
+
+impl PaddingProcessor for NoPadding {
+    fn pad_input<W: WriteBuffer>(&mut self, _: &mut W) { }
+    fn strip_output<R: ReadBuffer>(&mut self, _: &mut R) -> bool { true }
+}
+
+/// PKCS padding mode for ECB and CBC encryption
+#[derive(Clone, Copy)]
+pub struct PkcsPadding;
+
+// This class implements both encryption padding, where padding is added, and decryption padding,
+// where padding is stripped. Since BlockEngine doesn't know if its an Encryption or Decryption
+// operation, it will call both methods if given a chance. So, this class can't be passed directly
+// to BlockEngine. Instead, it must be wrapped with EncPadding or DecPadding which will ensure that
+// only the propper methods are called. The client of the library, however, doesn't have to
+// distinguish encryption padding handling from decryption padding handline, which is the whole
+// point.
+impl PaddingProcessor for PkcsPadding {
+    fn pad_input<W: WriteBuffer>(&mut self, input_buffer: &mut W) {
+        let rem = input_buffer.remaining();
+        assert!(rem != 0 && rem <= 255);
+        for v in input_buffer.take_remaining().iter_mut() {
+            *v = rem as u8;
+        }
+    }
+    fn strip_output<R: ReadBuffer>(&mut self, output_buffer: &mut R) -> bool {
+        let last_byte: u8;
+        {
+            let data = output_buffer.peek_remaining();
+            last_byte = *data.last().unwrap();
+            for &x in data.iter().rev().take(last_byte as usize) {
+                if x != last_byte {
+                    return false;
+                }
+            }
+        }
+        output_buffer.truncate(last_byte as usize);
+        true
+    }
+}
+
+/// Wraps a PaddingProcessor so that only pad_input() will actually be called.
+pub struct EncPadding<X> {
+    padding: X
+}
+
+impl <X: PaddingProcessor> EncPadding<X> {
+    fn wrap(p: X) -> EncPadding<X> { EncPadding { padding: p } }
+}
+
+impl <X: PaddingProcessor> PaddingProcessor for EncPadding<X> {
+    fn pad_input<W: WriteBuffer>(&mut self, a: &mut W) { self.padding.pad_input(a); }
+    fn strip_output<R: ReadBuffer>(&mut self, _: &mut R) -> bool { true }
+}
+
+/// Wraps a PaddingProcessor so that only strip_output() will actually be called.
+pub struct DecPadding<X> {
+    padding: X
+}
+
+impl <X: PaddingProcessor> DecPadding<X> {
+    fn wrap(p: X) -> DecPadding<X> { DecPadding { padding: p } }
+}
+
+impl <X: PaddingProcessor> PaddingProcessor for DecPadding<X> {
+    fn pad_input<W: WriteBuffer>(&mut self, _: &mut W) { }
+    fn strip_output<R: ReadBuffer>(&mut self, a: &mut R) -> bool { self.padding.strip_output(a) }
+}
+
+struct EcbEncryptorProcessor<T> {
+    algo: T
+}
+
+impl <T: BlockEncryptor> BlockProcessor for EcbEncryptorProcessor<T> {
+    fn process_block(&mut self, _: &[u8], _: &[u8], input: &[u8], output: &mut [u8]) {
+        self.algo.encrypt_block(input, output);
+    }
+}
+
+/// ECB Encryption mode
+pub struct EcbEncryptor<T, X> {
+    block_engine: BlockEngine<EcbEncryptorProcessor<T>, X>
+}
+
+impl <T: BlockEncryptor, X: PaddingProcessor> EcbEncryptor<T, X> {
+    /// Create a new ECB encryption mode object
+    pub fn new(algo: T, padding: X) -> EcbEncryptor<T, EncPadding<X>> {
+        let block_size = algo.block_size();
+        let processor = EcbEncryptorProcessor {
+            algo: algo
+        };
+        EcbEncryptor {
+            block_engine: BlockEngine::new(processor, EncPadding::wrap(padding), block_size)
+        }
+    }
+    pub fn reset(&mut self) {
+        self.block_engine.reset();
+    }
+}
+
+impl <T: BlockEncryptor, X: PaddingProcessor> Encryptor for EcbEncryptor<T, X> {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, eof: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        self.block_engine.process(input, output, eof)
+    }
+}
+
+struct EcbDecryptorProcessor<T> {
+    algo: T
+}
+
+impl <T: BlockDecryptor> BlockProcessor for EcbDecryptorProcessor<T> {
+    fn process_block(&mut self, _: &[u8], _: &[u8], input: &[u8], output: &mut [u8]) {
+        self.algo.decrypt_block(input, output);
+    }
+}
+
+/// ECB Decryption mode
+pub struct EcbDecryptor<T, X> {
+    block_engine: BlockEngine<EcbDecryptorProcessor<T>, X>
+}
+
+impl <T: BlockDecryptor, X: PaddingProcessor> EcbDecryptor<T, X> {
+    /// Create a new ECB decryption mode object
+    pub fn new(algo: T, padding: X) -> EcbDecryptor<T, DecPadding<X>> {
+        let block_size = algo.block_size();
+        let processor = EcbDecryptorProcessor {
+            algo: algo
+        };
+        EcbDecryptor {
+            block_engine: BlockEngine::new(processor, DecPadding::wrap(padding), block_size)
+        }
+    }
+    pub fn reset(&mut self) {
+        self.block_engine.reset();
+    }
+}
+
+impl <T: BlockDecryptor, X: PaddingProcessor> Decryptor for EcbDecryptor<T, X> {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, eof: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        self.block_engine.process(input, output, eof)
+    }
+}
+
+struct CbcEncryptorProcessor<T> {
+    algo: T,
+    temp: Vec<u8>
+}
+
+impl <T: BlockEncryptor> BlockProcessor for CbcEncryptorProcessor<T> {
+    fn process_block(&mut self, _: &[u8], out_hist: &[u8], input: &[u8], output: &mut [u8]) {
+        for ((&x, &y), o) in input.iter().zip(out_hist.iter()).zip(self.temp.iter_mut()) {
+            *o = x ^ y;
+        }
+        self.algo.encrypt_block(&self.temp[..], output);
+    }
+}
+
+/// CBC encryption mode
+pub struct CbcEncryptor<T, X> {
+    block_engine: BlockEngine<CbcEncryptorProcessor<T>, X>
+}
+
+impl <T: BlockEncryptor, X: PaddingProcessor> CbcEncryptor<T, X> {
+    /// Create a new CBC encryption mode object
+    pub fn new(algo: T, padding: X, iv: Vec<u8>) -> CbcEncryptor<T, EncPadding<X>> {
+        let block_size = algo.block_size();
+        let processor = CbcEncryptorProcessor {
+            algo: algo,
+            temp: repeat(0).take(block_size).collect()
+        };
+        CbcEncryptor {
+            block_engine: BlockEngine::new_with_history(
+                processor,
+                EncPadding::wrap(padding),
+                block_size,
+                Vec::new(),
+                iv)
+        }
+    }
+    pub fn reset(&mut self, iv: &[u8]) {
+        self.block_engine.reset_with_history(&[], iv);
+    }
+}
+
+impl <T: BlockEncryptor, X: PaddingProcessor> Encryptor for CbcEncryptor<T, X> {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, eof: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        self.block_engine.process(input, output, eof)
+    }
+}
+
+struct CbcDecryptorProcessor<T> {
+    algo: T,
+    temp: Vec<u8>
+}
+
+impl <T: BlockDecryptor> BlockProcessor for CbcDecryptorProcessor<T> {
+    fn process_block(&mut self, in_hist: &[u8], _: &[u8], input: &[u8], output: &mut [u8]) {
+        self.algo.decrypt_block(input, &mut self.temp);
+        for ((&x, &y), o) in self.temp.iter().zip(in_hist.iter()).zip(output.iter_mut()) {
+            *o = x ^ y;
+        }
+    }
+}
+
+/// CBC decryption mode
+pub struct CbcDecryptor<T, X> {
+    block_engine: BlockEngine<CbcDecryptorProcessor<T>, X>
+}
+
+impl <T: BlockDecryptor, X: PaddingProcessor> CbcDecryptor<T, X> {
+    /// Create a new CBC decryption mode object
+    pub fn new(algo: T, padding: X, iv: Vec<u8>) -> CbcDecryptor<T, DecPadding<X>> {
+        let block_size = algo.block_size();
+        let processor = CbcDecryptorProcessor {
+            algo: algo,
+            temp: repeat(0).take(block_size).collect()
+        };
+        CbcDecryptor {
+            block_engine: BlockEngine::new_with_history(
+                processor,
+                DecPadding::wrap(padding),
+                block_size,
+                iv,
+                Vec::new())
+        }
+    }
+    pub fn reset(&mut self, iv: &[u8]) {
+        self.block_engine.reset_with_history(iv, &[]);
+    }
+}
+
+impl <T: BlockDecryptor, X: PaddingProcessor> Decryptor for CbcDecryptor<T, X> {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, eof: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        self.block_engine.process(input, output, eof)
+    }
+}
+
+fn add_ctr(ctr: &mut [u8], mut ammount: u8) {
+    for i in ctr.iter_mut().rev() {
+        let prev = *i;
+        *i = i.wrapping_add(ammount);
+        if *i >= prev {
+            break;
+        }
+        ammount = 1;
+    }
+}
+
+/// CTR Mode
+pub struct CtrMode<A> {
+    algo: A,
+    ctr: Vec<u8>,
+    bytes: OwnedReadBuffer
+}
+
+impl <A: BlockEncryptor> CtrMode<A> {
+    /// Create a new CTR object
+    pub fn new(algo: A, ctr: Vec<u8>) -> CtrMode<A> {
+        let block_size = algo.block_size();
+        CtrMode {
+            algo: algo,
+            ctr: ctr,
+            bytes: OwnedReadBuffer::new_with_len(repeat(0).take(block_size).collect(), 0)
+        }
+    }
+    pub fn reset(&mut self, ctr: &[u8]) {
+        cryptoutil::copy_memory(ctr, &mut self.ctr);
+        self.bytes.reset();
+    }
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == output.len());
+        let len = input.len();
+        let mut i = 0;
+        while i < len {
+            if self.bytes.is_empty() {
+                let mut wb = self.bytes.borrow_write_buffer();
+                self.algo.encrypt_block(&self.ctr[..], wb.take_remaining());
+                add_ctr(&mut self.ctr, 1);
+            }
+            let count = cmp::min(self.bytes.remaining(), len - i);
+            let bytes_it = self.bytes.take_next(count).iter();
+            let in_it = input[i..].iter();
+            let out_it = output[i..].iter_mut();
+            for ((&x, &y), o) in bytes_it.zip(in_it).zip(out_it) {
+                *o = x ^ y;
+            }
+            i += count;
+        }
+    }
+}
+
+impl <A: BlockEncryptor> SynchronousStreamCipher for CtrMode<A> {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        self.process(input, output);
+    }
+}
+
+impl <A: BlockEncryptor> Encryptor for CtrMode<A> {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl <A: BlockEncryptor> Decryptor for CtrMode<A> {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+/// CTR Mode that operates on 8 blocks at a time
+pub struct CtrModeX8<A> {
+    algo: A,
+    ctr_x8: Vec<u8>,
+    bytes: OwnedReadBuffer
+}
+
+fn construct_ctr_x8(in_ctr: &[u8], out_ctr_x8: &mut [u8]) {
+    for (i, ctr_i) in out_ctr_x8.chunks_mut(in_ctr.len()).enumerate() {
+        cryptoutil::copy_memory(in_ctr, ctr_i);
+        add_ctr(ctr_i, i as u8);
+    }
+}
+
+impl <A: BlockEncryptorX8> CtrModeX8<A> {
+    /// Create a new CTR object that operates on 8 blocks at a time
+    pub fn new(algo: A, ctr: &[u8]) -> CtrModeX8<A> {
+        let block_size = algo.block_size();
+        let mut ctr_x8: Vec<u8> = repeat(0).take(block_size * 8).collect();
+        construct_ctr_x8(ctr, &mut ctr_x8);
+        CtrModeX8 {
+            algo: algo,
+            ctr_x8: ctr_x8,
+            bytes: OwnedReadBuffer::new_with_len(repeat(0).take(block_size * 8).collect(), 0)
+        }
+    }
+    pub fn reset(&mut self, ctr: &[u8]) {
+        construct_ctr_x8(ctr, &mut self.ctr_x8);
+        self.bytes.reset();
+    }
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        // TODO - Can some of this be combined with regular CtrMode?
+        assert!(input.len() == output.len());
+        let len = input.len();
+        let mut i = 0;
+        while i < len {
+            if self.bytes.is_empty() {
+                let mut wb = self.bytes.borrow_write_buffer();
+                self.algo.encrypt_block_x8(&self.ctr_x8[..], wb.take_remaining());
+                for ctr_i in &mut self.ctr_x8.chunks_mut(self.algo.block_size()) {
+                    add_ctr(ctr_i, 8);
+                }
+            }
+            let count = cmp::min(self.bytes.remaining(), len - i);
+            let bytes_it = self.bytes.take_next(count).iter();
+            let in_it = input[i..].iter();
+            let out_it = &mut output[i..];
+            for ((&x, &y), o) in bytes_it.zip(in_it).zip(out_it.iter_mut()) {
+                *o = x ^ y;
+            }
+            i += count;
+        }
+    }
+}
+
+impl <A: BlockEncryptorX8> SynchronousStreamCipher for CtrModeX8<A> {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        self.process(input, output);
+    }
+}
+
+impl <A: BlockEncryptorX8> Encryptor for CtrModeX8<A> {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl <A: BlockEncryptorX8> Decryptor for CtrModeX8<A> {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use aessafe;
+    use blockmodes::{EcbEncryptor, EcbDecryptor, CbcEncryptor, CbcDecryptor, CtrMode, CtrModeX8,
+        NoPadding, PkcsPadding};
+    use buffer::{ReadBuffer, WriteBuffer, RefReadBuffer, RefWriteBuffer, BufferResult};
+    use buffer::BufferResult::{BufferUnderflow, BufferOverflow};
+    use symmetriccipher::{Encryptor, Decryptor};
+    use symmetriccipher::SymmetricCipherError::{self, InvalidLength, InvalidPadding};
+
+    use std::cmp;
+
+    trait CipherTest {
+        fn get_plain<'a>(&'a self) -> &'a [u8];
+        fn get_cipher<'a>(&'a self) -> &'a [u8];
+    }
+
+    struct EcbTest {
+        key: Vec<u8>,
+        plain: Vec<u8>,
+        cipher: Vec<u8>
+    }
+
+    impl CipherTest for EcbTest {
+        fn get_plain<'a>(&'a self) -> &'a [u8] {
+            &self.plain[..]
+        }
+        fn get_cipher<'a>(&'a self) -> &'a [u8] {
+            &self.cipher[..]
+        }
+    }
+
+    struct CbcTest {
+        key: Vec<u8>,
+        iv: Vec<u8>,
+        plain: Vec<u8>,
+        cipher: Vec<u8>
+    }
+
+    impl CipherTest for CbcTest {
+        fn get_plain<'a>(&'a self) -> &'a [u8] {
+            &self.plain[..]
+        }
+        fn get_cipher<'a>(&'a self) -> &'a [u8] {
+            &self.cipher[..]
+        }
+    }
+
+    struct CtrTest {
+        key: Vec<u8>,
+        ctr: Vec<u8>,
+        plain: Vec<u8>,
+        cipher: Vec<u8>
+    }
+
+    impl CipherTest for CtrTest {
+        fn get_plain<'a>(&'a self) -> &'a [u8] {
+            &self.plain[..]
+        }
+        fn get_cipher<'a>(&'a self) -> &'a [u8] {
+            &self.cipher[..]
+        }
+    }
+
+    fn aes_ecb_no_padding_tests() -> Vec<EcbTest> {
+        vec![
+            EcbTest {
+                key: repeat(0).take(16).collect(),
+                plain: repeat(0).take(32).collect(),
+                cipher: vec![
+                    0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+                    0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e,
+                    0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+                    0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e ]
+            }
+        ]
+    }
+
+    fn aes_ecb_pkcs_padding_tests() -> Vec<EcbTest> {
+        vec![
+            EcbTest {
+                key: repeat(0).take(16).collect(),
+                plain: repeat(0).take(32).collect(),
+                cipher: vec![
+                    0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+                    0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e,
+                    0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+                    0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e,
+                    0x01, 0x43, 0xdb, 0x63, 0xee, 0x66, 0xb0, 0xcd,
+                    0xff, 0x9f, 0x69, 0x91, 0x76, 0x80, 0x15, 0x1e ]
+            },
+            EcbTest {
+                key: repeat(0).take(16).collect(),
+                plain: repeat(0).take(33).collect(),
+                cipher: vec![
+                    0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+                    0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e,
+                    0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+                    0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e,
+                    0x7a, 0xdc, 0x99, 0xb2, 0x9e, 0x82, 0xb1, 0xb2,
+                    0xb0, 0xa6, 0x5a, 0x38, 0xbc, 0x57, 0x8a, 0x01 ]
+            }
+        ]
+    }
+
+    fn aes_cbc_no_padding_tests() -> Vec<CbcTest> {
+        vec![
+            CbcTest {
+                key: repeat(1).take(16).collect(),
+                iv: repeat(3).take(16).collect(),
+                plain: repeat(2).take(32).collect(),
+                cipher: vec![
+                    0x5e, 0x77, 0xe5, 0x9f, 0x8f, 0x85, 0x94, 0x34,
+                    0x89, 0xa2, 0x41, 0x49, 0xc7, 0x5f, 0x4e, 0xc9,
+                    0xe0, 0x9a, 0x77, 0x36, 0xfb, 0xc8, 0xb2, 0xdc,
+                    0xb3, 0xfb, 0x9f, 0xc0, 0x31, 0x4c, 0xb0, 0xb1 ]
+            }
+        ]
+    }
+
+    fn aes_cbc_pkcs_padding_tests() -> Vec<CbcTest> {
+        vec![
+            CbcTest {
+                key: repeat(1).take(16).collect(),
+                iv: repeat(3).take(16).collect(),
+                plain: repeat(2).take(32).collect(),
+                cipher: vec![
+                    0x5e, 0x77, 0xe5, 0x9f, 0x8f, 0x85, 0x94, 0x34,
+                    0x89, 0xa2, 0x41, 0x49, 0xc7, 0x5f, 0x4e, 0xc9,
+                    0xe0, 0x9a, 0x77, 0x36, 0xfb, 0xc8, 0xb2, 0xdc,
+                    0xb3, 0xfb, 0x9f, 0xc0, 0x31, 0x4c, 0xb0, 0xb1,
+                    0xa4, 0xc2, 0xe4, 0x62, 0xef, 0x7a, 0xe3, 0x7e,
+                    0xef, 0x88, 0xf3, 0x27, 0xbd, 0x9c, 0xc8, 0x4d ]
+            },
+            CbcTest {
+                key: repeat(1).take(16).collect(),
+                iv: repeat(3).take(16).collect(),
+                plain: repeat(2).take(33).collect(),
+                cipher: vec![
+                    0x5e, 0x77, 0xe5, 0x9f, 0x8f, 0x85, 0x94, 0x34,
+                    0x89, 0xa2, 0x41, 0x49, 0xc7, 0x5f, 0x4e, 0xc9,
+                    0xe0, 0x9a, 0x77, 0x36, 0xfb, 0xc8, 0xb2, 0xdc,
+                    0xb3, 0xfb, 0x9f, 0xc0, 0x31, 0x4c, 0xb0, 0xb1,
+                    0x6c, 0x47, 0xcd, 0xec, 0xae, 0xbb, 0x1a, 0x65,
+                    0x04, 0xd2, 0x32, 0x23, 0xa6, 0x8d, 0x4a, 0x65 ]
+            }
+        ]
+    }
+
+    fn aes_ctr_tests() -> Vec<CtrTest> {
+        vec![
+            CtrTest {
+                key: repeat(1).take(16).collect(),
+                ctr: repeat(3).take(16).collect(),
+                plain: repeat(2).take(33).collect(),
+                cipher: vec![
+                    0x64, 0x3e, 0x05, 0x19, 0x79, 0x78, 0xd7, 0x45,
+                    0xa9, 0x10, 0x5f, 0xd8, 0x4c, 0xd7, 0xe6, 0xb1,
+                    0x5f, 0x66, 0xc6, 0x17, 0x4b, 0x25, 0xea, 0x24,
+                    0xe6, 0xf9, 0x19, 0x09, 0xb7, 0xdd, 0x84, 0xfb,
+                    0x86 ]
+            }
+        ]
+    }
+
+    // Test the mode by encrypting all of the data at once
+    fn run_full_test<T: CipherTest, E: Encryptor, D: Decryptor>(
+            test: &T,
+            enc: &mut E,
+            dec: &mut D) {
+        let mut cipher_out: Vec<u8> = repeat(0).take(test.get_cipher().len()).collect();
+        {
+            let mut buff_in = RefReadBuffer::new(test.get_plain());
+            let mut buff_out = RefWriteBuffer::new(&mut cipher_out);
+            match enc.encrypt(&mut buff_in, &mut buff_out, true) {
+                Ok(BufferUnderflow) => {}
+                Ok(BufferOverflow) => panic!("Encryption not completed"),
+                Err(_) => panic!("Error"),
+            }
+        }
+        assert!(test.get_cipher() == &cipher_out[..]);
+
+        let mut plain_out: Vec<u8> = repeat(0).take(test.get_plain().len()).collect();
+        {
+            let mut buff_in = RefReadBuffer::new(test.get_cipher());
+            let mut buff_out = RefWriteBuffer::new(&mut plain_out);
+            match dec.decrypt(&mut buff_in, &mut buff_out, true) {
+                Ok(BufferUnderflow) => {}
+                Ok(BufferOverflow) => panic!("Decryption not completed"),
+                Err(_) => panic!("Error"),
+            }
+        }
+        assert!(test.get_plain() == &plain_out[..]);
+    }
+
+    /// Run and encryption or decryption operation, passing in variable sized input and output
+    /// buffers.
+    ///
+    /// # Arguments
+    /// * input - The complete input vector
+    /// * output - The complete output vector
+    /// * op - A closure that runs either an encryption or decryption operation
+    /// * next_in_len - A closure that returns the length to use for the next input buffer; If the
+    ///                 returned value is not in a valid range, it will be fixed up by this
+    ///                 function.
+    /// * next_out_len - A closure that returns the length to use for the next output buffer; If the
+    ///                  returned value is not in a valid range, it will be fixed up by this
+    ///                  function.
+    /// * immediate_eof - Whether eof should be set immediately upon running out of input or if eof
+    ///                   should be passed only after all input has been consumed.
+    fn run_inc<OpFunc, NextInFunc, NextOutFunc>(
+            input: &[u8],
+            output: &mut [u8],
+            mut op: OpFunc,
+            mut next_in_len: NextInFunc,
+            mut next_out_len: NextOutFunc,
+            immediate_eof: bool)
+            where
+                OpFunc: FnMut(&mut RefReadBuffer, &mut RefWriteBuffer, bool) ->
+                    Result<BufferResult, SymmetricCipherError>,
+                NextInFunc: FnMut() -> usize,
+                NextOutFunc: FnMut() -> usize {
+        use std::cell::Cell;
+
+        let in_len = input.len();
+        let out_len = output.len();
+
+        let mut state: Result<BufferResult, SymmetricCipherError> = Ok(BufferUnderflow);
+        let mut in_pos: usize = 0;
+        let mut out_pos: usize = 0;
+        let eof = Cell::new(false);
+
+        let mut in_end = |in_pos: usize, primary: bool| {
+            if eof.get() {
+                return in_len;
+            }
+            let x = next_in_len();
+            if x >= in_len && immediate_eof {
+                eof.set(true);
+            }
+            cmp::min(in_len, in_pos + cmp::max(x, if primary { 1 } else { 0 }))
+        };
+
+        let mut out_end = |out_pos: usize| {
+            let x = next_out_len();
+            cmp::min(out_len, out_pos + cmp::max(x, 1))
+        };
+
+        loop {
+            match state {
+                Ok(BufferUnderflow) => {
+                    if in_pos == input.len() {
+                        break;
+                    }
+                    let mut tmp_in = RefReadBuffer::new(&input[in_pos..in_end(in_pos, true)]);
+                    let out_end = out_end(out_pos);
+                    let mut tmp_out = RefWriteBuffer::new(&mut output[out_pos..out_end]);
+                    state = op(&mut tmp_in, &mut tmp_out, eof.get());
+                    match state {
+                        Ok(BufferUnderflow) => assert!(tmp_in.is_empty()),
+                        _ => {}
+                    }
+                    in_pos += tmp_in.position();
+                    out_pos += tmp_out.position();
+                }
+                Ok(BufferOverflow) => {
+                    let mut tmp_in = RefReadBuffer::new(&input[in_pos..in_end(in_pos, false)]);
+                    let out_end = out_end(out_pos);
+                    let mut tmp_out = RefWriteBuffer::new(&mut output[out_pos..out_end]);
+                    state = op(&mut tmp_in, &mut tmp_out, eof.get());
+                    match state {
+                        Ok(BufferOverflow) => assert!(tmp_out.is_full()),
+                        _ => {}
+                    }
+                    in_pos += tmp_in.position();
+                    out_pos += tmp_out.position();
+                }
+                Err(InvalidPadding) => panic!("Invalid Padding"),
+                Err(InvalidLength) => panic!("Invalid Length")
+            }
+        }
+
+        if !eof.get() {
+            eof.set(true);
+            let mut tmp_out = RefWriteBuffer::new(&mut output[out_pos..out_end(out_pos)]);
+            state = op(&mut RefReadBuffer::new(&[]), &mut tmp_out, eof.get());
+            out_pos += tmp_out.position();
+        }
+
+        loop {
+            match state {
+                Ok(BufferUnderflow) => {
+                    break;
+                }
+                Ok(BufferOverflow) => {
+                    let out_end = out_end(out_pos);
+                    let mut tmp_out = RefWriteBuffer::new(&mut output[out_pos..out_end]);
+                    state = op(&mut RefReadBuffer::new(&[]), &mut tmp_out, eof.get());
+                    assert!(tmp_out.is_full());
+                    out_pos += tmp_out.position();
+                }
+                Err(InvalidPadding) => panic!("Invalid Padding"),
+                Err(InvalidLength) => panic!("Invalid Length")
+            }
+        }
+    }
+
+    fn run_inc1_test<T: CipherTest, E: Encryptor, D: Decryptor>(
+            test: &T,
+            enc: &mut E,
+            dec: &mut D) {
+        let mut cipher_out: Vec<u8> = repeat(0).take(test.get_cipher().len()).collect();
+        run_inc(
+            test.get_plain(),
+            &mut cipher_out,
+            |in_buff: &mut RefReadBuffer, out_buff: &mut RefWriteBuffer, eof: bool| {
+                enc.encrypt(in_buff, out_buff, eof)
+            },
+            || { 0 },
+            || { 1 },
+            false);
+        assert!(test.get_cipher() == &cipher_out[..]);
+
+        let mut plain_out: Vec<u8> = repeat(0).take(test.get_plain().len()).collect();
+        run_inc(
+            test.get_cipher(),
+            &mut plain_out,
+            |in_buff: &mut RefReadBuffer, out_buff: &mut RefWriteBuffer, eof: bool| {
+                dec.decrypt(in_buff, out_buff, eof)
+            },
+            || { 0 },
+            || { 1 },
+            false);
+        assert!(test.get_plain() == &plain_out[..]);
+    }
+
+    fn run_rand_test<T, E, D, NewEncFunc, NewDecFunc>(
+            test: &T,
+            mut new_enc: NewEncFunc,
+            mut new_dec: NewDecFunc)
+            where
+                T: CipherTest,
+                E: Encryptor,
+                D: Decryptor,
+                NewEncFunc: FnMut() -> E,
+                NewDecFunc: FnMut() -> D{
+        use rand;
+        use rand::Rng;
+
+        let tmp : &[_] = &[1, 2, 3, 4];
+        let mut rng1: rand::StdRng = rand::SeedableRng::from_seed(tmp);
+        let mut rng2: rand::StdRng = rand::SeedableRng::from_seed(tmp);
+        let mut rng3: rand::StdRng = rand::SeedableRng::from_seed(tmp);
+        let max_size = cmp::max(test.get_plain().len(), test.get_cipher().len());
+
+        let mut r1 = || {
+            rng1.gen_range(0, max_size)
+        };
+        let mut r2 = || {
+            rng2.gen_range(0, max_size)
+        };
+
+        for _ in 0..1000 {
+            let mut enc = new_enc();
+            let mut dec = new_dec();
+
+            let mut cipher_out: Vec<u8> = repeat(0).take(test.get_cipher().len()).collect();
+            run_inc(
+                test.get_plain(),
+                &mut cipher_out,
+                |in_buff: &mut RefReadBuffer, out_buff: &mut RefWriteBuffer, eof: bool| {
+                    enc.encrypt(in_buff, out_buff, eof)
+                },
+                || { r1() },
+                || { r2() },
+                rng3.gen());
+            assert!(test.get_cipher() == &cipher_out[..]);
+
+            let mut plain_out: Vec<u8> = repeat(0).take(test.get_plain().len()).collect();
+            run_inc(
+                test.get_cipher(),
+                &mut plain_out,
+                |in_buff: &mut RefReadBuffer, out_buff: &mut RefWriteBuffer, eof: bool| {
+                    dec.decrypt(in_buff, out_buff, eof)
+                },
+                || { r1() },
+                || { r2() },
+                rng3.gen());
+            assert!(test.get_plain() == &plain_out[..]);
+        }
+    }
+
+    fn run_test<T, E, D, NewEncFunc, NewDecFunc>(
+            test: &T,
+            mut new_enc: NewEncFunc,
+            mut new_dec: NewDecFunc)
+            where
+                T: CipherTest,
+                E: Encryptor,
+                D: Decryptor,
+                NewEncFunc: FnMut() -> E,
+                NewDecFunc: FnMut() -> D{
+        run_full_test(test, &mut new_enc(), &mut new_dec());
+        run_inc1_test(test, &mut new_enc(), &mut new_dec());
+        run_rand_test(test, new_enc, new_dec);
+    }
+
+    #[test]
+    fn aes_ecb_no_padding() {
+        let tests = aes_ecb_no_padding_tests();
+        for test in tests.iter() {
+            run_test(
+                test,
+                || {
+                    let aes_enc = aessafe::AesSafe128Encryptor::new(&test.key[..]);
+                    EcbEncryptor::new(aes_enc, NoPadding)
+                },
+                || {
+                    let aes_dec = aessafe::AesSafe128Decryptor::new(&test.key[..]);
+                    EcbDecryptor::new(aes_dec, NoPadding)
+                });
+        }
+    }
+
+    #[test]
+    fn aes_ecb_pkcs_padding() {
+        let tests = aes_ecb_pkcs_padding_tests();
+        for test in tests.iter() {
+            run_test(
+                test,
+                || {
+                    let aes_enc = aessafe::AesSafe128Encryptor::new(&test.key[..]);
+                    EcbEncryptor::new(aes_enc, PkcsPadding)
+                },
+                || {
+                    let aes_dec = aessafe::AesSafe128Decryptor::new(&test.key[..]);
+                    EcbDecryptor::new(aes_dec, PkcsPadding)
+                });
+        }
+    }
+
+    #[test]
+    fn aes_cbc_no_padding() {
+        let tests = aes_cbc_no_padding_tests();
+        for test in tests.iter() {
+            run_test(
+                test,
+                || {
+                    let aes_enc = aessafe::AesSafe128Encryptor::new(&test.key[..]);
+                    CbcEncryptor::new(aes_enc, NoPadding, test.iv.clone())
+                },
+                || {
+                    let aes_dec = aessafe::AesSafe128Decryptor::new(&test.key[..]);
+                    CbcDecryptor::new(aes_dec, NoPadding, test.iv.clone())
+                });
+        }
+    }
+
+    #[test]
+    fn aes_cbc_pkcs_padding() {
+        let tests = aes_cbc_pkcs_padding_tests();
+        for test in tests.iter() {
+            run_test(
+                test,
+                || {
+                    let aes_enc = aessafe::AesSafe128Encryptor::new(&test.key[..]);
+                    CbcEncryptor::new(aes_enc, PkcsPadding, test.iv.clone())
+                },
+                || {
+                    let aes_dec = aessafe::AesSafe128Decryptor::new(&test.key[..]);
+                    CbcDecryptor::new(aes_dec, PkcsPadding, test.iv.clone())
+                });
+        }
+    }
+
+    #[test]
+    fn aes_ctr() {
+        let tests = aes_ctr_tests();
+        for test in tests.iter() {
+            run_test(
+                test,
+                || {
+                    let aes_enc = aessafe::AesSafe128Encryptor::new(&test.key[..]);
+                    CtrMode::new(aes_enc, test.ctr.clone())
+                },
+                || {
+                    let aes_enc = aessafe::AesSafe128Encryptor::new(&test.key[..]);
+                    CtrMode::new(aes_enc, test.ctr.clone())
+                });
+        }
+    }
+
+    #[test]
+    fn aes_ctr_x8() {
+        let tests = aes_ctr_tests();
+        for test in tests.iter() {
+            run_test(
+                test,
+                || {
+                    let aes_enc = aessafe::AesSafe128EncryptorX8::new(&test.key[..]);
+                    CtrModeX8::new(aes_enc, &test.ctr[..])
+                },
+                || {
+                    let aes_enc = aessafe::AesSafe128EncryptorX8::new(&test.key[..]);
+                    CtrModeX8::new(aes_enc, &test.ctr[..])
+                });
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use aessafe;
+    use blockmodes::{EcbEncryptor, CbcEncryptor, CtrMode, CtrModeX8,
+        NoPadding, PkcsPadding};
+    use buffer::{ReadBuffer, WriteBuffer, RefReadBuffer, RefWriteBuffer};
+    use buffer::BufferResult::{BufferUnderflow, BufferOverflow};
+    use symmetriccipher::{Encryptor};
+
+    use test::Bencher;
+
+    #[bench]
+    pub fn aes_ecb_no_padding_bench(bh: &mut Bencher) {
+        let key = [1u8; 16];
+        let plain = [3u8; 512];
+        let mut cipher = [3u8; 528];
+
+        let aes_enc = aessafe::AesSafe128Encryptor::new(&key);
+        let mut enc = EcbEncryptor::new(aes_enc, NoPadding);
+
+        bh.iter( || {
+            enc.reset();
+
+            let mut buff_in = RefReadBuffer::new(&plain);
+            let mut buff_out = RefWriteBuffer::new(&mut cipher);
+
+            match enc.encrypt(&mut buff_in, &mut buff_out, true) {
+                Ok(BufferUnderflow) => {}
+                Ok(BufferOverflow) => panic!("Encryption not completed"),
+                Err(_) => panic!("Error"),
+            }
+        });
+
+        bh.bytes = (plain.len()) as u64;
+    }
+
+    #[bench]
+    pub fn aes_cbc_pkcs_padding_bench(bh: &mut Bencher) {
+        let key = [1u8; 16];
+        let iv = [2u8; 16];
+        let plain = [3u8; 512];
+        let mut cipher = [3u8; 528];
+
+        let aes_enc = aessafe::AesSafe128Encryptor::new(&key);
+        let mut enc = CbcEncryptor::new(aes_enc, PkcsPadding, iv.to_vec());
+
+        bh.iter( || {
+            enc.reset(&iv);
+
+            let mut buff_in = RefReadBuffer::new(&plain);
+            let mut buff_out = RefWriteBuffer::new(&mut cipher);
+
+            match enc.encrypt(&mut buff_in, &mut buff_out, true) {
+                Ok(BufferUnderflow) => {}
+                Ok(BufferOverflow) => panic!("Encryption not completed"),
+                Err(_) => panic!("Error"),
+            }
+        });
+
+        bh.bytes = (plain.len()) as u64;
+    }
+
+    #[bench]
+    pub fn aes_ctr_bench(bh: &mut Bencher) {
+        let key = [1u8; 16];
+        let ctr = [2u8; 16];
+        let plain = [3u8; 512];
+        let mut cipher = [3u8; 528];
+
+        let aes_enc = aessafe::AesSafe128Encryptor::new(&key);
+        let mut enc = CtrMode::new(aes_enc, ctr.to_vec());
+
+        bh.iter( || {
+            enc.reset(&ctr);
+
+            let mut buff_in = RefReadBuffer::new(&plain);
+            let mut buff_out = RefWriteBuffer::new(&mut cipher);
+
+            match enc.encrypt(&mut buff_in, &mut buff_out, true) {
+                Ok(BufferUnderflow) => {}
+                Ok(BufferOverflow) => panic!("Encryption not completed"),
+                Err(_) => panic!("Error"),
+            }
+        });
+
+        bh.bytes = (plain.len()) as u64;
+    }
+
+    #[bench]
+    pub fn aes_ctr_x8_bench(bh: &mut Bencher) {
+        let key = [1u8; 16];
+        let ctr = [2u8; 16];
+        let plain = [3u8; 512];
+        let mut cipher = [3u8; 528];
+
+        let aes_enc = aessafe::AesSafe128EncryptorX8::new(&key);
+        let mut enc = CtrModeX8::new(aes_enc, &ctr);
+
+        bh.iter( || {
+            enc.reset(&ctr);
+
+            let mut buff_in = RefReadBuffer::new(&plain);
+            let mut buff_out = RefWriteBuffer::new(&mut cipher);
+
+            match enc.encrypt(&mut buff_in, &mut buff_out, true) {
+                Ok(BufferUnderflow) => {}
+                Ok(BufferOverflow) => panic!("Encryption not completed"),
+                Err(_) => panic!("Error"),
+            }
+        });
+
+        bh.bytes = (plain.len()) as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/blowfish.rs b/third_party/rust-crypto/src/blowfish.rs
new file mode 100644
index 0000000..a429bbf
--- /dev/null
+++ b/third_party/rust-crypto/src/blowfish.rs
@@ -0,0 +1,567 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cryptoutil::{read_u32v_be, write_u32_be};
+use symmetriccipher::{BlockEncryptor, BlockDecryptor};
+use step_by::RangeExt;
+
+#[derive(Clone,Copy)]
+pub struct Blowfish {
+    s: [[u32; 256]; 4],
+    p: [u32; 18]
+}
+
+fn next_u32_wrap(buf: &[u8], offset: &mut usize) -> u32 {
+    let mut v = 0;
+    for _ in 0..4 {
+        if *offset >= buf.len() {
+            *offset = 0;
+        }
+        v = (v << 8) | buf[*offset] as u32;
+        *offset += 1;
+    }
+    v
+}
+
+impl Blowfish {
+    pub fn new(key: &[u8]) -> Blowfish {
+        assert!(4 <= key.len() && key.len() <= 56);
+        let mut blowfish = Blowfish::init_state();
+        blowfish.expand_key(key);
+        blowfish
+    }
+
+    // For bcrypt. Use Blowfish::new instead.
+    pub fn init_state() -> Blowfish {
+        Blowfish {
+            p: [0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+                0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+                0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b],
+            s: [[0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+                 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+                 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+                 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+                 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+                 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+                 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+                 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+                 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+                 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+                 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+                 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+                 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+                 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+                 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+                 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+                 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+                 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+                 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+                 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+                 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+                 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+                 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+                 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+                 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+                 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+                 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+                 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+                 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+                 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+                 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+                 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+                 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+                 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+                 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+                 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+                 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+                 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+                 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+                 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+                 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+                 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+                 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a],
+                [0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+                 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+                 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+                 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+                 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+                 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+                 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+                 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+                 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+                 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+                 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+                 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+                 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+                 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+                 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+                 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+                 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+                 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+                 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+                 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+                 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+                 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+                 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+                 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+                 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+                 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+                 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+                 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+                 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+                 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+                 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+                 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+                 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+                 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+                 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+                 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+                 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+                 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+                 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+                 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+                 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+                 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+                 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7],
+                [0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+                 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+                 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+                 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+                 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+                 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+                 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+                 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+                 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+                 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+                 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+                 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+                 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+                 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+                 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+                 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+                 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+                 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+                 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+                 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+                 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+                 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+                 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+                 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+                 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+                 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+                 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+                 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+                 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+                 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+                 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+                 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+                 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+                 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+                 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+                 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+                 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+                 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+                 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+                 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+                 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+                 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+                 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0],
+                [0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+                 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+                 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+                 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+                 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+                 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+                 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+                 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+                 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+                 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+                 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+                 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+                 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+                 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+                 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+                 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+                 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+                 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+                 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+                 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+                 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+                 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+                 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+                 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+                 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+                 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+                 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+                 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+                 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+                 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+                 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+                 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+                 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+                 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+                 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+                 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+                 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+                 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+                 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+                 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+                 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+                 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+                 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6]]
+        }
+    }
+
+    // For bcrypt. Use Blowfish::new instead.
+    pub fn expand_key(&mut self, key: &[u8]) {
+        let mut key_pos = 0;
+        for i in 0..18 {
+            self.p[i] ^= next_u32_wrap(key, &mut key_pos);
+        }
+        let mut l = 0u32;
+        let mut r = 0u32;
+        for i in (0..18).step_up(2) {
+            let (new_l, new_r) = self.encrypt(l, r);
+            l = new_l;
+            r = new_r;
+            self.p[i] = l;
+            self.p[i+1] = r;
+        }
+        for i in 0..4 {
+            for j in (0..256).step_up(2) {
+                let (new_l, new_r) = self.encrypt(l, r);
+                l = new_l;
+                r = new_r;
+                self.s[i][j] = l;
+                self.s[i][j+1] = r;
+            }
+        }
+    }
+
+    // Bcrypt key schedule.
+    pub fn salted_expand_key(&mut self, salt: &[u8], key: &[u8]) {
+        let mut key_pos = 0;
+        for i in 0..18 {
+            self.p[i] ^= next_u32_wrap(key, &mut key_pos);
+        }
+        let mut l = 0u32;
+        let mut r = 0u32;
+        let mut salt_pos = 0;
+        for i in (0..18).step_up(2) {
+            let (new_l, new_r) = self.encrypt(l ^ next_u32_wrap(salt, &mut salt_pos), r ^ next_u32_wrap(salt, &mut salt_pos));
+            l = new_l;
+            r = new_r;
+            self.p[i] = l;
+            self.p[i+1] = r;
+        }
+        for i in 0..4 {
+            for j in (0..256).step_up(4) {
+                let (new_l, new_r) = self.encrypt(l ^ next_u32_wrap(salt, &mut salt_pos), r ^ next_u32_wrap(salt, &mut salt_pos));
+                l = new_l;
+                r = new_r;
+                self.s[i][j] = l;
+                self.s[i][j+1] = r;
+
+                let (new_l, new_r) = self.encrypt(l ^ next_u32_wrap(salt, &mut salt_pos), r ^ next_u32_wrap(salt, &mut salt_pos));
+                l = new_l;
+                r = new_r;
+                self.s[i][j+2] = l;
+                self.s[i][j+3] = r;
+            }
+        }
+    }
+
+    fn round_function(&self, x: u32) -> u32 {
+        ((self.s[0][(x >> 24) as usize].wrapping_add(self.s[1][((x >> 16) & 0xff) as usize])) ^ self.s[2][((x >> 8) & 0xff) as usize]).wrapping_add(self.s[3][(x & 0xff) as usize])
+    }
+
+    // Public for bcrypt.
+    pub fn encrypt(&self, mut l: u32, mut r: u32) -> (u32, u32) {
+        for i in (0..16).step_up(2) {
+            l ^= self.p[i];
+            r ^= self.round_function(l);
+            r ^= self.p[i+1];
+            l ^= self.round_function(r);
+        }
+        l ^= self.p[16];
+        r ^= self.p[17];
+        (r, l)
+    }
+
+    fn decrypt(&self, mut l: u32, mut r: u32) -> (u32, u32) {
+        let mut i = 16;
+        while i > 0 {
+            l ^= self.p[i+1];
+            r ^= self.round_function(l);
+            r ^= self.p[i];
+            l ^= self.round_function(r);
+            i -= 2;
+        }
+        l ^= self.p[1];
+        r ^= self.p[0];
+        (r, l)
+    }
+}
+
+impl BlockEncryptor for Blowfish {
+    fn block_size(&self) -> usize {
+        8
+    }
+
+    fn encrypt_block(&self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == 8);
+        assert!(output.len() == 8);
+        let mut block = [0u32, 0u32];
+        read_u32v_be(&mut block, input);
+        let (l, r) = self.encrypt(block[0], block[1]);
+        write_u32_be(&mut output[0..4], l);
+        write_u32_be(&mut output[4..8], r);
+    }
+}
+
+impl BlockDecryptor for Blowfish {
+    fn block_size(&self) -> usize {
+        8
+    }
+
+    fn decrypt_block(&self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == 8);
+        assert!(output.len() == 8);
+        let mut block = [0u32, 0u32];
+        read_u32v_be(&mut block, input);
+        let (l, r) = self.decrypt(block[0], block[1]);
+        write_u32_be(&mut output[0..4], l);
+        write_u32_be(&mut output[4..8], r);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use blowfish::Blowfish;
+    use symmetriccipher::{BlockEncryptor, BlockDecryptor};
+    struct Test {
+        key: Vec<u8>,
+        plaintext: Vec<u8>,
+        ciphertext: Vec<u8>
+    }
+
+    fn eay_test_vectors() -> Vec<Test> {
+        vec![
+            Test {
+                    key: vec![0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    plaintext: vec![0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    ciphertext: vec![0x4Eu8, 0xF9u8, 0x97u8, 0x45u8, 0x61u8, 0x98u8, 0xDDu8, 0x78u8]
+            },
+            Test {
+                    key: vec![0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8],
+                    plaintext: vec![0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8],
+                    ciphertext: vec![0x51u8, 0x86u8, 0x6Fu8, 0xD5u8, 0xB8u8, 0x5Eu8, 0xCBu8, 0x8Au8]
+            },
+            Test {
+                    key: vec![0x30u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    plaintext: vec![0x10u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x01u8],
+                    ciphertext: vec![0x7Du8, 0x85u8, 0x6Fu8, 0x9Au8, 0x61u8, 0x30u8, 0x63u8, 0xF2u8]
+            },
+            Test {
+                    key: vec![0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8],
+                    plaintext: vec![0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8],
+                    ciphertext: vec![0x24u8, 0x66u8, 0xDDu8, 0x87u8, 0x8Bu8, 0x96u8, 0x3Cu8, 0x9Du8]
+            },
+            Test {
+                    key: vec![0x01u8, 0x23u8, 0x45u8, 0x67u8, 0x89u8, 0xABu8, 0xCDu8, 0xEFu8],
+                    plaintext: vec![0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8],
+                    ciphertext: vec![0x61u8, 0xF9u8, 0xC3u8, 0x80u8, 0x22u8, 0x81u8, 0xB0u8, 0x96u8]
+            },
+            Test {
+                    key: vec![0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8, 0x11u8],
+                    plaintext: vec![0x01u8, 0x23u8, 0x45u8, 0x67u8, 0x89u8, 0xABu8, 0xCDu8, 0xEFu8],
+                    ciphertext: vec![0x7Du8, 0x0Cu8, 0xC6u8, 0x30u8, 0xAFu8, 0xDAu8, 0x1Eu8, 0xC7u8]
+            },
+            Test {
+                    key: vec![0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    plaintext: vec![0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    ciphertext: vec![0x4Eu8, 0xF9u8, 0x97u8, 0x45u8, 0x61u8, 0x98u8, 0xDDu8, 0x78u8]
+            },
+            Test {
+                    key: vec![0xFEu8, 0xDCu8, 0xBAu8, 0x98u8, 0x76u8, 0x54u8, 0x32u8, 0x10u8],
+                    plaintext: vec![0x01u8, 0x23u8, 0x45u8, 0x67u8, 0x89u8, 0xABu8, 0xCDu8, 0xEFu8],
+                    ciphertext: vec![0x0Au8, 0xCEu8, 0xABu8, 0x0Fu8, 0xC6u8, 0xA0u8, 0xA2u8, 0x8Du8]
+            },
+            Test {
+                    key: vec![0x7Cu8, 0xA1u8, 0x10u8, 0x45u8, 0x4Au8, 0x1Au8, 0x6Eu8, 0x57u8],
+                    plaintext: vec![0x01u8, 0xA1u8, 0xD6u8, 0xD0u8, 0x39u8, 0x77u8, 0x67u8, 0x42u8],
+                    ciphertext: vec![0x59u8, 0xC6u8, 0x82u8, 0x45u8, 0xEBu8, 0x05u8, 0x28u8, 0x2Bu8]
+            },
+            Test {
+                    key: vec![0x01u8, 0x31u8, 0xD9u8, 0x61u8, 0x9Du8, 0xC1u8, 0x37u8, 0x6Eu8],
+                    plaintext: vec![0x5Cu8, 0xD5u8, 0x4Cu8, 0xA8u8, 0x3Du8, 0xEFu8, 0x57u8, 0xDAu8],
+                    ciphertext: vec![0xB1u8, 0xB8u8, 0xCCu8, 0x0Bu8, 0x25u8, 0x0Fu8, 0x09u8, 0xA0u8]
+            },
+            Test {
+                    key: vec![0x07u8, 0xA1u8, 0x13u8, 0x3Eu8, 0x4Au8, 0x0Bu8, 0x26u8, 0x86u8],
+                    plaintext: vec![0x02u8, 0x48u8, 0xD4u8, 0x38u8, 0x06u8, 0xF6u8, 0x71u8, 0x72u8],
+                    ciphertext: vec![0x17u8, 0x30u8, 0xE5u8, 0x77u8, 0x8Bu8, 0xEAu8, 0x1Du8, 0xA4u8]
+            },
+            Test {
+                    key: vec![0x38u8, 0x49u8, 0x67u8, 0x4Cu8, 0x26u8, 0x02u8, 0x31u8, 0x9Eu8],
+                    plaintext: vec![0x51u8, 0x45u8, 0x4Bu8, 0x58u8, 0x2Du8, 0xDFu8, 0x44u8, 0x0Au8],
+                    ciphertext: vec![0xA2u8, 0x5Eu8, 0x78u8, 0x56u8, 0xCFu8, 0x26u8, 0x51u8, 0xEBu8]
+            },
+            Test {
+                    key: vec![0x04u8, 0xB9u8, 0x15u8, 0xBAu8, 0x43u8, 0xFEu8, 0xB5u8, 0xB6u8],
+                    plaintext: vec![0x42u8, 0xFDu8, 0x44u8, 0x30u8, 0x59u8, 0x57u8, 0x7Fu8, 0xA2u8],
+                    ciphertext: vec![0x35u8, 0x38u8, 0x82u8, 0xB1u8, 0x09u8, 0xCEu8, 0x8Fu8, 0x1Au8]
+            },
+            Test {
+                    key: vec![0x01u8, 0x13u8, 0xB9u8, 0x70u8, 0xFDu8, 0x34u8, 0xF2u8, 0xCEu8],
+                    plaintext: vec![0x05u8, 0x9Bu8, 0x5Eu8, 0x08u8, 0x51u8, 0xCFu8, 0x14u8, 0x3Au8],
+                    ciphertext: vec![0x48u8, 0xF4u8, 0xD0u8, 0x88u8, 0x4Cu8, 0x37u8, 0x99u8, 0x18u8]
+            },
+            Test {
+                    key: vec![0x01u8, 0x70u8, 0xF1u8, 0x75u8, 0x46u8, 0x8Fu8, 0xB5u8, 0xE6u8],
+                    plaintext: vec![0x07u8, 0x56u8, 0xD8u8, 0xE0u8, 0x77u8, 0x47u8, 0x61u8, 0xD2u8],
+                    ciphertext: vec![0x43u8, 0x21u8, 0x93u8, 0xB7u8, 0x89u8, 0x51u8, 0xFCu8, 0x98u8]
+            },
+            Test {
+                    key: vec![0x43u8, 0x29u8, 0x7Fu8, 0xADu8, 0x38u8, 0xE3u8, 0x73u8, 0xFEu8],
+                    plaintext: vec![0x76u8, 0x25u8, 0x14u8, 0xB8u8, 0x29u8, 0xBFu8, 0x48u8, 0x6Au8],
+                    ciphertext: vec![0x13u8, 0xF0u8, 0x41u8, 0x54u8, 0xD6u8, 0x9Du8, 0x1Au8, 0xE5u8]
+            },
+            Test {
+                    key: vec![0x07u8, 0xA7u8, 0x13u8, 0x70u8, 0x45u8, 0xDAu8, 0x2Au8, 0x16u8],
+                    plaintext: vec![0x3Bu8, 0xDDu8, 0x11u8, 0x90u8, 0x49u8, 0x37u8, 0x28u8, 0x02u8],
+                    ciphertext: vec![0x2Eu8, 0xEDu8, 0xDAu8, 0x93u8, 0xFFu8, 0xD3u8, 0x9Cu8, 0x79u8]
+            },
+            Test {
+                    key: vec![0x04u8, 0x68u8, 0x91u8, 0x04u8, 0xC2u8, 0xFDu8, 0x3Bu8, 0x2Fu8],
+                    plaintext: vec![0x26u8, 0x95u8, 0x5Fu8, 0x68u8, 0x35u8, 0xAFu8, 0x60u8, 0x9Au8],
+                    ciphertext: vec![0xD8u8, 0x87u8, 0xE0u8, 0x39u8, 0x3Cu8, 0x2Du8, 0xA6u8, 0xE3u8]
+            },
+            Test {
+                    key: vec![0x37u8, 0xD0u8, 0x6Bu8, 0xB5u8, 0x16u8, 0xCBu8, 0x75u8, 0x46u8],
+                    plaintext: vec![0x16u8, 0x4Du8, 0x5Eu8, 0x40u8, 0x4Fu8, 0x27u8, 0x52u8, 0x32u8],
+                    ciphertext: vec![0x5Fu8, 0x99u8, 0xD0u8, 0x4Fu8, 0x5Bu8, 0x16u8, 0x39u8, 0x69u8]
+            },
+            Test {
+                    key: vec![0x1Fu8, 0x08u8, 0x26u8, 0x0Du8, 0x1Au8, 0xC2u8, 0x46u8, 0x5Eu8],
+                    plaintext: vec![0x6Bu8, 0x05u8, 0x6Eu8, 0x18u8, 0x75u8, 0x9Fu8, 0x5Cu8, 0xCAu8],
+                    ciphertext: vec![0x4Au8, 0x05u8, 0x7Au8, 0x3Bu8, 0x24u8, 0xD3u8, 0x97u8, 0x7Bu8]
+            },
+            Test {
+                    key: vec![0x58u8, 0x40u8, 0x23u8, 0x64u8, 0x1Au8, 0xBAu8, 0x61u8, 0x76u8],
+                    plaintext: vec![0x00u8, 0x4Bu8, 0xD6u8, 0xEFu8, 0x09u8, 0x17u8, 0x60u8, 0x62u8],
+                    ciphertext: vec![0x45u8, 0x20u8, 0x31u8, 0xC1u8, 0xE4u8, 0xFAu8, 0xDAu8, 0x8Eu8]
+            },
+            Test {
+                    key: vec![0x02u8, 0x58u8, 0x16u8, 0x16u8, 0x46u8, 0x29u8, 0xB0u8, 0x07u8],
+                    plaintext: vec![0x48u8, 0x0Du8, 0x39u8, 0x00u8, 0x6Eu8, 0xE7u8, 0x62u8, 0xF2u8],
+                    ciphertext: vec![0x75u8, 0x55u8, 0xAEu8, 0x39u8, 0xF5u8, 0x9Bu8, 0x87u8, 0xBDu8]
+            },
+            Test {
+                    key: vec![0x49u8, 0x79u8, 0x3Eu8, 0xBCu8, 0x79u8, 0xB3u8, 0x25u8, 0x8Fu8],
+                    plaintext: vec![0x43u8, 0x75u8, 0x40u8, 0xC8u8, 0x69u8, 0x8Fu8, 0x3Cu8, 0xFAu8],
+                    ciphertext: vec![0x53u8, 0xC5u8, 0x5Fu8, 0x9Cu8, 0xB4u8, 0x9Fu8, 0xC0u8, 0x19u8]
+            },
+            Test {
+                    key: vec![0x4Fu8, 0xB0u8, 0x5Eu8, 0x15u8, 0x15u8, 0xABu8, 0x73u8, 0xA7u8],
+                    plaintext: vec![0x07u8, 0x2Du8, 0x43u8, 0xA0u8, 0x77u8, 0x07u8, 0x52u8, 0x92u8],
+                    ciphertext: vec![0x7Au8, 0x8Eu8, 0x7Bu8, 0xFAu8, 0x93u8, 0x7Eu8, 0x89u8, 0xA3u8]
+            },
+            Test {
+                    key: vec![0x49u8, 0xE9u8, 0x5Du8, 0x6Du8, 0x4Cu8, 0xA2u8, 0x29u8, 0xBFu8],
+                    plaintext: vec![0x02u8, 0xFEu8, 0x55u8, 0x77u8, 0x81u8, 0x17u8, 0xF1u8, 0x2Au8],
+                    ciphertext: vec![0xCFu8, 0x9Cu8, 0x5Du8, 0x7Au8, 0x49u8, 0x86u8, 0xADu8, 0xB5u8]
+            },
+            Test {
+                    key: vec![0x01u8, 0x83u8, 0x10u8, 0xDCu8, 0x40u8, 0x9Bu8, 0x26u8, 0xD6u8],
+                    plaintext: vec![0x1Du8, 0x9Du8, 0x5Cu8, 0x50u8, 0x18u8, 0xF7u8, 0x28u8, 0xC2u8],
+                    ciphertext: vec![0xD1u8, 0xABu8, 0xB2u8, 0x90u8, 0x65u8, 0x8Bu8, 0xC7u8, 0x78u8]
+            },
+            Test {
+                    key: vec![0x1Cu8, 0x58u8, 0x7Fu8, 0x1Cu8, 0x13u8, 0x92u8, 0x4Fu8, 0xEFu8],
+                    plaintext: vec![0x30u8, 0x55u8, 0x32u8, 0x28u8, 0x6Du8, 0x6Fu8, 0x29u8, 0x5Au8],
+                    ciphertext: vec![0x55u8, 0xCBu8, 0x37u8, 0x74u8, 0xD1u8, 0x3Eu8, 0xF2u8, 0x01u8]
+            },
+            Test {
+                    key: vec![0x01u8, 0x01u8, 0x01u8, 0x01u8, 0x01u8, 0x01u8, 0x01u8, 0x01u8],
+                    plaintext: vec![0x01u8, 0x23u8, 0x45u8, 0x67u8, 0x89u8, 0xABu8, 0xCDu8, 0xEFu8],
+                    ciphertext: vec![0xFAu8, 0x34u8, 0xECu8, 0x48u8, 0x47u8, 0xB2u8, 0x68u8, 0xB2u8]
+            },
+            Test {
+                    key: vec![0x1Fu8, 0x1Fu8, 0x1Fu8, 0x1Fu8, 0x0Eu8, 0x0Eu8, 0x0Eu8, 0x0Eu8],
+                    plaintext: vec![0x01u8, 0x23u8, 0x45u8, 0x67u8, 0x89u8, 0xABu8, 0xCDu8, 0xEFu8],
+                    ciphertext: vec![0xA7u8, 0x90u8, 0x79u8, 0x51u8, 0x08u8, 0xEAu8, 0x3Cu8, 0xAEu8]
+            },
+            Test {
+                    key: vec![0xE0u8, 0xFEu8, 0xE0u8, 0xFEu8, 0xF1u8, 0xFEu8, 0xF1u8, 0xFEu8],
+                    plaintext: vec![0x01u8, 0x23u8, 0x45u8, 0x67u8, 0x89u8, 0xABu8, 0xCDu8, 0xEFu8],
+                    ciphertext: vec![0xC3u8, 0x9Eu8, 0x07u8, 0x2Du8, 0x9Fu8, 0xACu8, 0x63u8, 0x1Du8]
+            },
+            Test {
+                    key: vec![0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    plaintext: vec![0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8],
+                    ciphertext: vec![0x01u8, 0x49u8, 0x33u8, 0xE0u8, 0xCDu8, 0xAFu8, 0xF6u8, 0xE4u8]
+            },
+            Test {
+                    key: vec![0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8],
+                    plaintext: vec![0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    ciphertext: vec![0xF2u8, 0x1Eu8, 0x9Au8, 0x77u8, 0xB7u8, 0x1Cu8, 0x49u8, 0xBCu8]
+            },
+            Test {
+                    key: vec![0x01u8, 0x23u8, 0x45u8, 0x67u8, 0x89u8, 0xABu8, 0xCDu8, 0xEFu8],
+                    plaintext: vec![0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8],
+                    ciphertext: vec![0x24u8, 0x59u8, 0x46u8, 0x88u8, 0x57u8, 0x54u8, 0x36u8, 0x9Au8]
+            },
+            Test {
+                    key: vec![0xFEu8, 0xDCu8, 0xBAu8, 0x98u8, 0x76u8, 0x54u8, 0x32u8, 0x10u8],
+                    plaintext: vec![0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8],
+                    ciphertext: vec![0x6Bu8, 0x5Cu8, 0x5Au8, 0x9Cu8, 0x5Du8, 0x9Eu8, 0x0Au8, 0x5Au8]
+            }
+        ]
+    }
+
+    #[test]
+    fn encrypt_eay_test_vectors() {
+        let tests = eay_test_vectors();
+        let mut output = [0u8; 8];
+        for test in tests.iter() {
+            let state = Blowfish::new(&test.key[..]);
+            state.encrypt_block(&test.plaintext[..], &mut output[..]);
+            assert!(test.ciphertext[..] == output[..]);
+        }
+    }
+
+    #[test]
+    fn decrypt_eay_test_vectors() {
+        let tests = eay_test_vectors();
+        let mut output = [0u8; 8];
+        for test in tests.iter() {
+            let state = Blowfish::new(&test.key[..]);
+            state.decrypt_block(&test.ciphertext[..], &mut output[..]);
+            assert!(test.plaintext[..] == output[..]);
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use blowfish::Blowfish;
+    use symmetriccipher::BlockEncryptor;
+    use test::Bencher;
+
+    #[bench]
+    fn blowfish(bh: &mut Bencher) {
+        let key = [0u8; 16];
+        let plaintext = [1u8; 8];
+        let state = Blowfish::new(&key);
+        let mut ciphertext = [0u8; 8];
+
+        bh.iter(|| {
+            state.encrypt_block(&plaintext, &mut ciphertext);
+        });
+        bh.bytes = 8u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/buffer.rs b/third_party/rust-crypto/src/buffer.rs
new file mode 100644
index 0000000..98b7836
--- /dev/null
+++ b/third_party/rust-crypto/src/buffer.rs
@@ -0,0 +1,289 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::prelude::v1::*;
+use std::cmp;
+
+use cryptoutil;
+
+#[derive(Clone,Copy)]
+pub enum BufferResult {
+    BufferUnderflow,
+    BufferOverflow
+}
+
+pub trait ReadBuffer {
+    fn is_empty(&self) -> bool;
+    fn is_full(&self) -> bool;
+    fn remaining(&self) -> usize;
+    fn capacity(&self) -> usize;
+    fn position(&self) -> usize { self.capacity() - self.remaining() }
+
+    fn rewind(&mut self, distance: usize);
+    fn truncate(&mut self, amount: usize);
+    fn reset(&mut self);
+
+    fn peek_next(&self, count: usize) -> &[u8];
+    fn peek_remaining(&self) -> &[u8] {
+        self.peek_next(self.remaining())
+    }
+
+    fn take_next(&mut self, count: usize) -> &[u8];
+    fn take_remaining(&mut self) -> &[u8] {
+        let rem = self.remaining();
+        self.take_next(rem)
+    }
+
+    fn push_to<W: WriteBuffer>(&mut self, output: &mut W) {
+        let count = cmp::min(output.remaining(), self.remaining());
+        cryptoutil::copy_memory(self.take_next(count), output.take_next(count));
+    }
+}
+
+pub trait WriteBuffer {
+    fn is_empty(&self) -> bool;
+    fn is_full(&self) -> bool;
+    fn remaining(&self) -> usize;
+    fn capacity(&self) -> usize;
+    fn position(&self) -> usize { self.capacity() - self.remaining() }
+
+    fn rewind(&mut self, distance: usize);
+    fn reset(&mut self);
+
+    // FIXME - Shouldn't need mut self
+    fn peek_read_buffer(&mut self) -> RefReadBuffer;
+
+    fn take_next(&mut self, count: usize) -> &mut [u8];
+    fn take_remaining(&mut self) -> &mut [u8] {
+        let rem = self.remaining();
+        self.take_next(rem)
+    }
+    fn take_read_buffer(&mut self) -> RefReadBuffer;
+}
+
+pub struct RefReadBuffer<'a> {
+    buff: &'a [u8],
+    pos: usize
+}
+
+impl <'a> RefReadBuffer<'a> {
+    pub fn new(buff: &[u8]) -> RefReadBuffer {
+        RefReadBuffer {
+            buff: buff,
+            pos: 0
+        }
+    }
+}
+
+impl <'a> ReadBuffer for RefReadBuffer<'a> {
+    fn is_empty(&self) -> bool { self.pos == self.buff.len() }
+    fn is_full(&self) -> bool { self.pos == 0 }
+    fn remaining(&self) -> usize { self.buff.len() - self.pos }
+    fn capacity(&self) -> usize { self.buff.len() }
+
+    fn rewind(&mut self, distance: usize) { self.pos -= distance; }
+    fn truncate(&mut self, amount: usize) {
+        self.buff = &self.buff[..self.buff.len() - amount];
+    }
+    fn reset(&mut self) { self.pos = 0; }
+
+    fn peek_next(&self, count: usize) -> &[u8] { &self.buff[self.pos..count] }
+
+    fn take_next(&mut self, count: usize) -> &[u8] {
+        let r = &self.buff[self.pos..self.pos + count];
+        self.pos += count;
+        r
+    }
+}
+
+pub struct OwnedReadBuffer {
+    buff: Vec<u8>,
+    len: usize,
+    pos: usize
+}
+
+impl OwnedReadBuffer {
+    pub fn new(buff: Vec<u8>) -> OwnedReadBuffer {
+        let len = buff.len();
+        OwnedReadBuffer {
+            buff: buff,
+            len: len,
+            pos: 0
+        }
+    }
+    pub fn new_with_len<'a>(buff: Vec<u8>, len: usize) -> OwnedReadBuffer {
+        OwnedReadBuffer {
+            buff: buff,
+            len: len,
+            pos: 0
+        }
+    }
+    pub fn into_write_buffer(self) -> OwnedWriteBuffer {
+        OwnedWriteBuffer::new(self.buff)
+    }
+    pub fn borrow_write_buffer(&mut self) -> BorrowedWriteBuffer {
+        self.pos = 0;
+        self.len = 0;
+        BorrowedWriteBuffer::new(self)
+    }
+}
+
+impl ReadBuffer for OwnedReadBuffer {
+    fn is_empty(&self) -> bool { self.pos == self.len }
+    fn is_full(&self) -> bool { self.pos == 0 }
+    fn remaining(&self) -> usize { self.len - self.pos }
+    fn capacity(&self) -> usize { self.len }
+
+    fn rewind(&mut self, distance: usize) { self.pos -= distance; }
+    fn truncate(&mut self, amount: usize) { self.len -= amount; }
+    fn reset(&mut self) { self.pos = 0; }
+
+    fn peek_next(&self, count: usize) -> &[u8] { &self.buff[self.pos..count] }
+
+    fn take_next(&mut self, count: usize) -> &[u8] {
+        let r = &self.buff[self.pos..self.pos + count];
+        self.pos += count;
+        r
+    }
+}
+
+pub struct RefWriteBuffer<'a> {
+    buff: &'a mut [u8],
+    len: usize,
+    pos: usize
+}
+
+impl <'a> RefWriteBuffer<'a> {
+    pub fn new(buff: &mut [u8]) -> RefWriteBuffer {
+        let len = buff.len();
+        RefWriteBuffer {
+            buff: buff,
+            len: len,
+            pos: 0
+        }
+    }
+}
+
+impl <'a> WriteBuffer for RefWriteBuffer<'a> {
+    fn is_empty(&self) -> bool { self.pos == 0 }
+    fn is_full(&self) -> bool { self.pos == self.len }
+    fn remaining(&self) -> usize { self.len - self.pos }
+    fn capacity(&self) -> usize { self.len }
+
+    fn rewind(&mut self, distance: usize) { self.pos -= distance; }
+    fn reset(&mut self) { self.pos = 0; }
+
+    fn peek_read_buffer(&mut self) -> RefReadBuffer {
+        RefReadBuffer::new(&mut self.buff[..self.pos])
+    }
+
+    fn take_next(&mut self, count: usize) -> &mut [u8] {
+        let r = &mut self.buff[self.pos..self.pos + count];
+        self.pos += count;
+        r
+    }
+    fn take_read_buffer(&mut self) -> RefReadBuffer {
+        let r = RefReadBuffer::new(&mut self.buff[..self.pos]);
+        self.pos = 0;
+        r
+    }
+}
+
+pub struct BorrowedWriteBuffer<'a> {
+    parent: &'a mut OwnedReadBuffer,
+    pos: usize,
+    len: usize
+}
+
+impl <'a> BorrowedWriteBuffer<'a> {
+    fn new(parent: &mut OwnedReadBuffer) -> BorrowedWriteBuffer {
+        let buff_len = parent.buff.len();
+        BorrowedWriteBuffer {
+            parent: parent,
+            pos: 0,
+            len: buff_len
+        }
+    }
+}
+
+impl <'a> WriteBuffer for BorrowedWriteBuffer<'a> {
+    fn is_empty(&self) -> bool { self.pos == 0 }
+    fn is_full(&self) -> bool { self.pos == self.len }
+    fn remaining(&self) -> usize { self.len - self.pos }
+    fn capacity(&self) -> usize { self.len }
+
+    fn rewind(&mut self, distance: usize) {
+        self.pos -= distance;
+        self.parent.len -= distance;
+    }
+    fn reset(&mut self) {
+        self.pos = 0;
+        self.parent.len = 0;
+    }
+
+    fn peek_read_buffer(&mut self) -> RefReadBuffer {
+        RefReadBuffer::new(&self.parent.buff[..self.pos])
+    }
+
+    fn take_next<>(&mut self, count: usize) -> &mut [u8] {
+        let r = &mut self.parent.buff[self.pos..self.pos + count];
+        self.pos += count;
+        self.parent.len += count;
+        r
+    }
+    fn take_read_buffer(&mut self) -> RefReadBuffer {
+        let r = RefReadBuffer::new(&self.parent.buff[..self.pos]);
+        self.pos = 0;
+        self.parent.len = 0;
+        r
+    }
+}
+
+pub struct OwnedWriteBuffer {
+    buff: Vec<u8>,
+    len: usize,
+    pos: usize
+}
+
+impl OwnedWriteBuffer {
+    pub fn new(buff: Vec<u8>) -> OwnedWriteBuffer {
+        let len = buff.len();
+        OwnedWriteBuffer {
+            buff: buff,
+            len: len,
+            pos: 0
+        }
+    }
+    pub fn into_read_buffer(self) -> OwnedReadBuffer {
+        let pos = self.pos;
+        OwnedReadBuffer::new_with_len(self.buff, pos)
+    }
+}
+
+impl WriteBuffer for OwnedWriteBuffer {
+    fn is_empty(&self) -> bool { self.pos == 0 }
+    fn is_full(&self) -> bool { self.pos == self.len }
+    fn remaining(&self) -> usize { self.len - self.pos }
+    fn capacity(&self) -> usize { self.len }
+
+    fn rewind(&mut self, distance: usize) { self.pos -= distance; }
+    fn reset(&mut self) { self.pos = 0; }
+
+    fn peek_read_buffer<'a>(&'a mut self) -> RefReadBuffer<'a> {
+        RefReadBuffer::new(&self.buff[..self.pos])
+    }
+
+    fn take_next<'a>(&'a mut self, count: usize) -> &'a mut [u8] {
+        let r = &mut self.buff[self.pos..self.pos + count];
+        self.pos += count;
+        r
+    }
+    fn take_read_buffer<'a>(&'a mut self) -> RefReadBuffer<'a> {
+        let r = RefReadBuffer::new(&self.buff[..self.pos]);
+        self.pos = 0;
+        r
+    }
+}
diff --git a/third_party/rust-crypto/src/chacha20.rs b/third_party/rust-crypto/src/chacha20.rs
new file mode 100644
index 0000000..0167970
--- /dev/null
+++ b/third_party/rust-crypto/src/chacha20.rs
@@ -0,0 +1,634 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+use std::cmp;
+
+use buffer::{BufferResult, RefReadBuffer, RefWriteBuffer};
+use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher, SymmetricCipherError};
+use cryptoutil::{read_u32_le, symm_enc_or_dec, write_u32_le, xor_keystream};
+use simd::u32x4;
+
+#[derive(Clone,Copy)]
+struct ChaChaState {
+  a: u32x4,
+  b: u32x4,
+  c: u32x4,
+  d: u32x4
+}
+
+#[derive(Copy)]
+pub struct ChaCha20 {
+    state  : ChaChaState,
+    output : [u8; 64],
+    offset : usize,
+}
+
+impl Clone for ChaCha20 { fn clone(&self) -> ChaCha20 { *self } }
+
+macro_rules! swizzle{
+    ($b: expr, $c: expr, $d: expr) => {{
+        let u32x4(b10, b11, b12, b13) = $b;
+        $b = u32x4(b11, b12, b13, b10);
+        let u32x4(c10, c11, c12, c13) = $c;
+        $c = u32x4(c12, c13,c10, c11);
+        let u32x4(d10, d11, d12, d13) = $d;
+        $d = u32x4(d13, d10, d11, d12);
+    }}
+}
+
+macro_rules! state_to_buffer {
+    ($state: expr, $output: expr) => {{
+        let u32x4(a1, a2, a3, a4) = $state.a;
+        let u32x4(b1, b2, b3, b4) = $state.b;
+        let u32x4(c1, c2, c3, c4) = $state.c;
+        let u32x4(d1, d2, d3, d4) = $state.d;
+        let lens = [
+            a1,a2,a3,a4,
+            b1,b2,b3,b4,
+            c1,c2,c3,c4,
+            d1,d2,d3,d4
+        ];
+        for i in 0..lens.len() {
+            write_u32_le(&mut $output[i*4..(i+1)*4], lens[i]);
+        }
+    }}
+}
+
+macro_rules! round{
+    ($state: expr) => {{
+      $state.a = $state.a + $state.b;
+      rotate!($state.d, $state.a, S16);
+      $state.c = $state.c + $state.d;
+      rotate!($state.b, $state.c, S12);
+      $state.a = $state.a + $state.b;
+      rotate!($state.d, $state.a, S8);
+      $state.c = $state.c + $state.d;
+      rotate!($state.b, $state.c, S7);
+    }}
+}
+
+macro_rules! rotate {
+    ($a: expr, $b: expr, $c:expr) => {{
+      let v = $a ^ $b;
+      let r = S32 - $c;
+      let right = v >> r;
+      $a = (v << $c) ^ right
+    }}
+}
+
+static S32:u32x4 = u32x4(32, 32, 32, 32);
+static S16:u32x4 = u32x4(16, 16, 16, 16);
+static S12:u32x4 = u32x4(12, 12, 12, 12);
+static S8:u32x4 = u32x4(8, 8, 8, 8);
+static S7:u32x4 = u32x4(7, 7, 7, 7);
+
+impl ChaCha20 {
+    pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
+        assert!(key.len() == 16 || key.len() == 32);
+        assert!(nonce.len() == 8 || nonce.len() == 12);
+
+        ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; 64], offset: 64 }
+    }
+
+    pub fn new_xchacha20(key: &[u8], nonce: &[u8]) -> ChaCha20 {
+        assert!(key.len() == 32);
+        assert!(nonce.len() == 24);
+
+        // HChaCha20 produces a 256-bit output block starting from a 512 bit
+        // input block where (x0,x1,...,x15) where
+        //
+        //  * (x0, x1, x2, x3) is the ChaCha20 constant.
+        //  * (x4, x5, ... x11) is a 256 bit key.
+        //  * (x12, x13, x14, x15) is a 128 bit nonce.
+        let mut xchacha20 = ChaCha20{ state: ChaCha20::expand(key, &nonce[0..16]), output: [0u8; 64], offset: 64 };
+
+        // Use HChaCha to derive the subkey, and initialize a ChaCha20 instance
+        // with the subkey and the remaining 8 bytes of the nonce.
+        let mut new_key = [0; 32];
+        xchacha20.hchacha20(&mut new_key);
+        xchacha20.state = ChaCha20::expand(&new_key, &nonce[16..24]);
+
+        xchacha20
+    }
+
+    fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
+
+        let constant = match key.len() {
+            16 => b"expand 16-byte k",
+            32 => b"expand 32-byte k",
+            _  => unreachable!(),
+        };
+        ChaChaState {
+            a: u32x4(
+                read_u32_le(&constant[0..4]),
+                read_u32_le(&constant[4..8]),
+                read_u32_le(&constant[8..12]),
+                read_u32_le(&constant[12..16])
+            ),
+            b: u32x4(
+                read_u32_le(&key[0..4]),
+                read_u32_le(&key[4..8]),
+                read_u32_le(&key[8..12]),
+                read_u32_le(&key[12..16])
+            ),
+            c: if key.len() == 16 {
+                    u32x4(
+                        read_u32_le(&key[0..4]),
+                        read_u32_le(&key[4..8]),
+                        read_u32_le(&key[8..12]),
+                        read_u32_le(&key[12..16])
+                    )
+                } else {
+                    u32x4(
+                        read_u32_le(&key[16..20]),
+                        read_u32_le(&key[20..24]),
+                        read_u32_le(&key[24..28]),
+                        read_u32_le(&key[28..32])
+                    )
+                },
+            d: if nonce.len() == 16 {
+                   u32x4(
+                        read_u32_le(&nonce[0..4]),
+                        read_u32_le(&nonce[4..8]),
+                        read_u32_le(&nonce[8..12]),
+                        read_u32_le(&nonce[12..16])
+                    )
+               } else if nonce.len() == 12 {
+                   u32x4(
+                        0,
+                        read_u32_le(&nonce[0..4]),
+                        read_u32_le(&nonce[4..8]),
+                        read_u32_le(&nonce[8..12])
+                    )
+               } else {
+                   u32x4(
+                        0,
+                        0,
+                        read_u32_le(&nonce[0..4]),
+                        read_u32_le(&nonce[4..8])
+                    )
+               }
+        }
+    }
+
+    fn hchacha20(&mut self, out: &mut [u8]) -> () {
+        let mut state = self.state;
+
+        // Apply r/2 iterations of the same "double-round" function,
+        // obtaining (z0, z1, ... z15) = doubleround r/2 (x0, x1, ... x15).
+        for _ in 0..10 {
+            round!(state);
+            let u32x4(b10, b11, b12, b13) = state.b;
+            state.b = u32x4(b11, b12, b13, b10);
+            let u32x4(c10, c11, c12, c13) = state.c;
+            state.c = u32x4(c12, c13,c10, c11);
+            let u32x4(d10, d11, d12, d13) = state.d;
+            state.d = u32x4(d13, d10, d11, d12);
+            round!(state);
+            let u32x4(b20, b21, b22, b23) = state.b;
+            state.b = u32x4(b23, b20, b21, b22);
+            let u32x4(c20, c21, c22, c23) = state.c;
+            state.c = u32x4(c22, c23, c20, c21);
+            let u32x4(d20, d21, d22, d23) = state.d;
+            state.d = u32x4(d21, d22, d23, d20);
+        }
+
+        // HChaCha20 then outputs the 256-bit block (z0, z1, z2, z3, z12, z13,
+        // z14, z15).  These correspond to the constant and input positions in
+        // the ChaCha matrix.
+        let u32x4(a1, a2, a3, a4) = state.a;
+        let u32x4(d1, d2, d3, d4) = state.d;
+        let lens = [
+            a1,a2,a3,a4,
+            d1,d2,d3,d4
+        ];
+        for i in 0..lens.len() {
+            write_u32_le(&mut out[i*4..(i+1)*4], lens[i]);
+        }
+    }
+
+    // put the the next 64 keystream bytes into self.output
+    fn update(&mut self) {
+        let mut state = self.state;
+
+        for _ in 0..10 {
+            round!(state);
+            swizzle!(state.b, state.c, state.d);
+            round!(state);
+            swizzle!(state.d, state.c, state.b);
+        }
+        state.a = state.a + self.state.a;
+        state.b = state.b + self.state.b;
+        state.c = state.c + self.state.c;
+        state.d = state.d + self.state.d;
+
+        state_to_buffer!(state, self.output);
+
+        self.state.d = self.state.d + u32x4(1, 0, 0, 0);
+        let u32x4(c12, _, _, _) = self.state.d;
+        if c12 == 0 {
+            // we could increment the other counter word with an 8 byte nonce
+            // but other implementations like boringssl have this same
+            // limitation
+            panic!("counter is exhausted");
+        }
+
+        self.offset = 0;
+    }
+}
+
+impl SynchronousStreamCipher for ChaCha20 {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == output.len());
+        let len = input.len();
+        let mut i = 0;
+        while i < len {
+            // If there is no keystream available in the output buffer,
+            // generate the next block.
+            if self.offset == 64 {
+                self.update();
+            }
+
+            // Process the min(available keystream, remaining input length).
+            let count = cmp::min(64 - self.offset, len - i);
+            xor_keystream(&mut output[i..i+count], &input[i..i+count], &self.output[self.offset..]);
+            i += count;
+            self.offset += count;
+        }
+    }
+}
+
+impl Encryptor for ChaCha20 {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl Decryptor for ChaCha20 {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use chacha20::ChaCha20;
+    use symmetriccipher::SynchronousStreamCipher;
+
+    #[test]
+    fn test_chacha20_256_tls_vectors() {
+        struct TestVector {
+            key:   [u8; 32],
+            nonce: [u8; 8],
+            keystream: Vec<u8>,
+        };
+        // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
+        let test_vectors = vec!(
+            TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                keystream: vec!(
+                    0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
+                    0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
+                    0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
+                    0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
+                    0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
+                    0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
+                    0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
+                    0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                ],
+                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                keystream: vec!(
+                    0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
+                    0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
+                    0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
+                    0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
+                    0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
+                    0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
+                    0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
+                    0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
+                keystream: vec!(
+                    0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
+                    0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
+                    0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
+                    0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
+                    0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
+                    0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
+                    0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
+                    0x44, 0x5f, 0x41, 0xe3,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                nonce: [ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                keystream: vec!(
+                    0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
+                    0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
+                    0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
+                    0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
+                    0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
+                    0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
+                    0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
+                    0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                ],
+                nonce: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
+                keystream: vec!(
+                    0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
+                    0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
+                    0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
+                    0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
+                    0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
+                    0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
+                    0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
+                    0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
+                    0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
+                    0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
+                    0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
+                    0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
+                    0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
+                    0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
+                    0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
+                    0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
+                    0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
+                    0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
+                    0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
+                    0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
+                    0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
+                    0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
+                    0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
+                    0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
+                    0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
+                    0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
+                    0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
+                    0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
+                    0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
+                    0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
+                    0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
+                    0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
+                ),
+            },
+        );
+
+        for tv in test_vectors.iter() {
+            let mut c = ChaCha20::new(&tv.key, &tv.nonce);
+            let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
+            let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
+            c.process(&input[..], &mut output[..]);
+            assert_eq!(output, tv.keystream);
+        }
+    }
+
+    #[test]
+    fn test_xchacha20_basic() {
+        // There aren't any convenient test vectors for XChaCha/20,
+        // so, a simple test case was generated using Andrew Moon's
+        // chacha-opt library, with the key/nonce from test_salsa20_cryptopp().
+        let key =
+            [0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4,
+             0x62, 0xcd, 0x51, 0x19, 0x7a, 0x9a, 0x46, 0xc7,
+             0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2,
+             0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89];
+        let nonce =
+            [0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73,
+             0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6,
+             0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37];
+        let input = [0u8; 139];
+        let mut stream = [0u8; 139];
+        let result =
+            [0x4f, 0xeb, 0xf2, 0xfe, 0x4b, 0x35, 0x9c, 0x50,
+             0x8d, 0xc5, 0xe8, 0xb5, 0x98, 0x0c, 0x88, 0xe3,
+             0x89, 0x46, 0xd8, 0xf1, 0x8f, 0x31, 0x34, 0x65,
+             0xc8, 0x62, 0xa0, 0x87, 0x82, 0x64, 0x82, 0x48,
+             0x01, 0x8d, 0xac, 0xdc, 0xb9, 0x04, 0x17, 0x88,
+             0x53, 0xa4, 0x6d, 0xca, 0x3a, 0x0e, 0xaa, 0xee,
+             0x74, 0x7c, 0xba, 0x97, 0x43, 0x4e, 0xaf, 0xfa,
+             0xd5, 0x8f, 0xea, 0x82, 0x22, 0x04, 0x7e, 0x0d,
+             0xe6, 0xc3, 0xa6, 0x77, 0x51, 0x06, 0xe0, 0x33,
+             0x1a, 0xd7, 0x14, 0xd2, 0xf2, 0x7a, 0x55, 0x64,
+             0x13, 0x40, 0xa1, 0xf1, 0xdd, 0x9f, 0x94, 0x53,
+             0x2e, 0x68, 0xcb, 0x24, 0x1c, 0xbd, 0xd1, 0x50,
+             0x97, 0x0d, 0x14, 0xe0, 0x5c, 0x5b, 0x17, 0x31,
+             0x93, 0xfb, 0x14, 0xf5, 0x1c, 0x41, 0xf3, 0x93,
+             0x83, 0x5b, 0xf7, 0xf4, 0x16, 0xa7, 0xe0, 0xbb,
+             0xa8, 0x1f, 0xfb, 0x8b, 0x13, 0xaf, 0x0e, 0x21,
+             0x69, 0x1d, 0x7e, 0xce, 0xc9, 0x3b, 0x75, 0xe6,
+             0xe4, 0x18, 0x3a];
+
+        let mut xchacha20 = ChaCha20::new_xchacha20(&key, &nonce);
+        xchacha20.process(&input, &mut stream);
+        assert!(stream[..] == result[..]);
+    }
+
+    #[test]
+    fn test_chacha20_256_tls_vectors_96_nonce() {
+        struct TestVector {
+            key:   [u8; 32],
+            nonce: [u8; 12],
+            keystream: Vec<u8>,
+        };
+        // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
+        let test_vectors = vec!(
+            TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                keystream: vec!(
+                    0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
+                    0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
+                    0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
+                    0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
+                    0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
+                    0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
+                    0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
+                    0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                ],
+                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                keystream: vec!(
+                    0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
+                    0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
+                    0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
+                    0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
+                    0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
+                    0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
+                    0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
+                    0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
+                keystream: vec!(
+                    0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
+                    0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
+                    0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
+                    0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
+                    0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
+                    0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
+                    0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
+                    0x44, 0x5f, 0x41, 0xe3,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+                keystream: vec!(
+                    0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
+                    0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
+                    0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
+                    0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
+                    0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
+                    0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
+                    0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
+                    0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
+                ),
+            }, TestVector{
+                key: [
+                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                ],
+                nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
+                keystream: vec!(
+                    0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
+                    0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
+                    0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
+                    0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
+                    0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
+                    0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
+                    0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
+                    0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
+                    0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
+                    0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
+                    0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
+                    0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
+                    0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
+                    0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
+                    0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
+                    0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
+                    0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
+                    0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
+                    0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
+                    0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
+                    0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
+                    0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
+                    0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
+                    0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
+                    0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
+                    0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
+                    0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
+                    0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
+                    0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
+                    0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
+                    0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
+                    0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
+                ),
+            },
+        );
+
+        for tv in test_vectors.iter() {
+            let mut c = ChaCha20::new(&tv.key, &tv.nonce);
+            let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
+            let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
+            c.process(&input[..], &mut output[..]);
+            assert_eq!(output, tv.keystream);
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use symmetriccipher::SynchronousStreamCipher;
+    use chacha20::ChaCha20;
+
+    #[bench]
+    pub fn chacha20_10(bh: & mut Bencher) {
+        let mut chacha20 = ChaCha20::new(&[0; 32], &[0; 8]);
+        let input = [1u8; 10];
+        let mut output = [0u8; 10];
+        bh.iter( || {
+            chacha20.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn chacha20_1k(bh: & mut Bencher) {
+        let mut chacha20 = ChaCha20::new(&[0; 32], &[0; 8]);
+        let input = [1u8; 1024];
+        let mut output = [0u8; 1024];
+        bh.iter( || {
+            chacha20.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn chacha20_64k(bh: & mut Bencher) {
+        let mut chacha20 = ChaCha20::new(&[0; 32], &[0; 8]);
+        let input = [1u8; 65536];
+        let mut output = [0u8; 65536];
+        bh.iter( || {
+            chacha20.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/chacha20poly1305.rs b/third_party/rust-crypto/src/chacha20poly1305.rs
new file mode 100644
index 0000000..816d186
--- /dev/null
+++ b/third_party/rust-crypto/src/chacha20poly1305.rs
@@ -0,0 +1,801 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use aead::{AeadEncryptor,AeadDecryptor};
+
+use chacha20::ChaCha20;
+use symmetriccipher::SynchronousStreamCipher;
+use poly1305::Poly1305;
+use mac::Mac;
+use cryptoutil::{write_u64_le};
+use util::fixed_time_eq;
+#[derive(Clone, Copy)]
+pub struct ChaCha20Poly1305 {
+    cipher  : ChaCha20,
+    mac: Poly1305,
+    finished: bool,
+    data_len: usize
+}
+
+impl ChaCha20Poly1305 {
+  pub fn new(key: &[u8], nonce: &[u8], aad: &[u8]) -> ChaCha20Poly1305 {
+      assert!(key.len() == 16 || key.len() == 32);
+      assert!(nonce.len() == 8);
+
+      let mut cipher = ChaCha20::new(key, nonce);
+      let mut mac_key = [0u8; 64];
+      let zero_key = [0u8; 64];
+      cipher.process(&zero_key, &mut mac_key);
+
+      let mut mac = Poly1305::new(&mac_key[..32]);
+      mac.input(aad);
+      let mut aad_len = [0u8; 8];
+      let aad_len_uint: u64 = aad.len() as u64;
+      write_u64_le(&mut aad_len, aad_len_uint);
+      mac.input(&aad_len);
+      ChaCha20Poly1305 {
+        cipher: cipher,
+        mac: mac,
+        finished: false,
+        data_len: 0
+      }
+  }
+}
+
+impl AeadEncryptor for ChaCha20Poly1305 {
+    fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
+        assert!(input.len() == output.len());
+        assert!(self.finished == false);
+        self.cipher.process(input, output);
+        self.data_len += input.len();
+        self.mac.input(output);
+        self.finished = true;
+        let mut data_len_buf = [0u8; 8];
+        write_u64_le(&mut data_len_buf, self.data_len as u64);
+        self.mac.input(&data_len_buf);
+        self.mac.raw_result(out_tag);
+    }
+}
+
+impl AeadDecryptor for ChaCha20Poly1305 {
+    fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
+        assert!(input.len() == output.len());
+        assert!(self.finished == false);
+
+        self.finished = true;
+
+        self.mac.input(input);
+
+        self.data_len += input.len();
+        let mut data_len_buf = [0u8; 8];
+
+        write_u64_le(&mut data_len_buf, self.data_len as u64);
+        self.mac.input(&data_len_buf);
+
+        let mut calc_tag =  [0u8; 16];
+        self.mac.raw_result(&mut calc_tag);
+        if fixed_time_eq(&calc_tag, tag) {
+            self.cipher.process(input, output);
+            true
+        } else {
+            false
+        }
+    }
+}
+#[cfg(test)]
+mod test {
+  use std::iter::repeat;
+
+  use chacha20poly1305::ChaCha20Poly1305;
+  use aead::{AeadEncryptor,AeadDecryptor};
+  struct TestVector {
+    key:   [u8; 32],
+    nonce: [u8; 8],
+    plain_text: Vec<u8>,
+    cipher_text: Vec<u8>,
+    aad: Vec<u8>,
+    tag: Vec<u8>
+  }
+
+  #[test]
+  fn test_chacha20_256_poly1305_boringssl_vectors_encrypt() {
+
+    for tv in get_test_vectors().iter() {
+      if tv.tag.len() < 16 {
+        continue;
+      }
+      let mut c = ChaCha20Poly1305::new(&tv.key, &tv.nonce, &tv.aad[..]);
+      let mut output: Vec<u8> = repeat(0).take(tv.plain_text.len()).collect();
+      let mut tag: Vec<u8> = repeat(0).take(tv.tag.len()).collect();
+      c.encrypt(&tv.plain_text[..], &mut output[..], &mut tag[..]);
+      assert_eq!(output, tv.cipher_text);
+      assert_eq!(tag, tv.tag);
+    }
+  }
+  #[test]
+  fn test_chacha20_256_poly1305_boringssl_vectors_decrypt() {
+
+    for tv in get_test_vectors().iter() {
+      if tv.tag.len() < 16 {
+        continue;
+      }
+      let mut c = ChaCha20Poly1305::new(&tv.key, &tv.nonce, &tv.aad[..]);
+      let mut output: Vec<u8> = repeat(0).take(tv.plain_text.len()).collect();
+      let result = c.decrypt(&tv.cipher_text[..], &mut output[..], &tv.tag[..]);
+      assert_eq!(output, tv.plain_text);
+      assert!(result);
+    }
+  }
+  fn get_test_vectors()-> Vec<TestVector>{
+    vec!(
+      TestVector {
+        key: [0x9a, 0x97, 0xf6, 0x5b, 0x9b, 0x4c, 0x72, 0x1b, 0x96, 0x0a, 0x67, 0x21, 0x45, 0xfc, 0xa8, 0xd4, 0xe3, 0x2e, 0x67, 0xf9, 0x11, 0x1e, 0xa9, 0x79, 0xce, 0x9c, 0x48, 0x26, 0x80, 0x6a, 0xee, 0xe6],
+        nonce: [0x3d, 0xe9, 0xc0, 0xda, 0x2b, 0xd7, 0xf9, 0x1e],
+        aad: vec!(),
+        plain_text: vec!(),
+        cipher_text: vec!(),
+        tag: vec!(0x5a, 0x6e, 0x21, 0xf4, 0xba, 0x6d, 0xbe, 0xe5, 0x73, 0x80, 0xe7, 0x9e, 0x79, 0xc3, 0x0d, 0xef)
+      },
+      TestVector{
+        key: [0xbc, 0xb2, 0x63, 0x9b, 0xf9, 0x89, 0xc6, 0x25, 0x1b, 0x29, 0xbf, 0x38, 0xd3, 0x9a, 0x9b, 0xdc, 0xe7, 0xc5, 0x5f, 0x4b, 0x2a, 0xc1, 0x2a, 0x39, 0xc8, 0xa3, 0x7b, 0x5d, 0x0a, 0x5c, 0xc2, 0xb5],
+        nonce: [0x1e, 0x8b, 0x4c, 0x51, 0x0f, 0x5c, 0xa0, 0x83],
+        plain_text: vec!(0x8c, 0x84, 0x19, 0xbc, 0x27),
+        aad: vec!(0x34, 0xab, 0x88, 0xc2, 0x65),
+        cipher_text: vec!(0x1a, 0x7c, 0x2f, 0x33, 0xf5),
+        tag: vec!(0x28, 0x75, 0xc6, 0x59, 0xd0, 0xf2, 0x80, 0x8d, 0xe3, 0xa4, 0x00, 0x27, 0xfe, 0xff, 0x91, 0xa4)
+      },
+      TestVector{
+        key: [0x42, 0x90, 0xbc, 0xb1, 0x54, 0x17, 0x35, 0x31, 0xf3, 0x14, 0xaf, 0x57, 0xf3, 0xbe, 0x3b, 0x50, 0x06, 0xda, 0x37, 0x1e, 0xce, 0x27, 0x2a, 0xfa, 0x1b, 0x5d, 0xbd, 0xd1, 0x10, 0x0a, 0x10, 0x07],
+        nonce: [0xcd, 0x7c, 0xf6, 0x7b, 0xe3, 0x9c, 0x79, 0x4a],
+        plain_text: vec!(0x86, 0xd0, 0x99, 0x74, 0x84, 0x0b, 0xde, 0xd2, 0xa5, 0xca),
+        aad: vec!(0x87, 0xe2, 0x29, 0xd4, 0x50, 0x08, 0x45, 0xa0, 0x79, 0xc0),
+        cipher_text: vec!(0xe3, 0xe4, 0x46, 0xf7, 0xed, 0xe9, 0xa1, 0x9b, 0x62, 0xa4),
+        tag: vec!(0x67, 0x7d, 0xab, 0xf4, 0xe3, 0xd2, 0x4b, 0x87, 0x6b, 0xb2, 0x84, 0x75, 0x38, 0x96, 0xe1, 0xd6)
+      },
+      TestVector{
+        key: [0x42, 0x2a, 0x53, 0x55, 0xb5, 0x6d, 0xcf, 0x2b, 0x43, 0x6a, 0xa8, 0x15, 0x28, 0x58, 0x10, 0x6a, 0x88, 0xd9, 0xba, 0x23, 0xcd, 0xfe, 0x08, 0x7b, 0x5e, 0x74, 0xe8, 0x17, 0xa5, 0x23, 0x88, 0xb3],
+        nonce: [0x1d, 0x12, 0xd6, 0xd9, 0x18, 0x48, 0xf2, 0xea],
+        plain_text: vec!(0x53, 0x7a, 0x64, 0x53, 0x87, 0xf2, 0x2d, 0x6f, 0x6d, 0xbb, 0xea, 0x56, 0x8d, 0x3f, 0xeb),
+        aad: vec!(0xbe, 0xf2, 0x67, 0xc9, 0x9a, 0xec, 0x8a, 0xf5, 0x6b, 0xc2, 0x38, 0x61, 0x2b, 0xfe, 0xa6),
+        cipher_text: vec!(0x28, 0x1a, 0x36, 0x67, 0x05, 0xc5, 0xa2, 0x4b, 0x94, 0xe5, 0x61, 0x46, 0x68, 0x1e, 0x44),
+        tag: vec!(0x38, 0xf2, 0xb8, 0xee, 0x3b, 0xe4, 0x4a, 0xbb, 0xa3, 0xc0, 0x10, 0xd9, 0xca, 0xb6, 0xe0, 0x42)
+      },
+      TestVector{
+        key: [0xec, 0x7b, 0x86, 0x4a, 0x07, 0x8c, 0x3d, 0x05, 0xd9, 0x70, 0xb6, 0xea, 0x3b, 0xa6, 0xd3, 0x3d, 0x6b, 0xb7, 0x3d, 0xfa, 0x64, 0xc6, 0x22, 0xa4, 0x72, 0x7a, 0x96, 0xed, 0xe8, 0x76, 0xf6, 0x85],
+        nonce: [0x2b, 0xca, 0x0e, 0x59, 0xe3, 0x95, 0x08, 0xd3],
+        plain_text: vec!(0xb7, 0x67, 0x33, 0x89, 0x5c, 0x87, 0x1e, 0xdd, 0x72, 0x8a, 0x45, 0xed, 0x1a, 0x21, 0xf1, 0x5a, 0x95, 0x97, 0xd4, 0x9d),
+        aad: vec!(0xcc, 0x12, 0x43, 0xea, 0x54, 0x27, 0x2d, 0xb6, 0x02, 0xfb, 0x08, 0x53, 0xc8, 0xe7, 0x02, 0x7c, 0x56, 0x33, 0x8b, 0x6c),
+        cipher_text: vec!(0x1f, 0xb9, 0xb2, 0x95, 0x8f, 0xce, 0x47, 0xa5, 0xca, 0xda, 0x9d, 0x89, 0x5f, 0xbb, 0x0c, 0x00, 0xd3, 0x56, 0x98, 0x58),
+        tag: vec!(0x04, 0x2a, 0xd5, 0x04, 0x2c, 0x89, 0xeb, 0xc1, 0xaa, 0xd5, 0x7d, 0x3f, 0xb7, 0x03, 0xd3, 0x14)
+      },
+      // TestVector{
+      //   key: [0x2c, 0x4c, 0x0f, 0xdb, 0x61, 0x1d, 0xf2, 0xd4, 0xd5, 0xe7, 0x89, 0x8c, 0x6a, 0xf0, 0x02, 0x27, 0x95, 0x36, 0x4a, 0xdb, 0x87, 0x49, 0x15, 0x5e, 0x2c, 0x68, 0x77, 0x6a, 0x09, 0x0e, 0x7d, 0x5c],
+      //   nonce: [0x13, 0xce, 0x73, 0x82, 0x73, 0x4c, 0x4a, 0x71],
+      //   plain_text: vec!(0x0d, 0xc6, 0xff, 0x21, 0xa3, 0x46, 0xe1, 0x33, 0x7d, 0xd0, 0xdb, 0x81, 0xd8, 0xf7, 0xd9, 0xf6, 0xfd, 0x18, 0x64, 0x41, 0x8b, 0x98, 0xaa, 0xdc, 0xdb),
+      //   aad: vec!(0x01, 0x15, 0xed, 0xcb, 0x17, 0x6a, 0xb8, 0xbf, 0xa9, 0x47, 0xd1, 0xf7, 0xc3, 0xa8, 0x6a, 0x84, 0x5d, 0x31, 0x0b, 0xf6, 0x70, 0x6c, 0x59, 0xa8, 0xf9),
+      //   cipher_text: vec!(0xda, 0xd6, 0x5e, 0x42, 0x44, 0xa1, 0xa1, 0x7c, 0xe5, 0x9d, 0x88, 0xb0, 0x0a, 0xf4, 0xf7, 0x43, 0x4b, 0xd7, 0x83, 0x0f, 0xfd, 0xd4, 0xc5, 0x55, 0x8f),
+      //   tag: vec!(0xac, 0x14, 0x37, 0xb4, 0x5d, 0x8e, 0xac, 0xf9, 0xc0, 0xfe, 0x54, 0x7c, 0x84, 0xfb, 0x82, 0xa2)
+      // },
+      // TestVector{
+      //   key: [0xc6, 0x6e, 0x89, 0xfb, 0xab, 0x01, 0x20, 0x8f, 0x6a, 0x60, 0x84, 0x7f, 0x4f, 0x34, 0xb3, 0x8d, 0x27, 0xb5, 0x54, 0xc1, 0x19, 0xcf, 0x8d, 0x9e, 0x0b, 0x11, 0x8a, 0xa7, 0x26, 0x6a, 0xb8, 0x65],
+      //   nonce: [0x5d, 0x98, 0x56, 0x06, 0x0c, 0x54, 0xab, 0x06],
+      //   plain_text: vec!(0xf9, 0xe3, 0xe9, 0xb5, 0xed, 0x07, 0xb2, 0x08, 0x0d, 0xb8, 0xc1, 0xff, 0xc3, 0x7e, 0x4a, 0x6c, 0xb3, 0xcd, 0x54, 0x46, 0x08, 0x92, 0x1e, 0x18, 0x61, 0x0d, 0x00, 0xb1, 0x7c, 0x6e),
+      //   aad: vec!(0x85, 0xc1, 0x12, 0xa1, 0xef, 0xe0, 0xa2, 0x0e, 0xf3, 0xa5, 0x50, 0x52, 0x6a, 0x7a, 0xfb, 0xc9, 0x8f, 0x63, 0x67, 0xeb, 0xbe, 0xde, 0x4e, 0x70, 0x30, 0x99, 0xab, 0xd7, 0x8f, 0x51),
+      //   cipher_text: vec!(0xb5, 0xcc, 0x75, 0x4f, 0x6d, 0xd1, 0x9e, 0xf2, 0xd6, 0x6f, 0x90, 0xe6, 0xbc, 0x9a, 0x32, 0x2d, 0xdf, 0x21, 0x6e, 0xf2, 0x48, 0xcb, 0xe7, 0x6b, 0x5a, 0xb6, 0xdd, 0x53, 0xbc, 0x36),
+      //   tag: vec!(0x6d, 0xd9, 0x87, 0x10, 0xd8, 0xa8, 0x89, 0xdc, 0xee, 0xa0, 0xd0, 0xa9, 0x36, 0xf9, 0x86, 0x17)
+      // },
+      // TestVector{
+      //   key: [0xa8, 0xb9, 0x76, 0x6f, 0x40, 0x4d, 0xea, 0x8c, 0xf7, 0xd7, 0xdf, 0xaf, 0x58, 0x22, 0xf5, 0x3d, 0xf9, 0xcc, 0xd0, 0x92, 0xe3, 0x32, 0xa5, 0x7f, 0x00, 0x7b, 0x30, 0x1b, 0x50, 0x7d, 0x5e, 0x14],
+      //   nonce: [0xc7, 0xf2, 0xf7, 0xa2, 0x33, 0x10, 0x4a, 0x2d],
+      //   plain_text: vec!(0x4d, 0x6f, 0xae, 0xae, 0xe3, 0x91, 0x79, 0xa7, 0xc8, 0x92, 0xfa, 0xae, 0x37, 0x19, 0x65, 0x6c, 0xc6, 0x14, 0xc7, 0xe6, 0xec, 0xd8, 0xfc, 0xb5, 0x70, 0xa3, 0xb8, 0x2c, 0x4d, 0xac, 0xe9, 0x69, 0x09, 0x03, 0x38),
+      //   aad: vec!(0xc6, 0xd8, 0x3b, 0x6a, 0x56, 0x40, 0x8a, 0x35, 0x6e, 0x68, 0xd0, 0x49, 0x4d, 0x4e, 0xff, 0x15, 0x05, 0x30, 0xb0, 0x95, 0x51, 0xd0, 0x08, 0x37, 0x3d, 0x6d, 0xee, 0x2b, 0x8d, 0x6b, 0x56, 0x19, 0xd6, 0x7f, 0xdb),
+      //   cipher_text: vec!(0xa1, 0x54, 0x43, 0xf0, 0x83, 0x31, 0x6e, 0xef, 0x62, 0x7a, 0x37, 0x1f, 0x4c, 0x9a, 0xc6, 0x54, 0xd0, 0xdd, 0x75, 0x25, 0x5d, 0x8a, 0x30, 0x31, 0x25, 0xe9, 0xf5, 0x1a, 0xf4, 0x23, 0x3f, 0xf4, 0xce, 0xb7, 0xfe),
+      //   tag: vec!(0x52, 0x50, 0x4e, 0x88, 0x0f, 0x67, 0x92, 0xa6, 0x07, 0x08, 0xcc, 0x6d, 0xb7, 0x2e, 0xae, 0x42)
+      // },
+      // TestVector{
+      //   key: [0x5e, 0x8d, 0x0e, 0x5f, 0x14, 0x67, 0xf7, 0xa7, 0x50, 0xc5, 0x51, 0x44, 0xd0, 0xc6, 0x70, 0xf7, 0xd9, 0x10, 0x75, 0xf3, 0x86, 0x79, 0x5b, 0x23, 0x0c, 0x9b, 0xf1, 0xc0, 0x4b, 0xa2, 0x50, 0xbc],
+      //   nonce: [0x88, 0x04, 0x9f, 0x44, 0xba, 0x61, 0xb8, 0x8f],
+      //   plain_text: vec!(0x51, 0xa1, 0xee, 0xbc, 0xc3, 0x48, 0xe0, 0x58, 0x21, 0x96, 0xa0, 0xbc, 0xe1, 0x6e, 0xd1, 0xf8, 0xac, 0x2e, 0x91, 0xc3, 0xe8, 0xa6, 0x90, 0xe0, 0x4a, 0x9f, 0x4b, 0x5c, 0xf6, 0x33, 0x13, 0xd7, 0xad, 0x08, 0xd1, 0xef, 0xbf, 0xf8, 0x5c, 0x89),
+      //   aad: vec!(0x5d, 0x09, 0xbf, 0x0b, 0xe9, 0x00, 0x26, 0xf9, 0xfc, 0x51, 0xf7, 0x34, 0x18, 0xd6, 0xd8, 0x64, 0xb6, 0xd1, 0x97, 0xea, 0x03, 0x0b, 0x3d, 0xe0, 0x72, 0xbd, 0x2c, 0x2f, 0x5c, 0xab, 0x58, 0x60, 0xa3, 0x42, 0xab, 0xbd, 0x29, 0xdb, 0xa9, 0xdc),
+      //   cipher_text: vec!(0x35, 0xaa, 0x4b, 0xd4, 0x53, 0x7a, 0xa6, 0x11, 0xfd, 0x75, 0x78, 0xfc, 0x22, 0x7d, 0xf5, 0x0e, 0xbc, 0xb0, 0x0c, 0x69, 0x2a, 0x1c, 0xf6, 0xf0, 0x2e, 0x50, 0xed, 0x92, 0x70, 0xbd, 0x93, 0xaf, 0x3b, 0xc6, 0x8f, 0x4c, 0x75, 0xb9, 0x66, 0x38),
+      //   tag: vec!(0xcc, 0xea, 0x1c, 0xbb, 0xc8, 0x39, 0x44, 0xcc, 0x66, 0xdf, 0x4d, 0xbf, 0x6f, 0xb7, 0xfc, 0x46)
+      // },
+      // TestVector{
+      //   key: [0x21, 0xa9, 0xf0, 0x7e, 0xc8, 0x91, 0xd4, 0x88, 0x80, 0x5e, 0x9b, 0x92, 0xbb, 0x1b, 0x22, 0x86, 0xf3, 0xf0, 0x41, 0x0c, 0x32, 0x3b, 0x07, 0xfe, 0xe1, 0xdc, 0x6f, 0x73, 0x79, 0xe2, 0x2e, 0x48],
+      //   nonce: [0x06, 0x62, 0x15, 0xbe, 0x65, 0x67, 0x37, 0x7a],
+      //   plain_text: vec!(0xc1, 0xb0, 0xaf, 0xfa, 0xf2, 0xb8, 0xd7, 0xef, 0x51, 0xcc, 0xa9, 0xaa, 0xcf, 0x79, 0x69, 0xf9, 0x2f, 0x92, 0x8c, 0x2e, 0x3c, 0xc7, 0xdb, 0x2e, 0x15, 0xf4, 0x7e, 0xe1, 0xf6, 0x50, 0x23, 0x91, 0x0d, 0x09, 0xf2, 0x09, 0xd0, 0x07, 0xb7, 0x43, 0x6e, 0xe8, 0x98, 0x13, 0x3d),
+      //   aad: vec!(0xdf, 0xdf, 0xdf, 0x4d, 0x3a, 0x68, 0xb4, 0x7a, 0xd0, 0xd4, 0x88, 0x28, 0xdc, 0x17, 0xb2, 0x58, 0x5d, 0xa9, 0xc8, 0x1c, 0x3a, 0x8d, 0x71, 0xd8, 0x26, 0xb5, 0xfa, 0x80, 0x20, 0xfe, 0xe0, 0x02, 0x39, 0x7e, 0x91, 0xfc, 0x96, 0x58, 0xe9, 0xd6, 0x1d, 0x72, 0x8b, 0x93, 0xeb),
+      //   cipher_text: vec!(0x8f, 0xf4, 0xce, 0xb6, 0x00, 0xe7, 0xd4, 0x56, 0x96, 0xd0, 0x24, 0x67, 0xf8, 0xe3, 0x0d, 0xf0, 0xd3, 0x38, 0x64, 0xa0, 0x40, 0xa4, 0x1f, 0xfb, 0x9e, 0x4c, 0x2d, 0xa0, 0x9b, 0x92, 0xe8, 0x8b, 0x6f, 0x6b, 0x85, 0x0e, 0x9f, 0x72, 0x58, 0xd8, 0x27, 0xb9, 0xaa, 0xf3, 0x46),
+      //   tag: vec!(0x4e, 0xed, 0xdc, 0x99, 0x78, 0x40, 0x11, 0xf0, 0x75, 0x8b, 0xa5, 0xeb, 0xfb, 0xa6, 0x18, 0x27)
+      // },
+      // TestVector{
+      //   key: [0x54, 0xc9, 0x3d, 0xb9, 0xaa, 0x0e, 0x00, 0xd1, 0x0b, 0x45, 0x04, 0x1c, 0x7a, 0x7e, 0x41, 0xee, 0x9f, 0x90, 0xab, 0x78, 0xae, 0x4c, 0x1b, 0xba, 0x18, 0xd6, 0x73, 0xc3, 0xb3, 0x70, 0xab, 0xde],
+      //   nonce: [0x3f, 0x2d, 0x44, 0xe7, 0xb3, 0x52, 0x36, 0x0f],
+      //   plain_text: vec!(0x12, 0x41, 0xe7, 0xd6, 0xfb, 0xe5, 0xee, 0xf5, 0xd8, 0xaf, 0x9c, 0x2f, 0xb8, 0xb5, 0x16, 0xe0, 0xf1, 0xdd, 0x49, 0xaa, 0x4e, 0xbe, 0x54, 0x91, 0x20, 0x51, 0x94, 0xfe, 0x5a, 0xea, 0x37, 0x04, 0xef, 0xaf, 0x30, 0xd3, 0x92, 0xf4, 0x4c, 0xc9, 0x9e, 0x09, 0x25, 0xb8, 0x44, 0x60, 0xd4, 0x87, 0x33, 0x44),
+      //   aad: vec!(0xf1, 0xd1, 0xb0, 0x8d, 0xd6, 0xfe, 0x96, 0xc4, 0x65, 0x78, 0xc1, 0xd1, 0xad, 0x38, 0x88, 0x18, 0x40, 0xb1, 0x0c, 0xb5, 0xea, 0xe4, 0x1e, 0x5f, 0x05, 0xfe, 0x52, 0x87, 0x22, 0x3f, 0xa7, 0x22, 0x42, 0xae, 0xa4, 0x8c, 0xb3, 0x74, 0xa8, 0x0b, 0xe9, 0x37, 0xb5, 0x41, 0xf9, 0x38, 0x1e, 0xfa, 0x66, 0xbb),
+      //   cipher_text: vec!(0x02, 0x7b, 0x86, 0x86, 0x5b, 0x80, 0xb4, 0xc4, 0xda, 0x82, 0x3a, 0x7d, 0x3d, 0xbc, 0xf5, 0x84, 0x5b, 0xf5, 0x7d, 0x58, 0xee, 0x33, 0x4e, 0xb3, 0x57, 0xe8, 0x23, 0x69, 0xcc, 0x62, 0x89, 0x79, 0xe2, 0x94, 0x78, 0x30, 0xd9, 0xd4, 0x81, 0x7e, 0xfd, 0x3d, 0x0b, 0xc4, 0x77, 0x9f, 0x0b, 0x38, 0x89, 0x43),
+      //   tag: vec!(0x43, 0x03, 0xfa, 0x01, 0x74, 0xac, 0x2b, 0x99, 0x16, 0xbf, 0x89, 0xc5, 0x93, 0xba, 0xee, 0x37)
+      // },
+      // TestVector{
+      //   key: [0x80, 0x8e, 0x0e, 0x73, 0xe9, 0xbc, 0xd2, 0x74, 0xd4, 0xc6, 0xf6, 0x5d, 0xf2, 0xfe, 0x95, 0x78, 0x22, 0xa6, 0x02, 0xf0, 0x39, 0xd4, 0x75, 0x26, 0x16, 0xba, 0x29, 0xa2, 0x89, 0x26, 0xef, 0x4a],
+      //   nonce: [0x1b, 0x9c, 0xd7, 0x3d, 0x2f, 0xc3, 0xcb, 0x8e],
+      //   plain_text: vec!(0x34, 0x36, 0xc7, 0xb5, 0xbe, 0x23, 0x94, 0xaf, 0x7e, 0x88, 0x32, 0x0c, 0x82, 0x32, 0x6a, 0x6d, 0xb3, 0x78, 0x87, 0xff, 0x9d, 0xe4, 0x19, 0x61, 0xc7, 0xd6, 0x54, 0xdd, 0x22, 0xdd, 0x1f, 0x7d, 0x40, 0x44, 0x4d, 0x48, 0xf5, 0xc6, 0x63, 0xb8, 0x6f, 0xf4, 0x1f, 0x3e, 0x15, 0xb5, 0xc8, 0xca, 0x13, 0x37, 0xf9, 0x76, 0x35, 0x85, 0x8f),
+      //   aad: vec!(0xd5, 0x7c, 0xfb, 0xe5, 0xf2, 0x53, 0x80, 0x44, 0x28, 0x2e, 0x53, 0xb2, 0xf0, 0xbb, 0x4e, 0x86, 0xea, 0x22, 0x33, 0x04, 0x1f, 0xb3, 0x6a, 0xdb, 0x83, 0x38, 0xde, 0xd0, 0x92, 0x14, 0x8f, 0x8c, 0x2e, 0x89, 0x4e, 0xf8, 0x76, 0x6a, 0x7e, 0xc2, 0xdd, 0x02, 0xc6, 0xac, 0x5d, 0xba, 0xb0, 0xc3, 0x70, 0x3c, 0x5e, 0x91, 0x19, 0xe3, 0x7c),
+      //   cipher_text: vec!(0x9b, 0x95, 0x0b, 0x3c, 0xaf, 0x7d, 0x25, 0xea, 0xf5, 0xfc, 0xa6, 0xfa, 0x3f, 0xe1, 0x2e, 0xd0, 0x77, 0xd8, 0x0d, 0xcd, 0x55, 0x79, 0x85, 0x12, 0x33, 0xc7, 0x66, 0xbb, 0x8b, 0xb6, 0x13, 0xec, 0x91, 0xd9, 0x25, 0xa9, 0x39, 0xbb, 0x52, 0xfb, 0x88, 0xd5, 0xed, 0xa8, 0x03, 0xcf, 0xe2, 0xa8, 0xcd, 0xa2, 0xe0, 0x55, 0xb9, 0x62, 0xfd),
+      //   tag: vec!(0x6b, 0xf5, 0xb7, 0x18, 0xf5, 0xbb, 0xe1, 0x39, 0x5a, 0x5f, 0xdf, 0xcb, 0xbe, 0xf7, 0x52, 0xf5)
+      // },
+      // TestVector{
+      //   key: [0x4a, 0xdf, 0xe1, 0xa2, 0x6c, 0x56, 0x36, 0x53, 0x6c, 0xd7, 0xcb, 0x72, 0xaa, 0x5b, 0xde, 0xd0, 0xb1, 0xaa, 0x64, 0x48, 0x7a, 0xd0, 0xe4, 0x07, 0x8f, 0x31, 0x1e, 0x87, 0x82, 0x76, 0x8e, 0x97],
+      //   nonce: [0xd6, 0x9e, 0x54, 0xba, 0xde, 0xc1, 0x15, 0x60],
+      //   plain_text: vec!(0x19, 0xb3, 0xf9, 0x41, 0x1c, 0xe8, 0x75, 0xfc, 0xb6, 0x84, 0xcb, 0xdc, 0x07, 0x93, 0x8c, 0x4c, 0x13, 0x47, 0xe1, 0x64, 0xf9, 0x64, 0x0d, 0x37, 0xb2, 0x2f, 0x97, 0x5b, 0x4b, 0x9a, 0x37, 0x3c, 0x43, 0x02, 0xae, 0x0e, 0x7d, 0xfd, 0xeb, 0xa1, 0xe0, 0xd0, 0x0c, 0xed, 0x44, 0x6e, 0x33, 0x8f, 0x4c, 0x5b, 0xc0, 0x1b, 0x4b, 0xec, 0xef, 0x51, 0x15, 0x82, 0x52, 0x76),
+      //   aad: vec!(0xbd, 0xa1, 0xb0, 0xf6, 0xc2, 0xf4, 0xeb, 0x81, 0x21, 0xdc, 0xbd, 0x2e, 0xeb, 0xd9, 0x1a, 0x03, 0xae, 0x1d, 0x6e, 0x05, 0x23, 0xb9, 0xb6, 0xf3, 0x4b, 0x6f, 0x16, 0xce, 0xca, 0x0d, 0x08, 0x66, 0x54, 0xfb, 0x05, 0x52, 0xbf, 0xd5, 0xc8, 0xe1, 0x88, 0x77, 0x30, 0xe1, 0x44, 0x9e, 0xa0, 0x2d, 0x7f, 0x64, 0x7a, 0xe8, 0x35, 0xbc, 0x2d, 0xab, 0x4b, 0xbc, 0x65, 0xb9),
+      //   cipher_text: vec!(0xea, 0x76, 0x5a, 0x82, 0x9d, 0x96, 0x1e, 0x08, 0xba, 0xca, 0xed, 0x80, 0x12, 0x37, 0xef, 0x40, 0x67, 0xdf, 0x38, 0xad, 0x37, 0x37, 0xb7, 0xc6, 0xde, 0x4d, 0xb5, 0x87, 0xa1, 0x02, 0xa8, 0x6f, 0xc4, 0xab, 0xba, 0xab, 0xea, 0x0e, 0xe9, 0x7c, 0x95, 0xca, 0x7f, 0x57, 0x1c, 0x7b, 0xab, 0x6f, 0x38, 0xcb, 0xae, 0x60, 0xcd, 0x6e, 0x6a, 0x4c, 0xe3, 0xc7, 0xa3, 0x20),
+      //   tag: vec!(0xb4, 0x25, 0xcd, 0xf1, 0x0c, 0xd0, 0x12, 0x3a, 0x7e, 0x64, 0xb3, 0x47, 0xc6, 0xb4, 0xb1, 0xf0)
+      // },
+      // TestVector{
+      //   key: [0xeb, 0x3d, 0xb8, 0x6c, 0x14, 0xb7, 0xcc, 0x2e, 0x49, 0x43, 0x45, 0xd0, 0xdf, 0xb4, 0x84, 0x1b, 0xbd, 0x3a, 0xa1, 0xe2, 0xbc, 0x64, 0x0c, 0xca, 0x0c, 0x6c, 0x40, 0x55, 0x20, 0x68, 0x56, 0x39],
+      //   nonce: [0x88, 0xb5, 0x4b, 0x28, 0xd6, 0xda, 0x8c, 0x81],
+      //   plain_text: vec!(0xf7, 0x5c, 0x0a, 0x35, 0x72, 0x71, 0x43, 0x0b, 0x1e, 0xcf, 0xf0, 0x7a, 0x30, 0x7b, 0x6c, 0x29, 0x32, 0x5c, 0x6e, 0x66, 0x93, 0x50, 0x46, 0x70, 0x4a, 0x19, 0x84, 0x5e, 0x62, 0x9f, 0x87, 0xa9, 0xe3, 0xb8, 0xaa, 0x6c, 0x1d, 0xf5, 0x5d, 0xd4, 0x26, 0xa4, 0x87, 0xd5, 0x33, 0xbb, 0x33, 0x3e, 0x46, 0xf0, 0xd3, 0x41, 0x84, 0x64, 0xac, 0x1b, 0xef, 0x05, 0x92, 0x31, 0xf8, 0xe8, 0x7e, 0x62, 0x84),
+      //   aad: vec!(0x34, 0xb0, 0x8b, 0xb0, 0xdf, 0x82, 0x1c, 0x57, 0x3d, 0xcb, 0x56, 0xf5, 0xb8, 0xb4, 0xa9, 0x92, 0x04, 0x65, 0x06, 0x7f, 0x3b, 0x5b, 0xf3, 0xe3, 0x25, 0x4e, 0xa1, 0xda, 0x1a, 0x7f, 0xc9, 0x84, 0x7f, 0xd3, 0x8b, 0xdf, 0xe6, 0xb3, 0x09, 0x27, 0x94, 0x52, 0x63, 0xa9, 0x1f, 0xa2, 0x88, 0xc7, 0xcf, 0x1b, 0xee, 0x0f, 0xdd, 0xb0, 0xfa, 0xdf, 0x59, 0x48, 0xc5, 0xd8, 0x3e, 0xb4, 0x62, 0x35, 0x75),
+      //   cipher_text: vec!(0x14, 0x6e, 0xc8, 0x4f, 0x5d, 0xc1, 0xc9, 0xfe, 0x9d, 0xe3, 0x30, 0x7a, 0x91, 0x82, 0xdb, 0xaa, 0x75, 0x96, 0x5b, 0xf8, 0x5f, 0x5e, 0x64, 0x56, 0x3e, 0x68, 0xd0, 0x39, 0xa5, 0xb6, 0x59, 0xaa, 0x88, 0x63, 0xb8, 0x92, 0x28, 0xed, 0xb9, 0x3f, 0xf3, 0xd8, 0xc3, 0x32, 0x3a, 0xb0, 0xd0, 0x33, 0x00, 0x47, 0x6a, 0xa4, 0xac, 0xa2, 0x06, 0xd4, 0x62, 0x6a, 0x6b, 0x26, 0x9b, 0x20, 0x78, 0x91, 0x2d),
+      //   tag: vec!(0x00, 0x58, 0xa8, 0xdf, 0xf3, 0x2c, 0x29, 0x93, 0x5c, 0x62, 0x21, 0x0c, 0x35, 0x9b, 0xd2, 0x81)
+      // },
+      // TestVector{
+      //   key: [0xdd, 0x5b, 0x49, 0xb5, 0x95, 0x3e, 0x04, 0xd9, 0x26, 0xd6, 0x64, 0xda, 0x3b, 0x65, 0xeb, 0xcf, 0xfb, 0xbf, 0x06, 0xab, 0xbe, 0x93, 0xa3, 0x81, 0x9d, 0xfc, 0x1a, 0xbb, 0xec, 0xba, 0xab, 0x13],
+      //   nonce: [0xc5, 0xc8, 0x00, 0x94, 0x59, 0xb9, 0xe3, 0x1a],
+      //   plain_text: vec!(0xf2, 0x1f, 0x67, 0x06, 0xa4, 0xdc, 0x33, 0xa3, 0x61, 0x36, 0x2c, 0x21, 0x4d, 0xef, 0xd5, 0x6d, 0x35, 0x3b, 0xcb, 0x29, 0x81, 0x1e, 0x58, 0x19, 0xab, 0x3c, 0x5c, 0x2c, 0x13, 0x95, 0x0c, 0x7a, 0xa0, 0x00, 0x0b, 0x9d, 0x1f, 0xe6, 0x9b, 0xb4, 0x64, 0x54, 0x51, 0x4d, 0xcc, 0xe8, 0x8a, 0x4a, 0x5e, 0xda, 0x09, 0x7c, 0x28, 0x1b, 0x81, 0xe5, 0x1d, 0x6a, 0x4d, 0xba, 0x47, 0xc8, 0x03, 0x26, 0xba, 0x6c, 0xea, 0x8e, 0x2b, 0xab),
+      //   aad: vec!(0xfe, 0x6f, 0x4c, 0xbb, 0x00, 0x79, 0x4a, 0xde, 0xa5, 0x9e, 0x9d, 0xe8, 0xb0, 0x3c, 0x7f, 0xdf, 0x48, 0x2e, 0x46, 0xf6, 0xc4, 0x7a, 0x35, 0xf9, 0x69, 0x97, 0x66, 0x9c, 0x73, 0x5e, 0xd5, 0xe7, 0x29, 0xa4, 0x94, 0x16, 0xb4, 0x24, 0x68, 0x77, 0x7e, 0x6a, 0x8d, 0x7a, 0xa1, 0x73, 0xc1, 0x8b, 0x81, 0x77, 0x41, 0x8d, 0xed, 0x60, 0x01, 0x24, 0xa9, 0x8c, 0xbb, 0x65, 0x48, 0x9f, 0x9c, 0x24, 0xa0, 0x4f, 0x1e, 0x71, 0x27, 0xce),
+      //   cipher_text: vec!(0x91, 0x1e, 0xad, 0x61, 0xb2, 0xaa, 0x81, 0xd0, 0x0c, 0x5e, 0xff, 0x53, 0xae, 0xea, 0x3a, 0xb7, 0x13, 0x70, 0x9e, 0xd5, 0x71, 0x76, 0x58, 0x90, 0xd5, 0x58, 0xfb, 0x59, 0xd3, 0x99, 0x3b, 0x45, 0xf5, 0x98, 0xa3, 0x9e, 0x5e, 0xff, 0x4b, 0xe8, 0x44, 0xc4, 0xd4, 0xbd, 0x1e, 0xf9, 0x62, 0x2e, 0x60, 0x41, 0x2b, 0x21, 0x14, 0x00, 0x07, 0xd5, 0x4d, 0xcf, 0x31, 0xb2, 0xc0, 0xe3, 0xe9, 0x8c, 0xf3, 0x3a, 0x00, 0xfd, 0x27, 0xf0),
+      //   tag: vec!(0xd3, 0x8d, 0x67, 0x26, 0x65, 0xe2, 0xc8, 0xc4, 0xa0, 0x79, 0x54, 0xb1, 0x0e, 0xcf, 0xf7, 0xd9)
+      // },
+      // TestVector{
+      //   key: [0x3b, 0x31, 0x9e, 0x40, 0x14, 0x8a, 0x67, 0xdc, 0x0b, 0xb1, 0x92, 0x71, 0xd9, 0x27, 0x2b, 0x32, 0x7b, 0xc5, 0xee, 0xe0, 0x87, 0x17, 0x3d, 0x3d, 0x13, 0x4a, 0xd5, 0x6c, 0x8c, 0x7d, 0xc0, 0x20],
+      //   nonce: [0xce, 0x5c, 0xf6, 0xfe, 0xf8, 0x4d, 0x00, 0x10],
+      //   plain_text: vec!(0x27, 0xb5, 0x62, 0x7b, 0x17, 0xa2, 0xde, 0x31, 0xad, 0x00, 0xfc, 0x2e, 0xcb, 0x34, 0x7d, 0xa0, 0xa3, 0x99, 0xbb, 0x75, 0xcc, 0x6e, 0xad, 0xd4, 0xd6, 0xee, 0x02, 0xde, 0x8f, 0xbd, 0x6a, 0x21, 0x68, 0xd4, 0x76, 0x3b, 0xa9, 0x36, 0x8b, 0xa9, 0x82, 0xe9, 0x7a, 0x2d, 0xb8, 0x12, 0x6d, 0xf0, 0x34, 0x3c, 0xda, 0xd0, 0x6d, 0x2b, 0xc7, 0xd7, 0xe1, 0x2e, 0xec, 0x73, 0x1d, 0x13, 0x0f, 0x8b, 0x87, 0x45, 0xc1, 0x95, 0x4b, 0xfd, 0x1d, 0x71, 0x7b, 0x4e, 0xa2),
+      //   aad: vec!(0xa0, 0x26, 0xb6, 0x63, 0x8f, 0x29, 0x39, 0xec, 0x9c, 0xc2, 0x8d, 0x93, 0x5f, 0xb7, 0x11, 0x31, 0x57, 0xf3, 0xb5, 0xb7, 0xe2, 0x6c, 0x12, 0xf8, 0xf2, 0x5b, 0x36, 0x41, 0x2b, 0x0c, 0xd5, 0x60, 0xb7, 0xf1, 0x1b, 0x62, 0x78, 0x8a, 0x76, 0xbd, 0x17, 0x13, 0x42, 0xe2, 0xae, 0x85, 0x8b, 0xce, 0xcb, 0x82, 0x66, 0xff, 0x84, 0x82, 0xbb, 0xae, 0xd5, 0x93, 0xaf, 0xe8, 0x18, 0xb9, 0x82, 0x9e, 0x05, 0xe8, 0xe2, 0xb2, 0x81, 0xae, 0x77, 0x99, 0x58, 0x01, 0x42),
+      //   cipher_text: vec!(0x36, 0x8f, 0xb6, 0x98, 0x92, 0x44, 0x7b, 0x75, 0x77, 0x8f, 0x1c, 0x52, 0x36, 0xe1, 0xe9, 0xd5, 0xd8, 0x92, 0x55, 0xc3, 0xd6, 0x8d, 0x56, 0x5a, 0x5b, 0xba, 0x4f, 0x52, 0x4d, 0x6a, 0xd2, 0x7d, 0xe1, 0x30, 0x87, 0xf3, 0x01, 0xe2, 0xef, 0x4c, 0x08, 0xf5, 0xe2, 0xc6, 0x12, 0x8b, 0x1d, 0x3e, 0x26, 0xde, 0x84, 0x5c, 0x4a, 0xc4, 0x86, 0x9e, 0x4c, 0x8b, 0xd8, 0x85, 0x8a, 0xd0, 0xd2, 0x6d, 0xec, 0x3b, 0x5d, 0x61, 0xa9, 0xe3, 0x66, 0x6a, 0x39, 0x11, 0xba),
+      //   tag: vec!(0x2e, 0x70, 0x56, 0x4c, 0x39, 0x99, 0xc4, 0x48, 0xd9, 0x2c, 0xc6, 0xdf, 0x29, 0xd0, 0x95, 0xc4)
+      // },
+      // TestVector{
+      //   key: [0x43, 0xbf, 0x97, 0x40, 0x7a, 0x82, 0xd0, 0xf6, 0x84, 0xbb, 0x85, 0x34, 0x23, 0x80, 0xd6, 0x6b, 0x85, 0xfc, 0xc8, 0x1c, 0x3e, 0x22, 0xf1, 0xc0, 0xd9, 0x72, 0xcd, 0x5b, 0xfd, 0xf4, 0x07, 0xf4],
+      //   nonce: [0x8b, 0x6b, 0xa4, 0x94, 0xc5, 0x40, 0xfb, 0xa4],
+      //   plain_text: vec!(0x4b, 0x4c, 0x7e, 0x29, 0x2a, 0x35, 0x7f, 0x56, 0xfd, 0xf5, 0x67, 0xc3, 0x2f, 0xc0, 0xf3, 0x36, 0x08, 0x11, 0x0d, 0x7c, 0xe5, 0xc6, 0x91, 0x12, 0x98, 0x7d, 0x7b, 0x5a, 0x0b, 0xd4, 0x6d, 0x86, 0x27, 0xa7, 0x21, 0xb0, 0xae, 0xd0, 0x70, 0xb5, 0x4e, 0xa9, 0x72, 0x60, 0x84, 0x18, 0x8c, 0x51, 0x8c, 0xba, 0x82, 0x9f, 0x39, 0x20, 0x36, 0x5a, 0xfc, 0x93, 0x82, 0xc6, 0xa5, 0xeb, 0x0d, 0xd3, 0x32, 0xb8, 0x46, 0x12, 0x36, 0x67, 0x35, 0xbe, 0x24, 0x79, 0xb6, 0x3c, 0x9e, 0xfc, 0x7f, 0xf5),
+      //   aad: vec!(0x1e, 0x0a, 0xcf, 0x40, 0x70, 0xe8, 0xd6, 0x75, 0x8b, 0x60, 0xd8, 0x1b, 0x6d, 0x28, 0x9a, 0x4e, 0xcd, 0xc3, 0x0e, 0x3d, 0xe4, 0xf9, 0x09, 0x0c, 0x13, 0x69, 0x1d, 0x5b, 0x93, 0xd5, 0xbb, 0xce, 0xf9, 0x84, 0xf9, 0x09, 0x56, 0xde, 0x53, 0xc5, 0xcf, 0x44, 0xbe, 0x6c, 0x70, 0x44, 0x06, 0x61, 0xfa, 0x58, 0xe6, 0x5d, 0xec, 0x27, 0x34, 0xff, 0x51, 0xd6, 0xd0, 0x3f, 0x57, 0xbd, 0xdd, 0xa1, 0xf4, 0x78, 0x07, 0x24, 0x7e, 0x31, 0x94, 0xe2, 0xf7, 0xdd, 0xd5, 0xf3, 0xca, 0xfd, 0x25, 0x0f),
+      //   cipher_text: vec!(0xd0, 0x07, 0x6c, 0x88, 0xad, 0x4b, 0xc1, 0x2d, 0x77, 0xeb, 0x8a, 0xe8, 0xd9, 0xb5, 0xbf, 0x3a, 0x2c, 0x58, 0x88, 0xa8, 0xd4, 0xc1, 0x52, 0x97, 0xb3, 0x8e, 0xce, 0x5d, 0x64, 0xf6, 0x73, 0x19, 0x1d, 0xc8, 0x15, 0x47, 0x24, 0x0a, 0x0c, 0xbe, 0x06, 0x6c, 0x9c, 0x56, 0x3f, 0x5c, 0x34, 0x24, 0x80, 0x99, 0x71, 0xb5, 0xa0, 0x7d, 0xcc, 0x70, 0xb1, 0x07, 0x30, 0x55, 0x61, 0xce, 0x85, 0xae, 0xcb, 0x0b, 0x0e, 0xa0, 0xe8, 0xb4, 0xff, 0x4d, 0x1e, 0x4f, 0x84, 0x83, 0x69, 0x55, 0xa9, 0x45),
+      //   tag: vec!(0x75, 0xc9, 0x34, 0x74, 0x25, 0xb4, 0x59, 0xaf, 0x6d, 0x99, 0xb1, 0x73, 0x45, 0xc6, 0x1f, 0xf7)
+      // },
+      // TestVector{
+      //   key: [0x12, 0xfc, 0x0b, 0xc9, 0x41, 0x04, 0xed, 0x81, 0x50, 0xbd, 0xe1, 0xe5, 0x68, 0x56, 0xce, 0x3c, 0x57, 0xcd, 0x1c, 0xf6, 0x33, 0x95, 0x4d, 0x22, 0x55, 0x21, 0x40, 0xe1, 0xf4, 0xe7, 0xc6, 0x5d],
+      //   nonce: [0xd3, 0x87, 0x5d, 0x1b, 0x6c, 0x80, 0x83, 0x53],
+      //   plain_text: vec!(0x24, 0x59, 0x20, 0x82, 0xd6, 0xe7, 0x3e, 0xb6, 0x5c, 0x40, 0x9b, 0x26, 0xce, 0xae, 0x03, 0x2e, 0x57, 0xf6, 0x87, 0x75, 0x14, 0x94, 0x7f, 0xc4, 0x5e, 0xb0, 0x07, 0xb8, 0xa6, 0x03, 0x44, 0x94, 0xdd, 0xe5, 0x56, 0x3a, 0xc5, 0x86, 0xea, 0x08, 0x1d, 0xc1, 0x2f, 0xa6, 0xcd, 0xa3, 0x22, 0x66, 0xbe, 0x85, 0x8e, 0x47, 0x48, 0xbe, 0x40, 0xbb, 0x20, 0xf7, 0x13, 0x20, 0x71, 0x1b, 0xf8, 0x4c, 0x3f, 0x0e, 0x27, 0x83, 0xa6, 0x3a, 0xd6, 0xe2, 0x5a, 0x63, 0xb4, 0x4c, 0x37, 0x3a, 0x99, 0xaf, 0x84, 0x5c, 0xdf, 0x45, 0x2c),
+      //   aad: vec!(0xb8, 0xbe, 0x08, 0x46, 0x3e, 0x84, 0xa9, 0x09, 0xd0, 0x71, 0xf5, 0xff, 0x87, 0x21, 0x33, 0x91, 0xb7, 0xda, 0x88, 0x9d, 0xc5, 0x6f, 0xd2, 0xf1, 0xe3, 0xcf, 0x86, 0xa0, 0xa0, 0x3e, 0x2c, 0x8e, 0xaa, 0x2f, 0x53, 0x9b, 0xf7, 0x3f, 0x90, 0xf5, 0x29, 0x8c, 0x26, 0xf2, 0x7e, 0xf4, 0xa6, 0x73, 0xa1, 0x27, 0x84, 0x83, 0x3a, 0xcb, 0x4d, 0x08, 0x61, 0x56, 0x21, 0x42, 0xc9, 0x74, 0xee, 0x37, 0xb0, 0x9a, 0xe7, 0x70, 0x8a, 0x19, 0xf1, 0x4d, 0x1a, 0xd8, 0xc4, 0x02, 0xbd, 0x1e, 0xcf, 0x5e, 0xa2, 0x80, 0xfa, 0xb2, 0x80),
+      //   cipher_text: vec!(0x9d, 0x9a, 0xe6, 0x32, 0x87, 0x11, 0xfb, 0x89, 0x7a, 0x88, 0x46, 0x2d, 0x20, 0xb8, 0xaa, 0x1b, 0x27, 0x81, 0x34, 0xcd, 0xf7, 0xb2, 0x3e, 0x1f, 0x1c, 0x80, 0x9f, 0xa4, 0x08, 0xb6, 0x8a, 0x7b, 0xfc, 0x2b, 0xe6, 0x1a, 0x79, 0x00, 0x08, 0xed, 0xaa, 0x98, 0x82, 0x33, 0x81, 0xf4, 0x5a, 0xe6, 0x5f, 0x71, 0x04, 0x26, 0x89, 0xd8, 0x8a, 0xcf, 0xa5, 0xf6, 0x33, 0x32, 0xf0, 0xfb, 0xa7, 0x37, 0xc4, 0x77, 0x2c, 0x97, 0x2e, 0xba, 0x26, 0x66, 0x40, 0x05, 0x64, 0x52, 0x90, 0x3d, 0x65, 0x22, 0xce, 0xfd, 0x3f, 0x26, 0x4e),
+      //   tag: vec!(0xe9, 0xc9, 0x82, 0xd4, 0xad, 0xe7, 0x39, 0x7b, 0xcf, 0xaa, 0x1e, 0x4c, 0x5a, 0x6c, 0xd5, 0x78)
+      // },
+      // TestVector{
+      //   key: [0x7b, 0x63, 0x00, 0xf7, 0xdc, 0x21, 0xc9, 0xfd, 0xde, 0xaa, 0x71, 0xf4, 0x39, 0xd5, 0x3b, 0x55, 0x3a, 0x7b, 0xf3, 0xe6, 0x9f, 0xf5, 0x15, 0xb5, 0xcb, 0x64, 0x95, 0xd6, 0x52, 0xa0, 0xf9, 0x9c],
+      //   nonce: [0x40, 0xb3, 0x2e, 0x3f, 0xdc, 0x64, 0x64, 0x53],
+      //   plain_text: vec!(0x57, 0x2f, 0x60, 0xd9, 0x8c, 0x8b, 0xec, 0xc8, 0xba, 0x80, 0xdd, 0x6b, 0x8d, 0x2d, 0x0f, 0x7b, 0x7b, 0xbf, 0xd7, 0xe4, 0xab, 0xc2, 0x35, 0xf3, 0x74, 0xab, 0xd4, 0x4d, 0x90, 0x35, 0xc7, 0x65, 0x0a, 0x79, 0xd1, 0xdd, 0x54, 0x5f, 0xa2, 0xf6, 0xfb, 0x0b, 0x5e, 0xba, 0x27, 0x17, 0x79, 0x91, 0x3e, 0x5c, 0x5e, 0xb4, 0x50, 0x52, 0x8e, 0x41, 0x28, 0x90, 0x9a, 0x96, 0xd1, 0x1a, 0x65, 0x2b, 0xf3, 0xf7, 0xae, 0x9d, 0x0d, 0x17, 0xad, 0xbf, 0x61, 0x2e, 0xc9, 0xca, 0x32, 0xe7, 0x3e, 0xf6, 0xe8, 0x7d, 0x7f, 0x4e, 0x21, 0xfe, 0x34, 0x12, 0xce, 0x14),
+      //   aad: vec!(0x9f, 0xf3, 0x77, 0x54, 0x5a, 0x35, 0xcf, 0x1b, 0xfb, 0x77, 0xc7, 0x34, 0xad, 0x90, 0x0c, 0x70, 0x3a, 0xee, 0x6c, 0x31, 0x74, 0xfd, 0xb3, 0x73, 0x66, 0x64, 0x86, 0x30, 0x36, 0xa3, 0xa9, 0xd0, 0x91, 0x63, 0xc2, 0x99, 0x2f, 0x09, 0x3e, 0x24, 0x08, 0x91, 0x1b, 0x87, 0x51, 0xf0, 0x01, 0xe4, 0x93, 0xde, 0xcc, 0x41, 0xe4, 0xee, 0xee, 0xd0, 0x4f, 0x69, 0x8b, 0x6d, 0xae, 0xd4, 0x84, 0x52, 0xa7, 0xe1, 0xa7, 0x4e, 0xc3, 0xb4, 0xf3, 0xdc, 0xf2, 0x15, 0x1c, 0xa2, 0x49, 0xfa, 0x56, 0x8a, 0xa0, 0x84, 0xc8, 0x42, 0x8a, 0x41, 0xf2, 0x0b, 0xe5, 0xfd),
+      //   cipher_text: vec!(0x22, 0x9d, 0xa7, 0x68, 0x44, 0x42, 0x66, 0x39, 0xe2, 0xfd, 0x3e, 0xf2, 0x53, 0xa1, 0x95, 0xe0, 0xa9, 0x3f, 0x08, 0x45, 0x2b, 0xa3, 0x72, 0x19, 0xb6, 0x77, 0x3f, 0x10, 0x31, 0x34, 0xf3, 0xf8, 0x7b, 0x13, 0x45, 0xf9, 0xb4, 0xbf, 0x8c, 0xfc, 0x11, 0x27, 0x7c, 0x31, 0x17, 0x80, 0xa2, 0xb6, 0xe1, 0x9a, 0x36, 0x3b, 0x6a, 0xc2, 0xef, 0xe6, 0xc4, 0xcc, 0x54, 0xa3, 0x9b, 0x14, 0x4e, 0x29, 0xc9, 0x4b, 0x9e, 0xbb, 0xde, 0x6f, 0xd0, 0x94, 0xc3, 0x0f, 0x59, 0xd1, 0xb7, 0x70, 0xeb, 0xf9, 0xfc, 0xad, 0x2a, 0x5c, 0x69, 0x5d, 0xc0, 0x03, 0xbf, 0x51),
+      //   tag: vec!(0xb7, 0x2a, 0xca, 0xb5, 0x01, 0x31, 0xa2, 0x95, 0x58, 0xd5, 0x6a, 0xe7, 0xb9, 0xd4, 0x8e, 0x4e)
+      // },
+      // TestVector{
+      //   key: [0x4a, 0xeb, 0x62, 0xf0, 0x24, 0xe1, 0x87, 0x60, 0x6e, 0xe7, 0xcc, 0x9f, 0x58, 0x65, 0xc3, 0x91, 0xc4, 0x3d, 0xf1, 0x96, 0x3f, 0x45, 0x9c, 0x87, 0xba, 0x00, 0xe4, 0x4b, 0xb1, 0x63, 0xa8, 0x66],
+      //   nonce: [0x95, 0x59, 0xbd, 0x08, 0x71, 0x8b, 0x75, 0xaf],
+      //   plain_text: vec!(0xc5, 0xd5, 0x86, 0xce, 0xec, 0xe6, 0xf4, 0x18, 0x12, 0xc9, 0x69, 0xbc, 0xf1, 0xe7, 0x27, 0xfe, 0x6f, 0xf8, 0xd1, 0xae, 0x8c, 0x8c, 0x52, 0x36, 0x7c, 0x61, 0x2c, 0xaa, 0x7c, 0xdf, 0x50, 0xe0, 0x66, 0x2f, 0x5d, 0xff, 0xc5, 0xea, 0x7d, 0x3c, 0xc3, 0x94, 0x00, 0xdf, 0xe3, 0xdc, 0x18, 0x97, 0x90, 0x5f, 0x64, 0x90, 0xfd, 0x77, 0x47, 0xb5, 0xf5, 0xf9, 0x84, 0x27, 0x39, 0xc6, 0x7d, 0x07, 0xce, 0x7c, 0x33, 0x9a, 0x5b, 0x39, 0x97, 0xa7, 0xfb, 0x4c, 0xd0, 0xd8, 0xe4, 0x81, 0x7f, 0xf8, 0x91, 0x6b, 0x25, 0x1c, 0x11, 0xef, 0x91, 0x91, 0x67, 0xf8, 0x58, 0xe4, 0x15, 0x04, 0xb9),
+      //   aad: vec!(0x51, 0xf5, 0xb5, 0x03, 0xb7, 0x3a, 0x5d, 0xe8, 0xb9, 0x65, 0x34, 0xc2, 0xa3, 0xf2, 0xd8, 0x59, 0xec, 0xe0, 0xbd, 0x06, 0x3e, 0xa6, 0xdf, 0xa4, 0x86, 0xa7, 0xee, 0xc9, 0x9f, 0x6c, 0x02, 0x09, 0x83, 0xf7, 0x14, 0x8c, 0xcc, 0xb8, 0x62, 0x02, 0xcf, 0x96, 0x85, 0xcc, 0x1c, 0xc2, 0x66, 0x93, 0x0f, 0x04, 0xe5, 0x36, 0xad, 0x8b, 0xc2, 0x60, 0x94, 0x25, 0x2b, 0xaa, 0x46, 0x06, 0xd8, 0x83, 0xbd, 0x2a, 0xee, 0xd6, 0xb4, 0x30, 0x15, 0x22, 0x02, 0xe9, 0xb6, 0xcc, 0x79, 0x7f, 0xf2, 0x4f, 0xc3, 0x65, 0x31, 0x5e, 0xd6, 0x73, 0x91, 0x37, 0x4c, 0x13, 0x57, 0xc9, 0xa8, 0x45, 0xf2),
+      //   cipher_text: vec!(0x25, 0x2e, 0xa4, 0x2b, 0x6e, 0x57, 0x40, 0x30, 0x68, 0x16, 0x97, 0x4a, 0x4f, 0xe6, 0x7b, 0x66, 0xe7, 0x93, 0xeb, 0xe0, 0x91, 0x47, 0x78, 0xef, 0x48, 0x5d, 0x55, 0x28, 0x8e, 0xb6, 0xc9, 0xc4, 0x5f, 0xa3, 0x4a, 0xc8, 0x53, 0xdc, 0x7a, 0x39, 0x25, 0x25, 0x20, 0x51, 0x4c, 0x3c, 0xb3, 0x4c, 0x72, 0xb9, 0x73, 0xb1, 0x4b, 0x32, 0xbc, 0x25, 0x76, 0x87, 0xd3, 0x98, 0xf3, 0x6f, 0x64, 0xcc, 0x2a, 0x66, 0x8f, 0xaf, 0xfa, 0x73, 0x05, 0xab, 0x24, 0x01, 0x71, 0x34, 0x3b, 0x5f, 0x9f, 0x49, 0xb6, 0xc2, 0x19, 0x7e, 0x4f, 0xbe, 0x18, 0x7b, 0x10, 0x54, 0x0d, 0x7c, 0xdc, 0xfa, 0x37),
+      //   tag: vec!(0x71, 0x1f, 0xf3, 0x3e, 0xf8, 0xd2, 0xb0, 0x67, 0xa1, 0xb8, 0x5c, 0x64, 0xf3, 0x2f, 0x18, 0x14)
+      // },
+      // TestVector{
+      //   key: [0x9a, 0x19, 0xe7, 0x2f, 0x00, 0x5c, 0xae, 0x1a, 0xe7, 0x8b, 0x8e, 0x35, 0x0d, 0x7a, 0xab, 0xe5, 0x9f, 0xc8, 0x84, 0x59, 0x99, 0xe8, 0xc5, 0x2f, 0xad, 0x54, 0x5b, 0x94, 0x2c, 0x22, 0x5e, 0xaf],
+      //   nonce: [0xd9, 0xda, 0xe2, 0xea, 0x8d, 0x2f, 0xfc, 0x31],
+      //   plain_text: vec!(0x21, 0x10, 0x37, 0x8d, 0x85, 0x6d, 0xed, 0x07, 0xeb, 0x2b, 0xe8, 0xe8, 0xf4, 0x33, 0x08, 0xe0, 0xc7, 0x5b, 0xc8, 0xa3, 0xfc, 0xc7, 0xb1, 0x77, 0x3b, 0x07, 0x25, 0xb7, 0xde, 0x49, 0xf6, 0xa1, 0x66, 0xc4, 0x52, 0x8e, 0x64, 0x12, 0x0b, 0xdf, 0x7c, 0x97, 0x76, 0x61, 0x5d, 0x3c, 0xe6, 0xfe, 0xeb, 0x03, 0xde, 0x96, 0x4a, 0x7b, 0x91, 0x92, 0x06, 0xa7, 0x73, 0x92, 0xf8, 0x04, 0x37, 0xfa, 0xce, 0xb6, 0x74, 0x58, 0x45, 0xca, 0xfc, 0x16, 0x6e, 0x1c, 0x13, 0xb6, 0x8e, 0x70, 0xca, 0x2a, 0x1d, 0x00, 0xc7, 0x17, 0x37, 0xb8, 0xfc, 0xbb, 0xbd, 0x50, 0x90, 0x25, 0x65, 0xc3, 0x21, 0x59, 0xe0, 0x5f, 0xcd, 0x23),
+      //   aad: vec!(0x1c, 0xd7, 0x3b, 0x72, 0xc4, 0xe1, 0x03, 0xaf, 0xbe, 0xfd, 0x7c, 0x77, 0x7e, 0x04, 0x80, 0xf3, 0xf5, 0xe6, 0x8c, 0x60, 0xb8, 0x5b, 0xd2, 0xe7, 0x1e, 0xf5, 0xca, 0xeb, 0xb1, 0x75, 0xd7, 0xfc, 0x65, 0x35, 0xd3, 0x9f, 0x38, 0xf9, 0x2c, 0x24, 0xf2, 0xeb, 0x0f, 0xe9, 0x7d, 0x87, 0x8e, 0xd3, 0xd5, 0x96, 0x7c, 0x0b, 0xb4, 0x39, 0x4a, 0x5d, 0x41, 0xf7, 0xd3, 0x4c, 0xda, 0x6e, 0x15, 0x23, 0xd3, 0x84, 0x8f, 0x04, 0x9c, 0xde, 0x55, 0x4a, 0x7d, 0x31, 0xe1, 0xaf, 0xea, 0xb5, 0xd3, 0xe6, 0x15, 0x0f, 0x85, 0x85, 0x83, 0x35, 0xcb, 0xd2, 0x8c, 0x8a, 0x7f, 0x87, 0xd5, 0x28, 0x05, 0x8d, 0xf5, 0x0e, 0xea, 0x06),
+      //   cipher_text: vec!(0x5f, 0x00, 0x9f, 0xbc, 0xe4, 0xec, 0x8e, 0x4c, 0xa9, 0xd8, 0xd4, 0x22, 0x58, 0xb1, 0xa3, 0xe4, 0xe9, 0x20, 0xb2, 0xfb, 0xad, 0x33, 0xd5, 0xe9, 0xf0, 0x75, 0x57, 0xd9, 0x59, 0x5e, 0x84, 0x10, 0x25, 0x19, 0x3b, 0x52, 0x1b, 0xa4, 0x40, 0x11, 0x0d, 0xd8, 0x39, 0x58, 0xe8, 0xee, 0x30, 0x21, 0x9d, 0x95, 0x2b, 0x41, 0x8e, 0x98, 0xa6, 0xc6, 0x24, 0x89, 0x4a, 0xa2, 0x48, 0xae, 0xdc, 0x06, 0x78, 0xf2, 0xd2, 0x63, 0xe7, 0xbf, 0xaf, 0x54, 0xca, 0x37, 0x9f, 0xef, 0x6c, 0x5d, 0x2f, 0x7a, 0xc4, 0x22, 0xea, 0x4b, 0x43, 0x69, 0x40, 0x8b, 0x82, 0xd6, 0x22, 0x5a, 0x7a, 0x2c, 0xf9, 0xa9, 0xf4, 0x6f, 0xd4, 0xef),
+      //   tag: vec!(0xaa, 0x0a, 0x5f, 0xa7, 0xd3, 0xcf, 0x71, 0x7a, 0x47, 0x04, 0xa5, 0x99, 0x73, 0xb1, 0xcd, 0x15)
+      // },
+      // TestVector{
+      //   key: [0xba, 0x1d, 0x0b, 0x33, 0x29, 0xec, 0xc0, 0x09, 0xf1, 0xda, 0x0f, 0xab, 0x4c, 0x85, 0x4b, 0x00, 0xad, 0x94, 0x48, 0x70, 0xfd, 0xca, 0x56, 0x18, 0x38, 0xe3, 0x8b, 0xad, 0x36, 0x4d, 0xa5, 0x07],
+      //   nonce: [0x8a, 0x81, 0xc9, 0x2b, 0x37, 0x22, 0x1f, 0x2f],
+      //   plain_text: vec!(0x62, 0x89, 0x94, 0x4f, 0xfa, 0x3c, 0xce, 0xa4, 0xbf, 0x25, 0xcd, 0x60, 0x1b, 0x27, 0x1f, 0x64, 0xe6, 0xde, 0xb0, 0xeb, 0xa7, 0x7d, 0x65, 0xef, 0xb4, 0xd6, 0x9c, 0xa9, 0x3e, 0x01, 0x99, 0x6e, 0x47, 0x27, 0x16, 0x8b, 0x6f, 0x74, 0xf3, 0xcc, 0xf1, 0x7b, 0xd4, 0x47, 0x15, 0xf2, 0x3c, 0xeb, 0x8f, 0xc0, 0x30, 0xc0, 0xe0, 0x35, 0xe7, 0x7f, 0x53, 0x26, 0x3d, 0xb0, 0x25, 0x02, 0x1f, 0xd2, 0xd0, 0x4b, 0x87, 0xa1, 0xb5, 0x4b, 0x12, 0x22, 0x9c, 0x5e, 0x86, 0x04, 0x81, 0x45, 0x2a, 0x80, 0xa1, 0x25, 0xcb, 0x06, 0x93, 0xa2, 0xba, 0x1b, 0x47, 0xe2, 0x8e, 0xe7, 0xcb, 0xaf, 0x9e, 0x68, 0x3c, 0x17, 0x82, 0x32, 0xc7, 0xf6, 0xd3, 0x4f, 0x97),
+      //   aad: vec!(0xe5, 0x78, 0x83, 0x96, 0x1b, 0x8d, 0x04, 0x1d, 0x9b, 0x9e, 0xea, 0xdd, 0xcf, 0xd6, 0x1f, 0xa9, 0xf5, 0x92, 0x13, 0xf6, 0x65, 0x71, 0xfa, 0xdf, 0xff, 0xfd, 0xd1, 0x49, 0x8b, 0x9b, 0x01, 0x4f, 0x1e, 0xf2, 0xe7, 0xe5, 0x6c, 0x30, 0x44, 0xd7, 0xf9, 0xfa, 0x7a, 0x14, 0x03, 0xa1, 0x16, 0x9e, 0x86, 0x43, 0x0a, 0x2a, 0x78, 0x21, 0x37, 0x09, 0x3f, 0x54, 0x56, 0xe1, 0x42, 0xaa, 0xd0, 0x3a, 0x5f, 0x7a, 0x66, 0xd3, 0x80, 0x09, 0xdd, 0x01, 0xb7, 0xfc, 0x02, 0xc9, 0xcf, 0x61, 0x64, 0x2d, 0xed, 0xaf, 0x7c, 0xc8, 0xd4, 0x60, 0x66, 0xc2, 0x81, 0xee, 0x17, 0x78, 0x06, 0x74, 0xc3, 0xa3, 0x6e, 0xae, 0x66, 0xc5, 0x8d, 0x2d, 0x76, 0x50, 0x75),
+      //   cipher_text: vec!(0x9c, 0x44, 0xd9, 0x13, 0x5d, 0xb0, 0xdb, 0xf8, 0x1c, 0x86, 0x2c, 0x1f, 0x69, 0xbe, 0xc5, 0x5a, 0x27, 0x97, 0x94, 0xcd, 0xd2, 0x9a, 0x58, 0xe6, 0x19, 0x09, 0xaa, 0x29, 0xec, 0x4c, 0x12, 0x0c, 0x9c, 0x5a, 0x50, 0x8d, 0x85, 0x6b, 0x9e, 0x56, 0x13, 0x80, 0x95, 0x71, 0x4a, 0x4b, 0xb5, 0x84, 0x02, 0xa1, 0xad, 0x06, 0x77, 0x4c, 0xf4, 0xec, 0xdf, 0x22, 0x73, 0x83, 0x9c, 0x00, 0x07, 0xcb, 0x88, 0xb5, 0x44, 0x4b, 0x25, 0xc7, 0x6f, 0x6d, 0x24, 0x24, 0x28, 0x11, 0x01, 0xd0, 0x43, 0xfc, 0x63, 0x69, 0xeb, 0xb3, 0xb2, 0xff, 0x63, 0xcd, 0xb0, 0xf1, 0x1a, 0x6e, 0xa1, 0xb8, 0xa7, 0xda, 0xfc, 0x80, 0xcd, 0xae, 0xf2, 0x81, 0x3f, 0xa6, 0x61),
+      //   tag: vec!(0x65, 0xc7, 0x46, 0xf6, 0x59, 0xbc, 0xbd, 0xcd, 0x05, 0x4e, 0x76, 0x8c, 0x57, 0xc8, 0x48, 0xc9)
+      // },
+      // TestVector{
+      //   key: [0x0c, 0xf8, 0xc7, 0x3a, 0x6c, 0xff, 0xc1, 0xb8, 0xb2, 0xf5, 0xd3, 0x20, 0xda, 0x1d, 0x85, 0x9d, 0x31, 0x43, 0x74, 0xe4, 0xa9, 0x46, 0x8d, 0xb7, 0xfd, 0x42, 0xc8, 0xd2, 0x70, 0xb7, 0x61, 0x3a],
+      //   nonce: [0x3c, 0x4c, 0x6f, 0x02, 0x81, 0x84, 0x1a, 0xff],
+      //   plain_text: vec!(0x44, 0x34, 0x72, 0x8d, 0x23, 0x46, 0x03, 0xc9, 0x16, 0xe2, 0xfa, 0xa0, 0x6b, 0x25, 0xd8, 0x3b, 0xad, 0x33, 0x48, 0x99, 0x0e, 0xcd, 0xe2, 0x34, 0x43, 0x68, 0xd1, 0xa7, 0xaf, 0x13, 0x09, 0xbd, 0x04, 0x25, 0x1b, 0xb2, 0xe0, 0xb7, 0x20, 0x44, 0x94, 0x8f, 0x8d, 0xea, 0x33, 0xcc, 0xe2, 0x61, 0x82, 0x83, 0xb6, 0xaf, 0x74, 0x20, 0x73, 0xa9, 0x58, 0x6b, 0x26, 0xc1, 0x08, 0x93, 0x35, 0xfe, 0x73, 0x51, 0x41, 0xe0, 0x99, 0x78, 0x5a, 0x12, 0x35, 0x81, 0x0a, 0x3a, 0x67, 0xff, 0x30, 0x9e, 0x2f, 0x0c, 0xe6, 0x82, 0x20, 0xba, 0x00, 0x77, 0xad, 0x1a, 0x5d, 0xc1, 0xa4, 0xae, 0xf8, 0x98, 0xa3, 0xb9, 0xff, 0x8f, 0x5a, 0xd7, 0xfe, 0x60, 0x14, 0x9b, 0xd0, 0xbd, 0x6d, 0x83),
+      //   aad: vec!(0xa3, 0x8d, 0x09, 0xa4, 0xf1, 0xc9, 0x24, 0x16, 0x23, 0xc6, 0x39, 0xb7, 0x68, 0x8d, 0x8d, 0x35, 0x34, 0x5e, 0xa5, 0x82, 0x40, 0x80, 0xc9, 0xd7, 0x4e, 0x43, 0x52, 0x91, 0x9d, 0xb6, 0x3c, 0x74, 0xd3, 0x18, 0xf1, 0x9e, 0x1c, 0xbb, 0x9b, 0x14, 0xee, 0xbd, 0x7c, 0x74, 0xb0, 0xad, 0x01, 0x19, 0x24, 0x76, 0x51, 0x91, 0x1f, 0x35, 0x51, 0x58, 0x3e, 0x74, 0x9e, 0xa5, 0x0f, 0xf6, 0x48, 0x85, 0x8d, 0xca, 0xaa, 0x78, 0x9b, 0x74, 0x19, 0xd9, 0xe9, 0x3a, 0x5b, 0xf6, 0xc8, 0x16, 0x71, 0x88, 0xdb, 0xac, 0x2f, 0x36, 0x80, 0x43, 0x80, 0xdb, 0x32, 0x52, 0x01, 0x98, 0x2b, 0x8b, 0x06, 0x59, 0x7e, 0xfe, 0xb7, 0x68, 0x45, 0x46, 0xb2, 0x72, 0x64, 0x29, 0x41, 0x59, 0x1e, 0x92),
+      //   cipher_text: vec!(0xbd, 0xfb, 0xfe, 0xa2, 0x61, 0xb1, 0xf4, 0xc1, 0x34, 0x44, 0x53, 0x21, 0xdb, 0x9e, 0x6e, 0x40, 0x47, 0x6e, 0x2d, 0xd2, 0xf4, 0xe4, 0xdb, 0xe8, 0x6e, 0x31, 0xd6, 0xa1, 0x16, 0xd2, 0x58, 0x30, 0x76, 0x2e, 0x06, 0x5b, 0x07, 0xb1, 0x1a, 0x37, 0x99, 0xaa, 0xb9, 0x3a, 0x94, 0xb4, 0xf9, 0x8c, 0x31, 0xc0, 0xfa, 0xeb, 0x77, 0xec, 0x52, 0xc0, 0x20, 0x48, 0xe9, 0x57, 0x92, 0x57, 0xe6, 0x7f, 0x5a, 0x6b, 0xae, 0x9b, 0xc6, 0x52, 0x10, 0xc2, 0x5b, 0x37, 0xfc, 0x16, 0xee, 0x93, 0xbd, 0xa8, 0x8f, 0xd5, 0xf3, 0x0a, 0x53, 0x3e, 0x47, 0x0b, 0x61, 0x88, 0xc6, 0xce, 0x57, 0x39, 0xfa, 0x3e, 0x90, 0xf7, 0x71, 0x20, 0xb4, 0x90, 0xfc, 0x10, 0x27, 0x96, 0x4f, 0x27, 0x7f, 0x40),
+      //   tag: vec!(0x49, 0x93, 0xee, 0x95, 0x82, 0xf5, 0x8e, 0xab, 0xdb, 0x26, 0xb9, 0x8c, 0x4d, 0x56, 0xa2, 0x44)
+      // },
+      // TestVector{
+      //   key: [0x69, 0xf4, 0xe5, 0x78, 0x8d, 0x48, 0x6a, 0x75, 0xad, 0xf9, 0x20, 0x7d, 0xf1, 0xbd, 0x26, 0x2d, 0xd2, 0xfe, 0x3d, 0xd3, 0xa0, 0x23, 0x64, 0x20, 0x39, 0x0d, 0x16, 0xe2, 0xa3, 0x04, 0x04, 0x66],
+      //   nonce: [0x62, 0x55, 0xbf, 0x5c, 0x71, 0xbb, 0x27, 0xd1],
+      //   plain_text: vec!(0xc1, 0x50, 0x48, 0xca, 0x29, 0x41, 0xef, 0x96, 0x00, 0xe7, 0x67, 0xa5, 0x04, 0x5a, 0xa9, 0x8a, 0xc6, 0x15, 0x22, 0x5b, 0x80, 0x5a, 0x9f, 0xbd, 0xa3, 0xac, 0x63, 0x01, 0xcd, 0x5a, 0x66, 0xae, 0xf6, 0x11, 0x40, 0x0f, 0xa3, 0xbc, 0x04, 0x83, 0x8e, 0xad, 0x99, 0x24, 0xd3, 0x82, 0xbe, 0xf8, 0x25, 0x1a, 0x47, 0xf1, 0xe4, 0x87, 0xd2, 0xf3, 0xca, 0x4b, 0xcc, 0xd3, 0x47, 0x6a, 0x6c, 0xa7, 0xf1, 0x3e, 0x94, 0xfd, 0x63, 0x9a, 0x25, 0x9e, 0xf2, 0x3c, 0xc2, 0xf8, 0xb8, 0xd2, 0x48, 0xa4, 0x71, 0xd3, 0x0a, 0xc9, 0x21, 0x96, 0x31, 0xc3, 0xe6, 0x98, 0x51, 0x00, 0xdc, 0x45, 0xe0, 0xb5, 0x9b, 0x8f, 0xc6, 0x20, 0x46, 0x30, 0x91, 0x65, 0xdd, 0xb6, 0xf0, 0x92, 0xda, 0x3a, 0x4f, 0x06, 0x7c, 0x8a, 0x44),
+      //   aad: vec!(0x0c, 0x83, 0x03, 0x95, 0x04, 0xc8, 0x46, 0x4b, 0x49, 0xd6, 0x3b, 0x7f, 0x94, 0x48, 0x02, 0xf0, 0xd3, 0x9c, 0x85, 0xe9, 0xf3, 0x74, 0x5e, 0x25, 0x0f, 0x10, 0x11, 0x9f, 0xa2, 0xc9, 0x60, 0x49, 0x0f, 0x75, 0xae, 0x4d, 0xce, 0xd8, 0x50, 0x3b, 0x15, 0x6d, 0x07, 0x2a, 0x69, 0xf2, 0x04, 0x00, 0xe9, 0x49, 0x4a, 0xb2, 0xfa, 0x58, 0x44, 0x6c, 0x25, 0x5d, 0x82, 0xff, 0x0b, 0xe4, 0xb7, 0xe4, 0x30, 0x46, 0x58, 0x0b, 0xc1, 0xcf, 0x34, 0x06, 0x0c, 0x6f, 0x07, 0x6c, 0x72, 0xea, 0x45, 0x5c, 0x36, 0x87, 0x38, 0x1a, 0x3b, 0x90, 0x8e, 0x15, 0x2b, 0x10, 0xc9, 0x5c, 0x7b, 0x94, 0x15, 0x5b, 0x0b, 0x4b, 0x30, 0x3b, 0x77, 0x64, 0xa8, 0xa2, 0x7d, 0x1d, 0xb0, 0xa8, 0x85, 0xf1, 0x04, 0x0d, 0x5d, 0xbc, 0xc3),
+      //   cipher_text: vec!(0xf0, 0xbb, 0x2b, 0x73, 0xd9, 0x4f, 0x2a, 0x7c, 0xef, 0x70, 0xfe, 0x77, 0xe0, 0x54, 0xf2, 0x06, 0x99, 0x8e, 0xac, 0xf2, 0xb8, 0x6c, 0x05, 0xc4, 0xfa, 0x3f, 0x40, 0xf2, 0xb8, 0xce, 0xbf, 0x03, 0x4f, 0xe1, 0x7b, 0xcb, 0xee, 0x4d, 0xea, 0x82, 0x1f, 0x51, 0xc1, 0x8c, 0x0a, 0xa8, 0x5b, 0x16, 0x0f, 0x85, 0x08, 0xbd, 0x1d, 0xc4, 0x55, 0xcc, 0x7f, 0x49, 0x66, 0x8b, 0x1f, 0xb2, 0x55, 0x57, 0xcd, 0xae, 0x14, 0x7b, 0xf2, 0x39, 0x9e, 0x07, 0xfc, 0xac, 0xac, 0xa1, 0x8e, 0xcc, 0xde, 0xd7, 0x41, 0xe0, 0x26, 0xef, 0x25, 0x36, 0x5a, 0x6b, 0x0f, 0x44, 0xa6, 0xb3, 0xdd, 0x97, 0x5e, 0xe6, 0xbb, 0x58, 0x0f, 0x5f, 0xcc, 0xd0, 0x40, 0xb7, 0x3c, 0x18, 0xb0, 0xfb, 0xf8, 0xf6, 0x31, 0x99, 0xba, 0x10, 0xfe),
+      //   tag: vec!(0x42, 0x36, 0xa8, 0x75, 0x0f, 0x0c, 0xaf, 0xee, 0x3c, 0x4a, 0x06, 0xa5, 0x77, 0xa8, 0x5c, 0xb3)
+      // },
+      // TestVector{
+      //   key: [0xad, 0x7b, 0x94, 0x09, 0x14, 0x7a, 0x89, 0x66, 0x48, 0xa2, 0xa2, 0xfe, 0x21, 0x28, 0xf7, 0x90, 0x22, 0xa7, 0x0d, 0x96, 0xdc, 0x48, 0x27, 0x30, 0xcd, 0x85, 0xc7, 0x0d, 0xb4, 0x92, 0xb6, 0x38],
+      //   nonce: [0xa2, 0x8a, 0x6d, 0xed, 0xf3, 0xf2, 0xb0, 0x1a],
+      //   plain_text: vec!(0x79, 0x1d, 0x29, 0x3f, 0xf0, 0xa3, 0xb8, 0x51, 0x0b, 0x4d, 0x49, 0x4b, 0x30, 0xf5, 0x0b, 0x38, 0xa0, 0x16, 0x38, 0xbf, 0x13, 0x0e, 0x58, 0xc7, 0x60, 0x19, 0x04, 0xf1, 0x2c, 0xb8, 0x90, 0x08, 0x71, 0xe8, 0xcf, 0x3d, 0x50, 0xab, 0xd4, 0xd3, 0x4f, 0xda, 0x12, 0x2c, 0x76, 0xdf, 0xee, 0x5b, 0x7f, 0x82, 0xcd, 0x6e, 0x85, 0x90, 0x64, 0x75, 0x35, 0xc9, 0x15, 0xae, 0x08, 0x71, 0x4e, 0x42, 0x7d, 0xa5, 0x2f, 0x80, 0xae, 0xf0, 0x9f, 0x40, 0x04, 0x00, 0x36, 0x03, 0x4c, 0xa5, 0x27, 0x18, 0xea, 0x68, 0x31, 0x3c, 0x53, 0x4e, 0x7a, 0x04, 0x5c, 0xd5, 0x17, 0x45, 0xec, 0x52, 0xf2, 0xe1, 0xb5, 0x94, 0x63, 0xdb, 0x07, 0xde, 0x7c, 0xa4, 0x01, 0xc6, 0xf6, 0x45, 0x38, 0x41, 0xd2, 0x47, 0xf3, 0x70, 0x34, 0x1b, 0x2d, 0xbc, 0x12, 0x12),
+      //   aad: vec!(0x9a, 0x6d, 0xef, 0xdd, 0xb9, 0xb8, 0xd5, 0xc2, 0x4a, 0x26, 0xdd, 0x80, 0x96, 0xf5, 0xb8, 0xc3, 0xaf, 0x7a, 0x89, 0xe1, 0xf7, 0xd8, 0x86, 0xf5, 0x60, 0xfa, 0xbb, 0xe6, 0x4f, 0x14, 0xdb, 0x83, 0x8d, 0x6e, 0xb9, 0xd6, 0x87, 0x9f, 0x4f, 0x0b, 0x76, 0x9f, 0xe1, 0xf9, 0xee, 0xbf, 0x67, 0xfc, 0xd4, 0x7b, 0x6f, 0x9c, 0xeb, 0x48, 0x40, 0xb2, 0xdb, 0xa7, 0x58, 0x7e, 0x98, 0xdc, 0x5c, 0xae, 0x18, 0x6e, 0xf2, 0xa0, 0xf8, 0x60, 0x10, 0x60, 0xe8, 0x05, 0x8d, 0x9d, 0xda, 0x81, 0x2d, 0x91, 0x38, 0x7c, 0x58, 0x3d, 0xa7, 0x01, 0xd2, 0xba, 0x33, 0x47, 0xf2, 0x85, 0xc5, 0xd4, 0x43, 0x85, 0xa2, 0xb0, 0xbf, 0x07, 0x15, 0x0c, 0xbc, 0x95, 0xe7, 0xfc, 0xfa, 0x8a, 0xe0, 0x71, 0x32, 0x84, 0x9a, 0x02, 0x3c, 0x98, 0x81, 0x7c, 0x03, 0xd2),
+      //   cipher_text: vec!(0xc2, 0xf1, 0x09, 0xd6, 0xd9, 0x4f, 0x77, 0xa7, 0x28, 0x9c, 0x8a, 0x2a, 0xb3, 0x3b, 0xc6, 0xa9, 0x8d, 0x97, 0x65, 0x54, 0x72, 0x1b, 0x0c, 0x72, 0x6c, 0xbf, 0x41, 0x21, 0x06, 0x94, 0x73, 0xe6, 0x2b, 0xa3, 0x6e, 0x70, 0x90, 0xe0, 0x24, 0x14, 0xf3, 0xed, 0xc2, 0x5c, 0x5d, 0x83, 0xac, 0x80, 0xb4, 0x9a, 0xd5, 0x28, 0xcd, 0xa1, 0xe3, 0xad, 0x81, 0x5b, 0x5a, 0x8c, 0x8a, 0xe9, 0xad, 0x07, 0x53, 0xde, 0x72, 0x53, 0x19, 0xdf, 0x23, 0x69, 0x83, 0xab, 0xd3, 0xf6, 0x9a, 0xb4, 0x46, 0x5d, 0x9b, 0x80, 0x6c, 0x07, 0x5b, 0x18, 0x96, 0xd4, 0x0b, 0xdb, 0xa7, 0x2d, 0x73, 0xba, 0x84, 0xc4, 0xa5, 0x30, 0x89, 0x6e, 0xb9, 0x4f, 0xfc, 0xcf, 0x5f, 0xb6, 0x7e, 0xb5, 0x91, 0x19, 0xe6, 0x6a, 0x18, 0x61, 0x87, 0x22, 0x18, 0xf9, 0x28, 0xcf),
+      //   tag: vec!(0xe4, 0x8d, 0xc0, 0x15, 0x3d, 0x5b, 0x0f, 0x7e, 0xdb, 0x76, 0xfc, 0x97, 0xa0, 0x22, 0x49, 0x87)
+      // },
+      // TestVector{
+      //   key: [0x48, 0x47, 0x0d, 0xa9, 0x82, 0x28, 0xc9, 0xb5, 0x3f, 0x58, 0x74, 0x76, 0x73, 0x50, 0x4f, 0x74, 0xca, 0x17, 0x37, 0xd7, 0xd4, 0xbb, 0x6d, 0xbf, 0x7c, 0x0c, 0xba, 0x6c, 0xa4, 0x2f, 0x80, 0xb9],
+      //   nonce: [0x56, 0xfb, 0x49, 0x23, 0xa9, 0x7e, 0x93, 0x20],
+      //   plain_text: vec!(0xbc, 0x66, 0x26, 0xd6, 0x51, 0xe2, 0xb2, 0x37, 0xf2, 0x2e, 0xe5, 0x16, 0x08, 0xdd, 0xcf, 0xfe, 0xba, 0x5f, 0x31, 0xc2, 0x6d, 0xf7, 0x2f, 0x44, 0x3f, 0x70, 0x1f, 0x2b, 0x08, 0x5d, 0x6f, 0x34, 0xf8, 0x06, 0xe2, 0x96, 0x73, 0x58, 0x4c, 0xb2, 0x15, 0x22, 0x17, 0x9e, 0xdb, 0x62, 0xa8, 0x24, 0x27, 0xd9, 0x46, 0xac, 0xab, 0xce, 0x06, 0x5b, 0x88, 0xb2, 0x87, 0x8e, 0x9e, 0xb8, 0x7e, 0xd1, 0x00, 0x4e, 0x55, 0xef, 0x58, 0xf5, 0x1e, 0xc4, 0x63, 0x75, 0xac, 0x54, 0x2c, 0x57, 0x82, 0x72, 0x5f, 0xf0, 0x13, 0x13, 0x6c, 0xb5, 0x06, 0xfc, 0xf9, 0x94, 0x96, 0xe1, 0x3f, 0xcd, 0x22, 0x4b, 0x8a, 0x74, 0xa9, 0x71, 0xcc, 0x8d, 0xdb, 0x8b, 0x39, 0x3c, 0xcc, 0x6a, 0xc9, 0x10, 0xbd, 0x19, 0x06, 0xea, 0x9f, 0x2e, 0xd8, 0xa5, 0xd0, 0x66, 0xdc, 0x63, 0x9c, 0x20, 0xcd),
+      //   aad: vec!(0xdf, 0x8a, 0xb6, 0x34, 0xd3, 0xdc, 0xa1, 0x4e, 0x2e, 0x09, 0x1b, 0x15, 0xec, 0xc7, 0x8f, 0x91, 0xe2, 0x29, 0xa1, 0xa1, 0x3c, 0xba, 0x5e, 0xdd, 0x65, 0x26, 0xd1, 0x82, 0x52, 0x5e, 0xc5, 0x75, 0xaa, 0x45, 0xbc, 0x70, 0xfb, 0x61, 0x93, 0xff, 0xcd, 0x59, 0xba, 0xd3, 0xc3, 0x47, 0x15, 0x90, 0x99, 0xc4, 0xf1, 0x39, 0xc3, 0x23, 0xc3, 0x0a, 0x23, 0x07, 0x53, 0xd0, 0x70, 0x01, 0x87, 0x86, 0xb2, 0xe5, 0x9b, 0x75, 0x8d, 0xd4, 0xa9, 0x7d, 0x1a, 0x88, 0xe8, 0xf6, 0x72, 0x09, 0x2b, 0xef, 0x78, 0x0b, 0x45, 0x1f, 0xd6, 0x6b, 0xa7, 0x43, 0x1c, 0xbb, 0x56, 0x60, 0xea, 0x78, 0x16, 0xcd, 0xf2, 0x6e, 0x19, 0xa6, 0xeb, 0xb9, 0xaa, 0xdc, 0x30, 0x88, 0xe6, 0x92, 0x3f, 0x29, 0xf5, 0x3f, 0x87, 0x7a, 0x67, 0x58, 0x06, 0x8f, 0x79, 0xa6, 0xf2, 0xa1, 0x82, 0xb4, 0xbf),
+      //   cipher_text: vec!(0xa6, 0x2e, 0x31, 0x3e, 0xcf, 0x25, 0x8c, 0xc9, 0x08, 0x7c, 0xbb, 0x94, 0xfc, 0xc1, 0x26, 0x43, 0xeb, 0x72, 0x2d, 0x25, 0x5c, 0x3f, 0x98, 0xc3, 0x9f, 0x13, 0x0e, 0x10, 0x05, 0x8a, 0x37, 0x5f, 0x08, 0x09, 0x66, 0x24, 0x42, 0xc7, 0xb1, 0x80, 0x44, 0xfe, 0xb1, 0x60, 0x2d, 0x89, 0xbe, 0x40, 0xfa, 0xca, 0xe8, 0xe8, 0x9c, 0xa9, 0x67, 0x01, 0x5f, 0x0b, 0x7f, 0x8c, 0x2e, 0x4e, 0x4a, 0x38, 0x55, 0xdb, 0xb4, 0x6a, 0x06, 0x6e, 0x49, 0xab, 0xf9, 0xce, 0xf6, 0x7e, 0x60, 0x36, 0x40, 0x0c, 0x8f, 0xf4, 0x6b, 0x24, 0x1f, 0xc9, 0x9b, 0xa1, 0x97, 0x4b, 0xa3, 0xba, 0x6e, 0xa2, 0x0d, 0xc5, 0x2e, 0xc6, 0x75, 0x3f, 0x6f, 0xc7, 0x69, 0x7a, 0xdb, 0xcc, 0xd0, 0x2b, 0x0b, 0xbe, 0xa1, 0xdf, 0x83, 0x52, 0x62, 0x9b, 0x03, 0xb4, 0x3c, 0xc3, 0xd6, 0x32, 0x57, 0x67, 0x87),
+      //   tag: vec!(0x67, 0x52, 0x87, 0xf8, 0x14, 0x3b, 0x9b, 0x97, 0x6e, 0x50, 0xa8, 0x0f, 0x85, 0x31, 0xbd, 0x39)
+      // },
+      // TestVector{
+      //   key: [0xb6, 0x2f, 0xb8, 0x5c, 0x1d, 0xec, 0xd0, 0xfa, 0xf2, 0x42, 0xce, 0x66, 0x21, 0x40, 0xad, 0x1b, 0x82, 0x97, 0x5e, 0x99, 0xa3, 0xfa, 0x01, 0x66, 0x6c, 0xac, 0x23, 0x85, 0xab, 0x91, 0xda, 0x54],
+      //   nonce: [0x2f, 0x4a, 0x5c, 0xa0, 0x96, 0xa4, 0xfa, 0xf8],
+      //   plain_text: vec!(0x03, 0xb1, 0x4f, 0x13, 0xc0, 0x06, 0x5e, 0x4a, 0x44, 0x21, 0xde, 0x62, 0xab, 0x1d, 0x84, 0x2b, 0xff, 0xb8, 0x0f, 0x3d, 0xa3, 0x0b, 0xf4, 0x7d, 0x11, 0x5c, 0x09, 0x85, 0x7f, 0x5b, 0xdd, 0x57, 0x56, 0xfd, 0x7c, 0x9a, 0xc3, 0xd9, 0xaf, 0x1c, 0x9f, 0xb9, 0x4f, 0x26, 0x40, 0xf7, 0xf4, 0x38, 0x6c, 0xfb, 0xa7, 0x4d, 0xb4, 0x68, 0xe5, 0x28, 0x8d, 0xbe, 0x4d, 0xd7, 0x8b, 0xfe, 0x4f, 0x69, 0xe4, 0x14, 0x80, 0xca, 0x61, 0x38, 0xe8, 0xbe, 0xac, 0xc6, 0xea, 0xa3, 0x37, 0x41, 0x57, 0xc7, 0x13, 0xcf, 0xa9, 0x00, 0xc0, 0x7d, 0xd8, 0x36, 0xea, 0xec, 0xc8, 0x82, 0x7f, 0xa3, 0xe7, 0x0e, 0x05, 0x2a, 0xe0, 0x9e, 0x84, 0x73, 0xe2, 0xae, 0x1a, 0x10, 0xb1, 0xbb, 0x66, 0x9e, 0xf6, 0x0a, 0x8d, 0xd9, 0x57, 0xf6, 0x55, 0x3d, 0xaa, 0x81, 0x14, 0x91, 0x8e, 0x17, 0x37, 0x1f, 0x2a, 0xc3, 0x27, 0xbd),
+      //   aad: vec!(0xcf, 0xe3, 0xb7, 0xab, 0x75, 0x50, 0xb0, 0xe8, 0xe2, 0xe8, 0x23, 0x5f, 0xa0, 0xdc, 0xef, 0x95, 0x64, 0x7c, 0xe6, 0x81, 0x4a, 0xbd, 0x3d, 0xc3, 0xf5, 0xa3, 0xbd, 0x7d, 0x6d, 0x28, 0x25, 0x04, 0x66, 0x0c, 0x34, 0xad, 0x83, 0x41, 0xe4, 0xd1, 0x14, 0x02, 0xc7, 0xd4, 0x6c, 0x83, 0xa4, 0x94, 0xd7, 0xdd, 0xb1, 0x05, 0xe1, 0x00, 0x29, 0x79, 0x02, 0x3e, 0x0e, 0x3d, 0xc2, 0x97, 0x8c, 0x9a, 0xe5, 0x3e, 0x10, 0xeb, 0x85, 0x67, 0xe7, 0xa0, 0x2b, 0x60, 0xe5, 0x1e, 0x94, 0x5c, 0x70, 0x40, 0xd8, 0x32, 0xca, 0x90, 0x0d, 0x13, 0x2b, 0x42, 0x05, 0xa3, 0x50, 0x34, 0xfe, 0xd9, 0x39, 0xa1, 0xb7, 0x96, 0x51, 0x83, 0xc2, 0x56, 0x54, 0x93, 0x1a, 0x9b, 0x74, 0x44, 0x01, 0xc4, 0x64, 0x9c, 0x94, 0x57, 0x10, 0xb0, 0xd9, 0x73, 0x3b, 0x87, 0x45, 0x13, 0x48, 0xb3, 0x2b, 0xa8, 0x1d, 0xe3, 0x0e, 0xa7),
+      //   cipher_text: vec!(0x89, 0x65, 0xdb, 0x3d, 0x3a, 0xe4, 0xfb, 0x48, 0x32, 0x08, 0xf1, 0x47, 0x27, 0x6e, 0x7d, 0x81, 0xb7, 0x1a, 0x86, 0xe7, 0x20, 0x2f, 0xfc, 0x9b, 0x1e, 0xaa, 0xde, 0x00, 0x9b, 0xc0, 0x16, 0x83, 0x8d, 0xc0, 0x9c, 0xa4, 0xbc, 0xf3, 0x08, 0x87, 0xb2, 0xf4, 0x24, 0x3f, 0xbd, 0x65, 0x2c, 0xd9, 0x0e, 0xbe, 0xd1, 0xce, 0xef, 0x81, 0x51, 0xff, 0x17, 0xea, 0x70, 0x51, 0x8d, 0x03, 0xb0, 0xf2, 0xa2, 0x49, 0x60, 0xaa, 0x7d, 0xe9, 0xb3, 0x0f, 0xa6, 0x5c, 0x2e, 0x2d, 0x57, 0x36, 0x00, 0x61, 0xaa, 0xe6, 0xd9, 0x37, 0x6e, 0x98, 0x4e, 0x9f, 0xcd, 0x5e, 0x5d, 0xd0, 0x91, 0x1a, 0x4b, 0xc8, 0xde, 0xca, 0x83, 0x2f, 0xfb, 0x76, 0xf2, 0x52, 0xbd, 0x7d, 0xa5, 0x23, 0x07, 0x65, 0x93, 0xba, 0x6b, 0x17, 0x4f, 0x7d, 0x9f, 0xb0, 0x37, 0x7e, 0x06, 0x6e, 0xcb, 0xb6, 0x63, 0x80, 0x36, 0x24, 0x1e, 0x86),
+      //   tag: vec!(0x3d, 0x0f, 0xc5, 0x3e, 0x90, 0x58, 0xc2, 0xbe, 0x32, 0xaa, 0x08, 0x50, 0xe0, 0xfa, 0xb5, 0xa6)
+      // },
+      // TestVector{
+      //   key: [0xde, 0x9c, 0x65, 0x72, 0x58, 0x77, 0x4d, 0x4e, 0xbc, 0x09, 0xd1, 0x09, 0xa0, 0xfc, 0x79, 0xd6, 0x64, 0x93, 0xae, 0x57, 0x87, 0x97, 0xca, 0xc4, 0xeb, 0x88, 0x30, 0xa6, 0xa4, 0xb5, 0x47, 0xe0],
+      //   nonce: [0xb5, 0xe3, 0x5f, 0xe3, 0x39, 0x8e, 0xfa, 0x34],
+      //   plain_text: vec!(0x4d, 0x68, 0xfb, 0x68, 0x3a, 0xa4, 0xf4, 0xc7, 0xa1, 0x6b, 0xa1, 0x11, 0x4f, 0xc0, 0xb1, 0xb8, 0xd8, 0x89, 0x86, 0x10, 0xfa, 0x27, 0x63, 0xe4, 0x35, 0xde, 0xd8, 0x77, 0x1b, 0x36, 0x51, 0x07, 0x8b, 0xef, 0x73, 0xd4, 0xdf, 0xd1, 0x4e, 0x76, 0xa3, 0x4c, 0xd5, 0xeb, 0x9e, 0xf4, 0xdb, 0x4e, 0xad, 0x4d, 0xa9, 0xe8, 0x3f, 0x4c, 0xe5, 0x0f, 0xe0, 0x59, 0x97, 0x7b, 0x2d, 0x17, 0xd6, 0x87, 0xc2, 0x93, 0x35, 0xa0, 0x4d, 0x87, 0x38, 0x9d, 0x21, 0x1f, 0x82, 0x15, 0x44, 0x97, 0x49, 0x96, 0x9f, 0x76, 0x52, 0xdc, 0x19, 0x35, 0xa0, 0xf9, 0xa9, 0x45, 0x38, 0xdc, 0x81, 0xdc, 0x9a, 0x39, 0xaf, 0x63, 0x44, 0x6a, 0x65, 0x17, 0x60, 0x90, 0x76, 0x98, 0x79, 0x20, 0x54, 0x7d, 0x00, 0x98, 0xa9, 0xc6, 0x76, 0x6c, 0xf5, 0xe7, 0x04, 0x88, 0x3e, 0xa3, 0x2f, 0xea, 0xea, 0x18, 0x89, 0xb1, 0x55, 0x4b, 0x5e, 0xb0, 0xce, 0x5e, 0xcc),
+      //   aad: vec!(0x43, 0x6e, 0xa5, 0xa5, 0xfe, 0xe8, 0x29, 0x3b, 0x93, 0xe4, 0xe8, 0x48, 0x81, 0x16, 0xc9, 0x4d, 0x32, 0x69, 0xc1, 0x9f, 0x1d, 0x50, 0x50, 0xde, 0xf2, 0x3d, 0x28, 0x05, 0x15, 0x45, 0x7b, 0x93, 0x1b, 0xbe, 0xd6, 0x4a, 0x54, 0x2b, 0x31, 0x7c, 0xc5, 0x02, 0x3d, 0x64, 0x83, 0x30, 0xa4, 0xb7, 0xad, 0xca, 0x14, 0xdd, 0x6f, 0x37, 0x83, 0x20, 0x7b, 0x94, 0xf8, 0x6c, 0xca, 0xa0, 0xa0, 0xac, 0x39, 0xb7, 0xdb, 0x00, 0xac, 0x87, 0xa9, 0x9e, 0x3c, 0xd8, 0xa7, 0x64, 0xed, 0x9c, 0x75, 0xda, 0x84, 0x54, 0x47, 0x96, 0x36, 0xab, 0x2b, 0x29, 0xe7, 0x70, 0xb1, 0x66, 0xa5, 0xb7, 0x5c, 0xac, 0xc4, 0x25, 0xc9, 0x19, 0xbf, 0x1c, 0xe9, 0xac, 0x34, 0xaf, 0xe6, 0xb4, 0x42, 0x5c, 0x3d, 0x9f, 0xd2, 0xe4, 0x8b, 0xc8, 0x1e, 0x7d, 0x15, 0x51, 0x6d, 0x60, 0xe5, 0x92, 0xbf, 0xcc, 0x2e, 0xbe, 0xfb, 0x66, 0x0f, 0x09, 0x95, 0xf2, 0xb5),
+      //   cipher_text: vec!(0x97, 0xa9, 0x7b, 0x8f, 0x0f, 0x54, 0x20, 0x84, 0x5a, 0xe8, 0xd5, 0x75, 0x67, 0xf9, 0xbb, 0xa6, 0x93, 0xd3, 0x0e, 0x6d, 0xb9, 0x16, 0xfa, 0xd0, 0xb9, 0x71, 0xf5, 0x53, 0xad, 0x7d, 0x99, 0x3f, 0x80, 0x6f, 0x27, 0xab, 0x8b, 0x45, 0x8d, 0x80, 0x46, 0x06, 0x2c, 0xed, 0x47, 0x78, 0xc0, 0x04, 0xb4, 0xf9, 0x58, 0xa4, 0x43, 0x61, 0x41, 0x63, 0x7c, 0x60, 0x39, 0x96, 0x33, 0x08, 0xde, 0xa2, 0xf5, 0x40, 0x08, 0xb7, 0xfe, 0xab, 0x79, 0x65, 0x02, 0x95, 0xed, 0x41, 0xbf, 0x9e, 0x65, 0xe1, 0xa2, 0xd7, 0x5a, 0xb1, 0xc7, 0xb2, 0xa7, 0x0e, 0xbb, 0x9e, 0x9f, 0x38, 0xd0, 0x7a, 0x9a, 0x67, 0x2d, 0x3e, 0x95, 0xea, 0x78, 0xaf, 0xe9, 0xac, 0x02, 0xf2, 0x56, 0x6b, 0x48, 0xb0, 0x25, 0x1a, 0xef, 0x6e, 0xee, 0xca, 0x8b, 0xd1, 0x5b, 0xd8, 0xd4, 0x3b, 0x55, 0x94, 0x26, 0xaa, 0x9d, 0x15, 0xd9, 0x60, 0xee, 0x35, 0xcb, 0x3e, 0xdf),
+      //   tag: vec!(0xe5, 0x5d, 0xbb, 0x21, 0x85, 0x1e, 0x8a, 0x5b, 0x36, 0x5f, 0x86, 0xd0, 0x25, 0x18, 0x33, 0x1c)
+      // },
+      // TestVector{
+      //   key: [0x68, 0x85, 0xbd, 0x33, 0x3c, 0x33, 0x6c, 0x76, 0x72, 0xdb, 0x8e, 0xbd, 0xf2, 0x4c, 0x1a, 0x1b, 0x60, 0x5c, 0x5a, 0x4a, 0xe2, 0x79, 0xf0, 0xf6, 0x98, 0x16, 0x2f, 0x47, 0xe6, 0xc7, 0x34, 0x01],
+      //   nonce: [0xf0, 0xc4, 0xa2, 0x13, 0xa6, 0x16, 0x8a, 0xab],
+      //   plain_text: vec!(0xfa, 0x90, 0x5a, 0x2b, 0xfa, 0x5b, 0x5b, 0xad, 0x76, 0x72, 0x39, 0xfb, 0x07, 0x0a, 0x7b, 0xc0, 0xb3, 0x03, 0xd1, 0x50, 0x3e, 0xcd, 0x2b, 0x42, 0x94, 0x18, 0xcc, 0x8f, 0xeb, 0xa8, 0x43, 0xe5, 0x44, 0x4e, 0xd8, 0x90, 0x22, 0xfd, 0xb3, 0x79, 0xc3, 0xb1, 0x55, 0xa0, 0xf9, 0xce, 0xab, 0x29, 0x79, 0x00, 0x0a, 0x0f, 0x60, 0x29, 0x2a, 0x63, 0x17, 0x71, 0xf2, 0xfd, 0xe4, 0xef, 0x06, 0x5a, 0xa7, 0x46, 0x42, 0x66, 0x09, 0x08, 0x29, 0x69, 0x53, 0x0a, 0x9c, 0x70, 0xad, 0x14, 0x53, 0x08, 0xc3, 0x0b, 0xa3, 0x89, 0xea, 0x12, 0x2f, 0xd7, 0x66, 0x08, 0x15, 0x11, 0xa0, 0x31, 0xce, 0x3a, 0x0b, 0xd9, 0xf9, 0xf5, 0x83, 0xc7, 0x00, 0x0b, 0x33, 0x3b, 0x79, 0xac, 0x00, 0x4f, 0xbd, 0xe6, 0xec, 0x3e, 0xb2, 0xd9, 0x05, 0x97, 0x7f, 0xf9, 0x5d, 0xcf, 0xf7, 0x78, 0x58, 0xe3, 0xc4, 0x24, 0xfe, 0x89, 0x32, 0xa6, 0xa1, 0x21, 0x39, 0xe6, 0xec, 0x8d, 0x5e, 0x98),
+      //   aad: vec!(0x8d, 0xed, 0x36, 0x8f, 0x91, 0x9e, 0xfb, 0x52, 0x2b, 0xb6, 0xa9, 0xad, 0x00, 0x9e, 0x02, 0xff, 0xbc, 0x6a, 0x16, 0x53, 0x6e, 0x34, 0xd9, 0x5c, 0xdb, 0x34, 0xf1, 0x15, 0x3d, 0x7c, 0xb7, 0xb0, 0xf3, 0xc2, 0xb1, 0x3d, 0xd0, 0x5c, 0xed, 0xae, 0x27, 0xcf, 0xe6, 0x8e, 0xc3, 0xac, 0xa8, 0x04, 0x7e, 0x09, 0x30, 0xa2, 0x9c, 0x9d, 0x07, 0x70, 0xc1, 0xb8, 0x3c, 0x23, 0x4d, 0xcb, 0x03, 0x85, 0xde, 0xae, 0x7a, 0xe8, 0x5d, 0xa7, 0x3a, 0x5f, 0x8d, 0xe3, 0xdf, 0xb2, 0x86, 0x12, 0xa0, 0x01, 0xf4, 0xe5, 0x52, 0xc4, 0xf6, 0x7a, 0xe0, 0xe2, 0xec, 0x53, 0x85, 0x32, 0x89, 0xb7, 0x01, 0x7a, 0x58, 0x59, 0x1f, 0xd6, 0xf7, 0x0b, 0x0e, 0x95, 0x48, 0x76, 0xbb, 0x2f, 0x7e, 0xc3, 0x30, 0x01, 0xe2, 0x98, 0x85, 0x6a, 0x64, 0xbb, 0x16, 0x18, 0x10, 0x17, 0xba, 0x92, 0x46, 0x48, 0xc0, 0x9f, 0xc6, 0x3c, 0x62, 0xef, 0xf2, 0x62, 0xc8, 0x0d, 0x61, 0x46, 0x79, 0xbd),
+      //   cipher_text: vec!(0x0c, 0xb3, 0xd6, 0xc3, 0x1e, 0x0f, 0x40, 0x29, 0xec, 0xa5, 0x52, 0x4f, 0x95, 0x12, 0x44, 0xdf, 0x04, 0x2f, 0xc6, 0x37, 0xc4, 0x16, 0x25, 0x11, 0xfe, 0xa5, 0x12, 0xa5, 0x2d, 0x3f, 0x75, 0x81, 0xaf, 0x09, 0x7e, 0xb6, 0x42, 0xe7, 0x9e, 0x48, 0x66, 0x6c, 0xb1, 0x08, 0x6e, 0xdb, 0xd3, 0x8c, 0x47, 0x77, 0xc5, 0x35, 0xa2, 0x09, 0x45, 0xfa, 0xbc, 0x23, 0xe7, 0xc9, 0x27, 0x7e, 0x2b, 0x96, 0x0a, 0xac, 0x46, 0x86, 0x5f, 0x10, 0x26, 0xeb, 0x6d, 0xa8, 0x27, 0x59, 0x10, 0x8b, 0x9b, 0xae, 0xce, 0x5d, 0xa9, 0x30, 0xcc, 0xfc, 0x10, 0x52, 0xb1, 0x65, 0x6b, 0x0e, 0xad, 0xaa, 0x12, 0x0e, 0xd0, 0xc4, 0x5a, 0xd0, 0x4b, 0x24, 0xae, 0x8c, 0xdb, 0x22, 0xce, 0xab, 0x76, 0xc5, 0xf1, 0x80, 0xb4, 0x6a, 0x39, 0x2a, 0xb4, 0x5b, 0x1b, 0x99, 0xc6, 0x12, 0x54, 0x6e, 0x6b, 0x94, 0x7f, 0x4d, 0x5c, 0x06, 0xad, 0x5a, 0xbe, 0xe9, 0x2f, 0xf9, 0x63, 0x45, 0xad, 0x43),
+      //   tag: vec!(0xd3, 0xb5, 0x41, 0xac, 0x44, 0x6c, 0x84, 0x62, 0x6d, 0xaf, 0x80, 0x0c, 0x01, 0x72, 0xee, 0xc6)
+      // },
+      // TestVector{
+      //   key: [0xfb, 0xc9, 0x78, 0xab, 0xb1, 0x24, 0x0a, 0x69, 0x37, 0xcc, 0xc1, 0x67, 0x35, 0xb8, 0xd6, 0xed, 0x54, 0x11, 0xcd, 0xbc, 0x18, 0x97, 0x21, 0x41, 0x65, 0xa1, 0x74, 0xe1, 0x6f, 0x4e, 0x69, 0x9b],
+      //   nonce: [0x79, 0x68, 0x37, 0x9a, 0x8c, 0xe8, 0x81, 0x17],
+      //   plain_text: vec!(0x1a, 0x81, 0x96, 0xcd, 0x4a, 0x13, 0x89, 0xec, 0x91, 0x6e, 0xf8, 0xb7, 0xda, 0x50, 0x78, 0xa2, 0xaf, 0xa8, 0xe9, 0xf1, 0x08, 0x12, 0x23, 0xfa, 0x72, 0xf6, 0x52, 0x4a, 0xc0, 0xa1, 0xa8, 0x01, 0x9e, 0x44, 0xa0, 0x95, 0x63, 0xa9, 0x53, 0x61, 0x55, 0x87, 0x42, 0x92, 0x95, 0x05, 0x2c, 0xc9, 0x04, 0xb8, 0x9f, 0x77, 0x8e, 0xf4, 0x46, 0xed, 0x34, 0x14, 0x30, 0xd7, 0xd8, 0xf7, 0x47, 0xcf, 0x2d, 0xb4, 0x30, 0x84, 0x78, 0x52, 0x46, 0x39, 0xf4, 0x44, 0x57, 0x25, 0x3a, 0xe5, 0xa4, 0x45, 0x1c, 0x7e, 0xfc, 0xa8, 0xae, 0x0b, 0x6c, 0x5c, 0x05, 0x1a, 0xaa, 0x78, 0x1e, 0x9c, 0x50, 0x54, 0x89, 0xb3, 0x81, 0xa6, 0xdc, 0xba, 0x87, 0xb1, 0x57, 0xed, 0xc7, 0xf8, 0x20, 0xa8, 0xfb, 0xaf, 0x2a, 0x52, 0xe4, 0x84, 0xdc, 0x12, 0x1f, 0x33, 0xd9, 0xd8, 0xb9, 0xac, 0x59, 0xd4, 0x90, 0x1d, 0x6e, 0xd8, 0x99, 0x6e, 0xd4, 0xf6, 0x2d, 0x9d, 0x4d, 0x82, 0x27, 0x4c, 0x44, 0x9c, 0xd7, 0x4e, 0xfa),
+      //   aad: vec!(0x39, 0x13, 0xcd, 0x01, 0x29, 0x9b, 0x8a, 0x4e, 0x50, 0x7f, 0x06, 0x7d, 0x88, 0x7d, 0x7e, 0x9a, 0x6d, 0xed, 0x16, 0xdd, 0x9f, 0x9b, 0xb3, 0x11, 0x5c, 0x57, 0x79, 0xaa, 0x14, 0x23, 0x9f, 0xd3, 0x3e, 0xe9, 0xf2, 0x57, 0x56, 0xd4, 0x52, 0x62, 0xdc, 0x30, 0x11, 0x06, 0x93, 0x56, 0x42, 0x5b, 0x5c, 0x81, 0xa4, 0x72, 0x95, 0x94, 0xe1, 0x7c, 0x97, 0x47, 0x11, 0x9f, 0x81, 0x46, 0x3e, 0x85, 0x62, 0x5d, 0x56, 0x03, 0xd0, 0x5e, 0x00, 0xf5, 0x68, 0xb0, 0xc8, 0x00, 0xbb, 0x18, 0x1e, 0xb7, 0x17, 0xbe, 0x8d, 0x7a, 0x93, 0x16, 0x6a, 0x50, 0x4c, 0xe1, 0xbc, 0x81, 0x7e, 0x15, 0x53, 0x0c, 0x5b, 0xd2, 0xb3, 0xdf, 0x1d, 0x42, 0x22, 0x24, 0x5e, 0xa7, 0x8a, 0x38, 0xbc, 0x10, 0xf6, 0x6c, 0x5c, 0xf6, 0x8d, 0x66, 0x15, 0x03, 0x13, 0x1f, 0x11, 0xaf, 0x88, 0x5c, 0x8a, 0x91, 0x0b, 0x6d, 0xce, 0x70, 0xbc, 0x3a, 0x74, 0x48, 0xdf, 0xae, 0x00, 0x59, 0x5b, 0xeb, 0x70, 0x7f, 0xe0, 0x54, 0xd3),
+      //   cipher_text: vec!(0xd1, 0x52, 0xbc, 0xb4, 0xc2, 0x4c, 0x37, 0x11, 0xb0, 0xfa, 0xd2, 0x85, 0x48, 0xdc, 0x4d, 0xb6, 0x05, 0xbb, 0xc8, 0x92, 0x37, 0xcd, 0xbe, 0xa7, 0xdb, 0xf9, 0x56, 0xb8, 0x85, 0x5d, 0x11, 0x61, 0xa0, 0x78, 0x1f, 0x27, 0xbd, 0x56, 0xd7, 0x98, 0x14, 0x1e, 0x2a, 0xce, 0x33, 0x99, 0x55, 0xef, 0xb9, 0x8f, 0xe0, 0x5d, 0x9b, 0x44, 0xcd, 0x01, 0x1e, 0x64, 0x51, 0x06, 0xbf, 0x47, 0x72, 0x61, 0x83, 0x95, 0x8c, 0xb6, 0xdf, 0x34, 0xce, 0x57, 0x66, 0x69, 0x5f, 0x60, 0xbc, 0x70, 0xb6, 0xfe, 0x0f, 0xab, 0xb9, 0xaf, 0xa0, 0x09, 0xa8, 0xef, 0x04, 0x3d, 0xbf, 0x75, 0xf8, 0x61, 0x88, 0x13, 0x68, 0xfa, 0x07, 0x72, 0x66, 0x25, 0x44, 0x8f, 0xe6, 0x08, 0xd5, 0x78, 0xcd, 0xc4, 0x82, 0x77, 0xf2, 0xdc, 0x53, 0xea, 0xaf, 0x1b, 0xdc, 0x07, 0x52, 0x69, 0xa4, 0x2f, 0x93, 0x02, 0xa5, 0x7c, 0xad, 0x38, 0x7a, 0x82, 0xc6, 0x96, 0x96, 0x08, 0xac, 0xac, 0xda, 0x20, 0xe1, 0xca, 0xc4, 0x59, 0x6c),
+      //   tag: vec!(0x94, 0x5d, 0xca, 0x73, 0xcf, 0x2f, 0x00, 0x7a, 0xe2, 0x43, 0x99, 0x1c, 0x4f, 0xbe, 0x04, 0x79)
+      // },
+      // TestVector{
+      //   key: [0x77, 0xd1, 0xa8, 0x57, 0xfb, 0xad, 0xfe, 0x01, 0xab, 0xa7, 0x97, 0x4e, 0xea, 0x2d, 0xfb, 0x3d, 0xc7, 0xbf, 0x41, 0xde, 0x73, 0x68, 0x6a, 0xec, 0xe4, 0x03, 0x99, 0x3e, 0x50, 0x16, 0xc7, 0x14],
+      //   nonce: [0xfd, 0xd9, 0x13, 0xa3, 0x21, 0xc4, 0x0e, 0xb0],
+      //   plain_text: vec!(0xdb, 0x89, 0x15, 0xbf, 0xe6, 0x51, 0xe2, 0xec, 0xb3, 0xce, 0x0b, 0x27, 0xd9, 0x9a, 0x6b, 0xfa, 0x7a, 0x7c, 0x50, 0x7c, 0xfc, 0xb2, 0x98, 0x72, 0x93, 0x01, 0x86, 0x36, 0xc3, 0x65, 0xa4, 0x59, 0xc6, 0xa1, 0x38, 0xb4, 0x42, 0x8b, 0xe5, 0x38, 0x41, 0x3d, 0xb1, 0x5b, 0xda, 0x69, 0xe6, 0x97, 0xcb, 0xb9, 0x2b, 0x15, 0x4b, 0x7f, 0x4d, 0x2c, 0xbb, 0x07, 0x96, 0x52, 0x25, 0xaa, 0x68, 0x65, 0xd7, 0xdc, 0xd1, 0xba, 0x2c, 0x17, 0xc4, 0x84, 0xb0, 0x0b, 0x19, 0x86, 0xfe, 0xd6, 0x3e, 0x88, 0x9f, 0x25, 0xa4, 0x96, 0x6d, 0xc3, 0xed, 0x42, 0x73, 0xf1, 0x57, 0x77, 0x68, 0xf6, 0x65, 0x36, 0x2d, 0x7d, 0x3e, 0x82, 0x44, 0x84, 0xf0, 0xdd, 0xed, 0x7f, 0x82, 0xb8, 0xbe, 0x87, 0x97, 0xad, 0x95, 0x17, 0x19, 0x71, 0x93, 0x65, 0xe4, 0x5a, 0xbb, 0xf7, 0x63, 0x24, 0xbc, 0x7d, 0x65, 0x77, 0x99, 0xd4, 0xd4, 0xf4, 0xbb, 0x1d, 0xba, 0x67, 0xd9, 0x6a, 0xb1, 0xc8, 0x85, 0x19, 0xa5, 0xbe, 0xe7, 0x04, 0xf7, 0x21, 0x48, 0x14),
+      //   aad: vec!(0x3c, 0xb2, 0xc0, 0x6c, 0x20, 0xcb, 0x08, 0x32, 0xbb, 0xac, 0xeb, 0xfc, 0x20, 0x5d, 0x77, 0x39, 0x3c, 0xa1, 0x81, 0x63, 0x46, 0xea, 0x26, 0x81, 0xde, 0x4d, 0x3a, 0xb1, 0xfa, 0xdb, 0x77, 0x4a, 0xd2, 0x73, 0xe4, 0x71, 0x32, 0x90, 0x45, 0x44, 0x96, 0xf5, 0x28, 0x1e, 0xbc, 0x65, 0xe0, 0x4c, 0xfe, 0x84, 0xed, 0x37, 0xcd, 0x0a, 0xed, 0xc4, 0xbb, 0xe3, 0xde, 0xcb, 0xd8, 0xd7, 0x9d, 0x04, 0xa4, 0xe4, 0x34, 0x87, 0x66, 0x50, 0xe0, 0xd6, 0x43, 0x09, 0xe3, 0x36, 0xbf, 0xb1, 0x0e, 0x92, 0x40, 0x66, 0xa6, 0x4a, 0xcb, 0x92, 0x26, 0x0b, 0x2d, 0xbd, 0x96, 0x73, 0x5d, 0x03, 0xaf, 0x03, 0x90, 0x9a, 0xa6, 0xa8, 0x0a, 0x6e, 0x89, 0xfd, 0xa8, 0x10, 0x37, 0x25, 0x7a, 0xec, 0x21, 0xfe, 0x9b, 0xe7, 0xe9, 0x1a, 0x64, 0xe8, 0x8e, 0x0a, 0x58, 0xfa, 0x38, 0xec, 0xba, 0x4c, 0x4c, 0x4c, 0xff, 0xb6, 0x19, 0x58, 0xf3, 0xc4, 0x86, 0xcb, 0xb0, 0xb1, 0xd0, 0xb0, 0x01, 0x4a, 0x2d, 0x1d, 0x3d, 0xf2, 0x48, 0xee, 0xc1, 0xca),
+      //   cipher_text: vec!(0xac, 0xb8, 0x25, 0xe6, 0x02, 0x3b, 0x44, 0xb0, 0x3b, 0x2e, 0xfc, 0x26, 0x56, 0x03, 0xe8, 0x87, 0x95, 0x4e, 0x86, 0x12, 0xb2, 0xee, 0x13, 0x4b, 0xdc, 0xb6, 0x15, 0x01, 0xcf, 0xb9, 0x49, 0x29, 0x52, 0xbf, 0x67, 0xbe, 0x59, 0x7c, 0x3a, 0x00, 0x5b, 0x09, 0xaf, 0x74, 0xd9, 0xe4, 0x21, 0xa5, 0x76, 0xd2, 0xc6, 0x5e, 0x98, 0x10, 0x47, 0x80, 0xfe, 0xab, 0x83, 0x8d, 0x8c, 0xb1, 0xbd, 0x13, 0x54, 0x52, 0xea, 0x39, 0xdc, 0x89, 0x07, 0xa4, 0xc1, 0xa6, 0xa9, 0x16, 0x18, 0x05, 0xe4, 0xfa, 0x3e, 0x16, 0x98, 0x9e, 0x6a, 0x41, 0x8a, 0x7e, 0xea, 0x25, 0x82, 0xbf, 0x89, 0x5d, 0xa9, 0x67, 0x02, 0x8e, 0xab, 0x7c, 0x95, 0xd8, 0x46, 0xa6, 0xde, 0x4b, 0x99, 0x80, 0x78, 0x58, 0x14, 0xcf, 0x00, 0x48, 0x4b, 0xaa, 0x2f, 0x6d, 0xe6, 0x09, 0x91, 0x2f, 0xff, 0x68, 0x9b, 0xce, 0x6e, 0x85, 0x42, 0x61, 0xff, 0xe8, 0x66, 0xbd, 0x8e, 0x63, 0x27, 0x46, 0x05, 0xc7, 0xc5, 0xad, 0x67, 0x7b, 0xd7, 0x89, 0x7a, 0xde, 0x54, 0x3e),
+      //   tag: vec!(0x93, 0x84, 0x78, 0xa4, 0x1a, 0x32, 0x23, 0xa2, 0x19, 0x9f, 0x92, 0x76, 0xd1, 0x16, 0x21, 0x0f)
+      // },
+      // TestVector{
+      //   key: [0xb7, 0xe9, 0xb9, 0x0d, 0xc0, 0x2b, 0x5c, 0xd6, 0xdf, 0x5d, 0xf7, 0x28, 0x3e, 0xf2, 0x93, 0xed, 0x4d, 0xc0, 0x75, 0x13, 0xd9, 0xe6, 0x73, 0x31, 0xb6, 0x06, 0xf4, 0xd4, 0x2d, 0xec, 0x7d, 0x29],
+      //   nonce: [0xa6, 0xc1, 0x91, 0xf6, 0xd1, 0x81, 0x8f, 0x8e],
+      //   plain_text: vec!(0x2a, 0xda, 0x0e, 0x3c, 0x7c, 0xa6, 0xdb, 0x1f, 0x78, 0x0c, 0xe8, 0xc7, 0x94, 0x72, 0xaf, 0x4e, 0x8e, 0x95, 0x1d, 0xdc, 0x82, 0x8e, 0x0d, 0x6e, 0x8a, 0x67, 0xdf, 0x52, 0x06, 0x38, 0xff, 0x5f, 0x14, 0xa2, 0xf9, 0x5a, 0x5e, 0x59, 0x31, 0x74, 0x9a, 0xe2, 0xc4, 0xe9, 0x94, 0x6a, 0xe4, 0xd5, 0xeb, 0x5d, 0xe4, 0x2f, 0xb5, 0xb7, 0x7d, 0x22, 0x36, 0xe2, 0xe2, 0xbd, 0x81, 0x7d, 0xf5, 0x1b, 0xe4, 0x0b, 0x1b, 0x8a, 0x6c, 0x21, 0x01, 0x5a, 0x7c, 0x79, 0xfe, 0x06, 0xdb, 0xa4, 0xa0, 0x8b, 0x34, 0x01, 0x3d, 0xfa, 0x02, 0x74, 0x7b, 0x5f, 0x03, 0x93, 0x02, 0x68, 0x40, 0x4c, 0x45, 0x5d, 0xc5, 0x4a, 0x74, 0xd9, 0xc6, 0xe3, 0x54, 0x85, 0xe1, 0x00, 0x26, 0xda, 0x57, 0x3c, 0xb4, 0x1c, 0xd5, 0x0b, 0x64, 0xcf, 0xaf, 0xe4, 0xcf, 0xcd, 0xf3, 0xc9, 0x68, 0x4e, 0xf8, 0x77, 0xe4, 0x5d, 0x84, 0xe2, 0x2b, 0xd5, 0xe1, 0x5f, 0xa6, 0xc8, 0xfd, 0x5b, 0xe9, 0x21, 0x36, 0x6f, 0xf0, 0xdc, 0x6f, 0xe2, 0xdf, 0x45, 0xf7, 0x25, 0x29, 0x72, 0xc9, 0xb3, 0x03),
+      //   aad: vec!(0x0f, 0x42, 0x69, 0xed, 0x5e, 0xf0, 0xbf, 0xff, 0x7b, 0xe3, 0x99, 0x46, 0xa4, 0xe8, 0x6e, 0x8b, 0xf7, 0x9f, 0x84, 0xb7, 0x0c, 0xd0, 0xb1, 0x4f, 0xec, 0xb7, 0xbe, 0x3c, 0x07, 0x13, 0x16, 0xce, 0x86, 0xde, 0x3d, 0x99, 0xd6, 0x87, 0x1e, 0x0b, 0xa5, 0x66, 0x7d, 0x9d, 0x7b, 0xba, 0x7d, 0xca, 0xba, 0x10, 0xcb, 0x2a, 0x36, 0x66, 0x8b, 0x6c, 0x3e, 0x2f, 0xb6, 0xc1, 0x02, 0x93, 0x8b, 0x75, 0x00, 0x8b, 0xb9, 0xc2, 0x13, 0xeb, 0xf9, 0xb8, 0x5b, 0x5e, 0x91, 0xa8, 0x02, 0xdf, 0x0d, 0x31, 0xd7, 0xf1, 0x1d, 0x76, 0x4b, 0x22, 0x89, 0xf6, 0x22, 0x52, 0x12, 0x69, 0x4a, 0xb6, 0xb7, 0xc0, 0xe3, 0xff, 0x36, 0xe8, 0x42, 0x45, 0xd9, 0xf4, 0xf4, 0x3f, 0xc5, 0xf9, 0x8e, 0x65, 0x4d, 0xea, 0x7b, 0xa9, 0xbd, 0x91, 0x86, 0x58, 0x87, 0x9c, 0x5b, 0xb4, 0xa1, 0x64, 0x2a, 0xf0, 0xd8, 0x31, 0x13, 0xe3, 0xcf, 0x93, 0x5d, 0x3c, 0x0d, 0x52, 0x08, 0x31, 0x8f, 0x66, 0xf6, 0x54, 0xeb, 0x17, 0xd8, 0xc2, 0x8a, 0x60, 0x25, 0x43, 0xe7, 0x7a, 0xd3, 0xe8, 0x15),
+      //   cipher_text: vec!(0x22, 0x58, 0x6f, 0xe7, 0x33, 0x8e, 0x99, 0xcd, 0xaa, 0xd9, 0xf8, 0x5b, 0xd7, 0x24, 0xba, 0x4c, 0xfe, 0x62, 0x49, 0xb8, 0xa7, 0x13, 0x99, 0xf9, 0xa3, 0x70, 0x7b, 0x5c, 0x43, 0x23, 0xb8, 0xd9, 0x66, 0x79, 0x56, 0x8d, 0xfc, 0x8d, 0x23, 0x0a, 0xef, 0xb4, 0x53, 0xdf, 0x59, 0x6e, 0x13, 0xeb, 0x3e, 0x8a, 0x43, 0x92, 0x49, 0xbd, 0x64, 0xbc, 0x93, 0xa5, 0x8f, 0x95, 0x08, 0x9a, 0x62, 0xb9, 0x4f, 0x65, 0x62, 0xb8, 0x21, 0xc8, 0x3d, 0x91, 0xf5, 0x6c, 0x55, 0x14, 0x73, 0x81, 0xe9, 0xde, 0x4b, 0xeb, 0x4a, 0xe8, 0x1b, 0xd6, 0xfe, 0x7c, 0xae, 0xf7, 0xe7, 0xe9, 0xa2, 0x07, 0x8f, 0x2f, 0xba, 0x8f, 0x3e, 0x70, 0xd4, 0x91, 0x0d, 0xa9, 0xac, 0xcc, 0x92, 0xb8, 0xe8, 0x1a, 0x61, 0xb0, 0xfe, 0xfb, 0xec, 0xe4, 0xbd, 0x89, 0x44, 0x3e, 0x66, 0xe8, 0xdd, 0xda, 0x8e, 0x47, 0xa6, 0x6a, 0x62, 0xf1, 0x7f, 0xd0, 0xe7, 0xd0, 0xa4, 0x85, 0x2c, 0xe1, 0xa4, 0xd4, 0x3d, 0x72, 0xa0, 0xb5, 0xe8, 0x91, 0x4b, 0xbe, 0xc6, 0x98, 0xf0, 0x60, 0xf2, 0xb0, 0x92),
+      //   tag: vec!(0xc0, 0x82, 0x47, 0x02, 0x97, 0xda, 0x8c, 0x5f, 0x68, 0x2a, 0x16, 0x9d, 0x28, 0xbc, 0x02, 0x39)
+      // },
+      // TestVector{
+      //   key: [0x6b, 0x2c, 0xb2, 0x67, 0x8d, 0x11, 0x02, 0xf2, 0xfb, 0xbd, 0x02, 0x87, 0x94, 0xa7, 0x9f, 0x14, 0x58, 0x5c, 0x22, 0x3d, 0x40, 0x5e, 0x1a, 0xe9, 0x04, 0xc0, 0x36, 0x1e, 0x9b, 0x24, 0x1e, 0x99],
+      //   nonce: [0x7b, 0x3a, 0xe3, 0x1f, 0x8f, 0x93, 0x82, 0x51],
+      //   plain_text: vec!(0xb3, 0xcb, 0x74, 0x59, 0x30, 0xe0, 0x5f, 0x3a, 0xb8, 0xc9, 0x26, 0xc0, 0xa3, 0x43, 0xa6, 0xeb, 0x14, 0x80, 0x9f, 0xd2, 0x1b, 0x83, 0x90, 0xa6, 0xfc, 0xc5, 0x8a, 0xdb, 0x55, 0x79, 0xe5, 0x43, 0x20, 0x21, 0x76, 0x5b, 0x2d, 0x24, 0x9a, 0x0e, 0xcf, 0x6b, 0xa6, 0x78, 0x63, 0x4c, 0x4f, 0x53, 0xf7, 0x14, 0x95, 0x86, 0x5f, 0x03, 0x1e, 0xe9, 0x7a, 0xa1, 0x59, 0xf9, 0xea, 0xd3, 0xa3, 0xfc, 0xb8, 0x23, 0xee, 0x52, 0x38, 0xbd, 0xf1, 0x27, 0x06, 0xa9, 0xc6, 0x13, 0x7d, 0x23, 0x6e, 0x2e, 0x71, 0x10, 0xce, 0x65, 0x0c, 0x32, 0x1e, 0x41, 0xda, 0xf0, 0xaf, 0xd6, 0x2b, 0xab, 0x2a, 0x8f, 0xe5, 0x5d, 0x70, 0x18, 0xde, 0x49, 0xa1, 0x4e, 0xfe, 0x6d, 0x83, 0xa1, 0x5b, 0x2f, 0x25, 0x6d, 0x59, 0x5e, 0x99, 0x8d, 0x25, 0x30, 0x9f, 0x23, 0x63, 0x33, 0x60, 0xf5, 0x74, 0x5c, 0x50, 0xc4, 0xe5, 0xaf, 0x8c, 0xcc, 0x9a, 0x8a, 0x2c, 0xb4, 0x70, 0x64, 0x10, 0x5a, 0x02, 0x3e, 0x91, 0x9c, 0x77, 0x95, 0xd2, 0xdc, 0x33, 0x1d, 0x3f, 0x2a, 0xfb, 0x8c, 0x42, 0xe5, 0xc0, 0xbc, 0xc2, 0x6d),
+      //   aad: vec!(0x1c, 0x32, 0xfd, 0x3d, 0xf2, 0x2b, 0x3e, 0x44, 0x0e, 0x2a, 0x3c, 0x7a, 0x76, 0x24, 0x99, 0x01, 0x94, 0xcb, 0x16, 0xa5, 0xf7, 0x4a, 0xf3, 0x6f, 0x87, 0xfd, 0x6c, 0xa7, 0xd4, 0x10, 0xce, 0x90, 0x64, 0x31, 0x6a, 0x2d, 0x09, 0x19, 0x45, 0xde, 0xef, 0x7d, 0x9b, 0x35, 0xce, 0xec, 0x83, 0x96, 0x06, 0x93, 0x07, 0xca, 0xce, 0xd2, 0xb8, 0x0a, 0xfd, 0x7d, 0x53, 0xec, 0x47, 0x9c, 0x35, 0xce, 0xdf, 0x2d, 0xfd, 0x4c, 0x95, 0xc3, 0xdd, 0x84, 0x00, 0xf7, 0x1a, 0xd3, 0x40, 0x28, 0xc6, 0xe4, 0xf8, 0x68, 0x1d, 0x93, 0xd0, 0x77, 0x40, 0x64, 0xba, 0x38, 0xf3, 0xfb, 0x9b, 0x0c, 0x1d, 0xfa, 0x1f, 0x5f, 0x0c, 0x7d, 0x20, 0x67, 0x6a, 0x59, 0x11, 0xd9, 0x99, 0xfb, 0x6a, 0x1d, 0x41, 0x36, 0x7a, 0x8e, 0x99, 0xd8, 0x52, 0xbf, 0x3d, 0x3b, 0x7b, 0x3f, 0x4c, 0x23, 0x32, 0x49, 0xed, 0x1c, 0xa1, 0x35, 0x38, 0x9a, 0x67, 0x4f, 0xf4, 0x82, 0x32, 0xde, 0xd3, 0xf6, 0x80, 0x0a, 0x97, 0xb6, 0xd4, 0x09, 0xc4, 0x0e, 0x6c, 0xd7, 0x0d, 0x09, 0xbf, 0x9d, 0x2a, 0xd2, 0x5d, 0x9b, 0x94, 0x85),
+      //   cipher_text: vec!(0xef, 0x70, 0xc7, 0xde, 0x98, 0xab, 0x1d, 0x4a, 0xd8, 0x17, 0x02, 0x4a, 0x97, 0x0b, 0xe4, 0x63, 0x44, 0x36, 0x40, 0xeb, 0x0c, 0xd7, 0xff, 0x23, 0x4b, 0xdd, 0x00, 0xe6, 0x53, 0x07, 0x4a, 0x77, 0xa1, 0xd5, 0x74, 0x9e, 0x69, 0x8b, 0xd5, 0x26, 0xdc, 0x70, 0x9f, 0x82, 0xdf, 0x06, 0xf4, 0xc0, 0xe6, 0x40, 0x46, 0xb3, 0xdc, 0x5f, 0x3c, 0x70, 0x44, 0xae, 0xf5, 0x3a, 0xeb, 0xb8, 0x07, 0xd3, 0x22, 0x39, 0xd0, 0x65, 0x2d, 0xd9, 0x90, 0x36, 0x2c, 0x44, 0xec, 0x25, 0xbf, 0x5a, 0xea, 0xe6, 0x41, 0xe2, 0x7b, 0xf7, 0x16, 0xe0, 0xc4, 0xa1, 0xc9, 0xfb, 0xd3, 0x7b, 0xbf, 0x60, 0x2b, 0xb0, 0xd0, 0xc3, 0x5b, 0x06, 0x38, 0xbe, 0x20, 0xdd, 0x5d, 0x58, 0x91, 0xd4, 0x46, 0x13, 0x7e, 0x84, 0x2f, 0x92, 0xc0, 0xee, 0x07, 0x5c, 0x68, 0x22, 0x5e, 0x4d, 0xba, 0xcb, 0x63, 0xcc, 0x6f, 0xb3, 0x24, 0x42, 0xb4, 0xbc, 0xda, 0x5e, 0x62, 0xcb, 0x50, 0x0a, 0x4d, 0xf2, 0x74, 0x1a, 0x40, 0x59, 0x03, 0x4d, 0x2c, 0xcb, 0x71, 0xb0, 0xb8, 0xb0, 0x11, 0x2b, 0xf1, 0xc4, 0xca, 0x6e, 0xec, 0x74),
+      //   tag: vec!(0x39, 0x3a, 0xe2, 0x33, 0x84, 0x80, 0x34, 0x24, 0x8c, 0x19, 0x1a, 0xc0, 0xe3, 0x6b, 0x61, 0x23)
+      // },
+      // TestVector{
+      //   key: [0x4d, 0xbc, 0x80, 0xa4, 0x02, 0xc9, 0xfc, 0xea, 0xa7, 0x55, 0xe1, 0x10, 0x5d, 0xc4, 0x9e, 0xf6, 0x48, 0x90, 0x16, 0x77, 0x68, 0x83, 0xe0, 0x6f, 0xcf, 0x3a, 0xed, 0x93, 0xbf, 0x7f, 0x6a, 0xf7],
+      //   nonce: [0x23, 0x58, 0xae, 0x0c, 0xe3, 0xfb, 0x8e, 0x9f],
+      //   plain_text: vec!(0x19, 0x7c, 0x06, 0x40, 0x3e, 0xb8, 0x96, 0xd2, 0xfa, 0x64, 0x65, 0xe4, 0xd6, 0x44, 0x26, 0xd2, 0x4c, 0xc7, 0x47, 0x6a, 0xa1, 0xae, 0x41, 0x27, 0xcd, 0x2b, 0xd8, 0xa4, 0x8c, 0xe2, 0xc9, 0x9c, 0x16, 0xb1, 0xcb, 0xf3, 0x06, 0x48, 0x56, 0xe8, 0x40, 0x73, 0xb6, 0xcf, 0x12, 0xe7, 0x40, 0x66, 0x98, 0xef, 0x3d, 0xd1, 0x24, 0x0c, 0x02, 0x6c, 0xbd, 0x1a, 0xb0, 0x4e, 0xe6, 0x03, 0xe1, 0xe6, 0xe7, 0x35, 0xc9, 0xb7, 0x55, 0x1f, 0xd0, 0xd3, 0x55, 0x20, 0x2b, 0x4f, 0x64, 0xb4, 0x82, 0xdd, 0x4a, 0x7c, 0x7d, 0x82, 0xc4, 0xfe, 0x2e, 0xb4, 0x94, 0xd0, 0xd5, 0xe1, 0x77, 0x88, 0x98, 0x2d, 0x70, 0x4c, 0x13, 0x56, 0xc4, 0x1a, 0x94, 0x65, 0x55, 0x30, 0xde, 0xda, 0x23, 0x11, 0x8c, 0xba, 0x28, 0x1d, 0x0f, 0x71, 0x7e, 0x14, 0x9f, 0xbe, 0xb2, 0xc5, 0x9b, 0x22, 0xd0, 0xc0, 0x57, 0x4c, 0x1a, 0x2e, 0x64, 0x0a, 0xfa, 0xd1, 0xa6, 0xce, 0xb9, 0x2e, 0x1b, 0xf1, 0xdd, 0xe7, 0x17, 0x52, 0xa1, 0xc9, 0x91, 0xe9, 0xa5, 0x51, 0x7f, 0xe9, 0x86, 0x88, 0xa1, 0x6b, 0x07, 0x3d, 0xbf, 0x68, 0x84, 0xcf, 0xde, 0x61, 0xac),
+      //   aad: vec!(0xcf, 0x6c, 0xe7, 0xb8, 0x99, 0xfb, 0x70, 0x0a, 0x90, 0xd2, 0xa5, 0x46, 0x6d, 0x54, 0xd3, 0x13, 0x58, 0xec, 0xf0, 0x56, 0x2e, 0x02, 0xb3, 0x30, 0xa2, 0x7b, 0xa0, 0x13, 0x80, 0x06, 0xb3, 0x42, 0xb7, 0xed, 0x63, 0x49, 0xd7, 0x3c, 0x4c, 0x5c, 0x6d, 0x29, 0xbd, 0xe7, 0x5a, 0x25, 0x08, 0x9b, 0x11, 0xda, 0xc5, 0xb2, 0x7a, 0xde, 0xa7, 0xe7, 0x64, 0x0c, 0xa1, 0xa7, 0xce, 0xb0, 0x50, 0xe3, 0xaa, 0xe8, 0x4a, 0x47, 0xe1, 0x16, 0x40, 0xa6, 0xe4, 0x85, 0xbd, 0x54, 0xae, 0x9f, 0xdb, 0x54, 0x7e, 0xdc, 0x73, 0x13, 0xd2, 0x4a, 0x03, 0x28, 0x42, 0x9f, 0xcf, 0xfd, 0x8b, 0x18, 0xf3, 0x98, 0x80, 0xed, 0xd6, 0x16, 0x44, 0x73, 0x44, 0xeb, 0xee, 0xc9, 0xea, 0xdb, 0x2d, 0xcb, 0x1f, 0xa7, 0xe6, 0x71, 0x79, 0xe7, 0xf9, 0x13, 0xc1, 0x94, 0xeb, 0xd8, 0xf5, 0xa5, 0x8a, 0xea, 0x73, 0xb0, 0xc5, 0xd1, 0x13, 0x35, 0x61, 0x24, 0x5b, 0x6d, 0x9c, 0x5c, 0xfd, 0x8b, 0xb0, 0xc2, 0x5b, 0x38, 0xff, 0xb3, 0x7d, 0xb5, 0xe2, 0xde, 0x5c, 0xdd, 0xed, 0x6b, 0x57, 0x35, 0x5e, 0x9d, 0x21, 0x5c, 0xb0, 0x95, 0xb8, 0x73, 0x1f),
+      //   cipher_text: vec!(0xaa, 0x87, 0xf9, 0xa8, 0x30, 0x48, 0xb6, 0x91, 0x9c, 0x8f, 0x2b, 0x05, 0x03, 0x15, 0xdb, 0x4e, 0x2a, 0xda, 0xe4, 0xa9, 0xc2, 0xca, 0x01, 0x09, 0xb8, 0x19, 0x61, 0xb5, 0x20, 0xe6, 0x32, 0x99, 0xdc, 0xb0, 0x28, 0xce, 0xc0, 0xb9, 0xd3, 0x24, 0x9a, 0x94, 0x5e, 0xe6, 0x7d, 0xd0, 0x29, 0xb4, 0x0f, 0x36, 0x12, 0x45, 0xc7, 0x40, 0xf0, 0x04, 0xf8, 0xcf, 0x0d, 0x22, 0x14, 0xfc, 0xfa, 0x65, 0xe6, 0x12, 0x4a, 0x3e, 0x74, 0xb7, 0x8a, 0xa9, 0x43, 0x45, 0xc4, 0x6f, 0xdc, 0x15, 0x8d, 0x34, 0x82, 0x3e, 0xd2, 0x49, 0xee, 0x55, 0x04, 0x31, 0xea, 0xae, 0x92, 0x18, 0x36, 0x73, 0x21, 0xcd, 0xd6, 0xe6, 0xa4, 0x77, 0x65, 0x04, 0x69, 0xbb, 0x3c, 0xc1, 0x37, 0xa8, 0xf4, 0x8d, 0x9c, 0xf2, 0x79, 0x34, 0xb1, 0x67, 0x03, 0x60, 0x8b, 0x38, 0x3d, 0x21, 0x45, 0x65, 0x99, 0x22, 0xfb, 0x83, 0xbb, 0x2e, 0x7e, 0xe2, 0xef, 0x93, 0x8a, 0x90, 0xf2, 0xff, 0x84, 0x6a, 0x4a, 0x94, 0x91, 0x29, 0xb1, 0xfb, 0x74, 0xdd, 0xe5, 0x5c, 0x5a, 0xe0, 0x13, 0xc2, 0xf2, 0x85, 0xde, 0x84, 0xf7, 0xda, 0xc7, 0xd1, 0x66, 0x2f, 0x23),
+      //   tag: vec!(0x06, 0xb4, 0x31, 0x8a, 0xc7, 0xf6, 0x5d, 0x55, 0x6f, 0x78, 0x14, 0x28, 0xa0, 0x51, 0x4f, 0xfe)
+      // },
+      // TestVector{
+      //   key: [0x9e, 0x4a, 0x62, 0x01, 0x6d, 0xae, 0x4b, 0x32, 0x23, 0xfe, 0xd1, 0xd0, 0x1d, 0x07, 0x87, 0xe3, 0x1d, 0x30, 0x69, 0x4f, 0x79, 0xe8, 0x14, 0x22, 0x24, 0xfe, 0x4c, 0x47, 0x35, 0x24, 0x8a, 0x83],
+      //   nonce: [0x26, 0x3a, 0x2f, 0xc0, 0x6a, 0x28, 0x72, 0xe7],
+      //   plain_text: vec!(0x5a, 0x46, 0x94, 0x66, 0x01, 0xf9, 0x3a, 0x0c, 0xee, 0x59, 0x93, 0xc6, 0x95, 0x75, 0xe5, 0x99, 0xcc, 0x24, 0xf5, 0x1a, 0xaf, 0xa2, 0xd7, 0xc2, 0x8d, 0x81, 0x6a, 0x5b, 0x9b, 0x4d, 0xec, 0xda, 0x2e, 0x59, 0xc1, 0x11, 0x07, 0x5f, 0xb6, 0x0a, 0x90, 0x3d, 0x70, 0x1a, 0xd2, 0x68, 0x0b, 0xb1, 0x4a, 0xed, 0xa1, 0x4a, 0xf2, 0xae, 0x9c, 0x07, 0xa7, 0x59, 0xd8, 0x38, 0x8b, 0x30, 0x44, 0x6f, 0x28, 0xb8, 0x5f, 0x0a, 0x05, 0xcd, 0x15, 0x00, 0x50, 0xbd, 0x2e, 0x71, 0x5f, 0xf5, 0x50, 0xeb, 0xbd, 0x24, 0xda, 0x3e, 0xbb, 0x1e, 0xac, 0x15, 0xab, 0xa2, 0x3d, 0x44, 0x86, 0x59, 0xde, 0x34, 0xbe, 0x96, 0x2a, 0xb3, 0xab, 0x31, 0xcb, 0x17, 0x58, 0xdb, 0x76, 0xc4, 0x68, 0xb5, 0xbb, 0x8c, 0xe4, 0x4b, 0x06, 0xc4, 0xe4, 0xdb, 0x9b, 0xd2, 0xf0, 0x61, 0x5b, 0x1e, 0x72, 0x7f, 0x05, 0x3f, 0x6b, 0x4f, 0xfb, 0x63, 0x58, 0xd2, 0x48, 0xf0, 0x22, 0xbc, 0xad, 0x6c, 0xa9, 0x73, 0x04, 0x4b, 0xed, 0x23, 0xd3, 0x92, 0x09, 0x06, 0xa8, 0x9a, 0x9a, 0x9c, 0x5d, 0x80, 0x24, 0xec, 0x67, 0xd7, 0xf0, 0x61, 0xf6, 0x45, 0x29, 0xa9, 0x55, 0xce, 0x16, 0xb3),
+      //   aad: vec!(0x4c, 0xd6, 0x5f, 0x68, 0xf9, 0xf8, 0x8c, 0x05, 0x16, 0x23, 0x1f, 0x2a, 0x42, 0x5c, 0x8f, 0x8a, 0x28, 0x7d, 0xe4, 0x7d, 0x40, 0x9d, 0x5e, 0xcd, 0xe3, 0xad, 0x15, 0x1e, 0x90, 0x6b, 0x38, 0x39, 0xfb, 0x01, 0xbb, 0x91, 0xa4, 0x56, 0xf2, 0x0e, 0xa9, 0xd3, 0x94, 0xd4, 0xb0, 0x66, 0x04, 0xab, 0x1f, 0x90, 0x09, 0xef, 0x29, 0x01, 0x9a, 0xf7, 0x96, 0x8d, 0x96, 0x5d, 0x16, 0x43, 0x16, 0x1a, 0xb3, 0x3a, 0x53, 0x54, 0xcd, 0xa2, 0xfd, 0xc9, 0xf1, 0xd2, 0x1e, 0xc9, 0xcb, 0x71, 0xc3, 0x25, 0xc6, 0x59, 0x64, 0xa1, 0x4f, 0x9b, 0x26, 0xeb, 0x16, 0x56, 0x0b, 0xeb, 0x97, 0x92, 0x07, 0x5a, 0x15, 0x97, 0x39, 0x40, 0x00, 0xfd, 0x5f, 0x33, 0x1b, 0xd8, 0xb7, 0xd2, 0x0d, 0x88, 0xe5, 0xf8, 0x9c, 0xf8, 0xd0, 0xb3, 0x3e, 0x4e, 0x78, 0xe4, 0x90, 0x4b, 0xb5, 0x9c, 0x9c, 0x8d, 0x5d, 0x31, 0xac, 0x86, 0xb8, 0x93, 0xe4, 0xa0, 0x66, 0x7a, 0xf1, 0xbe, 0x85, 0xfd, 0xb7, 0x7f, 0x7e, 0xc3, 0xe2, 0x59, 0x4a, 0x68, 0x04, 0x8d, 0x20, 0xc2, 0xfb, 0x94, 0x22, 0xf5, 0x87, 0x90, 0x78, 0x77, 0x2e, 0xe2, 0x6a, 0x1c, 0x56, 0x0c, 0xbc, 0xbb, 0x21, 0x13),
+      //   cipher_text: vec!(0xe9, 0x44, 0xbb, 0x2a, 0xb0, 0x6d, 0x13, 0x8a, 0xd6, 0x33, 0xc1, 0x6c, 0xe8, 0x27, 0x06, 0xec, 0xf0, 0xef, 0x5d, 0x11, 0x9b, 0xe1, 0xf3, 0x46, 0x0c, 0x9c, 0xe1, 0x01, 0xd9, 0xc4, 0xe0, 0x4e, 0xf1, 0x67, 0x77, 0x07, 0xfc, 0xa4, 0x0d, 0x1f, 0x8c, 0xa1, 0x81, 0xe0, 0x72, 0x73, 0x70, 0x7b, 0x06, 0x62, 0x4d, 0x6d, 0x70, 0x63, 0xc3, 0xb7, 0xb0, 0xbb, 0x01, 0x51, 0xb7, 0x57, 0xb3, 0xe5, 0x23, 0x7f, 0xb8, 0x00, 0x4c, 0x16, 0x12, 0x33, 0xd8, 0xbc, 0x7e, 0x5f, 0x28, 0xea, 0x1c, 0x18, 0xda, 0x18, 0x74, 0xb3, 0xd5, 0x4c, 0x5a, 0xd6, 0xff, 0x08, 0x35, 0xee, 0xd3, 0x5c, 0x88, 0x53, 0x70, 0x45, 0x85, 0xcf, 0x83, 0x99, 0x6e, 0x5e, 0x7c, 0xec, 0x68, 0x18, 0x0a, 0xf4, 0x14, 0xe0, 0x4f, 0x08, 0x13, 0x4d, 0x3b, 0x03, 0x84, 0xeb, 0xdf, 0x03, 0x93, 0xc9, 0x31, 0x0b, 0x55, 0xd8, 0x69, 0x8f, 0xe1, 0x0c, 0xb3, 0x62, 0xde, 0xfc, 0x09, 0x95, 0xe9, 0xa1, 0x3b, 0x48, 0xb4, 0x2c, 0xff, 0x61, 0xff, 0xd9, 0xfe, 0x4c, 0x3c, 0x8c, 0x6d, 0xab, 0x35, 0x57, 0x13, 0xb8, 0x8f, 0x6e, 0x98, 0xa0, 0x2e, 0x72, 0x31, 0xa0, 0xc6, 0x64, 0x4e, 0xc4),
+      //   tag: vec!(0x27, 0xde, 0x0d, 0x4c, 0xa7, 0x64, 0x8f, 0x63, 0x96, 0xd5, 0x41, 0x9a, 0x7b, 0x12, 0x43, 0xb7)
+      // },
+      // TestVector{
+      //   key: [0x18, 0xca, 0x3e, 0xa3, 0xe8, 0xba, 0xee, 0xd1, 0xb3, 0x41, 0x18, 0x92, 0x97, 0xd3, 0x3c, 0xef, 0x7f, 0x4e, 0x0a, 0x2f, 0xab, 0x40, 0xec, 0x3b, 0x6b, 0xb6, 0x73, 0x85, 0xd0, 0x96, 0x9c, 0xfe],
+      //   nonce: [0xb6, 0xae, 0xf3, 0x4c, 0x75, 0x81, 0x8e, 0x7c],
+      //   plain_text: vec!(0xef, 0x6d, 0x1b, 0xb4, 0x09, 0x47, 0x82, 0xf6, 0x02, 0xfc, 0xf4, 0x15, 0x61, 0xcb, 0xa4, 0x97, 0x06, 0x79, 0x66, 0x1c, 0x63, 0xbe, 0xfe, 0x35, 0xff, 0x2c, 0xa7, 0xad, 0x1a, 0x28, 0x0b, 0xf6, 0xb1, 0xe7, 0xf1, 0x53, 0xfa, 0x84, 0x8e, 0xdf, 0xef, 0xfe, 0x25, 0x15, 0x3f, 0x54, 0x0b, 0x71, 0x25, 0x3e, 0x8b, 0xab, 0xa9, 0xae, 0xb7, 0x19, 0xa0, 0x27, 0x52, 0xcd, 0xa6, 0x0e, 0xa5, 0x93, 0x8a, 0xab, 0x33, 0x9e, 0xea, 0xd5, 0xaa, 0xbf, 0x81, 0xb1, 0x9b, 0x0f, 0xc5, 0xc1, 0xed, 0x55, 0x6b, 0xe6, 0xad, 0x89, 0x70, 0xea, 0x43, 0xc3, 0x03, 0xd3, 0x04, 0x62, 0x05, 0xb1, 0x2c, 0x41, 0x9d, 0xea, 0x71, 0xc4, 0x24, 0x5c, 0xfe, 0xdd, 0x0a, 0x31, 0xb0, 0xf4, 0x15, 0x0b, 0x5a, 0x9f, 0xe8, 0x00, 0x52, 0x79, 0x01, 0x88, 0x52, 0x9a, 0xb3, 0x2f, 0x5e, 0x61, 0xd8, 0xcc, 0xde, 0x59, 0x73, 0xed, 0x30, 0xbd, 0xf2, 0x90, 0xcb, 0xfb, 0xd5, 0xf0, 0x73, 0xc0, 0xc6, 0xa0, 0x20, 0xea, 0xc0, 0x33, 0x2f, 0xce, 0xd1, 0x7a, 0x9a, 0x08, 0xce, 0xf6, 0xf9, 0x21, 0x7b, 0xd6, 0xbe, 0xf6, 0x8c, 0x15, 0x05, 0xd6, 0xee, 0xd4, 0x09, 0x53, 0xe1, 0x55, 0x08, 0xd8, 0x7f, 0x08, 0xfc),
+      //   aad: vec!(0xf4, 0x0f, 0x03, 0xbe, 0xaa, 0x02, 0x3d, 0xb6, 0x31, 0x1b, 0xad, 0x9b, 0x4d, 0x5d, 0x0d, 0x66, 0xa5, 0x8d, 0x97, 0x8e, 0x0b, 0xcb, 0xbf, 0x78, 0xac, 0xeb, 0xde, 0x1f, 0x4e, 0xb9, 0xa2, 0x84, 0x09, 0x56, 0x28, 0x95, 0x5a, 0x0b, 0x15, 0xaf, 0xc4, 0x54, 0x15, 0x2f, 0x96, 0x2e, 0xc3, 0xea, 0x2b, 0x9a, 0x3b, 0x08, 0x9b, 0x99, 0x65, 0x8e, 0x68, 0xed, 0xe4, 0xde, 0xe5, 0xac, 0xd5, 0x66, 0x72, 0x02, 0x5e, 0xb7, 0x32, 0x3b, 0xcb, 0xc6, 0xba, 0x5d, 0x91, 0xc9, 0x43, 0x10, 0xf1, 0x8c, 0x91, 0x8e, 0x39, 0x14, 0xbb, 0xbf, 0x86, 0x9e, 0x1b, 0x87, 0x21, 0x47, 0x6f, 0x9d, 0xef, 0x31, 0xb9, 0xd3, 0x2c, 0x47, 0x1a, 0x54, 0x13, 0x24, 0x81, 0xaa, 0x89, 0xf6, 0xc7, 0x35, 0xab, 0x19, 0x33, 0x69, 0x49, 0x6d, 0x8d, 0xbe, 0xb4, 0x9b, 0x13, 0x0d, 0x85, 0xfb, 0xff, 0x3f, 0x9c, 0xb7, 0xdc, 0xce, 0xa4, 0xc1, 0xda, 0x7a, 0x28, 0x46, 0xee, 0xf5, 0xe6, 0x92, 0x9d, 0x90, 0x09, 0xa9, 0x14, 0x9e, 0x39, 0xc6, 0xc8, 0xec, 0x15, 0x0c, 0x9a, 0xb4, 0x9a, 0x09, 0xc1, 0x8c, 0x47, 0x49, 0xa0, 0xa9, 0xfc, 0xba, 0x77, 0x05, 0x7c, 0xde, 0xa6, 0xef, 0xd4, 0xd1, 0x42, 0x25, 0x6c),
+      //   cipher_text: vec!(0xc5, 0x31, 0x63, 0x3c, 0x0c, 0x98, 0x23, 0x0d, 0xcf, 0x05, 0x9c, 0x10, 0x81, 0xd1, 0xd6, 0x9c, 0x96, 0xba, 0xb7, 0x1c, 0x31, 0x43, 0xae, 0x60, 0xf9, 0xfc, 0x2b, 0x9c, 0xd1, 0x87, 0x62, 0x31, 0x44, 0x96, 0xab, 0x6e, 0x90, 0xbf, 0x67, 0x96, 0x25, 0x2c, 0xb9, 0xf6, 0x67, 0xa1, 0xf0, 0x8d, 0xa4, 0x7f, 0xc2, 0xb0, 0xee, 0xcd, 0xa8, 0x13, 0x22, 0x8c, 0xae, 0x00, 0xd4, 0xc0, 0xd7, 0x1f, 0x5e, 0x01, 0xb6, 0xce, 0x76, 0x2f, 0xa6, 0x36, 0xef, 0xff, 0xe5, 0x5d, 0x0e, 0x89, 0xfd, 0xc8, 0x9b, 0xa4, 0x25, 0x21, 0xcc, 0x01, 0x9a, 0xb9, 0xd4, 0x08, 0xfc, 0xd7, 0x9c, 0x14, 0x91, 0x4e, 0x8b, 0xbf, 0x0e, 0xa4, 0x4d, 0x8a, 0x1d, 0x35, 0x74, 0x3a, 0xd6, 0x28, 0x32, 0x7e, 0x43, 0x2f, 0xdc, 0xfe, 0xb0, 0xb6, 0x67, 0x9d, 0xdc, 0xa8, 0xc9, 0x2b, 0x99, 0x84, 0x73, 0x73, 0x2a, 0xbd, 0x55, 0xdb, 0xa5, 0x4e, 0xef, 0xff, 0x83, 0xc7, 0x84, 0x88, 0xee, 0xe5, 0xf9, 0x2b, 0x14, 0x5a, 0x74, 0xb6, 0x86, 0x65, 0x31, 0x47, 0x6f, 0xc4, 0x62, 0x79, 0xd4, 0xfd, 0xe2, 0x4d, 0x04, 0x9c, 0x1c, 0xe2, 0xb4, 0x23, 0x58, 0xff, 0x3a, 0xb2, 0xba, 0x3a, 0x88, 0x66, 0xe5, 0x47, 0xaf),
+      //   tag: vec!(0xa0, 0xa5, 0x24, 0x27, 0x59, 0xa6, 0xd9, 0xb1, 0xaa, 0x5b, 0xaf, 0x9a, 0x4e, 0xf8, 0x95, 0xa2)
+      // },
+      // TestVector{
+      //   key: [0x95, 0xfd, 0xd2, 0xd3, 0xd4, 0x29, 0x60, 0x69, 0x05, 0x5b, 0x6b, 0x79, 0xe5, 0xd1, 0x38, 0x76, 0x28, 0x25, 0x4a, 0x7b, 0xe6, 0x47, 0xba, 0xaf, 0xdf, 0x99, 0xdd, 0x8a, 0xf3, 0x54, 0xd8, 0x17],
+      //   nonce: [0xcd, 0x7e, 0xd9, 0xe7, 0x0f, 0x60, 0x86, 0x13],
+      //   plain_text: vec!(0x02, 0x48, 0x28, 0x4a, 0xcf, 0xfa, 0x4b, 0x2c, 0x46, 0x63, 0x6b, 0xdf, 0x8c, 0xc7, 0x00, 0x28, 0xdd, 0x15, 0x1a, 0x6d, 0x8e, 0x7a, 0x5a, 0x5b, 0xc2, 0xd3, 0x9a, 0xcc, 0x10, 0x20, 0xe7, 0x36, 0x88, 0x50, 0x31, 0xb2, 0x52, 0xbf, 0xe9, 0xf9, 0x64, 0x90, 0x92, 0x1f, 0x41, 0xd1, 0xe1, 0x74, 0xbf, 0x1a, 0xc0, 0x37, 0x07, 0xbc, 0x2a, 0xe5, 0x08, 0x8a, 0x12, 0x08, 0xa7, 0xc6, 0x64, 0x58, 0x38, 0x35, 0xe8, 0xbb, 0x93, 0xc7, 0x87, 0xb9, 0x6d, 0xea, 0x9f, 0xc4, 0xb8, 0x84, 0x93, 0x0c, 0x57, 0x79, 0x9e, 0x7b, 0x7a, 0x66, 0x49, 0xc6, 0x13, 0x40, 0x37, 0x6d, 0x04, 0x2b, 0x9f, 0x5f, 0xae, 0xe8, 0x95, 0x6c, 0x70, 0xa6, 0x3c, 0xf1, 0xcf, 0xf4, 0xfc, 0x2c, 0x7c, 0xb8, 0x53, 0x5c, 0x10, 0x21, 0x4e, 0x73, 0xce, 0xc6, 0xb7, 0x96, 0x69, 0xd8, 0x24, 0xf2, 0x3f, 0xf8, 0xc8, 0xa2, 0xca, 0x1c, 0x05, 0x97, 0x4d, 0xd6, 0x18, 0x9c, 0xfe, 0xe4, 0x84, 0xd0, 0x90, 0x6d, 0xf4, 0x87, 0xb6, 0xbd, 0x85, 0x67, 0x1c, 0xe2, 0xb2, 0x38, 0x25, 0x05, 0x2e, 0x44, 0xb8, 0x48, 0x03, 0xe2, 0x83, 0x9a, 0x96, 0x39, 0x1a, 0xbc, 0x25, 0x94, 0x5c, 0xb8, 0x67, 0xb5, 0x27, 0xcd, 0xd9, 0xb3, 0x73, 0xfb, 0xfb, 0x83),
+      //   aad: vec!(0x24, 0xa4, 0x5a, 0x3a, 0x00, 0x76, 0xa5, 0xbc, 0xfd, 0x5a, 0xfe, 0x1c, 0x54, 0xf7, 0xb7, 0x74, 0x96, 0x11, 0x7d, 0x29, 0xf4, 0xc0, 0x90, 0x9f, 0x1e, 0x69, 0x40, 0xb8, 0x1d, 0xde, 0x3a, 0xba, 0xcb, 0x71, 0xec, 0x71, 0xf0, 0xf4, 0xdb, 0x8a, 0x7e, 0x54, 0x0b, 0xd4, 0xc2, 0xc6, 0x0f, 0xae, 0xe2, 0x1d, 0xd3, 0xce, 0x72, 0x96, 0x38, 0x55, 0xbe, 0x1b, 0x0c, 0xe5, 0x4f, 0xb2, 0x0a, 0xd8, 0x2d, 0xbc, 0x45, 0xbe, 0x20, 0xcd, 0x6c, 0x17, 0x1e, 0x2b, 0xeb, 0xb7, 0x9e, 0x65, 0xe7, 0xd0, 0x15, 0x67, 0xad, 0x0e, 0xeb, 0x86, 0x98, 0x83, 0xe4, 0xe8, 0x14, 0xc9, 0x36, 0x88, 0x60, 0x7a, 0x12, 0xb3, 0xb7, 0x32, 0xc1, 0x70, 0x3b, 0x09, 0x56, 0x6c, 0x30, 0x8d, 0x29, 0xce, 0x67, 0x6a, 0x5c, 0x76, 0x2a, 0x85, 0x70, 0x06, 0x39, 0xb7, 0x0d, 0x82, 0xaa, 0xef, 0x40, 0x8c, 0xf9, 0x88, 0x21, 0xa3, 0x72, 0xc6, 0xa0, 0x61, 0x4a, 0x73, 0xba, 0x99, 0x18, 0xa7, 0x95, 0x1e, 0xa8, 0xb2, 0xbb, 0x77, 0xcd, 0x98, 0x96, 0xd2, 0x69, 0x88, 0x08, 0x6d, 0x85, 0x86, 0xd7, 0x2e, 0xdc, 0x92, 0xaf, 0x20, 0x42, 0xff, 0x5e, 0x5f, 0x14, 0x29, 0xa2, 0x2f, 0x61, 0x06, 0x5e, 0x03, 0xcf, 0xcd, 0x7e, 0xdc, 0x2a, 0x93),
+      //   cipher_text: vec!(0x40, 0xc6, 0x31, 0x8d, 0x9e, 0x38, 0x3e, 0x10, 0x7c, 0xdd, 0x3e, 0x1c, 0x89, 0x51, 0x56, 0x21, 0x93, 0xc3, 0xef, 0x64, 0xee, 0x44, 0x24, 0x32, 0xa6, 0x3e, 0x2e, 0xde, 0xfc, 0x78, 0xf3, 0x2a, 0xb0, 0x77, 0x72, 0xae, 0xac, 0x17, 0x2c, 0xb6, 0x7e, 0xcf, 0x4d, 0x21, 0xf8, 0xb4, 0x48, 0x42, 0x35, 0x27, 0xbb, 0xeb, 0x9d, 0x8d, 0xdd, 0x0b, 0x46, 0xbd, 0xb2, 0x7f, 0x74, 0x09, 0x6c, 0xeb, 0x24, 0xe4, 0x19, 0x63, 0xb4, 0xcd, 0xca, 0x17, 0x66, 0x76, 0xa7, 0x5b, 0xdb, 0xe3, 0xab, 0xc2, 0x70, 0xb3, 0x49, 0xac, 0x0c, 0x6c, 0xbd, 0x9c, 0x3a, 0x5c, 0xd5, 0xbc, 0xe2, 0x02, 0x02, 0xfc, 0x5c, 0xc0, 0xc1, 0xbd, 0xd4, 0xfd, 0x25, 0xe1, 0x21, 0xe0, 0xa2, 0x4b, 0xd7, 0xbb, 0xeb, 0x9b, 0x19, 0xb1, 0x91, 0x24, 0x67, 0xbf, 0x53, 0x38, 0xee, 0x2c, 0xe8, 0x8a, 0xa3, 0x83, 0xc0, 0x82, 0xb4, 0x2c, 0xc3, 0x99, 0xc9, 0x65, 0x4c, 0xa3, 0x25, 0xf3, 0x55, 0x23, 0xe8, 0x14, 0x38, 0xbe, 0xb3, 0xf8, 0x92, 0x6b, 0xe7, 0x9c, 0x37, 0x88, 0x22, 0xd7, 0xc8, 0xf7, 0x85, 0x61, 0x44, 0x08, 0xa5, 0xf7, 0xca, 0xc4, 0x9e, 0x45, 0x43, 0x18, 0x87, 0x25, 0x64, 0x3e, 0x6c, 0x1a, 0x70, 0xb4, 0x6d, 0x0e, 0xc4, 0x00),
+      //   tag: vec!(0x58, 0x01, 0xe8, 0x41, 0x92, 0xc7, 0x26, 0x7f, 0x66, 0xb0, 0xe0, 0x46, 0x07, 0xa3, 0x9a, 0x3e)
+      // },
+      // TestVector{
+      //   key: [0x6a, 0xe1, 0x10, 0x2f, 0x84, 0xed, 0x4d, 0xc1, 0x14, 0xbb, 0x9d, 0x63, 0xf4, 0xdc, 0x78, 0xd7, 0xdb, 0xb1, 0xab, 0x63, 0xf1, 0x65, 0x9d, 0xd9, 0x5f, 0x47, 0x94, 0x0a, 0x7b, 0x7a, 0x81, 0x1f],
+      //   nonce: [0xc9, 0x65, 0xd5, 0x78, 0xba, 0x91, 0xd2, 0x27],
+      //   plain_text: vec!(0xb8, 0x2a, 0x8a, 0x92, 0x09, 0x61, 0x8f, 0x1f, 0x5b, 0xe9, 0xc2, 0xc3, 0x2a, 0xba, 0x3d, 0xc4, 0x5b, 0x49, 0x47, 0x00, 0x7b, 0x14, 0xc8, 0x51, 0xcd, 0x69, 0x44, 0x56, 0xb3, 0x03, 0xad, 0x59, 0xa4, 0x65, 0x66, 0x28, 0x03, 0x00, 0x67, 0x05, 0x67, 0x3d, 0x6c, 0x3e, 0x29, 0xf1, 0xd3, 0x51, 0x0d, 0xfc, 0x04, 0x05, 0x46, 0x3c, 0x03, 0x41, 0x4e, 0x0e, 0x07, 0xe3, 0x59, 0xf1, 0xf1, 0x81, 0x6c, 0x68, 0xb2, 0x43, 0x4a, 0x19, 0xd3, 0xee, 0xe0, 0x46, 0x48, 0x73, 0xe2, 0x3c, 0x43, 0xf3, 0xab, 0x60, 0xa3, 0xf6, 0x06, 0xa0, 0xe5, 0xbe, 0x81, 0xe3, 0xab, 0x4a, 0xa2, 0x7f, 0xb7, 0x70, 0x7a, 0x57, 0xb9, 0x49, 0xf0, 0x0d, 0x6c, 0xd3, 0xa1, 0x1a, 0xe4, 0x82, 0x7d, 0x48, 0x89, 0xdd, 0x45, 0x5a, 0x0b, 0x6d, 0x39, 0xe9, 0x90, 0x12, 0xfd, 0x40, 0xdb, 0x23, 0xfb, 0x50, 0xe7, 0x9e, 0x11, 0xf8, 0xa6, 0x45, 0x16, 0x69, 0xbe, 0xb2, 0xfb, 0xd9, 0x13, 0xef, 0xfd, 0x49, 0xad, 0x1b, 0x43, 0x92, 0x63, 0x11, 0xf6, 0xe1, 0x3a, 0x6e, 0x7a, 0x09, 0xcf, 0x4b, 0xeb, 0xb1, 0xc0, 0xbf, 0x63, 0xce, 0x59, 0xcd, 0x5a, 0x08, 0xe4, 0xb8, 0xd8, 0xdb, 0xf9, 0xd0, 0x02, 0xe8, 0xa3, 0xd9, 0xe8, 0x0c, 0x79, 0x95, 0xbb, 0x0b, 0x48, 0x52, 0x80),
+      //   aad: vec!(0xdf, 0xd4, 0xac, 0x3e, 0x80, 0xb2, 0x90, 0x46, 0x23, 0xff, 0x79, 0xea, 0x8e, 0xe8, 0x78, 0x62, 0x26, 0x89, 0x39, 0xde, 0xcf, 0x53, 0x06, 0xc0, 0x7a, 0x17, 0x5b, 0x6b, 0x9d, 0xa0, 0xeb, 0x13, 0xac, 0x20, 0x9b, 0x4d, 0x16, 0x47, 0x55, 0x92, 0x9e, 0x03, 0x24, 0x0a, 0x0f, 0xe2, 0x65, 0x99, 0xf1, 0x36, 0xfb, 0x2a, 0xfd, 0xff, 0xd1, 0x2b, 0xb2, 0x03, 0x54, 0xaa, 0x1d, 0x20, 0xe5, 0x79, 0x98, 0x39, 0xab, 0xb6, 0x8a, 0xe4, 0x6d, 0x50, 0xc8, 0x97, 0x4e, 0x13, 0xe3, 0x61, 0xd8, 0x7e, 0xf5, 0x50, 0xfe, 0x6d, 0x82, 0xe8, 0xb5, 0xb1, 0x72, 0xcf, 0x5c, 0xd0, 0x84, 0x82, 0xef, 0xde, 0xf7, 0x93, 0xed, 0xe3, 0x53, 0x0d, 0x24, 0x66, 0x7f, 0xaf, 0x3a, 0x1e, 0x96, 0x34, 0x88, 0x67, 0xc2, 0x94, 0x26, 0x41, 0xf4, 0xc0, 0x36, 0x98, 0x1b, 0x83, 0xf5, 0x02, 0x36, 0xb8, 0xe8, 0xa1, 0x0b, 0x83, 0xeb, 0xf6, 0x90, 0x9a, 0xad, 0x00, 0x76, 0x30, 0x2f, 0x10, 0x83, 0xf7, 0x2d, 0xe4, 0xcf, 0x4a, 0x1a, 0x31, 0x83, 0xfe, 0x6e, 0xc6, 0xbf, 0xe2, 0xe7, 0x3e, 0x2a, 0xf8, 0xe1, 0xe8, 0xc9, 0xd8, 0x50, 0x79, 0x08, 0x3f, 0xd1, 0x79, 0xcc, 0xc2, 0xee, 0x9f, 0xf0, 0x02, 0xf2, 0x13, 0xdb, 0xd7, 0x33, 0x30, 0x53, 0xa4, 0x6c, 0x5e, 0x43),
+      //   cipher_text: vec!(0xa9, 0xae, 0xb8, 0xf0, 0xa2, 0xb3, 0xca, 0x14, 0x1a, 0xc7, 0x1a, 0x80, 0x8d, 0xcc, 0x0c, 0x97, 0x98, 0xac, 0x11, 0x7c, 0x5d, 0x2b, 0xd0, 0x9b, 0x3c, 0xfe, 0x62, 0x26, 0x93, 0xa9, 0xf8, 0xca, 0x62, 0xe8, 0x41, 0xb5, 0x8b, 0xdd, 0xb2, 0x04, 0x2f, 0x88, 0x8e, 0x30, 0x99, 0xb5, 0x36, 0x38, 0xb8, 0x8d, 0xfc, 0x93, 0x0b, 0x7a, 0x6e, 0xe4, 0x27, 0x2d, 0x77, 0xe4, 0xb1, 0xd7, 0xe4, 0x42, 0xba, 0xb6, 0xaf, 0xbd, 0xe9, 0x6a, 0xb0, 0xb4, 0x32, 0xf0, 0x09, 0x2d, 0x9c, 0xa5, 0x0e, 0xef, 0x42, 0xf6, 0x3c, 0x60, 0xc0, 0x9e, 0x7b, 0x8d, 0xe0, 0x19, 0xb3, 0x2e, 0xbe, 0x40, 0x30, 0xc3, 0x7b, 0x81, 0x83, 0xcc, 0x1e, 0x3b, 0x91, 0x3b, 0x0c, 0xe4, 0xee, 0x4d, 0x74, 0x43, 0x98, 0xfa, 0x03, 0xf9, 0xaf, 0x1c, 0x07, 0x0b, 0xed, 0x8c, 0xda, 0xfd, 0x65, 0xb3, 0xa8, 0x41, 0x40, 0xcb, 0x4d, 0xea, 0xdc, 0x70, 0x18, 0x4d, 0xe7, 0x57, 0x33, 0x2c, 0xe3, 0x78, 0x0a, 0xf8, 0x43, 0x53, 0xf5, 0x40, 0x75, 0x52, 0x27, 0xe8, 0x86, 0xa8, 0xd7, 0xad, 0x98, 0x0f, 0x3d, 0xd6, 0xfd, 0x68, 0x26, 0x3d, 0x82, 0xe9, 0x3f, 0x88, 0x33, 0x81, 0xde, 0xc8, 0x88, 0xbc, 0x9f, 0x4f, 0x48, 0x34, 0x9a, 0xa2, 0xb4, 0xc3, 0x42, 0xcb, 0x9f, 0x48, 0xc6),
+      //   tag: vec!(0xf2, 0x6b, 0x3a, 0xf8, 0xa4, 0x5c, 0x41, 0x62, 0x91, 0xce, 0x66, 0x33, 0x07, 0x33, 0xb2, 0xf8)
+      // },
+      // TestVector{
+      //   key: [0x40, 0x5b, 0xb7, 0xb9, 0x47, 0x15, 0xb8, 0x75, 0xdf, 0x06, 0x86, 0x55, 0xf0, 0x05, 0x13, 0xcb, 0x1a, 0xe2, 0x3f, 0xfa, 0xac, 0x97, 0x7c, 0xe2, 0x73, 0xe5, 0x7d, 0x3f, 0x83, 0xb4, 0x36, 0x63],
+      //   nonce: [0x5c, 0x6d, 0xa1, 0x25, 0x94, 0x51, 0x11, 0x9a],
+      //   plain_text: vec!(0xf9, 0xf1, 0x43, 0xc0, 0xc5, 0x2c, 0x94, 0xb4, 0xba, 0x7b, 0x06, 0x08, 0xb1, 0x44, 0x15, 0x6a, 0x49, 0xe7, 0xb5, 0xd2, 0x7c, 0x97, 0x31, 0x57, 0x43, 0xd1, 0x71, 0x91, 0x1e, 0x36, 0x45, 0xab, 0x79, 0x57, 0xc8, 0x09, 0x24, 0xe3, 0xc6, 0xb9, 0xc2, 0x2a, 0xb7, 0xa1, 0xca, 0xc4, 0xb7, 0xe9, 0xc0, 0xde, 0x84, 0xe4, 0x9f, 0xd5, 0xe4, 0xa2, 0xd1, 0xab, 0x51, 0xd7, 0x64, 0xfc, 0x56, 0x70, 0x31, 0x86, 0x88, 0xec, 0x94, 0x2f, 0x7a, 0xb3, 0x4c, 0x33, 0x1d, 0xce, 0x8f, 0x90, 0xfe, 0xa6, 0x97, 0x2e, 0x07, 0xf0, 0xda, 0xde, 0xc2, 0x9d, 0x8e, 0xb3, 0xb7, 0xb6, 0x52, 0x1d, 0xdd, 0x67, 0x8a, 0x65, 0x27, 0xa9, 0x62, 0xf4, 0xd8, 0xaf, 0x78, 0xc0, 0x77, 0xe2, 0x7f, 0x7a, 0x0b, 0x2e, 0xf7, 0xea, 0xbd, 0x19, 0xe9, 0x2b, 0x7f, 0x8c, 0x1e, 0x8f, 0xb1, 0x66, 0xd4, 0x76, 0x3c, 0xe9, 0xc4, 0x0c, 0x88, 0x8c, 0xf4, 0x9a, 0xa9, 0xcd, 0xfc, 0x3e, 0x99, 0x7c, 0x8f, 0xe1, 0xcc, 0xe3, 0xfe, 0x80, 0x24, 0x41, 0xbb, 0xd6, 0x98, 0xde, 0x26, 0x9f, 0xf3, 0x16, 0xf3, 0x1c, 0x19, 0x6e, 0x62, 0xd1, 0x2c, 0x6b, 0xb5, 0xcd, 0x93, 0xfb, 0x3c, 0x79, 0xca, 0x63, 0x69, 0xf8, 0xc1, 0xac, 0x91, 0x02, 0xda, 0xf8, 0x18, 0x97, 0x5e, 0xa7, 0xf5, 0x13, 0xbb, 0x38, 0x57, 0x6a),
+      //   aad: vec!(0x6f, 0xe6, 0x44, 0x65, 0x05, 0x67, 0x7b, 0xf0, 0x8b, 0x38, 0x5e, 0x2f, 0x6d, 0x83, 0xef, 0x70, 0xe1, 0x54, 0x77, 0x12, 0x20, 0x8d, 0x9c, 0xeb, 0xc0, 0x10, 0xcb, 0xa8, 0xc1, 0x6e, 0xa4, 0xec, 0xe0, 0x58, 0xd7, 0x3c, 0x72, 0x27, 0x3e, 0xed, 0x65, 0x0a, 0xfd, 0xc9, 0xf9, 0x54, 0xf3, 0x5a, 0xa1, 0xbd, 0xf9, 0x0f, 0x11, 0x18, 0xb1, 0x17, 0x33, 0x68, 0xac, 0xbc, 0x8d, 0x38, 0xd9, 0x3e, 0xbf, 0x85, 0xbd, 0x30, 0xd6, 0xdc, 0x6d, 0x1b, 0x90, 0x91, 0x37, 0x90, 0xc3, 0xef, 0xa5, 0x5f, 0x34, 0xd3, 0x15, 0x31, 0xf7, 0x0c, 0x95, 0x87, 0x59, 0xb2, 0xba, 0x6f, 0x95, 0x6c, 0x6f, 0xcd, 0xd2, 0x89, 0xb5, 0x8c, 0xb4, 0xc2, 0x6e, 0x95, 0x15, 0xbf, 0x55, 0x0f, 0x0f, 0xd7, 0x1a, 0xb8, 0x52, 0x7f, 0x06, 0x2c, 0x95, 0x05, 0xcb, 0xb1, 0x6e, 0x8e, 0x03, 0x7d, 0x34, 0xde, 0x17, 0x56, 0xbe, 0xf0, 0x2a, 0x13, 0x3d, 0xbf, 0x4a, 0x9c, 0x00, 0xac, 0x03, 0xbe, 0xfc, 0x3f, 0xb7, 0xf1, 0x37, 0xaf, 0x04, 0xe1, 0x25, 0x95, 0xce, 0x95, 0x60, 0xf9, 0x8b, 0x61, 0x24, 0x80, 0xfc, 0xdb, 0xa3, 0xb8, 0xbe, 0x01, 0xdb, 0x56, 0xeb, 0xec, 0x40, 0xf9, 0xde, 0xae, 0x53, 0x2c, 0x3b, 0x03, 0x70, 0xb5, 0xc2, 0x3a, 0x2a, 0x6b, 0x02, 0xa4, 0xde, 0x69, 0xef, 0xa8, 0x90, 0x0c),
+      //   cipher_text: vec!(0x1a, 0x4b, 0x07, 0x38, 0x81, 0x92, 0x2c, 0x63, 0x66, 0x68, 0x0c, 0xc9, 0xc2, 0xa1, 0x27, 0xb2, 0x6f, 0x26, 0x41, 0x48, 0x65, 0x1b, 0x29, 0xab, 0xb0, 0xc3, 0x88, 0xcf, 0x6c, 0x9b, 0x18, 0x65, 0xdb, 0xa5, 0xa9, 0x91, 0xe1, 0xf8, 0x30, 0x9e, 0xfb, 0xdb, 0x91, 0xbc, 0xe4, 0x4b, 0x27, 0x87, 0x72, 0xc5, 0x8f, 0xd4, 0x12, 0x73, 0x52, 0x6c, 0x33, 0xfe, 0xc8, 0x4b, 0xeb, 0x53, 0xd1, 0x68, 0x9b, 0x9d, 0xa8, 0x48, 0x3f, 0x71, 0xbe, 0x6d, 0xb7, 0x3a, 0x73, 0x41, 0x70, 0x69, 0xbb, 0x4c, 0xd3, 0xf1, 0x95, 0x23, 0x6e, 0x8d, 0x0a, 0x00, 0xd1, 0x24, 0xee, 0xd3, 0xa6, 0xb6, 0xf8, 0x94, 0x15, 0xb1, 0x9a, 0x27, 0xfb, 0xe3, 0x57, 0x74, 0xf6, 0xa1, 0xa6, 0xee, 0x4b, 0xd4, 0x35, 0x0b, 0x25, 0x2b, 0x97, 0x5f, 0x0d, 0xb2, 0xd2, 0xee, 0xa8, 0x2f, 0x48, 0x36, 0x35, 0x08, 0x50, 0xd6, 0x29, 0x09, 0x01, 0xe7, 0x26, 0xe8, 0xaf, 0x13, 0x64, 0x4e, 0x2d, 0x98, 0xbc, 0x1d, 0x56, 0x9c, 0x20, 0x80, 0x05, 0x21, 0xe6, 0xaf, 0xfe, 0x97, 0x6b, 0xd4, 0x07, 0x04, 0x9a, 0x2e, 0x6d, 0x9d, 0xd2, 0x3f, 0x88, 0xd5, 0x2e, 0x65, 0x13, 0x91, 0xec, 0xd2, 0xfc, 0x45, 0xb8, 0x64, 0x31, 0x08, 0x24, 0xaa, 0xad, 0xfa, 0x20, 0x37, 0x62, 0xa7, 0x7c, 0x1d, 0x64, 0x56, 0x2d, 0xae),
+      //   tag: vec!(0x00, 0x60, 0x02, 0x6d, 0x3e, 0xfc, 0x12, 0x0f, 0x11, 0xc0, 0x73, 0x99, 0x59, 0xae, 0x00, 0x66)
+      // },
+      // TestVector{
+      //   key: [0x8c, 0x60, 0x2b, 0xd9, 0x4c, 0x63, 0x0c, 0xd0, 0x0c, 0x7a, 0x9c, 0x50, 0x80, 0x67, 0xa5, 0xa9, 0xf1, 0x33, 0xd1, 0x2f, 0x06, 0xd9, 0xf6, 0xfe, 0x2a, 0x7b, 0x68, 0xdc, 0xe4, 0x78, 0x6d, 0x8a],
+      //   nonce: [0x76, 0x0d, 0xe0, 0xf7, 0xb7, 0xcb, 0x67, 0xe2],
+      //   plain_text: vec!(0xc3, 0xff, 0x55, 0x9c, 0xf1, 0xd6, 0xba, 0x6c, 0x0c, 0xc7, 0x93, 0xca, 0x09, 0xa0, 0xba, 0x57, 0x3a, 0x28, 0x35, 0x93, 0x86, 0xa6, 0xec, 0x93, 0xe1, 0xba, 0xcd, 0x8e, 0x63, 0x02, 0x09, 0xe0, 0xb4, 0x77, 0xa2, 0x0a, 0xed, 0xec, 0x3c, 0x9c, 0xbf, 0x51, 0x3e, 0xe6, 0xa1, 0xe3, 0x88, 0x71, 0x12, 0x21, 0x8d, 0x61, 0x55, 0xb9, 0x87, 0x5f, 0x7e, 0x6c, 0x4b, 0xbb, 0xa2, 0xc3, 0x19, 0x72, 0xe9, 0x05, 0xd1, 0x9f, 0x52, 0x9f, 0x4f, 0x0f, 0x95, 0x02, 0x99, 0x61, 0x99, 0xf9, 0x4f, 0x87, 0x28, 0xba, 0x8d, 0x64, 0x24, 0xbb, 0x15, 0xf8, 0x7f, 0xca, 0xcd, 0x88, 0xbb, 0x42, 0xc6, 0x3f, 0xcc, 0x51, 0x37, 0x59, 0x71, 0x2b, 0xd0, 0x17, 0x2b, 0x1e, 0x87, 0xc9, 0xda, 0x12, 0x2f, 0x19, 0x93, 0xff, 0xb7, 0xef, 0xd3, 0xa5, 0xc3, 0x4b, 0x24, 0x0d, 0xd3, 0xdb, 0x89, 0xdd, 0xde, 0xa3, 0x6d, 0xbe, 0xb2, 0x83, 0x6d, 0x9f, 0x86, 0x48, 0xf8, 0xe7, 0xcd, 0x42, 0x8c, 0x0f, 0x94, 0x80, 0x97, 0xaf, 0x75, 0x3b, 0x35, 0xf9, 0x87, 0x60, 0x59, 0xe7, 0x70, 0x20, 0x27, 0xbb, 0x00, 0xdc, 0x69, 0x07, 0x12, 0x06, 0xe7, 0x85, 0xf4, 0x8f, 0xcb, 0xf8, 0x1b, 0x39, 0xcc, 0x03, 0x43, 0x97, 0x4a, 0xc7, 0x07, 0x84, 0xa2, 0xe6, 0x0c, 0x0d, 0xf9, 0x3b, 0x40, 0x37, 0x9b, 0xea, 0x4a, 0xd8, 0xca, 0xc6, 0x25),
+      //   aad: vec!(0x9e, 0x14, 0x90, 0x7c, 0x3a, 0x8e, 0x96, 0xc2, 0x63, 0x6d, 0xb1, 0xf3, 0xd7, 0x8e, 0xb1, 0xf6, 0x73, 0xd6, 0xef, 0x04, 0x3c, 0xbb, 0xb3, 0x49, 0x46, 0x7f, 0x1f, 0xe2, 0x9b, 0xf6, 0x0f, 0x23, 0xd5, 0xd5, 0xd1, 0xc3, 0xb1, 0x33, 0xa8, 0xad, 0x72, 0x06, 0x5d, 0x82, 0x23, 0x47, 0x54, 0x1c, 0x13, 0xd1, 0x57, 0x4b, 0xaf, 0x73, 0x7e, 0xb3, 0xcc, 0x33, 0x82, 0xfb, 0x47, 0x9e, 0x6d, 0x51, 0x93, 0xb9, 0xc8, 0xe7, 0xd2, 0x44, 0x4c, 0x66, 0x97, 0x1e, 0xf0, 0x99, 0xdc, 0x7f, 0x37, 0xf6, 0xcd, 0x97, 0xb9, 0xf7, 0x95, 0x9d, 0x46, 0xe2, 0xcf, 0x25, 0xe8, 0xa5, 0xb3, 0x11, 0x1b, 0x4d, 0x9e, 0x2e, 0xf9, 0x06, 0xd9, 0x05, 0xf0, 0xee, 0x2d, 0x17, 0x58, 0x7f, 0x70, 0x82, 0xd7, 0xc8, 0xe9, 0xa5, 0x15, 0x09, 0xbd, 0xe0, 0x3d, 0x3d, 0x64, 0x33, 0x8e, 0x18, 0x38, 0xd7, 0x17, 0x00, 0xf1, 0xb4, 0xfc, 0xb1, 0x00, 0xb5, 0xe0, 0x40, 0x29, 0x69, 0xda, 0x46, 0x2f, 0x26, 0xf9, 0x74, 0xb4, 0xf9, 0xe7, 0x66, 0x12, 0x1f, 0x8f, 0xd5, 0x4b, 0xe9, 0x9f, 0xc1, 0x0b, 0xeb, 0x9a, 0x60, 0x6e, 0x13, 0xfb, 0xb1, 0xf9, 0x60, 0x06, 0x28, 0x15, 0xd1, 0x9e, 0x67, 0xf8, 0x00, 0x93, 0x36, 0x03, 0x24, 0x01, 0x30, 0x95, 0x71, 0x92, 0x73, 0xc6, 0x55, 0x42, 0xb0, 0xe3, 0x1b, 0x1a, 0x2a, 0x3d, 0x92, 0x8f),
+      //   cipher_text: vec!(0x27, 0x94, 0xe6, 0xe1, 0x33, 0xf6, 0x89, 0x2f, 0x23, 0x83, 0x7f, 0xff, 0x60, 0xcf, 0x7c, 0x28, 0xee, 0x99, 0x42, 0xf8, 0x98, 0x2e, 0xf8, 0x08, 0x9d, 0xb1, 0x17, 0x90, 0x3d, 0x01, 0x43, 0x29, 0x3f, 0xdf, 0x12, 0xea, 0x1c, 0xc0, 0x14, 0xbc, 0xd8, 0x80, 0x6f, 0xb8, 0x3c, 0x19, 0x57, 0x0e, 0xed, 0x7a, 0xf5, 0x22, 0xdb, 0x0d, 0xe4, 0x89, 0xbb, 0xc8, 0x71, 0x33, 0xa1, 0x34, 0x34, 0x51, 0x8b, 0xcf, 0xb9, 0xcd, 0xa4, 0xd9, 0xf6, 0xd8, 0x32, 0xa6, 0x92, 0x09, 0x65, 0x7a, 0x44, 0x7a, 0xbf, 0x8a, 0xfd, 0x81, 0x6a, 0xe1, 0x5f, 0x31, 0x3c, 0x7e, 0xa9, 0x5e, 0xc4, 0xbc, 0x69, 0x4e, 0xfc, 0x23, 0x86, 0xcd, 0xd8, 0xd9, 0x15, 0xdc, 0x47, 0x5e, 0x8f, 0xad, 0xf3, 0x42, 0x1f, 0xbb, 0x03, 0x19, 0xa3, 0xc0, 0xb3, 0xb6, 0xdf, 0xa8, 0x0c, 0xa3, 0xbb, 0x22, 0xc7, 0xaa, 0xb0, 0x7f, 0xe1, 0x4a, 0x3f, 0xea, 0x5f, 0x0a, 0xee, 0x17, 0xab, 0x13, 0x02, 0x33, 0x8e, 0xea, 0xc0, 0x10, 0xa0, 0x4e, 0x50, 0x5e, 0x20, 0x09, 0x6a, 0x95, 0xf3, 0x34, 0x7d, 0xc2, 0xb4, 0x51, 0x0f, 0x62, 0xd6, 0xa4, 0xc1, 0xfa, 0xe6, 0xb3, 0x69, 0x39, 0x50, 0x3a, 0x6a, 0xc2, 0x27, 0x80, 0xa6, 0x2d, 0x72, 0xf2, 0xfc, 0x38, 0x49, 0xd4, 0xef, 0x21, 0x26, 0x7f, 0xff, 0xde, 0xf2, 0x31, 0x96, 0xd8, 0x8f, 0xbb, 0x9b),
+      //   tag: vec!(0x45, 0x7c, 0xce, 0x6e, 0x07, 0x5f, 0xfd, 0xb1, 0x80, 0x76, 0x5a, 0xb2, 0xe1, 0x05, 0xc7, 0x07)
+      // },
+      // TestVector{
+      //   key: [0xbd, 0x68, 0xff, 0x5e, 0xb2, 0x96, 0xc7, 0x1c, 0xfe, 0x6b, 0xc9, 0x03, 0xc1, 0x49, 0x07, 0xf7, 0x72, 0x6b, 0xcb, 0x13, 0x31, 0xf0, 0xc7, 0x5f, 0x78, 0x01, 0xcd, 0x1b, 0x79, 0x48, 0xf3, 0xa1],
+      //   nonce: [0x65, 0xa7, 0x48, 0x00, 0x4b, 0x35, 0x2b, 0xa6],
+      //   plain_text: vec!(0x52, 0xbf, 0x78, 0xc0, 0x0f, 0x6e, 0x5d, 0xca, 0x2f, 0xc6, 0x0e, 0x2e, 0x9a, 0x52, 0xe8, 0x27, 0xdf, 0x97, 0x80, 0x8e, 0x9c, 0xf7, 0x27, 0x77, 0x38, 0x60, 0xca, 0xfc, 0x89, 0xf4, 0xb6, 0x41, 0x78, 0xa1, 0x9b, 0x30, 0xb4, 0x6e, 0xd8, 0x13, 0xfe, 0x00, 0xc8, 0xf0, 0x9b, 0x25, 0xa6, 0xa1, 0xb6, 0xe3, 0x50, 0xd5, 0xb0, 0x05, 0x12, 0x29, 0x34, 0xa5, 0x9b, 0xfb, 0xd5, 0xe6, 0xe0, 0xc6, 0x35, 0xc8, 0x4a, 0x52, 0x26, 0xc3, 0xf2, 0xf7, 0xdc, 0xf9, 0x51, 0x56, 0x0f, 0x18, 0xac, 0x22, 0x04, 0x53, 0xd5, 0x83, 0x01, 0x5f, 0xdb, 0x2e, 0x44, 0x6c, 0x69, 0xc6, 0xe6, 0xfd, 0xec, 0xf2, 0xe5, 0x95, 0xe0, 0x4f, 0xab, 0x1b, 0x0c, 0x50, 0x6e, 0x3c, 0x6b, 0xd5, 0xe4, 0x41, 0x4a, 0x35, 0xf1, 0x50, 0x21, 0xe9, 0x7f, 0x44, 0x7a, 0xa3, 0x34, 0xf5, 0x4a, 0x8f, 0x1e, 0xf9, 0x42, 0xde, 0xc6, 0x27, 0x35, 0x11, 0xb5, 0x66, 0x8b, 0x69, 0x6f, 0xca, 0x97, 0x18, 0x8f, 0xf1, 0x5e, 0xd8, 0x4b, 0x2f, 0x46, 0x14, 0x5c, 0xce, 0x03, 0x1c, 0x1a, 0x7f, 0x00, 0xbd, 0x88, 0xbb, 0x83, 0xd9, 0x07, 0x97, 0xed, 0xc4, 0x61, 0x61, 0xb3, 0xfd, 0xa7, 0xa2, 0x29, 0x91, 0x73, 0x49, 0x6d, 0x73, 0xb8, 0x12, 0x13, 0x95, 0x56, 0xe8, 0xb4, 0xeb, 0x31, 0x80, 0x78, 0xb9, 0xeb, 0x2a, 0xe5, 0x04, 0x6e, 0x83, 0xb7, 0x9d, 0xd3, 0xd4, 0x59, 0x50),
+      //   aad: vec!(0x55, 0x57, 0xb0, 0x8a, 0x50, 0x10, 0xcb, 0xc9, 0xf4, 0x6b, 0xb1, 0x40, 0xc2, 0x50, 0x5f, 0x68, 0x68, 0x4e, 0xb2, 0x48, 0x89, 0x32, 0x4b, 0xff, 0x44, 0xb2, 0x72, 0x34, 0xfd, 0x7a, 0x95, 0xa9, 0x9c, 0xfb, 0x4f, 0xf9, 0x0a, 0x8f, 0x99, 0x82, 0x08, 0x5b, 0x72, 0x5f, 0x78, 0xac, 0x42, 0xec, 0xa6, 0xce, 0x7f, 0x33, 0x14, 0xe4, 0x57, 0xdc, 0x41, 0xf4, 0x04, 0x00, 0x86, 0x81, 0xa9, 0xd2, 0x9b, 0xa7, 0x65, 0x66, 0x0d, 0xe2, 0xe0, 0x5b, 0xb6, 0x79, 0xd6, 0x5b, 0x81, 0xf5, 0xe7, 0x97, 0xd8, 0x41, 0x7b, 0x94, 0xeb, 0x9a, 0xab, 0xbd, 0x05, 0x76, 0xb5, 0xc5, 0x7f, 0x86, 0xea, 0xe2, 0x5f, 0x60, 0x50, 0xa7, 0x91, 0x8e, 0x4c, 0x80, 0x21, 0xa8, 0x5b, 0x47, 0xf7, 0xa8, 0x3b, 0x4c, 0x84, 0x46, 0x89, 0x84, 0x41, 0xc5, 0xcc, 0x4e, 0x02, 0x29, 0x77, 0x6e, 0xf3, 0xe8, 0x09, 0xcb, 0x08, 0x5d, 0x71, 0xf3, 0xc7, 0x5e, 0xc0, 0x33, 0x78, 0x73, 0x0c, 0xb0, 0x66, 0x15, 0x0f, 0x07, 0xe6, 0x0f, 0x96, 0xae, 0xc9, 0x83, 0xc0, 0xe7, 0xe7, 0x2b, 0xf6, 0xbf, 0x87, 0xae, 0x42, 0x22, 0x8d, 0xfd, 0xa1, 0x95, 0xf9, 0x78, 0x55, 0xfc, 0xdf, 0x4e, 0x6d, 0x1c, 0x44, 0x79, 0xd9, 0x78, 0xab, 0xcf, 0xa2, 0x76, 0xd1, 0x6e, 0xd6, 0x0e, 0xcb, 0xfb, 0xfc, 0x66, 0x40, 0x41, 0x33, 0x5c, 0xe6, 0x5a, 0x40, 0xa2, 0xca, 0x34, 0x24, 0xdf),
+      //   cipher_text: vec!(0xa5, 0xc8, 0xcf, 0x42, 0x28, 0x7d, 0x47, 0x60, 0xfc, 0xa7, 0x55, 0xe2, 0x11, 0x18, 0x17, 0xb9, 0x81, 0xc4, 0x7e, 0x85, 0xb0, 0x04, 0x7d, 0xe2, 0x70, 0xec, 0x30, 0x1c, 0xa5, 0xf7, 0xb3, 0x67, 0x9f, 0x47, 0x49, 0x21, 0x08, 0x92, 0xb6, 0xea, 0x65, 0x68, 0xf3, 0xa6, 0xa4, 0x34, 0x47, 0x34, 0xa0, 0xef, 0xc0, 0x12, 0x0f, 0xfe, 0xde, 0xcf, 0x21, 0x2d, 0x55, 0xcb, 0xcb, 0xb6, 0x78, 0x15, 0xac, 0x96, 0x48, 0x75, 0xaf, 0x45, 0xf7, 0x35, 0xb7, 0x00, 0x92, 0xa8, 0xf8, 0x43, 0x5f, 0x52, 0xfc, 0x01, 0xb9, 0x81, 0xae, 0x97, 0x1d, 0x48, 0x60, 0x26, 0xfb, 0x69, 0xa9, 0xc3, 0x92, 0x7a, 0xcf, 0xe1, 0xf2, 0xea, 0xb0, 0x34, 0x0a, 0xe9, 0x5f, 0x8d, 0xbe, 0xe4, 0x1b, 0x25, 0x48, 0xe4, 0x00, 0x80, 0x5e, 0xce, 0x19, 0x1d, 0xb5, 0xfd, 0x1f, 0x08, 0x04, 0x05, 0x3f, 0x1d, 0xbf, 0xaf, 0x7f, 0x8d, 0x6f, 0xde, 0xd3, 0x87, 0x4c, 0xb9, 0x2d, 0x99, 0xa2, 0x72, 0x9d, 0x3f, 0xaa, 0xa6, 0x05, 0x22, 0x06, 0x0c, 0xf0, 0xb8, 0x10, 0x1b, 0x46, 0x3b, 0x3e, 0xb3, 0x5b, 0x38, 0x0f, 0xcd, 0xdb, 0x64, 0x06, 0xc0, 0x27, 0xd7, 0x3f, 0xe7, 0x01, 0xa5, 0x09, 0x0c, 0x8d, 0xd5, 0x31, 0xc2, 0x03, 0xce, 0x97, 0x9e, 0x26, 0xb9, 0xce, 0xd3, 0x43, 0x1e, 0x2b, 0x72, 0x6a, 0x72, 0x44, 0xa2, 0x0d, 0x93, 0x77, 0xbd, 0x62, 0x95, 0x1b, 0xf5),
+      //   tag: vec!(0x45, 0x79, 0xfa, 0x1f, 0xdb, 0x4c, 0x67, 0x4c, 0xc3, 0xcd, 0x23, 0x2b, 0x8d, 0xa5, 0x2a, 0x97)
+      // },
+      // TestVector{
+      //   key: [0x93, 0x4f, 0xd0, 0x43, 0xc3, 0x2d, 0x16, 0xa8, 0x8f, 0xad, 0x01, 0xc3, 0x50, 0x64, 0x69, 0xb0, 0x77, 0xcb, 0x79, 0xd2, 0x58, 0xb5, 0x66, 0x4f, 0xa5, 0x5a, 0xd8, 0x52, 0x1a, 0xfd, 0xca, 0xa2],
+      //   nonce: [0xc7, 0x09, 0x1f, 0x6a, 0xfb, 0xbe, 0xb3, 0x60],
+      //   plain_text: vec!(0x2b, 0xdd, 0x1f, 0xc4, 0xf0, 0x11, 0xef, 0x97, 0xea, 0x52, 0xec, 0x64, 0x38, 0x19, 0x94, 0x1c, 0x7e, 0x0f, 0xb3, 0x90, 0x23, 0xc2, 0xf3, 0xc7, 0x68, 0x38, 0x04, 0xa0, 0xdd, 0xee, 0x14, 0xa5, 0xd1, 0x78, 0x4a, 0x52, 0x46, 0x96, 0x6d, 0x53, 0x3b, 0x35, 0x38, 0xed, 0xc7, 0xd8, 0x74, 0x2d, 0x27, 0x06, 0x1c, 0x3c, 0xab, 0x88, 0xdf, 0x03, 0x18, 0xab, 0x24, 0x21, 0x02, 0xde, 0x3a, 0x54, 0xd0, 0x36, 0x32, 0xee, 0xb8, 0x71, 0xb7, 0x2c, 0x7e, 0x8f, 0x80, 0x65, 0xb4, 0x9f, 0x4a, 0x91, 0xe9, 0x5e, 0x15, 0xf3, 0xf4, 0x6b, 0x29, 0xfd, 0x76, 0xb8, 0xfc, 0xea, 0x0d, 0x23, 0x57, 0x0c, 0x55, 0x30, 0xe3, 0xbb, 0xb8, 0xa6, 0xaa, 0xfa, 0x9a, 0xe3, 0x2c, 0x1b, 0x3e, 0xac, 0x65, 0x3c, 0x5e, 0xd5, 0xfd, 0xb2, 0xda, 0x5a, 0x98, 0x60, 0x75, 0x80, 0x8f, 0x63, 0x85, 0x87, 0x0c, 0x85, 0xb1, 0x91, 0x3e, 0x26, 0x04, 0x2a, 0x9d, 0x8e, 0x78, 0xf5, 0xbc, 0x2e, 0xa6, 0xde, 0x5a, 0x64, 0xf8, 0xae, 0xaf, 0xa2, 0x2a, 0xdc, 0xff, 0xc7, 0xf6, 0x93, 0x2d, 0x54, 0x3c, 0x29, 0xbb, 0x3a, 0x04, 0x61, 0x47, 0x83, 0xf9, 0x48, 0x68, 0x0e, 0x43, 0x3a, 0x71, 0x57, 0x35, 0x68, 0xd2, 0xce, 0x98, 0x4d, 0x24, 0x9f, 0xb4, 0xfc, 0x06, 0xa9, 0xf3, 0x58, 0xc7, 0x6a, 0xa3, 0xe6, 0x4a, 0x35, 0x7f, 0x4e, 0xae, 0x92, 0x4c, 0x13, 0x56, 0xbd, 0x5b, 0xac, 0xcf, 0x7e, 0x0f),
+      //   aad: vec!(0xf7, 0x37, 0xdd, 0x85, 0x63, 0x8e, 0xb3, 0x24, 0xdd, 0x38, 0x91, 0x21, 0x9c, 0x5e, 0xef, 0x7c, 0x2d, 0xd0, 0x53, 0xcf, 0xd0, 0x55, 0xd4, 0x47, 0xa4, 0x11, 0xeb, 0xa3, 0x04, 0xa4, 0xb2, 0x7d, 0xce, 0x98, 0x1d, 0x11, 0x2c, 0x45, 0x40, 0x59, 0x09, 0x33, 0xc1, 0x53, 0xd6, 0x03, 0x02, 0x2c, 0x91, 0xeb, 0xd2, 0xb4, 0xa5, 0x80, 0x69, 0xd2, 0x7e, 0x6c, 0xa1, 0x7a, 0x46, 0x2e, 0xf8, 0x22, 0xca, 0x41, 0xbf, 0xfa, 0x80, 0xb4, 0x3a, 0x68, 0xb1, 0xb5, 0x64, 0x64, 0x4c, 0xb3, 0xc5, 0xa7, 0xf0, 0xfd, 0xdf, 0x7a, 0x13, 0xa3, 0x0f, 0xf2, 0x44, 0x37, 0xfd, 0xdd, 0x8e, 0xf9, 0x3c, 0x6f, 0x6f, 0x20, 0x5d, 0x05, 0x4f, 0x81, 0x89, 0x0d, 0x98, 0x2b, 0xd4, 0xd4, 0xec, 0xe0, 0xb1, 0x56, 0x36, 0x77, 0xe8, 0x43, 0xfe, 0x48, 0xc1, 0xf5, 0x4e, 0x9a, 0x57, 0xed, 0x4d, 0xa6, 0x60, 0x61, 0x48, 0x27, 0x12, 0xe7, 0x10, 0xa4, 0x01, 0x07, 0x3b, 0xe5, 0x08, 0x0d, 0x5b, 0x8b, 0x96, 0x52, 0x5b, 0xff, 0xa6, 0x7d, 0xe5, 0xaf, 0x31, 0xd5, 0x03, 0x85, 0xfb, 0xbf, 0x1a, 0x87, 0xc2, 0x1b, 0xf0, 0xe0, 0xa1, 0xfd, 0xff, 0x69, 0xec, 0x32, 0xc7, 0xb7, 0x10, 0x3e, 0x0b, 0x8e, 0xe6, 0xc8, 0x44, 0x24, 0x5e, 0x0f, 0xc8, 0x4b, 0x9f, 0x89, 0xfc, 0xce, 0x62, 0x96, 0x6c, 0xea, 0x68, 0xe2, 0x87, 0x1d, 0x3b, 0x82, 0xe8, 0xdf, 0x42, 0x4c, 0x76, 0x30, 0x9f, 0xc8, 0x8d),
+      //   cipher_text: vec!(0xdd, 0x13, 0xfb, 0xf2, 0x2c, 0x8d, 0x18, 0x35, 0x4d, 0x77, 0x4b, 0xcd, 0x18, 0xf7, 0xeb, 0x81, 0x4e, 0x9b, 0x52, 0x8e, 0x9e, 0x42, 0x4a, 0xbc, 0x4e, 0x3f, 0x24, 0x63, 0x19, 0x5e, 0x80, 0x18, 0x57, 0x65, 0x65, 0xd1, 0x6a, 0xb4, 0x88, 0x45, 0xd1, 0x1c, 0x92, 0x77, 0xf2, 0x86, 0x5e, 0xbb, 0x4d, 0xc4, 0x12, 0xfd, 0x5b, 0x27, 0x07, 0x8f, 0x83, 0x25, 0xea, 0xdf, 0x97, 0x1e, 0x69, 0x44, 0xc6, 0x65, 0x42, 0xe3, 0x4d, 0x9d, 0xda, 0x97, 0x1e, 0x2a, 0xba, 0x70, 0xdb, 0xd3, 0xe9, 0x4a, 0x1e, 0x63, 0x8d, 0x52, 0x14, 0x77, 0xa0, 0x27, 0x77, 0x6b, 0x52, 0xac, 0xf9, 0x05, 0x20, 0xca, 0x22, 0x9e, 0xbc, 0x76, 0x0b, 0x73, 0x12, 0x88, 0x79, 0x47, 0x5d, 0x1c, 0xbe, 0x1f, 0x70, 0xfc, 0x59, 0x8b, 0x54, 0x9c, 0xd9, 0x2d, 0x8a, 0x9a, 0xc6, 0x83, 0x3e, 0x50, 0x0c, 0x13, 0x8c, 0x56, 0x47, 0x4d, 0xb8, 0x4c, 0xb3, 0xd7, 0x0b, 0x7a, 0xa4, 0xf2, 0x93, 0xa4, 0xc2, 0xb4, 0xd8, 0x18, 0xb0, 0xff, 0x9f, 0xd8, 0x59, 0x18, 0xdc, 0x59, 0x0a, 0x12, 0xa8, 0xc0, 0xe3, 0x75, 0xc4, 0xd9, 0x8b, 0x7f, 0xc8, 0x75, 0x96, 0x54, 0x7e, 0xb9, 0x60, 0x67, 0x6a, 0xad, 0x55, 0x59, 0x83, 0x45, 0x88, 0xf0, 0x0f, 0x25, 0x1a, 0x9d, 0x53, 0xf9, 0x5c, 0x47, 0xaf, 0x4d, 0xf3, 0xc4, 0x29, 0x91, 0x75, 0xd5, 0x21, 0x17, 0x79, 0xc1, 0x48, 0xcf, 0xc9, 0x88, 0xa5, 0xe9, 0xd9),
+      //   tag: vec!(0x47, 0x66, 0x16, 0xea, 0x15, 0x19, 0x0c, 0x10, 0x93, 0xfd, 0xc4, 0xa0, 0x87, 0x64, 0x3c, 0xae)
+      // },
+      // TestVector{
+      //   key: [0xf9, 0xf6, 0xeb, 0x9a, 0xd7, 0x36, 0xa8, 0xf6, 0x6e, 0x74, 0x59, 0xfe, 0xf5, 0xec, 0x28, 0x90, 0x18, 0x8d, 0xc2, 0x6b, 0xaf, 0x34, 0xa9, 0x5f, 0x6f, 0x03, 0x84, 0xe7, 0x9f, 0x5c, 0x65, 0x59],
+      //   nonce: [0x78, 0x58, 0xdf, 0xc0, 0x84, 0xfe, 0x4b, 0x0f],
+      //   plain_text: vec!(0xa6, 0x44, 0xca, 0x6e, 0x7c, 0xc0, 0x76, 0xe8, 0x7e, 0xb2, 0x92, 0x9f, 0xd2, 0x57, 0x69, 0x3f, 0xce, 0x0f, 0x6f, 0xb6, 0x4f, 0xd6, 0x32, 0xf7, 0xf0, 0x7c, 0x64, 0x8e, 0xbd, 0x03, 0x69, 0x6c, 0x8e, 0x26, 0x2e, 0x6a, 0x81, 0x0d, 0x7b, 0x7c, 0x4e, 0x5e, 0xef, 0x8c, 0x65, 0xb5, 0x32, 0x3c, 0x99, 0xdb, 0xba, 0x50, 0xa7, 0x0b, 0x4a, 0x9e, 0x5c, 0x2a, 0x9e, 0x73, 0x15, 0x97, 0x3c, 0xd6, 0x7f, 0x35, 0xd8, 0x05, 0x2c, 0xe9, 0xa8, 0x5a, 0x20, 0x64, 0x16, 0xdd, 0x30, 0x31, 0x92, 0x9f, 0x4f, 0x92, 0x9b, 0x13, 0xd0, 0xa5, 0xfb, 0x10, 0xcb, 0x73, 0xc6, 0x5f, 0x6c, 0x0a, 0xce, 0x01, 0x9d, 0xa1, 0x46, 0xb5, 0x1c, 0x52, 0x74, 0xa0, 0x99, 0xf4, 0x4e, 0x36, 0x69, 0xd2, 0x6a, 0xdd, 0x6f, 0x2f, 0xf0, 0x81, 0xe8, 0x86, 0xf3, 0xcf, 0x95, 0x2f, 0xe0, 0xdb, 0xbe, 0x6b, 0x05, 0x34, 0xc2, 0x3e, 0x30, 0x75, 0x74, 0xbd, 0x35, 0xfb, 0xd6, 0x57, 0xf5, 0xfc, 0xbd, 0x5d, 0xc1, 0x9f, 0xb3, 0x82, 0xa1, 0xdc, 0x0a, 0x2d, 0xc8, 0x28, 0x5a, 0x03, 0x50, 0xf7, 0x15, 0x54, 0xe4, 0xc6, 0x01, 0x49, 0x77, 0x49, 0xe3, 0x55, 0x67, 0xdd, 0x4a, 0x27, 0x3c, 0xdd, 0xc9, 0xa4, 0x8c, 0xe5, 0x3a, 0x5f, 0x1d, 0x29, 0x7f, 0xd8, 0xba, 0xf8, 0xd1, 0xb9, 0xfe, 0xb3, 0x5d, 0x91, 0x51, 0x11, 0x43, 0x45, 0xab, 0xad, 0xa4, 0xd9, 0x0d, 0xb9, 0x47, 0xbb, 0x9a, 0x74, 0x3c, 0x17, 0x5f, 0x56, 0x53, 0xd1),
+      //   aad: vec!(0x20, 0x48, 0xd1, 0xc2, 0xdd, 0xfb, 0x5e, 0xc3, 0x85, 0xb2, 0x01, 0x83, 0x2c, 0x7a, 0x99, 0x3f, 0x22, 0x9b, 0xa7, 0x2e, 0xc1, 0x6d, 0x6e, 0xbf, 0x72, 0x3e, 0xf0, 0xc5, 0x03, 0x2b, 0x99, 0x66, 0x20, 0x9a, 0x9e, 0x8a, 0x63, 0x15, 0x1b, 0x40, 0x41, 0x2e, 0x96, 0xb8, 0x2f, 0x86, 0x72, 0x8e, 0xa6, 0x58, 0x8c, 0x7e, 0x8e, 0x11, 0xac, 0x71, 0xcc, 0x8e, 0xab, 0xab, 0x8c, 0x4b, 0x54, 0xde, 0x86, 0x66, 0x58, 0xd9, 0xc5, 0x01, 0x1d, 0xef, 0x61, 0xfb, 0x3d, 0xbe, 0x4e, 0x63, 0x01, 0x58, 0xa4, 0x5e, 0xa4, 0x1a, 0x2e, 0xd5, 0x5e, 0xbd, 0x1e, 0xfb, 0x1a, 0xbe, 0xda, 0x76, 0x37, 0xde, 0x6f, 0xa5, 0xfd, 0x2f, 0x15, 0x1c, 0x6d, 0x2f, 0x38, 0x5b, 0xf6, 0xcd, 0x00, 0x2c, 0xa8, 0xb4, 0xa2, 0x89, 0x6e, 0x0d, 0x65, 0x94, 0x4e, 0xe9, 0x13, 0xe3, 0xc7, 0x84, 0x66, 0x9d, 0xd2, 0x01, 0xb1, 0x98, 0x5e, 0xf3, 0x57, 0x7f, 0x7f, 0x12, 0x3a, 0x5f, 0x9b, 0xcf, 0xfa, 0x17, 0x6c, 0x8f, 0x55, 0x7c, 0x4f, 0x72, 0x91, 0x33, 0xca, 0xc5, 0x18, 0x64, 0x2f, 0x27, 0xd9, 0xb2, 0x2c, 0xa9, 0xb9, 0x7f, 0xaa, 0xaf, 0xe5, 0xb6, 0x69, 0xa1, 0x0b, 0x79, 0xac, 0xe4, 0xa7, 0xd5, 0x72, 0x7d, 0xf1, 0x46, 0xc7, 0x7c, 0xe6, 0x81, 0x35, 0x7d, 0x69, 0xf9, 0xc2, 0xd6, 0x5b, 0x44, 0x01, 0xbd, 0x73, 0xcd, 0x11, 0x33, 0x87, 0xe3, 0xb3, 0xa0, 0x5d, 0x89, 0x7a, 0xda, 0xd7, 0xa2, 0x4c, 0x48, 0x5e, 0x7b),
+      //   cipher_text: vec!(0x41, 0x46, 0xfa, 0xff, 0xd7, 0x31, 0x3f, 0x5d, 0x9f, 0x62, 0x53, 0x70, 0xd2, 0x04, 0x13, 0xcc, 0x62, 0xab, 0x65, 0xf4, 0xac, 0xfa, 0x3c, 0x7e, 0xe1, 0x12, 0x5b, 0x93, 0x7d, 0xd7, 0xa3, 0x9f, 0x63, 0x8f, 0xc4, 0x6c, 0x8e, 0xd0, 0x04, 0xfb, 0x52, 0x56, 0x98, 0xde, 0x5d, 0x86, 0x20, 0xec, 0x15, 0x34, 0x35, 0x57, 0x18, 0x17, 0xc3, 0xde, 0x25, 0x7b, 0x0d, 0x0e, 0x64, 0x8e, 0xbb, 0x92, 0x94, 0x0c, 0x86, 0xa9, 0x82, 0x62, 0xd5, 0x4e, 0x76, 0x4f, 0x28, 0xcb, 0xdd, 0x4f, 0x7d, 0x9b, 0xea, 0x97, 0x02, 0x91, 0xf2, 0x11, 0x04, 0x14, 0xf6, 0x20, 0x64, 0xd7, 0x22, 0x9c, 0x63, 0x32, 0x23, 0x6c, 0x50, 0x7b, 0x3d, 0xac, 0x74, 0x2e, 0x65, 0x1d, 0x85, 0xa2, 0xa2, 0x2f, 0xb2, 0x43, 0xc0, 0xcc, 0x7c, 0xc2, 0xd0, 0x16, 0xe5, 0xbe, 0xa3, 0x8f, 0x33, 0xf9, 0xa9, 0xce, 0x04, 0x89, 0x44, 0xa5, 0xfe, 0x8b, 0x07, 0x8d, 0x71, 0xd2, 0x31, 0x68, 0xe1, 0x2d, 0xfe, 0x5a, 0x0f, 0x0b, 0x82, 0x97, 0x71, 0xed, 0xc7, 0x07, 0x3f, 0xb9, 0x60, 0x32, 0xb7, 0xbe, 0x47, 0x13, 0x37, 0xa3, 0x7a, 0xca, 0x0c, 0xf7, 0xc0, 0xcd, 0xd5, 0x43, 0xee, 0xd6, 0x86, 0xcd, 0x34, 0x93, 0x47, 0x17, 0xfd, 0x79, 0xa3, 0xf1, 0x84, 0x92, 0xee, 0xf7, 0x2f, 0x9f, 0x45, 0x0b, 0x88, 0x0a, 0xa7, 0xe2, 0xe1, 0xb6, 0x5e, 0x3b, 0x04, 0xc2, 0x2e, 0x72, 0x30, 0x13, 0x38, 0xb4, 0x3a, 0xa3, 0x2c, 0xee, 0xc2, 0xe6),
+      //   tag: vec!(0x10, 0xff, 0xaf, 0x2b, 0xe3, 0x16, 0x67, 0x6d, 0xa0, 0x2d, 0x74, 0x73, 0xa9, 0xdf, 0x87, 0xb9)
+      // },
+      // TestVector{
+      //   key: [0x29, 0xb1, 0x96, 0x36, 0xcd, 0xd3, 0x25, 0x07, 0xfd, 0x98, 0xec, 0x4e, 0xe2, 0x6c, 0xaa, 0xb1, 0xa9, 0x17, 0x64, 0x6f, 0xb8, 0xf0, 0x5b, 0x0d, 0xc0, 0x17, 0x28, 0xa9, 0xf4, 0xa1, 0x27, 0xf0],
+      //   nonce: [0x06, 0x69, 0x9d, 0x24, 0x59, 0x16, 0x68, 0x6d],
+      //   plain_text: vec!(0x5f, 0xdf, 0x91, 0x3a, 0xce, 0xab, 0x1d, 0x6d, 0xba, 0xf7, 0xd9, 0xa2, 0x93, 0x52, 0xfa, 0x8a, 0x3e, 0xb2, 0x27, 0x18, 0x04, 0x3a, 0x79, 0xcf, 0xfa, 0x2f, 0xe8, 0xc3, 0x5c, 0x82, 0x0a, 0xec, 0x7c, 0x07, 0x64, 0x4b, 0x87, 0x85, 0xdc, 0xf7, 0xa4, 0x33, 0xb4, 0x18, 0x9a, 0xbb, 0x25, 0x7f, 0xb1, 0x2b, 0x06, 0xfa, 0xe0, 0x66, 0x26, 0x41, 0x01, 0x1a, 0x06, 0x98, 0x73, 0xc3, 0xe3, 0xc5, 0xcc, 0xc7, 0x8e, 0x73, 0x58, 0x18, 0x4a, 0x62, 0xc2, 0x00, 0x5c, 0x44, 0xb8, 0xa9, 0x22, 0x54, 0x95, 0x8e, 0xb5, 0xff, 0x46, 0x0d, 0x73, 0xcd, 0x80, 0x28, 0x4d, 0x6d, 0xab, 0xa2, 0x2c, 0x3f, 0xab, 0xa0, 0x46, 0xc5, 0x42, 0x6f, 0xe8, 0xb7, 0xca, 0xce, 0xc6, 0x4b, 0x23, 0x5a, 0x8f, 0x8d, 0x3e, 0x26, 0x41, 0xe5, 0xbc, 0x37, 0x88, 0x30, 0x59, 0x4b, 0xcf, 0xb2, 0x7c, 0x17, 0x7a, 0xea, 0x74, 0x59, 0x51, 0xee, 0x57, 0x80, 0xa6, 0x37, 0x05, 0x72, 0x7e, 0xf4, 0x2c, 0x4a, 0xd3, 0xab, 0xf5, 0x56, 0xd8, 0x8e, 0x38, 0x30, 0xf3, 0xdb, 0x6b, 0x09, 0xe9, 0x3e, 0xdd, 0x09, 0x48, 0x5c, 0xbf, 0x90, 0x7f, 0x79, 0xde, 0x61, 0xf8, 0xdc, 0x5c, 0xb5, 0xfb, 0x76, 0x65, 0xff, 0xa0, 0xef, 0x53, 0xcb, 0x48, 0x70, 0x2f, 0x6a, 0x81, 0xd8, 0xad, 0x42, 0x1c, 0xef, 0x20, 0xc1, 0xdb, 0xdf, 0x40, 0x2b, 0x8f, 0xaf, 0xed, 0x56, 0xa5, 0x36, 0x1b, 0x2f, 0x93, 0xf9, 0x14, 0xa2, 0x38, 0x0f, 0xdd, 0x05, 0x57, 0xfa, 0xf1, 0xf4, 0xde),
+      //   aad: vec!(0x39, 0x11, 0x6c, 0x49, 0xcc, 0x13, 0xad, 0xb0, 0x65, 0xb9, 0x2c, 0xb7, 0x63, 0x5f, 0x73, 0xd5, 0xf6, 0xbf, 0x6b, 0x5c, 0xcb, 0xf7, 0x2a, 0x3f, 0x65, 0xa5, 0xdf, 0x6b, 0xd4, 0xa6, 0x61, 0x10, 0x50, 0x15, 0x35, 0x8d, 0x9e, 0x69, 0xf4, 0x2e, 0x98, 0xae, 0xd7, 0x95, 0xe8, 0x16, 0x12, 0x82, 0xbc, 0x11, 0x30, 0x58, 0xb7, 0xef, 0x3b, 0x9e, 0x23, 0xfc, 0xd8, 0xee, 0xab, 0x34, 0xa3, 0x92, 0xe0, 0x3f, 0x4d, 0x63, 0x29, 0xc1, 0x12, 0xcb, 0x96, 0x83, 0x85, 0xec, 0x52, 0xa7, 0xaf, 0xc9, 0x8b, 0xb8, 0x69, 0x57, 0x85, 0xaf, 0x6b, 0x27, 0xb7, 0x00, 0x97, 0x3c, 0xc9, 0x52, 0x63, 0x0b, 0x72, 0x47, 0xce, 0x22, 0x6b, 0x4f, 0xbb, 0x99, 0xb8, 0xa4, 0x86, 0x37, 0x0b, 0xf6, 0x34, 0x5d, 0x45, 0x16, 0xc5, 0x2c, 0x64, 0xe3, 0x3f, 0x40, 0x7c, 0x4f, 0x2d, 0x1b, 0xa9, 0x05, 0x45, 0xc8, 0x87, 0x32, 0xd9, 0x8b, 0xbd, 0x97, 0x97, 0x2a, 0xc5, 0xe9, 0x4c, 0x69, 0x46, 0x24, 0xa9, 0xb3, 0x78, 0x2b, 0x00, 0x99, 0x82, 0x46, 0x51, 0xcb, 0x75, 0x67, 0x91, 0x4d, 0x25, 0xb3, 0xe1, 0x31, 0x81, 0xa7, 0x91, 0xdb, 0xcd, 0x40, 0xe7, 0x6e, 0x83, 0x6b, 0x33, 0x50, 0xd3, 0x10, 0xa5, 0x21, 0x51, 0xbf, 0x83, 0x5d, 0x3c, 0x35, 0x7c, 0x98, 0x71, 0x48, 0x2c, 0x29, 0x28, 0xe8, 0x40, 0x4c, 0x6e, 0x53, 0x34, 0x06, 0xd4, 0xd6, 0xfa, 0x8f, 0x63, 0x36, 0x6f, 0x2c, 0x4e, 0xd8, 0x28, 0x14, 0x1f, 0x1f, 0xf0, 0x0f, 0x01, 0xa5, 0x36),
+      //   cipher_text: vec!(0x01, 0xe2, 0x37, 0x22, 0x0b, 0x61, 0x90, 0x54, 0xa1, 0xf3, 0x67, 0x09, 0x28, 0xfe, 0x67, 0xd4, 0x04, 0x84, 0xb5, 0xaf, 0x40, 0xfb, 0xd0, 0x4d, 0x03, 0x25, 0x00, 0xaa, 0xc5, 0xac, 0xaa, 0x3b, 0x45, 0x84, 0xdd, 0x99, 0xa5, 0x8c, 0x39, 0x06, 0x27, 0x63, 0x6a, 0x50, 0xde, 0x5d, 0x74, 0x4f, 0x76, 0xa5, 0x6a, 0x33, 0x20, 0x5f, 0x9e, 0x3b, 0x00, 0xe1, 0x61, 0x62, 0xeb, 0x47, 0xff, 0x33, 0x33, 0xe1, 0xe2, 0x08, 0xca, 0x20, 0x0f, 0x1a, 0x53, 0x38, 0xa8, 0x6e, 0x17, 0xbd, 0x92, 0xdd, 0x2d, 0x16, 0xaf, 0x8b, 0xb0, 0x22, 0xa7, 0xdc, 0x05, 0xb9, 0x23, 0xd0, 0x19, 0xe0, 0x52, 0x47, 0xf1, 0xa0, 0xd0, 0xb4, 0xbf, 0xcf, 0xce, 0x58, 0xdd, 0x6d, 0x83, 0x83, 0x07, 0x05, 0x70, 0x76, 0x76, 0xd5, 0x57, 0x39, 0xab, 0xee, 0x89, 0xfc, 0xd5, 0xcb, 0x94, 0xb8, 0xfd, 0xe0, 0x06, 0xa5, 0xda, 0x02, 0xdf, 0x64, 0xb0, 0x0a, 0x46, 0x7f, 0x45, 0x97, 0x0b, 0x5c, 0xa4, 0x40, 0xf2, 0x23, 0x19, 0xb9, 0x73, 0x5a, 0x55, 0xd4, 0x54, 0xb9, 0xfb, 0xa0, 0x58, 0x8f, 0xef, 0x0c, 0x59, 0xd3, 0xd8, 0x38, 0x23, 0xeb, 0xa6, 0xe0, 0x60, 0x1a, 0x96, 0xe1, 0x02, 0x33, 0x82, 0x6c, 0x5a, 0xde, 0xea, 0x6b, 0x2a, 0x51, 0xd3, 0x86, 0xa0, 0x7a, 0x9e, 0x04, 0x7a, 0xd4, 0x05, 0xb2, 0x3d, 0x4c, 0x3d, 0x89, 0xf3, 0x0c, 0x31, 0xe3, 0x19, 0x9f, 0x0c, 0x8f, 0x92, 0x7b, 0xfa, 0xc4, 0x3c, 0xee, 0xa1, 0xf9, 0x69, 0xde, 0x0a, 0x8c, 0x0f),
+      //   tag: vec!(0x09, 0x2f, 0x9f, 0x3c, 0x5d, 0x4f, 0x25, 0x70, 0xc9, 0x94, 0x6c, 0x87, 0x96, 0x7f, 0x45, 0x79)
+      // },
+      // TestVector{
+      //   key: [0xba, 0xe0, 0x6b, 0x9b, 0x54, 0x56, 0x70, 0x75, 0x51, 0xc7, 0xb0, 0xe2, 0x07, 0xaa, 0xe0, 0x2a, 0x19, 0xb4, 0x84, 0x8a, 0xd8, 0xca, 0x4c, 0xe4, 0x07, 0x05, 0xbf, 0x8c, 0x85, 0x6a, 0x6e, 0x52],
+      //   nonce: [0x9c, 0x27, 0x06, 0x5c, 0x3e, 0xf2, 0xd5, 0x22],
+      //   plain_text: vec!(0x50, 0xcd, 0xd8, 0x81, 0x37, 0xff, 0x42, 0x8a, 0x88, 0xe8, 0x7b, 0x58, 0x45, 0xbe, 0x49, 0x24, 0xf6, 0x38, 0x75, 0x37, 0xbb, 0x5c, 0x0b, 0x65, 0x4c, 0x80, 0x10, 0x7a, 0xb5, 0x69, 0x8d, 0xb7, 0x5b, 0x2e, 0x13, 0x18, 0x48, 0xe7, 0xae, 0xc1, 0x56, 0xd3, 0x1a, 0xed, 0x07, 0x66, 0xd3, 0x1c, 0x37, 0x9f, 0xec, 0xe4, 0x09, 0x5d, 0x38, 0x26, 0x4c, 0x6d, 0x59, 0x45, 0x97, 0x4d, 0x25, 0xf7, 0x29, 0xc3, 0xb0, 0xba, 0x11, 0xea, 0x85, 0x3e, 0x9c, 0xeb, 0xdb, 0x6f, 0x03, 0xbb, 0x67, 0x0f, 0xce, 0x08, 0xad, 0xff, 0x74, 0xd0, 0xa8, 0xf0, 0x2d, 0x63, 0x3f, 0xb3, 0x4e, 0x0f, 0xb7, 0x33, 0x7a, 0x8e, 0x66, 0xe1, 0xc1, 0x20, 0x84, 0xd9, 0x14, 0xfb, 0x61, 0x73, 0xb8, 0x10, 0x56, 0x84, 0xdb, 0x82, 0x27, 0x52, 0xc6, 0x75, 0x1a, 0x37, 0x2b, 0xb1, 0x66, 0x90, 0x28, 0x4d, 0x66, 0x1b, 0x8b, 0x8b, 0xc6, 0xa6, 0xdf, 0xbd, 0xdf, 0x45, 0xeb, 0xc2, 0x21, 0x95, 0x96, 0xf9, 0xf2, 0xf8, 0x78, 0xc1, 0x18, 0xdf, 0x69, 0x03, 0x0d, 0xe3, 0x8b, 0x4d, 0x99, 0xdd, 0xe4, 0x3b, 0x9b, 0x9e, 0x20, 0xa3, 0xda, 0xb6, 0x91, 0x64, 0x5d, 0xd5, 0x18, 0x34, 0x2f, 0x49, 0xb0, 0x6a, 0x0f, 0xe0, 0xa3, 0x97, 0xad, 0xf2, 0x61, 0xe9, 0x9f, 0x07, 0xaf, 0x5b, 0x0b, 0x37, 0x98, 0xb1, 0x02, 0x2b, 0xa0, 0x93, 0x9c, 0x42, 0xa5, 0x4d, 0x3b, 0x93, 0x64, 0x1c, 0xff, 0xa3, 0xc2, 0xe1, 0x74, 0xbc, 0xe9, 0xab, 0x7a, 0xd7, 0xe7, 0xc7, 0x92, 0x43, 0x08, 0xd1, 0xa7, 0x7a),
+      //   aad: vec!(0x5d, 0x55, 0x90, 0xdb, 0x1b, 0xd3, 0x16, 0xeb, 0x7a, 0x0e, 0x30, 0xe4, 0xc7, 0xa6, 0xdf, 0xdb, 0xef, 0x9d, 0x32, 0x87, 0xfd, 0xb8, 0xd8, 0x24, 0x38, 0x95, 0x99, 0xc3, 0xc2, 0xee, 0x26, 0x2b, 0x21, 0x92, 0xeb, 0x5b, 0x97, 0x08, 0xe6, 0x6e, 0x22, 0xdb, 0xc7, 0xec, 0xa8, 0x3f, 0xa1, 0xa9, 0x95, 0xda, 0x3c, 0xe6, 0x4c, 0x86, 0xfe, 0x5a, 0xa0, 0x8b, 0x82, 0x6d, 0x47, 0x6d, 0xc4, 0x39, 0x49, 0x7e, 0x2d, 0x12, 0xe2, 0x70, 0x2c, 0x63, 0xc8, 0xd2, 0x7a, 0xa7, 0xf0, 0x9f, 0xed, 0xee, 0x81, 0x6d, 0xc8, 0xbf, 0xfe, 0x13, 0x51, 0xd5, 0x32, 0x71, 0xa3, 0x4d, 0x42, 0x92, 0xb6, 0x13, 0xb7, 0xef, 0xce, 0xdb, 0x7e, 0x3c, 0xf3, 0xe6, 0xad, 0x38, 0x9e, 0xef, 0x12, 0x47, 0x1e, 0x9e, 0x20, 0xe3, 0x8e, 0x7a, 0xe2, 0x2a, 0x32, 0x3a, 0xbb, 0xad, 0xfe, 0x8f, 0x2e, 0x84, 0x27, 0x1b, 0xff, 0xb1, 0x81, 0x9f, 0xeb, 0x4f, 0x77, 0xb8, 0x28, 0x43, 0xcb, 0x87, 0x57, 0xcf, 0xae, 0x29, 0x36, 0x31, 0xbc, 0x6d, 0x39, 0x66, 0x91, 0x07, 0xe7, 0x01, 0x5c, 0x85, 0xd7, 0x34, 0x3f, 0xfa, 0x6f, 0xc1, 0xbb, 0xe6, 0xf5, 0xab, 0x4d, 0xe3, 0x0c, 0xd7, 0x52, 0xa2, 0x81, 0xe0, 0x30, 0x61, 0xea, 0x89, 0xde, 0x2a, 0x3f, 0x5e, 0x90, 0xe2, 0x0d, 0xa2, 0x2f, 0xd6, 0xe8, 0x52, 0x5c, 0x10, 0x07, 0x38, 0x66, 0x7f, 0x42, 0x21, 0x2b, 0x2c, 0xf4, 0x5f, 0xcb, 0x23, 0xbb, 0xb5, 0x4b, 0x21, 0xc1, 0x17, 0x48, 0x4b, 0x22, 0xc6, 0xe5, 0x14, 0x68, 0x53, 0x14, 0xdf),
+      //   cipher_text: vec!(0x66, 0xb7, 0xf6, 0x9a, 0xc4, 0x9f, 0xab, 0x4e, 0x59, 0x75, 0xae, 0xb6, 0xfa, 0x92, 0x87, 0xd8, 0xea, 0xc0, 0x2a, 0xc3, 0x12, 0xc4, 0xde, 0x78, 0xf7, 0x7f, 0x59, 0xda, 0x16, 0xcb, 0xcf, 0x87, 0x27, 0x4e, 0x66, 0x80, 0x1c, 0x4b, 0x86, 0x2c, 0x33, 0xea, 0x79, 0xcd, 0xc7, 0x65, 0x28, 0x86, 0x2b, 0xb2, 0x95, 0x6c, 0x06, 0xdb, 0x8b, 0x8a, 0xcf, 0xac, 0x47, 0x94, 0xeb, 0xf3, 0x9e, 0x35, 0xac, 0x03, 0xcc, 0x73, 0xa4, 0x35, 0x1a, 0x4f, 0xf7, 0x62, 0xf6, 0x81, 0xa4, 0x8d, 0x6f, 0x25, 0xca, 0xd3, 0x6e, 0x28, 0x14, 0xc9, 0xb5, 0xc4, 0x0b, 0x9a, 0xe9, 0x25, 0x09, 0xe5, 0x84, 0x29, 0x10, 0x68, 0x47, 0x78, 0x94, 0x54, 0xd3, 0x76, 0x83, 0x69, 0x36, 0xbe, 0xbc, 0x7a, 0x80, 0xe6, 0xc6, 0x6e, 0x7a, 0xa5, 0x29, 0x36, 0xd6, 0xb3, 0x61, 0x37, 0x8a, 0x41, 0xf8, 0x49, 0xad, 0x4e, 0x48, 0xf9, 0xee, 0x2d, 0x3e, 0x92, 0x21, 0x7a, 0x90, 0x8f, 0xa8, 0xeb, 0x35, 0x73, 0x6a, 0xc8, 0xad, 0xa7, 0xd3, 0x2a, 0xe0, 0x53, 0x91, 0xf2, 0xd8, 0x07, 0xbe, 0x35, 0x12, 0x54, 0x3c, 0x36, 0x13, 0x8a, 0x5f, 0xe6, 0x60, 0xdd, 0x4c, 0xd4, 0xcd, 0x18, 0x4b, 0xb4, 0x3b, 0x6b, 0xa6, 0xbc, 0x0b, 0xae, 0x63, 0x4e, 0x2f, 0xa9, 0x66, 0x93, 0x04, 0xcd, 0x51, 0x0e, 0xd5, 0x10, 0x3f, 0x63, 0x00, 0x68, 0xff, 0x76, 0xd3, 0x37, 0x57, 0x38, 0xde, 0x60, 0xa3, 0x81, 0x84, 0x2b, 0x42, 0x14, 0x77, 0xe2, 0x5a, 0x49, 0x0c, 0xdd, 0x68, 0x94, 0xb2, 0x70, 0x41, 0x25),
+      //   tag: vec!(0xc9, 0x99, 0x8a, 0x67, 0x7d, 0xfb, 0x0e, 0x91, 0x92, 0x4a, 0xec, 0x9d, 0xe0, 0xaf, 0xd5, 0x85)
+      // },
+      // TestVector{
+      //   key: [0x2c, 0xb3, 0x74, 0xcb, 0x04, 0x8c, 0x16, 0x8f, 0x2e, 0x43, 0x59, 0x7f, 0x02, 0x8d, 0x9e, 0x73, 0xca, 0xde, 0x1b, 0x45, 0x82, 0x84, 0xff, 0xc2, 0x60, 0xd4, 0xfc, 0x6b, 0x90, 0x11, 0xc4, 0x14],
+      //   nonce: [0x9f, 0xb9, 0x09, 0x16, 0x9b, 0xc9, 0xf4, 0xe9],
+      //   plain_text: vec!(0x39, 0xeb, 0x92, 0x94, 0x82, 0x78, 0x4b, 0x46, 0x35, 0x46, 0xf5, 0xd8, 0x4f, 0x80, 0x51, 0x0f, 0x20, 0x19, 0x92, 0x3d, 0x46, 0x5b, 0x99, 0xd1, 0x94, 0x24, 0x6d, 0x68, 0xc7, 0xae, 0x34, 0x3f, 0x91, 0x97, 0x1d, 0x8f, 0x70, 0x59, 0xce, 0xbb, 0x86, 0xaa, 0x5d, 0xd0, 0x99, 0x28, 0x9a, 0xa6, 0x48, 0x24, 0x8b, 0x8c, 0x5c, 0xa0, 0x4e, 0x66, 0xac, 0x5e, 0x9b, 0xf0, 0x67, 0x76, 0xe3, 0x88, 0x34, 0x95, 0x39, 0x76, 0x18, 0xa0, 0x22, 0x7f, 0x03, 0x56, 0x66, 0x80, 0x6e, 0x63, 0x68, 0x36, 0xb4, 0x7d, 0x3d, 0x2d, 0x25, 0x5a, 0x49, 0xdb, 0x79, 0x86, 0x6c, 0xf0, 0x0d, 0x9d, 0xda, 0xbd, 0xa2, 0x59, 0xc4, 0xf9, 0x68, 0xa1, 0xe0, 0x1e, 0x65, 0x1c, 0x78, 0x11, 0xce, 0xbb, 0xee, 0x2e, 0xe7, 0x18, 0x03, 0xea, 0x1d, 0x9d, 0x23, 0x48, 0x7e, 0xb2, 0x21, 0xf2, 0xd9, 0x55, 0x57, 0x56, 0x80, 0x0a, 0xba, 0x5e, 0x6a, 0xbb, 0xef, 0xd6, 0xfb, 0x72, 0xb3, 0x15, 0x1c, 0xc9, 0x9c, 0xed, 0x59, 0x9c, 0xd8, 0x6d, 0xf2, 0xa9, 0xb1, 0xce, 0x94, 0xf8, 0x9f, 0x34, 0x7e, 0xeb, 0x12, 0x4d, 0x9e, 0x7f, 0x0d, 0x9c, 0xc4, 0x8d, 0x3d, 0xed, 0xd8, 0x19, 0xe6, 0xd3, 0xdb, 0xac, 0x57, 0xec, 0xee, 0x19, 0x95, 0x47, 0xb2, 0x66, 0x11, 0x6a, 0x20, 0x35, 0xc9, 0xac, 0xc4, 0xc8, 0xca, 0x32, 0x71, 0xac, 0x74, 0x95, 0x23, 0x72, 0x89, 0x7c, 0x4a, 0x5f, 0x2c, 0xb8, 0x4e, 0x2d, 0x81, 0x81, 0x7f, 0xec, 0x9d, 0x67, 0x74, 0xf6, 0xd8, 0xa5, 0xb2, 0x02, 0x16, 0x84, 0x13, 0x2d, 0xb4, 0xfc, 0xa3),
+      //   aad: vec!(0x0c, 0x7b, 0xd4, 0xf3, 0xa3, 0x0e, 0xe9, 0x44, 0xcc, 0xf9, 0x48, 0x91, 0x81, 0xe6, 0x91, 0x16, 0x84, 0xdc, 0xff, 0xad, 0x45, 0x93, 0xa9, 0xb6, 0x5a, 0x67, 0xdf, 0xc8, 0x07, 0x18, 0xc6, 0x9b, 0x35, 0x89, 0x7d, 0x01, 0x28, 0x10, 0x16, 0xb7, 0x73, 0x1e, 0x12, 0xc1, 0x5c, 0xad, 0x84, 0x82, 0xe7, 0x94, 0x58, 0xe0, 0x8a, 0x75, 0x56, 0x22, 0xe3, 0xf3, 0xf2, 0x2a, 0x23, 0xef, 0x6c, 0x84, 0x87, 0xa3, 0x6a, 0xd1, 0x77, 0x1b, 0xa0, 0x6c, 0x64, 0x1f, 0x06, 0xf8, 0x5d, 0xe0, 0xdb, 0x37, 0x76, 0xcc, 0x6d, 0xf0, 0x6a, 0xd8, 0xfe, 0x3b, 0x4d, 0x60, 0xd5, 0x85, 0x08, 0xde, 0x94, 0x30, 0x83, 0xf1, 0x7c, 0xbb, 0x9d, 0xc0, 0xd3, 0x90, 0xac, 0x94, 0xd8, 0x42, 0x9e, 0x8c, 0x6f, 0xcf, 0xe0, 0x63, 0xf4, 0x24, 0xfb, 0xde, 0x0f, 0x62, 0xf6, 0xa7, 0xf9, 0x1a, 0x62, 0x6d, 0x19, 0x5d, 0xc4, 0x98, 0xa6, 0xe6, 0x9b, 0xd9, 0x31, 0x09, 0xc4, 0xe9, 0xba, 0x13, 0xe7, 0x33, 0x0a, 0xba, 0x45, 0x6d, 0x71, 0x0a, 0x4b, 0x0c, 0xc2, 0x79, 0xd4, 0x04, 0x56, 0x60, 0x40, 0x6e, 0x26, 0xd6, 0x1d, 0xff, 0x70, 0xd4, 0xa3, 0x3c, 0x4f, 0x10, 0x52, 0x86, 0x9f, 0x92, 0x48, 0x02, 0x4e, 0x7a, 0x0f, 0x85, 0xf1, 0xef, 0xfb, 0x32, 0xf6, 0xf7, 0xcc, 0xb1, 0xf8, 0x60, 0xf3, 0xef, 0x04, 0xe8, 0xf7, 0xb2, 0x90, 0x96, 0xe6, 0xbc, 0xf9, 0xd4, 0xb3, 0xe0, 0xce, 0x70, 0x3e, 0x9b, 0xf2, 0x28, 0xfd, 0xf5, 0x15, 0xc2, 0xff, 0x9c, 0xba, 0xbd, 0x16, 0x98, 0x7b, 0xe0, 0xf9, 0xba, 0xbd, 0x3d, 0x8a),
+      //   cipher_text: vec!(0x91, 0xdd, 0xad, 0xb8, 0x6b, 0x7e, 0xbe, 0xf7, 0x98, 0xdd, 0xaa, 0x59, 0xda, 0x51, 0xd7, 0x13, 0x16, 0xfc, 0xf6, 0xc9, 0x67, 0x81, 0x43, 0x17, 0x82, 0x27, 0xd7, 0x78, 0x75, 0x0d, 0xc9, 0x82, 0x7f, 0xc6, 0xcc, 0x21, 0xe6, 0x05, 0xc5, 0x05, 0x02, 0x3e, 0x6d, 0xb2, 0x58, 0x49, 0xdf, 0x7f, 0xb6, 0xfc, 0x1c, 0xa4, 0xd2, 0x23, 0xaa, 0x21, 0x5f, 0x8c, 0x85, 0xb7, 0x24, 0x64, 0x3c, 0x83, 0xbf, 0x82, 0x18, 0x81, 0x5a, 0x9f, 0x9e, 0x29, 0x52, 0x38, 0x4e, 0x0c, 0xa6, 0xa8, 0x0a, 0x37, 0x60, 0xb3, 0x9d, 0xaf, 0x91, 0xa3, 0xc6, 0x15, 0x4c, 0x47, 0x28, 0xc2, 0x37, 0x1f, 0xd1, 0x81, 0xfa, 0x37, 0x64, 0x75, 0x3d, 0x0b, 0x0c, 0x23, 0x80, 0x8a, 0x82, 0xcd, 0x8f, 0x04, 0x97, 0x24, 0x6e, 0x3a, 0x0f, 0x17, 0xf8, 0x90, 0x6a, 0x07, 0xc7, 0x25, 0xd2, 0x89, 0x1c, 0xe9, 0x68, 0xa9, 0xd4, 0x32, 0xc2, 0xb1, 0x02, 0xd8, 0x5c, 0x05, 0x51, 0x0b, 0x28, 0xe7, 0x15, 0xbb, 0x60, 0xd0, 0x40, 0x3a, 0x77, 0x49, 0x0e, 0x7f, 0x18, 0xbe, 0x81, 0x21, 0x8b, 0xc4, 0xf3, 0x92, 0x87, 0xb9, 0xbb, 0x09, 0xf5, 0x02, 0x27, 0xdd, 0x2f, 0x55, 0xe4, 0xfb, 0x70, 0xc4, 0x43, 0x8d, 0xa8, 0xba, 0x3c, 0x8f, 0xfb, 0xce, 0xd8, 0x7d, 0x90, 0x15, 0x59, 0x13, 0xfa, 0xa9, 0x97, 0x9f, 0xc5, 0x7e, 0x6c, 0xbe, 0xdd, 0xfa, 0xba, 0x3d, 0x3a, 0xb4, 0x16, 0x3c, 0x0e, 0xeb, 0xc7, 0xd9, 0x42, 0x79, 0xc2, 0x7d, 0x3e, 0xd5, 0x63, 0x38, 0x89, 0x3d, 0xba, 0x54, 0x2e, 0xae, 0xfb, 0xa3, 0x0f, 0x8c, 0x3b),
+      //   tag: vec!(0x72, 0x8e, 0x60, 0xf8, 0x12, 0x4e, 0xff, 0xba, 0xc2, 0x34, 0xf7, 0x0d, 0xa9, 0x25, 0x88, 0x1c)
+      // },
+      // TestVector{
+      //   key: [0xf0, 0xf1, 0x6b, 0x6f, 0x12, 0xb3, 0x84, 0x0b, 0xbd, 0x1c, 0x4a, 0x6a, 0x08, 0x11, 0xee, 0xf2, 0x37, 0xf1, 0x52, 0x1b, 0x45, 0xde, 0x99, 0x86, 0xda, 0xec, 0x9f, 0x28, 0xfc, 0xa6, 0x48, 0x5c],
+      //   nonce: [0x7a, 0xc9, 0x3e, 0x75, 0x4e, 0x29, 0x03, 0x23],
+      //   plain_text: vec!(0x05, 0x30, 0x55, 0x64, 0x24, 0xd8, 0x23, 0xf9, 0x0a, 0x7f, 0x1c, 0x52, 0x4c, 0x4b, 0xaa, 0x70, 0x6a, 0xad, 0x28, 0x07, 0xe2, 0x89, 0xe9, 0x47, 0x93, 0x01, 0xe3, 0xe7, 0xa7, 0x1f, 0x2a, 0x5e, 0x14, 0xe6, 0x23, 0x2e, 0xa7, 0x85, 0xf3, 0x39, 0xc6, 0x69, 0xaf, 0x2e, 0x6d, 0x25, 0xf1, 0xd5, 0xa2, 0x61, 0x09, 0x6a, 0x54, 0x8d, 0x23, 0x86, 0x49, 0x45, 0xc3, 0xa5, 0x89, 0xb6, 0x7b, 0x09, 0xb0, 0x30, 0x4a, 0x78, 0x4d, 0x61, 0xb4, 0x2b, 0x24, 0x19, 0x13, 0x94, 0x85, 0x24, 0x2e, 0x0d, 0x51, 0xfc, 0xbe, 0x9e, 0x8f, 0xed, 0x99, 0x6d, 0x21, 0x4d, 0xe8, 0x71, 0x7e, 0x6a, 0x71, 0xf8, 0x98, 0x7c, 0xca, 0xd6, 0x5e, 0xb9, 0x2e, 0x66, 0x70, 0x70, 0x34, 0xa5, 0xae, 0x38, 0xe6, 0x48, 0x6e, 0x26, 0xeb, 0x43, 0x74, 0xc5, 0x65, 0xaa, 0xd5, 0xdf, 0x94, 0x9d, 0xab, 0x20, 0x9f, 0x7f, 0x7b, 0xcd, 0x8e, 0xb6, 0xfc, 0x52, 0x76, 0x1a, 0x26, 0xcf, 0xe5, 0xd0, 0x1f, 0xd3, 0x49, 0xe5, 0x9f, 0x40, 0x42, 0xe6, 0xdb, 0xe6, 0xb2, 0x32, 0xf9, 0x30, 0x1b, 0x97, 0x1d, 0xee, 0x12, 0x1d, 0x8a, 0xa1, 0xe6, 0x2d, 0x40, 0xf0, 0x43, 0xa4, 0x2f, 0x3a, 0xa8, 0x59, 0xd8, 0x67, 0xeb, 0x80, 0x9b, 0x1c, 0xed, 0x5a, 0xe1, 0xec, 0x62, 0xca, 0xcf, 0x94, 0xa6, 0x9f, 0xaf, 0xd0, 0x63, 0x1a, 0x8b, 0x5d, 0xfd, 0x66, 0xd8, 0x55, 0x90, 0x0f, 0xb2, 0x95, 0xee, 0xc9, 0x0a, 0xe5, 0xfc, 0xbf, 0x77, 0xbe, 0xae, 0x26, 0x7a, 0x79, 0xd2, 0x40, 0x81, 0xbb, 0x32, 0x2d, 0x8c, 0x4e, 0x06, 0x30, 0xfe, 0xd2, 0x52, 0x54, 0x1b, 0x36),
+      //   aad: vec!(0x13, 0xbf, 0xcc, 0x17, 0xb8, 0x10, 0x09, 0x9c, 0xda, 0x31, 0xca, 0x53, 0xa1, 0x32, 0x3d, 0xb9, 0xb0, 0x76, 0x33, 0xce, 0xb2, 0x08, 0x8a, 0x42, 0x26, 0x3a, 0x4c, 0xbd, 0x6a, 0x4d, 0x47, 0x97, 0x87, 0x76, 0x00, 0x5c, 0x9a, 0x20, 0x20, 0x33, 0x19, 0xc3, 0xa3, 0xae, 0x43, 0x4e, 0x9a, 0x26, 0xfb, 0x54, 0x10, 0x47, 0xdc, 0x9d, 0xf3, 0x8d, 0xc3, 0x6c, 0x09, 0x52, 0x67, 0x27, 0x2e, 0x20, 0x3d, 0x0b, 0x24, 0xd1, 0x19, 0xa7, 0x0a, 0x7e, 0x96, 0x04, 0x1b, 0x6d, 0x82, 0xb7, 0xc4, 0xd5, 0x57, 0x0e, 0x1e, 0x4a, 0x1c, 0xf2, 0xf6, 0xe4, 0x4a, 0xe6, 0x3f, 0xe0, 0x05, 0xa1, 0xf5, 0xb9, 0x00, 0x77, 0x8c, 0x48, 0x2f, 0x7b, 0xd8, 0x9e, 0x2e, 0x02, 0x30, 0x5e, 0x35, 0xb8, 0xf6, 0x1b, 0x7b, 0xb2, 0xc7, 0x8a, 0x13, 0xae, 0xbf, 0xce, 0x01, 0x45, 0xd1, 0xc5, 0xaa, 0x0b, 0xf1, 0xd1, 0x0d, 0x23, 0x61, 0x6d, 0x5a, 0x3a, 0x44, 0x6d, 0xe5, 0x50, 0x30, 0x2f, 0x56, 0xf8, 0x1d, 0xc5, 0x6f, 0xe4, 0xf3, 0x70, 0x0f, 0x14, 0x24, 0x26, 0x88, 0xd9, 0xb9, 0x2d, 0x8a, 0x42, 0x79, 0x79, 0xb4, 0x03, 0xc8, 0xde, 0x8c, 0x49, 0x3a, 0x2c, 0xde, 0x51, 0x0e, 0xaf, 0x6b, 0x28, 0x5e, 0x66, 0x75, 0xb1, 0x73, 0xaa, 0x03, 0x14, 0xa3, 0x86, 0xb6, 0x35, 0xc7, 0x57, 0x7d, 0x5a, 0xff, 0x0d, 0x86, 0x8a, 0x0c, 0xb3, 0xf7, 0x3c, 0x8d, 0x20, 0x05, 0xf8, 0xc7, 0xc9, 0xda, 0xb5, 0xa0, 0x60, 0xef, 0x80, 0x10, 0x2c, 0x9d, 0x4a, 0x4a, 0xf9, 0x88, 0x83, 0x8a, 0xfe, 0x87, 0xaf, 0xf0, 0x4c, 0x06, 0x89, 0xe8, 0xc3, 0xc7, 0xf9),
+      //   cipher_text: vec!(0x2c, 0x14, 0xc3, 0x93, 0x1e, 0x98, 0xe8, 0x45, 0x07, 0xc4, 0xc1, 0x65, 0xc2, 0xed, 0x47, 0xad, 0x4a, 0x17, 0x8f, 0x0e, 0x21, 0x6c, 0xd7, 0xac, 0x24, 0x53, 0xbb, 0xbf, 0x9f, 0x85, 0xdd, 0x06, 0xbd, 0x8e, 0xf5, 0x4a, 0x9f, 0xf1, 0xfd, 0x3d, 0xd8, 0xe0, 0xca, 0xfb, 0x63, 0x5d, 0x8f, 0x2d, 0xe8, 0x61, 0xa0, 0xdb, 0x5b, 0x14, 0xd0, 0x3f, 0x17, 0xaa, 0xea, 0x8c, 0x89, 0xb3, 0x01, 0x07, 0x97, 0xc7, 0x1c, 0x13, 0xa0, 0xe6, 0x66, 0x89, 0x9d, 0x7f, 0xf6, 0xe5, 0x3c, 0x4f, 0x08, 0xbe, 0x8d, 0xdb, 0x3e, 0x37, 0x68, 0x8b, 0x5a, 0xfa, 0x08, 0x80, 0x79, 0xb6, 0xc7, 0x51, 0x9b, 0x83, 0x3e, 0x16, 0x56, 0x00, 0x73, 0xe6, 0x99, 0x53, 0x03, 0x02, 0x02, 0x8a, 0x34, 0x96, 0xe0, 0x5e, 0xdd, 0xde, 0xc0, 0x1a, 0x23, 0xa4, 0xc7, 0x98, 0x39, 0x56, 0x25, 0x0e, 0x8d, 0x9e, 0x61, 0x6f, 0x7b, 0x94, 0x08, 0x56, 0x95, 0x5c, 0xde, 0x81, 0xc1, 0xef, 0xab, 0xf6, 0xb7, 0xb9, 0x2f, 0x15, 0x3d, 0x03, 0xf4, 0xcd, 0x17, 0xe7, 0xf7, 0xd2, 0x90, 0x76, 0x70, 0xcf, 0xc8, 0x4d, 0x45, 0xc1, 0xd7, 0x93, 0x67, 0x75, 0xa3, 0xfc, 0xe4, 0x79, 0x68, 0x50, 0x42, 0x78, 0xff, 0xae, 0xca, 0xce, 0xa0, 0x87, 0x1b, 0x22, 0x7f, 0x25, 0x0e, 0x29, 0x79, 0x51, 0x6f, 0x6f, 0xa3, 0x10, 0xfe, 0xc0, 0xd8, 0xdf, 0x1a, 0xf7, 0x87, 0x2e, 0x5a, 0x53, 0x4e, 0x82, 0x87, 0x0a, 0xa0, 0x5f, 0x43, 0xef, 0x0a, 0x45, 0x58, 0x46, 0xb9, 0x3c, 0xe9, 0x38, 0x06, 0x4f, 0xa3, 0x3e, 0x92, 0xde, 0x26, 0x2e, 0x41, 0x56, 0xda, 0xe5, 0x67, 0x75),
+      //   tag: vec!(0xd9, 0x5d, 0x73, 0xbf, 0x9a, 0xeb, 0x71, 0xeb, 0xa9, 0x04, 0x23, 0x96, 0xf3, 0x72, 0x54, 0x24)
+      // },
+      // TestVector{
+      //   key: [0x37, 0x92, 0x94, 0x3c, 0x03, 0x96, 0xf1, 0x84, 0x04, 0x96, 0x91, 0x7c, 0xe8, 0xad, 0x89, 0x60, 0x83, 0x85, 0x00, 0x7e, 0x79, 0x6f, 0xeb, 0xee, 0xa3, 0x80, 0x5f, 0x3f, 0x4c, 0xbe, 0xcc, 0xf7],
+      //   nonce: [0x23, 0xb2, 0xf9, 0x06, 0x8b, 0x2c, 0x4c, 0x85],
+      //   plain_text: vec!(0xbe, 0x6b, 0x67, 0xeb, 0x94, 0x3e, 0xe7, 0xb5, 0xc7, 0x85, 0xcd, 0x88, 0x2f, 0x65, 0x3e, 0x73, 0xa8, 0xf7, 0x5b, 0x4a, 0x41, 0xa2, 0xa7, 0xc5, 0x6a, 0xe5, 0xa1, 0x0f, 0x72, 0x9c, 0xaf, 0x39, 0x94, 0x8f, 0xe4, 0x8a, 0xd0, 0xe5, 0x12, 0x40, 0xe2, 0xe7, 0xaa, 0x43, 0x19, 0x3c, 0x7e, 0xc6, 0xce, 0x7f, 0x49, 0x09, 0xfc, 0x94, 0xc9, 0xf9, 0x9e, 0x38, 0xe6, 0xa0, 0xad, 0x7e, 0x98, 0xeb, 0x29, 0xc5, 0xc2, 0xe6, 0x1c, 0x99, 0xe9, 0xcb, 0xe8, 0x90, 0xf1, 0x54, 0x18, 0x5c, 0xec, 0x21, 0x3a, 0x74, 0x72, 0x5d, 0x23, 0xc1, 0xa4, 0xe4, 0xd0, 0xcb, 0x9b, 0x1a, 0x36, 0xb7, 0x8c, 0x87, 0xe5, 0xee, 0xe2, 0x0d, 0x2a, 0xa2, 0x9a, 0xae, 0x80, 0xd4, 0x75, 0x9e, 0xb0, 0xc5, 0x1c, 0x5d, 0xc3, 0xa9, 0x5b, 0xdb, 0xbf, 0x7e, 0x14, 0xeb, 0x43, 0x44, 0x19, 0xa6, 0xc8, 0x8a, 0x95, 0x4a, 0xc0, 0x3d, 0x0c, 0x98, 0x73, 0x9f, 0x42, 0x11, 0xb8, 0x73, 0x2a, 0xcd, 0x71, 0xc2, 0x97, 0xf5, 0x78, 0xb8, 0xcb, 0x64, 0xcc, 0xac, 0x45, 0xf7, 0x23, 0x5d, 0xdc, 0x7f, 0x2a, 0x3f, 0x5f, 0x99, 0x75, 0x25, 0xc1, 0xed, 0x39, 0xdc, 0x55, 0x01, 0x26, 0xcd, 0xf9, 0xce, 0xda, 0xf5, 0x54, 0x25, 0x48, 0x90, 0x85, 0xe9, 0x1b, 0x17, 0x0b, 0xe6, 0x20, 0x5a, 0x5a, 0x39, 0x5f, 0x2d, 0xd4, 0x08, 0x4a, 0x3e, 0x8d, 0xbc, 0x4f, 0xd8, 0xb1, 0x32, 0x52, 0xf7, 0xef, 0xfa, 0xe0, 0x67, 0xb5, 0x71, 0xcb, 0x94, 0xa1, 0xe5, 0x4a, 0xba, 0x45, 0xb1, 0xb9, 0x84, 0x13, 0x08, 0xdb, 0x0c, 0xc7, 0x5b, 0x03, 0xcf, 0xce, 0x4d, 0xda, 0xfe, 0x89, 0xce, 0x20, 0xf2, 0xd1),
+      //   aad: vec!(0x7e, 0xb6, 0xd7, 0xb7, 0xbb, 0xaa, 0xa3, 0xc2, 0x02, 0xa4, 0xf0, 0xf1, 0xde, 0x22, 0x63, 0x76, 0x71, 0x69, 0xeb, 0x4a, 0x64, 0x85, 0x32, 0x40, 0xd4, 0x8c, 0x0f, 0x8d, 0x5d, 0x31, 0xb0, 0x8d, 0x5b, 0xaf, 0x42, 0x97, 0x76, 0x14, 0xa5, 0x7a, 0xad, 0x99, 0x42, 0x6c, 0xde, 0x76, 0xd2, 0x42, 0xcb, 0x37, 0xd2, 0x95, 0x6d, 0x8c, 0x77, 0xdc, 0x4f, 0xd6, 0x2a, 0x3a, 0xbf, 0x30, 0xe8, 0xac, 0x6c, 0xd5, 0x8c, 0x8e, 0xf3, 0x5e, 0x67, 0x49, 0x70, 0x22, 0x96, 0x01, 0x38, 0xc5, 0x77, 0x87, 0x81, 0x88, 0x92, 0x46, 0x0f, 0x3b, 0xfc, 0x16, 0xe3, 0x7f, 0xf3, 0x88, 0xb1, 0xed, 0xc6, 0xce, 0x2b, 0xc5, 0x3c, 0x22, 0x71, 0x7e, 0xdc, 0x7a, 0x03, 0xd4, 0xc7, 0x8b, 0x0d, 0xbb, 0xe9, 0x12, 0x1c, 0x7f, 0xd8, 0xa3, 0xe3, 0x99, 0x3b, 0x87, 0xa4, 0xfe, 0x38, 0x9b, 0xff, 0x13, 0xbd, 0xae, 0x3b, 0x34, 0x9d, 0xe0, 0xb6, 0xdb, 0x56, 0x16, 0x02, 0xc5, 0x3f, 0x74, 0x60, 0x22, 0xae, 0xb4, 0x48, 0x3c, 0x72, 0x3b, 0x67, 0x82, 0x50, 0x42, 0xf4, 0xaf, 0x20, 0xb7, 0xdd, 0x1e, 0x60, 0x31, 0xcf, 0x54, 0x21, 0x52, 0x66, 0x29, 0x5c, 0x52, 0x4a, 0xc8, 0xe1, 0x37, 0x04, 0x24, 0xc5, 0xc5, 0xe6, 0x07, 0xfb, 0x3e, 0x23, 0xe9, 0x7c, 0x8e, 0xeb, 0xe6, 0x46, 0x56, 0x77, 0x5e, 0xdf, 0x61, 0x64, 0x22, 0xa8, 0xb9, 0x74, 0xe1, 0xac, 0xf1, 0x3a, 0xb4, 0x5c, 0x9a, 0x36, 0x7a, 0x7d, 0xd9, 0xb2, 0xd6, 0x2f, 0x48, 0xbb, 0xc0, 0x58, 0x19, 0xb6, 0x5e, 0xcc, 0xb8, 0x13, 0xca, 0x81, 0x3f, 0x57, 0xb2, 0x2e, 0xe4, 0xc2, 0x80, 0xdb, 0xb5, 0xa9, 0xd8, 0xd5),
+      //   cipher_text: vec!(0x0b, 0x31, 0x6a, 0xb2, 0xbc, 0xf5, 0x35, 0x99, 0x00, 0xfa, 0x40, 0x82, 0xd5, 0xd2, 0x53, 0xb4, 0x9a, 0xd9, 0x4b, 0x70, 0xe3, 0xfa, 0xb5, 0x44, 0xf9, 0x8b, 0xd1, 0x11, 0xcb, 0xce, 0xf6, 0x76, 0x6c, 0xf9, 0x53, 0xde, 0xec, 0x08, 0xca, 0xe1, 0xf4, 0x89, 0xfe, 0x12, 0xf7, 0xac, 0xc0, 0x03, 0x2d, 0xb8, 0xa6, 0xb0, 0xc0, 0xee, 0xe0, 0xc2, 0x06, 0xea, 0x5f, 0xb9, 0x73, 0xfe, 0xae, 0xbf, 0x90, 0xf6, 0x90, 0xe8, 0x40, 0x09, 0x4d, 0xb5, 0xe1, 0x3f, 0xdd, 0x71, 0x57, 0xba, 0x12, 0x73, 0x68, 0xc9, 0x95, 0xb4, 0x26, 0x52, 0x94, 0x35, 0xa1, 0xbc, 0xdd, 0x1f, 0x14, 0xce, 0x91, 0x25, 0xb8, 0xa0, 0xe4, 0xc9, 0x6b, 0x6e, 0xc0, 0x9e, 0x3c, 0x36, 0xa1, 0x80, 0xad, 0xf8, 0x19, 0x41, 0xc0, 0x02, 0xd1, 0x9c, 0x19, 0xd5, 0x3c, 0x20, 0x09, 0xbe, 0x80, 0x3b, 0x98, 0x75, 0x04, 0x60, 0x6b, 0x7d, 0x43, 0xbd, 0xee, 0x5e, 0x0b, 0x32, 0xff, 0x23, 0xc4, 0x66, 0xb6, 0xcc, 0xcf, 0xcd, 0x0d, 0x4e, 0x88, 0xfd, 0x13, 0x32, 0xe7, 0x37, 0x12, 0xb5, 0xab, 0x72, 0x5c, 0x1a, 0x38, 0x3e, 0x58, 0x4f, 0x34, 0xf8, 0x0d, 0xaf, 0xf2, 0x9d, 0x28, 0x5a, 0xe5, 0xe4, 0x3c, 0xf1, 0xd0, 0xcc, 0x7a, 0x82, 0x8e, 0x75, 0xc2, 0x5d, 0xac, 0xed, 0x3a, 0x58, 0x1a, 0x93, 0xd7, 0xa5, 0x0f, 0x31, 0x3b, 0x33, 0xf3, 0x8d, 0xdd, 0xfa, 0xa2, 0x3c, 0xd5, 0xb9, 0x91, 0x47, 0x97, 0xdb, 0x82, 0x0e, 0xe2, 0x40, 0x0d, 0x52, 0xbf, 0x5f, 0xa9, 0x82, 0x27, 0x7f, 0xe9, 0xb5, 0x88, 0x1a, 0xc4, 0x29, 0x81, 0x63, 0x3b, 0x39, 0x57, 0xb0, 0xe9, 0x35, 0x05, 0x18, 0x28),
+      //   tag: vec!(0x01, 0x97, 0x3e, 0xe2, 0xe8, 0x1c, 0xef, 0x22, 0x75, 0x1a, 0x6a, 0x88, 0x31, 0xd7, 0x52, 0xef)
+      // },
+      // TestVector{
+      //   key: [0xfe, 0x4b, 0xe6, 0x05, 0x47, 0x73, 0xf6, 0x34, 0x35, 0x6a, 0xc3, 0x28, 0x59, 0x1f, 0xbc, 0x6f, 0x83, 0x3b, 0x0d, 0x1b, 0xee, 0xb3, 0x8d, 0xd5, 0xb6, 0xfe, 0xb7, 0x48, 0x1b, 0x44, 0x89, 0xd4],
+      //   nonce: [0x0b, 0x3f, 0x16, 0xf8, 0x98, 0xa5, 0xa7, 0xd5],
+      //   plain_text: vec!(0x76, 0xce, 0xd1, 0xad, 0xe6, 0xd1, 0xef, 0x40, 0x69, 0xaf, 0xdd, 0xb3, 0x2e, 0x74, 0x32, 0xd4, 0xff, 0x2f, 0xd0, 0x66, 0x85, 0x12, 0x1f, 0x7b, 0x16, 0x46, 0x4e, 0x7a, 0x72, 0xd3, 0x65, 0x74, 0x4f, 0x54, 0x7d, 0x2c, 0xcf, 0x53, 0x48, 0x63, 0x10, 0xe3, 0x8b, 0x42, 0xd8, 0xba, 0xca, 0xf7, 0x11, 0xe5, 0x4c, 0x54, 0x58, 0xd2, 0xd6, 0x8c, 0x4d, 0xbc, 0xc8, 0xde, 0x31, 0xab, 0x67, 0x32, 0xf4, 0x43, 0x0e, 0x88, 0xa6, 0x45, 0x65, 0xf5, 0xb2, 0x87, 0x64, 0x07, 0x75, 0xaa, 0xa2, 0xaf, 0x1c, 0xc4, 0x61, 0xd3, 0xe4, 0x15, 0xbb, 0x27, 0x5c, 0x62, 0x46, 0xb1, 0xb5, 0x85, 0x17, 0xaa, 0x72, 0x66, 0x7e, 0xae, 0x29, 0x1a, 0x29, 0x82, 0xed, 0xa1, 0x75, 0xd1, 0xb2, 0x2c, 0x5a, 0x58, 0xe6, 0xfe, 0xc2, 0xb3, 0x74, 0x3d, 0x55, 0x71, 0x2f, 0x20, 0x1c, 0xa2, 0x4b, 0xa5, 0xc0, 0xae, 0x8c, 0x25, 0x72, 0x48, 0x71, 0xb2, 0xec, 0x2f, 0xb9, 0x14, 0xa8, 0xda, 0x5a, 0x52, 0x67, 0x0a, 0xb9, 0xb4, 0x3a, 0x83, 0xb8, 0x56, 0x8c, 0xe7, 0x4d, 0xb5, 0xc6, 0x34, 0x06, 0x1c, 0xb8, 0x05, 0x30, 0xc8, 0x07, 0x0c, 0x38, 0xb8, 0xf4, 0x8c, 0x33, 0xba, 0x13, 0x6c, 0xb9, 0xf2, 0x15, 0x8e, 0xe7, 0xed, 0xa8, 0xb6, 0x5f, 0x21, 0x92, 0xfc, 0x94, 0xd1, 0x29, 0x1f, 0x18, 0x2f, 0x10, 0x17, 0x95, 0xb7, 0x19, 0x0c, 0x74, 0xb3, 0x19, 0xd2, 0xd3, 0xe0, 0x2a, 0x97, 0xc8, 0x24, 0xd9, 0xc9, 0x47, 0x1a, 0x83, 0x79, 0x7e, 0x49, 0x36, 0x31, 0x0b, 0x20, 0x7e, 0x3a, 0x1e, 0x0b, 0xcf, 0x75, 0xf7, 0xc3, 0xe3, 0xee, 0x48, 0xa7, 0x47, 0x64, 0x1c, 0xdc, 0x43, 0x77, 0xf2, 0xd5, 0x50, 0x82),
+      //   aad: vec!(0x83, 0x4c, 0xd7, 0x75, 0xcb, 0xef, 0xe4, 0xb3, 0x3a, 0x3c, 0xa5, 0x3a, 0x00, 0xc0, 0x6a, 0x3c, 0x4a, 0x66, 0x69, 0x83, 0xe4, 0x11, 0x5a, 0x02, 0x9f, 0x15, 0x72, 0x94, 0x60, 0xda, 0xa4, 0x5d, 0x15, 0x05, 0xe9, 0x51, 0x72, 0xd3, 0x69, 0x56, 0x25, 0xa1, 0x86, 0xb2, 0x8b, 0x8b, 0xe1, 0x73, 0xa9, 0x25, 0xaf, 0x04, 0x66, 0x5f, 0x20, 0x92, 0x67, 0xb3, 0xc5, 0x12, 0x3e, 0x8b, 0xe1, 0x3d, 0xa4, 0x47, 0xee, 0x1a, 0xe8, 0x56, 0xbb, 0x09, 0x25, 0xf3, 0x5a, 0xaa, 0x76, 0xe0, 0x4a, 0x7b, 0xca, 0x84, 0x60, 0xf7, 0x6c, 0x20, 0x24, 0xde, 0x21, 0x49, 0xf3, 0x8a, 0x8c, 0xfb, 0xa8, 0x16, 0x94, 0xb8, 0x54, 0x88, 0x5d, 0x72, 0x56, 0x81, 0x05, 0x57, 0x1b, 0x6b, 0x21, 0x3a, 0x0b, 0xc1, 0x88, 0xa4, 0x4c, 0xc7, 0xfe, 0x13, 0x15, 0x3c, 0xbf, 0x26, 0x14, 0x01, 0xb2, 0x38, 0xcf, 0x12, 0xa9, 0x5e, 0x23, 0xcb, 0x56, 0xf2, 0x40, 0x11, 0x4f, 0x16, 0xe2, 0xf1, 0xe3, 0xa5, 0x14, 0x61, 0x5a, 0xab, 0x44, 0x49, 0xc0, 0xc4, 0x9e, 0x4d, 0x90, 0x0b, 0x0e, 0x17, 0xd1, 0xa8, 0xda, 0xbb, 0x53, 0xd4, 0x3d, 0xca, 0x32, 0xfa, 0x05, 0x2d, 0x57, 0x6b, 0x73, 0xdd, 0x9b, 0x40, 0x85, 0x6b, 0x51, 0x5d, 0x6d, 0x7e, 0xfc, 0x2a, 0x5c, 0x17, 0xe0, 0xeb, 0xcb, 0x17, 0xbd, 0x59, 0xdc, 0x86, 0xf2, 0x2c, 0xe9, 0x09, 0x30, 0x1a, 0x26, 0x52, 0xf1, 0x34, 0xe8, 0x2e, 0xf0, 0xe4, 0x51, 0x94, 0x87, 0xed, 0x12, 0xd5, 0x15, 0x36, 0x02, 0x4f, 0x2a, 0xe8, 0xf7, 0x5d, 0x93, 0x7c, 0x42, 0xd0, 0x03, 0x07, 0x6e, 0x5d, 0xea, 0x8d, 0xe0, 0xc6, 0x84, 0xcd, 0xa1, 0xf3, 0x42, 0x53, 0xd8, 0xfc),
+      //   cipher_text: vec!(0xf8, 0xde, 0xfb, 0x6f, 0xe9, 0x5d, 0xfe, 0xc4, 0x99, 0xb9, 0x09, 0x99, 0x6a, 0x1f, 0x75, 0xa1, 0x98, 0xa9, 0x0e, 0x4d, 0x6c, 0x64, 0x64, 0xd0, 0x0a, 0x35, 0x7a, 0x55, 0x53, 0x11, 0xc4, 0x2f, 0xe9, 0x2d, 0xbb, 0xc4, 0xb7, 0x9c, 0x93, 0x5e, 0x4f, 0x0b, 0x1a, 0x95, 0xe4, 0x4f, 0xdb, 0xc1, 0x38, 0x0b, 0xeb, 0xab, 0xca, 0x28, 0xdb, 0x4d, 0xd0, 0xd2, 0x87, 0x0d, 0xaa, 0xaf, 0xc3, 0x8e, 0xf2, 0x79, 0x08, 0xc3, 0x50, 0x9e, 0x94, 0x57, 0x14, 0x80, 0x1c, 0xc5, 0x1f, 0x1a, 0x07, 0xb2, 0x43, 0x0c, 0x74, 0xfa, 0x64, 0xf2, 0xa7, 0xc2, 0xf7, 0xfd, 0x15, 0x51, 0xd2, 0x58, 0xc9, 0xc3, 0xbe, 0x02, 0x08, 0x73, 0xfc, 0x1b, 0xf1, 0x9f, 0x33, 0xab, 0x6c, 0x66, 0x09, 0x11, 0xdc, 0xf2, 0x31, 0x71, 0x95, 0xd0, 0xef, 0xee, 0x82, 0xd2, 0x0e, 0xc2, 0x6d, 0x22, 0x61, 0x1f, 0x9c, 0xf8, 0x6c, 0x51, 0xa6, 0x4e, 0x28, 0xb3, 0xa1, 0xf3, 0x44, 0x50, 0x00, 0x18, 0xe0, 0x85, 0x5c, 0x88, 0xda, 0xe3, 0xc0, 0x7a, 0xca, 0xea, 0xa1, 0x0b, 0x60, 0x38, 0x84, 0x84, 0xdc, 0xe9, 0x3e, 0x16, 0xe6, 0xe1, 0xa6, 0xe6, 0x9e, 0x89, 0x98, 0x06, 0x64, 0x8a, 0x92, 0x56, 0x8c, 0x87, 0x80, 0xe9, 0xf4, 0xba, 0xac, 0xd9, 0x8c, 0xbb, 0x35, 0x3a, 0xc2, 0xf9, 0x08, 0xe7, 0x75, 0xd9, 0x23, 0x03, 0xcf, 0xab, 0x84, 0x3f, 0x15, 0xbe, 0x0e, 0x0c, 0x32, 0x2a, 0x95, 0x88, 0x02, 0xfb, 0x1a, 0x60, 0xfc, 0xc7, 0x63, 0x1f, 0x15, 0x1f, 0x4c, 0x2b, 0x8c, 0xb9, 0x65, 0xd2, 0xd2, 0x96, 0xac, 0xef, 0x25, 0x02, 0x75, 0xa2, 0xfe, 0xcc, 0x0c, 0xea, 0x80, 0x3c, 0xe7, 0xc0, 0x58, 0xb1, 0x2d, 0xd2),
+      //   tag: vec!(0xad, 0xe5, 0x15, 0x09, 0x19, 0x30, 0xdd, 0x78, 0x61, 0xb2, 0x7f, 0x78, 0xa8, 0x7e, 0xf6, 0x0c)
+      // },
+      // TestVector{
+      //   key: [0xa2, 0x88, 0xb1, 0x1c, 0xe5, 0x38, 0x2e, 0xc7, 0x24, 0xce, 0x4a, 0xb2, 0xd7, 0xef, 0xa8, 0xe7, 0x77, 0xe9, 0x1e, 0xbd, 0x04, 0x36, 0x79, 0x35, 0xe1, 0x5f, 0x9d, 0xac, 0x48, 0x3e, 0x95, 0x96],
+      //   nonce: [0x87, 0x41, 0x44, 0xdb, 0xf6, 0x48, 0xb3, 0x25],
+      //   plain_text: vec!(0x4c, 0x91, 0x95, 0x28, 0x0a, 0x79, 0xa5, 0x09, 0x91, 0x9a, 0xf4, 0x94, 0x7e, 0x9e, 0x07, 0x23, 0x16, 0x95, 0xfd, 0x7c, 0x50, 0x88, 0x53, 0x9f, 0x23, 0x93, 0x6c, 0xe8, 0x87, 0x70, 0xce, 0x07, 0xd9, 0xad, 0x3a, 0xe4, 0xa4, 0x63, 0xb3, 0xa5, 0x7d, 0x06, 0x34, 0xd3, 0xa7, 0x7c, 0xea, 0xad, 0xf3, 0x47, 0xa3, 0x34, 0x68, 0x2b, 0x04, 0xbe, 0x8e, 0x58, 0xb8, 0xe8, 0x6f, 0xb9, 0x4a, 0x1f, 0x93, 0x25, 0x51, 0x32, 0xb8, 0xcd, 0xb0, 0xdf, 0x86, 0xf5, 0xbe, 0xa3, 0x54, 0xee, 0xa4, 0xe8, 0x31, 0x5f, 0xea, 0x83, 0xe3, 0xfd, 0xf6, 0xe5, 0x8a, 0xa9, 0xf2, 0x6e, 0x93, 0xca, 0xa0, 0x8e, 0x5e, 0x25, 0x51, 0xa9, 0x4b, 0xd9, 0x16, 0xa5, 0x1f, 0xed, 0x29, 0xec, 0x16, 0xf6, 0x68, 0x00, 0xcd, 0xa6, 0xa0, 0xaa, 0x24, 0xec, 0x30, 0x8b, 0xf5, 0xfb, 0x88, 0x5a, 0xfb, 0xa2, 0x72, 0x68, 0x5d, 0xe2, 0x7c, 0x1e, 0xdc, 0xdd, 0x36, 0x68, 0x04, 0x8e, 0xf0, 0x7b, 0x06, 0xe9, 0x0d, 0x46, 0x4a, 0x8a, 0xa2, 0x86, 0x64, 0x90, 0x3c, 0xac, 0x45, 0xe1, 0x54, 0xe8, 0xe1, 0xe3, 0x9c, 0x25, 0x7e, 0x1f, 0xf5, 0x06, 0xb9, 0xd9, 0x5c, 0xef, 0x4f, 0x30, 0x0b, 0xb7, 0x3b, 0x89, 0x9e, 0x78, 0x28, 0x60, 0x2c, 0x3c, 0x1d, 0x29, 0x0b, 0x8c, 0xf5, 0x5e, 0xe5, 0xfd, 0x72, 0xec, 0xce, 0x9e, 0x6e, 0xfc, 0x92, 0x93, 0xae, 0xbf, 0x67, 0x4a, 0x70, 0xe2, 0xa7, 0x67, 0x3e, 0x75, 0x62, 0x9c, 0x12, 0x95, 0x06, 0x22, 0xdf, 0xf7, 0x1d, 0x3e, 0xc0, 0x99, 0x2e, 0x57, 0x77, 0x6c, 0x78, 0x8c, 0x69, 0x27, 0xd3, 0x0b, 0x4e, 0x24, 0xb7, 0x49, 0x19, 0x1c, 0x3c, 0xe8, 0x01, 0x7f, 0x0a, 0xda, 0x62, 0x76, 0xe4, 0x37, 0x20),
+      //   aad: vec!(0x04, 0xab, 0xe8, 0x58, 0x8c, 0x8c, 0x8c, 0x39, 0xa1, 0x82, 0x09, 0x2e, 0x5e, 0x78, 0x40, 0x44, 0x2b, 0xd1, 0xc1, 0x14, 0x9d, 0xa1, 0x02, 0xc4, 0xee, 0x41, 0x2b, 0xd8, 0xb8, 0x2b, 0xaa, 0x50, 0x87, 0xef, 0x72, 0x91, 0xb5, 0xcd, 0x07, 0x7c, 0x17, 0x7c, 0x42, 0x77, 0x0b, 0x00, 0x23, 0xe0, 0xe4, 0x62, 0xb0, 0x6e, 0x75, 0x53, 0xf1, 0x91, 0xbc, 0xb0, 0x31, 0x5a, 0x34, 0x91, 0x8d, 0xcd, 0xbf, 0xfe, 0x2b, 0x99, 0xc3, 0xe0, 0x11, 0xb4, 0x22, 0x0c, 0xc1, 0x77, 0x5d, 0xeb, 0xcc, 0x0d, 0xb5, 0x5f, 0xa6, 0x0d, 0xf9, 0xb5, 0x22, 0x34, 0xf3, 0xd3, 0xfa, 0x96, 0x06, 0x50, 0x8b, 0xad, 0xc2, 0x6f, 0x30, 0xb4, 0x7c, 0xdb, 0x4f, 0x1c, 0x0f, 0x47, 0x08, 0xd4, 0x17, 0xb6, 0x85, 0x3e, 0x66, 0xc2, 0xf1, 0xf6, 0x7f, 0x62, 0x00, 0xda, 0xf7, 0x60, 0xce, 0xb6, 0x4f, 0xfc, 0x43, 0xdb, 0x27, 0xf0, 0x57, 0xad, 0x3e, 0xe9, 0x73, 0xe3, 0x1d, 0x7e, 0x5d, 0x5d, 0xeb, 0x05, 0x03, 0x15, 0xc1, 0xc6, 0x87, 0x98, 0x0c, 0x0c, 0x14, 0x8e, 0xe1, 0xa4, 0x92, 0xd4, 0x7a, 0xcf, 0xcd, 0x61, 0x32, 0x33, 0x41, 0x76, 0xc1, 0x12, 0x58, 0xc8, 0x9b, 0x19, 0xba, 0x02, 0xe6, 0xac, 0xc5, 0x5d, 0x85, 0x2f, 0x87, 0xb6, 0xa2, 0x16, 0x9e, 0xd3, 0x4a, 0x61, 0x47, 0xca, 0xa6, 0x09, 0x06, 0xac, 0x8c, 0x08, 0x13, 0xc0, 0xf0, 0x55, 0x22, 0xaf, 0x7b, 0x7f, 0x0f, 0xad, 0xdb, 0x4b, 0xc2, 0x97, 0x40, 0x5e, 0x28, 0xec, 0xf5, 0xa0, 0xf6, 0xaa, 0xc6, 0x25, 0x84, 0x22, 0xd2, 0x9c, 0xfe, 0x25, 0x0d, 0x61, 0x40, 0x28, 0x40, 0xf3, 0xc2, 0x7d, 0x0c, 0xe3, 0x9b, 0x3e, 0x2d, 0x5f, 0x1e, 0x52, 0x05, 0x41, 0xd2, 0x96, 0x5e),
+      //   cipher_text: vec!(0x0a, 0xfc, 0xe7, 0x70, 0xa1, 0x2f, 0x15, 0xd6, 0x7a, 0xc1, 0x04, 0xba, 0x06, 0x40, 0xaa, 0xb9, 0x59, 0x22, 0x39, 0x06, 0x07, 0x47, 0x3c, 0xbd, 0xa7, 0x13, 0x21, 0x15, 0x6a, 0x55, 0x59, 0x90, 0x6b, 0xe9, 0x33, 0xfb, 0x09, 0x80, 0xda, 0x56, 0xf2, 0x7e, 0x89, 0x79, 0x6e, 0xaa, 0x10, 0x54, 0xf5, 0xaa, 0xcf, 0x16, 0x68, 0xd9, 0xf2, 0x73, 0xcc, 0x69, 0x07, 0x1b, 0x9e, 0x8e, 0x22, 0xaf, 0x6a, 0x20, 0x5a, 0x6a, 0x88, 0xf7, 0xad, 0x91, 0x8e, 0x22, 0xf6, 0x16, 0xbd, 0xdb, 0xb0, 0x7c, 0x78, 0x91, 0x3c, 0x7e, 0x05, 0x6e, 0x76, 0x9e, 0x6f, 0xcf, 0x91, 0xc7, 0x60, 0x0c, 0x27, 0x40, 0x21, 0x2e, 0x3a, 0x17, 0x6e, 0x41, 0x10, 0xca, 0xc9, 0xe3, 0x61, 0xa5, 0x9a, 0x77, 0x34, 0x57, 0x06, 0x4d, 0x2d, 0xc6, 0x52, 0xdd, 0x11, 0x5d, 0x04, 0xf1, 0xc3, 0x75, 0x6c, 0x0e, 0x1d, 0x39, 0xf6, 0x73, 0x7a, 0x16, 0xb4, 0x50, 0x86, 0x63, 0xe3, 0x10, 0x93, 0x4c, 0x49, 0xc5, 0x80, 0x58, 0xb3, 0xc7, 0xb9, 0xaf, 0x7b, 0xb2, 0x33, 0x4c, 0x8a, 0x16, 0x36, 0x08, 0xc4, 0x24, 0x99, 0x65, 0x89, 0x86, 0x92, 0x7c, 0xda, 0x36, 0x5e, 0x2a, 0xea, 0xd3, 0xac, 0x29, 0xde, 0x16, 0xe4, 0x7e, 0x95, 0x43, 0x83, 0xea, 0x56, 0x6f, 0x8f, 0xb2, 0x45, 0xa4, 0xe5, 0xa9, 0x34, 0xc7, 0x67, 0xbb, 0x3b, 0xf7, 0xe0, 0xeb, 0x8a, 0x47, 0x7f, 0xd0, 0xe1, 0xf6, 0x1b, 0xcb, 0x23, 0x84, 0x62, 0xa0, 0xd1, 0x9c, 0x5c, 0xea, 0x92, 0x93, 0xca, 0x58, 0xad, 0xe7, 0x68, 0x29, 0x41, 0x32, 0x16, 0xa7, 0x88, 0x2c, 0xd2, 0x84, 0x63, 0x23, 0x04, 0x66, 0x94, 0xf7, 0x8c, 0xd8, 0xb0, 0x34, 0x77, 0x92, 0xeb, 0xb7, 0x5a, 0xbd, 0xc1),
+      //   tag: vec!(0x97, 0x3e, 0x58, 0xb1, 0xb8, 0xad, 0xb1, 0x76, 0xa6, 0xf1, 0xe5, 0xc9, 0x63, 0xbf, 0xdc, 0x5c)
+      // },
+      // TestVector{
+      //   key: [0x65, 0xb6, 0x3e, 0xd5, 0x37, 0x50, 0xc8, 0x8c, 0x50, 0x8c, 0x44, 0x88, 0x1a, 0xe5, 0x9e, 0x6f, 0xff, 0x69, 0xc6, 0x62, 0x88, 0xf3, 0xc1, 0x4c, 0xfe, 0xc5, 0x03, 0x39, 0x12, 0x62, 0xca, 0xfc],
+      //   nonce: [0x7f, 0x5e, 0x56, 0x0a, 0x1d, 0xe4, 0x34, 0xba],
+      //   plain_text: vec!(0x84, 0x5e, 0xf2, 0x7b, 0x66, 0x15, 0xfb, 0x69, 0x9d, 0x37, 0x97, 0x1d, 0xb6, 0xb5, 0x97, 0x93, 0x0a, 0x7e, 0xf1, 0xe6, 0xf9, 0x00, 0x54, 0x79, 0x1e, 0xb0, 0x4d, 0xdf, 0xe7, 0x25, 0x2b, 0x5f, 0x88, 0xfd, 0x60, 0xeb, 0xa5, 0xaf, 0x46, 0x9b, 0xc0, 0x96, 0x61, 0xc0, 0x98, 0x7a, 0x49, 0x6f, 0xa5, 0x40, 0x62, 0x1a, 0xfe, 0xec, 0x51, 0xbe, 0xbd, 0xa7, 0x86, 0x82, 0x68, 0x00, 0x94, 0x3d, 0x97, 0x70, 0x39, 0xde, 0xe7, 0x62, 0x35, 0x24, 0x81, 0x12, 0xff, 0x8b, 0x74, 0x3f, 0x25, 0xed, 0x5f, 0x3c, 0xb0, 0xd3, 0x30, 0x7f, 0x5e, 0x11, 0x8d, 0x84, 0xfd, 0xbb, 0x9c, 0x3f, 0x55, 0x31, 0xbc, 0x17, 0x7f, 0xb8, 0x45, 0x49, 0xc9, 0x94, 0xea, 0x44, 0x96, 0xc6, 0x5e, 0x52, 0x49, 0xda, 0x98, 0x7d, 0xd7, 0x55, 0xd4, 0x6d, 0xc1, 0x78, 0x8f, 0x58, 0x24, 0x10, 0x26, 0x6a, 0x10, 0xf2, 0x91, 0xc1, 0x47, 0x4f, 0x73, 0x21, 0x83, 0xa2, 0xa3, 0x9a, 0xfe, 0x60, 0x37, 0x71, 0xbb, 0x9c, 0x42, 0x3f, 0xe3, 0xe8, 0x90, 0x6f, 0x2b, 0xe4, 0x4a, 0x0c, 0x9a, 0x7c, 0x3f, 0x0c, 0xeb, 0x09, 0xd1, 0xd0, 0xf9, 0x2d, 0x94, 0x23, 0x83, 0xa8, 0x75, 0xc0, 0x56, 0x7c, 0x78, 0x69, 0xf0, 0x45, 0xe5, 0x6d, 0xd1, 0xa4, 0xd6, 0xe9, 0x0c, 0x58, 0xd4, 0x4f, 0xe0, 0xc5, 0x76, 0x0b, 0xb4, 0xfd, 0x01, 0xde, 0x55, 0x43, 0x9d, 0xb5, 0x2b, 0x56, 0x83, 0x1e, 0x5a, 0x26, 0xa4, 0x7d, 0xe1, 0x42, 0x49, 0x45, 0x3a, 0x4f, 0x8e, 0x7d, 0xa3, 0xcb, 0x32, 0x82, 0xc6, 0x62, 0x29, 0x16, 0x19, 0x7e, 0xbf, 0xaa, 0xd8, 0x5d, 0xd6, 0x5c, 0x61, 0xe7, 0xd2, 0xd3, 0xba, 0x62, 0x62, 0x76, 0x36, 0x67, 0x46, 0xf3, 0x96, 0x39, 0x4c, 0x1b, 0xf7, 0x5f, 0x51, 0xce),
+      //   aad: vec!(0x51, 0xa3, 0x58, 0x83, 0x98, 0x80, 0x8e, 0x1d, 0x6a, 0x98, 0x50, 0x5c, 0x6e, 0x56, 0x01, 0xae, 0x2a, 0x27, 0x66, 0xf1, 0xf2, 0x8f, 0x8f, 0x69, 0xd1, 0xcc, 0xbc, 0xad, 0x18, 0x03, 0x8c, 0x15, 0x7b, 0x41, 0x52, 0x5b, 0xe5, 0x8a, 0xe4, 0x52, 0x7a, 0x07, 0x37, 0x48, 0xb7, 0xa0, 0x48, 0x09, 0xe5, 0x2a, 0x5d, 0xf0, 0xc7, 0x98, 0x84, 0x17, 0x60, 0x77, 0x38, 0xe6, 0x3d, 0x7e, 0xad, 0x47, 0xdb, 0x79, 0x5a, 0x34, 0x6b, 0x04, 0xe7, 0x40, 0x18, 0x6e, 0x73, 0xcc, 0xad, 0x79, 0xf7, 0x25, 0xb5, 0x8e, 0xe2, 0x2d, 0xc6, 0xe3, 0x0d, 0x1f, 0x0a, 0x21, 0x8e, 0xda, 0x17, 0x91, 0xe2, 0x22, 0x9b, 0x25, 0x3d, 0x4a, 0xb2, 0xb9, 0x63, 0xa4, 0x3e, 0x12, 0x31, 0x8c, 0x8b, 0x07, 0x85, 0xc2, 0x0f, 0xca, 0x3a, 0xbc, 0xf2, 0x20, 0xc0, 0x87, 0x45, 0xd9, 0xf9, 0x60, 0x2f, 0x0e, 0xce, 0x54, 0x4a, 0x05, 0x73, 0x6d, 0x76, 0xb1, 0x2d, 0x24, 0x96, 0x99, 0xc9, 0xe3, 0xe9, 0x9f, 0x3f, 0x13, 0xcf, 0x4e, 0x5d, 0xc1, 0x3a, 0x04, 0x12, 0x5c, 0x94, 0x9a, 0x5b, 0x30, 0xd0, 0x34, 0xb2, 0x3c, 0xb3, 0x64, 0xc8, 0x78, 0x19, 0x64, 0xbc, 0x6c, 0x30, 0xe5, 0xe5, 0xca, 0x96, 0x73, 0xd5, 0x17, 0xef, 0x5f, 0x35, 0x96, 0x5d, 0x8a, 0x8c, 0xf1, 0xbe, 0x01, 0x7e, 0x34, 0x3d, 0xf9, 0x7b, 0x6b, 0xee, 0x37, 0xb3, 0x06, 0x38, 0xb1, 0x54, 0x28, 0x6d, 0x1f, 0x36, 0xd2, 0xf9, 0xa0, 0xea, 0xa2, 0x3c, 0xc4, 0x84, 0xea, 0xc5, 0xa0, 0x5b, 0x15, 0xd9, 0xef, 0xc5, 0x37, 0xd9, 0x89, 0xdb, 0xc8, 0xb3, 0x10, 0x6c, 0x0d, 0xc1, 0xa5, 0x6e, 0x97, 0xe6, 0xae, 0xc2, 0xef, 0xf5, 0x4a, 0x82, 0xcf, 0x7a, 0xe9, 0xdf, 0x2a, 0xf4, 0x6b, 0x4c, 0x86, 0x0f, 0x83),
+      //   cipher_text: vec!(0x02, 0x7b, 0x14, 0x19, 0x7b, 0x40, 0x12, 0x25, 0x6b, 0x13, 0x3b, 0x78, 0xdd, 0xc9, 0x4e, 0x72, 0xfb, 0x4d, 0x72, 0x4f, 0xef, 0xa4, 0xae, 0x32, 0x9f, 0x5a, 0x5f, 0xa3, 0xfa, 0x78, 0x4f, 0xe6, 0xd7, 0xe1, 0xe8, 0x05, 0xe3, 0xf7, 0xa7, 0x55, 0x57, 0xde, 0x64, 0xde, 0x50, 0x6d, 0x38, 0x23, 0x7b, 0x46, 0x7f, 0xa5, 0x77, 0xef, 0xb5, 0x9e, 0x7c, 0xfe, 0x23, 0x56, 0xbe, 0xd6, 0x65, 0x5c, 0x5a, 0xa4, 0xe2, 0x38, 0xdc, 0xfe, 0xb7, 0x5c, 0x16, 0x54, 0x9a, 0x09, 0x17, 0x26, 0x87, 0x68, 0xa9, 0x6a, 0xcb, 0x5e, 0x20, 0x54, 0x6a, 0x1f, 0xb7, 0xe3, 0xa7, 0xcf, 0xf8, 0x87, 0xf4, 0x9f, 0x2c, 0xd7, 0xa1, 0x35, 0xf7, 0x2a, 0x98, 0xa7, 0x79, 0x15, 0x0f, 0x32, 0x07, 0xbf, 0x73, 0x3e, 0x88, 0x86, 0x1f, 0xd7, 0x9e, 0xad, 0xbf, 0x77, 0xfa, 0x3b, 0xfe, 0x97, 0xbf, 0xe8, 0xb6, 0xa9, 0x91, 0xcb, 0x3b, 0xcc, 0x2c, 0xde, 0x82, 0x87, 0xf7, 0xe8, 0x93, 0x84, 0x84, 0x65, 0x61, 0x93, 0x4b, 0x0f, 0x3e, 0x05, 0xe0, 0x64, 0x6e, 0x0e, 0x19, 0x07, 0x77, 0x0d, 0xf6, 0x7a, 0x75, 0x94, 0x16, 0x1a, 0x4d, 0x07, 0x63, 0xfa, 0xa6, 0xfa, 0x84, 0x40, 0x80, 0x93, 0x21, 0x59, 0x99, 0x9d, 0x52, 0x8e, 0xe0, 0x55, 0x87, 0x10, 0x05, 0x8c, 0xe1, 0x6f, 0x97, 0xd1, 0x3a, 0xc9, 0xfd, 0x9b, 0xf5, 0x04, 0x41, 0x91, 0x18, 0x8b, 0xbf, 0xb5, 0x98, 0xd0, 0xfa, 0xfb, 0xdf, 0x79, 0x0b, 0x61, 0xce, 0x07, 0x81, 0xec, 0xc0, 0x42, 0x18, 0xa3, 0x0d, 0xed, 0x45, 0xef, 0xd4, 0x98, 0xcc, 0x9b, 0xa0, 0x35, 0x62, 0xed, 0x2b, 0x4a, 0x99, 0x3e, 0xe9, 0x88, 0x76, 0xb3, 0xab, 0x7a, 0x9b, 0xc0, 0x78, 0x29, 0xf1, 0xc4, 0xca, 0x6e, 0xad, 0x98, 0xc0, 0x6b),
+      //   tag: vec!(0xe4, 0xd1, 0x8a, 0x70, 0x1b, 0x83, 0x08, 0x69, 0x7b, 0x5e, 0x79, 0x14, 0x1e, 0xd7, 0x83, 0xc1)
+      // },
+      // TestVector{
+      //   key: [0x49, 0x86, 0xfd, 0x62, 0xd6, 0xcb, 0x86, 0xb2, 0xea, 0xf2, 0x19, 0x17, 0x4b, 0xec, 0x68, 0x1b, 0xeb, 0xcd, 0xef, 0x86, 0xc8, 0xbe, 0x29, 0x1f, 0x27, 0xd3, 0xe5, 0xdc, 0x69, 0xe2, 0xfe, 0xba],
+      //   nonce: [0xd0, 0x8d, 0x48, 0x66, 0x20, 0xed, 0x2e, 0x84],
+      //   plain_text: vec!(0x3a, 0x22, 0xad, 0x5d, 0xe3, 0x87, 0xdb, 0x4f, 0xdd, 0x5d, 0x62, 0xa1, 0xb7, 0x28, 0xc2, 0x3a, 0x8d, 0xdd, 0xc5, 0x0b, 0x1e, 0x89, 0xf5, 0x4f, 0x61, 0x98, 0xb9, 0x04, 0x99, 0xf9, 0xda, 0x31, 0x22, 0xeb, 0xeb, 0x38, 0xeb, 0xf5, 0xfd, 0xfe, 0x30, 0x30, 0x97, 0x34, 0xf7, 0x9a, 0xff, 0x01, 0xe3, 0xde, 0x1e, 0x19, 0x6b, 0x35, 0xbf, 0xfa, 0x33, 0xba, 0xe4, 0x51, 0xf3, 0x1f, 0x74, 0xb8, 0xae, 0xc0, 0x37, 0x63, 0xf9, 0xe0, 0x86, 0x1a, 0x34, 0xfe, 0x5d, 0xb0, 0xb4, 0x0c, 0x76, 0xe5, 0x7c, 0x7f, 0xc5, 0x82, 0xbf, 0xa1, 0x9c, 0x94, 0xee, 0x25, 0xb5, 0xe1, 0x68, 0x27, 0x0f, 0x37, 0x9b, 0xf9, 0xf8, 0xa0, 0xa1, 0x8b, 0xed, 0x05, 0xde, 0x25, 0x6f, 0x8f, 0x0d, 0xd7, 0xc2, 0x3b, 0xa2, 0xff, 0x1c, 0x7f, 0x72, 0x14, 0x09, 0x46, 0x2f, 0x04, 0xcc, 0x61, 0x1a, 0xd9, 0xbd, 0x4c, 0x3c, 0x9a, 0xcf, 0x30, 0x74, 0x2a, 0xcf, 0xb9, 0x51, 0x8a, 0x63, 0x75, 0xcb, 0xb1, 0x5d, 0x65, 0xa1, 0xbc, 0x69, 0x93, 0xea, 0x43, 0x48, 0x94, 0xf9, 0x3d, 0x4f, 0x6e, 0x05, 0x99, 0x6e, 0xbc, 0x1b, 0xd5, 0x65, 0x79, 0x29, 0x63, 0x09, 0xa2, 0xc6, 0xb8, 0xfd, 0xe9, 0x50, 0x72, 0x16, 0x8b, 0x5f, 0xd3, 0x19, 0x27, 0xc4, 0xc0, 0xab, 0xaa, 0x05, 0x6b, 0xcd, 0x16, 0x22, 0x1d, 0x5f, 0x22, 0x0b, 0xe4, 0x75, 0x91, 0xf4, 0x32, 0x55, 0x01, 0x3a, 0x26, 0x2d, 0xce, 0x43, 0x98, 0x17, 0xf5, 0x34, 0x83, 0x0b, 0xa8, 0x21, 0x55, 0x34, 0x7e, 0x5f, 0xe3, 0x10, 0x1f, 0x80, 0x11, 0xb8, 0x93, 0x65, 0xa6, 0x56, 0x82, 0x14, 0xed, 0x06, 0x61, 0x91, 0x4e, 0x8c, 0xb3, 0x43, 0x1d, 0x6c, 0x8f, 0x23, 0x47, 0xdf, 0xc1, 0x20, 0x9a, 0x3e, 0xca, 0x4a, 0xaf, 0x0a, 0x11, 0x1f, 0x47, 0xfe),
+      //   aad: vec!(0x7d, 0xd3, 0xf6, 0x56, 0xa0, 0x3c, 0x00, 0x1b, 0x45, 0xca, 0x06, 0x80, 0xbc, 0x3a, 0xc9, 0xd6, 0x8c, 0x6e, 0x96, 0xb5, 0x91, 0xd3, 0xc6, 0x9e, 0xb8, 0xc6, 0x5e, 0x48, 0x90, 0x09, 0xd8, 0x45, 0xcb, 0x33, 0x1c, 0x98, 0xb8, 0x2e, 0x62, 0x7e, 0x06, 0xd5, 0xbf, 0x01, 0xe7, 0x4c, 0x57, 0x3d, 0xf2, 0x68, 0xc2, 0x38, 0x6f, 0x12, 0x62, 0x8c, 0x01, 0x99, 0x51, 0xd4, 0x2f, 0x55, 0x99, 0x1f, 0xf2, 0x0d, 0x72, 0xa7, 0xb2, 0xc4, 0x5f, 0x41, 0xd0, 0xbe, 0x7a, 0xf4, 0x28, 0xc9, 0x2f, 0x32, 0x4a, 0xaa, 0xb8, 0xdf, 0x70, 0xd9, 0x00, 0x30, 0x1c, 0xdf, 0x09, 0xa3, 0xd9, 0x3e, 0xb7, 0x11, 0xc9, 0x19, 0xd3, 0x4a, 0x86, 0xff, 0xf9, 0xcb, 0x07, 0x83, 0x22, 0xee, 0x2e, 0x0a, 0xd4, 0x8d, 0xbd, 0xf3, 0xb7, 0x88, 0x4f, 0x0f, 0x2d, 0xc5, 0xc3, 0x62, 0x62, 0xc5, 0x9b, 0xcf, 0xd7, 0x5a, 0xc6, 0x20, 0x0f, 0x59, 0xc6, 0xfc, 0xd0, 0xce, 0x10, 0xff, 0x50, 0x05, 0xfe, 0xf5, 0xdf, 0x8f, 0x04, 0x32, 0x37, 0x7d, 0xfb, 0xfc, 0x1d, 0xb8, 0xf5, 0x59, 0xe2, 0x7e, 0x1a, 0xee, 0xf3, 0x38, 0x0e, 0xa3, 0x86, 0x48, 0x67, 0xd3, 0x6a, 0x25, 0xa1, 0x86, 0x54, 0x77, 0x9a, 0x75, 0x15, 0x86, 0xca, 0xd3, 0xb8, 0xa4, 0x6b, 0x90, 0x86, 0x4e, 0xe6, 0x97, 0xb0, 0x86, 0x05, 0x67, 0x3b, 0x8d, 0x21, 0x23, 0x43, 0x3c, 0x02, 0x0a, 0x21, 0xc4, 0xdb, 0x24, 0x3d, 0xde, 0x24, 0x20, 0xc1, 0x2f, 0xd4, 0xd5, 0x4a, 0x27, 0x04, 0xa0, 0xc8, 0xc3, 0x76, 0x45, 0x4a, 0x1b, 0x5e, 0x80, 0xfd, 0x6d, 0xb8, 0x9a, 0xab, 0xd5, 0x6d, 0x9b, 0x42, 0x1f, 0x29, 0x64, 0x9e, 0x47, 0x48, 0x24, 0xdf, 0xa5, 0x6c, 0xb5, 0xc6, 0x73, 0xc5, 0x04, 0xd1, 0x0b, 0xe5, 0x2b, 0x53, 0x75, 0x17, 0x09, 0xfe),
+      //   cipher_text: vec!(0xc4, 0x01, 0x80, 0xaf, 0xd5, 0x30, 0x01, 0x66, 0x3f, 0xf4, 0x83, 0x41, 0x10, 0xf5, 0x6e, 0x6b, 0x0f, 0x17, 0x8c, 0xd3, 0xc0, 0xe7, 0xf7, 0xde, 0x5d, 0x00, 0x89, 0xee, 0x41, 0xd8, 0x40, 0x3f, 0xfb, 0x98, 0xe8, 0x49, 0x22, 0x70, 0x65, 0x44, 0xa3, 0x44, 0xd7, 0xe2, 0x62, 0x5b, 0x12, 0xcf, 0x66, 0xb9, 0xc9, 0x66, 0xf9, 0xf5, 0x7d, 0x7b, 0x94, 0xe3, 0xe4, 0xb3, 0x4e, 0x6f, 0x0a, 0xae, 0xd1, 0x76, 0x3c, 0xe0, 0x12, 0x78, 0x2e, 0x2f, 0x5e, 0x16, 0x82, 0xe6, 0xc3, 0x43, 0xfc, 0x79, 0x61, 0xfe, 0xdd, 0xdd, 0x09, 0x19, 0xd0, 0xb9, 0x10, 0xe9, 0x92, 0x3c, 0x17, 0xe3, 0x64, 0x06, 0x97, 0x9b, 0x25, 0x6b, 0x85, 0xae, 0xc2, 0x4e, 0xe3, 0x52, 0xf0, 0x3b, 0x48, 0xc1, 0x30, 0x2e, 0xab, 0x41, 0x9c, 0x83, 0xdc, 0xcc, 0x53, 0x72, 0xcc, 0x05, 0x9e, 0x9d, 0xe5, 0x96, 0x22, 0x4f, 0xa7, 0x00, 0x98, 0xeb, 0x32, 0xfc, 0x95, 0x79, 0xe9, 0x79, 0x17, 0xb9, 0x23, 0x91, 0x4f, 0xa2, 0xef, 0xc3, 0x0a, 0xb2, 0x9b, 0x45, 0x7b, 0xf1, 0x4e, 0x45, 0x58, 0x3b, 0x37, 0x71, 0x48, 0x6b, 0xdc, 0x08, 0x76, 0xf3, 0xea, 0x6e, 0x1a, 0x64, 0x67, 0x46, 0xc4, 0xf8, 0xc5, 0xcb, 0x26, 0x41, 0xa1, 0x55, 0x7c, 0x84, 0x73, 0xe6, 0xea, 0x67, 0xd4, 0x81, 0x1a, 0x67, 0x48, 0x5a, 0xe9, 0xa6, 0x78, 0xff, 0x3a, 0x24, 0x08, 0xca, 0x84, 0x5c, 0x3b, 0x51, 0x95, 0x7e, 0x18, 0x9e, 0xef, 0x47, 0xdf, 0xc1, 0xd4, 0x6b, 0xde, 0x4b, 0x9d, 0x75, 0x4d, 0x7d, 0xf1, 0x3f, 0x82, 0x8d, 0xda, 0xdb, 0x06, 0xe4, 0xeb, 0xdd, 0xb5, 0xf0, 0xda, 0xfb, 0xdb, 0x28, 0xde, 0x4c, 0x5e, 0x60, 0x78, 0x92, 0x6f, 0x20, 0xcd, 0xf9, 0xe9, 0x7e, 0xcd, 0x58, 0xe3, 0x09, 0xe6, 0x40, 0xf7, 0x4f, 0x06),
+      //   tag: vec!(0xfd, 0x5e, 0x29, 0x33, 0x28, 0x32, 0xa1, 0x4a, 0x31, 0xa9, 0xce, 0x2c, 0xa8, 0x56, 0x84, 0x98)
+      // },
+      // TestVector{
+      //   key: [0x7d, 0x28, 0xa6, 0x08, 0x10, 0xe4, 0x3d, 0x3d, 0xfa, 0x32, 0xe9, 0x7c, 0x07, 0x95, 0x7e, 0xc0, 0x69, 0xfc, 0x80, 0xcc, 0x6a, 0x50, 0x06, 0x18, 0x30, 0xaa, 0x29, 0xb3, 0xaa, 0x77, 0x7d, 0xfc],
+      //   nonce: [0x47, 0x73, 0x8a, 0xc8, 0xf1, 0x0f, 0x2c, 0x3a],
+      //   plain_text: vec!(0xb5, 0x02, 0x78, 0xae, 0x0f, 0x0f, 0xa2, 0xf9, 0x18, 0xbb, 0x9a, 0x5e, 0xd3, 0xa0, 0x79, 0x7c, 0x32, 0x8e, 0x45, 0x29, 0x74, 0xd3, 0x3c, 0xbf, 0x26, 0xa1, 0xe2, 0x13, 0xaa, 0x20, 0xc0, 0x3d, 0x0d, 0x89, 0x49, 0x08, 0x69, 0x75, 0x4a, 0xbf, 0x84, 0xdb, 0xbe, 0x23, 0x1d, 0x7b, 0xcc, 0xdc, 0xed, 0x77, 0xd5, 0x3f, 0xd4, 0x52, 0x73, 0x56, 0xd8, 0xe0, 0x2b, 0x68, 0x1f, 0xc8, 0x9a, 0x53, 0x5a, 0xe8, 0x73, 0x08, 0xbf, 0x7f, 0xbc, 0x26, 0x19, 0x7a, 0x5e, 0xa8, 0x5b, 0xdb, 0x3a, 0xa0, 0x33, 0xb8, 0xda, 0x5c, 0xd1, 0x97, 0xea, 0x6d, 0x72, 0xf9, 0x6f, 0x63, 0xb0, 0x3f, 0x4e, 0xcc, 0x7a, 0xde, 0xdf, 0x39, 0x9a, 0x50, 0x43, 0x77, 0x6c, 0xdb, 0x32, 0xc0, 0x8f, 0x30, 0xb7, 0x7f, 0x34, 0xdf, 0x85, 0xf8, 0xad, 0xb8, 0xe0, 0x26, 0x49, 0xa0, 0x4b, 0x02, 0x0b, 0x03, 0xe1, 0x7d, 0x44, 0x5c, 0xa6, 0x3e, 0x4e, 0xd7, 0x3a, 0xe4, 0x32, 0xc4, 0x81, 0x39, 0x2e, 0x03, 0x1e, 0xba, 0x2f, 0x9d, 0x2f, 0x7f, 0x98, 0x1d, 0x1e, 0x50, 0x91, 0x78, 0x22, 0xbd, 0x6f, 0xf7, 0x1c, 0x23, 0x9d, 0x33, 0x44, 0x4a, 0xda, 0x35, 0x23, 0xa5, 0x9d, 0xfb, 0xce, 0x54, 0x57, 0xea, 0xde, 0xc1, 0xab, 0x92, 0x6c, 0x9e, 0x6c, 0x52, 0x99, 0xc7, 0x52, 0x1e, 0x3f, 0x20, 0x4b, 0x96, 0x90, 0x1a, 0x71, 0x25, 0x04, 0xfc, 0xc7, 0x82, 0xe8, 0xce, 0xa8, 0x0b, 0xa1, 0x2a, 0x7f, 0x7e, 0x71, 0xce, 0xc3, 0xd0, 0x87, 0x18, 0x99, 0xb6, 0xca, 0x05, 0x90, 0x61, 0xda, 0x03, 0x77, 0x15, 0xf7, 0xd1, 0x3f, 0xed, 0x01, 0xc9, 0xca, 0xde, 0x1e, 0x68, 0x7b, 0x4f, 0xbb, 0x1f, 0x4a, 0xc4, 0xb0, 0x40, 0xdb, 0x3b, 0x43, 0x80, 0x0f, 0x11, 0x2f, 0xb9, 0x00, 0xe4, 0xf7, 0x72, 0xd6, 0x1b, 0x92, 0x1c, 0xbc, 0xe4, 0xda, 0x6f),
+      //   aad: vec!(0x32, 0x42, 0x92, 0x81, 0x3b, 0x7d, 0xf1, 0x5b, 0xc0, 0x70, 0xcc, 0x5d, 0x8a, 0x4b, 0xf7, 0x4e, 0xad, 0x03, 0x64, 0x30, 0xbe, 0x63, 0xab, 0xc4, 0x33, 0x04, 0xcf, 0x65, 0x39, 0x59, 0xa2, 0x4a, 0x91, 0xc7, 0xde, 0x5a, 0x67, 0x1c, 0x50, 0xfa, 0x8a, 0x87, 0xe2, 0x1b, 0xb8, 0x2b, 0x06, 0x99, 0x99, 0xaa, 0xdf, 0xb6, 0x89, 0x5d, 0x8b, 0xda, 0x4c, 0x30, 0x83, 0xd1, 0x7b, 0x8c, 0xa5, 0x5b, 0x9a, 0xb1, 0x51, 0x1e, 0xd8, 0xc4, 0xb3, 0x9d, 0x8c, 0x28, 0xc1, 0x1a, 0x22, 0xef, 0x90, 0xc0, 0x8a, 0x98, 0x3e, 0x3f, 0xe2, 0xd9, 0x88, 0xdf, 0x9e, 0x02, 0xb1, 0x6a, 0x20, 0xb2, 0x4f, 0x39, 0xdd, 0xb2, 0x84, 0x29, 0x62, 0x5f, 0x51, 0x1d, 0xb0, 0x82, 0x98, 0xc4, 0xdc, 0x32, 0x1f, 0x6c, 0x26, 0x8f, 0xc8, 0x36, 0xa6, 0x19, 0x1d, 0xf6, 0x23, 0x2f, 0x51, 0xc4, 0x63, 0xa3, 0x97, 0xa8, 0xd8, 0xb3, 0x33, 0x74, 0xab, 0xe9, 0x4e, 0x62, 0xc0, 0xf5, 0xc3, 0x22, 0x38, 0x7e, 0x1f, 0xc4, 0xa1, 0xc1, 0x98, 0x0a, 0x04, 0xa1, 0xa3, 0xc2, 0xc3, 0x1b, 0x32, 0xf1, 0x83, 0xa1, 0x1c, 0x32, 0x68, 0xc6, 0xdc, 0xa5, 0x21, 0x14, 0x9d, 0xc1, 0x6a, 0xf1, 0x20, 0xa7, 0x8b, 0xe6, 0x62, 0x72, 0x10, 0xe8, 0xdd, 0xbc, 0x44, 0x47, 0x2b, 0xc2, 0x4d, 0x66, 0xce, 0x36, 0x81, 0xc7, 0x57, 0x9b, 0x3d, 0x9a, 0x42, 0x52, 0x12, 0xa7, 0x04, 0xa4, 0xf5, 0x10, 0x5c, 0xb8, 0x0f, 0x0d, 0x18, 0xee, 0x86, 0x09, 0x53, 0xd1, 0x0b, 0x59, 0xc1, 0x14, 0x82, 0x67, 0x79, 0xbb, 0xc3, 0x68, 0xd7, 0xa0, 0xee, 0xce, 0x9f, 0x22, 0x3e, 0x47, 0xcd, 0x8e, 0x5f, 0xd4, 0x53, 0x60, 0x7d, 0x10, 0x1d, 0x9d, 0x9c, 0x2b, 0xd9, 0xa6, 0x58, 0xd6, 0x52, 0x0b, 0x87, 0xd7, 0xb4, 0x26, 0x3f, 0x6d, 0x84, 0x5a, 0x52, 0x4a, 0x36, 0xe4),
+      //   cipher_text: vec!(0x2c, 0x21, 0x7e, 0x96, 0x9c, 0x04, 0x74, 0x0a, 0x1a, 0xcf, 0xa3, 0x01, 0x17, 0xeb, 0x5b, 0x32, 0xdc, 0x57, 0x3d, 0xf3, 0x35, 0x4f, 0x4c, 0xc3, 0xbf, 0x8f, 0x69, 0x6f, 0xf9, 0x05, 0xf1, 0xe6, 0x40, 0xf3, 0xb2, 0xc2, 0x50, 0x47, 0x3b, 0x37, 0x66, 0x22, 0xe0, 0xc9, 0xbd, 0xa1, 0x3b, 0x94, 0x64, 0x05, 0x21, 0xbe, 0x1e, 0xf0, 0xfc, 0x66, 0x0b, 0x4c, 0x10, 0xdb, 0xe2, 0xbf, 0xc0, 0x93, 0x03, 0x07, 0x53, 0xe0, 0x4f, 0x6a, 0xae, 0xcf, 0x81, 0x3b, 0x43, 0xb6, 0x1f, 0x96, 0x04, 0x55, 0x97, 0x4b, 0x8b, 0xb8, 0xa9, 0xb4, 0x61, 0xd1, 0xe8, 0xfd, 0x38, 0x02, 0x31, 0x5e, 0x86, 0x3c, 0x00, 0x44, 0x8f, 0x24, 0xdd, 0x38, 0xde, 0xb9, 0x0e, 0x13, 0x54, 0x93, 0x27, 0x4e, 0xb1, 0x4c, 0xcb, 0xde, 0x15, 0xc5, 0x0d, 0xca, 0xd7, 0x34, 0xed, 0x81, 0x5a, 0x80, 0x6b, 0xe6, 0x62, 0x24, 0x92, 0xa8, 0x4c, 0xd0, 0x62, 0xe3, 0xba, 0x56, 0x7b, 0x90, 0x9a, 0x20, 0x5a, 0x1d, 0x0d, 0x2b, 0xed, 0xd4, 0x01, 0x69, 0x69, 0x7d, 0x26, 0x1c, 0x7b, 0x6c, 0x2e, 0x0b, 0x1f, 0x06, 0x98, 0x53, 0xfd, 0x47, 0x0e, 0x8f, 0x36, 0x4a, 0x14, 0x2c, 0x38, 0x6c, 0x43, 0x9a, 0x6d, 0xbe, 0x19, 0x2d, 0xed, 0x5a, 0x3d, 0x0f, 0xbf, 0x73, 0x79, 0x9f, 0x58, 0x8c, 0x59, 0xe5, 0x8c, 0x60, 0x24, 0x9d, 0x98, 0x0d, 0xdc, 0xf0, 0xd9, 0x69, 0x36, 0x31, 0xcd, 0x9b, 0x3f, 0x97, 0x25, 0x09, 0xc3, 0xa7, 0x71, 0x23, 0xd3, 0x8d, 0x9e, 0x26, 0x7e, 0xca, 0xd0, 0x6e, 0x12, 0x08, 0xe3, 0xf1, 0xc0, 0xa6, 0x9f, 0xbc, 0xa7, 0xc3, 0xbb, 0x1a, 0x48, 0xfd, 0xa1, 0x94, 0x93, 0xd0, 0xf8, 0xf4, 0x83, 0x98, 0x82, 0x00, 0x57, 0xb9, 0x41, 0x20, 0xf3, 0xef, 0x97, 0xd8, 0x7e, 0x9e, 0x8a, 0x1b, 0x30, 0x1a, 0x25, 0x34, 0xc6, 0x8f),
+      //   tag: vec!(0x1f, 0xdd, 0x2d, 0xcd, 0x93, 0x5f, 0x55, 0x82, 0x2b, 0xf7, 0x23, 0x1a, 0x51, 0x6c, 0xa8, 0x41)
+      // },
+      // TestVector{
+      //   key: [0xa7, 0x6e, 0x9b, 0x91, 0x6f, 0x5a, 0x67, 0xb7, 0x8a, 0x59, 0x49, 0x65, 0x1c, 0x8c, 0x3a, 0x97, 0x41, 0xa1, 0xbc, 0x3c, 0x41, 0xcd, 0xf8, 0x5f, 0xd2, 0xc8, 0xf3, 0xe9, 0xa0, 0x61, 0x60, 0x98],
+      //   nonce: [0x08, 0x08, 0xda, 0x82, 0x92, 0xdc, 0x14, 0xe0],
+      //   plain_text: vec!(0x9c, 0x14, 0x9e, 0xeb, 0x09, 0x34, 0x5c, 0x3c, 0x22, 0x46, 0x2b, 0x03, 0xe4, 0x9e, 0xb4, 0xdb, 0xa6, 0xbc, 0x98, 0xb2, 0x69, 0xb1, 0x08, 0x6d, 0x75, 0x2b, 0xcd, 0x8e, 0xea, 0x53, 0xb8, 0x97, 0x7b, 0x23, 0x8a, 0x04, 0xa9, 0x94, 0xba, 0xf9, 0x15, 0x59, 0x16, 0x86, 0xba, 0xab, 0x90, 0xb7, 0x9a, 0x3b, 0xf7, 0xd9, 0xad, 0xb2, 0xc6, 0xc2, 0xe3, 0x1a, 0xcd, 0x3e, 0x72, 0xf0, 0x81, 0x3f, 0xb7, 0x45, 0xaa, 0x5f, 0xb2, 0xe3, 0xda, 0x40, 0x8f, 0x78, 0x00, 0x1c, 0x9c, 0x09, 0xbd, 0x26, 0xa1, 0xa2, 0x64, 0x60, 0x11, 0xb6, 0x12, 0x0a, 0xaa, 0x2b, 0xba, 0xcc, 0x4a, 0x16, 0xc3, 0x9f, 0xb5, 0x25, 0x7b, 0x9b, 0x2e, 0xa2, 0xad, 0x8b, 0xf7, 0x0b, 0xcc, 0x98, 0x55, 0xcf, 0x11, 0x84, 0x11, 0x16, 0xc2, 0x76, 0x73, 0x10, 0xcf, 0x3c, 0xd4, 0x9d, 0x1a, 0xa4, 0x4c, 0xd5, 0x05, 0xf0, 0x79, 0x76, 0x1e, 0x06, 0x4d, 0x5b, 0xc7, 0xce, 0xa4, 0xa7, 0x17, 0x3b, 0x08, 0x68, 0x82, 0xa7, 0x7d, 0x3f, 0xc1, 0x79, 0xef, 0xc8, 0x6f, 0xc4, 0xdb, 0x8a, 0x37, 0x34, 0x91, 0xd2, 0xed, 0x81, 0xea, 0xbc, 0x63, 0xc9, 0x50, 0xe8, 0x32, 0xdb, 0x17, 0xd0, 0x9f, 0x47, 0x4d, 0x4e, 0xc4, 0x6b, 0xde, 0x47, 0x83, 0x0c, 0xaf, 0x26, 0xfa, 0xba, 0xa0, 0x37, 0x2b, 0x81, 0xfc, 0xcc, 0x44, 0x9c, 0x0e, 0x19, 0xcc, 0xd6, 0x30, 0xca, 0xf6, 0x93, 0xa7, 0xb4, 0x3b, 0xb1, 0xc4, 0x08, 0xa5, 0x4e, 0x03, 0xf5, 0x0c, 0x44, 0x28, 0x0a, 0x05, 0xad, 0x89, 0xfb, 0x6e, 0x8f, 0x01, 0xd8, 0xac, 0x27, 0x8e, 0xdf, 0x55, 0x6e, 0x5d, 0x86, 0xce, 0xb4, 0xb6, 0x14, 0xfb, 0x2e, 0xf1, 0x33, 0x81, 0x9c, 0x6e, 0x1f, 0xf6, 0xab, 0xb8, 0x6c, 0x54, 0xa1, 0x35, 0x25, 0x62, 0x04, 0xb5, 0xcd, 0x40, 0x0b, 0x93, 0x62, 0x4d, 0x39, 0x32, 0xe7, 0xc2, 0xb0, 0x46),
+      //   aad: vec!(0x6a, 0xeb, 0x70, 0x31, 0xe4, 0xa2, 0xe2, 0x3e, 0xea, 0x93, 0xf0, 0x5f, 0xdc, 0x56, 0x2a, 0xa2, 0xbf, 0x43, 0xb8, 0x99, 0x8b, 0xea, 0x73, 0x44, 0x37, 0x7a, 0xad, 0xdc, 0x60, 0xfb, 0xdb, 0x7b, 0xcb, 0x14, 0x91, 0xd3, 0x79, 0xed, 0x0c, 0xb6, 0x13, 0xee, 0x75, 0x7c, 0xfb, 0x66, 0x49, 0x0d, 0xb6, 0x1b, 0xb4, 0x31, 0xd2, 0xfa, 0xd3, 0x4b, 0x38, 0xdd, 0xd5, 0x5b, 0xc5, 0xb2, 0x2a, 0xa6, 0xc4, 0x77, 0x3b, 0x99, 0x92, 0xf3, 0x4b, 0x87, 0x8c, 0x56, 0x63, 0xf6, 0xe8, 0xcd, 0xb5, 0xf8, 0x0a, 0x17, 0xf4, 0xd3, 0x12, 0xbf, 0x34, 0x24, 0x92, 0xe4, 0x8d, 0x1c, 0xe4, 0xc6, 0xd7, 0x54, 0x07, 0x6a, 0x63, 0x4f, 0xec, 0xe6, 0x15, 0x00, 0xac, 0xf8, 0x16, 0x8d, 0x47, 0x38, 0x1a, 0xf4, 0xfa, 0xf9, 0x80, 0xc6, 0xca, 0xc2, 0xbf, 0xd5, 0xda, 0x8c, 0x09, 0xb6, 0xed, 0xb0, 0xf5, 0x43, 0xbf, 0x0f, 0xe0, 0x26, 0x43, 0xe3, 0x8d, 0x73, 0xfa, 0x37, 0xd8, 0xae, 0x87, 0xfb, 0x66, 0x19, 0x3f, 0x22, 0xe5, 0x7f, 0xaf, 0x43, 0x93, 0xc0, 0x07, 0xd4, 0x8c, 0x86, 0x31, 0xa6, 0x85, 0xd5, 0x20, 0x57, 0x8f, 0x8f, 0x89, 0xdb, 0x68, 0x4f, 0xb3, 0x71, 0xea, 0x02, 0xf3, 0xa5, 0x8b, 0x1e, 0x21, 0x68, 0xf0, 0x21, 0x63, 0x21, 0x13, 0x94, 0x72, 0xe0, 0xd0, 0x3b, 0x6d, 0x90, 0xba, 0x8a, 0xab, 0x65, 0x40, 0x2e, 0x1c, 0x1a, 0xc4, 0xf9, 0x17, 0x2a, 0x60, 0xe2, 0x7e, 0x3d, 0x99, 0x7b, 0x9b, 0x05, 0xe2, 0xf6, 0x72, 0x12, 0x0d, 0x6c, 0x87, 0xbc, 0xaf, 0xa6, 0xd4, 0xc9, 0xb4, 0xcf, 0x8b, 0xa8, 0xa8, 0x29, 0x32, 0xd9, 0x28, 0x40, 0x36, 0x8f, 0xc5, 0x3d, 0xc5, 0xb4, 0x85, 0x26, 0x10, 0x3d, 0xca, 0xb5, 0xf1, 0x53, 0x10, 0x38, 0xaa, 0xbe, 0x89, 0x17, 0x13, 0x27, 0xac, 0x55, 0x9b, 0x98, 0xa3, 0xcf, 0x4e, 0xa7, 0x0b, 0xf0, 0x51),
+      //   cipher_text: vec!(0x9c, 0x3f, 0xaa, 0xb9, 0x26, 0x1a, 0x63, 0xce, 0xa9, 0x47, 0x7b, 0x32, 0x69, 0x00, 0x72, 0x83, 0x99, 0x5b, 0x06, 0xba, 0x77, 0xef, 0x83, 0xd9, 0xe6, 0x93, 0xf7, 0xe4, 0xee, 0x98, 0x55, 0x55, 0x0e, 0xef, 0x94, 0x85, 0x5b, 0xe3, 0x9a, 0x7a, 0x43, 0x5b, 0x6a, 0x35, 0x84, 0xb2, 0x02, 0x97, 0x37, 0x77, 0xc7, 0xb2, 0x48, 0x23, 0x76, 0xba, 0x47, 0xb4, 0x93, 0x11, 0x94, 0x7a, 0x64, 0x98, 0x3b, 0x60, 0x23, 0x67, 0x56, 0xee, 0x44, 0x55, 0xd4, 0xcf, 0xad, 0xa8, 0xc3, 0x6a, 0xf8, 0xeb, 0x06, 0xb0, 0x6b, 0xa2, 0xf6, 0xb7, 0x9f, 0xfb, 0x11, 0x85, 0xc8, 0x9f, 0x2b, 0x2a, 0x83, 0x1c, 0xfa, 0xa3, 0x85, 0x5f, 0xc1, 0x84, 0x1d, 0x89, 0x10, 0x90, 0x8b, 0xe5, 0x07, 0x83, 0x52, 0x01, 0x11, 0x68, 0xa6, 0x7d, 0x36, 0x37, 0x2d, 0x85, 0x1a, 0x32, 0x17, 0xca, 0xbf, 0x59, 0x3e, 0xa4, 0x62, 0xdc, 0xd3, 0x25, 0xcf, 0x9a, 0x4f, 0x67, 0xe8, 0x54, 0x18, 0xfd, 0x5c, 0x92, 0x4e, 0x9b, 0x92, 0xab, 0x02, 0x6c, 0xbe, 0xe4, 0xe7, 0xab, 0x10, 0x67, 0x06, 0x6c, 0xb5, 0x94, 0x9d, 0xfc, 0x69, 0x9a, 0x68, 0xfe, 0x53, 0x9e, 0x1a, 0xbb, 0x13, 0xce, 0xc3, 0x39, 0x04, 0xe5, 0x20, 0x7e, 0x69, 0x63, 0xd2, 0x4f, 0x5a, 0x0b, 0x77, 0x06, 0x13, 0xb8, 0xb0, 0x00, 0x14, 0xe7, 0x91, 0xbf, 0xff, 0x88, 0xf9, 0xc2, 0x5c, 0xa1, 0x26, 0x12, 0x7a, 0x2f, 0x8d, 0x1d, 0x1e, 0x97, 0x94, 0xef, 0xd2, 0x8d, 0xce, 0x98, 0xb5, 0x3e, 0x22, 0x80, 0x73, 0xfa, 0xae, 0x8d, 0x50, 0x47, 0x53, 0x0d, 0x50, 0x21, 0x84, 0xfc, 0x34, 0x13, 0x21, 0xc3, 0xf5, 0x5f, 0xcb, 0xf4, 0x11, 0x87, 0xfc, 0x31, 0x26, 0x2c, 0x32, 0x5b, 0x97, 0xf5, 0x19, 0x95, 0x9b, 0x6a, 0x29, 0xb3, 0x6c, 0x71, 0xf7, 0x6f, 0x60, 0x19, 0x6b, 0xb1, 0x45, 0x7b, 0x77, 0xc8, 0xbb),
+      //   tag: vec!(0xb4, 0x5d, 0xf1, 0x19, 0x04, 0x3d, 0x29, 0x00, 0x8f, 0xce, 0xf3, 0x6a, 0x16, 0x9e, 0xf8, 0x86)
+      // },
+      // TestVector{
+      //   key: [0x98, 0xcd, 0x24, 0x77, 0xa7, 0xa0, 0x72, 0xc6, 0x9f, 0x37, 0x5b, 0x88, 0xd0, 0x9e, 0xd9, 0xd7, 0xb9, 0xc3, 0xdf, 0x3f, 0x87, 0xe3, 0x6c, 0xe6, 0x21, 0x72, 0x6f, 0x76, 0xe3, 0xb4, 0x1a, 0x1d],
+      //   nonce: [0x77, 0xd1, 0x85, 0xaa, 0xf7, 0x15, 0xaa, 0x48],
+      //   plain_text: vec!(0x42, 0xb3, 0x1e, 0xef, 0xda, 0xca, 0xb0, 0xf0, 0x3e, 0xf6, 0x06, 0x01, 0x56, 0x00, 0x0c, 0x81, 0x95, 0xad, 0xb0, 0x97, 0x6c, 0xab, 0xbe, 0x1a, 0x42, 0xbf, 0xcc, 0x09, 0xf8, 0x56, 0x59, 0xc6, 0x0b, 0x98, 0x63, 0x84, 0x01, 0xf2, 0xd2, 0xe2, 0xfa, 0xcf, 0xb9, 0xa9, 0x7a, 0x62, 0x92, 0x6b, 0xb0, 0xce, 0xca, 0xf3, 0xaf, 0x01, 0x80, 0xa0, 0x1b, 0xfb, 0x6e, 0x57, 0x6b, 0xab, 0xf7, 0xfc, 0x43, 0x33, 0x19, 0x37, 0xa9, 0x2a, 0xbd, 0x30, 0xcd, 0xdf, 0xa3, 0xe4, 0x50, 0xf8, 0x95, 0xe9, 0xdd, 0x91, 0x4d, 0xea, 0x3f, 0xaf, 0xd7, 0x59, 0xc1, 0x36, 0xd6, 0x85, 0x31, 0x0e, 0xbc, 0xe2, 0x8a, 0xc0, 0x61, 0x3c, 0xcd, 0xbf, 0x30, 0x11, 0x59, 0x46, 0xc9, 0x63, 0x4b, 0x67, 0x51, 0x0b, 0x77, 0xd0, 0xe3, 0x7f, 0x07, 0x71, 0x4b, 0x2d, 0xda, 0xc9, 0xd7, 0x09, 0x5b, 0x8d, 0x4b, 0xd8, 0x87, 0xc1, 0x32, 0xc4, 0xa9, 0x12, 0x7e, 0xb0, 0x1c, 0x8d, 0xed, 0xb4, 0xc3, 0x9c, 0x87, 0xb9, 0x8a, 0x74, 0x13, 0x16, 0x65, 0x6f, 0x9a, 0x8d, 0x5a, 0x5b, 0x0c, 0x0a, 0xc8, 0x47, 0x89, 0xaa, 0x23, 0x47, 0xa5, 0xf9, 0x9c, 0xa5, 0xad, 0x55, 0xcd, 0x1b, 0xcf, 0x98, 0xf7, 0x03, 0xeb, 0x4b, 0x00, 0xba, 0xdb, 0x8a, 0x85, 0x55, 0xf3, 0x8b, 0x3b, 0x36, 0x8d, 0xb8, 0xba, 0x7c, 0xee, 0xa9, 0x4e, 0x8b, 0x21, 0x9f, 0x51, 0xed, 0xce, 0x75, 0xd8, 0x41, 0x66, 0xb5, 0x60, 0x21, 0x56, 0xed, 0x59, 0x62, 0xa9, 0x3a, 0x51, 0xdb, 0x73, 0xc5, 0x9d, 0x87, 0xe9, 0x06, 0x17, 0x9d, 0x7a, 0x74, 0xa2, 0xa2, 0xa6, 0x9d, 0x8a, 0xd9, 0x9f, 0x32, 0x32, 0x25, 0xc8, 0x7e, 0x47, 0x5d, 0x3f, 0x77, 0x1b, 0x4a, 0x20, 0x3a, 0x2e, 0x2b, 0x03, 0xb4, 0x58, 0x40, 0x10, 0x44, 0x64, 0x9f, 0xa6, 0x53, 0x6d, 0xfa, 0xb2, 0x4d, 0x70, 0x37, 0x80, 0x7d, 0xcb, 0xf6, 0x51, 0x8e, 0x65, 0x78),
+      //   aad: vec!(0xf5, 0xbb, 0x14, 0x96, 0x05, 0x2a, 0x43, 0x61, 0xdd, 0xdf, 0x72, 0xa2, 0x88, 0xe3, 0x69, 0x53, 0xa3, 0xd8, 0x15, 0xd6, 0x87, 0x6c, 0x01, 0x3f, 0x1d, 0x6b, 0xa8, 0x39, 0xe1, 0x27, 0xf7, 0x21, 0xb0, 0x52, 0xb1, 0xf7, 0xd8, 0xca, 0x20, 0xc7, 0xdc, 0x03, 0x86, 0xa7, 0xd4, 0x59, 0xeb, 0xd7, 0xeb, 0x9f, 0xc8, 0xcb, 0x08, 0x94, 0x1e, 0x6c, 0xa9, 0xdd, 0xb9, 0x80, 0xf3, 0x11, 0x5f, 0x65, 0xbc, 0x19, 0x28, 0xa4, 0x14, 0xd4, 0x41, 0xae, 0x71, 0xdc, 0xb8, 0x79, 0xd5, 0xbf, 0xe0, 0xcd, 0xe0, 0x56, 0x2b, 0xc3, 0x7f, 0x8f, 0xde, 0x0d, 0x52, 0x91, 0xad, 0x40, 0x5c, 0x92, 0xfc, 0xbb, 0x86, 0x0c, 0x43, 0xb5, 0x5a, 0xc0, 0xfe, 0x66, 0x3b, 0x54, 0xb3, 0xd0, 0x61, 0x6a, 0xca, 0x13, 0xa5, 0xc8, 0x2b, 0x7b, 0x5d, 0x34, 0x12, 0x5a, 0x05, 0xc2, 0xac, 0xb5, 0x53, 0x01, 0x41, 0x03, 0x0e, 0x6f, 0x2a, 0xa0, 0xc8, 0x32, 0x2b, 0x2c, 0x8f, 0xa3, 0x07, 0xe7, 0x51, 0x89, 0x18, 0xe5, 0x50, 0xe9, 0xf4, 0x89, 0x21, 0xc6, 0x16, 0x8f, 0x09, 0x4d, 0x87, 0x58, 0xe1, 0x6b, 0x9f, 0x81, 0x5f, 0xd0, 0x45, 0x80, 0x95, 0xc4, 0x14, 0x3f, 0x09, 0x22, 0xad, 0xb1, 0x84, 0x0d, 0x0e, 0x68, 0x56, 0x36, 0x82, 0x5a, 0x9c, 0x90, 0xee, 0x90, 0xee, 0x53, 0x7f, 0x4b, 0x8d, 0xce, 0xec, 0xbc, 0x42, 0x87, 0xc8, 0x2d, 0xc9, 0xa0, 0x0d, 0x7e, 0x51, 0x67, 0x1e, 0x37, 0xea, 0x28, 0x4e, 0xe3, 0xca, 0x50, 0x1b, 0x1b, 0x25, 0x96, 0x45, 0x9d, 0x3f, 0x59, 0x2f, 0x70, 0x18, 0x6f, 0x41, 0x12, 0x57, 0x39, 0xe3, 0x42, 0xc9, 0xf6, 0xbe, 0x92, 0x41, 0x97, 0x3b, 0x14, 0x14, 0xdf, 0xe5, 0xfb, 0x8c, 0xba, 0x1a, 0xf8, 0x2e, 0x67, 0x92, 0x78, 0xcf, 0xcf, 0x95, 0x42, 0x0d, 0xf0, 0xc5, 0x36, 0x4a, 0xf4, 0xd7, 0xe7, 0x2a, 0xd5, 0x7d, 0x5c, 0x87, 0x1f, 0xcb, 0xc3, 0x54, 0x62),
+      //   cipher_text: vec!(0x7a, 0x3b, 0xf3, 0xe3, 0xad, 0x5a, 0xe3, 0xab, 0x71, 0xfb, 0x1f, 0x71, 0x21, 0xc3, 0xd8, 0xfb, 0x51, 0x10, 0x99, 0x48, 0x4b, 0x50, 0xaf, 0x7c, 0xa1, 0x28, 0xee, 0x03, 0x37, 0xed, 0x4b, 0x82, 0x8d, 0xc4, 0xcd, 0xe0, 0xb8, 0x8d, 0xc1, 0xe8, 0x08, 0x91, 0x01, 0xfa, 0x82, 0xc9, 0xbe, 0xb3, 0xeb, 0x48, 0xfd, 0xcf, 0x0f, 0x5b, 0x16, 0xda, 0x44, 0x1f, 0x5a, 0x3f, 0xce, 0x9a, 0x59, 0x00, 0x22, 0xaf, 0x95, 0xa9, 0x4a, 0xed, 0x6a, 0x3e, 0x71, 0xe5, 0x05, 0xf6, 0x0f, 0x30, 0x3c, 0x78, 0xc3, 0x56, 0xf2, 0x74, 0xea, 0x85, 0xa5, 0x53, 0x54, 0x07, 0x85, 0x30, 0x66, 0x4e, 0xcd, 0xa3, 0x2c, 0x80, 0xe7, 0x7d, 0xc2, 0x09, 0x74, 0xb3, 0xb3, 0x8f, 0x48, 0x25, 0xb8, 0xfb, 0xee, 0x8c, 0x39, 0x70, 0x76, 0x9a, 0x2f, 0x42, 0xc5, 0x18, 0x16, 0x08, 0xa8, 0xd7, 0xd7, 0x6e, 0xf4, 0xd0, 0x93, 0x96, 0x1b, 0x66, 0x5e, 0xe4, 0x2b, 0x97, 0x08, 0xfc, 0xaf, 0xe2, 0xc8, 0x2d, 0x3a, 0x30, 0x71, 0x73, 0xe2, 0xa2, 0x5a, 0xd2, 0x52, 0x8c, 0x3b, 0xf8, 0x33, 0x52, 0xb9, 0x26, 0x5e, 0x45, 0xb7, 0x07, 0x22, 0xd7, 0xcf, 0x8c, 0x9b, 0x80, 0x82, 0x6d, 0x21, 0x33, 0x52, 0x34, 0xee, 0x3d, 0xb6, 0x9d, 0x0d, 0x37, 0x87, 0x1c, 0x83, 0x22, 0x23, 0x65, 0x90, 0x0c, 0x96, 0xc1, 0x7a, 0x7e, 0x9f, 0x57, 0x42, 0xd0, 0xbf, 0xe3, 0x83, 0xbe, 0x24, 0xd0, 0xd4, 0x45, 0x90, 0xd4, 0xb0, 0xf2, 0x9f, 0x7a, 0xbe, 0x0c, 0x65, 0xda, 0xaf, 0xfb, 0x96, 0x8b, 0x3f, 0x26, 0x57, 0xb1, 0xeb, 0x30, 0x05, 0x34, 0xea, 0xcb, 0x52, 0xec, 0x7a, 0x6b, 0x6f, 0x9f, 0x57, 0xa5, 0x0a, 0x91, 0xb1, 0x79, 0x9f, 0x49, 0x13, 0x61, 0xcf, 0x61, 0x3c, 0x93, 0x4b, 0x7f, 0x52, 0x0d, 0xc4, 0xee, 0xeb, 0x40, 0xff, 0xc4, 0x5e, 0x10, 0xbe, 0x0a, 0x95, 0xe7, 0x6f, 0x36, 0x6d, 0x4e, 0xac, 0x14),
+      //   tag: vec!(0xf6, 0x13, 0xb6, 0x52, 0x26, 0xaf, 0xb6, 0x4c, 0x61, 0x4f, 0xe6, 0x0d, 0x9c, 0x71, 0xed, 0x74)
+      // },
+      // TestVector{
+      //   key: [0x2f, 0x0f, 0x46, 0x31, 0xab, 0x1c, 0x1b, 0xcf, 0x8f, 0x3a, 0xd0, 0x55, 0x9c, 0x81, 0x8d, 0x50, 0xe0, 0xaf, 0x7d, 0x8c, 0xd6, 0x3f, 0xaa, 0x35, 0x7f, 0x20, 0x69, 0xf3, 0x08, 0x81, 0xd9, 0xcb],
+      //   nonce: [0x7d, 0x0c, 0xed, 0x2f, 0xdb, 0x1c, 0x91, 0x73],
+      //   plain_text: vec!(0x65, 0x16, 0xba, 0x1d, 0x29, 0x35, 0x71, 0x44, 0xee, 0xbf, 0xa4, 0x86, 0xd2, 0x1d, 0xec, 0xf2, 0x23, 0xda, 0x3a, 0xa7, 0x6e, 0xc2, 0x9b, 0xbf, 0xcb, 0xe7, 0xf1, 0xee, 0xaf, 0x4a, 0x84, 0x77, 0x10, 0xe5, 0x08, 0x01, 0x77, 0xf7, 0xe5, 0xa7, 0xc8, 0xb4, 0x75, 0x2c, 0x21, 0x9b, 0x1c, 0xc7, 0x0a, 0xef, 0x4d, 0xb8, 0x61, 0xba, 0x67, 0xd0, 0xfa, 0x62, 0x22, 0xd9, 0xf4, 0xa1, 0xdc, 0x75, 0x6a, 0x0b, 0xa4, 0x4e, 0x62, 0x90, 0x6f, 0x93, 0x74, 0xa9, 0x60, 0xc1, 0x61, 0x98, 0x86, 0x6d, 0x86, 0x78, 0x54, 0xd8, 0x8f, 0x52, 0x8a, 0x60, 0xe2, 0x12, 0xeb, 0x91, 0x64, 0x57, 0x87, 0xe7, 0x56, 0x85, 0xb2, 0xe2, 0x15, 0xc0, 0xa4, 0x19, 0x90, 0xab, 0xc3, 0x44, 0xa7, 0x72, 0x36, 0xec, 0x01, 0x86, 0xba, 0x63, 0xa6, 0x64, 0x59, 0x29, 0x38, 0xcc, 0x5a, 0x8a, 0xc1, 0xd3, 0xeb, 0x99, 0xc9, 0x5c, 0xe0, 0x0e, 0x19, 0xfb, 0xe2, 0x49, 0x26, 0x30, 0x83, 0xd8, 0x5b, 0x05, 0x2d, 0x48, 0xbf, 0xdf, 0xfc, 0x01, 0x58, 0x5d, 0xc5, 0x7b, 0xb2, 0xa2, 0xc6, 0xc4, 0xa8, 0x19, 0x60, 0x4c, 0x1e, 0xc0, 0x54, 0x8c, 0x6f, 0x0f, 0x78, 0xdc, 0x05, 0xe4, 0x41, 0x8b, 0x36, 0x27, 0x7d, 0xc0, 0x72, 0x33, 0xc7, 0x53, 0x2f, 0x9c, 0x28, 0x9d, 0x6a, 0xed, 0x0c, 0xc6, 0xbc, 0x7d, 0xf4, 0xfd, 0x0a, 0x53, 0x6c, 0x49, 0x7b, 0x98, 0x2e, 0x2d, 0xad, 0x2c, 0x30, 0xd2, 0xdb, 0x1c, 0x65, 0x45, 0xa8, 0x45, 0xc5, 0xdf, 0xa8, 0x3a, 0x4a, 0xc4, 0x9e, 0xf0, 0x6f, 0xc9, 0xc9, 0x19, 0x07, 0x9d, 0x3e, 0x29, 0x9e, 0x31, 0xb5, 0xc3, 0xbe, 0x37, 0x08, 0x14, 0xae, 0x50, 0x22, 0xae, 0x46, 0x9d, 0x3e, 0xe5, 0x52, 0x46, 0xa4, 0x1b, 0xd0, 0xdc, 0x4e, 0x64, 0x35, 0x1c, 0xc3, 0x8c, 0x3c, 0x09, 0xaf, 0x0a, 0x1a, 0xee, 0x3b, 0x38, 0x8a, 0x68, 0x92, 0xde, 0xff, 0x0d, 0xf3, 0xf9, 0x3c, 0xd9, 0x2d, 0x72, 0x2b),
+      //   aad: vec!(0x1c, 0xcf, 0xa1, 0xec, 0xec, 0xc8, 0xde, 0x1e, 0x20, 0x0d, 0x0e, 0xcc, 0x19, 0xdc, 0xf6, 0x7b, 0x7c, 0x96, 0xbe, 0xa3, 0xa2, 0x82, 0xc2, 0xbc, 0xcb, 0xa6, 0x10, 0x35, 0xdb, 0x5c, 0x14, 0x77, 0x63, 0x87, 0xb8, 0xb8, 0xf5, 0x8e, 0x57, 0x57, 0xde, 0xb0, 0x12, 0x9d, 0x4e, 0x5e, 0x31, 0x5f, 0x64, 0xdf, 0x35, 0x4a, 0x59, 0x85, 0xd2, 0xe4, 0x7e, 0xbb, 0xbe, 0xaf, 0xe0, 0xc9, 0x14, 0xf7, 0xcf, 0x1d, 0x63, 0xdd, 0x03, 0x11, 0xac, 0xe1, 0x9e, 0x69, 0xa8, 0xb6, 0xff, 0x0a, 0xb2, 0x5c, 0xc8, 0xdf, 0x04, 0x08, 0xd2, 0x21, 0x32, 0x20, 0x5e, 0x89, 0xe5, 0xeb, 0x67, 0x92, 0x68, 0xd8, 0x2b, 0x29, 0x13, 0xe6, 0x4e, 0x3f, 0x88, 0x5b, 0xbf, 0x4a, 0x6d, 0x37, 0x9b, 0x76, 0x0b, 0x94, 0x59, 0x0e, 0x31, 0x40, 0xdd, 0x72, 0x75, 0xab, 0x47, 0x13, 0xcb, 0x56, 0xd0, 0xb7, 0x16, 0xe2, 0x71, 0x8f, 0x11, 0x31, 0x66, 0x40, 0xcb, 0x39, 0x48, 0x02, 0x86, 0x2d, 0x39, 0xe7, 0x7a, 0x46, 0xd0, 0xc0, 0x65, 0xaf, 0x3c, 0xaf, 0x7d, 0xec, 0x14, 0xe8, 0x87, 0x03, 0x9d, 0x8a, 0xa8, 0xc3, 0xd3, 0xa8, 0xac, 0x1e, 0xe0, 0x60, 0x26, 0xf4, 0x9d, 0x00, 0xb2, 0xf5, 0x9d, 0x97, 0x1b, 0x54, 0x73, 0x5e, 0x95, 0xa5, 0x1f, 0x19, 0x93, 0x89, 0xa9, 0x3a, 0x4f, 0xc2, 0x4e, 0xba, 0xba, 0x1f, 0x7a, 0x2e, 0xef, 0x74, 0x12, 0xf6, 0x1f, 0xeb, 0xf7, 0x90, 0x84, 0xfb, 0xf4, 0x81, 0xaf, 0xc6, 0xfb, 0x6b, 0x20, 0x40, 0x84, 0xe5, 0xef, 0x5d, 0xf7, 0x1f, 0x30, 0x50, 0x64, 0x59, 0xde, 0xa0, 0x74, 0xf1, 0x1f, 0xc0, 0x55, 0xcd, 0x2a, 0x8c, 0x0f, 0xc9, 0x22, 0xc4, 0x81, 0x1a, 0x84, 0x99, 0x84, 0x35, 0x2a, 0x56, 0xa1, 0x56, 0x59, 0xb7, 0xd0, 0x7a, 0x4c, 0xc9, 0x0b, 0x88, 0x62, 0x36, 0x38, 0xea, 0x00, 0xc4, 0xc8, 0xbc, 0x13, 0x88, 0x4d, 0xf2, 0x23, 0x7b, 0x35, 0x9f, 0x28, 0x77, 0xaa, 0x41, 0xd6),
+      //   cipher_text: vec!(0xe5, 0x80, 0x09, 0x37, 0x89, 0xba, 0x17, 0xff, 0xb4, 0x66, 0x72, 0xdc, 0x32, 0x6f, 0x09, 0x27, 0x8a, 0xca, 0x08, 0x59, 0x8d, 0x3e, 0x54, 0x58, 0xea, 0xa5, 0x3e, 0x6e, 0xd4, 0x5d, 0x5c, 0x71, 0xa3, 0x96, 0xe3, 0x5b, 0x5e, 0xa3, 0xfe, 0x7b, 0x7c, 0x04, 0x96, 0xa7, 0x34, 0xd2, 0x4f, 0x1c, 0x75, 0x42, 0x06, 0x94, 0xbe, 0x2f, 0xf0, 0x95, 0xd5, 0x17, 0x2f, 0xd3, 0x40, 0x77, 0x94, 0xe4, 0xb9, 0x9f, 0xd7, 0xc3, 0x74, 0xfb, 0xe8, 0xd1, 0x56, 0x4a, 0x04, 0x86, 0x14, 0xd3, 0xf3, 0x55, 0xbf, 0xb5, 0x86, 0x6d, 0xe1, 0xa5, 0x3e, 0x1a, 0x51, 0xf9, 0xf5, 0xe8, 0x31, 0x22, 0x53, 0xcf, 0xd8, 0x2f, 0x36, 0xef, 0xaa, 0x18, 0x98, 0xc8, 0x50, 0xca, 0x0d, 0x97, 0x5a, 0xd1, 0xe8, 0xb0, 0xd9, 0x59, 0x7a, 0x5a, 0x9e, 0x65, 0x16, 0xfe, 0x2a, 0x3c, 0x92, 0xef, 0xb7, 0x49, 0x55, 0x57, 0xa8, 0xaf, 0xc3, 0xda, 0x15, 0xb0, 0xd3, 0xe2, 0xba, 0x58, 0xf6, 0x12, 0x51, 0x98, 0x36, 0x94, 0x6c, 0xf2, 0xd1, 0x5b, 0x89, 0x83, 0x20, 0xd1, 0x6a, 0x02, 0x6c, 0x8c, 0x00, 0xa1, 0xbe, 0x2e, 0x35, 0xf0, 0xeb, 0xe6, 0x8f, 0x28, 0xd9, 0x1c, 0x6c, 0x45, 0xd2, 0x4c, 0x3f, 0x3c, 0x15, 0x7c, 0xb1, 0x32, 0xfa, 0x65, 0x9b, 0x77, 0x94, 0xdf, 0x88, 0x3d, 0x90, 0x74, 0x1f, 0xa2, 0xd2, 0xaf, 0xcc, 0x4f, 0x27, 0x85, 0x8e, 0x13, 0xec, 0xd4, 0x1b, 0x15, 0x4a, 0x35, 0xd2, 0x49, 0x47, 0xae, 0x73, 0x61, 0x17, 0x00, 0x60, 0xc1, 0x07, 0xd8, 0xec, 0xac, 0xb3, 0x93, 0xea, 0x67, 0x10, 0x4b, 0x60, 0x45, 0x72, 0x78, 0xa3, 0x92, 0xfd, 0xf1, 0x79, 0x4b, 0xab, 0x97, 0xd3, 0xb0, 0x2b, 0x71, 0xa4, 0xeb, 0x01, 0x5e, 0xaa, 0x38, 0xa4, 0xb4, 0xc9, 0x44, 0xc2, 0xbc, 0x7c, 0xd5, 0xe3, 0x29, 0xda, 0x4a, 0x1a, 0xb2, 0x93, 0x7a, 0x6a, 0xf8, 0x1a, 0x6c, 0xaa, 0x5f, 0xce, 0x75, 0x23, 0x31, 0xfd, 0xef, 0xd4),
+      //   tag: vec!(0x0f, 0xd7, 0x41, 0x9c, 0x54, 0xbc, 0x84, 0x26, 0x5e, 0xd3, 0x10, 0xa3, 0x41, 0x1a, 0x3f, 0x2e)
+      // },
+      // TestVector{
+      //   key: [0xa4, 0x8b, 0x9b, 0x6d, 0xf4, 0x75, 0xe5, 0x66, 0xab, 0xa7, 0x67, 0x1f, 0xbd, 0x76, 0x77, 0x2c, 0xb0, 0xef, 0xf0, 0xb1, 0x24, 0x99, 0x96, 0x79, 0x78, 0xce, 0x3e, 0x25, 0xfa, 0xc9, 0x2f, 0xeb],
+      //   nonce: [0x2c, 0xcb, 0xf0, 0xd6, 0xc4, 0x0c, 0xb3, 0x02],
+      //   plain_text: vec!(0x09, 0xda, 0x1c, 0xac, 0xd0, 0x01, 0xdc, 0xe4, 0xf7, 0x57, 0x3a, 0x06, 0x5a, 0x44, 0x06, 0xfe, 0x0d, 0xa0, 0x4a, 0xb3, 0x67, 0xa2, 0xd8, 0x77, 0x80, 0xa2, 0x76, 0x2e, 0x16, 0x89, 0x57, 0xa8, 0x8d, 0x3f, 0xa7, 0x8f, 0x0a, 0x4b, 0x69, 0x78, 0xd4, 0x49, 0x02, 0x6e, 0x5a, 0x80, 0x1d, 0x32, 0x88, 0x4b, 0x6e, 0x14, 0xfd, 0xaa, 0xaf, 0x86, 0x42, 0x14, 0xf9, 0x28, 0xeb, 0xc0, 0x3d, 0xea, 0xd0, 0x81, 0xfe, 0xe9, 0x66, 0x83, 0xeb, 0xb0, 0x32, 0x36, 0x2d, 0x50, 0x88, 0xc4, 0xc2, 0xa3, 0xb1, 0xe2, 0x42, 0xf0, 0x55, 0xf2, 0x60, 0x49, 0x19, 0xf4, 0xdd, 0x55, 0x1d, 0xb7, 0x77, 0xa2, 0x58, 0xcf, 0x9d, 0xa6, 0xd9, 0x5a, 0x2b, 0xde, 0x24, 0x92, 0x47, 0x81, 0x2b, 0x9e, 0xfc, 0x79, 0x85, 0xcf, 0x08, 0x70, 0x76, 0x20, 0x80, 0x85, 0x24, 0xd6, 0xdd, 0x30, 0x79, 0xb0, 0xb6, 0x3b, 0xf0, 0xf7, 0x1e, 0xa5, 0xde, 0x83, 0x4c, 0xcb, 0x8b, 0x7c, 0x6a, 0x97, 0x12, 0x5f, 0xd6, 0xca, 0x49, 0x14, 0x8e, 0x86, 0x6d, 0x31, 0x34, 0xbb, 0xf1, 0xd8, 0xa6, 0xb7, 0x14, 0xe9, 0xa8, 0x0f, 0xe5, 0x49, 0xc8, 0xbf, 0xef, 0xe3, 0x42, 0xf4, 0x1b, 0xe2, 0xba, 0x23, 0x00, 0xe0, 0x02, 0x8f, 0x78, 0xce, 0xfa, 0xb6, 0x52, 0x74, 0x63, 0x2d, 0xfd, 0xbe, 0x70, 0xbf, 0x7d, 0x65, 0x5e, 0xc4, 0x03, 0x6d, 0xf5, 0x61, 0xf2, 0xd4, 0xfc, 0x4d, 0x56, 0xa4, 0x82, 0xbb, 0xe2, 0xf9, 0xf2, 0xae, 0x27, 0x9b, 0x3a, 0xa2, 0x16, 0xb3, 0x9a, 0xfe, 0xe7, 0x5e, 0x53, 0x60, 0x2d, 0xe3, 0x19, 0x48, 0x4d, 0xb8, 0x9a, 0x51, 0xe8, 0x44, 0xf3, 0x8c, 0x36, 0x16, 0x34, 0xe4, 0x74, 0xf8, 0xf1, 0xf0, 0x1c, 0x34, 0x0f, 0x3f, 0x35, 0x94, 0x86, 0x0d, 0x67, 0x13, 0x46, 0x44, 0x9c, 0x6d, 0x08, 0xee, 0x38, 0xde, 0x22, 0xd2, 0x46, 0x30, 0x9b, 0xc7, 0xe4, 0xa2, 0x52, 0xa2, 0x9c, 0x86, 0xaa, 0x6d, 0x94, 0xb5, 0xb4, 0xfa, 0x58, 0x90, 0x4c, 0x70),
+      //   aad: vec!(0x1c, 0x25, 0x03, 0xd5, 0xaa, 0x1a, 0xad, 0x19, 0x3f, 0x0d, 0xa1, 0x28, 0x74, 0x07, 0x4e, 0xa0, 0x43, 0x2b, 0xb7, 0x6a, 0x61, 0xcd, 0x43, 0xa3, 0x01, 0x70, 0x61, 0x51, 0x4d, 0xa0, 0x75, 0x98, 0x46, 0xa0, 0xf3, 0xae, 0x3a, 0x49, 0xfd, 0xb0, 0xb6, 0xd2, 0x9f, 0x71, 0x3d, 0xe6, 0x65, 0xbe, 0xac, 0xb6, 0x56, 0x8f, 0x26, 0x94, 0x11, 0x2c, 0xa3, 0x80, 0xd1, 0x3f, 0x3c, 0x16, 0x98, 0x31, 0x68, 0x66, 0xa7, 0xa7, 0xf8, 0x7f, 0x1d, 0x75, 0x03, 0xa9, 0x21, 0x76, 0xab, 0x84, 0xfc, 0x08, 0x97, 0x7b, 0x46, 0xba, 0x66, 0x45, 0x08, 0xa8, 0x58, 0xe7, 0x52, 0x57, 0x53, 0xc4, 0x55, 0x11, 0xb3, 0xd2, 0xf4, 0x07, 0xd5, 0xe9, 0x93, 0xc6, 0xed, 0xe7, 0x7f, 0x13, 0xd1, 0x29, 0x75, 0x70, 0x7e, 0x51, 0x95, 0x70, 0x49, 0x70, 0xa8, 0x9f, 0x71, 0xfc, 0x30, 0x82, 0x80, 0x49, 0xf9, 0x2f, 0x94, 0x4f, 0x3a, 0xa9, 0x3d, 0x6a, 0x52, 0x97, 0xe6, 0x78, 0xe0, 0x89, 0x52, 0x91, 0x9b, 0xeb, 0x7e, 0xac, 0x59, 0x19, 0xdf, 0x19, 0x19, 0xca, 0xb3, 0xc3, 0xda, 0x6a, 0xa6, 0x96, 0xa1, 0xee, 0xab, 0x63, 0x71, 0xf3, 0x10, 0xf7, 0xe8, 0x11, 0x43, 0xe7, 0xd2, 0x40, 0xb0, 0x21, 0x3a, 0xe5, 0x54, 0x52, 0x4b, 0x52, 0x00, 0x03, 0x06, 0x16, 0x0d, 0xd4, 0x87, 0x7b, 0xf1, 0x3b, 0xa0, 0xf1, 0x3b, 0xbe, 0x86, 0x7d, 0xa7, 0xc7, 0xd7, 0x07, 0xf3, 0x13, 0x35, 0xee, 0xf4, 0xcd, 0x94, 0x29, 0x38, 0xac, 0x89, 0x0a, 0x08, 0x29, 0xec, 0x66, 0xbd, 0x30, 0xae, 0x01, 0xa2, 0x18, 0x8a, 0x6e, 0x5e, 0xa0, 0xf1, 0x7c, 0xd7, 0xdc, 0x87, 0x5e, 0x17, 0xf0, 0x3c, 0x0a, 0xb5, 0xdd, 0x18, 0xe3, 0x6d, 0xb8, 0xa1, 0xfc, 0x1f, 0x72, 0x85, 0x9e, 0xe0, 0x46, 0xb6, 0x23, 0x68, 0xf1, 0x68, 0xb3, 0xbe, 0xa2, 0x23, 0x4e, 0x04, 0x32, 0xc0, 0x7b, 0x7d, 0x8e, 0x1b, 0x92, 0x77, 0xf2, 0x1e, 0x69, 0x2c, 0x51, 0x3b, 0x9e, 0x81, 0x6e, 0x68, 0x60),
+      //   cipher_text: vec!(0x7d, 0x35, 0xcf, 0xe4, 0xbe, 0x56, 0xbd, 0x6e, 0x0e, 0x09, 0xde, 0xdc, 0xd0, 0x17, 0x35, 0xb9, 0x15, 0xbc, 0x18, 0x91, 0xa4, 0xd1, 0xf6, 0xa5, 0x41, 0xab, 0xc4, 0xbc, 0xd0, 0xeb, 0xe8, 0x9d, 0xcb, 0x8e, 0x36, 0x5e, 0x58, 0x13, 0x74, 0x2e, 0x8e, 0xc6, 0x57, 0x77, 0xb6, 0x15, 0x94, 0x22, 0xfa, 0xda, 0x74, 0x7d, 0xa9, 0x93, 0x94, 0x25, 0x2b, 0xaf, 0x8a, 0x04, 0x6f, 0xc1, 0xb6, 0x0a, 0xd7, 0x97, 0x55, 0xf5, 0x45, 0xf4, 0x44, 0x86, 0x27, 0xb7, 0xac, 0xaf, 0x40, 0x30, 0x00, 0x89, 0x4f, 0x56, 0x41, 0xe7, 0x8d, 0x3f, 0x94, 0x6d, 0xfc, 0xa2, 0x9e, 0xc6, 0x17, 0xf0, 0x66, 0x0d, 0xcd, 0x6e, 0x8d, 0x88, 0x27, 0xe6, 0x7e, 0x10, 0x22, 0xa2, 0x45, 0xc5, 0x95, 0xd8, 0x6e, 0x60, 0xfb, 0xd1, 0x76, 0xbf, 0x72, 0x1b, 0x17, 0x1b, 0xbe, 0x5e, 0xca, 0xf4, 0xae, 0x67, 0x1b, 0x9f, 0x3d, 0xd3, 0x92, 0x01, 0x46, 0xe6, 0xad, 0x43, 0x1b, 0xd8, 0xfc, 0x43, 0x18, 0x20, 0xe1, 0x94, 0x54, 0xb6, 0xca, 0x20, 0x97, 0x23, 0xd8, 0x0f, 0xdb, 0xee, 0x18, 0x7f, 0xca, 0x9c, 0x93, 0x7c, 0x97, 0x92, 0x06, 0xae, 0x97, 0xbe, 0x55, 0xf6, 0xba, 0x73, 0x66, 0xa5, 0x60, 0x87, 0x70, 0xa1, 0x1d, 0x53, 0x73, 0x96, 0x48, 0x5e, 0xb0, 0xa6, 0x65, 0x86, 0x38, 0x5f, 0x4d, 0x4c, 0xf3, 0x90, 0x5d, 0x1f, 0xc9, 0x08, 0x31, 0xc3, 0xe1, 0x36, 0xd5, 0xd5, 0x13, 0xfa, 0x22, 0xbe, 0x28, 0x51, 0x93, 0x14, 0x29, 0x94, 0xa3, 0xed, 0x47, 0x71, 0x45, 0xba, 0xcd, 0xcb, 0xdd, 0x79, 0x1e, 0x8b, 0x3b, 0x88, 0xb0, 0xd4, 0xf1, 0xd1, 0x8b, 0x27, 0x38, 0x25, 0x50, 0xa8, 0x18, 0xc4, 0xfd, 0x88, 0x84, 0xbf, 0x36, 0xf6, 0x77, 0xc6, 0xc3, 0xff, 0x56, 0x77, 0x40, 0x6e, 0x51, 0x09, 0x11, 0xe6, 0x96, 0xaf, 0x75, 0xe5, 0xb3, 0xf8, 0x59, 0xbe, 0xf6, 0x99, 0xbd, 0xd1, 0x6e, 0x62, 0x15, 0xfd, 0xb9, 0x8d, 0x87, 0x40, 0x25, 0xea, 0xda, 0x50),
+      //   tag: vec!(0x2a, 0xab, 0xff, 0x35, 0x61, 0x1b, 0x3e, 0x00, 0x13, 0xf6, 0xae, 0x0d, 0xf1, 0x30, 0x79, 0x9b)
+      // },
+      // TestVector{
+      //   key: [0x92, 0x3d, 0x4b, 0x08, 0x6b, 0x9e, 0x43, 0xb9, 0x86, 0xf7, 0xb6, 0x5e, 0x4c, 0xea, 0x61, 0x13, 0xa3, 0xd8, 0xaa, 0xbe, 0xfa, 0x89, 0x32, 0x3c, 0x5e, 0x4d, 0x5b, 0x6f, 0x15, 0x8b, 0xb7, 0xe0],
+      //   nonce: [0xa0, 0xf7, 0x32, 0x97, 0xb8, 0x7f, 0x5d, 0xeb],
+      //   plain_text: vec!(0x21, 0x43, 0x5e, 0x8d, 0x5c, 0x8e, 0xdf, 0x06, 0x84, 0xf5, 0x8c, 0x2c, 0xba, 0x40, 0x70, 0xc1, 0x0b, 0x48, 0x01, 0xad, 0xf4, 0x6b, 0x6c, 0x4d, 0x32, 0x2e, 0xb3, 0x99, 0x0a, 0x38, 0xa9, 0xad, 0x33, 0x8a, 0xd7, 0x04, 0xb9, 0xdf, 0x65, 0x97, 0xf3, 0xe6, 0x8d, 0x66, 0xcd, 0x5b, 0x56, 0x29, 0x0c, 0x84, 0x66, 0xdb, 0x22, 0x31, 0xe5, 0x6d, 0x6b, 0xcb, 0x9c, 0x44, 0xe1, 0xbd, 0x08, 0x1f, 0x42, 0xca, 0x2a, 0x89, 0x4d, 0xad, 0x36, 0x9d, 0xf2, 0xbd, 0x0d, 0x2c, 0x63, 0xd6, 0xc8, 0x81, 0x73, 0x2d, 0x6e, 0xa2, 0x2b, 0xb2, 0x2b, 0x5b, 0xc9, 0xa6, 0x2e, 0xaf, 0xfa, 0x1b, 0x09, 0x4d, 0x08, 0x45, 0xf6, 0xb9, 0x66, 0xd2, 0xcb, 0x09, 0x5e, 0x7b, 0x3b, 0x8b, 0xcb, 0xc1, 0x5e, 0x70, 0x74, 0x49, 0xd3, 0x5c, 0x8d, 0xf4, 0xae, 0xa3, 0x0c, 0x3b, 0x72, 0x43, 0xe9, 0x77, 0xff, 0xfd, 0x59, 0xc8, 0x0f, 0x1c, 0x5c, 0x9a, 0xf4, 0xbb, 0x5a, 0x54, 0xb9, 0xc7, 0x86, 0xfb, 0xbe, 0x8d, 0x21, 0xb2, 0xb9, 0x06, 0xa8, 0x7a, 0x78, 0x6c, 0xae, 0xd8, 0x41, 0xa3, 0x4a, 0x3e, 0x0c, 0xc0, 0xac, 0x32, 0x09, 0xd8, 0x3c, 0x58, 0xaf, 0xba, 0x19, 0xed, 0xd6, 0x36, 0x22, 0xdd, 0x26, 0x15, 0x32, 0xd2, 0xcf, 0xb0, 0xb4, 0x9d, 0x52, 0x7d, 0x8e, 0xaa, 0x08, 0x87, 0xa0, 0x87, 0xf5, 0x12, 0x9d, 0x89, 0x7f, 0x66, 0x52, 0x64, 0xb2, 0x29, 0xf8, 0x60, 0x36, 0x3d, 0x71, 0xa8, 0x8b, 0x7d, 0x49, 0xc8, 0xdc, 0x63, 0x60, 0x18, 0x2b, 0x35, 0x7b, 0x06, 0x62, 0x39, 0x1b, 0xb4, 0x13, 0x37, 0xf4, 0x60, 0x10, 0xac, 0x32, 0xb9, 0xfa, 0xda, 0x2d, 0x60, 0xa2, 0xef, 0xcb, 0x99, 0x36, 0x5d, 0x3b, 0x27, 0xb7, 0xac, 0x39, 0x69, 0x00, 0xd1, 0xc8, 0x21, 0xd0, 0xdf, 0x8b, 0x86, 0xcc, 0x9c, 0xc1, 0xf2, 0x67, 0x32, 0x59, 0xa3, 0x3e, 0xfe, 0xa6, 0x10, 0xbf, 0x8e, 0x1d, 0x00, 0xd7, 0xe9, 0xdb, 0x2a, 0xfe, 0xa2, 0x1d, 0xa8, 0xf5, 0x8c, 0x55, 0xf7, 0x99, 0x99, 0x9d),
+      //   aad: vec!(0xc8, 0x53, 0xa8, 0xb3, 0x9c, 0x0d, 0xc5, 0x97, 0xd5, 0x62, 0xf1, 0x23, 0xcd, 0x22, 0x1e, 0x41, 0x04, 0xb6, 0x54, 0x23, 0xa0, 0x62, 0xa4, 0xf4, 0xba, 0x89, 0x0b, 0xa3, 0x44, 0xfe, 0xb8, 0x42, 0x90, 0xf6, 0x18, 0x17, 0xe2, 0x33, 0x30, 0xc3, 0x65, 0xf5, 0x8c, 0x35, 0x83, 0xce, 0x08, 0x36, 0x0d, 0x3c, 0x11, 0x71, 0x98, 0x2e, 0xad, 0x54, 0x96, 0xd5, 0x25, 0xac, 0x87, 0x8f, 0x23, 0xa5, 0x74, 0x80, 0xa6, 0xee, 0x39, 0xd4, 0xe6, 0x5a, 0xfd, 0x62, 0x68, 0x24, 0x5b, 0xb9, 0x82, 0xa2, 0x54, 0x5f, 0xa1, 0x19, 0x54, 0x27, 0xcd, 0xbb, 0xcd, 0x40, 0x4c, 0xda, 0xd5, 0x19, 0x8f, 0x55, 0xcc, 0xe2, 0xa5, 0xa0, 0x28, 0xfa, 0xe4, 0x35, 0xf7, 0x1b, 0x15, 0x92, 0x1d, 0x06, 0x6e, 0x8d, 0x43, 0x76, 0x6c, 0x32, 0xb2, 0xf2, 0xc3, 0xf5, 0x7c, 0x06, 0x74, 0xe1, 0x29, 0x60, 0x7d, 0xcd, 0x37, 0x03, 0xec, 0xa5, 0x29, 0x41, 0x4a, 0xda, 0xee, 0x79, 0xd8, 0x1f, 0xed, 0x43, 0x21, 0x53, 0xcc, 0xeb, 0x6f, 0x3f, 0xc5, 0x34, 0x04, 0x81, 0x0d, 0x8e, 0xc8, 0x78, 0xf7, 0xd9, 0x4b, 0xe5, 0xd3, 0x79, 0xd0, 0xe0, 0xe1, 0xaa, 0x9b, 0xc4, 0x04, 0xb4, 0xb5, 0xd3, 0x96, 0x03, 0x8a, 0x9d, 0x76, 0xa5, 0xce, 0x53, 0xc9, 0xf3, 0x75, 0x9b, 0x8e, 0x50, 0xfb, 0x33, 0x18, 0x58, 0xca, 0x58, 0xce, 0xe8, 0x1b, 0xfc, 0x3e, 0xe5, 0x8b, 0xae, 0xf5, 0xd1, 0x9c, 0x40, 0x2a, 0x3d, 0xc8, 0xb3, 0x63, 0x70, 0xec, 0x1a, 0xce, 0x5a, 0x4a, 0xa2, 0x52, 0x7f, 0xb9, 0x4b, 0x4f, 0x93, 0x3a, 0x4a, 0xb8, 0xcc, 0xaa, 0xf6, 0xa5, 0xaf, 0x5a, 0x77, 0x9e, 0xae, 0x56, 0x67, 0xc2, 0xa2, 0x4a, 0xb0, 0x27, 0xe7, 0x81, 0xc8, 0xd4, 0xf3, 0x0c, 0x37, 0x7a, 0xa5, 0x88, 0x5a, 0x2f, 0xda, 0xf6, 0x50, 0x7d, 0x18, 0xcd, 0x82, 0x4a, 0x84, 0x7c, 0x35, 0x36, 0x8b, 0x4e, 0xa9, 0x84, 0xd2, 0xc3, 0xc3, 0x82, 0x4a, 0x5b, 0x8b, 0xa3, 0x04, 0x2e, 0x18, 0x52, 0x50, 0x4a, 0x21, 0xa3),
+      //   cipher_text: vec!(0xf2, 0xe2, 0x10, 0x52, 0xee, 0xbb, 0xb8, 0x6a, 0x4f, 0x5e, 0x80, 0x33, 0x60, 0x85, 0x5d, 0x86, 0x32, 0xaa, 0x72, 0x7d, 0xca, 0x6f, 0x5e, 0x79, 0xdd, 0x74, 0xd7, 0xaf, 0xf1, 0x06, 0xe4, 0x42, 0x00, 0x19, 0x28, 0xd1, 0x13, 0x00, 0x5b, 0x03, 0x0f, 0x84, 0x46, 0xf8, 0xef, 0xf2, 0xee, 0x95, 0x1d, 0xb6, 0x63, 0x97, 0x8a, 0xbe, 0x43, 0x09, 0x0d, 0xd5, 0xad, 0x2c, 0x51, 0xba, 0x97, 0xa0, 0xec, 0xf9, 0x88, 0xc6, 0x07, 0xd9, 0x5e, 0x48, 0x6d, 0x02, 0x52, 0x4f, 0x69, 0x0f, 0xa3, 0xc2, 0x8d, 0x5c, 0x48, 0xc1, 0xf7, 0x5c, 0x1f, 0x55, 0x5e, 0x7b, 0x43, 0xfe, 0x7e, 0x46, 0xf2, 0xca, 0x2b, 0x9f, 0xdb, 0x40, 0x8e, 0xc4, 0xba, 0x18, 0xb6, 0xcd, 0xde, 0x2a, 0xf6, 0x73, 0x18, 0x3c, 0xb7, 0xb1, 0xa3, 0xc2, 0x3a, 0xe7, 0x7e, 0xdd, 0xd4, 0xca, 0xc7, 0x5e, 0x1e, 0xa1, 0x47, 0x43, 0xfc, 0x57, 0x1f, 0x8d, 0x31, 0xce, 0x2e, 0x96, 0x78, 0x75, 0x24, 0xcd, 0x48, 0xaa, 0xda, 0xa4, 0x74, 0x18, 0x1c, 0x09, 0x6a, 0x03, 0x21, 0x84, 0x57, 0x4d, 0xdc, 0x25, 0xa6, 0xe0, 0xac, 0x84, 0x41, 0xc2, 0x12, 0xbc, 0x36, 0x29, 0x87, 0x08, 0xe3, 0x3c, 0x96, 0x3a, 0xe9, 0x31, 0xe6, 0xc6, 0x24, 0x1d, 0x1a, 0xff, 0xee, 0xf7, 0xb6, 0xef, 0x75, 0x94, 0x95, 0xdf, 0x44, 0xb6, 0xab, 0x64, 0x74, 0x47, 0x69, 0x3c, 0xf7, 0x03, 0x56, 0x9e, 0x69, 0xaa, 0x72, 0xf1, 0xde, 0xf9, 0xa3, 0x42, 0xb8, 0x97, 0x8c, 0x1e, 0xde, 0xa9, 0x70, 0x3a, 0x42, 0x1c, 0xa7, 0x5b, 0x92, 0xca, 0xc4, 0xde, 0x14, 0xb8, 0x8c, 0x69, 0x32, 0x00, 0x02, 0x2b, 0x8a, 0x2e, 0xd2, 0x2b, 0x1c, 0x46, 0x78, 0xb9, 0x9f, 0x4d, 0x69, 0x5e, 0x08, 0x0d, 0xd1, 0x19, 0x6d, 0x71, 0x68, 0xe1, 0x4f, 0x0d, 0x0f, 0x8f, 0xf8, 0x80, 0xd7, 0x42, 0xe9, 0x7b, 0x9f, 0x6d, 0x00, 0xaf, 0x1f, 0x71, 0x18, 0xe1, 0x0b, 0x77, 0xc5, 0xef, 0x3e, 0xa6, 0xc5, 0x2f, 0x84, 0xa2, 0x0f, 0xd6, 0xea, 0x46, 0xdc),
+      //   tag: vec!(0xfa, 0x8e, 0xe1, 0x34, 0x00, 0xfb, 0x3f, 0x63, 0xb8, 0x99, 0xdf, 0x58, 0x2f, 0x2f, 0xec, 0x45)
+      // },
+      // TestVector{
+      //   key: [0xdf, 0x73, 0xad, 0xab, 0x27, 0x68, 0x55, 0x9e, 0xa9, 0x83, 0xcc, 0xe8, 0x54, 0x53, 0xfe, 0x81, 0xd7, 0x9b, 0xe3, 0xb3, 0xc5, 0x7f, 0x20, 0x2b, 0x31, 0xb9, 0x4d, 0x66, 0x35, 0xcf, 0x2e, 0x4b],
+      //   nonce: [0xe7, 0xa8, 0x7e, 0x6b, 0xf6, 0xb5, 0xa3, 0x54],
+      //   plain_text: vec!(0x00, 0x32, 0xa3, 0x7a, 0xbf, 0x66, 0x1f, 0xaa, 0x18, 0xc5, 0x87, 0xfd, 0x2a, 0xa8, 0x88, 0x85, 0xc0, 0x61, 0xde, 0xeb, 0xa8, 0x11, 0x05, 0xdd, 0x22, 0x19, 0x69, 0xbe, 0xd5, 0xd5, 0x9c, 0x72, 0x04, 0xb0, 0x9b, 0x1a, 0x8c, 0x4c, 0x8d, 0xe3, 0xb9, 0xf7, 0x48, 0xc7, 0xfc, 0x70, 0x62, 0x6e, 0xbe, 0xac, 0xa0, 0x60, 0x23, 0x3a, 0x57, 0xb1, 0x02, 0x22, 0x1b, 0x1b, 0xf0, 0xf3, 0xd9, 0xfd, 0xaa, 0xad, 0x3d, 0x2b, 0x14, 0x39, 0xc2, 0x4d, 0x08, 0xf9, 0xc6, 0x7f, 0x49, 0xf3, 0xc4, 0x71, 0x28, 0xf9, 0x2e, 0xe5, 0x30, 0xab, 0xf4, 0xc4, 0xf4, 0x57, 0x3b, 0xc6, 0x0a, 0xe4, 0xb3, 0x81, 0x09, 0xf5, 0x5b, 0xca, 0x3c, 0xa9, 0xe1, 0xba, 0x9f, 0x9f, 0xd6, 0xe3, 0x4b, 0xa0, 0xd1, 0x74, 0x89, 0x29, 0x77, 0xa5, 0x33, 0x56, 0xe1, 0xf5, 0xc8, 0x8c, 0x61, 0x4f, 0xe3, 0xff, 0x3b, 0x3d, 0xd0, 0x81, 0x8e, 0x7a, 0x22, 0x85, 0x41, 0x2e, 0x3b, 0x37, 0x44, 0x4b, 0xbe, 0x8a, 0x80, 0x94, 0x2e, 0xfc, 0xfd, 0x03, 0x95, 0x88, 0x09, 0xa6, 0x96, 0x6c, 0xda, 0x94, 0x30, 0xb2, 0xf0, 0xc9, 0xe5, 0x52, 0xf4, 0xbc, 0xed, 0x6e, 0x19, 0xeb, 0x3e, 0x85, 0xfc, 0x57, 0x58, 0xbd, 0x7b, 0x58, 0x82, 0x97, 0xcc, 0xbe, 0xd3, 0x7e, 0xd9, 0x4c, 0x3a, 0xdc, 0x8c, 0x08, 0xea, 0x8b, 0x05, 0x84, 0x62, 0xaa, 0xc9, 0xd5, 0x7a, 0x93, 0x9e, 0xc7, 0x11, 0xbc, 0x4e, 0xcf, 0xec, 0x94, 0x4d, 0x2b, 0x65, 0x3b, 0x7c, 0xfc, 0x7b, 0x02, 0xa6, 0x5d, 0x70, 0x57, 0xc9, 0xfd, 0xad, 0xd5, 0x1b, 0x9d, 0xa8, 0xcc, 0x4a, 0x3c, 0x68, 0xda, 0xe9, 0xda, 0x8b, 0x9c, 0x53, 0x19, 0xc1, 0xa2, 0xba, 0xa3, 0xd6, 0xc8, 0x91, 0xc5, 0xac, 0x4a, 0x39, 0x46, 0x14, 0x84, 0xb5, 0xa0, 0x1a, 0xbc, 0x64, 0xdf, 0x44, 0x7a, 0xda, 0x24, 0xc0, 0x4a, 0x43, 0x63, 0xe6, 0x05, 0xea, 0xcc, 0xf3, 0x39, 0xa9, 0xaa, 0x51, 0x5e, 0x72, 0x42, 0x06, 0x20, 0x6d, 0xa6, 0xd2, 0x2b, 0xbd, 0x2f, 0x52, 0xe6, 0x4c, 0xd7, 0xc8, 0x95),
+      //   aad: vec!(0xf8, 0x33, 0xe5, 0xab, 0x4f, 0x8b, 0xc8, 0x91, 0x67, 0xf8, 0x0f, 0x57, 0x6b, 0x1d, 0x6b, 0x22, 0xcd, 0xd0, 0xe3, 0x07, 0x21, 0xf5, 0xf7, 0x35, 0x79, 0x97, 0x46, 0xcf, 0x64, 0x5b, 0x6e, 0xff, 0x53, 0x1d, 0x4c, 0x7b, 0x03, 0x58, 0x4f, 0x3d, 0xfc, 0xb7, 0x3c, 0xbd, 0x35, 0xac, 0x42, 0x73, 0x62, 0x16, 0xdc, 0x7f, 0x0d, 0xe0, 0x98, 0xa4, 0xf4, 0x2c, 0x61, 0xce, 0xb4, 0xb2, 0x27, 0xee, 0x28, 0x8e, 0x47, 0xd6, 0x97, 0xa0, 0xa7, 0x6a, 0xfc, 0x76, 0x2f, 0x08, 0x4e, 0x8f, 0xdb, 0xf9, 0x35, 0x1c, 0x28, 0x34, 0x0c, 0x32, 0x47, 0x71, 0xc1, 0x09, 0xa4, 0x69, 0x34, 0x1a, 0xb1, 0x0c, 0xa1, 0x04, 0x83, 0xed, 0x2a, 0xf5, 0xe8, 0x78, 0xd7, 0xd3, 0xdc, 0x2b, 0xce, 0xd2, 0xf7, 0x2d, 0xa3, 0xd1, 0xa2, 0x58, 0x52, 0xb1, 0x03, 0xee, 0x98, 0x78, 0xe8, 0x15, 0x8e, 0xb4, 0x30, 0x9c, 0x1c, 0xe5, 0x28, 0xf3, 0xa1, 0x78, 0xac, 0xe1, 0x53, 0xb6, 0xd3, 0xae, 0x0a, 0xf0, 0xd5, 0x77, 0xcb, 0x3c, 0xb1, 0x54, 0x04, 0x89, 0xe8, 0x04, 0x27, 0xf7, 0x92, 0x21, 0x7a, 0xd8, 0xa0, 0x9b, 0x84, 0xf0, 0x27, 0xfc, 0xa7, 0xce, 0xb6, 0x51, 0xb4, 0x26, 0x4e, 0x98, 0xe9, 0x4b, 0x4c, 0xb8, 0xa3, 0x7b, 0x13, 0x33, 0x90, 0x89, 0x72, 0x33, 0xe8, 0xba, 0x91, 0x03, 0x62, 0x8d, 0x05, 0xb9, 0x60, 0x9e, 0x85, 0x52, 0xc4, 0xa4, 0xb1, 0x1e, 0x3f, 0x2f, 0xa8, 0xd5, 0x6a, 0xf3, 0x69, 0x57, 0x39, 0x0e, 0x88, 0xcb, 0xa4, 0x46, 0x56, 0xbe, 0x3e, 0xda, 0xce, 0x79, 0x8c, 0xf8, 0xcd, 0xf7, 0x77, 0x1b, 0xac, 0x33, 0x8a, 0x25, 0x6b, 0xc3, 0xcb, 0xa6, 0xdf, 0x97, 0x72, 0x8f, 0x22, 0x2f, 0x42, 0x3c, 0xa7, 0xc6, 0xd1, 0x49, 0xc9, 0x37, 0x2d, 0x66, 0x16, 0x3a, 0x98, 0xf7, 0x9a, 0x23, 0x4b, 0x00, 0xd4, 0xb7, 0x5f, 0xb2, 0xec, 0x86, 0x0d, 0xcc, 0x2d, 0x19, 0x98, 0x10, 0x5e, 0x4b, 0x9c, 0x01, 0xd6, 0x8f, 0x07, 0x9f, 0x3e, 0x0a, 0xa2, 0x1c, 0xc5, 0x34, 0x04, 0x7f, 0xc7, 0xb8, 0x58, 0xf8),
+      //   cipher_text: vec!(0xb8, 0x42, 0xea, 0xdf, 0xdf, 0x43, 0x1c, 0x13, 0x5b, 0xd6, 0x58, 0x1d, 0x3e, 0xcc, 0xae, 0x54, 0xe2, 0x26, 0x7d, 0x88, 0x90, 0x03, 0x6a, 0xa3, 0x3d, 0xfe, 0x2d, 0x2d, 0x97, 0x15, 0xc4, 0x46, 0x25, 0x44, 0x12, 0x10, 0xa3, 0xa0, 0xd6, 0x66, 0xd7, 0x08, 0xd3, 0x05, 0x88, 0xfe, 0x85, 0x1e, 0xc3, 0x6e, 0x10, 0xd8, 0xfa, 0x35, 0x84, 0xed, 0x77, 0xb0, 0x95, 0x14, 0x94, 0x94, 0xb7, 0xc5, 0x43, 0x79, 0xd6, 0x2c, 0x89, 0x35, 0xe1, 0xd2, 0xb9, 0xa8, 0xf4, 0x7e, 0x47, 0x59, 0xad, 0x0b, 0x34, 0x37, 0xfd, 0xf2, 0xcc, 0x2f, 0xb6, 0xc5, 0xea, 0x25, 0xad, 0x10, 0xe0, 0xbd, 0xc9, 0xdc, 0x5b, 0x05, 0x17, 0xfc, 0x23, 0x7e, 0xb7, 0x83, 0xcc, 0x46, 0x1c, 0x46, 0x66, 0x5e, 0x2b, 0x1d, 0x1a, 0x5b, 0x80, 0x08, 0xdb, 0xf4, 0x09, 0xea, 0x2a, 0x63, 0xfe, 0xa0, 0x27, 0x6d, 0xe2, 0x3a, 0x32, 0xc9, 0x9d, 0x92, 0xa4, 0x98, 0x80, 0x7a, 0x0f, 0x95, 0xe2, 0x08, 0xfc, 0x62, 0x62, 0x32, 0x1a, 0x78, 0xaa, 0xfa, 0xf0, 0xcc, 0x3f, 0x83, 0x3f, 0xff, 0x37, 0xbd, 0x4e, 0xfa, 0x66, 0xf6, 0x02, 0x3a, 0x25, 0xcd, 0xc6, 0x70, 0x2c, 0xee, 0x39, 0x12, 0x79, 0x95, 0x63, 0xd9, 0x08, 0xa5, 0x18, 0x3c, 0x99, 0x56, 0xa0, 0x6a, 0xa7, 0x10, 0x85, 0xd8, 0x55, 0xdc, 0x7c, 0x80, 0x9e, 0xd6, 0xe2, 0x88, 0x95, 0x92, 0xb3, 0x61, 0xab, 0x3a, 0xb3, 0x90, 0x60, 0xf8, 0xe4, 0x19, 0x15, 0x21, 0x87, 0xa7, 0x94, 0xa1, 0x9c, 0x2a, 0x11, 0x28, 0x88, 0x22, 0x01, 0x90, 0x0e, 0xa2, 0xcd, 0x59, 0x78, 0x60, 0x67, 0x4b, 0xf7, 0x8d, 0x97, 0x20, 0x64, 0x3d, 0xf8, 0x70, 0x16, 0x76, 0x71, 0x8f, 0xd2, 0x01, 0xba, 0xed, 0x49, 0x35, 0xa8, 0x8e, 0x50, 0x55, 0x8d, 0xaf, 0x86, 0xed, 0xd0, 0x8a, 0x9a, 0xb2, 0x27, 0xac, 0x7a, 0xfa, 0xe5, 0x5c, 0x97, 0x4b, 0x68, 0xde, 0x8d, 0xac, 0xad, 0x4a, 0x4d, 0x79, 0xb1, 0x3e, 0xd6, 0xdf, 0xe7, 0x40, 0x17, 0xa4, 0xcb, 0x91, 0x48, 0xe0, 0x33, 0x43, 0x6f, 0xb6),
+      //   tag: vec!(0x18, 0x40, 0x95, 0xb7, 0xa8, 0x19, 0x0a, 0xbe, 0xc0, 0x8b, 0xb7, 0x2d, 0x19, 0xee, 0xb1, 0x03)
+      // },
+      // TestVector{
+      //   key: [0x55, 0xa4, 0xbe, 0x24, 0x48, 0xb4, 0x64, 0xc2, 0xea, 0x52, 0xa2, 0xf2, 0x66, 0x4e, 0xd6, 0xab, 0xa8, 0x65, 0xc1, 0x4e, 0xa1, 0xfe, 0xa7, 0x7f, 0x46, 0x89, 0x33, 0x1f, 0xd1, 0x05, 0xc8, 0xd4],
+      //   nonce: [0xdb, 0x37, 0xc0, 0xa4, 0x05, 0xb4, 0x62, 0x6d],
+      //   plain_text: vec!(0xd2, 0x66, 0xe6, 0x62, 0x72, 0xe5, 0xd3, 0x46, 0x20, 0x81, 0xb0, 0x04, 0xcb, 0x42, 0x42, 0x9c, 0x8b, 0x97, 0x41, 0xe9, 0xf6, 0x78, 0x15, 0x37, 0x54, 0xd7, 0x26, 0xf6, 0xf9, 0xaa, 0x51, 0x34, 0x64, 0x76, 0x3c, 0x5e, 0x79, 0x3b, 0x48, 0x2f, 0xe5, 0x12, 0xfe, 0xce, 0x97, 0x58, 0x5f, 0x14, 0x26, 0x12, 0x0d, 0x4c, 0xef, 0xb3, 0xd0, 0xa8, 0xcc, 0x0a, 0x8d, 0xb4, 0xbd, 0xe9, 0x3f, 0xc7, 0x2c, 0x78, 0xf4, 0x4d, 0x4f, 0xec, 0xca, 0x14, 0x65, 0x0c, 0x66, 0x0d, 0x3e, 0x28, 0x5b, 0x32, 0x7e, 0x7c, 0xdd, 0x81, 0x30, 0x63, 0xe7, 0xe8, 0x67, 0xb8, 0xa2, 0xd0, 0x59, 0xa4, 0x1b, 0xab, 0x70, 0x43, 0x2b, 0x7f, 0x85, 0x71, 0x99, 0x89, 0x4d, 0xa9, 0x0d, 0xca, 0x3f, 0xe5, 0x27, 0x2b, 0xae, 0x1e, 0xc6, 0x94, 0xa1, 0xa0, 0x7b, 0x60, 0xb0, 0x5d, 0xf2, 0x75, 0x78, 0x4d, 0x49, 0x75, 0x63, 0x7e, 0x46, 0x73, 0x10, 0x9f, 0x3b, 0xa8, 0x46, 0xdf, 0xd1, 0xa0, 0x48, 0xb2, 0x02, 0xed, 0x8e, 0x89, 0x97, 0x3b, 0xe6, 0x08, 0xb9, 0x1e, 0xe4, 0x74, 0x3b, 0x1e, 0x75, 0x99, 0x00, 0xf1, 0x44, 0x30, 0x38, 0x95, 0x1f, 0xe6, 0x18, 0x9e, 0x80, 0x66, 0x38, 0x98, 0x5f, 0x3c, 0x16, 0x33, 0x8c, 0x3c, 0x60, 0x69, 0x5d, 0xf5, 0x8e, 0x62, 0x11, 0x54, 0xd7, 0x9b, 0xb9, 0x73, 0x85, 0x9c, 0x45, 0x58, 0xe9, 0xdc, 0xa9, 0x04, 0x70, 0xf7, 0x7c, 0x73, 0xf0, 0x04, 0x44, 0x3a, 0xd5, 0xdb, 0x07, 0x17, 0xab, 0xbe, 0x43, 0x26, 0x6f, 0x90, 0xe5, 0x73, 0x97, 0xb8, 0x3a, 0xc3, 0x4d, 0x1f, 0xef, 0x2e, 0x89, 0x7e, 0x24, 0x83, 0xd5, 0xbc, 0xdc, 0xb6, 0x27, 0xab, 0xd6, 0x4b, 0x0d, 0x1a, 0xef, 0x52, 0x58, 0x35, 0xf2, 0x5e, 0x76, 0xd6, 0xe9, 0x15, 0x82, 0x32, 0xcd, 0xde, 0x6d, 0xce, 0x97, 0x0b, 0x59, 0xf5, 0x8d, 0xe8, 0xa9, 0x8e, 0x65, 0x3b, 0xe3, 0x2f, 0xb5, 0x8e, 0xda, 0xbb, 0xce, 0xfa, 0x50, 0x65, 0xd7, 0x3a, 0xfd, 0xf1, 0xc9, 0xc4, 0xfb, 0xf5, 0x0c, 0x10, 0x22, 0xbd, 0x22, 0xbf, 0xcb, 0x98, 0xe4, 0xb4, 0x22),
+      //   aad: vec!(0xfd, 0x6a, 0x3f, 0xdd, 0x87, 0x9f, 0x88, 0x80, 0x84, 0x3e, 0xac, 0x20, 0xae, 0x01, 0xc1, 0xb9, 0xdc, 0x34, 0x87, 0xd2, 0x70, 0xa8, 0x06, 0x57, 0x20, 0x88, 0xef, 0x2d, 0xdc, 0x1f, 0x1e, 0x0d, 0xe4, 0x95, 0xe7, 0x1d, 0x48, 0x13, 0xbf, 0x5c, 0x50, 0x1a, 0xd3, 0x1e, 0x5d, 0x79, 0x1c, 0x4b, 0x5b, 0x3a, 0x0a, 0x71, 0xb6, 0x3f, 0xdd, 0xdc, 0xc8, 0xde, 0x4b, 0x05, 0x60, 0x64, 0xef, 0x46, 0x79, 0x89, 0xec, 0xcc, 0xc5, 0xd0, 0x16, 0x0d, 0x40, 0x3b, 0xf3, 0xa0, 0x25, 0xd4, 0x89, 0x2b, 0x3b, 0x1d, 0xe3, 0xe0, 0x62, 0xbc, 0x35, 0x81, 0xd4, 0x41, 0x0f, 0x27, 0x33, 0x38, 0x31, 0x1e, 0xb4, 0x63, 0x75, 0x29, 0xe4, 0xa6, 0x80, 0xa6, 0xe4, 0xa5, 0xe2, 0x6e, 0x30, 0x86, 0x30, 0xa5, 0xb6, 0xd4, 0x9e, 0xad, 0x6d, 0x54, 0x3f, 0x8f, 0x2b, 0xf9, 0x05, 0x0a, 0xa9, 0x4c, 0xe0, 0x91, 0x31, 0x87, 0x21, 0xe1, 0xd8, 0xb9, 0x6e, 0x27, 0x9f, 0x34, 0xb9, 0x75, 0x9b, 0x65, 0x03, 0x7b, 0xec, 0x4b, 0xf6, 0xcc, 0xda, 0x69, 0x29, 0x70, 0x5a, 0xee, 0xee, 0xbe, 0x49, 0xe3, 0x27, 0xe4, 0xd7, 0xa9, 0x16, 0x62, 0x0c, 0x9f, 0xaf, 0x37, 0x65, 0x12, 0x06, 0x58, 0xaf, 0x34, 0xc5, 0x3f, 0xbb, 0x97, 0xec, 0x07, 0x65, 0x7b, 0x3f, 0x08, 0x8f, 0xcb, 0xdc, 0x40, 0x1a, 0xa7, 0x94, 0x9d, 0xde, 0xda, 0x34, 0xd8, 0x85, 0x01, 0x8c, 0x2c, 0x23, 0xf4, 0xf0, 0xbb, 0x82, 0x18, 0xbf, 0x0d, 0x4f, 0xc9, 0x06, 0x43, 0x65, 0x8b, 0x4d, 0x88, 0x34, 0xf4, 0xa8, 0xc0, 0x8e, 0x59, 0x0c, 0x2a, 0x79, 0x09, 0x95, 0xba, 0xa9, 0xe7, 0x76, 0x27, 0xc3, 0x42, 0xd2, 0x83, 0xe4, 0x54, 0xf8, 0x4f, 0xcc, 0x05, 0xbe, 0x15, 0xe9, 0x62, 0x7a, 0x2d, 0x9b, 0xe3, 0x40, 0xc9, 0xd7, 0x2f, 0x22, 0x2b, 0xbd, 0xfc, 0x47, 0x90, 0x5f, 0x56, 0x61, 0x6c, 0xd9, 0xf9, 0x36, 0xd4, 0x9e, 0x47, 0x32, 0xf3, 0x19, 0xf0, 0x20, 0x51, 0x33, 0x40, 0xfb, 0x8b, 0x22, 0x82, 0x8d, 0xb2, 0x51, 0xb1, 0x02, 0xb6, 0xb1, 0x37, 0xc9, 0x53, 0x39, 0x36, 0xd6),
+      //   cipher_text: vec!(0xbd, 0x11, 0xed, 0x07, 0xb7, 0xb4, 0xb3, 0x0e, 0xea, 0xf2, 0x5d, 0x6a, 0x41, 0xa5, 0x49, 0xcc, 0xa0, 0xa5, 0xae, 0xe7, 0x1f, 0x99, 0x0a, 0xc5, 0x66, 0xa3, 0x72, 0x65, 0xd7, 0xaf, 0x2c, 0xe3, 0xc0, 0x37, 0x03, 0x42, 0x7e, 0xe0, 0xb2, 0x75, 0x5c, 0x2b, 0xdf, 0xc2, 0x9f, 0x9d, 0x82, 0x6a, 0xec, 0x6e, 0xe4, 0xad, 0x28, 0xaf, 0x48, 0x07, 0x9a, 0xc2, 0x3d, 0xb1, 0x65, 0x80, 0xb9, 0x74, 0x24, 0xf3, 0xa4, 0xe3, 0x5c, 0xc2, 0x36, 0x25, 0xd3, 0x9f, 0x95, 0x69, 0x9d, 0x9f, 0xf5, 0x14, 0x3e, 0x9a, 0x2b, 0xc2, 0x6f, 0xcf, 0xee, 0x4f, 0x12, 0x5f, 0x5a, 0xa2, 0xd9, 0x68, 0xcc, 0xfc, 0x2f, 0xaa, 0xf9, 0xdb, 0x3c, 0x28, 0x85, 0x0f, 0x67, 0x57, 0xf7, 0x35, 0xcb, 0xc5, 0x0c, 0x94, 0xc4, 0x98, 0xbc, 0xde, 0x4f, 0x23, 0xbf, 0xfa, 0xfa, 0x8d, 0xd5, 0xf7, 0x0d, 0x1a, 0x01, 0x1e, 0x35, 0xeb, 0x26, 0xe9, 0x05, 0xd4, 0xe6, 0x88, 0x48, 0xfe, 0xde, 0xbe, 0xb1, 0x97, 0xbe, 0x59, 0x5c, 0x08, 0x5b, 0xa3, 0x3f, 0x11, 0xba, 0x83, 0x98, 0x25, 0x84, 0x45, 0x05, 0x17, 0x51, 0x88, 0x8e, 0x9b, 0xba, 0x11, 0x1f, 0x80, 0x0f, 0x31, 0xb3, 0x7c, 0x44, 0x70, 0x74, 0xca, 0x6d, 0xce, 0x6d, 0x54, 0xb4, 0xdf, 0xad, 0x6c, 0xee, 0x51, 0x38, 0x64, 0x3d, 0x4f, 0x6a, 0xc0, 0x45, 0xe8, 0x04, 0x72, 0x48, 0x92, 0x4e, 0x88, 0xea, 0x42, 0x94, 0xc7, 0x87, 0x8b, 0xc2, 0x2c, 0x9b, 0x41, 0x92, 0x4c, 0xe3, 0x01, 0xf2, 0x26, 0x93, 0xc3, 0x37, 0x33, 0x10, 0x7b, 0xf1, 0xba, 0x85, 0xe3, 0x48, 0x06, 0xc5, 0xe4, 0x36, 0x6e, 0xa6, 0x6f, 0xc5, 0x2a, 0x5f, 0x89, 0xdd, 0x9b, 0xf2, 0x13, 0x23, 0x91, 0x58, 0xb3, 0xd4, 0xd2, 0x60, 0x0d, 0xde, 0x69, 0x6c, 0x61, 0xd7, 0x6c, 0x39, 0x8b, 0x9b, 0xf1, 0x0d, 0xe9, 0x11, 0x8e, 0x81, 0x2e, 0x89, 0x1c, 0x8f, 0x33, 0x55, 0xc0, 0xec, 0xc6, 0x40, 0x5f, 0x79, 0xbc, 0x32, 0xa5, 0x89, 0x05, 0xe3, 0x78, 0x88, 0xa1, 0xd8, 0x39, 0x5f, 0xbe, 0xdc, 0x3a, 0xc5, 0x4e, 0xca, 0x56, 0x9f),
+      //   tag: vec!(0xf7, 0xd3, 0xb5, 0x8a, 0x34, 0xa8, 0x6e, 0x99, 0x26, 0x7e, 0x5d, 0xb2, 0x06, 0xf1, 0x7b, 0xbe)
+      // },
+      // TestVector{
+      //   key: [0x33, 0x04, 0xe4, 0x91, 0x7a, 0xd7, 0x77, 0x7b, 0x86, 0xc2, 0x6a, 0x63, 0x62, 0x92, 0xc9, 0xcc, 0x4c, 0x10, 0xd3, 0x20, 0x03, 0xc4, 0x9e, 0x07, 0x20, 0x9e, 0xb0, 0xef, 0x85, 0x05, 0x03, 0x1a],
+      //   nonce: [0x4d, 0x57, 0x2d, 0x11, 0x6f, 0xbd, 0x8c, 0x4d],
+      //   plain_text: vec!(0x2f, 0x24, 0x2c, 0x2b, 0xa3, 0x37, 0x90, 0xec, 0xef, 0x86, 0x2b, 0x0e, 0x07, 0x7f, 0xf8, 0xb1, 0x5e, 0xb9, 0xd1, 0x0c, 0xf2, 0xff, 0x62, 0x1e, 0xd6, 0x59, 0x02, 0x49, 0x44, 0x31, 0xdc, 0xbd),
+      //   aad: vec!(0xe6, 0x99, 0xbb, 0xf2, 0x50, 0xcd, 0xd9, 0x3d, 0x22, 0x9d, 0x07, 0x40, 0xe4, 0x33, 0x89, 0x7e, 0x2d, 0x19, 0x13, 0x2e, 0x2b, 0x72, 0x2d, 0xf8, 0xb6, 0x9b, 0xb6, 0xa7, 0xc2, 0xcf, 0x3b, 0x93),
+      //   cipher_text: vec!(0xfb, 0x81, 0xe3, 0x04, 0x36, 0xe4, 0x37, 0xc7, 0xf6, 0x86, 0xf8, 0x6b, 0x1b, 0x65, 0xc7, 0x35, 0x49, 0xa9, 0xd0, 0x9d, 0xb8, 0x10, 0xd3, 0x20, 0x78, 0x5c, 0x36, 0x34, 0x93, 0x41, 0x50, 0xb3),
+      //   tag: vec!(0x8b)
+      // },
+      // TestVector{
+      //   key: [0xed, 0x60, 0x57, 0xbb, 0x16, 0x3f, 0x16, 0x09, 0xff, 0x28, 0xb9, 0x38, 0x12, 0x2f, 0x49, 0x5e, 0x3d, 0x5a, 0xe4, 0xec, 0x3d, 0xbd, 0x74, 0x56, 0xc9, 0xb5, 0xc8, 0x2e, 0x28, 0xe9, 0x52, 0xdc],
+      //   nonce: [0xe6, 0xff, 0x68, 0x52, 0xf3, 0xa3, 0xaf, 0xde],
+      //   plain_text: vec!(0x3c, 0x50, 0xed, 0xc9, 0x67, 0xeb, 0x0b, 0x3b, 0x23, 0x55, 0xf6, 0x40, 0x0e, 0x0a, 0x03, 0x6e, 0x79, 0x6c, 0x8b, 0x7d, 0x72, 0xc5, 0xe5, 0x83, 0xa8, 0x6e, 0x82, 0x0d, 0x53, 0xe7, 0x6c, 0x43),
+      //   aad: vec!(0x24, 0x41, 0xdb, 0x55, 0x14, 0x8e, 0x14, 0xe9, 0xe2, 0x41, 0xd6, 0x82, 0x96, 0xeb, 0x60, 0xd5, 0x29, 0x40, 0x8f, 0x05, 0x34, 0x14, 0x30, 0x89, 0x67, 0x1b, 0xce, 0x54, 0x6d, 0xb9, 0x6d, 0x88),
+      //   cipher_text: vec!(0x6e, 0xca, 0xbc, 0xce, 0xe3, 0x15, 0x19, 0x37, 0x4d, 0x4b, 0xed, 0x11, 0x29, 0x6e, 0x74, 0x83, 0xd1, 0xcb, 0x75, 0x9b, 0xea, 0x3f, 0x44, 0x46, 0xa9, 0x6b, 0xda, 0x8b, 0x4c, 0xa6, 0xd7, 0xac),
+      //   tag: vec!(0x35, 0x5f)
+      // },
+      // TestVector{
+      //   key: [0x73, 0x56, 0x81, 0x83, 0xc1, 0xf9, 0x72, 0x5a, 0xf3, 0x0e, 0x0f, 0x20, 0x67, 0x60, 0x6c, 0xe8, 0x02, 0xc3, 0xfe, 0x3a, 0xb5, 0xcf, 0xf8, 0xd0, 0x2b, 0x3d, 0xb8, 0xc3, 0x51, 0x76, 0xee, 0x0d],
+      //   nonce: [0x0b, 0xc9, 0xe1, 0x93, 0x21, 0xb3, 0xd0, 0x0a],
+      //   plain_text: vec!(0xec, 0x25, 0x90, 0xaf, 0x5c, 0xcd, 0x22, 0x6a, 0x32, 0xff, 0x75, 0x0c, 0x1b, 0x02, 0x9c, 0x11, 0xe3, 0xdd, 0x76, 0xc4, 0x69, 0xa5, 0x57, 0x9d, 0xa9, 0x41, 0x8e, 0x4c, 0x3f, 0xdc, 0x0d, 0x41),
+      //   aad: vec!(0xdf, 0x30, 0x16, 0x0a, 0xe0, 0xcb, 0xf2, 0xcf, 0x89, 0x92, 0x22, 0x1b, 0xd6, 0x2d, 0xff, 0xe6, 0x91, 0xdd, 0x60, 0x2a, 0xfa, 0x78, 0x4c, 0xa6, 0x91, 0x47, 0x9e, 0x95, 0x7a, 0xf3, 0xac, 0xf1),
+      //   cipher_text: vec!(0x9e, 0x8d, 0x8a, 0xc3, 0x06, 0x26, 0xf8, 0xb8, 0x31, 0x44, 0x8d, 0x69, 0x76, 0x93, 0x3a, 0xa5, 0xbb, 0x8c, 0x6d, 0xbc, 0x79, 0x4e, 0x1f, 0x4b, 0x7e, 0xeb, 0x0e, 0x4a, 0x59, 0x34, 0x2c, 0x07),
+      //   tag: vec!(0x9f, 0xd3, 0x6a)
+      // },
+      // TestVector{
+      //   key: [0x27, 0x3b, 0xcb, 0x3f, 0x8c, 0x06, 0x7d, 0xa4, 0xec, 0x34, 0x18, 0x79, 0x9a, 0xd4, 0x0e, 0x7e, 0x4a, 0xee, 0x74, 0xad, 0x7e, 0x62, 0x94, 0x99, 0xd6, 0x46, 0xdf, 0x4a, 0x7e, 0x58, 0x50, 0x25],
+      //   nonce: [0xf6, 0x0b, 0xe3, 0xeb, 0x89, 0x4b, 0x40, 0x30],
+      //   plain_text: vec!(0x69, 0x74, 0x98, 0xba, 0x96, 0x4d, 0x5e, 0xf4, 0x01, 0xda, 0x4d, 0x94, 0x84, 0x4f, 0xab, 0x1e, 0xfc, 0x63, 0x5e, 0x71, 0x57, 0xd0, 0x83, 0x1a, 0x32, 0x5b, 0xb5, 0xa4, 0xcf, 0x1f, 0xbd, 0x34),
+      //   aad: vec!(0x91, 0x29, 0x71, 0x5d, 0xea, 0xb1, 0x4f, 0x02, 0xc7, 0x6b, 0xa8, 0x17, 0x25, 0x71, 0xb1, 0xfa, 0x9d, 0x50, 0x36, 0x5c, 0xd7, 0x95, 0xbf, 0xcc, 0xdf, 0xc2, 0x8e, 0x7e, 0x7b, 0x4f, 0x66, 0xfc),
+      //   cipher_text: vec!(0xbd, 0x4c, 0xd5, 0xaf, 0x83, 0xbe, 0x1c, 0x13, 0x93, 0x33, 0x02, 0x67, 0x5d, 0x9f, 0xca, 0xf1, 0xc4, 0xca, 0xcd, 0xf2, 0x69, 0xf6, 0xff, 0x44, 0x1d, 0x1e, 0xa2, 0x21, 0x1c, 0x54, 0xe7, 0xed),
+      //   tag: vec!(0x7a, 0xb1, 0x2a, 0x37)
+      // },
+      // TestVector{
+      //   key: [0xad, 0x39, 0x61, 0x0c, 0x2e, 0x6a, 0x6d, 0x09, 0x61, 0x20, 0x73, 0x90, 0xe0, 0x76, 0xe9, 0x72, 0xc2, 0xed, 0xad, 0xca, 0x88, 0x5c, 0x92, 0x96, 0x5f, 0xa6, 0x48, 0xb2, 0xce, 0x34, 0xfd, 0xbf],
+      //   nonce: [0xa9, 0x0d, 0xb6, 0x90, 0xbb, 0xa8, 0x3b, 0x78],
+      //   plain_text: vec!(0x31, 0xc4, 0x9e, 0x3c, 0xd3, 0xd8, 0x0a, 0x82, 0xe6, 0xb9, 0x03, 0x16, 0xdf, 0xb9, 0x4b, 0x38, 0xb8, 0xa2, 0x30, 0x42, 0x51, 0x9b, 0xf4, 0x0c, 0x81, 0x81, 0xfe, 0xc8, 0x73, 0xc9, 0x90, 0x02),
+      //   aad: vec!(0xdd, 0xbd, 0x7d, 0x82, 0x1d, 0x18, 0xd4, 0x4c, 0x66, 0x29, 0x5a, 0xbf, 0x24, 0x5b, 0x22, 0x7b, 0x5c, 0xf4, 0x36, 0x68, 0x11, 0xb7, 0xb3, 0x4c, 0x07, 0x67, 0x96, 0x00, 0xab, 0xdb, 0xfc, 0x29),
+      //   cipher_text: vec!(0x94, 0x62, 0x8f, 0xc3, 0x03, 0xa0, 0x54, 0x6e, 0xdd, 0x51, 0xe9, 0x66, 0xf2, 0xbd, 0x87, 0x96, 0x8f, 0x37, 0x80, 0x0c, 0x60, 0x7d, 0x5e, 0x5a, 0x91, 0xf7, 0x27, 0xfc, 0x1f, 0xec, 0x40, 0x6f),
+      //   tag: vec!(0xc2, 0x2e, 0xc4, 0xe4, 0xc8)
+      // },
+      // TestVector{
+      //   key: [0x29, 0x98, 0x49, 0x54, 0x06, 0x0b, 0xa0, 0x6e, 0xce, 0x1b, 0xcf, 0xc0, 0xe5, 0x01, 0x95, 0xf4, 0x63, 0x2c, 0x6d, 0xf4, 0x8d, 0xa1, 0xe0, 0x2a, 0xe6, 0xc1, 0x4f, 0x70, 0x65, 0x66, 0x89, 0x71],
+      //   nonce: [0xcc, 0xe5, 0x3a, 0x25, 0xae, 0xea, 0xf7, 0x47],
+      //   plain_text: vec!(0xb9, 0xb8, 0x74, 0x33, 0xa9, 0x89, 0x4f, 0x3c, 0x9c, 0xa8, 0x21, 0x26, 0x23, 0xd6, 0x23, 0x69, 0xa5, 0x65, 0xa2, 0xed, 0xcd, 0xdd, 0x27, 0x6e, 0x07, 0xd6, 0x11, 0xed, 0xa3, 0x59, 0x74, 0x26),
+      //   aad: vec!(0x19, 0xfa, 0x9a, 0xa5, 0x96, 0x97, 0x55, 0x9d, 0x8b, 0x46, 0xd9, 0xcd, 0x49, 0xc3, 0xb7, 0x63, 0xc0, 0xb7, 0x3b, 0x26, 0xb9, 0xe3, 0x34, 0xa3, 0xee, 0xac, 0x2c, 0x86, 0xfd, 0xba, 0xca, 0x8d),
+      //   cipher_text: vec!(0xb6, 0x8c, 0x83, 0x39, 0x77, 0x70, 0xc3, 0x6f, 0x07, 0x37, 0x10, 0x88, 0x2f, 0xa8, 0x6d, 0x43, 0xb0, 0xe5, 0x4e, 0x8e, 0xfe, 0xf0, 0xff, 0x75, 0x07, 0x56, 0x04, 0xd0, 0xd7, 0xec, 0x4e, 0x1b),
+      //   tag: vec!(0x40, 0xd4, 0xab, 0x75, 0x2f, 0x3d)
+      // },
+      // TestVector{
+      //   key: [0x5c, 0x3b, 0x83, 0x8b, 0x84, 0x10, 0x0b, 0x2a, 0x81, 0x8c, 0x08, 0x42, 0xe9, 0xfe, 0x19, 0xa7, 0xc5, 0x0c, 0xf5, 0xf3, 0xea, 0x73, 0x36, 0x4c, 0x81, 0x6e, 0xf5, 0x88, 0xe5, 0x00, 0xff, 0x3f],
+      //   nonce: [0xfd, 0xf6, 0xb0, 0x22, 0x9e, 0x4b, 0xcc, 0x2a],
+      //   plain_text: vec!(0x2b, 0xa9, 0x19, 0x04, 0xc1, 0x43, 0xbe, 0x99, 0x29, 0x7b, 0x39, 0xf5, 0x28, 0x56, 0x90, 0x4a, 0xf4, 0x17, 0x05, 0xc1, 0x76, 0xc8, 0xc6, 0x55, 0x4b, 0x6b, 0xc8, 0x9b, 0xdd, 0xff, 0xbc, 0xc1),
+      //   aad: vec!(0x35, 0x39, 0xd9, 0xdd, 0x82, 0x1f, 0x00, 0x4f, 0x4c, 0xed, 0x16, 0x37, 0x07, 0x1f, 0x4b, 0xe6, 0xab, 0xd7, 0xfe, 0x98, 0xf0, 0x17, 0xf0, 0xa8, 0xce, 0x3f, 0x49, 0xdc, 0x8d, 0x49, 0x6f, 0x46),
+      //   cipher_text: vec!(0xff, 0x9d, 0x6d, 0x92, 0x4e, 0x73, 0x7a, 0x1d, 0xf8, 0xc2, 0xbd, 0x30, 0x47, 0xe4, 0x0a, 0xb4, 0x01, 0xf9, 0x03, 0xaa, 0x0e, 0x5b, 0x51, 0xac, 0xb9, 0x91, 0xba, 0xc3, 0x8a, 0xc2, 0xcc, 0x4d),
+      //   tag: vec!(0x1b, 0xca, 0xa4, 0x15, 0xa6, 0xa3, 0xc7)
+      // },
+      TestVector{
+        key: [0x6d, 0x65, 0xe6, 0x27, 0xca, 0xb6, 0xd5, 0xeb, 0x1a, 0x08, 0x8b, 0x25, 0xbd, 0x6c, 0x3a, 0x8a, 0x00, 0x4a, 0x7a, 0x19, 0xcc, 0xca, 0xe9, 0x09, 0xd6, 0x2f, 0xed, 0x35, 0x59, 0xc8, 0x12, 0xf7],
+        nonce: [0x7f, 0xf0, 0x0a, 0x87, 0x98, 0xb7, 0x92, 0xde],
+        plain_text: vec!(0x68, 0x48, 0xee, 0x4a, 0xc8, 0x20, 0x29, 0x1a, 0x2e, 0x1d, 0xc3, 0xba, 0xad, 0x97, 0xf1, 0xad, 0x8b, 0x71, 0x60, 0xdf, 0xea, 0xa1, 0xbc, 0x83, 0xb2, 0x70, 0x0a, 0xe4, 0x2b, 0x5a, 0x36, 0x6b),
+        aad: vec!(0xd2, 0x43, 0x7b, 0x13, 0x06, 0xbf, 0x0e, 0xa2, 0x11, 0x44, 0x9f, 0xac, 0x86, 0x3c, 0xa0, 0xd1, 0x07, 0x4d, 0x84, 0xca, 0xee, 0x90, 0x09, 0xc5, 0xd5, 0x4b, 0x9e, 0x9b, 0xdc, 0x8d, 0xe6, 0xb1),
+        cipher_text: vec!(0x2d, 0xa0, 0xab, 0xe2, 0xa7, 0x1e, 0x1c, 0x0b, 0x1a, 0xb3, 0x09, 0xc1, 0x60, 0xa8, 0xce, 0xbe, 0x45, 0xc6, 0xe1, 0x61, 0x70, 0xaa, 0x55, 0x61, 0x80, 0x64, 0x84, 0xba, 0x2b, 0x5b, 0x9a, 0x9a),
+        tag: vec!(0x56, 0x60, 0x03, 0xe1, 0xf7, 0x8d, 0x2a, 0x90)
+      },
+      TestVector{
+        key: [0x63, 0x40, 0x10, 0x46, 0xa9, 0x6e, 0xfb, 0xc8, 0xc6, 0x48, 0x3a, 0x2c, 0x39, 0x6b, 0x2a, 0x59, 0x3d, 0x3f, 0xae, 0x0d, 0xb5, 0x65, 0x52, 0x5b, 0x85, 0x99, 0x9f, 0xae, 0x13, 0xa4, 0x6b, 0x6a],
+        nonce: [0x05, 0x13, 0x93, 0xd7, 0x75, 0xe6, 0x35, 0xee],
+        plain_text: vec!(0x2b, 0x4b, 0x64, 0x77, 0x58, 0x03, 0x82, 0xaa, 0xe7, 0x82, 0xf8, 0xb5, 0x77, 0x2c, 0x09, 0x48, 0xa4, 0x44, 0xd8, 0xd9, 0x5c, 0xaa, 0xcd, 0x85, 0xc0, 0x85, 0x6c, 0x7e, 0x43, 0x93, 0xfe, 0x09),
+        aad: vec!(0x3d, 0x84, 0xd2, 0xe7, 0x0e, 0x9c, 0x06, 0x2d, 0x1f, 0x51, 0x1e, 0xb6, 0x85, 0xa9, 0xa9, 0x0c, 0x8d, 0x5f, 0xa5, 0x0e, 0xad, 0xf8, 0x45, 0x5c, 0x71, 0x48, 0x66, 0x6b, 0x3e, 0x71, 0x55, 0xe0),
+        cipher_text: vec!(0x88, 0x0c, 0x11, 0x23, 0xe5, 0x4f, 0xd8, 0xff, 0xb3, 0xc2, 0x93, 0x72, 0x0d, 0xd1, 0x74, 0x91, 0x35, 0x72, 0xe6, 0x19, 0xef, 0x46, 0x50, 0x4c, 0xda, 0xa6, 0x4f, 0xc4, 0x51, 0xb0, 0xec, 0x1c),
+        tag: vec!(0x33, 0x92, 0x74, 0x33, 0x9c, 0x88, 0xd5, 0x0a, 0xc0)
+      },
+      TestVector{
+        key: [0x29, 0x1f, 0xcc, 0xfc, 0xe0, 0x78, 0x2f, 0x17, 0x87, 0xd6, 0x2d, 0x4b, 0x92, 0x93, 0xd2, 0xad, 0xa4, 0xc0, 0x4d, 0x37, 0xa8, 0x28, 0x8b, 0xa9, 0xba, 0x9a, 0xae, 0x0d, 0x31, 0xaa, 0xd2, 0x04],
+        nonce: [0x74, 0x50, 0xbb, 0xd6, 0x2e, 0x4a, 0xba, 0x7b],
+        plain_text: vec!(0xad, 0xc2, 0x51, 0xe7, 0x93, 0x18, 0x1e, 0x5d, 0x4c, 0x4b, 0xd9, 0x83, 0xb8, 0x53, 0xeb, 0x13, 0xf2, 0x09, 0x6c, 0xcb, 0x34, 0x09, 0x96, 0xb6, 0xec, 0xa4, 0xcd, 0x21, 0x57, 0xef, 0xce, 0xc7),
+        aad: vec!(0x4c, 0x59, 0x8f, 0x6d, 0xee, 0xdc, 0x8c, 0x1d, 0x97, 0xda, 0x33, 0x65, 0x47, 0x63, 0x49, 0x5c, 0xca, 0x35, 0x17, 0x43, 0x0e, 0xec, 0x4e, 0xdb, 0x00, 0x6b, 0x10, 0xc9, 0x5e, 0x03, 0x1a, 0xe6),
+        cipher_text: vec!(0x28, 0xbd, 0xa2, 0x2e, 0x49, 0x22, 0xcd, 0x8f, 0xf6, 0x73, 0x9c, 0xd8, 0xa6, 0xbd, 0xaf, 0xce, 0x03, 0x6d, 0x9c, 0x61, 0xa1, 0x45, 0xa6, 0x5c, 0xa1, 0xb8, 0x6f, 0x6d, 0x4d, 0x32, 0x06, 0xa1),
+        tag: vec!(0xd9, 0x8f, 0xd4, 0x3f, 0xe7, 0xac, 0x74, 0xd4, 0xb0, 0x16)
+      },
+      TestVector{
+        key: [0xfa, 0x3a, 0x96, 0x74, 0xd4, 0xa0, 0xeb, 0x36, 0xb2, 0xf7, 0x54, 0x7c, 0x95, 0x64, 0x43, 0xd0, 0x9e, 0x6b, 0x4e, 0x4a, 0xcf, 0xc9, 0xde, 0xda, 0x83, 0x8e, 0xb7, 0xeb, 0xdb, 0x99, 0x9a, 0x8d],
+        nonce: [0x0a, 0x25, 0x72, 0x59, 0x2c, 0x3b, 0xbb, 0xf6],
+        plain_text: vec!(0xae, 0x27, 0xf7, 0x0f, 0xda, 0x9f, 0x5a, 0x5b, 0xe0, 0xf7, 0x04, 0xa2, 0x7f, 0x0b, 0x8a, 0x9c, 0x04, 0xce, 0x83, 0xd3, 0xc2, 0xe0, 0xd7, 0xec, 0x15, 0x2d, 0xa2, 0x5f, 0x47, 0x3b, 0x0c, 0x8a),
+        aad: vec!(0x6e, 0xe8, 0x70, 0x5a, 0x9a, 0x36, 0x55, 0xd1, 0x98, 0x49, 0x7a, 0xd4, 0x10, 0xda, 0x02, 0x00, 0x58, 0x72, 0xec, 0xbe, 0x39, 0x78, 0x24, 0x85, 0x1b, 0x80, 0xf4, 0x05, 0x0b, 0xfd, 0xd3, 0x11),
+        cipher_text: vec!(0xf3, 0x56, 0xcb, 0xd8, 0x8e, 0x4e, 0x2a, 0xff, 0x62, 0xd9, 0x1e, 0x3f, 0x91, 0x40, 0x32, 0x08, 0x53, 0x88, 0x95, 0x5b, 0xbb, 0xa9, 0x95, 0xfd, 0xe0, 0x13, 0x75, 0x8b, 0x87, 0x02, 0xe3, 0x8f),
+        tag: vec!(0x00, 0x32, 0x4c, 0x76, 0xfe, 0xcd, 0x3f, 0x50, 0xe1, 0xe3, 0xb8)
+      },
+      TestVector{
+        key: [0x47, 0x1e, 0xc8, 0x7b, 0x99, 0x2b, 0x10, 0x4d, 0x36, 0x97, 0x48, 0xd9, 0x68, 0x56, 0xb5, 0xf6, 0x61, 0x49, 0xcb, 0x45, 0xca, 0x05, 0xc1, 0x7f, 0x29, 0xd2, 0x4e, 0xb9, 0x52, 0x6f, 0xe6, 0xdb],
+        nonce: [0x23, 0xa2, 0xdf, 0x9e, 0xd0, 0xb4, 0x74, 0x39],
+        plain_text: vec!(0x2b, 0x94, 0x52, 0xbc, 0xa0, 0xf4, 0x8e, 0x55, 0x19, 0xec, 0x3d, 0x07, 0x36, 0x59, 0x76, 0x08, 0xdf, 0x6a, 0xd9, 0xce, 0x79, 0x9e, 0xba, 0x91, 0x3c, 0xff, 0x71, 0x57, 0x3d, 0x79, 0xc0, 0x92),
+        aad: vec!(0xa5, 0x67, 0x22, 0xdd, 0xfa, 0xee, 0x5f, 0x1b, 0x64, 0x39, 0x8c, 0x22, 0x5e, 0xe8, 0xbc, 0xdc, 0xfd, 0xe5, 0xc2, 0x12, 0x71, 0x01, 0xc3, 0x63, 0xbf, 0xac, 0x52, 0xbc, 0x40, 0x9c, 0x10, 0x82),
+        cipher_text: vec!(0x7b, 0xbc, 0x46, 0x4a, 0xac, 0x5d, 0xd2, 0x9c, 0x25, 0x26, 0x2f, 0xe0, 0xb1, 0x16, 0xc1, 0x76, 0xd8, 0x27, 0xc2, 0xcc, 0x8d, 0xd6, 0x34, 0x28, 0x39, 0x3b, 0x0a, 0x91, 0x10, 0xf3, 0xc1, 0x94),
+        tag: vec!(0x2e, 0x87, 0xf4, 0xa6, 0x66, 0x3a, 0x62, 0xe4, 0x7c, 0x7e, 0x19, 0x7f)
+      },
+      TestVector{
+        key: [0xa2, 0x9d, 0x1c, 0xfd, 0x4c, 0xcd, 0xc1, 0x88, 0x03, 0xfb, 0xca, 0x95, 0x00, 0xf4, 0xbb, 0x29, 0xce, 0x99, 0xcf, 0xcb, 0xf8, 0xac, 0xc4, 0x1b, 0x82, 0x08, 0xda, 0xe4, 0xb7, 0xee, 0x5d, 0x64],
+        nonce: [0x63, 0x4f, 0x99, 0xe8, 0x8e, 0x23, 0x7e, 0xf0],
+        plain_text: vec!(0x09, 0xee, 0x59, 0x82, 0xc5, 0x74, 0x3f, 0x39, 0x6d, 0x0c, 0x29, 0xc1, 0x3e, 0x3f, 0xbb, 0x8f, 0xb8, 0x9f, 0x61, 0x70, 0x5d, 0xa0, 0x54, 0x66, 0x29, 0x1e, 0x01, 0x0e, 0xff, 0xd5, 0x1a, 0x5c),
+        aad: vec!(0x56, 0x4d, 0xdd, 0xfc, 0xc3, 0x22, 0x7b, 0x41, 0x32, 0x44, 0xf1, 0x10, 0x5b, 0x61, 0x0f, 0x19, 0x2d, 0xec, 0xf1, 0x5c, 0x4c, 0xfa, 0x06, 0x7f, 0x4d, 0x7f, 0xcd, 0x6b, 0xd7, 0xaf, 0x11, 0xb8),
+        cipher_text: vec!(0x32, 0x91, 0x6b, 0x67, 0xa6, 0xf3, 0x27, 0x33, 0x62, 0x33, 0x44, 0xc9, 0x8c, 0x49, 0x77, 0x3f, 0x3e, 0x72, 0x1d, 0xc2, 0xde, 0xd1, 0x05, 0xfb, 0x24, 0x57, 0x99, 0x52, 0x5b, 0xc9, 0xc8, 0x4c),
+        tag: vec!(0xff, 0x46, 0x3c, 0x07, 0xe7, 0xef, 0x83, 0x13, 0x21, 0xd3, 0xfd, 0x77, 0x5f)
+      },
+      TestVector{
+        key: [0x08, 0xba, 0x23, 0x61, 0x6d, 0x91, 0x11, 0x88, 0xf9, 0x1d, 0xa0, 0x63, 0x27, 0x8b, 0xef, 0x12, 0x37, 0xdc, 0xbf, 0x17, 0xf5, 0x25, 0x85, 0xe5, 0x3c, 0x2c, 0x4b, 0x6c, 0xf3, 0xac, 0x9f, 0x0d],
+        nonce: [0x98, 0x9a, 0xe5, 0x93, 0xed, 0xdd, 0x38, 0x74],
+        plain_text: vec!(0x74, 0x91, 0x52, 0xc9, 0x47, 0x89, 0x44, 0xc8, 0x27, 0x1c, 0x0c, 0x11, 0xe0, 0x7b, 0xc1, 0xc5, 0x69, 0xee, 0xc0, 0x14, 0x93, 0xe6, 0x5b, 0x3b, 0x94, 0x84, 0x2a, 0x1b, 0xf5, 0xd7, 0x21, 0xf8),
+        aad: vec!(0xa1, 0x2d, 0x1a, 0x45, 0xb7, 0xc9, 0xb9, 0x1a, 0xb0, 0x87, 0x51, 0xa7, 0x0b, 0x75, 0x37, 0x14, 0x05, 0x2a, 0xd2, 0x4e, 0x0b, 0x26, 0x19, 0xfe, 0x8c, 0x3b, 0xe3, 0x03, 0xc6, 0x5f, 0x2d, 0xbc),
+        cipher_text: vec!(0x34, 0xc4, 0x05, 0x38, 0xee, 0x1d, 0x22, 0xdd, 0xf8, 0xac, 0x29, 0x0d, 0xd7, 0xd4, 0x23, 0xdf, 0xc6, 0x22, 0xb5, 0xcf, 0x8f, 0x34, 0x12, 0xa5, 0x34, 0x3e, 0x27, 0x78, 0x22, 0xae, 0xa7, 0x13),
+        tag: vec!(0x01, 0x4c, 0x7c, 0x67, 0x8e, 0x09, 0x49, 0xe8, 0x80, 0x71, 0xd1, 0xfe, 0x35, 0x31)
+      },
+      TestVector{
+        key: [0xc2, 0xba, 0x8b, 0xed, 0x86, 0x34, 0x15, 0x6a, 0xfc, 0x6b, 0xfe, 0x37, 0x54, 0xc9, 0x17, 0x44, 0xd4, 0x13, 0x1d, 0xe3, 0x9d, 0x05, 0x9f, 0x3a, 0x86, 0x63, 0x99, 0xf9, 0x16, 0x55, 0x3b, 0x5c],
+        nonce: [0x80, 0xfb, 0xf7, 0xb4, 0x33, 0xa4, 0xcd, 0x9c],
+        plain_text: vec!(0x41, 0x9b, 0xe6, 0x62, 0x3e, 0x79, 0x64, 0xf9, 0xf2, 0x60, 0x68, 0xdd, 0x96, 0x9e, 0x4a, 0x13, 0x96, 0x17, 0xe6, 0x7c, 0x5f, 0xfb, 0x26, 0x9b, 0x30, 0x13, 0xc4, 0x33, 0xfe, 0x77, 0x1c, 0x77),
+        aad: vec!(0x39, 0x37, 0x59, 0x2d, 0xb7, 0x8a, 0x61, 0xff, 0x46, 0x96, 0x91, 0xb6, 0x80, 0x07, 0x92, 0x01, 0x9b, 0xc2, 0xb3, 0xd4, 0x25, 0x12, 0xf2, 0x3c, 0x1b, 0x1a, 0x66, 0xa8, 0x27, 0x44, 0x95, 0xcb),
+        cipher_text: vec!(0x9d, 0x5b, 0xd1, 0xc7, 0xe7, 0x66, 0x76, 0x3e, 0xb0, 0x06, 0x84, 0xc0, 0x38, 0x04, 0x31, 0x11, 0xd8, 0xc6, 0x39, 0x0a, 0x8d, 0x6e, 0x17, 0xa1, 0x5e, 0xf9, 0x7c, 0x02, 0xab, 0x16, 0xf0, 0x9c),
+        tag: vec!(0xa6, 0x4d, 0x0e, 0xeb, 0x4a, 0x01, 0x48, 0x1e, 0xc0, 0xce, 0xe8, 0xc1, 0xc3, 0x57, 0xe3)
+      }
+    )
+  }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use chacha20poly1305::ChaCha20Poly1305;
+    use aead::{AeadEncryptor, AeadDecryptor};
+
+    #[bench]
+    pub fn chacha20poly1305_10(bh: & mut Bencher) {
+      let input = [1u8; 10];
+      let aad = [3u8; 10];
+      bh.iter( || {
+          let mut cipher = ChaCha20Poly1305::new(&[0; 32], &[0; 8], &aad);
+          let mut decipher = ChaCha20Poly1305::new(&[0; 32], &[0; 8], &aad);
+
+          let mut output = [0u8; 10];
+          let mut tag = [0u8; 16];
+          let mut output2 = [0u8; 10];
+          cipher.encrypt(&input, &mut output, &mut tag);
+          decipher.decrypt(&output, &mut output2, &tag);
+
+        });
+        bh.bytes = 10u64;
+    }
+
+
+    #[bench]
+    pub fn chacha20poly1305_1k(bh: & mut Bencher) {
+      let input = [1u8; 1024];
+      let aad = [3u8; 1024];
+      bh.iter( || {
+        let mut cipher = ChaCha20Poly1305::new(&[0; 32], &[0; 8], &aad);
+        let mut decipher = ChaCha20Poly1305::new(&[0; 32], &[0; 8], &aad);
+
+        let mut output = [0u8; 1024];
+        let mut tag = [0u8; 16];
+        let mut output2 = [0u8; 1024];
+
+        cipher.encrypt(&input, &mut output, &mut tag);
+        decipher.decrypt(&output, &mut output2, &tag);
+        });
+      bh.bytes = 1024u64;
+
+    }
+
+    #[bench]
+    pub fn chacha20poly1305_64k(bh: & mut Bencher) {
+      let input = [1u8; 65536];
+      let aad = [3u8; 65536];
+        bh.iter( || {
+          let mut cipher = ChaCha20Poly1305::new(&[0; 32], &[0; 8], &aad);
+          let mut decipher = ChaCha20Poly1305::new(&[0; 32], &[0; 8], &aad);
+
+          let mut output = [0u8; 65536];
+          let mut tag = [0u8; 16];
+          let mut output2 = [0u8; 65536];
+
+          cipher.encrypt(&input, &mut output, &mut tag);
+          decipher.decrypt(&output, &mut output2, &tag);
+
+        });
+         bh.bytes = 65536u64;
+
+    }
+}
diff --git a/third_party/rust-crypto/src/cryptoutil.rs b/third_party/rust-crypto/src/cryptoutil.rs
new file mode 100644
index 0000000..e908ab6
--- /dev/null
+++ b/third_party/rust-crypto/src/cryptoutil.rs
@@ -0,0 +1,592 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std;
+use std::{io, mem};
+use std::ptr;
+
+use buffer::{ReadBuffer, WriteBuffer, BufferResult};
+use buffer::BufferResult::{BufferUnderflow, BufferOverflow};
+use symmetriccipher::{SynchronousStreamCipher, SymmetricCipherError};
+
+/// Write a u64 into a vector, which must be 8 bytes long. The value is written in big-endian
+/// format.
+pub fn write_u64_be(dst: &mut[u8], mut input: u64) {
+    assert!(dst.len() == 8);
+    input = input.to_be();
+    unsafe {
+        let tmp = &input as *const _ as *const u8;
+        ptr::copy_nonoverlapping(tmp, dst.get_unchecked_mut(0), 8);
+    }
+}
+
+/// Write a u64 into a vector, which must be 8 bytes long. The value is written in little-endian
+/// format.
+pub fn write_u64_le(dst: &mut[u8], mut input: u64) {
+    assert!(dst.len() == 8);
+    input = input.to_le();
+    unsafe {
+        let tmp = &input as *const _ as *const u8;
+        ptr::copy_nonoverlapping(tmp, dst.get_unchecked_mut(0), 8);
+    }
+}
+
+/// Write a vector of u64s into a vector of bytes. The values are written in little-endian format.
+pub fn write_u64v_le(dst: &mut[u8], input: &[u64]) {
+    assert!(dst.len() == 8 * input.len());
+    unsafe {
+        let mut x: *mut u8 = dst.get_unchecked_mut(0);
+        let mut y: *const u64 = input.get_unchecked(0);
+        for _ in 0..input.len() {
+            let tmp = (*y).to_le();
+            ptr::copy_nonoverlapping(&tmp as *const _ as *const u8, x, 8);
+            x = x.offset(8);
+            y = y.offset(1);
+        }
+    }
+}
+
+/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
+/// format.
+pub fn write_u32_be(dst: &mut [u8], mut input: u32) {
+    assert!(dst.len() == 4);
+    input = input.to_be();
+    unsafe {
+        let tmp = &input as *const _ as *const u8;
+        ptr::copy_nonoverlapping(tmp, dst.get_unchecked_mut(0), 4);
+    }
+}
+
+/// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
+/// format.
+pub fn write_u32_le(dst: &mut[u8], mut input: u32) {
+    assert!(dst.len() == 4);
+    input = input.to_le();
+    unsafe {
+        let tmp = &input as *const _ as *const u8;
+        ptr::copy_nonoverlapping(tmp, dst.get_unchecked_mut(0), 4);
+    }
+}
+
+/// Write a vector of u32s into a vector of bytes. The values are written in little-endian format.
+pub fn write_u32v_le (dst: &mut[u8], input: &[u32]) {
+    assert!(dst.len() == 4 * input.len());
+    unsafe {
+        let mut x: *mut u8 = dst.get_unchecked_mut(0);
+        let mut y: *const u32 = input.get_unchecked(0);
+        for _ in 0..input.len() {
+            let tmp = (*y).to_le();
+            ptr::copy_nonoverlapping(&tmp as *const _ as *const u8, x, 4);
+            x = x.offset(4);
+            y = y.offset(1);
+        }
+    }
+}
+
+/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
+pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
+    assert!(dst.len() * 8 == input.len());
+    unsafe {
+        let mut x: *mut u64 = dst.get_unchecked_mut(0);
+        let mut y: *const u8 = input.get_unchecked(0);
+        for _ in 0..dst.len() {
+            let mut tmp: u64 = mem::uninitialized();
+            ptr::copy_nonoverlapping(y, &mut tmp as *mut _ as *mut u8, 8);
+            *x = u64::from_be(tmp);
+            x = x.offset(1);
+            y = y.offset(8);
+        }
+    }
+}
+
+/// Read a vector of bytes into a vector of u64s. The values are read in little-endian format.
+pub fn read_u64v_le(dst: &mut[u64], input: &[u8]) {
+    assert!(dst.len() * 8 == input.len());
+    unsafe {
+        let mut x: *mut u64 = dst.get_unchecked_mut(0);
+        let mut y: *const u8 = input.get_unchecked(0);
+        for _ in 0..dst.len() {
+            let mut tmp: u64 = mem::uninitialized();
+            ptr::copy_nonoverlapping(y, &mut tmp as *mut _ as *mut u8, 8);
+            *x = u64::from_le(tmp);
+            x = x.offset(1);
+            y = y.offset(8);
+        }
+    }
+}
+
+/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
+pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
+    assert!(dst.len() * 4 == input.len());
+    unsafe {
+        let mut x: *mut u32 = dst.get_unchecked_mut(0);
+        let mut y: *const u8 = input.get_unchecked(0);
+        for _ in 0..dst.len() {
+            let mut tmp: u32 = mem::uninitialized();
+            ptr::copy_nonoverlapping(y, &mut tmp as *mut _ as *mut u8, 4);
+            *x = u32::from_be(tmp);
+            x = x.offset(1);
+            y = y.offset(4);
+        }
+    }
+}
+
+/// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
+pub fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
+    assert!(dst.len() * 4 == input.len());
+    unsafe {
+        let mut x: *mut u32 = dst.get_unchecked_mut(0);
+        let mut y: *const u8 = input.get_unchecked(0);
+        for _ in 0..dst.len() {
+            let mut tmp: u32 = mem::uninitialized();
+            ptr::copy_nonoverlapping(y, &mut tmp as *mut _ as *mut u8, 4);
+            *x = u32::from_le(tmp);
+            x = x.offset(1);
+            y = y.offset(4);
+        }
+    }
+}
+
+/// Read the value of a vector of bytes as a u32 value in little-endian format.
+pub fn read_u32_le(input: &[u8]) -> u32 {
+    assert!(input.len() == 4);
+    unsafe {
+        let mut tmp: u32 = mem::uninitialized();
+        ptr::copy_nonoverlapping(input.get_unchecked(0), &mut tmp as *mut _ as *mut u8, 4);
+        u32::from_le(tmp)
+    }
+}
+
+/// Read the value of a vector of bytes as a u32 value in big-endian format.
+pub fn read_u32_be(input: &[u8]) -> u32 {
+    assert!(input.len() == 4);
+    unsafe {
+        let mut tmp: u32 = mem::uninitialized();
+        ptr::copy_nonoverlapping(input.get_unchecked(0), &mut tmp as *mut _ as *mut u8, 4);
+        u32::from_be(tmp)
+    }
+}
+
+/// XOR plaintext and keystream, storing the result in dst.
+pub fn xor_keystream(dst: &mut[u8], plaintext: &[u8], keystream: &[u8]) {
+    assert!(dst.len() == plaintext.len());
+    assert!(plaintext.len() <= keystream.len());
+
+    // Do one byte at a time, using unsafe to skip bounds checking.
+    let p = plaintext.as_ptr();
+    let k = keystream.as_ptr();
+    let d = dst.as_mut_ptr();
+    for i in 0isize..plaintext.len() as isize {
+        unsafe{ *d.offset(i) = *p.offset(i) ^ *k.offset(i) };
+    }
+}
+
+/// Copy bytes from src to dest
+#[inline]
+pub fn copy_memory(src: &[u8], dst: &mut [u8]) {
+    assert!(dst.len() >= src.len());
+    unsafe {
+        let srcp = src.as_ptr();
+        let dstp = dst.as_mut_ptr();
+        ptr::copy_nonoverlapping(srcp, dstp, src.len());
+    }
+}
+
+/// Zero all bytes in dst
+#[inline]
+pub fn zero(dst: &mut [u8]) {
+    unsafe {
+        ptr::write_bytes(dst.as_mut_ptr(), 0, dst.len());
+    }
+}
+
+/// An extension trait to implement a few useful serialization
+/// methods on types that implement Write
+pub trait WriteExt {
+    fn write_u8(&mut self, val: u8) -> io::Result<()>;
+    fn write_u32_le(&mut self, val: u32) -> io::Result<()>;
+    fn write_u32_be(&mut self, val: u32) -> io::Result<()>;
+    fn write_u64_le(&mut self, val: u64) -> io::Result<()>;
+    fn write_u64_be(&mut self, val: u64) -> io::Result<()>;
+}
+
+impl <T> WriteExt for T where T: io::Write {
+    fn write_u8(&mut self, val: u8) -> io::Result<()> {
+        let buff = [val];
+        self.write_all(&buff)
+    }
+    fn write_u32_le(&mut self, val: u32) -> io::Result<()> {
+        let mut buff = [0u8; 4];
+        write_u32_le(&mut buff, val);
+        self.write_all(&buff)
+    }
+    fn write_u32_be(&mut self, val: u32) -> io::Result<()> {
+        let mut buff = [0u8; 4];
+        write_u32_be(&mut buff, val);
+        self.write_all(&buff)
+    }
+    fn write_u64_le(&mut self, val: u64) -> io::Result<()> {
+        let mut buff = [0u8; 8];
+        write_u64_le(&mut buff, val);
+        self.write_all(&buff)
+    }
+    fn write_u64_be(&mut self, val: u64) -> io::Result<()> {
+        let mut buff = [0u8; 8];
+        write_u64_be(&mut buff, val);
+        self.write_all(&buff)
+    }
+}
+
+/// symm_enc_or_dec() implements the necessary functionality to turn a SynchronousStreamCipher into
+/// an Encryptor or Decryptor
+pub fn symm_enc_or_dec<S: SynchronousStreamCipher, R: ReadBuffer, W: WriteBuffer>(
+        c: &mut S,
+        input: &mut R,
+        output: &mut W) ->
+        Result<BufferResult, SymmetricCipherError> {
+    let count = std::cmp::min(input.remaining(), output.remaining());
+    c.process(input.take_next(count), output.take_next(count));
+    if input.is_empty() {
+        Ok(BufferUnderflow)
+    } else {
+        Ok(BufferOverflow)
+    }
+}
+
+/// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
+/// high-order value and the 2nd item is the low order value.
+fn to_bits(x: u64) -> (u64, u64) {
+    (x >> 61, x << 3)
+}
+
+/// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric
+/// overflow.
+pub fn add_bytes_to_bits(bits: u64, bytes: u64) -> u64 {
+    let (new_high_bits, new_low_bits) = to_bits(bytes);
+
+    if new_high_bits > 0 {
+        panic!("Numeric overflow occured.")
+    }
+
+    bits.checked_add(new_low_bits).expect("Numeric overflow occured.")
+}
+
+/// Adds the specified number of bytes to the bit count, which is a tuple where the first element is
+/// the high order value. panic!() if this would cause numeric overflow.
+pub fn add_bytes_to_bits_tuple
+        (bits: (u64, u64), bytes: u64) -> (u64, u64) {
+    let (new_high_bits, new_low_bits) = to_bits(bytes);
+    let (hi, low) = bits;
+
+    // Add the low order value - if there is no overflow, then add the high order values
+    // If the addition of the low order values causes overflow, add one to the high order values
+    // before adding them.
+    match low.checked_add(new_low_bits) {
+        Some(x) => {
+            if new_high_bits == 0 {
+                // This is the fast path - every other alternative will rarely occur in practice
+                // considering how large an input would need to be for those paths to be used.
+                return (hi, x);
+            } else {
+                match hi.checked_add(new_high_bits) {
+                    Some(y) => return (y, x),
+                    None => panic!("Numeric overflow occured.")
+                }
+            }
+        },
+        None => {
+            let z = match new_high_bits.checked_add(1) {
+                Some(w) => w,
+                None => panic!("Numeric overflow occured.")
+            };
+            match hi.checked_add(z) {
+                // This re-executes the addition that was already performed earlier when overflow
+                // occured, this time allowing the overflow to happen. Technically, this could be
+                // avoided by using the checked add intrinsic directly, but that involves using
+                // unsafe code and is not really worthwhile considering how infrequently code will
+                // run in practice. This is the reason that this function requires that the type T
+                // be UnsignedInt - overflow is not defined for Signed types. This function could
+                // be implemented for signed types as well if that were needed.
+                Some(y) => return (y, low.wrapping_add(new_low_bits)),
+                None => panic!("Numeric overflow occured.")
+            }
+        }
+    }
+}
+
+
+/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
+/// must be processed. The input() method takes care of processing and then clearing the buffer
+/// automatically. However, other methods do not and require the caller to process the buffer. Any
+/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
+/// results in those bytes being marked as used by the buffer.
+pub trait FixedBuffer {
+    /// Input a vector of bytes. If the buffer becomes full, process it with the provided
+    /// function and then clear the buffer.
+    fn input<F: FnMut(&[u8])>(&mut self, input: &[u8], func: F);
+
+    /// Reset the buffer.
+    fn reset(&mut self);
+
+    /// Zero the buffer up until the specified index. The buffer position currently must not be
+    /// greater than that index.
+    fn zero_until(&mut self, idx: usize);
+
+    /// Get a slice of the buffer of the specified size. There must be at least that many bytes
+    /// remaining in the buffer.
+    fn next<'s>(&'s mut self, len: usize) -> &'s mut [u8];
+
+    /// Get the current buffer. The buffer must already be full. This clears the buffer as well.
+    fn full_buffer<'s>(&'s mut self) -> &'s [u8];
+
+     /// Get the current buffer.
+    fn current_buffer<'s>(&'s mut self) -> &'s [u8];
+
+    /// Get the current position of the buffer.
+    fn position(&self) -> usize;
+
+    /// Get the number of bytes remaining in the buffer until it is full.
+    fn remaining(&self) -> usize;
+
+    /// Get the size of the buffer
+    fn size(&self) -> usize;
+}
+
+macro_rules! impl_fixed_buffer( ($name:ident, $size:expr) => (
+    impl FixedBuffer for $name {
+        fn input<F: FnMut(&[u8])>(&mut self, input: &[u8], mut func: F) {
+            let mut i = 0;
+
+            // FIXME: #6304 - This local variable shouldn't be necessary.
+            let size = $size;
+
+            // If there is already data in the buffer, copy as much as we can into it and process
+            // the data if the buffer becomes full.
+            if self.buffer_idx != 0 {
+                let buffer_remaining = size - self.buffer_idx;
+                if input.len() >= buffer_remaining {
+                        copy_memory(
+                            &input[..buffer_remaining],
+                            &mut self.buffer[self.buffer_idx..size]);
+                    self.buffer_idx = 0;
+                    func(&self.buffer);
+                    i += buffer_remaining;
+                } else {
+                    copy_memory(
+                        input,
+                        &mut self.buffer[self.buffer_idx..self.buffer_idx + input.len()]);
+                    self.buffer_idx += input.len();
+                    return;
+                }
+            }
+
+            // While we have at least a full buffer size chunks's worth of data, process that data
+            // without copying it into the buffer
+            while input.len() - i >= size {
+                func(&input[i..i + size]);
+                i += size;
+            }
+
+            // Copy any input data into the buffer. At this point in the method, the ammount of
+            // data left in the input vector will be less than the buffer size and the buffer will
+            // be empty.
+            let input_remaining = input.len() - i;
+            copy_memory(
+                &input[i..],
+                &mut self.buffer[0..input_remaining]);
+            self.buffer_idx += input_remaining;
+        }
+
+        fn reset(&mut self) {
+            self.buffer_idx = 0;
+        }
+
+        fn zero_until(&mut self, idx: usize) {
+            assert!(idx >= self.buffer_idx);
+            zero(&mut self.buffer[self.buffer_idx..idx]);
+            self.buffer_idx = idx;
+        }
+
+        fn next<'s>(&'s mut self, len: usize) -> &'s mut [u8] {
+            self.buffer_idx += len;
+            &mut self.buffer[self.buffer_idx - len..self.buffer_idx]
+        }
+
+        fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
+            assert!(self.buffer_idx == $size);
+            self.buffer_idx = 0;
+            &self.buffer[..$size]
+        }
+
+        fn current_buffer<'s>(&'s mut self) -> &'s [u8] {
+            let tmp = self.buffer_idx;
+            self.buffer_idx = 0;
+            &self.buffer[..tmp]
+        }
+
+        fn position(&self) -> usize { self.buffer_idx }
+
+        fn remaining(&self) -> usize { $size - self.buffer_idx }
+
+        fn size(&self) -> usize { $size }
+    }
+));
+
+/// A fixed size buffer of 64 bytes useful for cryptographic operations.
+#[derive(Copy)]
+pub struct FixedBuffer64 {
+    buffer: [u8; 64],
+    buffer_idx: usize,
+}
+
+impl Clone for FixedBuffer64 { fn clone(&self) -> FixedBuffer64 { *self } }
+
+impl FixedBuffer64 {
+    /// Create a new buffer
+    pub fn new() -> FixedBuffer64 {
+        FixedBuffer64 {
+            buffer: [0u8; 64],
+            buffer_idx: 0
+        }
+    }
+}
+
+impl_fixed_buffer!(FixedBuffer64, 64);
+
+/// A fixed size buffer of 128 bytes useful for cryptographic operations.
+#[derive(Copy)]
+pub struct FixedBuffer128 {
+    buffer: [u8; 128],
+    buffer_idx: usize,
+}
+
+impl Clone for FixedBuffer128 { fn clone(&self) -> FixedBuffer128 { *self } }
+
+impl FixedBuffer128 {
+    /// Create a new buffer
+    pub fn new() -> FixedBuffer128 {
+        FixedBuffer128 {
+            buffer: [0u8; 128],
+            buffer_idx: 0
+        }
+    }
+}
+
+impl_fixed_buffer!(FixedBuffer128, 128);
+
+
+/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
+/// struct.
+pub trait StandardPadding {
+    /// Add standard padding to the buffer. The buffer must not be full when this method is called
+    /// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
+    /// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
+    /// filled with zeros again until only rem bytes are remaining.
+    fn standard_padding<F: FnMut(&[u8])>(&mut self, rem: usize, func: F);
+}
+
+impl <T: FixedBuffer> StandardPadding for T {
+    fn standard_padding<F: FnMut(&[u8])>(&mut self, rem: usize, mut func: F) {
+        let size = self.size();
+
+        self.next(1)[0] = 128;
+
+        if self.remaining() < rem {
+            self.zero_until(size);
+            func(self.full_buffer());
+        }
+
+        self.zero_until(size - rem);
+    }
+}
+
+
+#[cfg(test)]
+pub mod test {
+    use std;
+    use std::iter::repeat;
+
+    use rand::IsaacRng;
+    use rand::distributions::{IndependentSample, Range};
+
+    use cryptoutil::{add_bytes_to_bits, add_bytes_to_bits_tuple};
+    use digest::Digest;
+
+    /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
+    /// correct.
+    pub fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: usize, expected: &str) {
+        let total_size = 1000000;
+        let buffer: Vec<u8> = repeat('a' as u8).take(blocksize * 2).collect();
+        let mut rng = IsaacRng::new_unseeded();
+        let range = Range::new(0, 2 * blocksize + 1);
+        let mut count = 0;
+
+        digest.reset();
+
+        while count < total_size {
+            let next = range.ind_sample(&mut rng);
+            let remaining = total_size - count;
+            let size = if next > remaining { remaining } else { next };
+            digest.input(&buffer[..size]);
+            count += size;
+        }
+
+        let result_str = digest.result_str();
+
+        assert!(expected == &result_str[..]);
+    }
+
+    // A normal addition - no overflow occurs
+    #[test]
+    fn test_add_bytes_to_bits_ok() {
+        assert!(add_bytes_to_bits(100, 10) == 180);
+    }
+
+    // A simple failure case - adding 1 to the max value
+    #[test]
+    #[should_panic]
+    fn test_add_bytes_to_bits_overflow() {
+        add_bytes_to_bits(std::u64::MAX, 1);
+    }
+
+    // A normal addition - no overflow occurs (fast path)
+    #[test]
+    fn test_add_bytes_to_bits_tuple_ok() {
+        assert!(add_bytes_to_bits_tuple((5, 100), 10) == (5, 180));
+    }
+
+    // The low order value overflows into the high order value
+    #[test]
+    fn test_add_bytes_to_bits_tuple_ok2() {
+        assert!(add_bytes_to_bits_tuple((5, std::u64::MAX), 1) == (6, 7));
+    }
+
+    // The value to add is too large to be converted into bits without overflowing its type
+    #[test]
+    fn test_add_bytes_to_bits_tuple_ok3() {
+        assert!(add_bytes_to_bits_tuple((5, 0), 0x4000000000000001) == (7, 8));
+    }
+
+    // A simple failure case - adding 1 to the max value
+    #[test]
+    #[should_panic]
+    fn test_add_bytes_to_bits_tuple_overflow() {
+        add_bytes_to_bits_tuple((std::u64::MAX, std::u64::MAX), 1);
+    }
+
+    // The value to add is too large to convert to bytes without overflowing its type, but the high
+    // order value from this conversion overflows when added to the existing high order value
+    #[test]
+    #[should_panic]
+    fn test_add_bytes_to_bits_tuple_overflow2() {
+        let value: u64 = std::u64::MAX;
+        add_bytes_to_bits_tuple((value - 1, 0), 0x8000000000000000);
+    }
+}
diff --git a/third_party/rust-crypto/src/curve25519.rs b/third_party/rust-crypto/src/curve25519.rs
new file mode 100644
index 0000000..873a2c4
--- /dev/null
+++ b/third_party/rust-crypto/src/curve25519.rs
@@ -0,0 +1,3642 @@
+use std::ops::{Add, Sub, Mul};
+use std::cmp::{Eq, PartialEq,min};
+use util::{fixed_time_eq};
+use step_by::RangeExt;
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+#[derive(Clone, Copy)]
+pub struct Fe(pub [i32; 10]);
+
+impl PartialEq for Fe {
+    fn eq(&self, other: &Fe) -> bool {
+        let &Fe(self_elems) = self;
+        let &Fe(other_elems) = other;
+        self_elems.to_vec() == other_elems.to_vec()
+    }
+}
+impl Eq for Fe { }
+
+static FE_ZERO : Fe = Fe([0,0,0,0,0,0,0,0,0,0]);
+static FE_ONE : Fe = Fe([1,0,0,0,0,0,0,0,0,0]);
+static FE_SQRTM1 : Fe = Fe([-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482]);
+static FE_D : Fe = Fe([-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116]);
+static FE_D2 : Fe = Fe([-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199]);
+
+
+fn load_4u(s: &[u8]) -> u64 {
+    (s[0] as u64)
+        | ((s[1] as u64)<<8)
+        | ((s[2] as u64)<<16)
+        | ((s[3] as u64)<<24)
+}
+fn load_4i(s: &[u8]) -> i64 {
+    load_4u(s) as i64
+}
+fn load_3u(s: &[u8]) -> u64 {
+    (s[0] as u64)
+        | ((s[1] as u64)<<8)
+        | ((s[2] as u64)<<16)
+}
+fn load_3i(s: &[u8]) -> i64 {
+    load_3u(s) as i64
+}
+
+impl Add for Fe {
+    type Output = Fe;
+
+    /*
+    h = f + g
+    Can overlap h with f or g.
+
+    Preconditions:
+       |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+       |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+    Postconditions:
+       |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+    */
+    fn add(self, _rhs: Fe) -> Fe {
+        let Fe(f) = self;
+        let Fe(g) = _rhs;
+
+        let f0 = f[0];
+        let f1 = f[1];
+        let f2 = f[2];
+        let f3 = f[3];
+        let f4 = f[4];
+        let f5 = f[5];
+        let f6 = f[6];
+        let f7 = f[7];
+        let f8 = f[8];
+        let f9 = f[9];
+        let g0 = g[0];
+        let g1 = g[1];
+        let g2 = g[2];
+        let g3 = g[3];
+        let g4 = g[4];
+        let g5 = g[5];
+        let g6 = g[6];
+        let g7 = g[7];
+        let g8 = g[8];
+        let g9 = g[9];
+        let h0 = f0 + g0;
+        let h1 = f1 + g1;
+        let h2 = f2 + g2;
+        let h3 = f3 + g3;
+        let h4 = f4 + g4;
+        let h5 = f5 + g5;
+        let h6 = f6 + g6;
+        let h7 = f7 + g7;
+        let h8 = f8 + g8;
+        let h9 = f9 + g9;
+        Fe([h0, h1, h2, h3, h4, h5, h6, h7, h8, h9])
+    }
+}
+
+impl Sub for Fe {
+    type Output = Fe;
+
+    /*
+    h = f - g
+    Can overlap h with f or g.
+
+    Preconditions:
+       |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+       |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+    Postconditions:
+       |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+    */
+    fn sub(self, _rhs: Fe) -> Fe {
+        let Fe(f) = self;
+        let Fe(g) = _rhs;
+
+        let f0 = f[0];
+        let f1 = f[1];
+        let f2 = f[2];
+        let f3 = f[3];
+        let f4 = f[4];
+        let f5 = f[5];
+        let f6 = f[6];
+        let f7 = f[7];
+        let f8 = f[8];
+        let f9 = f[9];
+        let g0 = g[0];
+        let g1 = g[1];
+        let g2 = g[2];
+        let g3 = g[3];
+        let g4 = g[4];
+        let g5 = g[5];
+        let g6 = g[6];
+        let g7 = g[7];
+        let g8 = g[8];
+        let g9 = g[9];
+        let h0 = f0 - g0;
+        let h1 = f1 - g1;
+        let h2 = f2 - g2;
+        let h3 = f3 - g3;
+        let h4 = f4 - g4;
+        let h5 = f5 - g5;
+        let h6 = f6 - g6;
+        let h7 = f7 - g7;
+        let h8 = f8 - g8;
+        let h9 = f9 - g9;
+        Fe([h0, h1, h2, h3, h4, h5, h6, h7, h8, h9])
+    }
+}
+
+impl Mul for Fe {
+    type Output = Fe;
+
+    /*
+    h = f * g
+    Can overlap h with f or g.
+
+    Preconditions:
+       |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+       |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+    Postconditions:
+       |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+    */
+
+    /*
+    Notes on implementation strategy:
+
+    Using schoolbook multiplication.
+    Karatsuba would save a little in some cost models.
+
+    Most multiplications by 2 and 19 are 32-bit precomputations;
+    cheaper than 64-bit postcomputations.
+
+    There is one remaining multiplication by 19 in the carry chain;
+    one *19 precomputation can be merged into this,
+    but the resulting data flow is considerably less clean.
+
+    There are 12 carries below.
+    10 of them are 2-way parallelizable and vectorizable.
+    Can get away with 11 carries, but then data flow is much deeper.
+
+    With tighter constraints on inputs can squeeze carries into int32.
+    */
+
+    fn mul(self, _rhs: Fe) -> Fe {
+        let Fe(f) = self;
+        let Fe(g) = _rhs;
+        let f0 = f[0];
+        let f1 = f[1];
+        let f2 = f[2];
+        let f3 = f[3];
+        let f4 = f[4];
+        let f5 = f[5];
+        let f6 = f[6];
+        let f7 = f[7];
+        let f8 = f[8];
+        let f9 = f[9];
+        let g0 = g[0];
+        let g1 = g[1];
+        let g2 = g[2];
+        let g3 = g[3];
+        let g4 = g[4];
+        let g5 = g[5];
+        let g6 = g[6];
+        let g7 = g[7];
+        let g8 = g[8];
+        let g9 = g[9];
+        let g1_19 = 19 * g1; /* 1.4*2^29 */
+        let g2_19 = 19 * g2; /* 1.4*2^30; still ok */
+        let g3_19 = 19 * g3;
+        let g4_19 = 19 * g4;
+        let g5_19 = 19 * g5;
+        let g6_19 = 19 * g6;
+        let g7_19 = 19 * g7;
+        let g8_19 = 19 * g8;
+        let g9_19 = 19 * g9;
+        let f1_2 = 2 * f1;
+        let f3_2 = 2 * f3;
+        let f5_2 = 2 * f5;
+        let f7_2 = 2 * f7;
+        let f9_2 = 2 * f9;
+        let f0g0    = (f0   as i64) * (g0 as i64);
+        let f0g1    = (f0   as i64) * (g1 as i64);
+        let f0g2    = (f0   as i64) * (g2 as i64);
+        let f0g3    = (f0   as i64) * (g3 as i64);
+        let f0g4    = (f0   as i64) * (g4 as i64);
+        let f0g5    = (f0   as i64) * (g5 as i64);
+        let f0g6    = (f0   as i64) * (g6 as i64);
+        let f0g7    = (f0   as i64) * (g7 as i64);
+        let f0g8    = (f0   as i64) * (g8 as i64);
+        let f0g9    = (f0   as i64) * (g9 as i64);
+        let f1g0    = (f1   as i64) * (g0 as i64);
+        let f1g1_2  = (f1_2 as i64) * (g1 as i64);
+        let f1g2    = (f1   as i64) * (g2 as i64);
+        let f1g3_2  = (f1_2 as i64) * (g3 as i64);
+        let f1g4    = (f1   as i64) * (g4 as i64);
+        let f1g5_2  = (f1_2 as i64) * (g5 as i64);
+        let f1g6    = (f1   as i64) * (g6 as i64);
+        let f1g7_2  = (f1_2 as i64) * (g7 as i64);
+        let f1g8    = (f1   as i64) * (g8 as i64);
+        let f1g9_38 = (f1_2 as i64) * (g9_19 as i64);
+        let f2g0    = (f2   as i64) * (g0 as i64);
+        let f2g1    = (f2   as i64) * (g1 as i64);
+        let f2g2    = (f2   as i64) * (g2 as i64);
+        let f2g3    = (f2   as i64) * (g3 as i64);
+        let f2g4    = (f2   as i64) * (g4 as i64);
+        let f2g5    = (f2   as i64) * (g5 as i64);
+        let f2g6    = (f2   as i64) * (g6 as i64);
+        let f2g7    = (f2   as i64) * (g7 as i64);
+        let f2g8_19 = (f2   as i64) * (g8_19 as i64);
+        let f2g9_19 = (f2   as i64) * (g9_19 as i64);
+        let f3g0    = (f3   as i64) * (g0 as i64);
+        let f3g1_2  = (f3_2 as i64) * (g1 as i64);
+        let f3g2    = (f3   as i64) * (g2 as i64);
+        let f3g3_2  = (f3_2 as i64) * (g3 as i64);
+        let f3g4    = (f3   as i64) * (g4 as i64);
+        let f3g5_2  = (f3_2 as i64) * (g5 as i64);
+        let f3g6    = (f3   as i64) * (g6 as i64);
+        let f3g7_38 = (f3_2 as i64) * (g7_19 as i64);
+        let f3g8_19 = (f3   as i64) * (g8_19 as i64);
+        let f3g9_38 = (f3_2 as i64) * (g9_19 as i64);
+        let f4g0    = (f4   as i64) * (g0 as i64);
+        let f4g1    = (f4   as i64) * (g1 as i64);
+        let f4g2    = (f4   as i64) * (g2 as i64);
+        let f4g3    = (f4   as i64) * (g3 as i64);
+        let f4g4    = (f4   as i64) * (g4 as i64);
+        let f4g5    = (f4   as i64) * (g5 as i64);
+        let f4g6_19 = (f4   as i64) * (g6_19 as i64);
+        let f4g7_19 = (f4   as i64) * (g7_19 as i64);
+        let f4g8_19 = (f4   as i64) * (g8_19 as i64);
+        let f4g9_19 = (f4   as i64) * (g9_19 as i64);
+        let f5g0    = (f5   as i64) * (g0 as i64);
+        let f5g1_2  = (f5_2 as i64) * (g1 as i64);
+        let f5g2    = (f5   as i64) * (g2 as i64);
+        let f5g3_2  = (f5_2 as i64) * (g3 as i64);
+        let f5g4    = (f5   as i64) * (g4 as i64);
+        let f5g5_38 = (f5_2 as i64) * (g5_19 as i64);
+        let f5g6_19 = (f5   as i64) * (g6_19 as i64);
+        let f5g7_38 = (f5_2 as i64) * (g7_19 as i64);
+        let f5g8_19 = (f5   as i64) * (g8_19 as i64);
+        let f5g9_38 = (f5_2 as i64) * (g9_19 as i64);
+        let f6g0    = (f6   as i64) * (g0 as i64);
+        let f6g1    = (f6   as i64) * (g1 as i64);
+        let f6g2    = (f6   as i64) * (g2 as i64);
+        let f6g3    = (f6   as i64) * (g3 as i64);
+        let f6g4_19 = (f6   as i64) * (g4_19 as i64);
+        let f6g5_19 = (f6   as i64) * (g5_19 as i64);
+        let f6g6_19 = (f6   as i64) * (g6_19 as i64);
+        let f6g7_19 = (f6   as i64) * (g7_19 as i64);
+        let f6g8_19 = (f6   as i64) * (g8_19 as i64);
+        let f6g9_19 = (f6   as i64) * (g9_19 as i64);
+        let f7g0    = (f7   as i64) * (g0 as i64);
+        let f7g1_2  = (f7_2 as i64) * (g1 as i64);
+        let f7g2    = (f7   as i64) * (g2 as i64);
+        let f7g3_38 = (f7_2 as i64) * (g3_19 as i64);
+        let f7g4_19 = (f7   as i64) * (g4_19 as i64);
+        let f7g5_38 = (f7_2 as i64) * (g5_19 as i64);
+        let f7g6_19 = (f7   as i64) * (g6_19 as i64);
+        let f7g7_38 = (f7_2 as i64) * (g7_19 as i64);
+        let f7g8_19 = (f7   as i64) * (g8_19 as i64);
+        let f7g9_38 = (f7_2 as i64) * (g9_19 as i64);
+        let f8g0    = (f8   as i64) * (g0 as i64);
+        let f8g1    = (f8   as i64) * (g1 as i64);
+        let f8g2_19 = (f8   as i64) * (g2_19 as i64);
+        let f8g3_19 = (f8   as i64) * (g3_19 as i64);
+        let f8g4_19 = (f8   as i64) * (g4_19 as i64);
+        let f8g5_19 = (f8   as i64) * (g5_19 as i64);
+        let f8g6_19 = (f8   as i64) * (g6_19 as i64);
+        let f8g7_19 = (f8   as i64) * (g7_19 as i64);
+        let f8g8_19 = (f8   as i64) * (g8_19 as i64);
+        let f8g9_19 = (f8   as i64) * (g9_19 as i64);
+        let f9g0    = (f9   as i64) * (g0 as i64);
+        let f9g1_38 = (f9_2 as i64) * (g1_19 as i64);
+        let f9g2_19 = (f9   as i64) * (g2_19 as i64);
+        let f9g3_38 = (f9_2 as i64) * (g3_19 as i64);
+        let f9g4_19 = (f9   as i64) * (g4_19 as i64);
+        let f9g5_38 = (f9_2 as i64) * (g5_19 as i64);
+        let f9g6_19 = (f9   as i64) * (g6_19 as i64);
+        let f9g7_38 = (f9_2 as i64) * (g7_19 as i64);
+        let f9g8_19 = (f9   as i64) * (g8_19 as i64);
+        let f9g9_38 = (f9_2 as i64) * (g9_19 as i64);
+        let mut h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+        let mut h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+        let mut h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+        let mut h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+        let mut h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+        let mut h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+        let mut h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+        let mut h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+        let mut h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+        let mut h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+        let mut carry0;
+        let carry1;
+        let carry2;
+        let carry3;
+        let mut carry4;
+        let carry5;
+        let carry6;
+        let carry7;
+        let carry8;
+        let carry9;
+
+        /*
+        |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+          i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+        |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+          i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+        */
+
+        carry0 = (h0 + (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+        carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+        /* |h0| <= 2^25 */
+        /* |h4| <= 2^25 */
+        /* |h1| <= 1.51*2^58 */
+        /* |h5| <= 1.51*2^58 */
+
+        carry1 = (h1 + (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+        carry5 = (h5 + (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+        /* |h1| <= 2^24; from now on fits into int32 */
+        /* |h5| <= 2^24; from now on fits into int32 */
+        /* |h2| <= 1.21*2^59 */
+        /* |h6| <= 1.21*2^59 */
+
+        carry2 = (h2 + (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+        carry6 = (h6 + (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+        /* |h2| <= 2^25; from now on fits into int32 unchanged */
+        /* |h6| <= 2^25; from now on fits into int32 unchanged */
+        /* |h3| <= 1.51*2^58 */
+        /* |h7| <= 1.51*2^58 */
+
+        carry3 = (h3 + (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+        carry7 = (h7 + (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+        /* |h3| <= 2^24; from now on fits into int32 unchanged */
+        /* |h7| <= 2^24; from now on fits into int32 unchanged */
+        /* |h4| <= 1.52*2^33 */
+        /* |h8| <= 1.52*2^33 */
+
+        carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+        carry8 = (h8 + (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+        /* |h4| <= 2^25; from now on fits into int32 unchanged */
+        /* |h8| <= 2^25; from now on fits into int32 unchanged */
+        /* |h5| <= 1.01*2^24 */
+        /* |h9| <= 1.51*2^58 */
+
+        carry9 = (h9 + (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+        /* |h9| <= 2^24; from now on fits into int32 unchanged */
+        /* |h0| <= 1.8*2^37 */
+
+        carry0 = (h0 + (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+        /* |h0| <= 2^25; from now on fits into int32 unchanged */
+        /* |h1| <= 1.01*2^24 */
+
+        Fe([h0 as i32, h1 as i32, h2 as i32, h3 as i32, h4 as i32,
+            h5 as i32, h6 as i32, h7 as i32, h8 as i32, h9 as i32])
+    }
+}
+
+impl Fe {
+    pub fn from_bytes(s: &[u8]) -> Fe {
+        let mut h0 = load_4i(&s[0..4]);
+        let mut h1 = load_3i(&s[4..7]) << 6;
+        let mut h2 = load_3i(&s[7..10]) << 5;
+        let mut h3 = load_3i(&s[10..13]) << 3;
+        let mut h4 = load_3i(&s[13..16]) << 2;
+        let mut h5 = load_4i(&s[16..20]);
+        let mut h6 = load_3i(&s[20..23]) << 7;
+        let mut h7 = load_3i(&s[23..26]) << 5;
+        let mut h8 = load_3i(&s[26..29]) << 4;
+        let mut h9 = (load_3i(&s[29..32]) & 8388607) << 2;
+
+        let carry9 = (h9 + (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+        let carry1 = (h1 + (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+        let carry3 = (h3 + (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+        let carry5 = (h5 + (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+        let carry7 = (h7 + (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+        let carry0 = (h0 + (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+        let carry2 = (h2 + (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+        let carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+        let carry6 = (h6 + (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+        let carry8 = (h8 + (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+        Fe([h0 as i32, h1 as i32, h2 as i32, h3 as i32, h4 as i32,
+            h5 as i32, h6 as i32, h7 as i32, h8 as i32, h9 as i32])
+    }
+
+    /*
+    Preconditions:
+      |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+    Write p=2^255-19; q=floor(h/p).
+    Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+    Proof:
+      Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+      Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+      Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+      Then 0<y<1.
+
+      Write r=h-pq.
+      Have 0<=r<=p-1=2^255-20.
+      Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+      Write x=r+19(2^-255)r+y.
+      Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+      Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+      so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+    */
+
+    pub fn to_bytes(&self) -> [u8; 32] {
+        let &Fe(es) = self;
+        let mut h0 = es[0];
+        let mut h1 = es[1];
+        let mut h2 = es[2];
+        let mut h3 = es[3];
+        let mut h4 = es[4];
+        let mut h5 = es[5];
+        let mut h6 = es[6];
+        let mut h7 = es[7];
+        let mut h8 = es[8];
+        let mut h9 = es[9];
+        let mut q;
+
+        q = (19 * h9 + (1 << 24)) >> 25;
+        q = (h0 + q) >> 26;
+        q = (h1 + q) >> 25;
+        q = (h2 + q) >> 26;
+        q = (h3 + q) >> 25;
+        q = (h4 + q) >> 26;
+        q = (h5 + q) >> 25;
+        q = (h6 + q) >> 26;
+        q = (h7 + q) >> 25;
+        q = (h8 + q) >> 26;
+        q = (h9 + q) >> 25;
+
+        /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+        h0 += 19 * q;
+        /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+        let carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+        let carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+        let carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+        let carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+        let carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+        let carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+        let carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+        let carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+        let carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+        let carry9 = h9 >> 25;               h9 -= carry9 << 25;
+                            /* h10 = carry9 */
+
+        /*
+        Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+        Have h0+...+2^230 h9 between 0 and 2^255-1;
+        evidently 2^255 h10-2^255 q = 0.
+        Goal: Output h0+...+2^230 h9.
+        */
+        [
+            (h0 >> 0) as u8,
+            (h0 >> 8) as u8,
+            (h0 >> 16) as u8,
+            ((h0 >> 24) | (h1 << 2)) as u8,
+            (h1 >> 6) as u8,
+            (h1 >> 14) as u8,
+            ((h1 >> 22) | (h2 << 3)) as u8,
+            (h2 >> 5) as u8,
+            (h2 >> 13) as u8,
+            ((h2 >> 21) | (h3 << 5)) as u8,
+            (h3 >> 3) as u8,
+            (h3 >> 11) as u8,
+            ((h3 >> 19) | (h4 << 6)) as u8,
+            (h4 >> 2) as u8,
+            (h4 >> 10) as u8,
+            (h4 >> 18) as u8,
+            (h5 >> 0) as u8,
+            (h5 >> 8) as u8,
+            (h5 >> 16) as u8,
+            ((h5 >> 24) | (h6 << 1)) as u8,
+            (h6 >> 7) as u8,
+            (h6 >> 15) as u8,
+            ((h6 >> 23) | (h7 << 3)) as u8,
+            (h7 >> 5) as u8,
+            (h7 >> 13) as u8,
+            ((h7 >> 21) | (h8 << 4)) as u8,
+            (h8 >> 4) as u8,
+            (h8 >> 12) as u8,
+            ((h8 >> 20) | (h9 << 6)) as u8,
+            (h9 >> 2) as u8,
+            (h9 >> 10) as u8,
+            (h9 >> 18) as u8,
+        ]
+    }
+
+    pub fn maybe_swap_with(&mut self, other: &mut Fe, do_swap: i32) {
+        let &mut Fe(f) = self;
+        let &mut Fe(g) = other;
+        let f0 = f[0];
+        let f1 = f[1];
+        let f2 = f[2];
+        let f3 = f[3];
+        let f4 = f[4];
+        let f5 = f[5];
+        let f6 = f[6];
+        let f7 = f[7];
+        let f8 = f[8];
+        let f9 = f[9];
+        let g0 = g[0];
+        let g1 = g[1];
+        let g2 = g[2];
+        let g3 = g[3];
+        let g4 = g[4];
+        let g5 = g[5];
+        let g6 = g[6];
+        let g7 = g[7];
+        let g8 = g[8];
+        let g9 = g[9];
+        let mut x0 = f0 ^ g0;
+        let mut x1 = f1 ^ g1;
+        let mut x2 = f2 ^ g2;
+        let mut x3 = f3 ^ g3;
+        let mut x4 = f4 ^ g4;
+        let mut x5 = f5 ^ g5;
+        let mut x6 = f6 ^ g6;
+        let mut x7 = f7 ^ g7;
+        let mut x8 = f8 ^ g8;
+        let mut x9 = f9 ^ g9;
+        let b = -do_swap;
+        x0 &= b;
+        x1 &= b;
+        x2 &= b;
+        x3 &= b;
+        x4 &= b;
+        x5 &= b;
+        x6 &= b;
+        x7 &= b;
+        x8 &= b;
+        x9 &= b;
+        *self  = Fe([f0^x0, f1^x1, f2^x2, f3^x3, f4^x4,
+                     f5^x5, f6^x6, f7^x7, f8^x8, f9^x9]);
+        *other = Fe([g0^x0, g1^x1, g2^x2, g3^x3, g4^x4,
+                     g5^x5, g6^x6, g7^x7, g8^x8, g9^x9]);
+    }
+
+    pub fn maybe_set(&mut self, other: &Fe, do_swap: i32) {
+        let &mut Fe(f) = self;
+        let &Fe(g) = other;
+        let f0 = f[0];
+        let f1 = f[1];
+        let f2 = f[2];
+        let f3 = f[3];
+        let f4 = f[4];
+        let f5 = f[5];
+        let f6 = f[6];
+        let f7 = f[7];
+        let f8 = f[8];
+        let f9 = f[9];
+        let g0 = g[0];
+        let g1 = g[1];
+        let g2 = g[2];
+        let g3 = g[3];
+        let g4 = g[4];
+        let g5 = g[5];
+        let g6 = g[6];
+        let g7 = g[7];
+        let g8 = g[8];
+        let g9 = g[9];
+        let mut x0 = f0 ^ g0;
+        let mut x1 = f1 ^ g1;
+        let mut x2 = f2 ^ g2;
+        let mut x3 = f3 ^ g3;
+        let mut x4 = f4 ^ g4;
+        let mut x5 = f5 ^ g5;
+        let mut x6 = f6 ^ g6;
+        let mut x7 = f7 ^ g7;
+        let mut x8 = f8 ^ g8;
+        let mut x9 = f9 ^ g9;
+        let b = -do_swap;
+        x0 &= b;
+        x1 &= b;
+        x2 &= b;
+        x3 &= b;
+        x4 &= b;
+        x5 &= b;
+        x6 &= b;
+        x7 &= b;
+        x8 &= b;
+        x9 &= b;
+        *self  = Fe([f0^x0, f1^x1, f2^x2, f3^x3, f4^x4,
+                     f5^x5, f6^x6, f7^x7, f8^x8, f9^x9]);
+    }
+
+    /*
+    h = f * 121666
+    Can overlap h with f.
+
+    Preconditions:
+       |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+    Postconditions:
+       |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+    */
+
+    fn mul_121666(&self) -> Fe {
+        let &Fe(f) = self;
+
+        let mut h0 = (f[0] as i64) * 121666;
+        let mut h1 = (f[1] as i64) * 121666;
+        let mut h2 = (f[2] as i64) * 121666;
+        let mut h3 = (f[3] as i64) * 121666;
+        let mut h4 = (f[4] as i64) * 121666;
+        let mut h5 = (f[5] as i64) * 121666;
+        let mut h6 = (f[6] as i64) * 121666;
+        let mut h7 = (f[7] as i64) * 121666;
+        let mut h8 = (f[8] as i64) * 121666;
+        let mut h9 = (f[9] as i64) * 121666;
+
+        let carry9 = (h9 + (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+        let carry1 = (h1 + (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+        let carry3 = (h3 + (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+        let carry5 = (h5 + (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+        let carry7 = (h7 + (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+        let carry0 = (h0 + (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+        let carry2 = (h2 + (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+        let carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+        let carry6 = (h6 + (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+        let carry8 = (h8 + (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+        Fe([h0 as i32, h1 as i32, h2 as i32, h3 as i32, h4 as i32,
+            h5 as i32, h6 as i32, h7 as i32, h8 as i32, h9 as i32])
+    }
+
+
+    /*
+    h = f * f
+    Can overlap h with f.
+
+    Preconditions:
+       |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+    Postconditions:
+       |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+    */
+
+    /*
+    See fe_mul.c for discussion of implementation strategy.
+    */
+    fn square(&self) -> Fe {
+        let &Fe(f) = self;
+
+        let f0 = f[0];
+        let f1 = f[1];
+        let f2 = f[2];
+        let f3 = f[3];
+        let f4 = f[4];
+        let f5 = f[5];
+        let f6 = f[6];
+        let f7 = f[7];
+        let f8 = f[8];
+        let f9 = f[9];
+        let f0_2 = 2 * f0;
+        let f1_2 = 2 * f1;
+        let f2_2 = 2 * f2;
+        let f3_2 = 2 * f3;
+        let f4_2 = 2 * f4;
+        let f5_2 = 2 * f5;
+        let f6_2 = 2 * f6;
+        let f7_2 = 2 * f7;
+        let f5_38 = 38 * f5; /* 1.31*2^30 */
+        let f6_19 = 19 * f6; /* 1.31*2^30 */
+        let f7_38 = 38 * f7; /* 1.31*2^30 */
+        let f8_19 = 19 * f8; /* 1.31*2^30 */
+        let f9_38 = 38 * f9; /* 1.31*2^30 */
+        let f0f0    = (f0   as i64) * (f0 as i64);
+        let f0f1_2  = (f0_2 as i64) * (f1 as i64);
+        let f0f2_2  = (f0_2 as i64) * (f2 as i64);
+        let f0f3_2  = (f0_2 as i64) * (f3 as i64);
+        let f0f4_2  = (f0_2 as i64) * (f4 as i64);
+        let f0f5_2  = (f0_2 as i64) * (f5 as i64);
+        let f0f6_2  = (f0_2 as i64) * (f6 as i64);
+        let f0f7_2  = (f0_2 as i64) * (f7 as i64);
+        let f0f8_2  = (f0_2 as i64) * (f8 as i64);
+        let f0f9_2  = (f0_2 as i64) * (f9 as i64);
+        let f1f1_2  = (f1_2 as i64) * (f1 as i64);
+        let f1f2_2  = (f1_2 as i64) * (f2 as i64);
+        let f1f3_4  = (f1_2 as i64) * (f3_2 as i64);
+        let f1f4_2  = (f1_2 as i64) * (f4 as i64);
+        let f1f5_4  = (f1_2 as i64) * (f5_2 as i64);
+        let f1f6_2  = (f1_2 as i64) * (f6 as i64);
+        let f1f7_4  = (f1_2 as i64) * (f7_2 as i64);
+        let f1f8_2  = (f1_2 as i64) * (f8 as i64);
+        let f1f9_76 = (f1_2 as i64) * (f9_38 as i64);
+        let f2f2    = (f2   as i64) * (f2 as i64);
+        let f2f3_2  = (f2_2 as i64) * (f3 as i64);
+        let f2f4_2  = (f2_2 as i64) * (f4 as i64);
+        let f2f5_2  = (f2_2 as i64) * (f5 as i64);
+        let f2f6_2  = (f2_2 as i64) * (f6 as i64);
+        let f2f7_2  = (f2_2 as i64) * (f7 as i64);
+        let f2f8_38 = (f2_2 as i64) * (f8_19 as i64);
+        let f2f9_38 = (f2   as i64) * (f9_38 as i64);
+        let f3f3_2  = (f3_2 as i64) * (f3 as i64);
+        let f3f4_2  = (f3_2 as i64) * (f4 as i64);
+        let f3f5_4  = (f3_2 as i64) * (f5_2 as i64);
+        let f3f6_2  = (f3_2 as i64) * (f6 as i64);
+        let f3f7_76 = (f3_2 as i64) * (f7_38 as i64);
+        let f3f8_38 = (f3_2 as i64) * (f8_19 as i64);
+        let f3f9_76 = (f3_2 as i64) * (f9_38 as i64);
+        let f4f4    = (f4   as i64) * (f4 as i64);
+        let f4f5_2  = (f4_2 as i64) * (f5 as i64);
+        let f4f6_38 = (f4_2 as i64) * (f6_19 as i64);
+        let f4f7_38 = (f4   as i64) * (f7_38 as i64);
+        let f4f8_38 = (f4_2 as i64) * (f8_19 as i64);
+        let f4f9_38 = (f4   as i64) * (f9_38 as i64);
+        let f5f5_38 = (f5   as i64) * (f5_38 as i64);
+        let f5f6_38 = (f5_2 as i64) * (f6_19 as i64);
+        let f5f7_76 = (f5_2 as i64) * (f7_38 as i64);
+        let f5f8_38 = (f5_2 as i64) * (f8_19 as i64);
+        let f5f9_76 = (f5_2 as i64) * (f9_38 as i64);
+        let f6f6_19 = (f6   as i64) * (f6_19 as i64);
+        let f6f7_38 = (f6   as i64) * (f7_38 as i64);
+        let f6f8_38 = (f6_2 as i64) * (f8_19 as i64);
+        let f6f9_38 = (f6   as i64) * (f9_38 as i64);
+        let f7f7_38 = (f7   as i64) * (f7_38 as i64);
+        let f7f8_38 = (f7_2 as i64) * (f8_19 as i64);
+        let f7f9_76 = (f7_2 as i64) * (f9_38 as i64);
+        let f8f8_19 = (f8   as i64) * (f8_19 as i64);
+        let f8f9_38 = (f8   as i64) * (f9_38 as i64);
+        let f9f9_38 = (f9   as i64) * (f9_38 as i64);
+        let mut h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+        let mut h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+        let mut h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+        let mut h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+        let mut h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+        let mut h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+        let mut h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+        let mut h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+        let mut h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+        let mut h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+
+        let carry0 = (h0 + (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+        let carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+        let carry1 = (h1 + (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+        let carry5 = (h5 + (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+        let carry2 = (h2 + (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+        let carry6 = (h6 + (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+        let carry3 = (h3 + (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+        let carry7 = (h7 + (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+        let carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+        let carry8 = (h8 + (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+        let carry9 = (h9 + (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+        let carrya = (h0 + (1<<25)) >> 26; h1 += carrya; h0 -= carrya << 26;
+
+        Fe([h0 as i32, h1 as i32, h2 as i32, h3 as i32, h4 as i32,
+            h5 as i32, h6 as i32, h7 as i32, h8 as i32, h9 as i32])
+    }
+
+    fn square_and_double(&self) -> Fe {
+        let &Fe(f) = self;
+
+        let f0 = f[0];
+        let f1 = f[1];
+        let f2 = f[2];
+        let f3 = f[3];
+        let f4 = f[4];
+        let f5 = f[5];
+        let f6 = f[6];
+        let f7 = f[7];
+        let f8 = f[8];
+        let f9 = f[9];
+        let f0_2 = 2 * f0;
+        let f1_2 = 2 * f1;
+        let f2_2 = 2 * f2;
+        let f3_2 = 2 * f3;
+        let f4_2 = 2 * f4;
+        let f5_2 = 2 * f5;
+        let f6_2 = 2 * f6;
+        let f7_2 = 2 * f7;
+        let f5_38 = 38 * f5; /* 1.959375*2^30 */
+        let f6_19 = 19 * f6; /* 1.959375*2^30 */
+        let f7_38 = 38 * f7; /* 1.959375*2^30 */
+        let f8_19 = 19 * f8; /* 1.959375*2^30 */
+        let f9_38 = 38 * f9; /* 1.959375*2^30 */
+        let f0f0    = (f0    as i64) * (f0 as i64);
+        let f0f1_2  = (f0_2  as i64) * (f1 as i64);
+        let f0f2_2  = (f0_2  as i64) * (f2 as i64);
+        let f0f3_2  = (f0_2  as i64) * (f3 as i64);
+        let f0f4_2  = (f0_2  as i64) * (f4 as i64);
+        let f0f5_2  = (f0_2  as i64) * (f5 as i64);
+        let f0f6_2  = (f0_2  as i64) * (f6 as i64);
+        let f0f7_2  = (f0_2  as i64) * (f7 as i64);
+        let f0f8_2  = (f0_2  as i64) * (f8 as i64);
+        let f0f9_2  = (f0_2  as i64) * (f9 as i64);
+        let f1f1_2  = (f1_2  as i64) * (f1 as i64);
+        let f1f2_2  = (f1_2  as i64) * (f2 as i64);
+        let f1f3_4  = (f1_2  as i64) * (f3_2 as i64);
+        let f1f4_2  = (f1_2  as i64) * (f4 as i64);
+        let f1f5_4  = (f1_2  as i64) * (f5_2 as i64);
+        let f1f6_2  = (f1_2  as i64) * (f6 as i64);
+        let f1f7_4  = (f1_2  as i64) * (f7_2 as i64);
+        let f1f8_2  = (f1_2  as i64) * (f8 as i64);
+        let f1f9_76 = (f1_2  as i64) * (f9_38 as i64);
+        let f2f2    = (f2    as i64) * (f2 as i64);
+        let f2f3_2  = (f2_2  as i64) * (f3 as i64);
+        let f2f4_2  = (f2_2  as i64) * (f4 as i64);
+        let f2f5_2  = (f2_2  as i64) * (f5 as i64);
+        let f2f6_2  = (f2_2  as i64) * (f6 as i64);
+        let f2f7_2  = (f2_2  as i64) * (f7 as i64);
+        let f2f8_38 = (f2_2  as i64) * (f8_19 as i64);
+        let f2f9_38 = (f2    as i64) * (f9_38 as i64);
+        let f3f3_2  = (f3_2  as i64) * (f3 as i64);
+        let f3f4_2  = (f3_2  as i64) * (f4 as i64);
+        let f3f5_4  = (f3_2  as i64) * (f5_2 as i64);
+        let f3f6_2  = (f3_2  as i64) * (f6 as i64);
+        let f3f7_76 = (f3_2  as i64) * (f7_38 as i64);
+        let f3f8_38 = (f3_2  as i64) * (f8_19 as i64);
+        let f3f9_76 = (f3_2  as i64) * (f9_38 as i64);
+        let f4f4    = (f4    as i64) * (f4 as i64);
+        let f4f5_2  = (f4_2  as i64) * (f5 as i64);
+        let f4f6_38 = (f4_2  as i64) * (f6_19 as i64);
+        let f4f7_38 = (f4    as i64) * (f7_38 as i64);
+        let f4f8_38 = (f4_2  as i64) * (f8_19 as i64);
+        let f4f9_38 = (f4    as i64) * (f9_38 as i64);
+        let f5f5_38 = (f5    as i64) * (f5_38 as i64);
+        let f5f6_38 = (f5_2  as i64) * (f6_19 as i64);
+        let f5f7_76 = (f5_2  as i64) * (f7_38 as i64);
+        let f5f8_38 = (f5_2  as i64) * (f8_19 as i64);
+        let f5f9_76 = (f5_2  as i64) * (f9_38 as i64);
+        let f6f6_19 = (f6    as i64) * (f6_19 as i64);
+        let f6f7_38 = (f6    as i64) * (f7_38 as i64);
+        let f6f8_38 = (f6_2  as i64) * (f8_19 as i64);
+        let f6f9_38 = (f6    as i64) * (f9_38 as i64);
+        let f7f7_38 = (f7    as i64) * (f7_38 as i64);
+        let f7f8_38 = (f7_2  as i64) * (f8_19 as i64);
+        let f7f9_76 = (f7_2  as i64) * (f9_38 as i64);
+        let f8f8_19 = (f8    as i64) * (f8_19 as i64);
+        let f8f9_38 = (f8    as i64) * (f9_38 as i64);
+        let f9f9_38 = (f9    as i64) * (f9_38 as i64);
+        let mut h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+        let mut h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+        let mut h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+        let mut h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+        let mut h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+        let mut h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+        let mut h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+        let mut h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+        let mut h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+        let mut h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+        let mut carry0: i64;
+        let carry1: i64;
+        let carry2: i64;
+        let carry3: i64;
+        let mut carry4: i64;
+        let carry5: i64;
+        let carry6: i64;
+        let carry7: i64;
+        let carry8: i64;
+        let carry9: i64;
+
+        h0 += h0;
+        h1 += h1;
+        h2 += h2;
+        h3 += h3;
+        h4 += h4;
+        h5 += h5;
+        h6 += h6;
+        h7 += h7;
+        h8 += h8;
+        h9 += h9;
+
+        carry0 = (h0 + (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+        carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+        carry1 = (h1 + (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+        carry5 = (h5 + (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+        carry2 = (h2 + (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+        carry6 = (h6 + (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+        carry3 = (h3 + (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+        carry7 = (h7 + (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+        carry4 = (h4 + (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+        carry8 = (h8 + (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+        carry9 = (h9 + (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+        carry0 = (h0 + (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+        Fe([h0 as i32, h1 as i32, h2 as i32, h3 as i32, h4 as i32,
+            h5 as i32, h6 as i32, h7 as i32, h8 as i32, h9 as i32])
+    }
+
+    pub fn invert(&self) -> Fe {
+        let z1 = *self;
+
+        /* qhasm: z2 = z1^2^1 */
+        let z2 = z1.square();
+        /* qhasm: z8 = z2^2^2 */
+        let z8 = z2.square().square();
+        /* qhasm: z9 = z1*z8 */
+        let z9 = z1*z8;
+
+        /* qhasm: z11 = z2*z9 */
+        let z11 = z2*z9;
+
+        /* qhasm: z22 = z11^2^1 */
+        let z22 = z11.square();
+
+        /* qhasm: z_5_0 = z9*z22 */
+        let z_5_0 = z9*z22;
+
+        /* qhasm: z_10_5 = z_5_0^2^5 */
+        let z_10_5 = (0..5).fold(z_5_0, |z_5_n, _| z_5_n.square());
+
+        /* qhasm: z_10_0 = z_10_5*z_5_0 */
+        let z_10_0 = z_10_5*z_5_0;
+
+        /* qhasm: z_20_10 = z_10_0^2^10 */
+        let z_20_10 = (0..10).fold(z_10_0, |x, _| x.square());
+
+        /* qhasm: z_20_0 = z_20_10*z_10_0 */
+        let z_20_0 = z_20_10*z_10_0;
+
+        /* qhasm: z_40_20 = z_20_0^2^20 */
+        let z_40_20 = (0..20).fold(z_20_0, |x, _| x.square());
+
+        /* qhasm: z_40_0 = z_40_20*z_20_0 */
+        let z_40_0 = z_40_20*z_20_0;
+
+        /* qhasm: z_50_10 = z_40_0^2^10 */
+        let z_50_10 = (0..10).fold(z_40_0, |x, _| x.square());
+
+        /* qhasm: z_50_0 = z_50_10*z_10_0 */
+        let z_50_0 = z_50_10*z_10_0;
+
+        /* qhasm: z_100_50 = z_50_0^2^50 */
+        let z_100_50 = (0..50).fold(z_50_0, |x, _| x.square());
+
+        /* qhasm: z_100_0 = z_100_50*z_50_0 */
+        let z_100_0 = z_100_50*z_50_0;
+
+        /* qhasm: z_200_100 = z_100_0^2^100 */
+        let z_200_100 = (0..100).fold(z_100_0, |x, _| x.square());
+
+        /* qhasm: z_200_0 = z_200_100*z_100_0 */
+        /* asm 1: fe_mul(>z_200_0=fe#3,<z_200_100=fe#4,<z_100_0=fe#3); */
+        /* asm 2: fe_mul(>z_200_0=t2,<z_200_100=t3,<z_100_0=t2); */
+        let z_200_0 = z_200_100*z_100_0;
+
+        /* qhasm: z_250_50 = z_200_0^2^50 */
+        let z_250_50 = (0..50).fold(z_200_0, |x, _| x.square());
+
+        /* qhasm: z_250_0 = z_250_50*z_50_0 */
+        let z_250_0 = z_250_50*z_50_0;
+
+        /* qhasm: z_255_5 = z_250_0^2^5 */
+        let z_255_5 = (0..5).fold(z_250_0, |x, _| x.square());
+
+        /* qhasm: z_255_21 = z_255_5*z11 */
+        /* asm 1: fe_mul(>z_255_21=fe#12,<z_255_5=fe#2,<z11=fe#1); */
+        /* asm 2: fe_mul(>z_255_21=out,<z_255_5=t1,<z11=t0); */
+        let z_255_21 = z_255_5*z11;
+
+        z_255_21
+    }
+
+
+    fn is_nonzero(&self) -> bool {
+        let bs = self.to_bytes();
+        let zero = [0; 32];
+        !fixed_time_eq(bs.as_ref(), zero.as_ref())
+    }
+
+    fn is_negative(&self) -> bool {
+        (self.to_bytes()[0] & 1) != 0
+    }
+
+    fn neg(&self) -> Fe {
+        let &Fe(f) = self;
+        Fe([-f[0], -f[1], -f[2], -f[3], -f[4],
+            -f[5], -f[6], -f[7], -f[8], -f[9]])
+    }
+
+    fn pow25523(&self) -> Fe {
+        let z2 = self.square();
+        let z8 = (0..2).fold(z2, |x, _| x.square());
+        let z9 = *self * z8;
+        let z11 = z2 * z9;
+        let z22 = z11.square();
+        let z_5_0 = z9 * z22;
+        let z_10_5 = (0..5).fold(z_5_0, |x, _| x.square());
+        let z_10_0 = z_10_5 * z_5_0;
+        let z_20_10 = (0..10).fold(z_10_0, |x, _| x.square());
+        let z_20_0 = z_20_10 * z_10_0;
+        let z_40_20 = (0..20).fold(z_20_0, |x, _| x.square());
+        let z_40_0 = z_40_20 * z_20_0;
+        let z_50_10 = (0..10).fold(z_40_0, |x, _| x.square());
+        let z_50_0 = z_50_10 * z_10_0;
+        let z_100_50 = (0..50).fold(z_50_0, |x, _| x.square());
+        let z_100_0 = z_100_50 * z_50_0;
+        let z_200_100 = (0..100).fold(z_100_0, |x, _| x.square());
+        let z_200_0 = z_200_100 * z_100_0;
+        let z_250_50 = (0..50).fold(z_200_0, |x, _| x.square());
+        let z_250_0 = z_250_50 * z_50_0;
+        let z_252_2 = (0..2).fold(z_250_0, |x, _| x.square());
+        let z_252_3 = z_252_2 * *self;
+
+        z_252_3
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct GeP2 {
+    x: Fe,
+    y: Fe,
+    z: Fe,
+}
+
+#[derive(Clone, Copy)]
+pub struct GeP3 {
+    x: Fe,
+    y: Fe,
+    z: Fe,
+    t: Fe,
+}
+
+#[derive(Clone, Copy)]
+pub struct GeP1P1 {
+    x: Fe,
+    y: Fe,
+    z: Fe,
+    t: Fe,
+}
+
+#[derive(Clone, Copy)]
+pub struct GePrecomp {
+    y_plus_x: Fe,
+    y_minus_x: Fe,
+    xy2d: Fe,
+}
+
+#[derive(Clone, Copy)]
+pub struct GeCached {
+    y_plus_x: Fe,
+    y_minus_x: Fe,
+    z: Fe,
+    t2d: Fe,
+}
+
+impl GeP1P1 {
+    fn to_p2(&self) -> GeP2 {
+        GeP2 {
+            x: self.x * self.t,
+            y: self.y * self.z,
+            z: self.z * self.t,
+        }
+    }
+
+
+    fn to_p3(&self) -> GeP3 {
+        GeP3 {
+            x: self.x * self.t,
+            y: self.y * self.z,
+            z: self.z * self.t,
+            t: self.x * self.y,
+        }
+    }
+
+}
+
+impl GeP2 {
+    fn zero() -> GeP2 {
+        GeP2 {
+            x: FE_ZERO,
+            y: FE_ONE,
+            z: FE_ONE,
+        }
+    }
+
+    pub fn to_bytes(&self) -> [u8; 32] {
+        let recip = self.z.invert();
+        let x = self.x * recip;
+        let y = self.y * recip;
+        let mut bs = y.to_bytes();
+        bs[31] ^= (if x.is_negative() { 1 } else { 0 }) << 7;
+        bs
+    }
+
+    fn dbl(&self) -> GeP1P1 {
+        let xx = self.x.square();
+        let yy = self.y.square();
+        let b = self.z.square_and_double();
+        let a = self.x + self.y;
+        let aa = a.square();
+        let y3 = yy + xx;
+        let z3 = yy - xx;
+        let x3 = aa - y3;
+        let t3 = b - z3;
+
+        GeP1P1 { x: x3, y: y3, z: z3, t: t3 }
+    }
+
+    fn slide(a: &[u8]) -> [i8; 256] {
+        let mut r = [0i8; 256];
+        for i in 0..256 {
+            r[i] = (1 & (a[i >> 3] >> (i & 7))) as i8;
+        }
+        for i in 0..256 {
+            if r[i]!=0 {
+                for b in 1..min(7, 256-i) {
+                    if r[i + b] != 0 {
+                        if r[i] + (r[i + b] << b) <= 15 {
+                            r[i] += r[i + b] << b; r[i + b] = 0;
+                        } else if r[i] - (r[i + b] << b) >= -15 {
+                            r[i] -= r[i + b] << b;
+                            for k in i+b..256 {
+                                if r[k]==0 {
+                                    r[k] = 1;
+                                    break;
+                                }
+                                r[k] = 0;
+                            }
+                        } else {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        r
+    }
+
+    /*
+    r = a * A + b * B
+    where a = a[0]+256*a[1]+...+256^31 a[31].
+    and b = b[0]+256*b[1]+...+256^31 b[31].
+    B is the Ed25519 base point (x,4/5) with x positive.
+    */
+    pub fn double_scalarmult_vartime(a_scalar: &[u8], a_point: GeP3, b_scalar: &[u8]) -> GeP2 {
+        let aslide = GeP2::slide(a_scalar);
+        let bslide = GeP2::slide(b_scalar);
+
+        let mut ai = [GeCached{y_plus_x:FE_ZERO, y_minus_x: FE_ZERO, z: FE_ZERO, t2d: FE_ZERO}; 8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+        ai[0] = a_point.to_cached();
+        let a2 = a_point.dbl().to_p3();
+        ai[1] = (a2 + ai[0]).to_p3().to_cached();
+        ai[2] = (a2 + ai[1]).to_p3().to_cached();
+        ai[3] = (a2 + ai[2]).to_p3().to_cached();
+        ai[4] = (a2 + ai[3]).to_p3().to_cached();
+        ai[5] = (a2 + ai[4]).to_p3().to_cached();
+        ai[6] = (a2 + ai[5]).to_p3().to_cached();
+        ai[7] = (a2 + ai[6]).to_p3().to_cached();
+
+        let mut r = GeP2::zero();
+
+        let mut i: usize = 255;
+        loop {
+            if aslide[i]!=0 || bslide[i]!=0 {
+                break;
+            }
+            if i==0 {
+                return r;
+            }
+            i -= 1;
+        }
+
+        loop {
+            let mut t = r.dbl();
+            if aslide[i] > 0 {
+                t = t.to_p3() + ai[(aslide[i]/2) as usize];
+            } else if aslide[i] < 0 {
+                t = t.to_p3() - ai[(-aslide[i]/2) as usize];
+            }
+
+            if bslide[i] > 0 {
+                t = t.to_p3() + BI[(bslide[i]/2) as usize];
+            } else if bslide[i] < 0 {
+                t = t.to_p3() - BI[(-bslide[i]/2) as usize];
+            }
+
+            r = t.to_p2();
+
+            if i==0 {
+                return r;
+            }
+            i -= 1;
+        }
+    }
+
+}
+
+impl GeP3 {
+    pub fn from_bytes_negate_vartime(s: &[u8]) -> Option<GeP3> {
+        let y = Fe::from_bytes(s);
+        let z = FE_ONE;
+        let y_squared = y.square();
+        let u = y_squared - FE_ONE;
+        let v = (y_squared * FE_D) + FE_ONE;
+        let v_raise_3 = v.square() * v;
+        let v_raise_7 = v_raise_3.square() * v;
+        let uv7 = v_raise_7 * u;// Is this commutative? u comes second in the code, but not in the notation...
+
+        let mut x = uv7.pow25523() * v_raise_3 * u;
+
+        let vxx = x.square() * v;
+        let check = vxx - u;
+        if check.is_nonzero() {
+            let check2 = vxx + u;
+            if check2.is_nonzero() {
+                return None;
+            }
+            x = x * FE_SQRTM1;
+        }
+
+        if x.is_negative() == ((s[31]>>7)!=0) {
+            x = x.neg();
+        }
+
+        let t = x * y;
+
+        Some(GeP3{x: x, y: y, z: z, t: t})
+    }
+
+    fn to_p2(&self) -> GeP2 {
+        GeP2 {
+            x: self.x,
+            y: self.y,
+            z: self.z,
+        }
+    }
+
+    fn to_cached(&self) -> GeCached {
+        GeCached {
+            y_plus_x: self.y + self.x,
+            y_minus_x: self.y - self.x,
+            z: self.z,
+            t2d: self.t * FE_D2
+        }
+    }
+
+    fn zero() -> GeP3 {
+        GeP3 {
+            x: FE_ZERO,
+            y: FE_ONE,
+            z: FE_ONE,
+            t: FE_ZERO,
+        }
+    }
+
+    fn dbl(&self) -> GeP1P1 {
+        self.to_p2().dbl()
+    }
+
+    pub fn to_bytes(&self) -> [u8; 32] {
+        let recip = self.z.invert();
+        let x = self.x * recip;
+        let y = self.y * recip;
+        let mut bs = y.to_bytes();
+        bs[31] ^= (if x.is_negative() { 1 } else { 0 }) << 7;
+        bs
+    }
+
+
+}
+
+impl Add<GeCached> for GeP3 {
+    type Output = GeP1P1;
+
+    fn add(self, _rhs: GeCached) -> GeP1P1 {
+        let y1_plus_x1 = self.y + self.x;
+        let y1_minus_x1 = self.y - self.x;
+        let a = y1_plus_x1 * _rhs.y_plus_x;
+        let b = y1_minus_x1 * _rhs.y_minus_x;
+        let c = _rhs.t2d * self.t;
+        let zz = self.z * _rhs.z;
+        let d = zz + zz;
+        let x3 = a - b;
+        let y3 = a + b;
+        let z3 = d + c;
+        let t3 = d - c;
+
+        GeP1P1 { x: x3, y: y3, z: z3, t: t3 }
+    }
+}
+
+impl Add<GePrecomp> for GeP3 {
+    type Output = GeP1P1;
+
+    fn add(self, _rhs: GePrecomp) -> GeP1P1 {
+        let y1_plus_x1 = self.y + self.x;
+        let y1_minus_x1 = self.y - self.x;
+        let a = y1_plus_x1 * _rhs.y_plus_x;
+        let b = y1_minus_x1 * _rhs.y_minus_x;
+        let c = _rhs.xy2d * self.t;
+        let d = self.z + self.z;
+        let x3 = a - b;
+        let y3 = a + b;
+        let z3 = d + c;
+        let t3 = d - c;
+
+        GeP1P1 { x: x3, y: y3, z: z3, t: t3 }
+    }
+}
+
+impl Sub<GeCached> for GeP3 {
+    type Output = GeP1P1;
+
+    fn sub(self, _rhs: GeCached) -> GeP1P1 {
+        let y1_plus_x1 = self.y + self.x;
+        let y1_minus_x1 = self.y - self.x;
+        let a = y1_plus_x1 * _rhs.y_minus_x;
+        let b = y1_minus_x1 * _rhs.y_plus_x;
+        let c = _rhs.t2d * self.t;
+        let zz = self.z * _rhs.z;
+        let d = zz + zz;
+        let x3 = a - b;
+        let y3 = a + b;
+        let z3 = d - c;
+        let t3 = d + c;
+
+        GeP1P1 { x: x3, y: y3, z: z3, t: t3 }
+    }
+}
+
+impl Sub<GePrecomp> for GeP3 {
+    type Output = GeP1P1;
+
+    fn sub(self, _rhs: GePrecomp) -> GeP1P1 {
+        let y1_plus_x1 = self.y + self.x;
+        let y1_minus_x1 = self.y - self.x;
+        let a = y1_plus_x1 * _rhs.y_minus_x;
+        let b = y1_minus_x1 * _rhs.y_plus_x;
+        let c = _rhs.xy2d * self.t;
+        let d = self.z + self.z;
+        let x3 = a - b;
+        let y3 = a + b;
+        let z3 = d - c;
+        let t3 = d + c;
+
+        GeP1P1 { x: x3, y: y3, z: z3, t: t3 }
+    }
+}
+
+fn equal(b: u8, c: u8) -> i32 {
+    let x = b ^ c; /* 0: yes; 1..255: no */
+    let mut y = x as u32; /* 0: yes; 1..255: no */
+    y = y.wrapping_sub(1); /* 4294967295: yes; 0..254: no */
+    y >>= 31; /* 1: yes; 0: no */
+    y as i32
+}
+
+
+
+impl GePrecomp {
+    fn zero() -> GePrecomp {
+        GePrecomp {
+            y_plus_x: FE_ONE,
+            y_minus_x: FE_ONE,
+            xy2d: FE_ZERO,
+        }
+    }
+
+    pub fn maybe_set(&mut self, other: &GePrecomp, do_swap: i32) {
+        self.y_plus_x.maybe_set(&other.y_plus_x, do_swap);
+        self.y_minus_x.maybe_set(&other.y_minus_x, do_swap);
+        self.xy2d.maybe_set(&other.xy2d, do_swap);
+    }
+
+    pub fn select(pos: usize, b: i8) -> GePrecomp {
+       let bnegative = (b as u8) >> 7;
+       let babs: u8 = (b - (((-(bnegative as i8)) & b) << 1)) as u8;
+       let mut t = GePrecomp::zero();
+       t.maybe_set(&GE_PRECOMP_BASE[pos][0], equal(babs, 1));
+       t.maybe_set(&GE_PRECOMP_BASE[pos][1], equal(babs, 2));
+       t.maybe_set(&GE_PRECOMP_BASE[pos][2], equal(babs, 3));
+       t.maybe_set(&GE_PRECOMP_BASE[pos][3], equal(babs, 4));
+       t.maybe_set(&GE_PRECOMP_BASE[pos][4], equal(babs, 5));
+       t.maybe_set(&GE_PRECOMP_BASE[pos][5], equal(babs, 6));
+       t.maybe_set(&GE_PRECOMP_BASE[pos][6], equal(babs, 7));
+       t.maybe_set(&GE_PRECOMP_BASE[pos][7], equal(babs, 8));
+       let minus_t = GePrecomp {
+           y_plus_x: t.y_minus_x,
+           y_minus_x: t.y_plus_x,
+           xy2d: t.xy2d.neg(),
+       };
+       t.maybe_set(&minus_t, bnegative as i32);
+       t
+    }
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+  a[31] <= 127
+*/
+pub fn ge_scalarmult_base(a: &[u8]) -> GeP3 {
+    let mut es: [i8; 64] = [0; 64];
+    let mut r: GeP1P1;
+    let mut s: GeP2;
+    let mut t: GePrecomp;
+
+    for i in 0..32 {
+        es[2 * i + 0] = ((a[i] >> 0) & 15) as i8;
+        es[2 * i + 1] = ((a[i] >> 4) & 15) as i8;
+    }
+    /* each es[i] is between 0 and 15 */
+    /* es[63] is between 0 and 7 */
+
+    let mut carry: i8 = 0;
+    for i in 0..63 {
+        es[i] += carry;
+        carry = es[i] + 8;
+        carry >>= 4;
+        es[i] -= carry << 4;
+    }
+    es[63] += carry;
+    /* each es[i] is between -8 and 8 */
+
+    let mut h = GeP3::zero();
+    for i in (1..64).step_up(2) {
+        t = GePrecomp::select(i/2, es[i]);
+        r = h + t;
+        h = r.to_p3();
+    }
+
+    r = h.dbl(); s = r.to_p2();
+    r = s.dbl(); s = r.to_p2();
+    r = s.dbl(); s = r.to_p2();
+    r = s.dbl(); h = r.to_p3();
+
+    for i in (0..64).step_up(2) {
+        t = GePrecomp::select(i/2, es[i]);
+        r = h + t;
+        h = r.to_p3();
+    }
+
+    h
+}
+/*
+Input:
+    s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+    s[0]+256*s[1]+...+256^31*s[31] = s mod l
+    where l = 2^252 + 27742317777372353535851937790883648493.
+    Overwrites s in place.
+*/
+pub fn sc_reduce(s: &mut [u8]) {
+    let mut s0: i64 = 2097151 & load_3i(s);
+    let mut s1: i64 = 2097151 & (load_4i(&s[2..6]) >> 5);
+    let mut s2: i64 = 2097151 & (load_3i(&s[5..8]) >> 2);
+    let mut s3: i64 = 2097151 & (load_4i(&s[7..11]) >> 7);
+    let mut s4: i64 = 2097151 & (load_4i(&s[10..14]) >> 4);
+    let mut s5: i64 = 2097151 & (load_3i(&s[13..16]) >> 1);
+    let mut s6: i64 = 2097151 & (load_4i(&s[15..19]) >> 6);
+    let mut s7: i64 = 2097151 & (load_3i(&s[18..21]) >> 3);
+    let mut s8: i64 = 2097151 & load_3i(&s[21..24]);
+    let mut s9: i64 = 2097151 & (load_4i(&s[23..27]) >> 5);
+    let mut s10: i64 = 2097151 & (load_3i(&s[26..29]) >> 2);
+    let mut s11: i64 = 2097151 & (load_4i(&s[28..32]) >> 7);
+    let mut s12: i64 = 2097151 & (load_4i(&s[31..35]) >> 4);
+    let mut s13: i64 = 2097151 & (load_3i(&s[34..37]) >> 1);
+    let mut s14: i64 = 2097151 & (load_4i(&s[36..40]) >> 6);
+    let mut s15: i64 = 2097151 & (load_3i(&s[39..42]) >> 3);
+    let mut s16: i64 = 2097151 & load_3i(&s[42..45]);
+    let mut s17: i64 = 2097151 & (load_4i(&s[44..48]) >> 5);
+    let s18: i64 = 2097151 & (load_3i(&s[47..50]) >> 2);
+    let s19: i64 = 2097151 & (load_4i(&s[49..53]) >> 7);
+    let s20: i64 = 2097151 & (load_4i(&s[52..56]) >> 4);
+    let s21: i64 = 2097151 & (load_3i(&s[55..58]) >> 1);
+    let s22: i64 = 2097151 & (load_4i(&s[57..61]) >> 6);
+    let s23: i64 = load_4i(&s[60..64]) >> 3;
+    let mut carry0: i64;
+    let mut carry1: i64;
+    let mut carry2: i64;
+    let mut carry3: i64;
+    let mut carry4: i64;
+    let mut carry5: i64;
+    let mut carry6: i64;
+    let mut carry7: i64;
+    let mut carry8: i64;
+    let mut carry9: i64;
+    let mut carry10: i64;
+    let mut carry11: i64;
+    let carry12: i64;
+    let carry13: i64;
+    let carry14: i64;
+    let carry15: i64;
+    let carry16: i64;
+
+    s11 += s23 * 666643;
+    s12 += s23 * 470296;
+    s13 += s23 * 654183;
+    s14 -= s23 * 997805;
+    s15 += s23 * 136657;
+    s16 -= s23 * 683901;
+
+
+    s10 += s22 * 666643;
+    s11 += s22 * 470296;
+    s12 += s22 * 654183;
+    s13 -= s22 * 997805;
+    s14 += s22 * 136657;
+    s15 -= s22 * 683901;
+
+
+    s9 += s21 * 666643;
+    s10 += s21 * 470296;
+    s11 += s21 * 654183;
+    s12 -= s21 * 997805;
+    s13 += s21 * 136657;
+    s14 -= s21 * 683901;
+
+
+    s8 += s20 * 666643;
+    s9 += s20 * 470296;
+    s10 += s20 * 654183;
+    s11 -= s20 * 997805;
+    s12 += s20 * 136657;
+    s13 -= s20 * 683901;
+
+
+    s7 += s19 * 666643;
+    s8 += s19 * 470296;
+    s9 += s19 * 654183;
+    s10 -= s19 * 997805;
+    s11 += s19 * 136657;
+    s12 -= s19 * 683901;
+
+
+    s6 += s18 * 666643;
+    s7 += s18 * 470296;
+    s8 += s18 * 654183;
+    s9 -= s18 * 997805;
+    s10 += s18 * 136657;
+    s11 -= s18 * 683901;
+
+
+    carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+    carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+    carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+    carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+    carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+    carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+    carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+    s5 += s17 * 666643;
+    s6 += s17 * 470296;
+    s7 += s17 * 654183;
+    s8 -= s17 * 997805;
+    s9 += s17 * 136657;
+    s10 -= s17 * 683901;
+
+
+    s4 += s16 * 666643;
+    s5 += s16 * 470296;
+    s6 += s16 * 654183;
+    s7 -= s16 * 997805;
+    s8 += s16 * 136657;
+    s9 -= s16 * 683901;
+
+
+    s3 += s15 * 666643;
+    s4 += s15 * 470296;
+    s5 += s15 * 654183;
+    s6 -= s15 * 997805;
+    s7 += s15 * 136657;
+    s8 -= s15 * 683901;
+
+
+    s2 += s14 * 666643;
+    s3 += s14 * 470296;
+    s4 += s14 * 654183;
+    s5 -= s14 * 997805;
+    s6 += s14 * 136657;
+    s7 -= s14 * 683901;
+
+
+    s1 += s13 * 666643;
+    s2 += s13 * 470296;
+    s3 += s13 * 654183;
+    s4 -= s13 * 997805;
+    s5 += s13 * 136657;
+    s6 -= s13 * 683901;
+
+
+    s0 += s12 * 666643;
+    s1 += s12 * 470296;
+    s2 += s12 * 654183;
+    s3 -= s12 * 997805;
+    s4 += s12 * 136657;
+    s5 -= s12 * 683901;
+    s12 = 0;
+
+    carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+    carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+    carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+    carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+    carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+    carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+    carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+    carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+    s0 += s12 * 666643;
+    s1 += s12 * 470296;
+    s2 += s12 * 654183;
+    s3 -= s12 * 997805;
+    s4 += s12 * 136657;
+    s5 -= s12 * 683901;
+    s12 = 0;
+
+    carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+    carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+    carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+    carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+    carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+    carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+    carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+    carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+    s0 += s12 * 666643;
+    s1 += s12 * 470296;
+    s2 += s12 * 654183;
+    s3 -= s12 * 997805;
+    s4 += s12 * 136657;
+    s5 -= s12 * 683901;
+
+
+    carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+    carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+    carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+    carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+    carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+    carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+    carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+    s[0] = (s0 >> 0) as u8;
+    s[1] = (s0 >> 8) as u8;
+    s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
+    s[3] = (s1 >> 3) as u8;
+    s[4] = (s1 >> 11) as u8;
+    s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
+    s[6] = (s2 >> 6) as u8;
+    s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
+    s[8] = (s3 >> 1) as u8;
+    s[9] = (s3 >> 9) as u8;
+    s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
+    s[11] = (s4 >> 4) as u8;
+    s[12] = (s4 >> 12) as u8;
+    s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
+    s[14] = (s5 >> 7) as u8;
+    s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
+    s[16] = (s6 >> 2) as u8;
+    s[17] = (s6 >> 10) as u8;
+    s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
+    s[19] = (s7 >> 5) as u8;
+    s[20] = (s7 >> 13) as u8;
+    s[21] = (s8 >> 0) as u8;
+    s[22] = (s8 >> 8) as u8;
+    s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
+    s[24] = (s9 >> 3) as u8;
+    s[25] = (s9 >> 11) as u8;
+    s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
+    s[27] = (s10 >> 6) as u8;
+    s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
+    s[29] = (s11 >> 1) as u8;
+    s[30] = (s11 >> 9) as u8;
+    s[31] = (s11 >> 17) as u8;
+}
+
+
+/*
+Input:
+    a[0]+256*a[1]+...+256^31*a[31] = a
+    b[0]+256*b[1]+...+256^31*b[31] = b
+    c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+    s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+    where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+pub fn sc_muladd(s: &mut[u8], a: &[u8], b: &[u8], c: &[u8]) {
+    let a0 = 2097151 & load_3i(&a[0..3]);
+    let a1 = 2097151 & (load_4i(&a[2..6]) >> 5);
+    let a2 = 2097151 & (load_3i(&a[5..8]) >> 2);
+    let a3 = 2097151 & (load_4i(&a[7..11]) >> 7);
+    let a4 = 2097151 & (load_4i(&a[10..14]) >> 4);
+    let a5 = 2097151 & (load_3i(&a[13..16]) >> 1);
+    let a6 = 2097151 & (load_4i(&a[15..19]) >> 6);
+    let a7 = 2097151 & (load_3i(&a[18..21]) >> 3);
+    let a8 = 2097151 & load_3i(&a[21..24]);
+    let a9 = 2097151 & (load_4i(&a[23..27]) >> 5);
+    let a10 = 2097151 & (load_3i(&a[26..29]) >> 2);
+    let a11 = load_4i(&a[28..32]) >> 7;
+    let b0 = 2097151 & load_3i(&b[0..3]);
+    let b1 = 2097151 & (load_4i(&b[2..6]) >> 5);
+    let b2 = 2097151 & (load_3i(&b[5..8]) >> 2);
+    let b3 = 2097151 & (load_4i(&b[7..11]) >> 7);
+    let b4 = 2097151 & (load_4i(&b[10..14]) >> 4);
+    let b5 = 2097151 & (load_3i(&b[13..16]) >> 1);
+    let b6 = 2097151 & (load_4i(&b[15..19]) >> 6);
+    let b7 = 2097151 & (load_3i(&b[18..21]) >> 3);
+    let b8 = 2097151 & load_3i(&b[21..24]);
+    let b9 = 2097151 & (load_4i(&b[23..27]) >> 5);
+    let b10 = 2097151 & (load_3i(&b[26..29]) >> 2);
+    let b11 = load_4i(&b[28..32]) >> 7;
+    let c0 = 2097151 & load_3i(&c[0..3]);
+    let c1 = 2097151 & (load_4i(&c[2..6]) >> 5);
+    let c2 = 2097151 & (load_3i(&c[5..8]) >> 2);
+    let c3 = 2097151 & (load_4i(&c[7..11]) >> 7);
+    let c4 = 2097151 & (load_4i(&c[10..14]) >> 4);
+    let c5 = 2097151 & (load_3i(&c[13..16]) >> 1);
+    let c6 = 2097151 & (load_4i(&c[15..19]) >> 6);
+    let c7 = 2097151 & (load_3i(&c[18..21]) >> 3);
+    let c8 = 2097151 & load_3i(&c[21..24]);
+    let c9 = 2097151 & (load_4i(&c[23..27]) >> 5);
+    let c10 = 2097151 & (load_3i(&c[26..29]) >> 2);
+    let c11 = load_4i(&c[28..32]) >> 7;
+    let mut s0: i64;
+    let mut s1: i64;
+    let mut s2: i64;
+    let mut s3: i64;
+    let mut s4: i64;
+    let mut s5: i64;
+    let mut s6: i64;
+    let mut s7: i64;
+    let mut s8: i64;
+    let mut s9: i64;
+    let mut s10: i64;
+    let mut s11: i64;
+    let mut s12: i64;
+    let mut s13: i64;
+    let mut s14: i64;
+    let mut s15: i64;
+    let mut s16: i64;
+    let mut s17: i64;
+    let mut s18: i64;
+    let mut s19: i64;
+    let mut s20: i64;
+    let mut s21: i64;
+    let mut s22: i64;
+    let mut s23: i64;
+    let mut carry0: i64;
+    let mut carry1: i64;
+    let mut carry2: i64;
+    let mut carry3: i64;
+    let mut carry4: i64;
+    let mut carry5: i64;
+    let mut carry6: i64;
+    let mut carry7: i64;
+    let mut carry8: i64;
+    let mut carry9: i64;
+    let mut carry10: i64;
+    let mut carry11: i64;
+    let mut carry12: i64;
+    let mut carry13: i64;
+    let mut carry14: i64;
+    let mut carry15: i64;
+    let mut carry16: i64;
+    let carry17: i64;
+    let carry18: i64;
+    let carry19: i64;
+    let carry20: i64;
+    let carry21: i64;
+    let carry22: i64;
+
+    s0 = c0 + a0*b0;
+    s1 = c1 + a0*b1 + a1*b0;
+    s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+    s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+    s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+    s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+    s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+    s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+    s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
+    s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
+    s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
+    s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+    s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
+    s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
+    s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
+    s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+    s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+    s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+    s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+    s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+    s20 = a9*b11 + a10*b10 + a11*b9;
+    s21 = a10*b11 + a11*b10;
+    s22 = a11*b11;
+    s23 = 0;
+
+    carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+    carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+    carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+    carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+    carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+    carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+    carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+    carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+    carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+    carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+    carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+    carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+    carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+    carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+    carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+    carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+    carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+    carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+    carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+    s11 += s23 * 666643;
+    s12 += s23 * 470296;
+    s13 += s23 * 654183;
+    s14 -= s23 * 997805;
+    s15 += s23 * 136657;
+    s16 -= s23 * 683901;
+
+
+    s10 += s22 * 666643;
+    s11 += s22 * 470296;
+    s12 += s22 * 654183;
+    s13 -= s22 * 997805;
+    s14 += s22 * 136657;
+    s15 -= s22 * 683901;
+
+
+    s9 += s21 * 666643;
+    s10 += s21 * 470296;
+    s11 += s21 * 654183;
+    s12 -= s21 * 997805;
+    s13 += s21 * 136657;
+    s14 -= s21 * 683901;
+
+
+    s8 += s20 * 666643;
+    s9 += s20 * 470296;
+    s10 += s20 * 654183;
+    s11 -= s20 * 997805;
+    s12 += s20 * 136657;
+    s13 -= s20 * 683901;
+
+
+    s7 += s19 * 666643;
+    s8 += s19 * 470296;
+    s9 += s19 * 654183;
+    s10 -= s19 * 997805;
+    s11 += s19 * 136657;
+    s12 -= s19 * 683901;
+
+
+    s6 += s18 * 666643;
+    s7 += s18 * 470296;
+    s8 += s18 * 654183;
+    s9 -= s18 * 997805;
+    s10 += s18 * 136657;
+    s11 -= s18 * 683901;
+
+
+    carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+    carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+    carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+    carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+    carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+    carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+    carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+    s5 += s17 * 666643;
+    s6 += s17 * 470296;
+    s7 += s17 * 654183;
+    s8 -= s17 * 997805;
+    s9 += s17 * 136657;
+    s10 -= s17 * 683901;
+
+
+    s4 += s16 * 666643;
+    s5 += s16 * 470296;
+    s6 += s16 * 654183;
+    s7 -= s16 * 997805;
+    s8 += s16 * 136657;
+    s9 -= s16 * 683901;
+
+
+    s3 += s15 * 666643;
+    s4 += s15 * 470296;
+    s5 += s15 * 654183;
+    s6 -= s15 * 997805;
+    s7 += s15 * 136657;
+    s8 -= s15 * 683901;
+
+
+    s2 += s14 * 666643;
+    s3 += s14 * 470296;
+    s4 += s14 * 654183;
+    s5 -= s14 * 997805;
+    s6 += s14 * 136657;
+    s7 -= s14 * 683901;
+
+
+    s1 += s13 * 666643;
+    s2 += s13 * 470296;
+    s3 += s13 * 654183;
+    s4 -= s13 * 997805;
+    s5 += s13 * 136657;
+    s6 -= s13 * 683901;
+
+
+    s0 += s12 * 666643;
+    s1 += s12 * 470296;
+    s2 += s12 * 654183;
+    s3 -= s12 * 997805;
+    s4 += s12 * 136657;
+    s5 -= s12 * 683901;
+    s12 = 0;
+
+    carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+    carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+    carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+    carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+    carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+    carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+    carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+    carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+    s0 += s12 * 666643;
+    s1 += s12 * 470296;
+    s2 += s12 * 654183;
+    s3 -= s12 * 997805;
+    s4 += s12 * 136657;
+    s5 -= s12 * 683901;
+    s12 = 0;
+
+    carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+    carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+    carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+    carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+    carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+    carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+    carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+    carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+    s0 += s12 * 666643;
+    s1 += s12 * 470296;
+    s2 += s12 * 654183;
+    s3 -= s12 * 997805;
+    s4 += s12 * 136657;
+    s5 -= s12 * 683901;
+
+
+    carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+    carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+    carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+    carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+    carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+    carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+    carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+    carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+    carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+    carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+    carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+    s[0] = (s0 >> 0) as u8;
+    s[1] = (s0 >> 8) as u8;
+    s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
+    s[3] = (s1 >> 3) as u8;
+    s[4] = (s1 >> 11) as u8;
+    s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
+    s[6] = (s2 >> 6) as u8;
+    s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
+    s[8] = (s3 >> 1) as u8;
+    s[9] = (s3 >> 9) as u8;
+    s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
+    s[11] = (s4 >> 4) as u8;
+    s[12] = (s4 >> 12) as u8;
+    s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
+    s[14] = (s5 >> 7) as u8;
+    s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
+    s[16] = (s6 >> 2) as u8;
+    s[17] = (s6 >> 10) as u8;
+    s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
+    s[19] = (s7 >> 5) as u8;
+    s[20] = (s7 >> 13) as u8;
+    s[21] = (s8 >> 0) as u8;
+    s[22] = (s8 >> 8) as u8;
+    s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
+    s[24] = (s9 >> 3) as u8;
+    s[25] = (s9 >> 11) as u8;
+    s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
+    s[27] = (s10 >> 6) as u8;
+    s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
+    s[29] = (s11 >> 1) as u8;
+    s[30] = (s11 >> 9) as u8;
+    s[31] = (s11 >> 17) as u8;
+}
+
+
+pub fn curve25519(n: &[u8], p: &[u8]) -> [u8; 32] {
+    let mut e = [0u8; 32];
+    let mut x2;
+    let mut z2;
+    let mut x3;
+    let mut z3;
+    let mut swap: i32;
+    let mut b: i32;
+
+    for (d,s) in e.iter_mut().zip(n.iter()) {
+      *d = *s;
+    }
+    e[0] &= 248;
+    e[31] &= 127;
+    e[31] |= 64;
+    let x1 = Fe::from_bytes(p);
+    x2 = FE_ONE;
+    z2 = FE_ZERO;
+    x3 = x1;
+    z3 = FE_ONE;
+
+    swap = 0;
+    // pos starts at 254 and goes down to 0
+    for pos in (0usize..255).rev() {
+        b = (e[pos / 8] >> (pos & 7)) as i32;
+        b &= 1;
+        swap ^= b;
+        x2.maybe_swap_with(&mut x3, swap);
+        z2.maybe_swap_with(&mut z3, swap);
+        swap = b;
+
+        let d = x3 - z3;
+        let b = x2 - z2;
+        let a = x2 + z2;
+        let c = x3 + z3;
+        let da = d * a;
+        let cb = c * b;
+        let bb = b.square();
+        let aa = a.square();
+        let t0 = da + cb;
+        let t1 = da - cb;
+        let x4 = aa*bb;
+        let e = aa - bb;
+        let t2 = t1.square();
+        let t3 = e.mul_121666();
+        let x5 = t0.square();
+        let t4 = bb + t3;
+        let z5 = x1 * t2;
+        let z4 = e*t4;
+
+        z2 = z4;
+        z3 = z5;
+        x2 = x4;
+        x3 = x5;
+    }
+    x2.maybe_swap_with(&mut x3, swap);
+    z2.maybe_swap_with(&mut z3, swap);
+
+    (z2.invert() * x2).to_bytes()
+}
+
+pub fn curve25519_base(x: &[u8]) -> [u8; 32] {
+    let mut base : [u8; 32] = [0; 32];
+    base[0] = 9;
+    curve25519(x, base.as_ref())
+}
+
+#[cfg(test)]
+mod tests {
+    use curve25519::{Fe, curve25519_base};
+
+    #[test]
+    fn from_to_bytes_preserves() {
+        for i in 0..50 {
+            let mut e: Vec<u8> = (0u32..32).map(|idx| (idx*(1289+i*761)) as u8).collect();
+            e[0] &= 248;
+            e[31] &= 127;
+            e[31] |= 64;
+            let fe = Fe::from_bytes(e.as_ref());
+            let e_preserved = fe.to_bytes();
+            assert!(e == e_preserved.to_vec());
+        }
+    }
+
+    #[test]
+    fn swap_test() {
+        let mut f = Fe([10,20,30,40,50,60,70,80,90,100]);
+        let mut g = Fe([11,21,31,41,51,61,71,81,91,101]);
+        let f_initial = f;
+        let g_initial = g;
+        f.maybe_swap_with(&mut g, 0);
+        assert!(f == f_initial);
+        assert!(g == g_initial);
+
+        f.maybe_swap_with(&mut g, 1);
+        assert!(f == g_initial);
+        assert!(g == f_initial);
+    }
+
+    struct CurveGen {
+        which: u32
+    }
+    impl CurveGen {
+        fn new(seed: u32) -> CurveGen {
+            CurveGen{which: seed}
+        }
+    }
+    impl Iterator for CurveGen {
+        type Item = Fe;
+
+        fn next(&mut self) -> Option<Fe> {
+            let mut e: Vec<u8> = (0..32).map(|idx| (idx*(1289+self.which*761)) as u8).collect();
+            e[0] &= 248;
+            e[31] &= 127;
+            e[31] |= 64;
+            Some(Fe::from_bytes(e.as_ref()))
+        }
+    }
+
+    #[test]
+    fn mul_commutes() {
+       for (x,y) in CurveGen::new(1).zip(CurveGen::new(2)).take(40) {
+          assert!(x*y == y*x);
+       };
+    }
+
+    #[test]
+    fn mul_assoc() {
+       for (x,(y,z)) in CurveGen::new(1).zip(CurveGen::new(2).zip(CurveGen::new(3))).take(40) {
+          assert!((x*y)*z == x*(y*z));
+       };
+    }
+
+    #[test]
+    fn invert_inverts() {
+       for x in CurveGen::new(1).take(40) {
+          assert!(x.invert().invert() == x);
+       };
+    }
+
+    #[test]
+    fn square_by_mul() {
+       for x in CurveGen::new(1).take(40) {
+          assert!(x*x == x.square());
+       };
+    }
+
+    #[test]
+    fn base_example() {
+        let sk : [u8; 32] = [
+            0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1,
+            0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0,
+            0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a ];
+        let pk = curve25519_base(sk.as_ref());
+        let correct : [u8; 32] = [
+             0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
+            ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
+            ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
+            ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a ];
+        assert_eq!(pk.to_vec(), correct.to_vec());
+    }
+}
+
+static BI: [GePrecomp; 8] = [
+    GePrecomp {
+        y_plus_x: Fe([ 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 ]),
+        y_minus_x: Fe([ -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 ]),
+        xy2d: Fe([ -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 ]),
+    },
+    GePrecomp {
+        y_plus_x: Fe([ 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 ]),
+        y_minus_x: Fe([ 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 ]),
+        xy2d: Fe([ 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 ]),
+    },
+    GePrecomp {
+        y_plus_x: Fe([ 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 ]),
+        y_minus_x: Fe([ 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 ]),
+        xy2d: Fe([ 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 ]),
+    },
+    GePrecomp {
+        y_plus_x: Fe([ 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 ]),
+        y_minus_x: Fe([ -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 ]),
+        xy2d: Fe([ 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 ]),
+    },
+    GePrecomp {
+        y_plus_x: Fe([ -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 ]),
+        y_minus_x: Fe([ -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 ]),
+        xy2d: Fe([ 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 ]),
+    },
+    GePrecomp {
+        y_plus_x: Fe([ -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 ]),
+        y_minus_x: Fe([ 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 ]),
+        xy2d: Fe([ 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 ]),
+    },
+    GePrecomp {
+        y_plus_x: Fe([ -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 ]),
+        y_minus_x: Fe([ -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 ]),
+        xy2d: Fe([ -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 ]),
+    },
+    GePrecomp {
+        y_plus_x: Fe([ -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 ]),
+        y_minus_x: Fe([ -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 ]),
+        xy2d: Fe([ -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 ]),
+    },
+];
+
+static GE_PRECOMP_BASE : [[GePrecomp; 8]; 32] = [
+[
+ GePrecomp {
+  y_plus_x: Fe([25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605]),
+  y_minus_x: Fe([-12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378]),
+  xy2d: Fe([-8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303]),
+  y_minus_x: Fe([-21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081]),
+  xy2d: Fe([26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024]),
+  y_minus_x: Fe([16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574]),
+  xy2d: Fe([30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540]),
+  y_minus_x: Fe([23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397]),
+  xy2d: Fe([7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380]),
+  y_minus_x: Fe([4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306]),
+  xy2d: Fe([19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777]),
+  y_minus_x: Fe([-8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737]),
+  xy2d: Fe([-18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766]),
+  y_minus_x: Fe([-30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701]),
+  xy2d: Fe([28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726]),
+  y_minus_x: Fe([-7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955]),
+  xy2d: Fe([27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171]),
+  y_minus_x: Fe([27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510]),
+  xy2d: Fe([17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639]),
+  y_minus_x: Fe([29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963]),
+  xy2d: Fe([5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568]),
+  y_minus_x: Fe([12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335]),
+  xy2d: Fe([25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007]),
+  y_minus_x: Fe([-2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772]),
+  xy2d: Fe([-22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567]),
+  y_minus_x: Fe([13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686]),
+  xy2d: Fe([21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887]),
+  y_minus_x: Fe([-23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954]),
+  xy2d: Fe([-29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833]),
+  y_minus_x: Fe([-16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532]),
+  xy2d: Fe([-22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268]),
+  y_minus_x: Fe([33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214]),
+  xy2d: Fe([1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800]),
+  y_minus_x: Fe([4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645]),
+  xy2d: Fe([-4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933]),
+  y_minus_x: Fe([-25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182]),
+  xy2d: Fe([-17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991]),
+  y_minus_x: Fe([20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880]),
+  xy2d: Fe([9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295]),
+  y_minus_x: Fe([19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788]),
+  xy2d: Fe([8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026]),
+  y_minus_x: Fe([11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347]),
+  xy2d: Fe([-18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395]),
+  y_minus_x: Fe([-27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278]),
+  xy2d: Fe([1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995]),
+  y_minus_x: Fe([-30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596]),
+  xy2d: Fe([-11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060]),
+  y_minus_x: Fe([11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608]),
+  xy2d: Fe([-20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389]),
+  y_minus_x: Fe([-19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016]),
+  xy2d: Fe([-11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505]),
+  y_minus_x: Fe([14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553]),
+  xy2d: Fe([-28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220]),
+  y_minus_x: Fe([12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631]),
+  xy2d: Fe([-4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556]),
+  y_minus_x: Fe([14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749]),
+  xy2d: Fe([236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391]),
+  y_minus_x: Fe([5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253]),
+  xy2d: Fe([20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958]),
+  y_minus_x: Fe([-11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082]),
+  xy2d: Fe([-28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521]),
+  y_minus_x: Fe([-11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807]),
+  xy2d: Fe([23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134]),
+  y_minus_x: Fe([-32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455]),
+  xy2d: Fe([27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069]),
+  y_minus_x: Fe([-32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746]),
+  xy2d: Fe([24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837]),
+  y_minus_x: Fe([8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906]),
+  xy2d: Fe([-28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817]),
+  y_minus_x: Fe([10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098]),
+  xy2d: Fe([10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504]),
+  y_minus_x: Fe([-26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727]),
+  xy2d: Fe([28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003]),
+  y_minus_x: Fe([-1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605]),
+  xy2d: Fe([-30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701]),
+  y_minus_x: Fe([-23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683]),
+  xy2d: Fe([29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563]),
+  y_minus_x: Fe([-19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260]),
+  xy2d: Fe([-5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672]),
+  y_minus_x: Fe([23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686]),
+  xy2d: Fe([-24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182]),
+  y_minus_x: Fe([-31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277]),
+  xy2d: Fe([14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474]),
+  y_minus_x: Fe([-26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539]),
+  xy2d: Fe([-25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970]),
+  y_minus_x: Fe([19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756]),
+  xy2d: Fe([-24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683]),
+  y_minus_x: Fe([-10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655]),
+  xy2d: Fe([-20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125]),
+  y_minus_x: Fe([-15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839]),
+  xy2d: Fe([-20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294]),
+  y_minus_x: Fe([-18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899]),
+  xy2d: Fe([-11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294]),
+  y_minus_x: Fe([-15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949]),
+  xy2d: Fe([-21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420]),
+  y_minus_x: Fe([-5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940]),
+  xy2d: Fe([29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567]),
+  y_minus_x: Fe([20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127]),
+  xy2d: Fe([-16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887]),
+  y_minus_x: Fe([22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964]),
+  xy2d: Fe([16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244]),
+  y_minus_x: Fe([24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999]),
+  xy2d: Fe([-1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274]),
+  y_minus_x: Fe([-33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236]),
+  xy2d: Fe([-16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761]),
+  y_minus_x: Fe([-22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884]),
+  xy2d: Fe([-6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638]),
+  y_minus_x: Fe([-11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490]),
+  xy2d: Fe([-32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736]),
+  y_minus_x: Fe([10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124]),
+  xy2d: Fe([-17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029]),
+  y_minus_x: Fe([6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048]),
+  xy2d: Fe([28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593]),
+  y_minus_x: Fe([26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071]),
+  xy2d: Fe([-11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687]),
+  y_minus_x: Fe([-160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441]),
+  xy2d: Fe([-20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460]),
+  y_minus_x: Fe([-19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007]),
+  xy2d: Fe([-21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005]),
+  y_minus_x: Fe([-9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674]),
+  xy2d: Fe([4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590]),
+  y_minus_x: Fe([-2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957]),
+  xy2d: Fe([-30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740]),
+  y_minus_x: Fe([-18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122]),
+  xy2d: Fe([-27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885]),
+  y_minus_x: Fe([26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140]),
+  xy2d: Fe([19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155]),
+  y_minus_x: Fe([19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260]),
+  xy2d: Fe([19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677]),
+  y_minus_x: Fe([32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815]),
+  xy2d: Fe([22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203]),
+  y_minus_x: Fe([-11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208]),
+  xy2d: Fe([1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850]),
+  y_minus_x: Fe([-21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389]),
+  xy2d: Fe([-9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689]),
+  y_minus_x: Fe([14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880]),
+  xy2d: Fe([5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632]),
+  y_minus_x: Fe([-3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412]),
+  xy2d: Fe([20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038]),
+  y_minus_x: Fe([-26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232]),
+  xy2d: Fe([-1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856]),
+  y_minus_x: Fe([23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738]),
+  xy2d: Fe([15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718]),
+  y_minus_x: Fe([-13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697]),
+  xy2d: Fe([-11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912]),
+  y_minus_x: Fe([-26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358]),
+  xy2d: Fe([3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307]),
+  y_minus_x: Fe([-14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977]),
+  xy2d: Fe([-6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644]),
+  y_minus_x: Fe([-22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616]),
+  xy2d: Fe([-27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099]),
+  y_minus_x: Fe([29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341]),
+  xy2d: Fe([-936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646]),
+  y_minus_x: Fe([31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425]),
+  xy2d: Fe([-17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743]),
+  y_minus_x: Fe([-16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822]),
+  xy2d: Fe([-8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985]),
+  y_minus_x: Fe([9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702]),
+  xy2d: Fe([-22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293]),
+  y_minus_x: Fe([27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100]),
+  xy2d: Fe([19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186]),
+  y_minus_x: Fe([2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610]),
+  xy2d: Fe([-2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220]),
+  y_minus_x: Fe([915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025]),
+  xy2d: Fe([32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992]),
+  y_minus_x: Fe([-4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027]),
+  xy2d: Fe([21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901]),
+  y_minus_x: Fe([31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952]),
+  xy2d: Fe([19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390]),
+  y_minus_x: Fe([32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730]),
+  xy2d: Fe([2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180]),
+  y_minus_x: Fe([-30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272]),
+  xy2d: Fe([-15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970]),
+  y_minus_x: Fe([-31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772]),
+  xy2d: Fe([-17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750]),
+  y_minus_x: Fe([20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373]),
+  xy2d: Fe([32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144]),
+  y_minus_x: Fe([-22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195]),
+  xy2d: Fe([5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684]),
+  y_minus_x: Fe([-8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518]),
+  xy2d: Fe([-2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793]),
+  y_minus_x: Fe([-2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794]),
+  xy2d: Fe([580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921]),
+  y_minus_x: Fe([13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518]),
+  xy2d: Fe([2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278]),
+  y_minus_x: Fe([-27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024]),
+  xy2d: Fe([4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783]),
+  y_minus_x: Fe([27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717]),
+  xy2d: Fe([6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333]),
+  y_minus_x: Fe([16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048]),
+  xy2d: Fe([22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760]),
+  y_minus_x: Fe([-15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757]),
+  xy2d: Fe([-2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468]),
+  y_minus_x: Fe([3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184]),
+  xy2d: Fe([10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066]),
+  y_minus_x: Fe([24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882]),
+  xy2d: Fe([13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101]),
+  y_minus_x: Fe([29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279]),
+  xy2d: Fe([-6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709]),
+  y_minus_x: Fe([20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714]),
+  xy2d: Fe([-2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464]),
+  y_minus_x: Fe([12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847]),
+  xy2d: Fe([13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414]),
+  y_minus_x: Fe([-15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158]),
+  xy2d: Fe([17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415]),
+  y_minus_x: Fe([-5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459]),
+  xy2d: Fe([-31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412]),
+  y_minus_x: Fe([-20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743]),
+  xy2d: Fe([-14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022]),
+  y_minus_x: Fe([18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429]),
+  xy2d: Fe([-6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861]),
+  y_minus_x: Fe([10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000]),
+  xy2d: Fe([-33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815]),
+  y_minus_x: Fe([29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642]),
+  xy2d: Fe([10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574]),
+  y_minus_x: Fe([-21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742]),
+  xy2d: Fe([-18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020]),
+  y_minus_x: Fe([-10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772]),
+  xy2d: Fe([3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953]),
+  y_minus_x: Fe([-16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218]),
+  xy2d: Fe([-17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073]),
+  y_minus_x: Fe([-3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325]),
+  xy2d: Fe([-11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870]),
+  y_minus_x: Fe([-7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863]),
+  xy2d: Fe([-13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267]),
+  y_minus_x: Fe([-9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663]),
+  xy2d: Fe([22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673]),
+  y_minus_x: Fe([15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943]),
+  xy2d: Fe([15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238]),
+  y_minus_x: Fe([11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064]),
+  xy2d: Fe([14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052]),
+  y_minus_x: Fe([-10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904]),
+  xy2d: Fe([29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979]),
+  y_minus_x: Fe([-5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841]),
+  xy2d: Fe([10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324]),
+  y_minus_x: Fe([-31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940]),
+  xy2d: Fe([10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184]),
+  y_minus_x: Fe([14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114]),
+  xy2d: Fe([30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784]),
+  y_minus_x: Fe([-2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091]),
+  xy2d: Fe([-16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208]),
+  y_minus_x: Fe([10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864]),
+  xy2d: Fe([17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233]),
+  y_minus_x: Fe([26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212]),
+  xy2d: Fe([-12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068]),
+  y_minus_x: Fe([9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397]),
+  xy2d: Fe([-8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889]),
+  y_minus_x: Fe([32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038]),
+  xy2d: Fe([14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875]),
+  y_minus_x: Fe([-25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905]),
+  xy2d: Fe([-25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818]),
+  y_minus_x: Fe([27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714]),
+  xy2d: Fe([10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931]),
+  y_minus_x: Fe([-30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024]),
+  xy2d: Fe([-23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204]),
+  y_minus_x: Fe([20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817]),
+  xy2d: Fe([27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504]),
+  y_minus_x: Fe([-12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768]),
+  xy2d: Fe([-19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790]),
+  y_minus_x: Fe([1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438]),
+  xy2d: Fe([-22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971]),
+  y_minus_x: Fe([31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905]),
+  xy2d: Fe([29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409]),
+  y_minus_x: Fe([6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499]),
+  xy2d: Fe([-8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664]),
+  y_minus_x: Fe([-11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324]),
+  xy2d: Fe([-21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990]),
+  y_minus_x: Fe([-17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914]),
+  xy2d: Fe([-25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257]),
+  y_minus_x: Fe([-6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433]),
+  xy2d: Fe([-16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045]),
+  y_minus_x: Fe([11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093]),
+  xy2d: Fe([-1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191]),
+  y_minus_x: Fe([-15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507]),
+  xy2d: Fe([-12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018]),
+  y_minus_x: Fe([-16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109]),
+  xy2d: Fe([-23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528]),
+  y_minus_x: Fe([8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625]),
+  xy2d: Fe([-32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033]),
+  y_minus_x: Fe([27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866]),
+  xy2d: Fe([21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075]),
+  y_minus_x: Fe([26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347]),
+  xy2d: Fe([-22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165]),
+  y_minus_x: Fe([-18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588]),
+  xy2d: Fe([-32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017]),
+  y_minus_x: Fe([-28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883]),
+  xy2d: Fe([21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043]),
+  y_minus_x: Fe([29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663]),
+  xy2d: Fe([-20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860]),
+  y_minus_x: Fe([2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466]),
+  xy2d: Fe([-24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997]),
+  y_minus_x: Fe([-1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295]),
+  xy2d: Fe([-13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385]),
+  y_minus_x: Fe([18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109]),
+  xy2d: Fe([2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424]),
+  y_minus_x: Fe([-19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185]),
+  xy2d: Fe([7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325]),
+  y_minus_x: Fe([10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593]),
+  xy2d: Fe([696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644]),
+  y_minus_x: Fe([17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801]),
+  xy2d: Fe([26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884]),
+  y_minus_x: Fe([-586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577]),
+  xy2d: Fe([-9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473]),
+  y_minus_x: Fe([-8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644]),
+  xy2d: Fe([-2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599]),
+  y_minus_x: Fe([-9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768]),
+  xy2d: Fe([-27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328]),
+  y_minus_x: Fe([-15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369]),
+  xy2d: Fe([20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815]),
+  y_minus_x: Fe([-32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025]),
+  xy2d: Fe([-21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448]),
+  y_minus_x: Fe([6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981]),
+  xy2d: Fe([30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501]),
+  y_minus_x: Fe([17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073]),
+  xy2d: Fe([-1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845]),
+  y_minus_x: Fe([-1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211]),
+  xy2d: Fe([18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096]),
+  y_minus_x: Fe([33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803]),
+  xy2d: Fe([-32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965]),
+  y_minus_x: Fe([-14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505]),
+  xy2d: Fe([18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782]),
+  y_minus_x: Fe([5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900]),
+  xy2d: Fe([-31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208]),
+  y_minus_x: Fe([8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232]),
+  xy2d: Fe([17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271]),
+  y_minus_x: Fe([-4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326]),
+  xy2d: Fe([-8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300]),
+  y_minus_x: Fe([8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570]),
+  xy2d: Fe([15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994]),
+  y_minus_x: Fe([-12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913]),
+  xy2d: Fe([31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730]),
+  y_minus_x: Fe([842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096]),
+  xy2d: Fe([-4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411]),
+  y_minus_x: Fe([-19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905]),
+  xy2d: Fe([-9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870]),
+  y_minus_x: Fe([-23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498]),
+  xy2d: Fe([12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677]),
+  y_minus_x: Fe([10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647]),
+  xy2d: Fe([-2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468]),
+  y_minus_x: Fe([21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375]),
+  xy2d: Fe([-25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725]),
+  y_minus_x: Fe([-12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612]),
+  xy2d: Fe([-10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944]),
+  y_minus_x: Fe([30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928]),
+  xy2d: Fe([9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139]),
+  y_minus_x: Fe([-8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963]),
+  xy2d: Fe([-31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734]),
+  y_minus_x: Fe([-448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680]),
+  xy2d: Fe([-24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931]),
+  y_minus_x: Fe([-16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654]),
+  xy2d: Fe([22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180]),
+  y_minus_x: Fe([-26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684]),
+  xy2d: Fe([-10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501]),
+  y_minus_x: Fe([-11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413]),
+  xy2d: Fe([6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874]),
+  y_minus_x: Fe([22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962]),
+  xy2d: Fe([-7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152]),
+  y_minus_x: Fe([9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063]),
+  xy2d: Fe([7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146]),
+  y_minus_x: Fe([-17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183]),
+  xy2d: Fe([-19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421]),
+  y_minus_x: Fe([-3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622]),
+  xy2d: Fe([-4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663]),
+  y_minus_x: Fe([31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753]),
+  xy2d: Fe([4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862]),
+  y_minus_x: Fe([-26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118]),
+  xy2d: Fe([26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380]),
+  y_minus_x: Fe([16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824]),
+  xy2d: Fe([28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438]),
+  y_minus_x: Fe([-31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584]),
+  xy2d: Fe([-594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471]),
+  y_minus_x: Fe([18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610]),
+  xy2d: Fe([19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650]),
+  y_minus_x: Fe([14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369]),
+  xy2d: Fe([19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462]),
+  y_minus_x: Fe([-5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793]),
+  xy2d: Fe([-2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226]),
+  y_minus_x: Fe([18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019]),
+  xy2d: Fe([-15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171]),
+  y_minus_x: Fe([-17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132]),
+  xy2d: Fe([-28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181]),
+  y_minus_x: Fe([-33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210]),
+  xy2d: Fe([-1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935]),
+  y_minus_x: Fe([24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105]),
+  xy2d: Fe([-28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852]),
+  y_minus_x: Fe([5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581]),
+  xy2d: Fe([-4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844]),
+  y_minus_x: Fe([10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025]),
+  xy2d: Fe([27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068]),
+  y_minus_x: Fe([4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192]),
+  xy2d: Fe([-17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259]),
+  y_minus_x: Fe([-12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426]),
+  xy2d: Fe([-5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305]),
+  y_minus_x: Fe([13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832]),
+  xy2d: Fe([28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011]),
+  y_minus_x: Fe([24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447]),
+  xy2d: Fe([17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245]),
+  y_minus_x: Fe([-20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859]),
+  xy2d: Fe([28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707]),
+  y_minus_x: Fe([10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848]),
+  xy2d: Fe([-11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391]),
+  y_minus_x: Fe([15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215]),
+  xy2d: Fe([-23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713]),
+  y_minus_x: Fe([21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849]),
+  xy2d: Fe([-7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940]),
+  y_minus_x: Fe([-21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031]),
+  xy2d: Fe([-17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243]),
+  y_minus_x: Fe([-23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116]),
+  xy2d: Fe([-24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509]),
+  y_minus_x: Fe([-10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883]),
+  xy2d: Fe([15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660]),
+  y_minus_x: Fe([4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273]),
+  xy2d: Fe([-28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560]),
+  y_minus_x: Fe([-10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135]),
+  xy2d: Fe([2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739]),
+  y_minus_x: Fe([18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756]),
+  xy2d: Fe([-30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347]),
+  y_minus_x: Fe([-27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028]),
+  xy2d: Fe([21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799]),
+  y_minus_x: Fe([-2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609]),
+  xy2d: Fe([-25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989]),
+  y_minus_x: Fe([-30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523]),
+  xy2d: Fe([4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045]),
+  y_minus_x: Fe([19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377]),
+  xy2d: Fe([24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016]),
+  y_minus_x: Fe([510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426]),
+  xy2d: Fe([18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396]),
+  y_minus_x: Fe([9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080]),
+  xy2d: Fe([12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275]),
+  y_minus_x: Fe([11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074]),
+  xy2d: Fe([20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717]),
+  y_minus_x: Fe([-1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101]),
+  xy2d: Fe([24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632]),
+  y_minus_x: Fe([-26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415]),
+  xy2d: Fe([-31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876]),
+  y_minus_x: Fe([22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625]),
+  xy2d: Fe([-15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164]),
+  y_minus_x: Fe([26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595]),
+  xy2d: Fe([-7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858]),
+  y_minus_x: Fe([15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193]),
+  xy2d: Fe([8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942]),
+  y_minus_x: Fe([-1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635]),
+  xy2d: Fe([21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935]),
+  y_minus_x: Fe([-25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415]),
+  xy2d: Fe([-15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018]),
+  y_minus_x: Fe([4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778]),
+  xy2d: Fe([366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385]),
+  y_minus_x: Fe([18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503]),
+  xy2d: Fe([476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056]),
+  y_minus_x: Fe([-13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838]),
+  xy2d: Fe([24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691]),
+  y_minus_x: Fe([-15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118]),
+  xy2d: Fe([-23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269]),
+  y_minus_x: Fe([-6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904]),
+  xy2d: Fe([-23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193]),
+  y_minus_x: Fe([-7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910]),
+  xy2d: Fe([-30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667]),
+  y_minus_x: Fe([25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481]),
+  xy2d: Fe([-9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640]),
+  y_minus_x: Fe([-8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278]),
+  xy2d: Fe([-21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272]),
+  y_minus_x: Fe([17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012]),
+  xy2d: Fe([-10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046]),
+  y_minus_x: Fe([13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345]),
+  xy2d: Fe([-19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937]),
+  y_minus_x: Fe([31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636]),
+  xy2d: Fe([-9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429]),
+  y_minus_x: Fe([-15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576]),
+  xy2d: Fe([31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490]),
+  y_minus_x: Fe([-12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104]),
+  xy2d: Fe([33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275]),
+  y_minus_x: Fe([-20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511]),
+  xy2d: Fe([22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439]),
+  y_minus_x: Fe([23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939]),
+  xy2d: Fe([-23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310]),
+  y_minus_x: Fe([3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608]),
+  xy2d: Fe([-32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101]),
+  y_minus_x: Fe([21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418]),
+  xy2d: Fe([18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356]),
+  y_minus_x: Fe([9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996]),
+  xy2d: Fe([-26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([-26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728]),
+  y_minus_x: Fe([-13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658]),
+  xy2d: Fe([-10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001]),
+  y_minus_x: Fe([-4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766]),
+  xy2d: Fe([18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458]),
+  y_minus_x: Fe([-17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628]),
+  xy2d: Fe([-13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062]),
+  y_minus_x: Fe([25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616]),
+  xy2d: Fe([31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383]),
+  y_minus_x: Fe([-25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814]),
+  xy2d: Fe([-20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417]),
+  y_minus_x: Fe([2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222]),
+  xy2d: Fe([33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597]),
+  y_minus_x: Fe([23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970]),
+  xy2d: Fe([1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647]),
+  y_minus_x: Fe([13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511]),
+  xy2d: Fe([-29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032]),
+ },
+],
+[
+ GePrecomp {
+  y_plus_x: Fe([9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834]),
+  y_minus_x: Fe([-23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461]),
+  xy2d: Fe([29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516]),
+  y_minus_x: Fe([-20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547]),
+  xy2d: Fe([-24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038]),
+  y_minus_x: Fe([-33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741]),
+  xy2d: Fe([16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747]),
+  y_minus_x: Fe([-1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323]),
+  xy2d: Fe([31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373]),
+  y_minus_x: Fe([15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228]),
+  xy2d: Fe([-2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399]),
+  y_minus_x: Fe([11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831]),
+  xy2d: Fe([-185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313]),
+  y_minus_x: Fe([-18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958]),
+  xy2d: Fe([-6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577]),
+ },
+ GePrecomp {
+  y_plus_x: Fe([-22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743]),
+  y_minus_x: Fe([29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684]),
+  xy2d: Fe([-20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476]),
+ },
+],
+];
diff --git a/third_party/rust-crypto/src/digest.rs b/third_party/rust-crypto/src/digest.rs
new file mode 100644
index 0000000..c3be0a5
--- /dev/null
+++ b/third_party/rust-crypto/src/digest.rs
@@ -0,0 +1,82 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::prelude::v1::*;
+use std::iter::repeat;
+
+/**
+ * The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
+ * family of digest functions.
+ */
+pub trait Digest {
+    /**
+     * Provide message data.
+     *
+     * # Arguments
+     *
+     * * input - A vector of message data
+     */
+    fn input(&mut self, input: &[u8]);
+
+    /**
+     * Retrieve the digest result. This method may be called multiple times.
+     *
+     * # Arguments
+     *
+     * * out - the vector to hold the result. Must be large enough to contain output_bits().
+     */
+    fn result(&mut self, out: &mut [u8]);
+
+    /**
+     * Reset the digest. This method must be called after result() and before supplying more
+     * data.
+     */
+    fn reset(&mut self);
+
+    /**
+     * Get the output size in bits.
+     */
+    fn output_bits(&self) -> usize;
+
+    /**
+     * Get the output size in bytes.
+     */
+    fn output_bytes(&self) -> usize {
+        (self.output_bits() + 7) / 8
+    }
+
+    /**
+     * Get the block size in bytes.
+     */
+    fn block_size(&self) -> usize;
+
+    /**
+     * Convenience function that feeds a string into a digest.
+     *
+     * # Arguments
+     *
+     * * `input` The string to feed into the digest
+     */
+    fn input_str(&mut self, input: &str) {
+        self.input(input.as_bytes());
+    }
+
+    /**
+     * Convenience function that retrieves the result of a digest as a
+     * String in hexadecimal format.
+     */
+    fn result_str(&mut self) -> String {
+        use serialize::hex::ToHex;
+
+        let mut buf: Vec<u8> = repeat(0).take((self.output_bits()+7)/8).collect();
+        self.result(&mut buf);
+        buf[..].to_hex()
+    }
+}
diff --git a/third_party/rust-crypto/src/ed25519.rs b/third_party/rust-crypto/src/ed25519.rs
new file mode 100644
index 0000000..85a6ee7
--- /dev/null
+++ b/third_party/rust-crypto/src/ed25519.rs
@@ -0,0 +1,277 @@
+use digest::Digest;
+use sha2::{Sha512};
+use curve25519::{GeP2, GeP3, ge_scalarmult_base, sc_reduce, sc_muladd, curve25519, Fe};
+use util::{fixed_time_eq};
+use std::ops::{Add, Sub, Mul};
+
+static L: [u8; 32] =
+      [ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7, 0x9c, 0xd6,
+        0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed ];
+
+pub fn keypair(seed: &[u8]) -> ([u8; 64], [u8; 32]) {
+    let mut secret: [u8; 64] = {
+        let mut hash_output: [u8; 64] = [0; 64];
+        let mut hasher = Sha512::new();
+        hasher.input(seed);
+        hasher.result(&mut hash_output);
+        hash_output[0] &= 248;
+        hash_output[31] &= 63;
+        hash_output[31] |= 64;
+        hash_output
+    };
+
+    let a = ge_scalarmult_base(&secret[0..32]);
+    let public_key = a.to_bytes();
+    for (dest, src) in (&mut secret[32..64]).iter_mut().zip(public_key.iter()) {
+        *dest = *src;
+    }
+    for (dest, src) in (&mut secret[0..32]).iter_mut().zip(seed.iter()) {
+        *dest = *src;
+    }
+    (secret, public_key)
+}
+
+pub fn signature(message: &[u8], secret_key: &[u8]) -> [u8; 64] {
+    let seed = &secret_key[0..32];
+    let public_key = &secret_key[32..64];
+    let az: [u8; 64] = {
+        let mut hash_output: [u8; 64] = [0; 64];
+        let mut hasher = Sha512::new();
+        hasher.input(seed);
+        hasher.result(&mut hash_output);
+        hash_output[0] &= 248;
+        hash_output[31] &= 63;
+        hash_output[31] |= 64;
+        hash_output
+    };
+
+    let nonce = {
+        let mut hash_output: [u8; 64] = [0; 64];
+        let mut hasher = Sha512::new();
+        hasher.input(&az[32..64]);
+        hasher.input(message);
+        hasher.result(&mut hash_output);
+        sc_reduce(&mut hash_output[0..64]);
+        hash_output
+    };
+
+    let mut signature: [u8; 64] = [0; 64];
+    let r: GeP3 = ge_scalarmult_base(&nonce[0..32]);
+    for (result_byte, source_byte) in (&mut signature[0..32]).iter_mut().zip(r.to_bytes().iter()) {
+        *result_byte = *source_byte;
+    }
+    for (result_byte, source_byte) in (&mut signature[32..64]).iter_mut().zip(public_key.iter()) {
+        *result_byte = *source_byte;
+    }
+
+    {
+        let mut hasher = Sha512::new();
+        hasher.input(signature.as_ref());
+        hasher.input(message);
+        let mut hram: [u8; 64] = [0; 64];
+        hasher.result(&mut hram);
+        sc_reduce(&mut hram);
+        sc_muladd(&mut signature[32..64], &hram[0..32], &az[0..32], &nonce[0..32]);
+    }
+
+    signature
+}
+
+fn check_s_lt_l(s: &[u8]) -> bool
+{
+    let mut c: u8 = 0;
+    let mut n: u8 = 1;
+
+    let mut i = 31;
+    loop {
+        c |= ((((s[i] as i32) - (L[i] as i32)) >> 8) as u8) & n;
+        n &= (((((s[i] ^ L[i]) as i32)) - 1) >> 8) as u8;
+        if i == 0 {
+            break;
+        } else {
+            i -= 1;
+        }
+    }
+
+    c == 0
+}
+
+pub fn verify(message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
+    if check_s_lt_l(&signature[32..64]) {
+        return false;
+    }
+
+    let a = match GeP3::from_bytes_negate_vartime(public_key) {
+        Some(g) => g,
+        None => { return false; }
+    };
+    let mut d = 0;
+    for pk_byte in public_key.iter() {
+        d |= *pk_byte;
+    }
+    if d == 0 {
+        return false;
+    }
+
+    let mut hasher = Sha512::new();
+    hasher.input(&signature[0..32]);
+    hasher.input(public_key);
+    hasher.input(message);
+    let mut hash: [u8; 64] = [0; 64];
+    hasher.result(&mut hash);
+    sc_reduce(&mut hash);
+
+    let r = GeP2::double_scalarmult_vartime(hash.as_ref(), a, &signature[32..64]);
+    let rcheck = r.to_bytes();
+
+    fixed_time_eq(rcheck.as_ref(), &signature[0..32])
+}
+
+pub fn exchange(public_key: &[u8], private_key: &[u8]) -> [u8; 32] {
+    let ed_y = Fe::from_bytes(&public_key);
+    // Produce public key in Montgomery form.
+    let mont_x = edwards_to_montgomery_x(ed_y);
+
+    // Produce private key from seed component (bytes 0 to 32)
+    // of the Ed25519 extended private key (64 bytes).
+    let mut hasher = Sha512::new();
+    hasher.input(&private_key[0..32]);
+    let mut hash: [u8; 64] = [0; 64];
+    hasher.result(&mut hash);
+    // Clamp the hash such that it is a valid private key
+    hash[0] &= 248;
+    hash[31] &= 127;
+    hash[31] |= 64;
+
+    let shared_mont_x : [u8; 32] = curve25519(&hash, &mont_x.to_bytes()); // priv., pub.
+
+    shared_mont_x
+}
+
+fn edwards_to_montgomery_x(ed_y: Fe) -> Fe {
+    let ed_z = Fe([1,0,0,0,0,0,0,0,0,0]);
+    let temp_x = ed_z.add(ed_y);
+    let temp_z = ed_z.sub(ed_y);
+    let temp_z_inv = temp_z.invert();
+
+    let mont_x = temp_x.mul(temp_z_inv);
+
+    mont_x
+}
+
+#[cfg(test)]
+mod tests {
+    use ed25519::{keypair, signature, verify, exchange};
+    use curve25519::{curve25519_base, curve25519};
+    use digest::Digest;
+    use sha2::{Sha512};
+
+    fn do_keypair_case(seed: [u8; 32], expected_secret: [u8; 64], expected_public: [u8; 32]) {
+        let (actual_secret, actual_public) = keypair(seed.as_ref());
+        assert_eq!(actual_secret.to_vec(), expected_secret.to_vec());
+        assert_eq!(actual_public.to_vec(), expected_public.to_vec());
+    }
+
+    #[test]
+    fn keypair_cases() {
+        do_keypair_case(
+            [0x26, 0x27, 0xf6, 0x85, 0x97, 0x15, 0xad, 0x1d, 0xd2, 0x94, 0xdd, 0xc4, 0x76, 0x19, 0x39, 0x31,
+             0xf1, 0xad, 0xb5, 0x58, 0xf0, 0x93, 0x97, 0x32, 0x19, 0x2b, 0xd1, 0xc0, 0xfd, 0x16, 0x8e, 0x4e],
+            [0x26, 0x27, 0xf6, 0x85, 0x97, 0x15, 0xad, 0x1d, 0xd2, 0x94, 0xdd, 0xc4, 0x76, 0x19, 0x39, 0x31,
+             0xf1, 0xad, 0xb5, 0x58, 0xf0, 0x93, 0x97, 0x32, 0x19, 0x2b, 0xd1, 0xc0, 0xfd, 0x16, 0x8e, 0x4e,
+             0x5d, 0x6d, 0x23, 0x6b, 0x52, 0xd1, 0x8e, 0x3a, 0xb6, 0xd6, 0x07, 0x2f, 0xb6, 0xe4, 0xc7, 0xd4,
+             0x6b, 0xd5, 0x9a, 0xd9, 0xcc, 0x19, 0x47, 0x26, 0x5f, 0x00, 0xb7, 0x20, 0xfa, 0x2c, 0x8f, 0x66],
+            [0x5d, 0x6d, 0x23, 0x6b, 0x52, 0xd1, 0x8e, 0x3a, 0xb6, 0xd6, 0x07, 0x2f, 0xb6, 0xe4, 0xc7, 0xd4,
+             0x6b, 0xd5, 0x9a, 0xd9, 0xcc, 0x19, 0x47, 0x26, 0x5f, 0x00, 0xb7, 0x20, 0xfa, 0x2c, 0x8f, 0x66]);
+        do_keypair_case(
+            [0x29, 0x23, 0xbe, 0x84, 0xe1, 0x6c, 0xd6, 0xae, 0x52, 0x90, 0x49, 0xf1, 0xf1, 0xbb, 0xe9, 0xeb,
+             0xb3, 0xa6, 0xdb, 0x3c, 0x87, 0x0c, 0x3e, 0x99, 0x24, 0x5e, 0x0d, 0x1c, 0x06, 0xb7, 0x47, 0xde],
+            [0x29, 0x23, 0xbe, 0x84, 0xe1, 0x6c, 0xd6, 0xae, 0x52, 0x90, 0x49, 0xf1, 0xf1, 0xbb, 0xe9, 0xeb,
+             0xb3, 0xa6, 0xdb, 0x3c, 0x87, 0x0c, 0x3e, 0x99, 0x24, 0x5e, 0x0d, 0x1c, 0x06, 0xb7, 0x47, 0xde,
+             0x5d, 0x83, 0x31, 0x26, 0x56, 0x0c, 0xb1, 0x9a, 0x14, 0x19, 0x37, 0x27, 0x78, 0x96, 0xf0, 0xfd,
+             0x43, 0x7b, 0xa6, 0x80, 0x1e, 0xb2, 0x10, 0xac, 0x4c, 0x39, 0xd9, 0x00, 0x72, 0xd7, 0x0d, 0xa8],
+            [0x5d, 0x83, 0x31, 0x26, 0x56, 0x0c, 0xb1, 0x9a, 0x14, 0x19, 0x37, 0x27, 0x78, 0x96, 0xf0, 0xfd,
+             0x43, 0x7b, 0xa6, 0x80, 0x1e, 0xb2, 0x10, 0xac, 0x4c, 0x39, 0xd9, 0x00, 0x72, 0xd7, 0x0d, 0xa8]);
+    }
+
+    #[test]
+    fn keypair_matches_mont() {
+        let seed = [0x26, 0x27, 0xf6, 0x85, 0x97, 0x15, 0xad, 0x1d, 0xd2, 0x94, 0xdd, 0xc4, 0x76, 0x19, 0x39, 0x31,
+                    0xf1, 0xad, 0xb5, 0x58, 0xf0, 0x93, 0x97, 0x32, 0x19, 0x2b, 0xd1, 0xc0, 0xfd, 0x16, 0x8e, 0x4e];
+        let (ed_private, ed_public) = keypair(seed.as_ref());
+
+        let mut hasher = Sha512::new();
+        hasher.input(&ed_private[0..32]);
+        let mut hash: [u8; 64] = [0; 64];
+        hasher.result(&mut hash);
+        hash[0] &= 248;
+        hash[31] &= 127;
+        hash[31] |= 64;
+
+        let cv_public = curve25519_base(&hash);
+
+        let edx_ss = exchange(&ed_public, &ed_private);
+        let cv_ss = curve25519(&hash, &cv_public);
+
+        assert_eq!(edx_ss.to_vec(), cv_ss.to_vec());
+    }
+
+    fn do_sign_verify_case(seed: [u8; 32], message: &[u8], expected_signature: [u8; 64]) {
+        let (secret_key, public_key) = keypair(seed.as_ref());
+        let mut actual_signature = signature(message, secret_key.as_ref());
+        assert_eq!(expected_signature.to_vec(), actual_signature.to_vec());
+        assert!(verify(message, public_key.as_ref(), actual_signature.as_ref()));
+
+        for &(index, flip) in [(0, 1), (31, 0x80), (20, 0xff)].iter() {
+            actual_signature[index] ^= flip;
+            assert!(!verify(message, public_key.as_ref(), actual_signature.as_ref()));
+            actual_signature[index] ^= flip;
+        }
+
+        let mut public_key_corrupt = public_key;
+        public_key_corrupt[0] ^= 1;
+        assert!(!verify(message, public_key_corrupt.as_ref(), actual_signature.as_ref()));
+    }
+
+    #[test]
+    fn sign_verify_cases() {
+        do_sign_verify_case(
+            [0x2d, 0x20, 0x86, 0x83, 0x2c, 0xc2, 0xfe, 0x3f, 0xd1, 0x8c, 0xb5, 0x1d, 0x6c, 0x5e, 0x99, 0xa5,
+             0x75, 0x9f, 0x02, 0x21, 0x1f, 0x85, 0xe5, 0xff, 0x2f, 0x90, 0x4a, 0x78, 0x0f, 0x58, 0x00, 0x6f],
+            [0x89, 0x8f, 0x9c, 0x4b, 0x2c, 0x6e, 0xe9, 0xe2, 0x28, 0x76, 0x1c, 0xa5, 0x08, 0x97, 0xb7, 0x1f,
+             0xfe, 0xca, 0x1c, 0x35, 0x28, 0x46, 0xf5, 0xfe, 0x13, 0xf7, 0xd3, 0xd5, 0x7e, 0x2c, 0x15, 0xac,
+             0x60, 0x90, 0x0c, 0xa3, 0x2c, 0x5b, 0x5d, 0xd9, 0x53, 0xc9, 0xa6, 0x81, 0x0a, 0xcc, 0x64, 0x39,
+             0x4f, 0xfd, 0x14, 0x98, 0x26, 0xd9, 0x98, 0x06, 0x29, 0x2a, 0xdd, 0xd1, 0x3f, 0xc3, 0xbb, 0x7d,
+             0xac, 0x70, 0x1c, 0x5b, 0x4a, 0x2d, 0x61, 0x5d, 0x15, 0x96, 0x01, 0x28, 0xed, 0x9f, 0x73, 0x6b,
+             0x98, 0x85, 0x4f, 0x6f, 0x07, 0x05, 0xb0, 0xf0, 0xda, 0xcb, 0xdc, 0x2c, 0x26, 0x2d, 0x27, 0x39,
+             0x75, 0x19, 0x14, 0x9b, 0x0e, 0x4c, 0xbe, 0x16, 0x77, 0xc5, 0x76, 0xc1, 0x39, 0x7a, 0xae, 0x5c,
+             0xe3, 0x49, 0x16, 0xe3, 0x51, 0x31, 0x04, 0x63, 0x2e, 0xc2, 0x19, 0x0d, 0xb8, 0xd2, 0x22, 0x89,
+             0xc3, 0x72, 0x3c, 0x8d, 0x01, 0x21, 0x3c, 0xad, 0x80, 0x3f, 0x4d, 0x75, 0x74, 0xc4, 0xdb, 0xb5,
+             0x37, 0x31, 0xb0, 0x1c, 0x8e, 0xc7, 0x5d, 0x08, 0x2e, 0xf7, 0xdc, 0x9d, 0x7f, 0x1b, 0x73, 0x15,
+             0x9f, 0x63, 0xdb, 0x56, 0xaa, 0x12, 0xa2, 0xca, 0x39, 0xea, 0xce, 0x6b, 0x28, 0xe4, 0xc3, 0x1d,
+             0x9d, 0x25, 0x67, 0x41, 0x45, 0x2e, 0x83, 0x87, 0xe1, 0x53, 0x6d, 0x03, 0x02, 0x6e, 0xe4, 0x84,
+             0x10, 0xd4, 0x3b, 0x21, 0x91, 0x88, 0xba, 0x14, 0xa8, 0xaf].as_ref(),
+            [0x91, 0x20, 0x91, 0x66, 0x1e, 0xed, 0x18, 0xa4, 0x03, 0x4b, 0xc7, 0xdb, 0x4b, 0xd6, 0x0f, 0xe2,
+             0xde, 0xeb, 0xf3, 0xff, 0x3b, 0x6b, 0x99, 0x8d, 0xae, 0x20, 0x94, 0xb6, 0x09, 0x86, 0x5c, 0x20,
+             0x19, 0xec, 0x67, 0x22, 0xbf, 0xdc, 0x87, 0xbd, 0xa5, 0x40, 0x91, 0x92, 0x2e, 0x11, 0xe3, 0x93,
+             0xf5, 0xfd, 0xce, 0xea, 0x3e, 0x09, 0x1f, 0x2e, 0xe6, 0xbc, 0x62, 0xdf, 0x94, 0x8e, 0x99, 0x09]
+        );
+        do_sign_verify_case(
+            [0x33, 0x19, 0x17, 0x82, 0xc1, 0x70, 0x4f, 0x60, 0xd0, 0x84, 0x8d, 0x75, 0x62, 0xa2, 0xfa, 0x19,
+             0xf9, 0x92, 0x4f, 0xea, 0x4e, 0x77, 0x33, 0xcd, 0x45, 0xf6, 0xc3, 0x2f, 0x21, 0x9a, 0x72, 0x91],
+            [0x77, 0x13, 0x43, 0x5a, 0x0e, 0x34, 0x6f, 0x67, 0x71, 0xae, 0x5a, 0xde, 0xa8, 0x7a, 0xe7, 0xa4,
+             0x52, 0xc6, 0x5d, 0x74, 0x8f, 0x48, 0x69, 0xd3, 0x1e, 0xd3, 0x67, 0x47, 0xc3, 0x28, 0xdd, 0xc4,
+             0xec, 0x0e, 0x48, 0x67, 0x93, 0xa5, 0x1c, 0x67, 0x66, 0xf7, 0x06, 0x48, 0x26, 0xd0, 0x74, 0x51,
+             0x4d, 0xd0, 0x57, 0x41, 0xf3, 0xbe, 0x27, 0x3e, 0xf2, 0x1f, 0x28, 0x0e, 0x49, 0x07, 0xed, 0x89,
+             0xbe, 0x30, 0x1a, 0x4e, 0xc8, 0x49, 0x6e, 0xb6, 0xab, 0x90, 0x00, 0x06, 0xe5, 0xa3, 0xc8, 0xe9,
+             0xc9, 0x93, 0x62, 0x1d, 0x6a, 0x3b, 0x0f, 0x6c, 0xba, 0xd0, 0xfd, 0xde, 0xf3, 0xb9, 0xc8, 0x2d].as_ref(),
+            [0x4b, 0x8d, 0x9b, 0x1e, 0xca, 0x54, 0x00, 0xea, 0xc6, 0xf5, 0xcc, 0x0c, 0x94, 0x39, 0x63, 0x00,
+             0x52, 0xf7, 0x34, 0xce, 0x45, 0x3e, 0x94, 0x26, 0xf3, 0x19, 0xdd, 0x96, 0x03, 0xb6, 0xae, 0xae,
+             0xb9, 0xd2, 0x3a, 0x5f, 0x93, 0xf0, 0x6a, 0x46, 0x00, 0x18, 0xf0, 0x69, 0xdf, 0x19, 0x44, 0x48,
+             0xf5, 0x60, 0x51, 0xab, 0x9e, 0x6b, 0xfa, 0xeb, 0x64, 0x10, 0x16, 0xf7, 0xa9, 0x0b, 0xe2, 0x0c]
+        );
+
+    }
+}
diff --git a/third_party/rust-crypto/src/fortuna.rs b/third_party/rust-crypto/src/fortuna.rs
new file mode 100644
index 0000000..ba3edcb
--- /dev/null
+++ b/third_party/rust-crypto/src/fortuna.rs
@@ -0,0 +1,517 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * An implementation of the Fortuna CSPRNG
+ *
+ * First create a `FortunaRng` object using either the `new_unseeded`
+ * constructor or `SeedableRng::from_seed`. Additional entropy may be
+ * added using the method `add_random_event`, or the underlying RNG
+ * maybe reseeded directly by `SeedableRng::reseed`. Note that this is
+ * not recommended, since the generator automatically reseeds itself
+ * using the data provided by `add_random_events` through an
+ * accumulator. The accumulator is part of Fortuna's design and using
+ * `SeedableRng::reseed` directly bypasses it.
+ *
+ * Note that the underlying block cipher is `AesSafe256Encryptor` which
+ * is designed to be timing-attack resistant. The speed hit from this
+ * is in line with a "safety first" API, but be aware of it.
+ *
+ * Fortuna was originally described in
+ *   Practical Cryptography, Niels Ferguson and Bruce Schneier.
+ *   John Wiley & Sons, 2003.
+ *
+ * Comments throughout this file contain references of the form
+ * (PC 1.2.3); these refer to sections within this text.
+ *
+ * # A note on forking
+ *
+ * Proper behaviour for a CSRNG on a process fork is to reseed itself with
+ * the timestamp and new process ID, to ensure that after forking the child
+ * process does not share the same RNG state (and therefore the same output)
+ * as its parent.
+ *
+ * However, this appears not to be possible in Rust, due to
+ *     https://github.com/rust-lang/rust/issues/16799
+ * The reason is that Rust's process management all happens through its
+ * stdlib runtime, which explicitly does not support forking, so it provides
+ * no mechanism with which to detect forks.
+ *
+ * What this means is that if you are writing forking code (using `#![no_std]`
+ * say) then you need to EXPLICITLY RESEED THE RNG AFTER FORKING.
+ */
+
+use cryptoutil::read_u32_le;
+
+use sgx_rand::{Rng, SeedableRng, thread_rng};
+//use time::precise_time_s;
+
+//use aessafe::AesSafe256Encryptor;
+//use cryptoutil::read_u32_le;
+use digest::Digest;
+use sha2::Sha256;
+//use symmetriccipher::BlockEncryptor;
+
+/// Length in bytes that the first pool must be before a "catastrophic
+/// reseed" is allowed to happen. (A direct reseed through the
+/// `SeedableRng` API is not affected by this limit.)
+pub const MIN_POOL_SIZE: usize = 64;
+// Maximum number of bytes to generate before rekeying
+//const MAX_GEN_SIZE: usize = (1 << 20);
+/// Length in bytes of the AES key
+const KEY_LEN: usize = 32;
+/// Length in bytes of the AES counter
+const CTR_LEN: usize = 16;
+// Length in bytes of the AES block
+//const AES_BLOCK_SIZE: usize = 16;
+/// Number of pools used to accumulate entropy
+const NUM_POOLS: usize = 32;
+
+/// The underlying PRNG (PC 9.4)
+struct FortunaGenerator {
+    key: [u8; KEY_LEN],
+    ctr: [u8; CTR_LEN],
+}
+
+impl FortunaGenerator {
+    /// Creates a new generator (PC 9.4.1)
+    fn new() -> FortunaGenerator {
+        FortunaGenerator {
+            key: [0; KEY_LEN],
+            ctr: [0; CTR_LEN],
+        }
+    }
+
+    /// Increments the counter in place
+    fn increment_counter(&mut self) {
+        for i in 0..self.ctr.len() {
+            self.ctr[i] = self.ctr[i].wrapping_add(1);
+            // As soon as we don't carry, stop
+            if self.ctr[i] != 0 {
+                break;
+            }
+        }
+    }
+
+    /// Reseeds the generator (PC 9.4.2)
+    fn reseed(&mut self, s: &[u8]) {
+        // Compute key as Sha256d( key || s )
+        let mut hasher = Sha256::new();
+        hasher.input(&self.key[..]);
+        hasher.input(s);
+        hasher.result(&mut self.key);
+        hasher = Sha256::new();
+        hasher.input(&self.key[..]);
+        hasher.result(&mut self.key[..]);
+        // Increment the counter
+        self.increment_counter();
+    }
+
+    // Generates some `k` 16-byte blocks of random output (PC 9.4.3)
+    // This should never be used directly, except by `generate_random_data`.
+    //fn generate_blocks(&mut self, k: usize, out: &mut [u8]) {
+    //    assert!(self.ctr[..] != [0; CTR_LEN][..]);
+
+    //    // Setup AES encryptor
+    //    let block_encryptor = AesSafe256Encryptor::new(&self.key[..]);
+    //    // Concatenate all the blocks
+    //    for j in 0..k {
+    //        block_encryptor.encrypt_block(&self.ctr[..],
+    //                                      &mut out[AES_BLOCK_SIZE * j..AES_BLOCK_SIZE * (j + 1)]);
+    //        self.increment_counter();
+    //    }
+    //}
+
+    // Generates `n` bytes of random data (9.4.4)
+    //fn generate_random_data(&mut self, out: &mut [u8]) {
+    //    let (n, rem) = (out.len() / AES_BLOCK_SIZE, out.len() % AES_BLOCK_SIZE);
+    //    assert!(n <= MAX_GEN_SIZE);
+
+    //    // Generate output
+    //    self.generate_blocks(n, &mut out[..(n * AES_BLOCK_SIZE)]);
+    //    if rem > 0 {
+    //        let mut buf = [0; AES_BLOCK_SIZE];
+    //        self.generate_blocks(1, &mut buf);
+    //        copy_memory(&buf[..rem], &mut out[(n * AES_BLOCK_SIZE)..]);
+    //    }
+
+    //    // Rekey
+    //    let mut new_key = [0; KEY_LEN];
+    //    self.generate_blocks(KEY_LEN / AES_BLOCK_SIZE, &mut new_key);
+    //    self.key = new_key;
+    //}
+}
+
+
+/// A single entropy pool (not public)
+#[derive(Clone, Copy)]
+struct Pool {
+    state: Sha256,
+    count: usize
+}
+
+impl Pool {
+    fn new() -> Pool {
+        Pool { state: Sha256::new(), count: 0 }
+    }
+
+    fn input(&mut self, data: &[u8]) {
+        self.state.input(data);
+        self.count += data.len();
+    }
+
+    //fn result(&mut self, output: &mut [u8]) {
+    //    self.state.result(output);
+    //    // Double-SHA256 it
+    //    self.state = Sha256::new();
+    //    self.state.input(output);
+    //    self.state.result(output);
+    //    // Clear the pool state
+    //    self.state = Sha256::new();
+    //    self.count = 0;
+    //}
+}
+
+/// The `Fortuna` CSPRNG (PC 9.5)
+pub struct Fortuna {
+    pool: [Pool; NUM_POOLS],
+    generator: FortunaGenerator,
+    reseed_count: u32,
+    //last_reseed_time: f64
+}
+
+impl Fortuna {
+    /// Creates a new unseeded `Fortuna` (PC 9.5.4)
+    pub fn new_unseeded() -> Fortuna {
+        Fortuna {
+            pool: [Pool::new(); NUM_POOLS],
+            generator: FortunaGenerator::new(),
+            reseed_count: 0,
+            //last_reseed_time: 0.0
+        }
+    }
+
+    /// Adds a random event `e` from source `s` to entropy pool `i` (PC 9.5.6)
+    pub fn add_random_event(&mut self, s: u8, i: usize, e: &[u8]) {
+        assert!(i <= NUM_POOLS);
+        // These restrictions (and `s` in [0, 255]) are part of the Fortuna spec.
+        assert!(e.len() > 0);
+        assert!(e.len() <= 32);
+        (&mut self.pool[i]).input(&[s]);
+        (&mut self.pool[i]).input(&[e.len() as u8]);
+        (&mut self.pool[i]).input(e);
+    }
+}
+
+impl Rng for Fortuna {
+    /// Generate a bunch of random data into `dest` (PC 9.5.5)
+    ///
+    /// # Failure modes
+    ///
+    /// If the RNG has not been seeded, and there is less than
+    /// `MIN_POOL_SIZE` bytes of data in the first accumulator
+    /// pool, this function will fail the task.
+    fn fill_bytes(&mut self, dest: &mut [u8]) {
+        thread_rng().fill_bytes(dest);
+        // Reseed if necessary
+        //let now = precise_time_s();
+        //if self.pool[0].count >= MIN_POOL_SIZE &&
+        //   now - self.last_reseed_time > 0.1 {
+        //    self.reseed_count += 1;
+        //    self.last_reseed_time = now;
+        //    // Compute key as Sha256d( key || s )
+        //    let mut hash = [0; (32 * NUM_POOLS)];
+        //    let mut n_pools = 0;
+        //    while self.reseed_count % (1 << n_pools) == 0 {
+        //        (&mut self.pool[n_pools]).result(&mut hash[n_pools * 32..(n_pools + 1) * 32]);
+        //        n_pools += 1;
+        //        assert!(n_pools < NUM_POOLS);
+        //        assert!(n_pools < 32); // width of counter
+        //    }
+        //    self.generator.reseed(&hash[..n_pools * 32]);
+        //}
+        //// Fail on unseeded RNG
+        //if self.reseed_count == 0 {
+        //    panic!("rust-crypto: an unseeded Fortuna was asked for random bytes!");
+        //}
+        //// Generate return data
+        //for dest in dest.chunks_mut(MAX_GEN_SIZE) {
+        //    self.generator.generate_random_data(dest);
+        //}
+
+    }
+
+    fn next_u32(&mut self) -> u32 {
+        let mut ret = [0; 4];
+        self.fill_bytes(&mut ret);
+        read_u32_le(&ret[..])
+    }
+}
+
+
+impl<'a> SeedableRng<&'a [u8]> for Fortuna {
+    fn from_seed(seed: &'a [u8]) -> Fortuna {
+        let mut ret = Fortuna::new_unseeded();
+        ret.reseed(seed);
+        ret
+    }
+
+    fn reseed(&mut self, seed: &'a [u8]) {
+        self.reseed_count += 1;
+        //self.last_reseed_time = precise_time_s();
+        self.generator.reseed(seed);
+    }
+}
+
+#[cfg(test)]
+fn test_force_reseed(f: &mut Fortuna) {
+    f.last_reseed_time -= 0.2;
+}
+
+#[cfg(test)]
+mod tests {
+    use rand::{SeedableRng, Rng};
+
+    use super::{Fortuna, Pool, NUM_POOLS, test_force_reseed};
+
+    #[test]
+    fn test_create_unseeded() {
+        let _: Fortuna = Fortuna::new_unseeded();
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_use_unseeded() {
+        let mut f: Fortuna = Fortuna::new_unseeded();
+        let _ = f.next_u32();
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_badly_seeded() {
+        let mut f: Fortuna = Fortuna::new_unseeded();
+        f.add_random_event(0, 0, &[10; 32]);
+        let _ = f.next_u32();
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_too_big_event() {
+        let mut f: Fortuna = Fortuna::new_unseeded();
+        f.add_random_event(0, 0, &[10; 33]);
+    }
+
+    #[test]
+    fn test_seeded() {
+        // NB for this test I'm just trusting the output of the RNG to be correct.
+        // I do check for some high-level features: changing most anything should
+        // change the output, there should be no tests, etc.
+        let mut f1: Fortuna = SeedableRng::from_seed(&[0, 1, 2, 3, 4, 5][..]);
+        assert_eq!(f1.next_u32(), 3369034117);
+
+        let mut f2: Fortuna = Fortuna::new_unseeded();
+        f2.reseed(&[0, 1, 2, 3, 4, 5]);
+        assert_eq!(f2.next_u32(), 3369034117);
+
+        // Ensure reseeding doesn't totally reset the seed. That is, this output should
+        // be different from the above
+        let mut f3: Fortuna = Fortuna::new_unseeded();
+        f3.reseed(&[0, 1, 2, 3, 4, 5]);
+        f3.reseed(&[0, 1, 2, 3, 4, 5]);
+        assert_eq!(f3.next_u32(), 2689122182);
+
+        // These three should all be different
+        let mut f4: Fortuna = Fortuna::new_unseeded();
+        f4.add_random_event(0, 0, &[10; 32]);
+        f4.add_random_event(0, 0, &[10; 32]);
+        let x = f4.next_u32();
+
+        let mut f5: Fortuna = Fortuna::new_unseeded();
+        f5.add_random_event(0, 0, &[10; 32]);
+        f5.add_random_event(0, 0, &[20; 32]);
+        let y = f5.next_u32();
+
+        let mut f6: Fortuna = Fortuna::new_unseeded();
+        f6.add_random_event(0, 0, &[20; 32]);
+        f6.add_random_event(0, 0, &[10; 32]);
+        let z = f6.next_u32();
+
+        assert!(x != y);
+        assert!(y != z);
+        assert!(x != z);
+    }
+
+    #[test]
+    fn test_generator_correctness() {
+        let mut output = [0; 100];
+        // Expected output as in http://www.seehuhn.de/pages/fortuna
+        let expected = [ 82, 254, 233, 139, 254,  85,   6, 222, 222, 149,
+                        120,  35, 173,  71,  89, 232,  51, 182, 252, 139,
+                        153, 153, 111,  30,  16,   7, 124, 185, 159,  24,
+                         50,  68, 236, 107, 133,  18, 217, 219,  46, 134,
+                        169, 156, 211,  74, 163,  17, 100, 173,  26,  70,
+                        246, 193,  57, 164, 167, 175, 233, 220, 160, 114,
+                          2, 200, 215,  80, 207, 218,  85,  58, 235, 117,
+                        177, 223,  87, 192,  50, 251,  61,  65, 141, 100,
+                         59, 228,  23, 215,  58, 107, 248, 248, 103,  57,
+                        127,  31, 241,  91, 230,  33,   0, 164,  77, 46];
+        let mut f: Fortuna = SeedableRng::from_seed(&[1, 2, 3, 4][..]);
+        f.fill_bytes(&mut output);
+        assert_eq!(&expected[..], &output[..]);
+
+        let mut scratch = [0; (1 << 20)];
+        f.generator.generate_random_data(&mut scratch);
+
+        let expected = [122, 164,  26,  67, 102,  65,  30, 217, 219, 113,
+                         14,  86, 214, 146, 185,  17, 107, 135, 183,   7,
+                         18, 162, 126, 206,  46,  38,  54, 172, 248, 194,
+                        118,  84, 162, 146,  83, 156, 152,  96, 192,  15,
+                         23, 224, 113,  76,  21,   8, 226,  41, 161, 171,
+                        197, 180, 138, 236, 126, 137, 101,  25, 219, 225,
+                          3, 189,  16, 242,  33,  91,  34,  27,   8, 171,
+                        171, 115, 157, 109, 248, 198, 227,  18, 204, 211,
+                         42, 184,  92,  42, 171, 222, 198, 117, 162, 134,
+                        116, 109,  77, 195, 187, 139,  37,  78, 224,  63];
+        f.fill_bytes(&mut output);
+        assert_eq!(&expected[..], &output[..]);
+
+        f.reseed(&[5]);
+
+        let expected = [217, 168, 141, 167,  46,   9, 218, 188,  98, 124,
+                        109, 128, 242,  22, 189, 120, 180, 124,  15, 192,
+                        116, 149, 211, 136, 253, 132,  60,   3,  29, 250,
+                         95,  66, 133, 195,  37,  78, 242, 255, 160, 209,
+                        185, 106,  68, 105,  83, 145, 165,  72, 179, 167,
+                         53, 254, 183, 251, 128,  69,  78, 156, 219,  26,
+                        124, 202,  35,   9, 174, 167,  41, 128, 184,  25,
+                          2,   1,  63, 142, 205, 162,  69,  68, 207, 251,
+                        101,  10,  29,  33, 133,  87, 189,  36, 229,  56,
+                         17, 100, 138,  49,  79, 239, 210, 189, 141,  46];
+
+        f.fill_bytes(&mut output);
+        assert_eq!(&expected[..], &output[..]);
+    }
+
+    #[test]
+    fn test_accumulator_correctness() {
+        let mut output = [0; 100];
+        // Expected output from experiments with pycryto
+        // Note that this does not match the results for the Go implementation
+        // as described at http://www.seehuhn.de/pages/fortuna ... I believe
+        // this is because the author there is reusing some Fortuna state from
+        // the previous test. These results agree with pycrypto on a fresh slate
+        let mut f = Fortuna::new_unseeded();
+        f.pool = [Pool::new(); NUM_POOLS];
+        f.add_random_event(0, 0, &[0; 32]);
+        f.add_random_event(0, 0, &[0; 32]);
+        for i in 0..32 {
+            f.add_random_event(1, i, &[1, 2]);
+        }
+
+        // from Crypto.Random.Fortuna import FortunaAccumulator
+        // x = FortunaAccumulator.FortunaAccumulator()
+        // x.add_random_event(0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
+        // x.add_random_event(0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
+        // x.add_random_event(1, 0, "\1\2")
+        // x.add_random_event(1, 1, "\1\2")
+        // print list(bytearray(x.random_data(100)))
+        let expected = [ 21,  42, 103, 180, 211,  46, 177, 231, 172, 210,
+                        109, 198,  34,  40, 245, 199,  76, 114, 105, 185,
+                        186, 112, 183, 213,  19,  72, 186,  26, 182, 211,
+                        254,  88,  67, 142, 246, 102,  80,  93, 144, 152,
+                        123, 191, 168,  26,  21, 194,  69, 214, 249,  80,
+                        182, 165, 203,  69, 134, 140,  11, 208,  50, 175,
+                        180, 210, 110, 119,   3,  75,   1,   8,   5, 142,
+                        226, 168, 179, 246,  82,  42, 223, 239, 201,  23,
+                         28,  30, 195, 195,   9, 154,  31, 172, 209, 232,
+                        238, 111,  75, 251, 196,  43, 217, 241,  93, 237];
+        f.fill_bytes(&mut output);
+        assert_eq!(&expected[..], &output[..]);
+
+        // Immediately (less than 100ms)
+        f.add_random_event(0, 0, &[0; 32]);
+        f.add_random_event(0, 0, &[0; 32]);
+
+        // x.add_random_event(0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
+        // x.add_random_event(0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
+        // print list(bytearray(x.random_data(100)))
+        let expected = [101, 123, 175, 157, 142, 202, 211,  47, 149, 214,
+                        135, 249, 148,  19,  50, 116, 169, 188, 240, 218,
+                         91,  62,  35,  44, 142, 108,  95,  20,  37, 185,
+                         19, 121, 128, 231, 213,  23,  94, 147,  14,  41,
+                        199, 253, 246,  14, 230, 152,  11,  17, 118, 254,
+                         96, 251, 171, 115,  66,  21, 196, 164,  82,   6,
+                        139, 238, 135,  22, 179,   6,   6, 252, 115,  87,
+                         19, 167,  56, 192, 140,  93, 132,  78,  22,  16,
+                        114,  68, 123, 200,  37, 183, 163, 224, 201, 155,
+                        233,  71, 111,  26,   8, 114, 232, 181,  13,  51];
+        f.fill_bytes(&mut output);
+        assert_eq!(&expected[..], &output[..]);
+
+        // Simulate more than 100 ms passing
+        test_force_reseed(&mut f);
+        // time.sleep(0.2)
+        // print list(bytearray(x.random_data(100)))
+        let expected = [ 62, 147, 205, 228,  22,   3, 225, 217, 211, 202,
+                         49, 148, 236, 125, 132,  43,  25, 177, 172,  93,
+                         98, 177, 112, 160,  76, 101,  60,  98, 225,   9,
+                        223, 120, 161,  98, 173, 178,  71,  15,  90, 153,
+                         64, 179, 143,  22,  43, 165,  87, 147, 177, 128,
+                         21, 105, 214, 197, 224, 187,  22, 139,  16, 153,
+                        251,  48, 244,  87,  10, 104, 119, 179,  27, 255,
+                         67, 148, 192,  52, 147, 216,  79, 204, 106, 112,
+                        238,   0, 239,  99, 159,  96, 184,  90,  54, 122,
+                        184, 241, 221, 151, 169,  29, 197,  45,  80,   6];
+        f.fill_bytes(&mut output);
+        assert_eq!(&expected[..], &output[..]);
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use rand::{SeedableRng, Rng};
+    use test::Bencher;
+
+    use super::Fortuna;
+
+    #[bench]
+    pub fn fortuna_new_32(bh: &mut Bencher) {
+        let mut f: Fortuna = SeedableRng::from_seed(&[100; 64][..]);
+        bh.iter( || {
+            f.next_u32();
+        });
+        bh.bytes = 4;
+    }
+
+    #[bench]
+    pub fn fortuna_new_64(bh: &mut Bencher) {
+        let mut f: Fortuna = SeedableRng::from_seed(&[100; 64][..]);
+        bh.iter( || {
+            f.next_u64();
+        });
+        bh.bytes = 8;
+    }
+
+    #[bench]
+    pub fn fortuna_new_1k(bh: &mut Bencher) {
+        let mut f: Fortuna = SeedableRng::from_seed(&[100; 64][..]);
+        let mut bytes = [0u8; 1024];
+        bh.iter( || {
+            f.fill_bytes(&mut bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn fortuna_new_64k(bh: &mut Bencher) {
+        let mut f: Fortuna = SeedableRng::from_seed(&[100; 64][..]);
+        let mut bytes = [0u8; 65536];
+        bh.iter( || {
+            f.fill_bytes(&mut bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/ghash.rs b/third_party/rust-crypto/src/ghash.rs
new file mode 100644
index 0000000..d9c6a14
--- /dev/null
+++ b/third_party/rust-crypto/src/ghash.rs
@@ -0,0 +1,577 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// This is an implementaiton of GHASH as used in GCM [1].
+/// It is defined as GHASH(H, A, C), where H is a MAC key, A is authenticated data,
+/// and C is the ciphertext. GHASH can be used as a keyed MAC, if C is left empty.
+///
+/// In order to ensure constant time computation it uses the approach described in [2] section 5.2.
+///
+/// [1] - "The Galois/Counter Mode of Operation (GCM)" - David A. McGrew and John Viega
+///       <http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf>
+/// [2] - "Faster and Timing-Attack Resistant AES-GCM" - Emilia Käsper and Peter Schwabe
+///       <http://cryptojedi.org/papers/aesbs-20090616.pdf>
+
+use std::ops::BitXor;
+use std::mem;
+use cryptoutil::copy_memory;
+
+use cryptoutil::{read_u32_be, write_u32_be};
+use mac::{Mac, MacResult};
+use simd;
+
+// A struct representing an element in GF(2^128)
+// x^0 is the msb, while x^127 is the lsb
+#[derive(Clone, Copy)]
+struct Gf128 { d: simd::u32x4 }
+
+impl Gf128 {
+    fn new(a: u32, b: u32, c: u32, d: u32) -> Gf128 {
+        Gf128 { d: simd::u32x4(a, b, c, d) }
+    }
+
+    fn from_bytes(bytes: &[u8]) -> Gf128 {
+        assert!(bytes.len() == 16);
+        let d = read_u32_be(&bytes[0..4]);
+        let c = read_u32_be(&bytes[4..8]);
+        let b = read_u32_be(&bytes[8..12]);
+        let a = read_u32_be(&bytes[12..16]);
+        Gf128::new(a, b, c, d)
+    }
+
+    fn to_bytes(&self) -> [u8; 16] {
+        let simd::u32x4(a, b, c, d) = self.d;
+        let mut result: [u8; 16] = unsafe { mem::uninitialized() };
+
+        write_u32_be(&mut result[0..4], d);
+        write_u32_be(&mut result[4..8], c);
+        write_u32_be(&mut result[8..12], b);
+        write_u32_be(&mut result[12..16], a);
+
+        result
+    }
+
+    // Multiply the element by x modulo x^128
+    // This is equivalent to a rightshift in the bit representation
+    fn times_x(self) -> Gf128 {
+        let simd::u32x4(a, b, c, d) = self.d;
+        Gf128::new(a >> 1 | b << 31, b >> 1 | c << 31, c >> 1 |  d << 31, d >> 1)
+    }
+
+    // Multiply the element by x modulo x^128 + x^7 + x^2 + x + 1
+    // This is equivalent to a rightshift, followed by an XOR iff the lsb was set,
+    // in the bit representation
+    fn times_x_reduce(self) -> Gf128 {
+        let r = Gf128::new(0, 0, 0, 0b1110_0001 << 24);
+        self.cond_xor(r, self.times_x())
+    }
+
+    // Adds y, and multiplies with h using a precomputed array of the values h * x^0 to h * x^127
+    fn add_and_mul(&mut self, y: Gf128, hs: &[Gf128; 128]) {
+        *self = *self ^ y;
+        let mut x = mem::replace(self, Gf128::new(0, 0, 0, 0));
+
+        for &y in hs.iter().rev() {
+            *self = x.cond_xor(y, *self);
+            x = x.times_x();
+        }
+    }
+
+    // This XORs the value of y with x if the LSB of self is set, otherwise y is returned
+    fn cond_xor(self, x: Gf128, y: Gf128) -> Gf128 {
+        use simd::SimdExt;
+        let lsb = simd::u32x4(1, 0, 0, 0);
+        let simd::u32x4(m, _, _, _) = (self.d & lsb).simd_eq(lsb);
+        let mask = simd::u32x4(m, m, m, m);
+        Gf128 { d: (x.d & mask) ^ y.d }
+    }
+}
+
+impl BitXor for Gf128 {
+    type Output = Gf128;
+
+    fn bitxor(self, rhs: Gf128) -> Gf128 {
+        Gf128 { d: self.d ^ rhs.d }
+    }
+}
+
+/// A structure representing the state of a GHASH computation
+#[derive(Copy)]
+pub struct Ghash {
+    hs: [Gf128; 128],
+    state: Gf128,
+    a_len: usize,
+    rest: Option<[u8; 16]>,
+    finished: bool
+}
+
+impl Clone for Ghash { fn clone(&self) -> Ghash { *self } }
+
+/// A structure representing the state of a GHASH computation, after input for C was provided
+#[derive(Copy)]
+pub struct GhashWithC {
+    hs: [Gf128; 128],
+    state: Gf128,
+    a_len: usize,
+    c_len: usize,
+    rest: Option<[u8; 16]>
+}
+
+impl Clone for GhashWithC { fn clone(&self) -> GhashWithC { *self } }
+
+fn update(state: &mut Gf128, len: &mut usize, data: &[u8], srest: &mut Option<[u8; 16]>,
+          hs: &[Gf128; 128]) {
+    let rest_len = *len % 16;
+    let data_len = data.len();
+    *len += data_len;
+
+    let data = match srest.take() {
+        None => data,
+        Some(mut rest) => {
+            if 16 - rest_len > data_len {
+                copy_memory(data, &mut rest[rest_len..]);
+                *srest = Some(rest);
+                return;
+            }
+
+            let (fill, data) = data.split_at(16 - rest_len);
+            copy_memory(fill, &mut rest[rest_len..]);
+            state.add_and_mul(Gf128::from_bytes(&rest), hs);
+            data
+        }
+    };
+
+    let (data, rest) = data.split_at(data_len - data_len % 16);
+
+    for chunk in data.chunks(16) {
+        let x = Gf128::from_bytes(chunk);
+        state.add_and_mul(x, hs);
+    }
+
+    if rest.len() != 0 {
+        let mut tmp = [0; 16];
+        copy_memory(rest, &mut tmp);
+        *srest = Some(tmp);
+    }
+}
+
+impl Ghash {
+    /// Creates a new GHASH state, with `h` as the key
+    #[inline]
+    pub fn new(h: &[u8]) -> Ghash {
+        assert!(h.len() == 16);
+        let mut table: [Gf128; 128] = unsafe { mem::uninitialized() };
+
+        // Precompute values for h * x^0 to h * x^127
+        let mut h = Gf128::from_bytes(h);
+        for poly in table.iter_mut() {
+            *poly = h;
+            h = h.times_x_reduce();
+        }
+
+        Ghash {
+            hs: table,
+            state: Gf128::new(0, 0, 0, 0),
+            a_len: 0,
+            rest: None,
+            finished: false
+        }
+    }
+
+    fn flush(&mut self) {
+        for rest in self.rest.take().iter() {
+            self.state.add_and_mul(Gf128::from_bytes(rest), &self.hs);
+        }
+    }
+
+    /// Feeds data for GHASH's A input
+    #[inline]
+    pub fn input_a(mut self, a: &[u8]) -> Ghash {
+        assert!(!self.finished);
+        update(&mut self.state, &mut self.a_len, a, &mut self.rest, &self.hs);
+        self
+    }
+
+    /// Feeds data for GHASH's C input
+    #[inline]
+    pub fn input_c(mut self, c: &[u8]) -> GhashWithC {
+        assert!(!self.finished);
+        self.flush();
+
+        let mut c_len = 0;
+        update(&mut self.state, &mut c_len, c, &mut self.rest, &self.hs);
+
+        let Ghash { hs, state, a_len, rest, .. } = self;
+        GhashWithC {
+            hs: hs,
+            state: state,
+            a_len: a_len,
+            c_len: c_len,
+            rest: rest
+        }
+    }
+
+    /// Retrieve the digest result
+    #[inline]
+    pub fn result(mut self) -> [u8; 16] {
+        if !self.finished {
+            self.flush();
+
+            let a_len = self.a_len as u64 * 8;
+            let lens = Gf128::new(0, 0, a_len as u32, (a_len >> 32) as u32);
+            self.state.add_and_mul(lens, &self.hs);
+
+            self.finished = true;
+        }
+
+        self.state.to_bytes()
+    }
+}
+
+impl GhashWithC {
+    /// Feeds data for GHASH's C input
+    #[inline]
+    pub fn input_c(mut self, c: &[u8]) -> GhashWithC {
+        update(&mut self.state, &mut self.c_len, c, &mut self.rest, &self.hs);
+        self
+    }
+
+    /// Retrieve the digest result
+    #[inline]
+    pub fn result(mut self) -> [u8; 16] {
+        for rest in self.rest.take().iter() {
+            self.state.add_and_mul(Gf128::from_bytes(rest), &self.hs);
+        }
+
+        let a_len = self.a_len as u64 * 8;
+        let c_len = self.c_len as u64 * 8;
+        let lens = Gf128::new(c_len as u32, (c_len >> 32) as u32,
+                              a_len as u32, (a_len >> 32) as u32);
+        self.state.add_and_mul(lens, &self.hs);
+
+        self.state.to_bytes()
+    }
+}
+
+impl Mac for Ghash {
+    fn input(&mut self, data: &[u8]) {
+        assert!(!self.finished);
+        update(&mut self.state, &mut self.a_len, data, &mut self.rest, &self.hs);
+    }
+
+    fn reset(&mut self) {
+        self.state = Gf128::new(0, 0, 0, 0);
+        self.a_len = 0;
+        self.rest = None;
+        self.finished = false;
+    }
+
+    fn result(&mut self) -> MacResult {
+        let mut mac = [0u8; 16];
+        self.raw_result(&mut mac[..]);
+        MacResult::new(&mac[..])
+    }
+
+    fn raw_result(&mut self, output: &mut [u8]) {
+        assert!(output.len() >= 16);
+        if !self.finished {
+            self.flush();
+
+            let a_len = self.a_len as u64 * 8;
+            let lens = Gf128::new(0, 0, a_len as u32, (a_len >> 32) as u32);
+            self.state.add_and_mul(lens, &self.hs);
+
+            self.finished = true;
+        }
+
+        copy_memory(&self.state.to_bytes(), output);
+    }
+
+    fn output_bytes(&self) -> usize { 16 }
+}
+
+#[cfg(test)]
+mod test {
+    use ghash::Ghash;
+
+    // Test cases from:
+    // <http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf>
+    static CASES: &'static [(&'static [u8], &'static [u8], &'static [u8], &'static [u8])] = &[
+        // Format: (H, A, C, GHASH(H, A, C))
+
+        // Test 1
+        (&[0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+           0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e],
+         &[],
+         &[],
+         &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
+
+        // Test 2
+        (&[0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
+           0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e],
+         &[],
+         &[0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
+           0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78],
+         &[0xf3, 0x8c, 0xbb, 0x1a, 0xd6, 0x92, 0x23, 0xdc,
+           0xc3, 0x45, 0x7a, 0xe5, 0xb6, 0xb0, 0xf8, 0x85]),
+
+        // Test 3
+        (&[0xb8, 0x3b, 0x53, 0x37, 0x08, 0xbf, 0x53, 0x5d,
+           0x0a, 0xa6, 0xe5, 0x29, 0x80, 0xd5, 0x3b, 0x78],
+         &[],
+         &[0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
+           0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
+           0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
+           0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+           0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85],
+         &[0x7f, 0x1b, 0x32, 0xb8, 0x1b, 0x82, 0x0d, 0x02,
+           0x61, 0x4f, 0x88, 0x95, 0xac, 0x1d, 0x4e, 0xac]),
+
+        // Test 4
+        (&[0xb8, 0x3b, 0x53, 0x37, 0x08, 0xbf, 0x53, 0x5d,
+           0x0a, 0xa6, 0xe5, 0x29, 0x80, 0xd5, 0x3b, 0x78],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0,
+           0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23,
+           0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f,
+           0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+           0x3d, 0x58, 0xe0, 0x91],
+         &[0x69, 0x8e, 0x57, 0xf7, 0x0e, 0x6e, 0xcc, 0x7f,
+           0xd9, 0x46, 0x3b, 0x72, 0x60, 0xa9, 0xae, 0x5f]),
+
+        // Test 5
+        (&[0xb8, 0x3b, 0x53, 0x37, 0x08, 0xbf, 0x53, 0x5d,
+           0x0a, 0xa6, 0xe5, 0x29, 0x80, 0xd5, 0x3b, 0x78],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a,
+           0x47, 0x55, 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, 0x37, 0x66, 0xe5, 0xf9,
+           0x7b, 0x6c, 0x74, 0x23, 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, 0x2b, 0x09,
+           0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
+           0xc2, 0x3f, 0x45, 0x98],
+         &[0xdf, 0x58, 0x6b, 0xb4, 0xc2, 0x49, 0xb9, 0x2c,
+           0xb6, 0x92, 0x28, 0x77, 0xe4, 0x44, 0xd3, 0x7b]),
+
+        // Test 6
+        (&[0xb8, 0x3b, 0x53, 0x37, 0x08, 0xbf, 0x53, 0x5d,
+           0x0a, 0xa6, 0xe5, 0x29, 0x80, 0xd5, 0x3b, 0x78],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f,
+           0xb8, 0x94, 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, 0xba, 0x26, 0x2a, 0x3c,
+           0xca, 0x7e, 0x2c, 0xa7, 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, 0xcc, 0xdc,
+           0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
+           0x4c, 0x34, 0xae, 0xe5],
+         &[0x1c, 0x5a, 0xfe, 0x97, 0x60, 0xd3, 0x93, 0x2f,
+           0x3c, 0x9a, 0x87, 0x8a, 0xac, 0x3d, 0xc3, 0xde]),
+
+        // Test 7
+        (&[0xaa, 0xe0, 0x69, 0x92, 0xac, 0xbf, 0x52, 0xa3,
+           0xe8, 0xf4, 0xa9, 0x6e, 0xc9, 0x30, 0x0b, 0xd7],
+         &[],
+         &[],
+         &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
+
+        // Test 8
+        (&[0xaa, 0xe0, 0x69, 0x92, 0xac, 0xbf, 0x52, 0xa3,
+           0xe8, 0xf4, 0xa9, 0x6e, 0xc9, 0x30, 0x0b, 0xd7],
+         &[],
+         &[0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
+           0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00],
+         &[0xe2, 0xc6, 0x3f, 0x0a, 0xc4, 0x4a, 0xd0, 0xe0,
+           0x2e, 0xfa, 0x05, 0xab, 0x67, 0x43, 0xd4, 0xce]),
+
+        // Test 9
+        (&[0x46, 0x69, 0x23, 0xec, 0x9a, 0xe6, 0x82, 0x21,
+           0x4f, 0x2c, 0x08, 0x2b, 0xad, 0xb3, 0x92, 0x49],
+         &[],
+         &[0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a,
+           0x27, 0x57, 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, 0x62, 0x85, 0x93, 0xb4,
+           0x0c, 0xa1, 0xe1, 0x9c, 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, 0xac, 0x61,
+           0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+           0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56],
+         &[0x51, 0x11, 0x0d, 0x40, 0xf6, 0xc8, 0xff, 0xf0,
+           0xeb, 0x1a, 0xe3, 0x34, 0x45, 0xa8, 0x89, 0xf0]),
+
+        // Test 10
+        (&[0x46, 0x69, 0x23, 0xec, 0x9a, 0xe6, 0x82, 0x21,
+           0x4f, 0x2c, 0x08, 0x2b, 0xad, 0xb3, 0x92, 0x49],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a,
+           0x27, 0x57, 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, 0x62, 0x85, 0x93, 0xb4,
+           0x0c, 0xa1, 0xe1, 0x9c, 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, 0xac, 0x61,
+           0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+           0xcc, 0xda, 0x27, 0x10],
+         &[0xed, 0x2c, 0xe3, 0x06, 0x2e, 0x4a, 0x8e, 0xc0,
+           0x6d, 0xb8, 0xb4, 0xc4, 0x90, 0xe8, 0xa2, 0x68]),
+
+        // Test 11
+        (&[0x46, 0x69, 0x23, 0xec, 0x9a, 0xe6, 0x82, 0x21,
+           0x4f, 0x2c, 0x08, 0x2b, 0xad, 0xb3, 0x92, 0x49],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32,
+           0x4d, 0xb8, 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, 0x83, 0x47, 0x28, 0x0f,
+           0xc4, 0x50, 0x70, 0x57, 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, 0xc6, 0x65,
+           0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f,
+           0xa0, 0xf0, 0x62, 0xf7],
+         &[0x1e, 0x6a, 0x13, 0x38, 0x06, 0x60, 0x78, 0x58,
+           0xee, 0x80, 0xea, 0xf2, 0x37, 0x06, 0x40, 0x89]),
+
+        // Test 12
+        (&[0x46, 0x69, 0x23, 0xec, 0x9a, 0xe6, 0x82, 0x21,
+           0x4f, 0x2c, 0x08, 0x2b, 0xad, 0xb3, 0x92, 0x49],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc,
+           0xf9, 0xff, 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, 0x6e, 0xf7, 0xb7, 0x98,
+           0x28, 0x66, 0x6e, 0x45, 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, 0xe2, 0xf0,
+           0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7,
+           0xe9, 0xb7, 0x37, 0x3b],
+         &[0x82, 0x56, 0x7f, 0xb0, 0xb4, 0xcc, 0x37, 0x18,
+           0x01, 0xea, 0xde, 0xc0, 0x05, 0x96, 0x8e, 0x94]),
+
+        // Test 13
+        (&[0xdc, 0x95, 0xc0, 0x78, 0xa2, 0x40, 0x89, 0x89,
+           0xad, 0x48, 0xa2, 0x14, 0x92, 0x84, 0x20, 0x87],
+         &[],
+         &[],
+         &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
+
+        // Test 14
+        (&[0xdc, 0x95, 0xc0, 0x78, 0xa2, 0x40, 0x89, 0x89,
+           0xad, 0x48, 0xa2, 0x14, 0x92, 0x84, 0x20, 0x87],
+         &[],
+         &[0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
+           0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18],
+         &[0x83, 0xde, 0x42, 0x5c, 0x5e, 0xdc, 0x5d, 0x49,
+           0x8f, 0x38, 0x2c, 0x44, 0x10, 0x41, 0xca, 0x92]),
+
+        // Test 15
+        (&[0xac, 0xbe, 0xf2, 0x05, 0x79, 0xb4, 0xb8, 0xeb,
+           0xce, 0x88, 0x9b, 0xac, 0x87, 0x32, 0xda, 0xd7],
+         &[],
+         &[0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84,
+           0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd,
+           0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0,
+           0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+           0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad],
+         &[0x4d, 0xb8, 0x70, 0xd3, 0x7c, 0xb7, 0x5f, 0xcb,
+           0x46, 0x09, 0x7c, 0x36, 0x23, 0x0d, 0x16, 0x12]),
+
+        // Test 16
+        (&[0xac, 0xbe, 0xf2, 0x05, 0x79, 0xb4, 0xb8, 0xeb,
+           0xce, 0x88, 0x9b, 0xac, 0x87, 0x32, 0xda, 0xd7],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84,
+           0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd,
+           0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0,
+           0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+           0xbc, 0xc9, 0xf6, 0x62],
+         &[0x8b, 0xd0, 0xc4, 0xd8, 0xaa, 0xcd, 0x39, 0x1e,
+           0x67, 0xcc, 0xa4, 0x47, 0xe8, 0xc3, 0x8f, 0x65]),
+
+        // Test 17
+        (&[0xac, 0xbe, 0xf2, 0x05, 0x79, 0xb4, 0xb8, 0xeb,
+           0xce, 0x88, 0x9b, 0xac, 0x87, 0x32, 0xda, 0xd7],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98,
+           0x44, 0xcb, 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, 0xc5, 0x2f, 0xf7, 0xd7,
+           0x9b, 0xba, 0x9d, 0xe0, 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, 0x95, 0x4c,
+           0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99,
+           0xf4, 0x7c, 0x9b, 0x1f],
+         &[0x75, 0xa3, 0x42, 0x88, 0xb8, 0xc6, 0x8f, 0x81,
+           0x1c, 0x52, 0xb2, 0xe9, 0xa2, 0xf9, 0x7f, 0x63]),
+
+        // Test 18
+        (&[0xac, 0xbe, 0xf2, 0x05, 0x79, 0xb4, 0xb8, 0xeb,
+           0xce, 0x88, 0x9b, 0xac, 0x87, 0x32, 0xda, 0xd7],
+         &[0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
+           0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2],
+         &[0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e,
+           0x2a, 0x20, 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, 0xa0, 0x58, 0xab, 0x4f,
+           0x6f, 0x74, 0x6b, 0xf4, 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, 0x2d, 0xa3,
+           0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e,
+           0x44, 0xae, 0x7e, 0x3f],
+         &[0xd5, 0xff, 0xcf, 0x6f, 0xc5, 0xac, 0x4d, 0x69,
+           0x72, 0x21, 0x87, 0x42, 0x1a, 0x7f, 0x17, 0x0b])
+    ];
+
+    #[test]
+    fn hash() {
+        for &(h, a, c, g) in CASES.iter() {
+            let ghash = Ghash::new(h);
+            assert_eq!(&ghash.input_a(a).input_c(c).result()[..], g);
+        }
+    }
+
+    #[test]
+    fn split_input() {
+        for &(h, a, c, g) in CASES.iter() {
+            let ghash = Ghash::new(h);
+            let (a1, a2) = a.split_at(a.len() / 2);
+            let (c1, c2) = c.split_at(c.len() / 2);
+            assert_eq!(&ghash.input_a(a1)
+                            .input_a(a2)
+                            .input_c(c1)
+                            .input_c(c2)
+                            .result()[..], g);
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use mac::Mac;
+    use ghash::Ghash;
+
+    #[bench]
+    pub fn ghash_10(bh: & mut Bencher) {
+        let mut mac = [0u8; 16];
+        let key     = [0u8; 16];
+        let bytes   = [1u8; 10];
+        bh.iter( || {
+            let mut ghash = Ghash::new(&key);
+            ghash.input(&bytes);
+            ghash.raw_result(&mut mac);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn ghash_1k(bh: & mut Bencher) {
+        let mut mac = [0u8; 16];
+        let key     = [0u8; 16];
+        let bytes   = [1u8; 1024];
+        bh.iter( || {
+            let mut ghash = Ghash::new(&key);
+            ghash.input(&bytes);
+            ghash.raw_result(&mut mac);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn ghash_64k(bh: & mut Bencher) {
+        let mut mac = [0u8; 16];
+        let key     = [0u8; 16];
+        let bytes   = [1u8; 65536];
+        bh.iter( || {
+            let mut ghash = Ghash::new(&key);
+            ghash.input(&bytes);
+            ghash.raw_result(&mut mac);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/hc128.rs b/third_party/rust-crypto/src/hc128.rs
new file mode 100644
index 0000000..5062785
--- /dev/null
+++ b/third_party/rust-crypto/src/hc128.rs
@@ -0,0 +1,297 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+use buffer::{BufferResult, RefReadBuffer, RefWriteBuffer};
+use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher, SymmetricCipherError};
+use cryptoutil::{read_u32_le, symm_enc_or_dec, write_u32_le};
+
+use std::ptr;
+
+
+#[derive(Copy)]
+pub struct Hc128 {
+    p: [u32; 512],
+    q: [u32; 512],
+    cnt: usize,
+    output: [u8; 4],
+    output_index: usize
+}
+
+impl Clone for Hc128 { fn clone(&self) -> Hc128 { *self } }
+
+impl Hc128 {
+    pub fn new(key: &[u8], nonce: &[u8]) -> Hc128 {
+        assert!(key.len() == 16);
+        assert!(nonce.len() == 16);
+        let mut hc128 = Hc128 { p: [0; 512], q: [0; 512], cnt: 0, output: [0; 4], output_index: 0 };
+        hc128.init(&key, &nonce);
+
+        hc128
+    }
+
+    fn init(&mut self, key : &[u8], nonce : &[u8]) {
+        self.cnt = 0;
+
+        let mut w : [u32; 1280] = [0; 1280];
+
+        for i in 0..16 {
+            w[i >> 2] |= (key[i] as u32) << (8 * (i & 0x3));
+        }
+        unsafe {
+            ptr::copy_nonoverlapping(w.as_ptr(), w.as_mut_ptr().offset(4), 4);
+        }
+
+        for i in 0..nonce.len() & 16 {
+            w[(i >> 2) + 8] |= (nonce[i] as u32) << (8 * (i & 0x3));
+        }
+        unsafe {
+            ptr::copy_nonoverlapping(w.as_ptr().offset(8), w.as_mut_ptr().offset(12), 4);
+        }
+
+        for i in 16..1280 {
+            w[i] = f2(w[i - 2]).wrapping_add(w[i - 7]).wrapping_add(f1(w[i - 15])).wrapping_add(w[i - 16]).wrapping_add(i as u32);
+        }
+
+        // Copy contents of w into p and q
+        unsafe {
+            ptr::copy_nonoverlapping(w.as_ptr().offset(256), self.p.as_mut_ptr(),  512);
+            ptr::copy_nonoverlapping(w.as_ptr().offset(768), self.q.as_mut_ptr(), 512);
+        }
+
+        for i in 0..512 {
+            self.p[i] = self.step();
+        }
+        for i in 0..512 {
+            self.q[i] = self.step();
+        }
+
+        self.cnt = 0;
+    }
+
+    fn step(&mut self) -> u32 {
+        let j : usize = self.cnt & 0x1FF;
+
+        // Precompute resources
+        let dim_j3 : usize = (j.wrapping_sub(3)) & 0x1FF;
+        let dim_j10 : usize = (j.wrapping_sub(10)) & 0x1FF;
+        let dim_j511 : usize = (j.wrapping_sub(511)) & 0x1FF;
+        let dim_j12 : usize = (j.wrapping_sub(12)) & 0x1FF;
+
+        let ret : u32;
+
+        if self.cnt < 512 {
+            self.p[j] = self.p[j].wrapping_add(self.p[dim_j3].rotate_right(10) ^ self.p[dim_j511].rotate_right(23)).wrapping_add(self.p[dim_j10].rotate_right(8));
+            ret = (self.q[(self.p[dim_j12] & 0xFF) as usize].wrapping_add(self.q[(((self.p[dim_j12] >> 16) & 0xFF) + 256) as usize])) ^ self.p[j];
+        } else {
+            self.q[j] = self.q[j].wrapping_add(self.q[dim_j3].rotate_left(10) ^ self.q[dim_j511].rotate_left(23)).wrapping_add(self.q[dim_j10].rotate_left(8));
+            ret = (self.p[(self.q[dim_j12] & 0xFF) as usize].wrapping_add(self.p[(((self.q[dim_j12] >> 16) & 0xFF) + 256) as usize])) ^ self.q[j];
+        }
+
+        self.cnt = (self.cnt + 1) & 0x3FF;
+        ret
+    }
+
+    fn next(&mut self) -> u8 {
+        if self.output_index == 0 {
+            let step = self.step();
+            write_u32_le(&mut self.output, step);
+        }
+        let ret = self.output[self.output_index];
+        self.output_index = (self.output_index + 1) & 0x3;
+
+        ret
+    }
+}
+
+fn f1(x: u32) -> u32 {
+    let ret : u32 = x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3);
+    ret
+}
+
+fn f2(x: u32) -> u32 {
+    let ret : u32 = x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10);
+    ret
+}
+
+impl SynchronousStreamCipher for Hc128 {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == output.len());
+
+        if input.len() <= 4 {
+            // Process data bytewise
+            for (inb, outb) in input.iter().zip(output.iter_mut()) {
+                *outb = *inb ^ self.next();
+            }
+        } else {
+            let mut data_index = 0;
+            let data_index_end = data_index + input.len();
+
+            /*  Process any unused keystream (self.buffer)
+             *  remaining from previous operations */
+            while self.output_index > 0 && data_index < data_index_end {
+                output[data_index] = input[data_index] ^ self.next();
+                data_index += 1;
+            }
+
+            /*  Process input data blockwise until depleted,
+             *  or remaining length less than block size
+             *  (size of the keystream buffer, self.buffer : 4 bytes) */
+            while data_index + 4 <= data_index_end {
+                let data_index_inc = data_index + 4;
+
+                // Read input as le-u32
+                let input_u32 = read_u32_le(&input[data_index..data_index_inc]);
+                // XOR with keystream u32
+                let xored = input_u32 ^ self.step();
+                // Write output as le-u32
+                write_u32_le(&mut output[data_index..data_index_inc], xored);
+
+                data_index = data_index_inc;
+            }
+
+            /*  Process remaining data, if any
+             *  (e.g. input length not divisible by 4) */
+            while data_index < data_index_end {
+                output[data_index] = input[data_index] ^ self.next();
+                data_index += 1;
+            }
+        }
+    }
+}
+
+impl Encryptor for Hc128 {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl Decryptor for Hc128 {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+
+#[cfg(test)]
+mod test {
+    use hc128::Hc128;
+    use symmetriccipher::SynchronousStreamCipher;
+    use serialize::hex::{FromHex};
+
+    // Vectors from http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/hc-256/hc-128/verified.test-vectors?rev=210&view=markup
+
+    #[test]
+    fn test_hc128_ecrypt_set_2_vector_0() {
+        let key = "00000000000000000000000000000000".from_hex().unwrap();
+        let nonce = "00000000000000000000000000000000".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "82001573A003FD3B7FD72FFB0EAF63AAC62F12DEB629DCA72785A66268EC758B1EDB36900560898178E0AD009ABF1F491330DC1C246E3D6CB264F6900271D59C";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut hc128 = Hc128::new(key.as_ref(), nonce.as_ref());
+        hc128.process(&input, &mut output);
+        let result: &[u8] = output.as_ref();
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(result == expected);    }
+
+    #[test]
+    fn test_hc128_ecrypt_set_6_vector_1() {
+        let key = "0558ABFE51A4F74A9DF04396E93C8FE2".from_hex().unwrap();
+        let nonce = "167DE44BB21980E74EB51C83EA51B81F".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "4F864BF3C96D0363B1903F0739189138F6ED2BC0AF583FEEA0CEA66BA7E06E63FB28BF8B3CA0031D24ABB511C57DD17BFC2861C32400072CB680DF2E58A5CECC";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut hc128 = Hc128::new(key.as_ref(), nonce.as_ref());
+        hc128.process(&input, &mut output);
+        let result: &[u8] = output.as_ref();
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(result == expected);
+    }
+
+    #[test]
+    fn test_hc128_ecrypt_set_6_vector_2() {
+        let key = "0A5DB00356A9FC4FA2F5489BEE4194E7".from_hex().unwrap();
+        let nonce = "1F86ED54BB2289F057BE258CF35AC128".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "82168AB0023B79AAF1E6B4D823855E14A7084378036A951B1CFEF35173875ED86CB66AB8410491A08582BE40080C3102193BA567F9E95D096C3CC60927DD7901";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut hc128 = Hc128::new(key.as_ref(), nonce.as_ref());
+        hc128.process(&input, &mut output);
+        let result: &[u8] = output.as_ref();
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(result == expected);
+    }
+
+    #[test]
+    fn test_hc128_ecrypt_set_6_vector_3() {
+        let key = "0F62B5085BAE0154A7FA4DA0F34699EC".from_hex().unwrap();
+        let nonce = "288FF65DC42B92F960C72E95FC63CA31".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "1CD8AEDDFE52E217E835D0B7E84E2922D04B1ADBCA53C4522B1AA604C42856A90AF83E2614BCE65C0AECABDD8975B55700D6A26D52FFF0888DA38F1DE20B77B7";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut hc128 = Hc128::new(&key, &nonce);
+        hc128.process(&input, &mut output);
+        assert!(&output[..] == &expected_output[..]);
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use symmetriccipher::SynchronousStreamCipher;
+    use hc128::Hc128;
+
+    #[bench]
+    pub fn hc128_10(bh: & mut Bencher) {
+        let mut hc128 = Hc128::new(&[0; 16], &[0; 16]);
+        let input = [1u8; 10];
+        let mut output = [0u8; 10];
+        bh.iter( || {
+            hc128.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn hc128_1k(bh: & mut Bencher) {
+        let mut hc128 = Hc128::new(&[0; 16], &[0; 16]);
+        let input = [1u8; 1024];
+        let mut output = [0u8; 1024];
+        bh.iter( || {
+            hc128.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn hc128_64k(bh: & mut Bencher) {
+        let mut hc128 = Hc128::new(&[0; 16], &[0; 16]);
+        let input = [1u8; 65536];
+        let mut output = [0u8; 65536];
+        bh.iter( || {
+            hc128.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/hkdf.rs b/third_party/rust-crypto/src/hkdf.rs
new file mode 100644
index 0000000..a729d9b
--- /dev/null
+++ b/third_party/rust-crypto/src/hkdf.rs
@@ -0,0 +1,244 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module implements the HMAC-based Extract-and-Expand Key
+//! Derivation Function as specified by  https://tools.ietf.org/html/rfc5869.
+
+use std::prelude::v1::*;
+use std::iter::repeat;
+use cryptoutil::copy_memory;
+
+use digest::Digest;
+use hmac::Hmac;
+use mac::Mac;
+
+/// Execute the HKDF-Extract function.  Applications MUST NOT use this for
+/// password hashing.
+///
+/// # Arguments
+/// * digest - The digest function to use.
+/// * salt - The optional salt value (a non-secret random value) to use.
+/// * ikm - The input keying material to use.
+/// * prk - The output buffer to fill with a digest.output_bytes() length
+///         pseudo random key.
+pub fn hkdf_extract<D: Digest>(mut digest: D, salt: &[u8], ikm: &[u8], prk: &mut [u8]) {
+    assert!(prk.len() == digest.output_bytes());
+    digest.reset();
+
+    let mut mac = Hmac::new(digest, salt);
+    mac.input(ikm);
+    mac.raw_result(prk);
+    mac.reset();
+}
+
+/// Execute the HKDF-Expand function.  Applications MUST NOT use this for
+/// password hashing.
+///
+/// # Arguments
+/// * digest - The digest function to use.
+/// * prk - The pseudorandom key of at least digest.output_bytes() octets.
+/// * info - The optional context and application specific information to use.
+/// * okm - The output buffer to fill with the derived key value.
+pub fn hkdf_expand<D: Digest>(mut digest: D, prk: &[u8], info: &[u8], okm: &mut [u8]) {
+    digest.reset();
+
+    let mut mac = Hmac::new(digest, prk);
+    let os = mac.output_bytes();
+    let mut t: Vec<u8> = repeat(0).take(os).collect();
+    let mut n: u8 = 0;
+
+    for chunk in okm.chunks_mut(os) {
+        // The block index starts at 1. So, this is supposed to run on the first execution.
+        n = n.checked_add(1).expect("HKDF size limit exceeded.");
+
+        if n != 1 {
+            mac.input(&t[..]);
+        }
+        let nbuf = [n];
+        mac.input(info);
+        mac.input(&nbuf);
+        mac.raw_result(&mut t);
+        mac.reset();
+        let chunk_len = chunk.len();
+        copy_memory(&t[..chunk_len], chunk);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use digest::Digest;
+    use sha1::Sha1;
+    use sha2::Sha256;
+    use hkdf::{hkdf_extract, hkdf_expand};
+
+    struct TestVector<D: Digest>{
+        digest: D,
+        ikm: Vec<u8>,
+        salt: Vec<u8>,
+        info: Vec<u8>,
+        l: usize,
+
+        prk: Vec<u8>,
+        okm: Vec<u8>,
+    }
+
+    #[test]
+    fn test_hkdf_rfc5869_sha256_vectors() {
+        let test_vectors = vec!(
+            TestVector{
+                digest: Sha256::new(),
+                ikm: repeat(0x0b).take(22).collect(),
+                salt: (0x00..0x0c + 1).collect(),
+                info: (0xf0..0xf9 + 1).collect(),
+                l: 42,
+                prk: vec![
+                    0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
+                    0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
+                    0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+                    0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5 ],
+                okm: vec![
+                    0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+                    0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+                    0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+                    0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+                    0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+                    0x58, 0x65 ],
+            },
+            TestVector{
+                digest: Sha256::new(),
+                ikm: (0x00..0x4f + 1).collect(),
+                salt: (0x60..0xaf + 1).collect(),
+                info: (0xb0..0xff + 1).map(|x| x as u8).collect(),
+                l: 82,
+                prk: vec![
+                    0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a,
+                    0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c,
+                    0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01,
+                    0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44 ],
+                okm: vec![
+                    0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1,
+                    0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
+                    0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
+                    0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
+                    0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72,
+                    0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+                    0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
+                    0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
+                    0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
+                    0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
+                    0x1d, 0x87 ],
+            },
+            TestVector{
+                digest: Sha256::new(),
+                ikm: repeat(0x0b).take(22).collect(),
+                salt: vec![],
+                info: vec![],
+                l:42,
+                prk: vec![
+                    0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16,
+                    0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf,
+                    0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77,
+                    0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04 ],
+                okm: vec![
+                    0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f,
+                    0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31,
+                    0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e,
+                    0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d,
+                    0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a,
+                    0x96, 0xc8 ],
+            },
+        );
+
+        for t in test_vectors.iter() {
+            let mut prk: Vec<u8> = repeat(0).take(t.prk.len()).collect();
+            hkdf_extract(t.digest, &t.salt[..], &t.ikm[..], &mut prk);
+            assert!(prk == t.prk);
+
+            let mut okm: Vec<u8> = repeat(0).take(t.okm.len()).collect();
+            assert!(okm.len() == t.l);
+            hkdf_expand(t.digest, &prk[..], &t.info[..], &mut okm);
+            assert!(okm == t.okm);
+        }
+    }
+
+    #[test]
+    fn test_hkdf_rfc5869_sha1_vectors() {
+        let test_vectors = vec!(
+            TestVector{
+                digest: Sha1::new(),
+                ikm: repeat(0x0b).take(11).collect(),
+                salt: (0x00..0x0c + 1).collect(),
+                info: (0xf0..0xf9 + 1).collect(),
+                l: 42,
+                prk: vec![
+                    0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f,
+                    0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b,
+                    0xaa, 0x2b, 0xa2, 0x43 ],
+                okm: vec![
+                    0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69,
+                    0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81,
+                    0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15,
+                    0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2,
+                    0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3,
+                    0xf8, 0x96 ],
+            },
+            TestVector{
+                digest: Sha1::new(),
+                ikm: (0x00..0x4f + 1).collect(),
+                salt: (0x60..0xaf + 1).collect(),
+                info: (0xb0..0xff + 1).map(|x| x as u8).collect(),
+                l: 82,
+                prk: vec![
+                    0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59,
+                    0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a,
+                    0x22, 0x4c, 0xfa, 0xf6 ],
+                okm: vec![
+                    0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7,
+                    0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb,
+                    0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19,
+                    0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe,
+                    0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3,
+                    0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c,
+                    0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed,
+                    0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e,
+                    0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43,
+                    0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52,
+                    0xd3, 0xb4 ],
+            },
+            TestVector{
+                digest: Sha1::new(),
+                ikm: repeat(0x0b).take(22).collect(),
+                salt: vec![],
+                info: vec![],
+                l:42,
+                prk: vec![
+                    0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28,
+                    0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a,
+                    0xa0, 0xd3, 0x2d, 0x01 ],
+                okm: vec![
+                    0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61,
+                    0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06,
+                    0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06,
+                    0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0,
+                    0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3,
+                    0x49, 0x18 ],
+            },
+        );
+
+        for t in test_vectors.iter() {
+            let mut prk: Vec<u8> = repeat(0).take(t.prk.len()).collect();
+            hkdf_extract(t.digest, &t.salt[..], &t.ikm[..], &mut prk);
+            assert!(prk == t.prk);
+
+            let mut okm: Vec<u8> = repeat(0).take(t.okm.len()).collect();
+            assert!(okm.len() == t.l);
+            hkdf_expand(t.digest, &prk[..], &t.info[..], &mut okm);
+            assert!(okm == t.okm);
+        }
+    }
+}
diff --git a/third_party/rust-crypto/src/hmac.rs b/third_party/rust-crypto/src/hmac.rs
new file mode 100644
index 0000000..2e9510a
--- /dev/null
+++ b/third_party/rust-crypto/src/hmac.rs
@@ -0,0 +1,197 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * This module implements the Hmac function - a Message Authentication Code using a Digest.
+ */
+
+use std::prelude::v1::*;
+use std::iter::repeat;
+
+use cryptoutil;
+use digest::Digest;
+use mac::{Mac, MacResult};
+
+/**
+ * The Hmac struct represents an Hmac function - a Message Authentication Code using a Digest.
+ */
+pub struct Hmac<D> {
+    digest: D,
+    i_key: Vec<u8>,
+    o_key: Vec<u8>,
+    finished: bool
+}
+
+fn derive_key(key: &mut [u8], mask: u8) {
+    for elem in key.iter_mut() {
+        *elem ^= mask;
+    }
+}
+
+// The key that Hmac processes must be the same as the block size of the underlying Digest. If the
+// provided key is smaller than that, we just pad it with zeros. If its larger, we hash it and then
+// pad it with zeros.
+fn expand_key<D: Digest>(digest: &mut D, key: &[u8]) -> Vec<u8> {
+    let bs = digest.block_size();
+    let mut expanded_key: Vec<u8> = repeat(0).take(bs).collect();
+
+    if key.len() <= bs {
+        cryptoutil::copy_memory(key, &mut expanded_key);
+    } else {
+        let output_size = digest.output_bytes();
+        digest.input(key);
+        digest.result(&mut expanded_key[..output_size]);
+        digest.reset();
+    }
+    expanded_key
+}
+
+// Hmac uses two keys derived from the provided key - one by xoring every byte with 0x36 and another
+// with 0x5c.
+fn create_keys<D: Digest>(digest: &mut D, key: &[u8]) -> (Vec<u8>, Vec<u8>) {
+    let mut i_key = expand_key(digest, key);
+    let mut o_key = i_key.clone();
+    derive_key(&mut i_key, 0x36);
+    derive_key(&mut o_key, 0x5c);
+    (i_key, o_key)
+}
+
+impl <D: Digest> Hmac<D> {
+    /**
+     * Create a new Hmac instance.
+     *
+     * # Arguments
+     * * digest - The Digest to use.
+     * * key - The key to use.
+     *
+     */
+    pub fn new(mut digest: D, key: &[u8]) -> Hmac<D> {
+        let (i_key, o_key) = create_keys(&mut digest, key);
+        digest.input(&i_key[..]);
+        Hmac {
+            digest: digest,
+            i_key: i_key,
+            o_key: o_key,
+            finished: false
+        }
+    }
+}
+
+impl <D: Digest> Mac for Hmac<D> {
+    fn input(&mut self, data: &[u8]) {
+        assert!(!self.finished);
+        self.digest.input(data);
+    }
+
+    fn reset(&mut self) {
+        self.digest.reset();
+        self.digest.input(&self.i_key[..]);
+        self.finished = false;
+    }
+
+    fn result(&mut self) -> MacResult {
+        let output_size = self.digest.output_bytes();
+        let mut code: Vec<u8> = repeat(0).take(output_size).collect();
+
+        self.raw_result(&mut code);
+
+        MacResult::new_from_owned(code)
+    }
+
+    fn raw_result(&mut self, output: &mut [u8]) {
+        if !self.finished {
+            self.digest.result(output);
+
+            self.digest.reset();
+            self.digest.input(&self.o_key[..]);
+            self.digest.input(output);
+
+            self.finished = true;
+        }
+
+        self.digest.result(output);
+    }
+
+    fn output_bytes(&self) -> usize { self.digest.output_bytes() }
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use mac::{Mac, MacResult};
+    use hmac::Hmac;
+    use digest::Digest;
+    use md5::Md5;
+
+    struct Test {
+        key: Vec<u8>,
+        data: Vec<u8>,
+        expected: Vec<u8>
+    }
+
+    // Test vectors from: http://tools.ietf.org/html/rfc2104
+
+    fn tests() -> Vec<Test> {
+        vec![
+            Test {
+                key: repeat(0x0bu8).take(16).collect(),
+                data: b"Hi There".to_vec(),
+                expected: vec![
+                    0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
+                    0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d ]
+            },
+            Test {
+                key: b"Jefe".to_vec(),
+                data: b"what do ya want for nothing?".to_vec(),
+                expected: vec![
+                    0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
+                    0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 ]
+            },
+            Test {
+                key: repeat(0xaau8).take(16).collect(),
+                data: repeat(0xddu8).take(50).collect(),
+                expected: vec![
+                    0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
+                    0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 ]
+            }
+        ]
+    }
+
+    #[test]
+    fn test_hmac_md5() {
+        let tests = tests();
+        for t in tests.iter() {
+            let mut hmac = Hmac::new(Md5::new(), &t.key[..]);
+
+            hmac.input(&t.data[..]);
+            let result = hmac.result();
+            let expected = MacResult::new(&t.expected[..]);
+            assert!(result == expected);
+
+            hmac.reset();
+
+            hmac.input(&t.data[..]);
+            let result2 = hmac.result();
+            let expected2 = MacResult::new(&t.expected[..]);
+            assert!(result2 == expected2);
+        }
+    }
+
+    #[test]
+    fn test_hmac_md5_incremental() {
+        let tests = tests();
+        for t in tests.iter() {
+            let mut hmac = Hmac::new(Md5::new(), &t.key[..]);
+            for i in 0..t.data.len() {
+                hmac.input(&t.data[i..i + 1]);
+            }
+            let result = hmac.result();
+            let expected = MacResult::new(&t.expected[..]);
+            assert!(result == expected);
+        }
+    }
+}
diff --git a/third_party/rust-crypto/src/lib.rs b/third_party/rust-crypto/src/lib.rs
new file mode 100644
index 0000000..542c250
--- /dev/null
+++ b/third_party/rust-crypto/src/lib.rs
@@ -0,0 +1,63 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//#![cfg_attr(feature = "with-bench", feature(test))]
+#![cfg_attr(not(target_env = "sgx"), no_std)]
+#![cfg_attr(target_env = "sgx", feature(rustc_private))]
+#[cfg(not(target_env = "sgx"))]
+#[macro_use]
+extern crate sgx_tstd as std;
+
+extern crate sgx_rand;
+extern crate rustc_serialize as serialize;
+//extern crate time;
+extern crate sgx_trts;
+
+//#[cfg(all(test, feature = "with-bench"))]
+//extern crate test;
+
+pub mod aead;
+pub mod aes;
+pub mod aes_gcm;
+pub mod aessafe;
+pub mod bcrypt;
+pub mod bcrypt_pbkdf;
+pub mod blake2b;
+pub mod blake2s;
+pub mod blockmodes;
+pub mod blowfish;
+pub mod buffer;
+pub mod chacha20;
+pub mod chacha20poly1305;
+mod cryptoutil;
+pub mod curve25519;
+pub mod digest;
+pub mod ed25519;
+pub mod fortuna;
+pub mod ghash;
+pub mod hc128;
+pub mod hmac;
+pub mod hkdf;
+pub mod mac;
+pub mod md5;
+pub mod pbkdf2;
+pub mod poly1305;
+pub mod rc4;
+pub mod ripemd160;
+pub mod salsa20;
+pub mod scrypt;
+pub mod sha1;
+pub mod sha2;
+pub mod sha3;
+mod simd;
+pub mod sosemanuk;
+mod step_by;
+pub mod symmetriccipher;
+pub mod util;
+pub mod whirlpool;
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub mod aesni;
diff --git a/third_party/rust-crypto/src/mac.rs b/third_party/rust-crypto/src/mac.rs
new file mode 100644
index 0000000..85903cd
--- /dev/null
+++ b/third_party/rust-crypto/src/mac.rs
@@ -0,0 +1,93 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * The mac module defines the Message Authentication Code (Mac) trait.
+ */
+
+use std::prelude::v1::*;
+use util::fixed_time_eq;
+
+/**
+ * The Mac trait defines methods for a Message Authentication function.
+ */
+pub trait Mac {
+    /**
+     * Process input data.
+     *
+     * # Arguments
+     * * data - The input data to process.
+     *
+     */
+    fn input(&mut self, data: &[u8]);
+
+    /**
+     * Reset the Mac state to begin processing another input stream.
+     */
+    fn reset(&mut self);
+
+    /**
+     * Obtain the result of a Mac computation as a MacResult.
+     */
+    fn result(&mut self) -> MacResult;
+
+    /**
+     * Obtain the result of a Mac computation as [u8]. This method should be used very carefully
+     * since incorrect use of the Mac code could result in permitting a timing attack which defeats
+     * the security provided by a Mac function.
+     */
+    fn raw_result(&mut self, output: &mut [u8]);
+
+    /**
+     * Get the size of the Mac code, in bytes.
+     */
+    fn output_bytes(&self) -> usize;
+}
+
+/**
+ * A MacResult wraps a Mac code and provides a safe Eq implementation that runs in fixed time.
+ */
+pub struct MacResult {
+    code: Vec<u8>
+}
+
+impl MacResult {
+    /**
+     * Create a new MacResult.
+     */
+    pub fn new(code: &[u8]) -> MacResult {
+        MacResult {
+            code: code.to_vec()
+        }
+    }
+
+    /**
+     * Create a new MacResult taking ownership of the specified code value.
+     */
+    pub fn new_from_owned(code: Vec<u8>) -> MacResult {
+        MacResult {
+            code: code
+        }
+    }
+
+    /**
+     * Get the code value. Be very careful using this method, since incorrect use of the code value
+     * may permit timing attacks which defeat the security provided by the Mac function.
+     */
+    pub fn code<'s>(&'s self) -> &'s [u8] {
+        &self.code[..]
+    }
+}
+
+impl PartialEq for MacResult {
+    fn eq(&self, x: &MacResult) -> bool {
+        let lhs = self.code();
+        let rhs = x.code();
+        fixed_time_eq(lhs, rhs)
+    }
+}
+
+impl Eq for MacResult { }
diff --git a/third_party/rust-crypto/src/md5.rs b/third_party/rust-crypto/src/md5.rs
new file mode 100644
index 0000000..6f35169
--- /dev/null
+++ b/third_party/rust-crypto/src/md5.rs
@@ -0,0 +1,328 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cryptoutil::{write_u32_le, read_u32v_le, FixedBuffer, FixedBuffer64, StandardPadding};
+use digest::Digest;
+use step_by::RangeExt;
+
+
+// A structure that represents that state of a digest computation for the MD5 digest function
+#[derive(Clone, Copy)]
+struct Md5State {
+    s0: u32,
+    s1: u32,
+    s2: u32,
+    s3: u32
+}
+
+impl Md5State {
+    fn new() -> Md5State {
+        Md5State {
+            s0: 0x67452301,
+            s1: 0xefcdab89,
+            s2: 0x98badcfe,
+            s3: 0x10325476
+        }
+    }
+
+    fn reset(&mut self) {
+        self.s0 = 0x67452301;
+        self.s1 = 0xefcdab89;
+        self.s2 = 0x98badcfe;
+        self.s3 = 0x10325476;
+    }
+
+    fn process_block(&mut self, input: &[u8]) {
+        fn f(u: u32, v: u32, w: u32) -> u32 {
+            (u & v) | (!u & w)
+        }
+
+        fn g(u: u32, v: u32, w: u32) -> u32 {
+            (u & w) | (v & !w)
+        }
+
+        fn h(u: u32, v: u32, w: u32) -> u32 {
+            u ^ v ^ w
+        }
+
+        fn i(u: u32, v: u32, w: u32) -> u32 {
+            v ^ (u | !w)
+        }
+
+        fn op_f(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+            w.wrapping_add(f(x, y, z)).wrapping_add(m).rotate_left(s).wrapping_add(x)
+        }
+
+        fn op_g(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+            w.wrapping_add(g(x, y, z)).wrapping_add(m).rotate_left(s).wrapping_add(x)
+        }
+
+        fn op_h(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+            w.wrapping_add(h(x, y, z)).wrapping_add(m).rotate_left(s).wrapping_add(x)
+        }
+
+        fn op_i(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+            w.wrapping_add(i(x, y, z)).wrapping_add(m).rotate_left(s).wrapping_add(x)
+        }
+
+        let mut a = self.s0;
+        let mut b = self.s1;
+        let mut c = self.s2;
+        let mut d = self.s3;
+
+        let mut data = [0u32; 16];
+
+        read_u32v_le(&mut data, input);
+
+        // round 1
+        for i in (0..16).step_up(4) {
+            a = op_f(a, b, c, d, data[i].wrapping_add(C1[i]), 7);
+            d = op_f(d, a, b, c, data[i + 1].wrapping_add(C1[i + 1]), 12);
+            c = op_f(c, d, a, b, data[i + 2].wrapping_add(C1[i + 2]), 17);
+            b = op_f(b, c, d, a, data[i + 3].wrapping_add(C1[i + 3]), 22);
+        }
+
+        // round 2
+        let mut t = 1;
+        for i in (0..16).step_up(4) {
+            a = op_g(a, b, c, d, data[t & 0x0f].wrapping_add(C2[i]), 5);
+            d = op_g(d, a, b, c, data[(t + 5) & 0x0f].wrapping_add(C2[i + 1]), 9);
+            c = op_g(c, d, a, b, data[(t + 10) & 0x0f].wrapping_add(C2[i + 2]), 14);
+            b = op_g(b, c, d, a, data[(t + 15) & 0x0f].wrapping_add(C2[i + 3]), 20);
+            t += 20;
+        }
+
+        // round 3
+        t = 5;
+        for i in (0..16).step_up(4) {
+            a = op_h(a, b, c, d, data[t & 0x0f].wrapping_add(C3[i]), 4);
+            d = op_h(d, a, b, c, data[(t + 3) & 0x0f].wrapping_add(C3[i + 1]), 11);
+            c = op_h(c, d, a, b, data[(t + 6) & 0x0f].wrapping_add(C3[i + 2]), 16);
+            b = op_h(b, c, d, a, data[(t + 9) & 0x0f].wrapping_add(C3[i + 3]), 23);
+            t += 12;
+        }
+
+        // round 4
+        t = 0;
+        for i in (0..16).step_up(4) {
+            a = op_i(a, b, c, d, data[t & 0x0f].wrapping_add(C4[i]), 6);
+            d = op_i(d, a, b, c, data[(t + 7) & 0x0f].wrapping_add(C4[i + 1]), 10);
+            c = op_i(c, d, a, b, data[(t + 14) & 0x0f].wrapping_add(C4[i + 2]), 15);
+            b = op_i(b, c, d, a, data[(t + 21) & 0x0f].wrapping_add(C4[i + 3]), 21);
+            t += 28;
+        }
+
+        self.s0 = self.s0.wrapping_add(a);
+        self.s1 = self.s1.wrapping_add(b);
+        self.s2 = self.s2.wrapping_add(c);
+        self.s3 = self.s3.wrapping_add(d);
+    }
+}
+
+// Round 1 constants
+static C1: [u32; 16] = [
+    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
+];
+
+// Round 2 constants
+static C2: [u32; 16] = [
+    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
+];
+
+// Round 3 constants
+static C3: [u32; 16] = [
+    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
+];
+
+// Round 4 constants
+static C4: [u32; 16] = [
+    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+];
+
+
+/// The MD5 Digest algorithm
+#[derive(Clone, Copy)]
+pub struct Md5 {
+    length_bytes: u64,
+    buffer: FixedBuffer64,
+    state: Md5State,
+    finished: bool,
+}
+
+impl Md5 {
+    /// Construct a new instance of the MD5 Digest.
+    pub fn new() -> Md5 {
+        Md5 {
+            length_bytes: 0,
+            buffer: FixedBuffer64::new(),
+            state: Md5State::new(),
+            finished: false
+        }
+    }
+}
+
+impl Digest for Md5 {
+    fn input(&mut self, input: &[u8]) {
+        assert!(!self.finished);
+        // Unlike Sha1 and Sha2, the length value in MD5 is defined as the length of the message mod
+        // 2^64 - ie: integer overflow is OK.
+        self.length_bytes += input.len() as u64;
+        let self_state = &mut self.state;
+        self.buffer.input(input, |d: &[u8]| { self_state.process_block(d);}
+        );
+    }
+
+    fn reset(&mut self) {
+        self.length_bytes = 0;
+        self.buffer.reset();
+        self.state.reset();
+        self.finished = false;
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        if !self.finished {
+            let self_state = &mut self.state;
+            self.buffer.standard_padding(8, |d: &[u8]| { self_state.process_block(d); });
+            write_u32_le(self.buffer.next(4), (self.length_bytes << 3) as u32);
+            write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
+            self_state.process_block(self.buffer.full_buffer());
+            self.finished = true;
+        }
+
+        write_u32_le(&mut out[0..4], self.state.s0);
+        write_u32_le(&mut out[4..8], self.state.s1);
+        write_u32_le(&mut out[8..12], self.state.s2);
+        write_u32_le(&mut out[12..16], self.state.s3);
+    }
+
+    fn output_bits(&self) -> usize { 128 }
+
+    fn block_size(&self) -> usize { 64 }
+}
+
+
+#[cfg(test)]
+mod tests {
+    use cryptoutil::test::test_digest_1million_random;
+    use digest::Digest;
+    use md5::Md5;
+
+
+    struct Test {
+        input: &'static str,
+        output_str: &'static str,
+    }
+
+    fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
+        // Test that it works when accepting the message all at once
+        for t in tests.iter() {
+            sh.input_str(t.input);
+
+            let out_str = sh.result_str();
+            assert_eq!(out_str, t.output_str);
+
+            sh.reset();
+        }
+
+        // Test that it works when accepting the message in pieces
+        for t in tests.iter() {
+            let len = t.input.len();
+            let mut left = len;
+            while left > 0 {
+                let take = (left + 1) / 2;
+                sh.input_str(&t.input[len - left..take + len - left]);
+                left = left - take;
+            }
+
+            let out_str = sh.result_str();
+            assert_eq!(out_str, t.output_str);
+
+            sh.reset();
+        }
+    }
+
+    #[test]
+    fn test_md5() {
+        // Examples from wikipedia
+        let wikipedia_tests = vec![
+            Test {
+                input: "",
+                output_str: "d41d8cd98f00b204e9800998ecf8427e"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output_str: "9e107d9d372bb6826bd81d3542a419d6"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog.",
+                output_str: "e4d909c290d0fb1ca068ffaddf22cbd0"
+            },
+        ];
+
+        let tests = wikipedia_tests;
+
+        let mut sh = Md5::new();
+
+        test_hash(&mut sh, &tests[..]);
+    }
+
+    #[test]
+    fn test_1million_random_md5() {
+        let mut sh = Md5::new();
+        test_digest_1million_random(
+            &mut sh,
+            64,
+            "7707d6ae4e027c70eea2a935c2296f21");
+    }
+}
+
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+
+    use digest::Digest;
+    use md5::Md5;
+
+
+    #[bench]
+    pub fn md5_10(bh: & mut Bencher) {
+        let mut sh = Md5::new();
+        let bytes = [1u8; 10];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn md5_1k(bh: & mut Bencher) {
+        let mut sh = Md5::new();
+        let bytes = [1u8; 1024];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn md5_64k(bh: & mut Bencher) {
+        let mut sh = Md5::new();
+        let bytes = [1u8; 65536];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/pbkdf2.rs b/third_party/rust-crypto/src/pbkdf2.rs
new file mode 100644
index 0000000..ddb1c92
--- /dev/null
+++ b/third_party/rust-crypto/src/pbkdf2.rs
@@ -0,0 +1,358 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * This module implements the PBKDF2 Key Derivation Function as specified by
+ * http://tools.ietf.org/html/rfc2898.
+ */
+
+use std::prelude::v1::*;
+use std::iter::repeat;
+use std::io;
+use cryptoutil::copy_memory;
+
+use sgx_rand::{thread_rng, Rng};
+use serialize::base64;
+use serialize::base64::{FromBase64, ToBase64};
+
+use cryptoutil::{read_u32_be, write_u32_be};
+use hmac::Hmac;
+use mac::Mac;
+use sha2::Sha256;
+use util::fixed_time_eq;
+
+// Calculate a block of the output of size equal to the output_bytes of the underlying Mac function
+// mac - The Mac function to use
+// salt - the salt value to use
+// c - the iteration count
+// idx - the 1 based index of the block
+// scratch - a temporary variable the same length as the block
+// block - the block of the output to calculate
+fn calculate_block<M: Mac>(
+        mac: &mut M,
+        salt: &[u8],
+        c: u32,
+        idx: u32,
+        scratch: &mut [u8],
+        block: &mut [u8]) {
+    // Perform the 1st iteration. The output goes directly into block
+    mac.input(salt);
+    let mut idx_buf = [0u8; 4];
+    write_u32_be(&mut idx_buf, idx);
+    mac.input(&idx_buf);
+    mac.raw_result(block);
+    mac.reset();
+
+    // Perform the 2nd iteration. The input comes from block and is output into scratch. scratch is
+    // then exclusive-or added into block. After all this, the input to the next step is now in
+    // scratch and block is left to just accumulate the exclusive-of sum of remaining iterations.
+    if c > 1 {
+        mac.input(block);
+        mac.raw_result(scratch);
+        mac.reset();
+        for (output, &input) in block.iter_mut().zip(scratch.iter()) {
+            *output ^= input;
+        }
+    }
+
+    // Perform all remaining iterations
+    for _ in 2..c {
+        mac.input(scratch);
+        mac.raw_result(scratch);
+        mac.reset();
+        for (output, &input) in block.iter_mut().zip(scratch.iter()) {
+            *output ^= input;
+        }
+    }
+}
+
+/**
+ * Execute the PBKDF2 Key Derivation Function. The Scrypt Key Derivation Function generally provides
+ * better security, so, applications that do not have a requirement to use PBKDF2 specifically
+ * should consider using that function instead.
+ *
+ * # Arguments
+ * * mac - The Pseudo Random Function to use.
+ * * salt - The salt value to use.
+ * * c - The iteration count. Users should carefully determine this value as it is the primary
+ *       factor in determining the security of the derived key.
+ * * output - The output buffer to fill with the derived key value.
+ *
+ */
+pub fn pbkdf2<M: Mac>(mac: &mut M, salt: &[u8], c: u32, output: &mut [u8]) {
+    assert!(c > 0);
+
+    let os = mac.output_bytes();
+
+    // A temporary storage array needed by calculate_block. This is really only necessary if c > 1.
+    // Most users of pbkdf2 should use a value much larger than 1, so, this allocation should almost
+    // always be necessary. A big exception is Scrypt. However, this allocation is unlikely to be
+    // the bottleneck in Scrypt performance.
+    let mut scratch: Vec<u8> = repeat(0).take(os).collect();
+
+    let mut idx: u32 = 0;
+
+    for chunk in output.chunks_mut(os) {
+        // The block index starts at 1. So, this is supposed to run on the first execution.
+        idx = idx.checked_add(1).expect("PBKDF2 size limit exceeded.");
+
+        if chunk.len() == os {
+            calculate_block(mac, salt, c, idx, &mut scratch, chunk);
+        } else {
+            let mut tmp: Vec<u8> = repeat(0).take(os).collect();
+            calculate_block(mac, salt, c, idx, &mut scratch[..], &mut tmp[..]);
+            let chunk_len = chunk.len();
+            copy_memory(&tmp[..chunk_len], chunk);
+        }
+    }
+}
+
+/**
+ * pbkdf2_simple is a helper function that should be sufficient for the majority of cases where
+ * an application needs to use PBKDF2 to hash a password for storage. The result is a String that
+ * contains the parameters used as part of its encoding. The pbkdf2_check function may be used on
+ * a password to check if it is equal to a hashed value.
+ *
+ * # Format
+ *
+ * The format of the output is a modified version of the Modular Crypt Format that encodes algorithm
+ * used and iteration count. The format is indicated as "rpbkdf2" which is short for "Rust PBKF2
+ * format."
+ *
+ * $rpbkdf2$0$<base64(c)>$<base64(salt)>$<based64(hash)>$
+ *
+ * # Arguments
+ *
+ * * password - The password to process as a str
+ * * c - The iteration count
+ *
+ */
+pub fn pbkdf2_simple(password: &str, c: u32) -> io::Result<String> {
+    let mut rng = thread_rng();
+
+    // 128-bit salt
+    let salt: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
+
+    // 256-bit derived key
+    let mut dk = [0u8; 32];
+
+    let mut mac = Hmac::new(Sha256::new(), password.as_bytes());
+
+    pbkdf2(&mut mac, &salt[..], c, &mut dk);
+
+    let mut result = "$rpbkdf2$0$".to_string();
+    let mut tmp = [0u8; 4];
+    write_u32_be(&mut tmp, c);
+    result.push_str(&tmp.to_base64(base64::STANDARD)[..]);
+    result.push('$');
+    result.push_str(&salt.to_base64(base64::STANDARD)[..]);
+    result.push('$');
+    result.push_str(&dk.to_base64(base64::STANDARD)[..]);
+    result.push('$');
+
+    Ok(result)
+}
+
+/**
+ * pbkdf2_check compares a password against the result of a previous call to pbkdf2_simple and
+ * returns true if the passed in password hashes to the same value.
+ *
+ * # Arguments
+ *
+ * * password - The password to process as a str
+ * * hashed_value - A string representing a hashed password returned by pbkdf2_simple()
+ *
+ */
+pub fn pbkdf2_check(password: &str, hashed_value: &str) -> Result<bool, &'static str> {
+    static ERR_STR: &'static str = "Hash is not in Rust PBKDF2 format.";
+
+    let mut iter = hashed_value.split('$');
+
+    // Check that there are no characters before the first "$"
+    match iter.next() {
+        Some(x) => if x != "" { return Err(ERR_STR); },
+        None => return Err(ERR_STR)
+    }
+
+    // Check the name
+    match iter.next() {
+        Some(t) => if t != "rpbkdf2" { return Err(ERR_STR); },
+        None => return Err(ERR_STR)
+    }
+
+    // Parse format - currenlty only version 0 is supported
+    match iter.next() {
+        Some(fstr) => {
+            match fstr {
+                "0" => { }
+                _ => return Err(ERR_STR)
+            }
+        }
+        None => return Err(ERR_STR)
+    }
+
+    // Parse the iteration count
+    let c = match iter.next() {
+        Some(pstr) => match pstr.from_base64() {
+            Ok(pvec) => {
+                if pvec.len() != 4 { return Err(ERR_STR); }
+                read_u32_be(&pvec[..])
+            }
+            Err(_) => return Err(ERR_STR)
+        },
+        None => return Err(ERR_STR)
+    };
+
+    // Salt
+    let salt = match iter.next() {
+        Some(sstr) => match sstr.from_base64() {
+            Ok(salt) => salt,
+            Err(_) => return Err(ERR_STR)
+        },
+        None => return Err(ERR_STR)
+    };
+
+    // Hashed value
+    let hash = match iter.next() {
+        Some(hstr) => match hstr.from_base64() {
+            Ok(hash) => hash,
+            Err(_) => return Err(ERR_STR)
+        },
+        None => return Err(ERR_STR)
+    };
+
+    // Make sure that the input ends with a "$"
+    match iter.next() {
+        Some(x) => if x != "" { return Err(ERR_STR); },
+        None => return Err(ERR_STR)
+    }
+
+    // Make sure there is no trailing data after the final "$"
+    match iter.next() {
+        Some(_) => return Err(ERR_STR),
+        None => { }
+    }
+
+    let mut mac = Hmac::new(Sha256::new(), password.as_bytes());
+
+    let mut output: Vec<u8> = repeat(0).take(hash.len()).collect();
+    pbkdf2(&mut mac, &salt[..], c, &mut output[..]);
+
+    // Be careful here - its important that the comparison be done using a fixed time equality
+    // check. Otherwise an adversary that can measure how long this step takes can learn about the
+    // hashed value which would allow them to mount an offline brute force attack against the
+    // hashed password.
+    Ok(fixed_time_eq(&output[..], &hash[..]))
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use pbkdf2::{pbkdf2, pbkdf2_simple, pbkdf2_check};
+    use hmac::Hmac;
+    use sha1::Sha1;
+
+    struct Test {
+        password: Vec<u8>,
+        salt: Vec<u8>,
+        c: u32,
+        expected: Vec<u8>
+    }
+
+    // Test vectors from http://tools.ietf.org/html/rfc6070. The 4th test vector is omitted because
+    // it takes too long to run.
+
+    fn tests() -> Vec<Test> {
+        vec![
+            Test {
+                password: b"password".to_vec(),
+                salt: b"salt".to_vec(),
+                c: 1,
+                expected: vec![
+                    0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+                    0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+                    0x2f, 0xe0, 0x37, 0xa6 ]
+            },
+            Test {
+                password: b"password".to_vec(),
+                salt: b"salt".to_vec(),
+                c: 2,
+                expected: vec![
+                    0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+                    0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+                    0xd8, 0xde, 0x89, 0x57 ]
+            },
+            Test {
+                password: b"password".to_vec(),
+                salt: b"salt".to_vec(),
+                c: 4096,
+                expected: vec![
+                    0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+                    0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+                    0x65, 0xa4, 0x29, 0xc1 ]
+            },
+            Test {
+                password: b"passwordPASSWORDpassword".to_vec(),
+                salt: b"saltSALTsaltSALTsaltSALTsaltSALTsalt".to_vec(),
+                c: 4096,
+                expected: vec![
+                    0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+                    0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+                    0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 0x38 ]
+            },
+            Test {
+                password: vec![112, 97, 115, 115, 0, 119, 111, 114, 100],
+                salt: vec![115, 97, 0, 108, 116],
+                c: 4096,
+                expected: vec![
+                    0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+                    0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 ]
+            }
+        ]
+    }
+
+    #[test]
+    fn test_pbkdf2() {
+        let tests = tests();
+        for t in tests.iter() {
+            let mut mac = Hmac::new(Sha1::new(), &t.password[..]);
+            let mut result: Vec<u8> = repeat(0).take(t.expected.len()).collect();
+            pbkdf2(&mut mac, &t.salt[..], t.c, &mut result);
+            assert!(result == t.expected);
+        }
+    }
+
+    #[test]
+    fn test_pbkdf2_simple() {
+        let password = "password";
+
+        let out1 = pbkdf2_simple(password, 1024).unwrap();
+        let out2 = pbkdf2_simple(password, 1024).unwrap();
+
+        // This just makes sure that a salt is being applied. It doesn't verify that that salt is
+        // cryptographically strong, however.
+        assert!(out1 != out2);
+
+        match pbkdf2_check(password, &out1[..]) {
+            Ok(r) => assert!(r),
+            Err(_) => panic!()
+        }
+        match pbkdf2_check(password, &out2[..]) {
+            Ok(r) => assert!(r),
+            Err(_) => panic!()
+        }
+
+        match pbkdf2_check("wrong", &out1[..]) {
+            Ok(r) => assert!(!r),
+            Err(_) => panic!()
+        }
+        match pbkdf2_check("wrong", &out2[..]) {
+            Ok(r) => assert!(!r),
+            Err(_) => panic!()
+        }
+    }
+}
diff --git a/third_party/rust-crypto/src/poly1305.rs b/third_party/rust-crypto/src/poly1305.rs
new file mode 100644
index 0000000..3ffe52e
--- /dev/null
+++ b/third_party/rust-crypto/src/poly1305.rs
@@ -0,0 +1,405 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This is a port of Andrew Moons poly1305-donna
+// https://github.com/floodyberry/poly1305-donna
+
+use std::cmp::min;
+
+use cryptoutil::{read_u32_le, write_u32_le};
+use mac::{Mac, MacResult};
+
+#[derive(Clone, Copy)]
+pub struct Poly1305 {
+    r         : [u32; 5],
+    h         : [u32; 5],
+    pad       : [u32; 4],
+    leftover  : usize,
+    buffer    : [u8; 16],
+    finalized : bool,
+}
+
+impl Poly1305 {
+    pub fn new(key: &[u8]) -> Poly1305 {
+        assert!(key.len() == 32);
+        let mut poly = Poly1305{ r: [0u32; 5], h: [0u32; 5], pad: [0u32; 4], leftover: 0, buffer: [0u8; 16], finalized: false };
+
+        // r &= 0xffffffc0ffffffc0ffffffc0fffffff
+        poly.r[0] = (read_u32_le(&key[0..4])     ) & 0x3ffffff;
+        poly.r[1] = (read_u32_le(&key[3..7]) >> 2) & 0x3ffff03;
+        poly.r[2] = (read_u32_le(&key[6..10]) >> 4) & 0x3ffc0ff;
+        poly.r[3] = (read_u32_le(&key[9..13]) >> 6) & 0x3f03fff;
+        poly.r[4] = (read_u32_le(&key[12..16]) >> 8) & 0x00fffff;
+
+        poly.pad[0] = read_u32_le(&key[16..20]);
+        poly.pad[1] = read_u32_le(&key[20..24]);
+        poly.pad[2] = read_u32_le(&key[24..28]);
+        poly.pad[3] = read_u32_le(&key[28..32]);
+
+        poly
+    }
+
+    fn block(&mut self, m: &[u8]) {
+        let hibit : u32 = if self.finalized { 0 } else { 1 << 24 };
+
+        let r0 = self.r[0];
+        let r1 = self.r[1];
+        let r2 = self.r[2];
+        let r3 = self.r[3];
+        let r4 = self.r[4];
+
+        let s1 = r1 * 5;
+        let s2 = r2 * 5;
+        let s3 = r3 * 5;
+        let s4 = r4 * 5;
+
+        let mut h0 = self.h[0];
+        let mut h1 = self.h[1];
+        let mut h2 = self.h[2];
+        let mut h3 = self.h[3];
+        let mut h4 = self.h[4];
+
+        // h += m
+        h0 += (read_u32_le(&m[0..4])     ) & 0x3ffffff;
+        h1 += (read_u32_le(&m[3..7]) >> 2) & 0x3ffffff;
+        h2 += (read_u32_le(&m[6..10]) >> 4) & 0x3ffffff;
+        h3 += (read_u32_le(&m[9..13]) >> 6) & 0x3ffffff;
+        h4 += (read_u32_le(&m[12..16]) >> 8) | hibit;
+
+        // h *= r
+        let     d0 = (h0 as u64 * r0 as u64) + (h1 as u64 * s4 as u64) + (h2 as u64 * s3 as u64) + (h3 as u64 * s2 as u64) + (h4 as u64 * s1 as u64);
+        let mut d1 = (h0 as u64 * r1 as u64) + (h1 as u64 * r0 as u64) + (h2 as u64 * s4 as u64) + (h3 as u64 * s3 as u64) + (h4 as u64 * s2 as u64);
+        let mut d2 = (h0 as u64 * r2 as u64) + (h1 as u64 * r1 as u64) + (h2 as u64 * r0 as u64) + (h3 as u64 * s4 as u64) + (h4 as u64 * s3 as u64);
+        let mut d3 = (h0 as u64 * r3 as u64) + (h1 as u64 * r2 as u64) + (h2 as u64 * r1 as u64) + (h3 as u64 * r0 as u64) + (h4 as u64 * s4 as u64);
+        let mut d4 = (h0 as u64 * r4 as u64) + (h1 as u64 * r3 as u64) + (h2 as u64 * r2 as u64) + (h3 as u64 * r1 as u64) + (h4 as u64 * r0 as u64);
+
+        // (partial) h %= p
+        let mut c : u32;
+                        c = (d0 >> 26) as u32; h0 = d0 as u32 & 0x3ffffff;
+        d1 += c as u64; c = (d1 >> 26) as u32; h1 = d1 as u32 & 0x3ffffff;
+        d2 += c as u64; c = (d2 >> 26) as u32; h2 = d2 as u32 & 0x3ffffff;
+        d3 += c as u64; c = (d3 >> 26) as u32; h3 = d3 as u32 & 0x3ffffff;
+        d4 += c as u64; c = (d4 >> 26) as u32; h4 = d4 as u32 & 0x3ffffff;
+        h0 += c * 5;    c = h0 >> 26; h0 = h0 & 0x3ffffff;
+        h1 += c;
+
+        self.h[0] = h0;
+        self.h[1] = h1;
+        self.h[2] = h2;
+        self.h[3] = h3;
+        self.h[4] = h4;
+    }
+
+    fn finish(&mut self) {
+        if self.leftover > 0 {
+            self.buffer[self.leftover] = 1;
+            for i in self.leftover+1..16 {
+                self.buffer[i] = 0;
+            }
+            self.finalized = true;
+            let tmp = self.buffer;
+            self.block(&tmp);
+        }
+
+        // fully carry h
+        let mut h0 = self.h[0];
+        let mut h1 = self.h[1];
+        let mut h2 = self.h[2];
+        let mut h3 = self.h[3];
+        let mut h4 = self.h[4];
+
+        let mut c : u32;
+                     c = h1 >> 26; h1 = h1 & 0x3ffffff;
+        h2 +=     c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
+        h3 +=     c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
+        h4 +=     c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
+        h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
+        h1 +=     c;
+
+        // compute h + -p
+        let mut g0 = h0.wrapping_add(5); c = g0 >> 26; g0 &= 0x3ffffff;
+        let mut g1 = h1.wrapping_add(c); c = g1 >> 26; g1 &= 0x3ffffff;
+        let mut g2 = h2.wrapping_add(c); c = g2 >> 26; g2 &= 0x3ffffff;
+        let mut g3 = h3.wrapping_add(c); c = g3 >> 26; g3 &= 0x3ffffff;
+        let mut g4 = h4.wrapping_add(c).wrapping_sub(1 << 26);
+
+        // select h if h < p, or h + -p if h >= p
+        let mut mask = (g4 >> (32 - 1)).wrapping_sub(1);
+        g0 &= mask;
+        g1 &= mask;
+        g2 &= mask;
+        g3 &= mask;
+        g4 &= mask;
+        mask = !mask;
+        h0 = (h0 & mask) | g0;
+        h1 = (h1 & mask) | g1;
+        h2 = (h2 & mask) | g2;
+        h3 = (h3 & mask) | g3;
+        h4 = (h4 & mask) | g4;
+
+        // h = h % (2^128)
+        h0 = ((h0      ) | (h1 << 26)) & 0xffffffff;
+        h1 = ((h1 >>  6) | (h2 << 20)) & 0xffffffff;
+        h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+        h3 = ((h3 >> 18) | (h4 <<  8)) & 0xffffffff;
+
+        // h = mac = (h + pad) % (2^128)
+        let mut f : u64;
+        f = h0 as u64 + self.pad[0] as u64            ; h0 = f as u32;
+        f = h1 as u64 + self.pad[1] as u64 + (f >> 32); h1 = f as u32;
+        f = h2 as u64 + self.pad[2] as u64 + (f >> 32); h2 = f as u32;
+        f = h3 as u64 + self.pad[3] as u64 + (f >> 32); h3 = f as u32;
+
+        self.h[0] = h0;
+        self.h[1] = h1;
+        self.h[2] = h2;
+        self.h[3] = h3;
+    }
+}
+
+impl Mac for Poly1305 {
+    fn input(&mut self, data: &[u8]) {
+        assert!(!self.finalized);
+        let mut m = data;
+
+        if self.leftover > 0 {
+            let want = min(16 - self.leftover, m.len());
+            for i in 0..want {
+                self.buffer[self.leftover+i] = m[i];
+            }
+            m = &m[want..];
+            self.leftover += want;
+
+            if self.leftover < 16 {
+                return;
+            }
+
+            // self.block(self.buffer[..]);
+            let tmp = self.buffer;
+            self.block(&tmp);
+
+            self.leftover = 0;
+        }
+
+        while m.len() >= 16 {
+            self.block(&m[0..16]);
+            m = &m[16..];
+        }
+
+        for i in 0..m.len() {
+            self.buffer[i] = m[i];
+        }
+        self.leftover = m.len();
+    }
+
+    fn reset(&mut self) {
+        self.h = [0u32; 5];
+        self.leftover = 0;
+        self.finalized = false;
+    }
+
+    fn result(&mut self) -> MacResult {
+        let mut mac = [0u8; 16];
+        self.raw_result(&mut mac);
+        MacResult::new(&mac[..])
+    }
+
+    fn raw_result(&mut self, output: &mut [u8]) {
+        assert!(output.len() >= 16);
+        if !self.finalized{
+            self.finish();
+        }
+        write_u32_le(&mut output[0..4], self.h[0]);
+        write_u32_le(&mut output[4..8], self.h[1]);
+        write_u32_le(&mut output[8..12], self.h[2]);
+        write_u32_le(&mut output[12..16], self.h[3]);
+    }
+
+    fn output_bytes(&self) -> usize { 16 }
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use poly1305::Poly1305;
+    use mac::Mac;
+
+    fn poly1305(key: &[u8], msg: &[u8], mac: &mut [u8]) {
+        let mut poly = Poly1305::new(key);
+        poly.input(msg);
+        poly.raw_result(mac);
+    }
+
+    #[test]
+    fn test_nacl_vector() {
+        let key = [
+            0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91,
+            0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25,
+            0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65,
+            0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80,
+        ];
+
+        let msg = [
+            0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73,
+            0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce,
+            0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4,
+            0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a,
+            0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b,
+            0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72,
+            0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2,
+            0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38,
+            0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a,
+            0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae,
+            0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea,
+            0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda,
+            0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde,
+            0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3,
+            0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6,
+            0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74,
+            0xe3,0x55,0xa5,
+        ];
+
+        let expected = [
+            0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5,
+            0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9,
+        ];
+
+        let mut mac = [0u8; 16];
+        poly1305(&key, &msg, &mut mac);
+        assert_eq!(&mac[..], &expected[..]);
+
+        let mut poly = Poly1305::new(&key);
+        poly.input(&msg[0..32]);
+        poly.input(&msg[32..96]);
+        poly.input(&msg[96..112]);
+        poly.input(&msg[112..120]);
+        poly.input(&msg[120..124]);
+        poly.input(&msg[124..126]);
+        poly.input(&msg[126..127]);
+        poly.input(&msg[127..128]);
+        poly.input(&msg[128..129]);
+        poly.input(&msg[129..130]);
+        poly.input(&msg[130..131]);
+        poly.raw_result(&mut mac);
+        assert_eq!(&mac[..], &expected[..]);
+    }
+
+    #[test]
+    fn donna_self_test() {
+        let wrap_key = [
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        ];
+
+        let wrap_msg = [
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        ];
+
+        let wrap_mac = [
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        ];
+
+        let mut mac = [0u8; 16];
+        poly1305(&wrap_key, &wrap_msg, &mut mac);
+        assert_eq!(&mac[..], &wrap_mac[..]);
+
+        let total_key = [
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff,
+            0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+        ];
+
+        let total_mac = [
+            0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd,
+            0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62, 0x3d, 0x39,
+        ];
+
+        let mut tpoly = Poly1305::new(&total_key);
+        for i in 0..256 {
+            let key: Vec<u8> = repeat(i as u8).take(32).collect();
+            let msg: Vec<u8> = repeat(i as u8).take(256).collect();
+            let mut mac = [0u8; 16];
+            poly1305(&key[..], &msg[0..i], &mut mac);
+            tpoly.input(&mac);
+        }
+        tpoly.raw_result(&mut mac);
+        assert_eq!(&mac[..], &total_mac[..]);
+    }
+
+    #[test]
+    fn test_tls_vectors() {
+        // from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
+        let key = b"this is 32-byte key for Poly1305";
+        let msg = [0u8; 32];
+        let expected = [
+            0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6,
+            0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07,
+        ];
+        let mut mac = [0u8; 16];
+        poly1305(key, &msg, &mut mac);
+        assert_eq!(&mac[..], &expected[..]);
+
+        let msg = b"Hello world!";
+        let expected= [
+            0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16,
+            0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0,
+        ];
+        poly1305(key, msg, &mut mac);
+        assert_eq!(&mac[..], &expected[..]);
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use mac::Mac;
+    use poly1305::Poly1305;
+
+    #[bench]
+    pub fn poly1305_10(bh: & mut Bencher) {
+        let mut mac = [0u8; 16];
+        let key     = [0u8; 32];
+        let bytes   = [1u8; 10];
+        bh.iter( || {
+            let mut poly = Poly1305::new(&key);
+            poly.input(&bytes);
+            poly.raw_result(&mut mac);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn poly1305_1k(bh: & mut Bencher) {
+        let mut mac = [0u8; 16];
+        let key     = [0u8; 32];
+        let bytes   = [1u8; 1024];
+        bh.iter( || {
+            let mut poly = Poly1305::new(&key);
+            poly.input(&bytes);
+            poly.raw_result(&mut mac);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn poly1305_64k(bh: & mut Bencher) {
+        let mut mac = [0u8; 16];
+        let key     = [0u8; 32];
+        let bytes   = [1u8; 65536];
+        bh.iter( || {
+            let mut poly = Poly1305::new(&key);
+            poly.input(&bytes);
+            poly.raw_result(&mut mac);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/rc4.rs b/third_party/rust-crypto/src/rc4.rs
new file mode 100644
index 0000000..016115c
--- /dev/null
+++ b/third_party/rust-crypto/src/rc4.rs
@@ -0,0 +1,155 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * An implementation of the RC4 (also sometimes called ARC4) stream cipher. THIS IMPLEMENTATION IS
+ * NOT A FIXED TIME IMPLEMENTATION.
+ */
+
+use buffer::{BufferResult, RefReadBuffer, RefWriteBuffer};
+use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher, SymmetricCipherError};
+use cryptoutil::symm_enc_or_dec;
+
+#[derive(Copy)]
+pub struct Rc4 {
+    i: u8,
+    j: u8,
+    state: [u8; 256]
+}
+
+impl Clone for Rc4 { fn clone(&self) -> Rc4 { *self } }
+
+impl Rc4 {
+    pub fn new(key: &[u8]) -> Rc4 {
+        assert!(key.len() >= 1 && key.len() <= 256);
+        let mut rc4 = Rc4 { i: 0, j: 0, state: [0; 256] };
+        for (i, x) in rc4.state.iter_mut().enumerate() {
+            *x = i as u8;
+        }
+        let mut j: u8 = 0;
+        for i in 0..256 {
+            j = j.wrapping_add(rc4.state[i]).wrapping_add(key[i % key.len()]);
+            rc4.state.swap(i, j as usize);
+        }
+        rc4
+    }
+    fn next(&mut self) -> u8 {
+        self.i = self.i.wrapping_add(1);
+        self.j = self.j.wrapping_add(self.state[self.i as usize]);
+        self.state.swap(self.i as usize, self.j as usize);
+        let k = self.state[(self.state[self.i as usize].wrapping_add(self.state[self.j as usize])) as usize];
+        k
+    }
+}
+
+impl SynchronousStreamCipher for Rc4 {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == output.len());
+        for (x, y) in input.iter().zip(output.iter_mut()) {
+            *y = *x ^ self.next();
+        }
+    }
+}
+
+impl Encryptor for Rc4 {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl Decryptor for Rc4 {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use symmetriccipher::SynchronousStreamCipher;
+    use rc4::Rc4;
+
+    struct Test {
+        key: &'static str,
+        input: &'static str,
+        output: Vec<u8>
+    }
+
+    fn tests() -> Vec<Test> {
+        vec![
+            Test {
+                key: "Key",
+                input: "Plaintext",
+                output: vec![0xBB, 0xF3, 0x16, 0xE8, 0xD9, 0x40, 0xAF, 0x0A, 0xD3]
+            },
+            Test {
+                key: "Wiki",
+                input: "pedia",
+                output: vec![0x10, 0x21, 0xBF, 0x04, 0x20]
+            },
+            Test {
+                key: "Secret",
+                input: "Attack at dawn",
+                output: vec![0x45, 0xA0, 0x1F, 0x64, 0x5F, 0xC3, 0x5B,
+                          0x38, 0x35, 0x52, 0x54, 0x4B, 0x9B, 0xF5]
+            }
+        ]
+    }
+
+    #[test]
+    fn wikipedia_tests() {
+        let tests = tests();
+        for t in tests.iter() {
+            let mut rc4 = Rc4::new(t.key.as_bytes());
+            let mut result: Vec<u8> = repeat(0).take(t.output.len()).collect();
+            rc4.process(t.input.as_bytes(), &mut result);
+            assert!(result == t.output);
+        }
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use symmetriccipher::SynchronousStreamCipher;
+    use rc4::Rc4;
+
+    #[bench]
+    pub fn rc4_10(bh: & mut Bencher) {
+        let mut rc4 = Rc4::new("key".as_bytes());
+        let input = [1u8; 10];
+        let mut output = [0u8; 10];
+        bh.iter( || {
+            rc4.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn rc4_1k(bh: & mut Bencher) {
+        let mut rc4 = Rc4::new("key".as_bytes());
+        let input = [1u8; 1024];
+        let mut output = [0u8; 1024];
+        bh.iter( || {
+            rc4.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn rc4_64k(bh: & mut Bencher) {
+        let mut rc4 = Rc4::new("key".as_bytes());
+        let input = [1u8; 65536];
+        let mut output = [0u8; 65536];
+        bh.iter( || {
+            rc4.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/ripemd160.rs b/third_party/rust-crypto/src/ripemd160.rs
new file mode 100644
index 0000000..a727335
--- /dev/null
+++ b/third_party/rust-crypto/src/ripemd160.rs
@@ -0,0 +1,562 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * An implementation of the RIPEMD-160 cryptographic hash.
+ *
+ * First create a `Ripemd160` object using the `Ripemd160` constructor,
+ * then feed it input using the `input` or `input_str` methods, which
+ * may be called any number of times.
+ *
+ * After the entire input has been fed to the hash read the result using
+ * the `result` or `result_str` methods.
+ *
+ * The `Ripemd160` object may be reused to create multiple hashes by
+ * calling the `reset` method.
+ */
+
+
+use cryptoutil::{write_u32_le, read_u32v_le, add_bytes_to_bits, FixedBuffer,
+    FixedBuffer64, StandardPadding};
+use digest::Digest;
+
+// Some unexported constants
+const DIGEST_BUF_LEN: usize = 5;
+const WORK_BUF_LEN: usize = 16;
+
+/// Structure representing the state of a Ripemd160 computation
+#[derive(Clone, Copy)]
+pub struct Ripemd160 {
+    h: [u32; DIGEST_BUF_LEN],
+    length_bits: u64,
+    buffer: FixedBuffer64,
+    computed: bool,
+}
+
+fn circular_shift(bits: u32, word: u32) -> u32 {
+    word << bits as usize | word >> (32u32 - bits) as usize
+}
+
+macro_rules! round(
+    ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr,
+     $x:expr, $bits:expr, $add:expr, $round:expr) => ({
+        $a = $a.wrapping_add($round).wrapping_add($x).wrapping_add($add);
+        $a = circular_shift($bits, $a).wrapping_add($e);
+        $c = circular_shift(10, $c);
+    });
+);
+
+macro_rules! process_block(
+    ($h:ident, $data:expr,
+     $( round1: h_ordering $f0:expr, $f1:expr, $f2:expr, $f3:expr, $f4:expr;
+                data_index $data_index1:expr; roll_shift $bits1:expr )*;
+     $( round2: h_ordering $g0:expr, $g1:expr, $g2:expr, $g3:expr, $g4:expr;
+                data_index $data_index2:expr; roll_shift $bits2:expr )*;
+     $( round3: h_ordering $h0:expr, $h1:expr, $h2:expr, $h3:expr, $h4:expr;
+                data_index $data_index3:expr; roll_shift $bits3:expr )*;
+     $( round4: h_ordering $i0:expr, $i1:expr, $i2:expr, $i3:expr, $i4:expr;
+                data_index $data_index4:expr; roll_shift $bits4:expr )*;
+     $( round5: h_ordering $j0:expr, $j1:expr, $j2:expr, $j3:expr, $j4:expr;
+                data_index $data_index5:expr; roll_shift $bits5:expr )*;
+     $( par_round1: h_ordering $pj0:expr, $pj1:expr, $pj2:expr, $pj3:expr, $pj4:expr;
+                    data_index $pdata_index1:expr; roll_shift $pbits1:expr )*;
+     $( par_round2: h_ordering $pi0:expr, $pi1:expr, $pi2:expr, $pi3:expr, $pi4:expr;
+                    data_index $pdata_index2:expr; roll_shift $pbits2:expr )*;
+     $( par_round3: h_ordering $ph0:expr, $ph1:expr, $ph2:expr, $ph3:expr, $ph4:expr;
+                    data_index $pdata_index3:expr; roll_shift $pbits3:expr )*;
+     $( par_round4: h_ordering $pg0:expr, $pg1:expr, $pg2:expr, $pg3:expr, $pg4:expr;
+                    data_index $pdata_index4:expr; roll_shift $pbits4:expr )*;
+     $( par_round5: h_ordering $pf0:expr, $pf1:expr, $pf2:expr, $pf3:expr, $pf4:expr;
+                    data_index $pdata_index5:expr; roll_shift $pbits5:expr )*;
+    ) => ({
+        let mut bb = *$h;
+        let mut bbb = *$h;
+
+        // Round 1
+        $( round!(bb[$f0], bb[$f1], bb[$f2], bb[$f3], bb[$f4],
+                  $data[$data_index1], $bits1, 0x00000000,
+                  bb[$f1] ^ bb[$f2] ^ bb[$f3]); )*
+
+        // Round 2
+        $( round!(bb[$g0], bb[$g1], bb[$g2], bb[$g3], bb[$g4],
+                  $data[$data_index2], $bits2, 0x5a827999,
+                  (bb[$g1] & bb[$g2]) | (!bb[$g1] & bb[$g3])); )*
+
+        // Round 3
+        $( round!(bb[$h0], bb[$h1], bb[$h2], bb[$h3], bb[$h4],
+                  $data[$data_index3], $bits3, 0x6ed9eba1,
+                  (bb[$h1] | !bb[$h2]) ^ bb[$h3]); )*
+
+        // Round 4
+        $( round!(bb[$i0], bb[$i1], bb[$i2], bb[$i3], bb[$i4],
+                  $data[$data_index4], $bits4, 0x8f1bbcdc,
+                  (bb[$i1] & bb[$i3]) | (bb[$i2] & !bb[$i3])); )*
+
+        // Round 5
+        $( round!(bb[$j0], bb[$j1], bb[$j2], bb[$j3], bb[$j4],
+                  $data[$data_index5], $bits5, 0xa953fd4e,
+                  bb[$j1] ^ (bb[$j2] | !bb[$j3])); )*
+
+        // Parallel rounds: these are the same as the previous five
+        // rounds except that the constants have changed, we work
+        // with the other buffer, and they are applied in reverse
+        // order.
+
+        // Parallel Round 1
+        $( round!(bbb[$pj0], bbb[$pj1], bbb[$pj2], bbb[$pj3], bbb[$pj4],
+                  $data[$pdata_index1], $pbits1, 0x50a28be6,
+                  bbb[$pj1] ^ (bbb[$pj2] | !bbb[$pj3])); )*
+
+        // Parallel Round 2
+        $( round!(bbb[$pi0], bbb[$pi1], bbb[$pi2], bbb[$pi3], bbb[$pi4],
+                  $data[$pdata_index2], $pbits2, 0x5c4dd124,
+                  (bbb[$pi1] & bbb[$pi3]) | (bbb[$pi2] & !bbb[$pi3])); )*
+
+        // Parallel Round 3
+        $( round!(bbb[$ph0], bbb[$ph1], bbb[$ph2], bbb[$ph3], bbb[$ph4],
+                  $data[$pdata_index3], $pbits3, 0x6d703ef3,
+                  (bbb[$ph1] | !bbb[$ph2]) ^ bbb[$ph3]); )*
+
+        // Parallel Round 4
+        $( round!(bbb[$pg0], bbb[$pg1], bbb[$pg2], bbb[$pg3], bbb[$pg4],
+                  $data[$pdata_index4], $pbits4, 0x7a6d76e9,
+                  (bbb[$pg1] & bbb[$pg2]) | (!bbb[$pg1] & bbb[$pg3])); )*
+
+        // Parallel Round 5
+        $( round!(bbb[$pf0], bbb[$pf1], bbb[$pf2], bbb[$pf3], bbb[$pf4],
+                  $data[$pdata_index5], $pbits5, 0x00000000,
+                  bbb[$pf1] ^ bbb[$pf2] ^ bbb[$pf3]); )*
+
+        // Combine results
+        bbb[3] = bbb[3].wrapping_add($h[1]).wrapping_add(bb[2]);
+        $h[1]   = $h[2].wrapping_add(bb[3]).wrapping_add(bbb[4]);
+        $h[2]   = $h[3].wrapping_add(bb[4]).wrapping_add(bbb[0]);
+        $h[3]   = $h[4].wrapping_add(bb[0]).wrapping_add(bbb[1]);
+        $h[4]   = $h[0].wrapping_add(bb[1]).wrapping_add(bbb[2]);
+        $h[0]   =                 bbb[3];
+    });
+);
+
+fn process_msg_block(data: &[u8], h: &mut [u32; DIGEST_BUF_LEN]) {
+    let mut w = [0u32; WORK_BUF_LEN];
+    read_u32v_le(&mut w[0..16], data);
+    process_block!(h, w[..],
+        // Round 1
+        round1: h_ordering 0, 1, 2, 3, 4; data_index  0; roll_shift 11
+        round1: h_ordering 4, 0, 1, 2, 3; data_index  1; roll_shift 14
+        round1: h_ordering 3, 4, 0, 1, 2; data_index  2; roll_shift 15
+        round1: h_ordering 2, 3, 4, 0, 1; data_index  3; roll_shift 12
+        round1: h_ordering 1, 2, 3, 4, 0; data_index  4; roll_shift  5
+        round1: h_ordering 0, 1, 2, 3, 4; data_index  5; roll_shift  8
+        round1: h_ordering 4, 0, 1, 2, 3; data_index  6; roll_shift  7
+        round1: h_ordering 3, 4, 0, 1, 2; data_index  7; roll_shift  9
+        round1: h_ordering 2, 3, 4, 0, 1; data_index  8; roll_shift 11
+        round1: h_ordering 1, 2, 3, 4, 0; data_index  9; roll_shift 13
+        round1: h_ordering 0, 1, 2, 3, 4; data_index 10; roll_shift 14
+        round1: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 15
+        round1: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift  6
+        round1: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift  7
+        round1: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift  9
+        round1: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift  8;
+
+        // Round 2
+        round2: h_ordering 4, 0, 1, 2, 3; data_index  7; roll_shift  7
+        round2: h_ordering 3, 4, 0, 1, 2; data_index  4; roll_shift  6
+        round2: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift  8
+        round2: h_ordering 1, 2, 3, 4, 0; data_index  1; roll_shift 13
+        round2: h_ordering 0, 1, 2, 3, 4; data_index 10; roll_shift 11
+        round2: h_ordering 4, 0, 1, 2, 3; data_index  6; roll_shift  9
+        round2: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift  7
+        round2: h_ordering 2, 3, 4, 0, 1; data_index  3; roll_shift 15
+        round2: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift  7
+        round2: h_ordering 0, 1, 2, 3, 4; data_index  0; roll_shift 12
+        round2: h_ordering 4, 0, 1, 2, 3; data_index  9; roll_shift 15
+        round2: h_ordering 3, 4, 0, 1, 2; data_index  5; roll_shift  9
+        round2: h_ordering 2, 3, 4, 0, 1; data_index  2; roll_shift 11
+        round2: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift  7
+        round2: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 13
+        round2: h_ordering 4, 0, 1, 2, 3; data_index  8; roll_shift 12;
+
+        // Round 3
+        round3: h_ordering 3, 4, 0, 1, 2; data_index  3; roll_shift 11
+        round3: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 13
+        round3: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift  6
+        round3: h_ordering 0, 1, 2, 3, 4; data_index  4; roll_shift  7
+        round3: h_ordering 4, 0, 1, 2, 3; data_index  9; roll_shift 14
+        round3: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift  9
+        round3: h_ordering 2, 3, 4, 0, 1; data_index  8; roll_shift 13
+        round3: h_ordering 1, 2, 3, 4, 0; data_index  1; roll_shift 15
+        round3: h_ordering 0, 1, 2, 3, 4; data_index  2; roll_shift 14
+        round3: h_ordering 4, 0, 1, 2, 3; data_index  7; roll_shift  8
+        round3: h_ordering 3, 4, 0, 1, 2; data_index  0; roll_shift 13
+        round3: h_ordering 2, 3, 4, 0, 1; data_index  6; roll_shift  6
+        round3: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift  5
+        round3: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 12
+        round3: h_ordering 4, 0, 1, 2, 3; data_index  5; roll_shift  7
+        round3: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift  5;
+
+        // Round 4
+        round4: h_ordering 2, 3, 4, 0, 1; data_index  1; roll_shift 11
+        round4: h_ordering 1, 2, 3, 4, 0; data_index  9; roll_shift 12
+        round4: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 14
+        round4: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 15
+        round4: h_ordering 3, 4, 0, 1, 2; data_index  0; roll_shift 14
+        round4: h_ordering 2, 3, 4, 0, 1; data_index  8; roll_shift 15
+        round4: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift  9
+        round4: h_ordering 0, 1, 2, 3, 4; data_index  4; roll_shift  8
+        round4: h_ordering 4, 0, 1, 2, 3; data_index 13; roll_shift  9
+        round4: h_ordering 3, 4, 0, 1, 2; data_index  3; roll_shift 14
+        round4: h_ordering 2, 3, 4, 0, 1; data_index  7; roll_shift  5
+        round4: h_ordering 1, 2, 3, 4, 0; data_index 15; roll_shift  6
+        round4: h_ordering 0, 1, 2, 3, 4; data_index 14; roll_shift  8
+        round4: h_ordering 4, 0, 1, 2, 3; data_index  5; roll_shift  6
+        round4: h_ordering 3, 4, 0, 1, 2; data_index  6; roll_shift  5
+        round4: h_ordering 2, 3, 4, 0, 1; data_index  2; roll_shift 12;
+
+        // Round 5
+        round5: h_ordering 1, 2, 3, 4, 0; data_index  4; roll_shift  9
+        round5: h_ordering 0, 1, 2, 3, 4; data_index  0; roll_shift 15
+        round5: h_ordering 4, 0, 1, 2, 3; data_index  5; roll_shift  5
+        round5: h_ordering 3, 4, 0, 1, 2; data_index  9; roll_shift 11
+        round5: h_ordering 2, 3, 4, 0, 1; data_index  7; roll_shift  6
+        round5: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift  8
+        round5: h_ordering 0, 1, 2, 3, 4; data_index  2; roll_shift 13
+        round5: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 12
+        round5: h_ordering 3, 4, 0, 1, 2; data_index 14; roll_shift  5
+        round5: h_ordering 2, 3, 4, 0, 1; data_index  1; roll_shift 12
+        round5: h_ordering 1, 2, 3, 4, 0; data_index  3; roll_shift 13
+        round5: h_ordering 0, 1, 2, 3, 4; data_index  8; roll_shift 14
+        round5: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 11
+        round5: h_ordering 3, 4, 0, 1, 2; data_index  6; roll_shift  8
+        round5: h_ordering 2, 3, 4, 0, 1; data_index 15; roll_shift  5
+        round5: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift  6;
+
+        // Parallel Round 1
+        par_round1: h_ordering 0, 1, 2, 3, 4; data_index  5; roll_shift  8
+        par_round1: h_ordering 4, 0, 1, 2, 3; data_index 14; roll_shift  9
+        par_round1: h_ordering 3, 4, 0, 1, 2; data_index  7; roll_shift  9
+        par_round1: h_ordering 2, 3, 4, 0, 1; data_index  0; roll_shift 11
+        par_round1: h_ordering 1, 2, 3, 4, 0; data_index  9; roll_shift 13
+        par_round1: h_ordering 0, 1, 2, 3, 4; data_index  2; roll_shift 15
+        par_round1: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 15
+        par_round1: h_ordering 3, 4, 0, 1, 2; data_index  4; roll_shift  5
+        par_round1: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift  7
+        par_round1: h_ordering 1, 2, 3, 4, 0; data_index  6; roll_shift  7
+        par_round1: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift  8
+        par_round1: h_ordering 4, 0, 1, 2, 3; data_index  8; roll_shift 11
+        par_round1: h_ordering 3, 4, 0, 1, 2; data_index  1; roll_shift 14
+        par_round1: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 14
+        par_round1: h_ordering 1, 2, 3, 4, 0; data_index  3; roll_shift 12
+        par_round1: h_ordering 0, 1, 2, 3, 4; data_index 12; roll_shift  6;
+
+        // Parallel Round 2
+        par_round2: h_ordering 4, 0, 1, 2, 3; data_index  6; roll_shift  9
+        par_round2: h_ordering 3, 4, 0, 1, 2; data_index 11; roll_shift 13
+        par_round2: h_ordering 2, 3, 4, 0, 1; data_index  3; roll_shift 15
+        par_round2: h_ordering 1, 2, 3, 4, 0; data_index  7; roll_shift  7
+        par_round2: h_ordering 0, 1, 2, 3, 4; data_index  0; roll_shift 12
+        par_round2: h_ordering 4, 0, 1, 2, 3; data_index 13; roll_shift  8
+        par_round2: h_ordering 3, 4, 0, 1, 2; data_index  5; roll_shift  9
+        par_round2: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 11
+        par_round2: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift  7
+        par_round2: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift  7
+        par_round2: h_ordering 4, 0, 1, 2, 3; data_index  8; roll_shift 12
+        par_round2: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift  7
+        par_round2: h_ordering 2, 3, 4, 0, 1; data_index  4; roll_shift  6
+        par_round2: h_ordering 1, 2, 3, 4, 0; data_index  9; roll_shift 15
+        par_round2: h_ordering 0, 1, 2, 3, 4; data_index  1; roll_shift 13
+        par_round2: h_ordering 4, 0, 1, 2, 3; data_index  2; roll_shift 11;
+
+        // Parallel Round 3
+        par_round3: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift  9
+        par_round3: h_ordering 2, 3, 4, 0, 1; data_index  5; roll_shift  7
+        par_round3: h_ordering 1, 2, 3, 4, 0; data_index  1; roll_shift 15
+        par_round3: h_ordering 0, 1, 2, 3, 4; data_index  3; roll_shift 11
+        par_round3: h_ordering 4, 0, 1, 2, 3; data_index  7; roll_shift  8
+        par_round3: h_ordering 3, 4, 0, 1, 2; data_index 14; roll_shift  6
+        par_round3: h_ordering 2, 3, 4, 0, 1; data_index  6; roll_shift  6
+        par_round3: h_ordering 1, 2, 3, 4, 0; data_index  9; roll_shift 14
+        par_round3: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 12
+        par_round3: h_ordering 4, 0, 1, 2, 3; data_index  8; roll_shift 13
+        par_round3: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift  5
+        par_round3: h_ordering 2, 3, 4, 0, 1; data_index  2; roll_shift 14
+        par_round3: h_ordering 1, 2, 3, 4, 0; data_index 10; roll_shift 13
+        par_round3: h_ordering 0, 1, 2, 3, 4; data_index  0; roll_shift 13
+        par_round3: h_ordering 4, 0, 1, 2, 3; data_index  4; roll_shift  7
+        par_round3: h_ordering 3, 4, 0, 1, 2; data_index 13; roll_shift  5;
+
+        // Parallel Round 4
+        par_round4: h_ordering 2, 3, 4, 0, 1; data_index  8; roll_shift 15
+        par_round4: h_ordering 1, 2, 3, 4, 0; data_index  6; roll_shift  5
+        par_round4: h_ordering 0, 1, 2, 3, 4; data_index  4; roll_shift  8
+        par_round4: h_ordering 4, 0, 1, 2, 3; data_index  1; roll_shift 11
+        par_round4: h_ordering 3, 4, 0, 1, 2; data_index  3; roll_shift 14
+        par_round4: h_ordering 2, 3, 4, 0, 1; data_index 11; roll_shift 14
+        par_round4: h_ordering 1, 2, 3, 4, 0; data_index 15; roll_shift  6
+        par_round4: h_ordering 0, 1, 2, 3, 4; data_index  0; roll_shift 14
+        par_round4: h_ordering 4, 0, 1, 2, 3; data_index  5; roll_shift  6
+        par_round4: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift  9
+        par_round4: h_ordering 2, 3, 4, 0, 1; data_index  2; roll_shift 12
+        par_round4: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift  9
+        par_round4: h_ordering 0, 1, 2, 3, 4; data_index  9; roll_shift 12
+        par_round4: h_ordering 4, 0, 1, 2, 3; data_index  7; roll_shift  5
+        par_round4: h_ordering 3, 4, 0, 1, 2; data_index 10; roll_shift 15
+        par_round4: h_ordering 2, 3, 4, 0, 1; data_index 14; roll_shift  8;
+
+        // Parallel Round 5
+        par_round5: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift  8
+        par_round5: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift  5
+        par_round5: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 12
+        par_round5: h_ordering 3, 4, 0, 1, 2; data_index  4; roll_shift  9
+        par_round5: h_ordering 2, 3, 4, 0, 1; data_index  1; roll_shift 12
+        par_round5: h_ordering 1, 2, 3, 4, 0; data_index  5; roll_shift  5
+        par_round5: h_ordering 0, 1, 2, 3, 4; data_index  8; roll_shift 14
+        par_round5: h_ordering 4, 0, 1, 2, 3; data_index  7; roll_shift  6
+        par_round5: h_ordering 3, 4, 0, 1, 2; data_index  6; roll_shift  8
+        par_round5: h_ordering 2, 3, 4, 0, 1; data_index  2; roll_shift 13
+        par_round5: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift  6
+        par_round5: h_ordering 0, 1, 2, 3, 4; data_index 14; roll_shift  5
+        par_round5: h_ordering 4, 0, 1, 2, 3; data_index  0; roll_shift 15
+        par_round5: h_ordering 3, 4, 0, 1, 2; data_index  3; roll_shift 13
+        par_round5: h_ordering 2, 3, 4, 0, 1; data_index  9; roll_shift 11
+        par_round5: h_ordering 1, 2, 3, 4, 0; data_index 11; roll_shift 11;
+    );
+}
+
+impl Ripemd160 {
+    // Construct a `Ripemd` object
+    pub fn new() -> Ripemd160 {
+        let mut st = Ripemd160 {
+            h: [0u32; DIGEST_BUF_LEN],
+            length_bits: 0u64,
+            buffer: FixedBuffer64::new(),
+            computed: false,
+        };
+        st.reset();
+        st
+    }
+}
+
+impl Digest for Ripemd160 {
+
+    /**
+     * Resets the hash to its original state also clearing the buffer.
+     * To be used in between hashing separate messages to avoid having
+     * to recreate and allocate the whole structure.
+     */
+    fn reset(&mut self) {
+        self.length_bits = 0;
+        self.h[0] = 0x67452301u32;
+        self.h[1] = 0xefcdab89u32;
+        self.h[2] = 0x98badcfeu32;
+        self.h[3] = 0x10325476u32;
+        self.h[4] = 0xc3d2e1f0u32;
+        self.buffer.reset();
+        self.computed = false;
+    }
+
+    /**
+     * Adds the input `msg` to the hash. This method can be called repeatedly
+     * for use with streaming messages.
+     */
+    fn input(&mut self, msg: &[u8]) {
+        assert!(!self.computed);
+        // Assumes that msg.len() can be converted to u64 without overflow
+        self.length_bits = add_bytes_to_bits(self.length_bits, msg.len() as u64);
+        let st_h = &mut self.h;
+        self.buffer.input(msg, |d: &[u8]| {process_msg_block(d, &mut *st_h);}
+        );
+    }
+
+    /**
+     * Returns the resulting digest of the entire message.
+     * Note: `out` must be at least 20 bytes (160 bits)
+     */
+    fn result(&mut self, out: &mut [u8]) {
+
+        if !self.computed {
+            let st_h = &mut self.h;
+            self.buffer.standard_padding(8, |d: &[u8]| { process_msg_block(d, &mut *st_h) });
+
+            write_u32_le(self.buffer.next(4), self.length_bits as u32);
+            write_u32_le(self.buffer.next(4), (self.length_bits >> 32) as u32 );
+            process_msg_block(self.buffer.full_buffer(), st_h);
+
+            self.computed = true;
+        }
+
+        write_u32_le(&mut out[0..4], self.h[0]);
+        write_u32_le(&mut out[4..8], self.h[1]);
+        write_u32_le(&mut out[8..12], self.h[2]);
+        write_u32_le(&mut out[12..16], self.h[3]);
+        write_u32_le(&mut out[16..20], self.h[4]);
+    }
+
+    /**
+     * Returns the size of the digest in bits
+     */
+    fn output_bits(&self) -> usize { 160 }
+
+    /**
+     * Returns the block size the hash operates on in bytes
+     */
+    fn block_size(&self) -> usize { 64 }
+}
+
+#[cfg(test)]
+mod tests {
+    use cryptoutil::test::test_digest_1million_random;
+    use digest::Digest;
+    use ripemd160::Ripemd160;
+
+    #[derive(Clone)]
+    struct Test {
+        input: &'static str,
+        output: Vec<u8>,
+        output_str: &'static str,
+    }
+
+    #[test]
+    fn test() {
+        let tests = vec![
+            // Test messages from FIPS 180-1
+            Test {
+                input: "abc",
+                output: vec![
+                    0x8eu8, 0xb2u8, 0x08u8, 0xf7u8,
+                    0xe0u8, 0x5du8, 0x98u8, 0x7au8,
+                    0x9bu8, 0x04u8, 0x4au8, 0x8eu8,
+                    0x98u8, 0xc6u8, 0xb0u8, 0x87u8,
+                    0xf1u8, 0x5au8, 0x0bu8, 0xfcu8,
+                ],
+                output_str: "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"
+            },
+            Test {
+                input:
+                     "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+                output: vec![
+                    0x12u8, 0xa0u8, 0x53u8, 0x38u8,
+                    0x4au8, 0x9cu8, 0x0cu8, 0x88u8,
+                    0xe4u8, 0x05u8, 0xa0u8, 0x6cu8,
+                    0x27u8, 0xdcu8, 0xf4u8, 0x9au8,
+                    0xdau8, 0x62u8, 0xebu8, 0x2bu8,
+                ],
+                output_str: "12a053384a9c0c88e405a06c27dcf49ada62eb2b"
+            },
+            // Examples from wikipedia
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output: vec![
+                    0x37u8, 0xf3u8, 0x32u8, 0xf6u8,
+                    0x8du8, 0xb7u8, 0x7bu8, 0xd9u8,
+                    0xd7u8, 0xedu8, 0xd4u8, 0x96u8,
+                    0x95u8, 0x71u8, 0xadu8, 0x67u8,
+                    0x1cu8, 0xf9u8, 0xddu8, 0x3bu8,
+                ],
+                output_str: "37f332f68db77bd9d7edd4969571ad671cf9dd3b",
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy cog",
+                output: vec![
+                    0x13u8, 0x20u8, 0x72u8, 0xdfu8,
+                    0x69u8, 0x09u8, 0x33u8, 0x83u8,
+                    0x5eu8, 0xb8u8, 0xb6u8, 0xadu8,
+                    0x0bu8, 0x77u8, 0xe7u8, 0xb6u8,
+                    0xf1u8, 0x4au8, 0xcau8, 0xd7u8,
+                ],
+                output_str: "132072df690933835eb8b6ad0b77e7b6f14acad7",
+            },
+        ];
+
+        // Test that it works when accepting the message all at once
+
+        let mut out = [0u8; 20];
+
+        let mut sh = Box::new(Ripemd160::new());
+        for t in tests.iter() {
+            (*sh).input_str(t.input);
+            sh.result(&mut out);
+            assert_eq!(&t.output[..], &out[..]);
+
+            let out_str = (*sh).result_str();
+            assert_eq!(out_str.len(), 40);
+            assert_eq!(&out_str[..], t.output_str);
+
+            sh.reset();
+        }
+
+
+        // Test that it works when accepting the message in pieces
+        for t in tests.iter() {
+            let len = t.input.len();
+            let mut left = len;
+            while left > 0 {
+                let take = (left + 1) / 2;
+                (*sh).input_str(&t.input[len - left..take + len - left]);
+                left = left - take;
+            }
+            sh.result(&mut out);
+            assert_eq!(&t.output[..], &out[..]);
+
+            let out_str = (*sh).result_str();
+            assert_eq!(out_str.len(), 40);
+            assert!(&out_str[..] == t.output_str);
+
+            sh.reset();
+        }
+    }
+
+    #[test]
+    fn test_1million_random_ripemd160() {
+        let mut sh = Ripemd160::new();
+        test_digest_1million_random(
+            &mut sh,
+            64,
+            "52783243c1697bdbe16d37f97f68f08325dc1528");
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use digest::Digest;
+    use ripemd160::Ripemd160;
+
+    #[bench]
+    pub fn ripemd160_10(bh: & mut Bencher) {
+        let mut sh = Ripemd160::new();
+        let bytes = [1u8; 10];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn ripemd160_1k(bh: & mut Bencher) {
+        let mut sh = Ripemd160::new();
+        let bytes = [1u8; 1024];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn ripemd160_64k(bh: & mut Bencher) {
+        let mut sh = Ripemd160::new();
+        let bytes = [1u8; 65536];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+}
diff --git a/third_party/rust-crypto/src/salsa20.rs b/third_party/rust-crypto/src/salsa20.rs
new file mode 100644
index 0000000..de8b263
--- /dev/null
+++ b/third_party/rust-crypto/src/salsa20.rs
@@ -0,0 +1,410 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use buffer::{BufferResult, RefReadBuffer, RefWriteBuffer};
+use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher, SymmetricCipherError};
+use cryptoutil::{read_u32_le, symm_enc_or_dec, write_u32_le, xor_keystream};
+use simd::u32x4;
+
+use std::cmp;
+
+#[derive(Clone, Copy)]
+struct SalsaState {
+  a: u32x4,
+  b: u32x4,
+  c: u32x4,
+  d: u32x4
+}
+
+#[derive(Copy)]
+pub struct Salsa20 {
+    state: SalsaState,
+    output: [u8; 64],
+    offset: usize,
+}
+
+impl Clone for Salsa20 { fn clone(&self) -> Salsa20 { *self } }
+
+const S7:u32x4 = u32x4(7, 7, 7, 7);
+const S9:u32x4 = u32x4(9, 9, 9, 9);
+const S13:u32x4 = u32x4(13, 13, 13, 13);
+const S18:u32x4 = u32x4(18, 18, 18, 18);
+const S32:u32x4 = u32x4(32, 32, 32, 32);
+
+macro_rules! prepare_rowround {
+    ($a: expr, $b: expr, $c: expr) => {{
+        let u32x4(a10, a11, a12, a13) = $a;
+        $a = u32x4(a13, a10, a11, a12);
+        let u32x4(b10, b11, b12, b13) = $b;
+        $b = u32x4(b12, b13, b10, b11);
+        let u32x4(c10, c11, c12, c13) = $c;
+        $c = u32x4(c11, c12, c13, c10);
+    }}
+}
+
+macro_rules! prepare_columnround {
+    ($a: expr, $b: expr, $c: expr) => {{
+        let u32x4(a13, a10, a11, a12) = $a;
+        $a = u32x4(a10, a11, a12, a13);
+        let u32x4(b12, b13, b10, b11) = $b;
+        $b = u32x4(b10, b11, b12, b13);
+        let u32x4(c11, c12, c13, c10) = $c;
+        $c = u32x4(c10, c11, c12, c13);
+    }}
+}
+
+macro_rules! add_rotate_xor {
+    ($dst: expr, $a: expr, $b: expr, $shift: expr) => {{
+        let v = $a + $b;
+        let r = S32 - $shift;
+        let right = v >> r;
+        $dst = $dst ^ (v << $shift) ^ right
+    }}
+}
+
+fn columnround(state: &mut SalsaState) -> () {
+    add_rotate_xor!(state.a, state.d, state.c, S7);
+    add_rotate_xor!(state.b, state.a, state.d, S9);
+    add_rotate_xor!(state.c, state.b, state.a, S13);
+    add_rotate_xor!(state.d, state.c, state.b, S18);
+}
+
+fn rowround(state: &mut SalsaState) -> () {
+    add_rotate_xor!(state.c, state.d, state.a, S7);
+    add_rotate_xor!(state.b, state.c, state.d, S9);
+    add_rotate_xor!(state.a, state.c, state.b, S13);
+    add_rotate_xor!(state.d, state.a, state.b, S18);
+}
+
+impl Salsa20 {
+    pub fn new(key: &[u8], nonce: &[u8]) -> Salsa20 {
+        assert!(key.len() == 16 || key.len() == 32);
+        assert!(nonce.len() == 8);
+        Salsa20 { state: Salsa20::expand(key, nonce), output: [0; 64], offset: 64 }
+    }
+
+    pub fn new_xsalsa20(key: &[u8], nonce: &[u8]) -> Salsa20 {
+        assert!(key.len() == 32);
+        assert!(nonce.len() == 24);
+        let mut xsalsa20 = Salsa20 { state: Salsa20::expand(key, &nonce[0..16]), output: [0; 64], offset: 64 };
+
+        let mut new_key = [0; 32];
+        xsalsa20.hsalsa20_hash(&mut new_key);
+        xsalsa20.state = Salsa20::expand(&new_key, &nonce[16..24]);
+
+        xsalsa20
+    }
+
+    fn expand(key: &[u8], nonce: &[u8]) -> SalsaState {
+        let constant = match key.len() {
+            16 => b"expand 16-byte k",
+            32 => b"expand 32-byte k",
+            _  => unreachable!(),
+        };
+
+        // The state vectors are laid out to facilitate SIMD operation,
+        // instead of the natural matrix ordering.
+        //
+        //  * Constant (x0, x5, x10, x15)
+        //  * Key (x1, x2, x3, x4, x11, x12, x13, x14)
+        //  * Input (x6, x7, x8, x9)
+
+        let key_tail; // (x11, x12, x13, x14)
+        if key.len() == 16 {
+            key_tail = key;
+        } else {
+            key_tail = &key[16..32];
+        }
+
+        let x8; let x9; // (x8, x9)
+        if nonce.len() == 16 {
+            // HSalsa uses the full 16 byte nonce.
+            x8 = read_u32_le(&nonce[8..12]);
+            x9 = read_u32_le(&nonce[12..16]);
+        } else {
+            x8 = 0;
+            x9 = 0;
+        }
+
+        SalsaState {
+            a: u32x4(
+                read_u32_le(&key[12..16]),      // x4
+                x9,                             // x9
+                read_u32_le(&key_tail[12..16]), // x14
+                read_u32_le(&key[8..12]),       // x3
+            ),
+            b: u32x4(
+                x8,                             // x8
+                read_u32_le(&key_tail[8..12]),  // x13
+                read_u32_le(&key[4..8]),        // x2
+                read_u32_le(&nonce[4..8])       // x7
+            ),
+            c: u32x4(
+                read_u32_le(&key_tail[4..8]),   // x12
+                read_u32_le(&key[0..4]),        // x1
+                read_u32_le(&nonce[0..4]),      // x6
+                read_u32_le(&key_tail[0..4])    // x11
+            ),
+            d: u32x4(
+                read_u32_le(&constant[0..4]),   // x0
+                read_u32_le(&constant[4..8]),   // x5
+                read_u32_le(&constant[8..12]),  // x10
+                read_u32_le(&constant[12..16]), // x15
+            )
+        }
+    }
+
+    fn hash(&mut self) {
+        let mut state = self.state;
+        for _ in 0..10 {
+            columnround(&mut state);
+            prepare_rowround!(state.a, state.b, state.c);
+            rowround(&mut state);
+            prepare_columnround!(state.a, state.b, state.c);
+        }
+        let u32x4(x4, x9, x14, x3) = self.state.a + state.a;
+        let u32x4(x8, x13, x2, x7) = self.state.b + state.b;
+        let u32x4(x12, x1, x6, x11) = self.state.c + state.c;
+        let u32x4(x0, x5, x10, x15) = self.state.d + state.d;
+        let lens = [
+             x0,  x1,  x2,  x3,
+             x4,  x5,  x6,  x7,
+             x8,  x9, x10, x11,
+            x12, x13, x14, x15
+        ];
+        for i in 0..lens.len() {
+            write_u32_le(&mut self.output[i*4..(i+1)*4], lens[i]);
+        }
+
+        self.state.b = self.state.b + u32x4(1, 0, 0, 0);
+        let u32x4(_, _, _, ctr_lo) = self.state.b;
+        if ctr_lo == 0 {
+            self.state.a = self.state.a + u32x4(0, 1, 0, 0);
+        }
+
+        self.offset = 0;
+    }
+
+    fn hsalsa20_hash(&mut self, out: &mut [u8]) {
+        let mut state = self.state;
+        for _ in 0..10 {
+            columnround(&mut state);
+            prepare_rowround!(state.a, state.b, state.c);
+            rowround(&mut state);
+            prepare_columnround!(state.a, state.b, state.c);
+        }
+        let u32x4(_, x9, _, _) = state.a;
+        let u32x4(x8, _, _, x7) = state.b;
+        let u32x4(_, _, x6, _) = state.c;
+        let u32x4(x0, x5, x10, x15) = state.d;
+        let lens = [
+            x0, x5, x10, x15,
+            x6, x7, x8, x9
+        ];
+        for i in 0..lens.len() {
+            write_u32_le(&mut out[i*4..(i+1)*4], lens[i]);
+        }
+    }
+}
+
+impl SynchronousStreamCipher for Salsa20 {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == output.len());
+        let len = input.len();
+        let mut i = 0;
+        while i < len {
+            // If there is no keystream available in the output buffer,
+            // generate the next block.
+            if self.offset == 64 {
+                self.hash();
+            }
+
+            // Process the min(available keystream, remaining input length).
+            let count = cmp::min(64 - self.offset, len - i);
+            xor_keystream(&mut output[i..i+count], &input[i..i+count], &self.output[self.offset..]);
+            i += count;
+            self.offset += count;
+        }
+    }
+}
+
+impl Encryptor for Salsa20 {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl Decryptor for Salsa20 {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+pub fn hsalsa20(key: &[u8], nonce: &[u8], out: &mut [u8]) {
+    assert!(key.len() == 32);
+    assert!(nonce.len() == 16);
+    let mut h = Salsa20 { state: Salsa20::expand(key, nonce), output: [0; 64], offset: 64 };
+    h.hsalsa20_hash(out);
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use salsa20::Salsa20;
+    use symmetriccipher::SynchronousStreamCipher;
+
+    use digest::Digest;
+    use sha2::Sha256;
+
+    #[test]
+    fn test_salsa20_128bit_ecrypt_set_1_vector_0() {
+        let key = [128u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+        let nonce = [0u8; 8];
+        let input = [0u8; 64];
+        let mut stream = [0u8; 64];
+        let result =
+            [0x4D, 0xFA, 0x5E, 0x48, 0x1D, 0xA2, 0x3E, 0xA0,
+             0x9A, 0x31, 0x02, 0x20, 0x50, 0x85, 0x99, 0x36,
+             0xDA, 0x52, 0xFC, 0xEE, 0x21, 0x80, 0x05, 0x16,
+             0x4F, 0x26, 0x7C, 0xB6, 0x5F, 0x5C, 0xFD, 0x7F,
+             0x2B, 0x4F, 0x97, 0xE0, 0xFF, 0x16, 0x92, 0x4A,
+             0x52, 0xDF, 0x26, 0x95, 0x15, 0x11, 0x0A, 0x07,
+             0xF9, 0xE4, 0x60, 0xBC, 0x65, 0xEF, 0x95, 0xDA,
+             0x58, 0xF7, 0x40, 0xB7, 0xD1, 0xDB, 0xB0, 0xAA];
+
+        let mut salsa20 = Salsa20::new(&key, &nonce);
+        salsa20.process(&input, &mut stream);
+        assert!(stream[..] == result[..]);
+    }
+
+    #[test]
+    fn test_salsa20_256bit_ecrypt_set_1_vector_0() {
+        let key =
+            [128u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+        let nonce = [0u8; 8];
+        let input = [0u8; 64];
+        let mut stream = [0u8; 64];
+        let result =
+            [0xE3, 0xBE, 0x8F, 0xDD, 0x8B, 0xEC, 0xA2, 0xE3,
+             0xEA, 0x8E, 0xF9, 0x47, 0x5B, 0x29, 0xA6, 0xE7,
+             0x00, 0x39, 0x51, 0xE1, 0x09, 0x7A, 0x5C, 0x38,
+             0xD2, 0x3B, 0x7A, 0x5F, 0xAD, 0x9F, 0x68, 0x44,
+             0xB2, 0x2C, 0x97, 0x55, 0x9E, 0x27, 0x23, 0xC7,
+             0xCB, 0xBD, 0x3F, 0xE4, 0xFC, 0x8D, 0x9A, 0x07,
+             0x44, 0x65, 0x2A, 0x83, 0xE7, 0x2A, 0x9C, 0x46,
+             0x18, 0x76, 0xAF, 0x4D, 0x7E, 0xF1, 0xA1, 0x17];
+
+        let mut salsa20 = Salsa20::new(&key, &nonce);
+        salsa20.process(&input, &mut stream);
+        assert!(stream[..] == result[..]);
+    }
+
+    #[test]
+    fn test_salsa20_256bit_nacl_vector_2() {
+        let key = [
+            0xdc,0x90,0x8d,0xda,0x0b,0x93,0x44,0xa9,
+            0x53,0x62,0x9b,0x73,0x38,0x20,0x77,0x88,
+            0x80,0xf3,0xce,0xb4,0x21,0xbb,0x61,0xb9,
+            0x1c,0xbd,0x4c,0x3e,0x66,0x25,0x6c,0xe4
+        ];
+        let nonce = [
+            0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
+        ];
+        let input: Vec<u8> = repeat(0).take(4194304).collect();
+        let mut stream: Vec<u8> = repeat(0).take(input.len()).collect();
+        let output_str = "662b9d0e3463029156069b12f918691a98f7dfb2ca0393c96bbfc6b1fbd630a2";
+
+        let mut salsa20 = Salsa20::new(&key, &nonce);
+        salsa20.process(input.as_ref(), &mut stream);
+
+        let mut sh = Sha256::new();
+        sh.input(stream.as_ref());
+        let out_str = sh.result_str();
+        assert!(&out_str[..] == output_str);
+    }
+
+    #[test]
+    fn test_xsalsa20_cryptopp() {
+        let key =
+            [0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4,
+             0x62, 0xcd, 0x51, 0x19, 0x7a, 0x9a, 0x46, 0xc7,
+             0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2,
+             0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89];
+        let nonce =
+            [0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73,
+             0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6,
+             0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37];
+        let input = [0u8; 139];
+        let mut stream = [0u8; 139];
+        let result =
+            [0xee, 0xa6, 0xa7, 0x25, 0x1c, 0x1e, 0x72, 0x91,
+             0x6d, 0x11, 0xc2, 0xcb, 0x21, 0x4d, 0x3c, 0x25,
+             0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65,
+             0x2d, 0x65, 0x1f, 0xa4, 0xc8, 0xcf, 0xf8, 0x80,
+             0x30, 0x9e, 0x64, 0x5a, 0x74, 0xe9, 0xe0, 0xa6,
+             0x0d, 0x82, 0x43, 0xac, 0xd9, 0x17, 0x7a, 0xb5,
+             0x1a, 0x1b, 0xeb, 0x8d, 0x5a, 0x2f, 0x5d, 0x70,
+             0x0c, 0x09, 0x3c, 0x5e, 0x55, 0x85, 0x57, 0x96,
+             0x25, 0x33, 0x7b, 0xd3, 0xab, 0x61, 0x9d, 0x61,
+             0x57, 0x60, 0xd8, 0xc5, 0xb2, 0x24, 0xa8, 0x5b,
+             0x1d, 0x0e, 0xfe, 0x0e, 0xb8, 0xa7, 0xee, 0x16,
+             0x3a, 0xbb, 0x03, 0x76, 0x52, 0x9f, 0xcc, 0x09,
+             0xba, 0xb5, 0x06, 0xc6, 0x18, 0xe1, 0x3c, 0xe7,
+             0x77, 0xd8, 0x2c, 0x3a, 0xe9, 0xd1, 0xa6, 0xf9,
+             0x72, 0xd4, 0x16, 0x02, 0x87, 0xcb, 0xfe, 0x60,
+             0xbf, 0x21, 0x30, 0xfc, 0x0a, 0x6f, 0xf6, 0x04,
+             0x9d, 0x0a, 0x5c, 0x8a, 0x82, 0xf4, 0x29, 0x23,
+             0x1f, 0x00, 0x80];
+
+        let mut xsalsa20 = Salsa20::new_xsalsa20(&key, &nonce);
+        xsalsa20.process(&input, &mut stream);
+        assert!(stream[..] == result[..]);
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use symmetriccipher::SynchronousStreamCipher;
+    use salsa20::Salsa20;
+
+    #[bench]
+    pub fn salsa20_10(bh: & mut Bencher) {
+        let mut salsa20 = Salsa20::new(&[0; 32], &[0; 8]);
+        let input = [1u8; 10];
+        let mut output = [0u8; 10];
+        bh.iter( || {
+            salsa20.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn salsa20_1k(bh: & mut Bencher) {
+        let mut salsa20 = Salsa20::new(&[0; 32], &[0; 8]);
+        let input = [1u8; 1024];
+        let mut output = [0u8; 1024];
+        bh.iter( || {
+            salsa20.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn salsa20_64k(bh: & mut Bencher) {
+        let mut salsa20 = Salsa20::new(&[0; 32], &[0; 8]);
+        let input = [1u8; 65536];
+        let mut output = [0u8; 65536];
+        bh.iter( || {
+            salsa20.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/scrypt.rs b/third_party/rust-crypto/src/scrypt.rs
new file mode 100644
index 0000000..399b35f
--- /dev/null
+++ b/third_party/rust-crypto/src/scrypt.rs
@@ -0,0 +1,532 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * This module implements the Scrypt key derivation function as specified in [1].
+ *
+ * # References
+ * [1] - C. Percival. Stronger Key Derivation Via Sequential Memory-Hard Functions.
+ *       http://www.tarsnap.com/scrypt/scrypt.pdf
+ */
+
+use std;
+use std::iter::repeat;
+use std::io;
+use std::mem::size_of;
+use std::prelude::v1::*;
+use cryptoutil::copy_memory;
+
+use sgx_rand::{thread_rng, Rng};
+use serialize::base64;
+use serialize::base64::{FromBase64, ToBase64};
+
+use cryptoutil::{read_u32_le, read_u32v_le, write_u32_le};
+use hmac::Hmac;
+use pbkdf2::pbkdf2;
+use sha2::Sha256;
+use util::fixed_time_eq;
+
+// The salsa20/8 core function.
+fn salsa20_8(input: &[u8], output: &mut [u8]) {
+
+    let mut x = [0u32; 16];
+    read_u32v_le(&mut x, input);
+
+    let rounds = 8;
+
+    macro_rules! run_round (
+        ($($set_idx:expr, $idx_a:expr, $idx_b:expr, $rot:expr);*) => { {
+            $( x[$set_idx] ^= x[$idx_a].wrapping_add(x[$idx_b]).rotate_left($rot); )*
+        } }
+    );
+
+    for _ in 0..rounds / 2 {
+        run_round!(
+            0x4, 0x0, 0xc, 7;
+            0x8, 0x4, 0x0, 9;
+            0xc, 0x8, 0x4, 13;
+            0x0, 0xc, 0x8, 18;
+            0x9, 0x5, 0x1, 7;
+            0xd, 0x9, 0x5, 9;
+            0x1, 0xd, 0x9, 13;
+            0x5, 0x1, 0xd, 18;
+            0xe, 0xa, 0x6, 7;
+            0x2, 0xe, 0xa, 9;
+            0x6, 0x2, 0xe, 13;
+            0xa, 0x6, 0x2, 18;
+            0x3, 0xf, 0xb, 7;
+            0x7, 0x3, 0xf, 9;
+            0xb, 0x7, 0x3, 13;
+            0xf, 0xb, 0x7, 18;
+            0x1, 0x0, 0x3, 7;
+            0x2, 0x1, 0x0, 9;
+            0x3, 0x2, 0x1, 13;
+            0x0, 0x3, 0x2, 18;
+            0x6, 0x5, 0x4, 7;
+            0x7, 0x6, 0x5, 9;
+            0x4, 0x7, 0x6, 13;
+            0x5, 0x4, 0x7, 18;
+            0xb, 0xa, 0x9, 7;
+            0x8, 0xb, 0xa, 9;
+            0x9, 0x8, 0xb, 13;
+            0xa, 0x9, 0x8, 18;
+            0xc, 0xf, 0xe, 7;
+            0xd, 0xc, 0xf, 9;
+            0xe, 0xd, 0xc, 13;
+            0xf, 0xe, 0xd, 18
+        )
+    }
+
+    for i in 0..16 {
+        write_u32_le(
+            &mut output[i * 4..(i + 1) * 4],
+            x[i].wrapping_add(read_u32_le(&input[i * 4..(i + 1) * 4])));
+    }
+}
+
+fn xor(x: &[u8], y: &[u8], output: &mut [u8]) {
+    for ((out, &x_i), &y_i) in output.iter_mut().zip(x.iter()).zip(y.iter()) {
+        *out = x_i ^ y_i;
+    }
+}
+
+// Execute the BlockMix operation
+// input - the input vector. The length must be a multiple of 128.
+// output - the output vector. Must be the same length as input.
+fn scrypt_block_mix(input: &[u8], output: &mut [u8]) {
+    let mut x = [0u8; 64];
+    copy_memory(&input[input.len() - 64..], &mut x);
+
+    let mut t = [0u8; 64];
+
+    for (i, chunk) in input.chunks(64).enumerate() {
+        xor(&x, chunk, &mut t);
+        salsa20_8(&t, &mut x);
+        let pos = if i % 2 == 0 { (i / 2) * 64 } else { (i / 2) * 64 + input.len() / 2 };
+        copy_memory(&x, &mut output[pos..pos + 64]);
+    }
+}
+
+// Execute the ROMix operation in-place.
+// b - the data to operate on
+// v - a temporary variable to store the vector V
+// t - a temporary variable to store the result of the xor
+// n - the scrypt parameter N
+fn scrypt_ro_mix(b: &mut [u8], v: &mut [u8], t: &mut [u8], n: usize) {
+    fn integerify(x: &[u8], n: usize) -> usize {
+        // n is a power of 2, so n - 1 gives us a bitmask that we can use to perform a calculation
+        // mod n using a simple bitwise and.
+        let mask = n - 1;
+        // This cast is safe since we're going to get the value mod n (which is a power of 2), so we
+        // don't have to care about truncating any of the high bits off
+        let result = (read_u32_le(&x[x.len() - 64..x.len() - 60]) as usize) & mask;
+        result
+    }
+
+    let len = b.len();
+
+    for chunk in v.chunks_mut(len) {
+        copy_memory(b, chunk);
+        scrypt_block_mix(chunk, b);
+    }
+
+    for _ in 0..n {
+        let j = integerify(b, n);
+        xor(b, &v[j * len..(j + 1) * len], t);
+        scrypt_block_mix(t, b);
+    }
+}
+
+/**
+ * The Scrypt parameter values.
+ */
+#[derive(Clone, Copy)]
+pub struct ScryptParams {
+    log_n: u8,
+    r: u32,
+    p: u32
+}
+
+impl ScryptParams {
+    /**
+     * Create a new instance of ScryptParams.
+     *
+     * # Arguments
+     *
+     * * log_n - The log2 of the Scrypt parameter N
+     * * r - The Scrypt parameter r
+     * * p - The Scrypt parameter p
+     *
+     */
+    pub fn new(log_n: u8, r: u32, p: u32) -> ScryptParams {
+        assert!(r > 0);
+        assert!(p > 0);
+        assert!(log_n > 0);
+        assert!((log_n as usize) < size_of::<usize>() * 8);
+        assert!(size_of::<usize>() >= size_of::<u32>() || (r <= std::usize::MAX as u32 && p < std::usize::MAX as u32));
+
+        let r = r as usize;
+        let p = p as usize;
+
+        let n: usize = 1 << log_n;
+
+        // check that r * 128 doesn't overflow
+        let r128 = match r.checked_mul(128) {
+            Some(x) => x,
+            None => panic!("Invalid Scrypt parameters.")
+        };
+
+        // check that n * r * 128 doesn't overflow
+        match r128.checked_mul(n) {
+            Some(_) => { },
+            None => panic!("Invalid Scrypt parameters.")
+        };
+
+        // check that p * r * 128 doesn't overflow
+        match r128.checked_mul(p) {
+            Some(_) => { },
+            None => panic!("Invalid Scrypt parameters.")
+        };
+
+        // This check required by Scrypt:
+        // check: n < 2^(128 * r / 8)
+        // r * 16 won't overflow since r128 didn't
+        assert!((log_n as usize) < r * 16);
+
+        // This check required by Scrypt:
+        // check: p <= ((2^32-1) * 32) / (128 * r)
+        // It takes a bit of re-arranging to get the check above into this form, but, it is indeed
+        // the same.
+        assert!(r * p < 0x40000000);
+
+        ScryptParams {
+            log_n: log_n,
+            r: r as u32,
+            p: p as u32
+        }
+    }
+}
+
+/**
+ * The scrypt key derivation function.
+ *
+ * # Arguments
+ *
+ * * password - The password to process as a byte vector
+ * * salt - The salt value to use as a byte vector
+ * * params - The ScryptParams to use
+ * * output - The resulting derived key is returned in this byte vector.
+ *
+ */
+pub fn scrypt(password: &[u8], salt: &[u8], params: &ScryptParams, output: &mut [u8]) {
+    // This check required by Scrypt:
+    // check output.len() > 0 && output.len() <= (2^32 - 1) * 32
+    assert!(output.len() > 0);
+    assert!(output.len() / 32 <= 0xffffffff);
+
+    // The checks in the ScryptParams constructor guarantee that the following is safe:
+    let n = 1 << params.log_n;
+    let r128 = (params.r as usize) * 128;
+    let pr128 = (params.p as usize) * r128;
+    let nr128 = n * r128;
+
+    let mut mac = Hmac::new(Sha256::new(), password);
+
+    let mut b: Vec<u8> = repeat(0).take(pr128).collect();
+    pbkdf2(&mut mac, salt, 1, &mut b);
+
+    let mut v: Vec<u8> = repeat(0).take(nr128).collect();
+    let mut t: Vec<u8> = repeat(0).take(r128).collect();
+
+    for chunk in &mut b.chunks_mut(r128) {
+        scrypt_ro_mix(chunk, &mut v, &mut t, n);
+    }
+
+    pbkdf2(&mut mac, &*b, 1, output);
+}
+
+/**
+ * scrypt_simple is a helper function that should be sufficient for the majority of cases where
+ * an application needs to use Scrypt to hash a password for storage. The result is a String that
+ * contains the parameters used as part of its encoding. The scrypt_check function may be used on
+ * a password to check if it is equal to a hashed value.
+ *
+ * # Format
+ *
+ * The format of the output is a modified version of the Modular Crypt Format that encodes algorithm
+ * used and the parameter values. If all parameter values can each fit within a single byte, a
+ * compact format is used (format 0). However, if any value cannot, an expanded format where the r
+ * and p parameters are encoded using 4 bytes (format 1) is used. Both formats use a 128-bit salt
+ * and a 256-bit hash. The format is indicated as "rscrypt" which is short for "Rust Scrypt format."
+ *
+ * $rscrypt$<format>$<base64(log_n,r,p)>$<base64(salt)>$<based64(hash)>$
+ *
+ * # Arguments
+ *
+ * * password - The password to process as a str
+ * * params - The ScryptParams to use
+ *
+ */
+pub fn scrypt_simple(password: &str, params: &ScryptParams) -> io::Result<String> {
+    let mut rng = thread_rng();
+
+    // 128-bit salt
+    let salt: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
+
+    // 256-bit derived key
+    let mut dk = [0u8; 32];
+
+    scrypt(password.as_bytes(), &*salt, params, &mut dk);
+
+    let mut result = "$rscrypt$".to_string();
+    if params.r < 256 && params.p < 256 {
+        result.push_str("0$");
+        let mut tmp = [0u8; 3];
+        tmp[0] = params.log_n;
+        tmp[1] = params.r as u8;
+        tmp[2] = params.p as u8;
+        result.push_str(&*tmp.to_base64(base64::STANDARD));
+    } else {
+        result.push_str("1$");
+        let mut tmp = [0u8; 9];
+        tmp[0] = params.log_n;
+        write_u32_le(&mut tmp[1..5], params.r);
+        write_u32_le(&mut tmp[5..9], params.p);
+        result.push_str(&*tmp.to_base64(base64::STANDARD));
+    }
+    result.push('$');
+    result.push_str(&*salt.to_base64(base64::STANDARD));
+    result.push('$');
+    result.push_str(&*dk.to_base64(base64::STANDARD));
+    result.push('$');
+
+    Ok(result)
+}
+
+/**
+ * scrypt_check compares a password against the result of a previous call to scrypt_simple and
+ * returns true if the passed in password hashes to the same value.
+ *
+ * # Arguments
+ *
+ * * password - The password to process as a str
+ * * hashed_value - A string representing a hashed password returned by scrypt_simple()
+ *
+ */
+pub fn scrypt_check(password: &str, hashed_value: &str) -> Result<bool, &'static str> {
+    static ERR_STR: &'static str = "Hash is not in Rust Scrypt format.";
+
+    let mut iter = hashed_value.split('$');
+
+    // Check that there are no characters before the first "$"
+    match iter.next() {
+        Some(x) => if x != "" { return Err(ERR_STR); },
+        None => return Err(ERR_STR)
+    }
+
+    // Check the name
+    match iter.next() {
+        Some(t) => if t != "rscrypt" { return Err(ERR_STR); },
+        None => return Err(ERR_STR)
+    }
+
+    // Parse format - currenlty only version 0 (compact) and 1 (expanded) are supported
+    let params: ScryptParams;
+    match iter.next() {
+        Some(fstr) => {
+            // Parse the parameters - the size of them depends on the if we are using the compact or
+            // expanded format
+            let pvec = match iter.next() {
+                Some(pstr) => match pstr.from_base64() {
+                    Ok(x) => x,
+                    Err(_) => return Err(ERR_STR)
+                },
+                None => return Err(ERR_STR)
+            };
+            match fstr {
+                "0" => {
+                    if pvec.len() != 3 { return Err(ERR_STR); }
+                    let log_n = pvec[0];
+                    let r = pvec[1] as u32;
+                    let p = pvec[2] as u32;
+                    params = ScryptParams::new(log_n, r, p);
+                }
+                "1" => {
+                    if pvec.len() != 9 { return Err(ERR_STR); }
+                    let log_n = pvec[0];
+                    let mut pval = [0u32; 2];
+                    read_u32v_le(&mut pval, &pvec[1..9]);
+                    params = ScryptParams::new(log_n, pval[0], pval[1]);
+                }
+                _ => return Err(ERR_STR)
+            }
+        }
+        None => return Err(ERR_STR)
+    }
+
+    // Salt
+    let salt = match iter.next() {
+        Some(sstr) => match sstr.from_base64() {
+            Ok(salt) => salt,
+            Err(_) => return Err(ERR_STR)
+        },
+        None => return Err(ERR_STR)
+    };
+
+    // Hashed value
+    let hash = match iter.next() {
+        Some(hstr) => match hstr.from_base64() {
+            Ok(hash) => hash,
+            Err(_) => return Err(ERR_STR)
+        },
+        None => return Err(ERR_STR)
+    };
+
+    // Make sure that the input ends with a "$"
+    match iter.next() {
+        Some(x) => if x != "" { return Err(ERR_STR); },
+        None => return Err(ERR_STR)
+    }
+
+    // Make sure there is no trailing data after the final "$"
+    match iter.next() {
+        Some(_) => return Err(ERR_STR),
+        None => { }
+    }
+
+    let mut output: Vec<u8> = repeat(0).take(hash.len()).collect();
+    scrypt(password.as_bytes(), &*salt, &params, &mut output);
+
+    // Be careful here - its important that the comparison be done using a fixed time equality
+    // check. Otherwise an adversary that can measure how long this step takes can learn about the
+    // hashed value which would allow them to mount an offline brute force attack against the
+    // hashed password.
+    Ok(fixed_time_eq(&*output, &*hash))
+}
+
+#[cfg(test)]
+mod test {
+    use std::iter::repeat;
+
+    use scrypt::{scrypt, scrypt_simple, scrypt_check, ScryptParams};
+
+    struct Test {
+        password: &'static str,
+        salt: &'static str,
+        log_n: u8,
+        r: u32,
+        p: u32,
+        expected: Vec<u8>
+    }
+
+    // Test vectors from [1]. The last test vector is omitted because it takes too long to run.
+
+    fn tests() -> Vec<Test> {
+        vec![
+            Test {
+                password: "",
+                salt: "",
+                log_n: 4,
+                r: 1,
+                p: 1,
+                expected: vec![
+                    0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20,
+                    0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97,
+                    0xf1, 0x6b, 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8,
+                    0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42,
+                    0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8,
+                    0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17,
+                    0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28,
+                    0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89, 0x06 ]
+            },
+            Test {
+                password: "password",
+                salt: "NaCl",
+                log_n: 10,
+                r: 8,
+                p: 16,
+                expected: vec![
+                    0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00,
+                    0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe,
+                    0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30,
+                    0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62,
+                    0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88,
+                    0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda,
+                    0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d,
+                    0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40 ]
+            },
+            Test {
+                password: "pleaseletmein",
+                salt: "SodiumChloride",
+                log_n: 14,
+                r: 8,
+                p: 1,
+                expected: vec![
+                    0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48,
+                    0x46, 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb,
+                    0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e,
+                    0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2,
+                    0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf,
+                    0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9,
+                    0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40,
+                    0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58, 0x87 ]
+            },
+        ]
+    }
+
+    #[test]
+    fn test_scrypt() {
+        let tests = tests();
+        for t in tests.iter() {
+            let mut result: Vec<u8> = repeat(0).take(t.expected.len()).collect();
+            let params = ScryptParams::new(t.log_n, t.r, t.p);
+            scrypt(t.password.as_bytes(), t.salt.as_bytes(), &params, &mut result);
+            assert!(result == t.expected);
+        }
+    }
+
+    fn test_scrypt_simple(log_n: u8, r: u32, p: u32) {
+        let password = "password";
+
+        let params = ScryptParams::new(log_n, r, p);
+        let out1 = scrypt_simple(password, &params).unwrap();
+        let out2 = scrypt_simple(password, &params).unwrap();
+
+        // This just makes sure that a salt is being applied. It doesn't verify that that salt is
+        // cryptographically strong, however.
+        assert!(out1 != out2);
+
+        match scrypt_check(password, &out1[..]) {
+            Ok(r) => assert!(r),
+            Err(_) => panic!()
+        }
+        match scrypt_check(password, &out2[..]) {
+            Ok(r) => assert!(r),
+            Err(_) => panic!()
+        }
+
+        match scrypt_check("wrong", &out1[..]) {
+            Ok(r) => assert!(!r),
+            Err(_) => panic!()
+        }
+        match scrypt_check("wrong", &out2[..]) {
+            Ok(r) => assert!(!r),
+            Err(_) => panic!()
+        }
+    }
+
+    #[test]
+    fn test_scrypt_simple_compact() {
+        // These parameters are intentionally very weak - the goal is to make the test run quickly!
+        test_scrypt_simple(7, 8, 1);
+    }
+
+    #[test]
+    fn test_scrypt_simple_expanded() {
+        // These parameters are intentionally very weak - the goal is to make the test run quickly!
+        test_scrypt_simple(3, 1, 256);
+    }
+}
diff --git a/third_party/rust-crypto/src/sha1.rs b/third_party/rust-crypto/src/sha1.rs
new file mode 100644
index 0000000..ef9a113
--- /dev/null
+++ b/third_party/rust-crypto/src/sha1.rs
@@ -0,0 +1,581 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+An implementation of the SHA-1 cryptographic hash algorithm.
+
+To use this module, first create a `Sha1` object using the `Sha1` constructor,
+then feed it an input message using the `input` or `input_str` methods,
+which may be called any number of times; they will buffer the input until
+there is enough to call the block algorithm.
+
+After the entire input has been fed to the hash read the result using
+the `result` or `result_str` methods. The first will return bytes, and
+the second will return a `String` object of the same bytes represented
+in hexadecimal form.
+
+The `Sha1` object may be reused to create multiple hashes by calling
+the `reset()` method. These traits are implemented by all hash digest
+algorithms that implement the `Digest` trait. An example of use is:
+
+```rust
+use self::crypto::digest::Digest;
+use self::crypto::sha1::Sha1;
+
+// create a Sha1 object
+let mut hasher = Sha1::new();
+
+// write input message
+hasher.input_str("hello world");
+
+// read hash digest
+let hex = hasher.result_str();
+
+assert_eq!(hex, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
+```
+
+# Mathematics
+
+The mathematics of the SHA-1 algorithm are quite interesting. In its
+definition, The SHA-1 algorithm uses:
+
+* 1 binary operation on bit-arrays:
+  * "exclusive or" (XOR)
+* 2 binary operations on integers:
+  * "addition" (ADD)
+  * "rotate left" (ROL)
+* 3 ternary operations on bit-arrays:
+  * "choose" (CH)
+  * "parity" (PAR)
+  * "majority" (MAJ)
+
+Some of these functions are commonly found in all hash digest
+algorithms, but some, like "parity" is only found in SHA-1.
+ */
+
+use digest::Digest;
+use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64, StandardPadding};
+use simd::u32x4;
+
+const STATE_LEN: usize = 5;
+const BLOCK_LEN: usize = 16;
+
+const K0: u32 = 0x5A827999u32;
+const K1: u32 = 0x6ED9EBA1u32;
+const K2: u32 = 0x8F1BBCDCu32;
+const K3: u32 = 0xCA62C1D6u32;
+
+/// Not an intrinsic, but gets the first element of a vector.
+#[inline]
+pub fn sha1_first(w0: u32x4) -> u32 {
+    w0.0
+}
+
+/// Not an intrinsic, but adds a word to the first element of a vector.
+#[inline]
+pub fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 {
+    let u32x4(a, b, c, d) = w0;
+    u32x4(e.wrapping_add(a), b, c, d)
+}
+
+/// Emulates `llvm.x86.sha1msg1` intrinsic.
+fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 {
+    let u32x4(_, _, w2, w3) = a;
+    let u32x4(w4, w5, _, _) = b;
+    a ^ u32x4(w2, w3, w4, w5)
+}
+
+/// Emulates `llvm.x86.sha1msg2` intrinsic.
+fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 {
+    let u32x4(x0, x1, x2, x3) = a;
+    let u32x4(_, w13, w14, w15) = b;
+
+    let w16 = (x0 ^ w13).rotate_left(1);
+    let w17 = (x1 ^ w14).rotate_left(1);
+    let w18 = (x2 ^ w15).rotate_left(1);
+    let w19 = (x3 ^ w16).rotate_left(1);
+
+    u32x4(w16, w17, w18, w19)
+}
+
+/// Performs 4 rounds of the message schedule update.
+pub fn sha1_schedule_x4(v0: u32x4, v1: u32x4, v2: u32x4, v3: u32x4) -> u32x4 {
+    sha1msg2(sha1msg1(v0, v1) ^ v2, v3)
+}
+
+/// Emulates `llvm.x86.sha1nexte` intrinsic.
+#[inline]
+pub fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
+    sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
+}
+
+/// Emulates `llvm.x86.sha1rnds4` intrinsic.
+/// Performs 4 rounds of the message block digest.
+pub fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 {
+    const K0V: u32x4 = u32x4(K0, K0, K0, K0);
+    const K1V: u32x4 = u32x4(K1, K1, K1, K1);
+    const K2V: u32x4 = u32x4(K2, K2, K2, K2);
+    const K3V: u32x4 = u32x4(K3, K3, K3, K3);
+
+    match i {
+        0 => sha1rnds4c(abcd, work + K0V),
+        1 => sha1rnds4p(abcd, work + K1V),
+        2 => sha1rnds4m(abcd, work + K2V),
+        3 => sha1rnds4p(abcd, work + K3V),
+        _ => panic!("unknown icosaround index")
+    }
+}
+
+/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
+fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 {
+    let u32x4(mut a, mut b, mut c, mut d) = abcd;
+    let u32x4(t, u, v, w) = msg;
+    let mut e = 0u32;
+
+    macro_rules! bool3ary_202 {
+        ($a:expr, $b:expr, $c:expr) => ($c ^ ($a & ($b ^ $c)))
+    } // Choose, MD5F, SHA1C
+
+    e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_202!(b, c, d)).wrapping_add(t);
+    b = b.rotate_left(30);
+
+    d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_202!(a, b, c)).wrapping_add(u);
+    a = a.rotate_left(30);
+
+    c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_202!(e, a, b)).wrapping_add(v);
+    e = e.rotate_left(30);
+
+    b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_202!(d, e, a)).wrapping_add(w);
+    d = d.rotate_left(30);
+
+    u32x4(b, c, d, e)
+}
+
+/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
+fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 {
+    let u32x4(mut a, mut b, mut c, mut d) = abcd;
+    let u32x4(t, u, v, w) = msg;
+    let mut e = 0u32;
+
+    macro_rules! bool3ary_150 {
+        ($a:expr, $b:expr, $c:expr) => ($a ^ $b ^ $c)
+    } // Parity, XOR, MD5H, SHA1P
+
+    e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_150!(b, c, d)).wrapping_add(t);
+    b = b.rotate_left(30);
+
+    d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_150!(a, b, c)).wrapping_add(u);
+    a = a.rotate_left(30);
+
+    c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_150!(e, a, b)).wrapping_add(v);
+    e = e.rotate_left(30);
+
+    b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_150!(d, e, a)).wrapping_add(w);
+    d = d.rotate_left(30);
+
+    u32x4(b, c, d, e)
+}
+
+/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
+fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 {
+    let u32x4(mut a, mut b, mut c, mut d) = abcd;
+    let u32x4(t, u, v, w) = msg;
+    let mut e = 0u32;
+
+    macro_rules! bool3ary_232 {
+        ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
+    } // Majority, SHA1M
+
+    e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_232!(b, c, d)).wrapping_add(t);
+    b = b.rotate_left(30);
+
+    d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_232!(a, b, c)).wrapping_add(u);
+    a = a.rotate_left(30);
+
+    c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_232!(e, a, b)).wrapping_add(v);
+    e = e.rotate_left(30);
+
+    b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_232!(d, e, a)).wrapping_add(w);
+    d = d.rotate_left(30);
+
+    u32x4(b, c, d, e)
+}
+
+/// Process a block with the SHA-1 algorithm.
+pub fn sha1_digest_block_u32(state: &mut [u32; 5], block: &[u32; 16]) {
+
+    macro_rules! schedule {
+        ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
+            sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
+        )
+    }
+
+    macro_rules! rounds4 {
+        ($h0:ident, $h1:ident, $wk:expr, $i:expr) => (
+            sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i)
+        )
+    }
+
+    // Rounds 0..20
+    let mut h0 = u32x4(state[0],
+                       state[1],
+                       state[2],
+                       state[3]);
+    let mut w0 = u32x4(block[0],
+                       block[1],
+                       block[2],
+                       block[3]);
+    let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(state[4], w0), 0);
+    let mut w1 = u32x4(block[4],
+                       block[5],
+                       block[6],
+                       block[7]);
+    h0 = rounds4!(h1, h0, w1, 0);
+    let mut w2 = u32x4(block[8],
+                       block[9],
+                       block[10],
+                       block[11]);
+    h1 = rounds4!(h0, h1, w2, 0);
+    let mut w3 = u32x4(block[12],
+                       block[13],
+                       block[14],
+                       block[15]);
+    h0 = rounds4!(h1, h0, w3, 0);
+    let mut w4 = schedule!(w0, w1, w2, w3);
+    h1 = rounds4!(h0, h1, w4, 0);
+
+    // Rounds 20..40
+    w0 = schedule!(w1, w2, w3, w4);
+    h0 = rounds4!(h1, h0, w0, 1);
+    w1 = schedule!(w2, w3, w4, w0);
+    h1 = rounds4!(h0, h1, w1, 1);
+    w2 = schedule!(w3, w4, w0, w1);
+    h0 = rounds4!(h1, h0, w2, 1);
+    w3 = schedule!(w4, w0, w1, w2);
+    h1 = rounds4!(h0, h1, w3, 1);
+    w4 = schedule!(w0, w1, w2, w3);
+    h0 = rounds4!(h1, h0, w4, 1);
+
+    // Rounds 40..60
+    w0 = schedule!(w1, w2, w3, w4);
+    h1 = rounds4!(h0, h1, w0, 2);
+    w1 = schedule!(w2, w3, w4, w0);
+    h0 = rounds4!(h1, h0, w1, 2);
+    w2 = schedule!(w3, w4, w0, w1);
+    h1 = rounds4!(h0, h1, w2, 2);
+    w3 = schedule!(w4, w0, w1, w2);
+    h0 = rounds4!(h1, h0, w3, 2);
+    w4 = schedule!(w0, w1, w2, w3);
+    h1 = rounds4!(h0, h1, w4, 2);
+
+    // Rounds 60..80
+    w0 = schedule!(w1, w2, w3, w4);
+    h0 = rounds4!(h1, h0, w0, 3);
+    w1 = schedule!(w2, w3, w4, w0);
+    h1 = rounds4!(h0, h1, w1, 3);
+    w2 = schedule!(w3, w4, w0, w1);
+    h0 = rounds4!(h1, h0, w2, 3);
+    w3 = schedule!(w4, w0, w1, w2);
+    h1 = rounds4!(h0, h1, w3, 3);
+    w4 = schedule!(w0, w1, w2, w3);
+    h0 = rounds4!(h1, h0, w4, 3);
+
+    let e = sha1_first(h1).rotate_left(30);
+    let u32x4(a, b, c, d) = h0;
+
+    state[0] = state[0].wrapping_add(a);
+    state[1] = state[1].wrapping_add(b);
+    state[2] = state[2].wrapping_add(c);
+    state[3] = state[3].wrapping_add(d);
+    state[4] = state[4].wrapping_add(e);
+}
+
+/// Process a block with the SHA-1 algorithm. (See more...)
+///
+/// SHA-1 is a cryptographic hash function, and as such, it operates
+/// on an arbitrary number of bytes. This function operates on a fixed
+/// number of bytes. If you call this function with anything other than
+/// 64 bytes, then it will panic! This function takes two arguments:
+///
+/// * `state` is reference to an **array** of 5 words.
+/// * `block` is reference to a **slice** of 64 bytes.
+///
+/// If you want the function that performs a message digest on an arbitrary
+/// number of bytes, then see also the `Sha1` struct above.
+///
+/// # Implementation
+///
+/// First, some background. Both ARM and Intel are releasing documentation
+/// that they plan to include instruction set extensions for SHA1 and SHA256
+/// sometime in the near future. Second, LLVM won't lower these intrinsics yet,
+/// so these functions were written emulate these instructions. Finally,
+/// the block function implemented with these emulated intrinsics turned out
+/// to be quite fast! What follows is a discussion of this CPU-level view
+/// of the SHA-1 algorithm and how it relates to the mathematical definition.
+///
+/// The SHA instruction set extensions can be divided up into two categories:
+///
+/// * message work schedule update calculation ("schedule" v., "work" n.)
+/// * message block 80-round digest calculation ("digest" v., "block" n.)
+///
+/// The schedule-related functions can be used to easily perform 4 rounds
+/// of the message work schedule update calculation, as shown below:
+///
+/// ```ignore
+/// macro_rules! schedule_x4 {
+///     ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
+///         sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
+///     )
+/// }
+///
+/// macro_rules! round_x4 {
+///     ($h0:ident, $h1:ident, $wk:expr, $i:expr) => (
+///         sha1rnds4($h0, sha1_first_half($h1, $wk), $i)
+///     )
+/// }
+/// ```
+///
+/// and also shown above is how the digest-related functions can be used to
+/// perform 4 rounds of the message block digest calculation.
+///
+pub fn sha1_digest_block(state: &mut [u32; 5], block: &[u8/*; 64*/]) {
+    assert_eq!(block.len(), BLOCK_LEN*4);
+    let mut block2 = [0u32; BLOCK_LEN];
+    read_u32v_be(&mut block2[..], block);
+    sha1_digest_block_u32(state, &block2);
+}
+
+fn add_input(st: &mut Sha1, msg: &[u8]) {
+    assert!((!st.computed));
+    // Assumes that msg.len() can be converted to u64 without overflow
+    st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
+    let st_h = &mut st.h;
+    st.buffer.input(msg, |d: &[u8]| { sha1_digest_block(st_h, d); });
+}
+
+fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
+    if !st.computed {
+        let st_h = &mut st.h;
+        st.buffer.standard_padding(8, |d: &[u8]| { sha1_digest_block(&mut *st_h, d) });
+        write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
+        write_u32_be(st.buffer.next(4), st.length_bits as u32);
+        sha1_digest_block(st_h, st.buffer.full_buffer());
+
+        st.computed = true;
+    }
+
+    write_u32_be(&mut rs[0..4], st.h[0]);
+    write_u32_be(&mut rs[4..8], st.h[1]);
+    write_u32_be(&mut rs[8..12], st.h[2]);
+    write_u32_be(&mut rs[12..16], st.h[3]);
+    write_u32_be(&mut rs[16..20], st.h[4]);
+}
+
+/// Structure representing the state of a Sha1 computation
+#[derive(Clone, Copy)]
+pub struct Sha1 {
+    h: [u32; STATE_LEN],
+    length_bits: u64,
+    buffer: FixedBuffer64,
+    computed: bool,
+}
+
+impl Sha1 {
+    /// Construct a `sha` object
+    pub fn new() -> Sha1 {
+        let mut st = Sha1 {
+            h: [0u32; STATE_LEN],
+            length_bits: 0u64,
+            buffer: FixedBuffer64::new(),
+            computed: false,
+        };
+        st.reset();
+        st
+    }
+}
+
+impl Digest for Sha1 {
+    fn reset(&mut self) {
+        self.length_bits = 0;
+        self.h[0] = 0x67452301u32;
+        self.h[1] = 0xEFCDAB89u32;
+        self.h[2] = 0x98BADCFEu32;
+        self.h[3] = 0x10325476u32;
+        self.h[4] = 0xC3D2E1F0u32;
+        self.buffer.reset();
+        self.computed = false;
+    }
+    fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
+    fn result(&mut self, out: &mut [u8]) { mk_result(self, out) }
+    fn output_bits(&self) -> usize { 160 }
+    fn block_size(&self) -> usize { 64 }
+}
+
+#[cfg(test)]
+mod tests {
+    use cryptoutil::test::test_digest_1million_random;
+    use digest::Digest;
+    use sha1::Sha1;
+
+    #[derive(Clone)]
+    struct Test {
+        input: &'static str,
+        output: Vec<u8>,
+        output_str: &'static str,
+    }
+
+    #[test]
+    fn test() {
+        let tests = vec![
+            // Test messages from FIPS 180-1
+            Test {
+                input: "abc",
+                output: vec![
+                    0xA9u8, 0x99u8, 0x3Eu8, 0x36u8,
+                    0x47u8, 0x06u8, 0x81u8, 0x6Au8,
+                    0xBAu8, 0x3Eu8, 0x25u8, 0x71u8,
+                    0x78u8, 0x50u8, 0xC2u8, 0x6Cu8,
+                    0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8,
+                ],
+                output_str: "a9993e364706816aba3e25717850c26c9cd0d89d"
+            },
+            Test {
+                input:
+                     "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+                output: vec![
+                    0x84u8, 0x98u8, 0x3Eu8, 0x44u8,
+                    0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8,
+                    0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8,
+                    0xF9u8, 0x51u8, 0x29u8, 0xE5u8,
+                    0xE5u8, 0x46u8, 0x70u8, 0xF1u8,
+                ],
+                output_str: "84983e441c3bd26ebaae4aa1f95129e5e54670f1"
+            },
+            // Examples from wikipedia
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output: vec![
+                    0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8,
+                    0x7au8, 0x2du8, 0x28u8, 0xfcu8,
+                    0xedu8, 0x84u8, 0x9eu8, 0xe1u8,
+                    0xbbu8, 0x76u8, 0xe7u8, 0x39u8,
+                    0x1bu8, 0x93u8, 0xebu8, 0x12u8,
+                ],
+                output_str: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy cog",
+                output: vec![
+                    0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8,
+                    0xd2u8, 0x5eu8, 0x1bu8, 0x3au8,
+                    0xfau8, 0xd3u8, 0xe8u8, 0x5au8,
+                    0x0bu8, 0xd1u8, 0x7du8, 0x9bu8,
+                    0x10u8, 0x0du8, 0xb4u8, 0xb3u8,
+                ],
+                output_str: "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
+            },
+        ];
+
+        // Test that it works when accepting the message all at once
+
+        let mut out = [0u8; 20];
+
+        let mut sh = Box::new(Sha1::new());
+        for t in tests.iter() {
+            (*sh).input_str(t.input);
+            sh.result(&mut out);
+            assert!(t.output[..] == out[..]);
+
+            let out_str = (*sh).result_str();
+            assert_eq!(out_str.len(), 40);
+            assert!(&out_str[..] == t.output_str);
+
+            sh.reset();
+        }
+
+
+        // Test that it works when accepting the message in pieces
+        for t in tests.iter() {
+            let len = t.input.len();
+            let mut left = len;
+            while left > 0 {
+                let take = (left + 1) / 2;
+                (*sh).input_str(&t.input[len - left..take + len - left]);
+                left = left - take;
+            }
+            sh.result(&mut out);
+            assert!(t.output[..] == out[..]);
+
+            let out_str = (*sh).result_str();
+            assert_eq!(out_str.len(), 40);
+            assert!(&out_str[..] == t.output_str);
+
+            sh.reset();
+        }
+    }
+
+    #[test]
+    fn test_1million_random_sha1() {
+        let mut sh = Sha1::new();
+        test_digest_1million_random(
+            &mut sh,
+            64,
+            "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use digest::Digest;
+    use sha1::{STATE_LEN, BLOCK_LEN};
+    use sha1::{Sha1, sha1_digest_block_u32};
+
+    #[bench]
+    pub fn sha1_block(bh: & mut Bencher) {
+        let mut state = [0u32; STATE_LEN];
+        let words = [1u32; BLOCK_LEN];
+        bh.iter( || {
+            sha1_digest_block_u32(&mut state, &words);
+        });
+        bh.bytes = 64u64;
+    }
+
+    #[bench]
+    pub fn sha1_10(bh: & mut Bencher) {
+        let mut sh = Sha1::new();
+        let bytes = [1u8; 10];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn sha1_1k(bh: & mut Bencher) {
+        let mut sh = Sha1::new();
+        let bytes = [1u8; 1024];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn sha1_64k(bh: & mut Bencher) {
+        let mut sh = Sha1::new();
+        let bytes = [1u8; 65536];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+}
diff --git a/third_party/rust-crypto/src/sha2.rs b/third_party/rust-crypto/src/sha2.rs
new file mode 100644
index 0000000..d9077c7
--- /dev/null
+++ b/third_party/rust-crypto/src/sha2.rs
@@ -0,0 +1,1496 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+An implementation of the SHA-2 cryptographic hash algorithms.
+
+There are 6 standard algorithms specified in the SHA-2 standard:
+
+ * `Sha224`, which is the 32-bit `Sha256` algorithm with the result truncated to 224 bits.
+ * `Sha256`, which is the 32-bit `Sha256` algorithm.
+ * `Sha384`, which is the 64-bit `Sha512` algorithm with the result truncated to 384 bits.
+ * `Sha512`, which is the 64-bit `Sha512` algorithm.
+ * `Sha512Trunc224`, which is the 64-bit `Sha512` algorithm with the result truncated to 224 bits.
+ * `Sha512Trunc256`, which is the 64-bit `Sha512` algorithm with the result truncated to 256 bits.
+
+Algorithmically, there are only 2 core algorithms: `Sha256` and `Sha512`.
+All other algorithms are just applications of these with different initial hash
+values, and truncated to different digest bit lengths.
+
+# Usage
+
+An example of using `Sha256` is:
+
+```rust
+use self::crypto::digest::Digest;
+use self::crypto::sha2::Sha256;
+
+// create a Sha256 object
+let mut hasher = Sha256::new();
+
+// write input message
+hasher.input_str("hello world");
+
+// read hash digest
+let hex = hasher.result_str();
+
+assert_eq!(hex,
+           concat!("b94d27b9934d3e08a52e52d7da7dabfa",
+                   "c484efe37a5380ee9088f7ace2efcde9"));
+```
+
+An example of using `Sha512` is:
+
+```rust
+use self::crypto::digest::Digest;
+use self::crypto::sha2::Sha512;
+
+// create a Sha512 object
+let mut hasher = Sha512::new();
+
+// write input message
+hasher.input_str("hello world");
+
+// read hash digest
+let hex = hasher.result_str();
+
+assert_eq!(hex,
+           concat!("309ecc489c12d6eb4cc40f50c902f2b4",
+                   "d0ed77ee511a7c7a9bcd3ca86d4cd86f",
+                   "989dd35bc5ff499670da34255b45b0cf",
+                   "d830e81f605dcf7dc5542e93ae9cd76f"));
+```
+
+ */
+
+use digest::Digest;
+use cryptoutil::{write_u32_be, read_u32v_be,
+                 write_u64_be, read_u64v_be,
+                 add_bytes_to_bits, add_bytes_to_bits_tuple,
+                 FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
+
+use simd::{u32x4, u64x2};
+
+const STATE_LEN: usize = 8;
+const BLOCK_LEN: usize = 16;
+
+/// Not an intrinsic, but works like an unaligned load.
+#[inline]
+fn sha256load(v2: u32x4, v3: u32x4) -> u32x4 {
+    u32x4(v3.3, v2.0, v2.1, v2.2)
+}
+
+/// Not an intrinsic, but useful for swapping vectors.
+#[inline]
+fn sha256swap(v0: u32x4) -> u32x4 {
+    u32x4(v0.2, v0.3, v0.0, v0.1)
+}
+
+/// Emulates `llvm.x86.sha256msg1` intrinsic.
+//#[inline]
+fn sha256msg1(v0: u32x4, v1: u32x4) -> u32x4 {
+
+    // sigma 0 on vectors
+    #[inline]
+    fn sigma0x4(x: u32x4) -> u32x4 {
+        ((x >> u32x4( 7,  7,  7,  7)) | (x << u32x4(25, 25, 25, 25))) ^
+        ((x >> u32x4(18, 18, 18, 18)) | (x << u32x4(14, 14, 14, 14))) ^
+         (x >> u32x4( 3,  3,  3,  3))
+    }
+
+    v0 + sigma0x4(sha256load(v0, v1))
+}
+
+/// Emulates `llvm.x86.sha256msg2` intrinsic.
+//#[inline]
+fn sha256msg2(v4: u32x4, v3: u32x4) -> u32x4 {
+
+    macro_rules! sigma1 {
+        ($a:expr) => ($a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10))
+    }
+
+    let u32x4(x3, x2, x1, x0) = v4;
+    let u32x4(w15, w14, _, _) = v3;
+
+    let w16 = x0.wrapping_add(sigma1!(w14));
+    let w17 = x1.wrapping_add(sigma1!(w15));
+    let w18 = x2.wrapping_add(sigma1!(w16));
+    let w19 = x3.wrapping_add(sigma1!(w17));
+
+    u32x4(w19, w18, w17, w16)
+}
+
+/// Performs 4 rounds of the SHA-256 message schedule update.
+pub fn sha256_schedule_x4(v0: u32x4, v1: u32x4, v2: u32x4, v3: u32x4) -> u32x4 {
+    sha256msg2(sha256msg1(v0, v1) + sha256load(v2, v3), v3)
+}
+
+/// Emulates `llvm.x86.sha256rnds2` intrinsic.
+//#[inline]
+pub fn sha256_digest_round_x2(cdgh: u32x4, abef: u32x4, wk: u32x4) -> u32x4 {
+
+    macro_rules! big_sigma0 {
+        ($a:expr) => (($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22)))
+    }
+    macro_rules! big_sigma1 {
+        ($a:expr) => (($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25)))
+    }
+    macro_rules! bool3ary_202 {
+        ($a:expr, $b:expr, $c:expr) => ($c ^ ($a & ($b ^ $c)))
+    } // Choose, MD5F, SHA1C
+    macro_rules! bool3ary_232 {
+        ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
+    } // Majority, SHA1M
+
+    let u32x4(_, _, wk1, wk0) = wk;
+    let u32x4(a0, b0, e0, f0) = abef;
+    let u32x4(c0, d0, g0, h0) = cdgh;
+
+    // a round
+    let x0 = big_sigma1!(e0).wrapping_add(bool3ary_202!(e0, f0, g0)).wrapping_add(wk0).wrapping_add(h0);
+    let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
+    let (a1, b1, c1, d1, e1, f1, g1, h1) = (
+        x0.wrapping_add(y0), a0, b0, c0,
+        x0.wrapping_add(d0), e0, f0, g0);
+
+    // a round
+    let x1 = big_sigma1!(e1).wrapping_add(bool3ary_202!(e1, f1, g1)).wrapping_add(wk1).wrapping_add(h1);
+    let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1));
+    let (a2, b2, _, _, e2, f2, _, _) = (
+        x1.wrapping_add(y1), a1, b1, c1,
+        x1.wrapping_add(d1), e1, f1, g1);
+
+    u32x4(a2, b2, e2, f2)
+}
+
+/// Process a block with the SHA-256 algorithm.
+pub fn sha256_digest_block_u32(state: &mut [u32; 8], block: &[u32; 16]) {
+    let k = &K32X4;
+
+    macro_rules! schedule {
+        ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
+            sha256msg2(sha256msg1($v0, $v1) + sha256load($v2, $v3), $v3)
+        )
+    }
+
+    macro_rules! rounds4 {
+        ($abef:ident, $cdgh:ident, $rest:expr) => {
+            {
+                $cdgh = sha256_digest_round_x2($cdgh, $abef, $rest);
+                $abef = sha256_digest_round_x2($abef, $cdgh, sha256swap($rest));
+            }
+        }
+    }
+
+    let mut abef = u32x4(state[0],
+                         state[1],
+                         state[4],
+                         state[5]);
+    let mut cdgh = u32x4(state[2],
+                         state[3],
+                         state[6],
+                         state[7]);
+
+    // Rounds 0..64
+    let mut w0 = u32x4(block[3],
+                       block[2],
+                       block[1],
+                       block[0]);
+    rounds4!(abef, cdgh, k[0] + w0);
+    let mut w1 = u32x4(block[7],
+                       block[6],
+                       block[5],
+                       block[4]);
+    rounds4!(abef, cdgh, k[1] + w1);
+    let mut w2 = u32x4(block[11],
+                       block[10],
+                       block[9],
+                       block[8]);
+    rounds4!(abef, cdgh, k[2] + w2);
+    let mut w3 = u32x4(block[15],
+                       block[14],
+                       block[13],
+                       block[12]);
+    rounds4!(abef, cdgh, k[3] + w3);
+    let mut w4 = schedule!(w0, w1, w2, w3);
+    rounds4!(abef, cdgh, k[4] + w4);
+    w0 = schedule!(w1, w2, w3, w4);
+    rounds4!(abef, cdgh, k[5] + w0);
+    w1 = schedule!(w2, w3, w4, w0);
+    rounds4!(abef, cdgh, k[6] + w1);
+    w2 = schedule!(w3, w4, w0, w1);
+    rounds4!(abef, cdgh, k[7] + w2);
+    w3 = schedule!(w4, w0, w1, w2);
+    rounds4!(abef, cdgh, k[8] + w3);
+    w4 = schedule!(w0, w1, w2, w3);
+    rounds4!(abef, cdgh, k[9] + w4);
+    w0 = schedule!(w1, w2, w3, w4);
+    rounds4!(abef, cdgh, k[10] + w0);
+    w1 = schedule!(w2, w3, w4, w0);
+    rounds4!(abef, cdgh, k[11] + w1);
+    w2 = schedule!(w3, w4, w0, w1);
+    rounds4!(abef, cdgh, k[12] + w2);
+    w3 = schedule!(w4, w0, w1, w2);
+    rounds4!(abef, cdgh, k[13] + w3);
+    w4 = schedule!(w0, w1, w2, w3);
+    rounds4!(abef, cdgh, k[14] + w4);
+    w0 = schedule!(w1, w2, w3, w4);
+    rounds4!(abef, cdgh, k[15] + w0);
+
+    let u32x4(a, b, e, f) = abef;
+    let u32x4(c, d, g, h) = cdgh;
+
+    state[0] = state[0].wrapping_add(a);
+    state[1] = state[1].wrapping_add(b);
+    state[2] = state[2].wrapping_add(c);
+    state[3] = state[3].wrapping_add(d);
+    state[4] = state[4].wrapping_add(e);
+    state[5] = state[5].wrapping_add(f);
+    state[6] = state[6].wrapping_add(g);
+    state[7] = state[7].wrapping_add(h);
+}
+
+/// Process a block with the SHA-256 algorithm. (See more...)
+///
+/// Internally, this uses functions which resemble the new Intel SHA instruction sets,
+/// and so it's data locality properties may improve performance. However, to benefit
+/// the most from this implementation, replace these functions with x86 intrinsics to
+/// get a possible speed boost.
+///
+/// # Implementation
+///
+/// The `Sha256` algorithm is implemented with functions that resemble the new
+/// Intel SHA instruction set extensions. These intructions fall into two categories:
+/// message schedule calculation, and the message block 64-round digest calculation.
+/// The schedule-related instructions allow 4 rounds to be calculated as:
+///
+/// ```ignore
+/// use std::simd::u32x4;
+/// use self::crypto::sha2::{
+///     sha256msg1,
+///     sha256msg2,
+///     sha256load
+/// };
+///
+/// fn schedule4_data(work: &mut [u32x4], w: &[u32]) {
+///
+///     // this is to illustrate the data order
+///     work[0] = u32x4(w[3], w[2], w[1], w[0]);
+///     work[1] = u32x4(w[7], w[6], w[5], w[4]);
+///     work[2] = u32x4(w[11], w[10], w[9], w[8]);
+///     work[3] = u32x4(w[15], w[14], w[13], w[12]);
+/// }
+///
+/// fn schedule4_work(work: &mut [u32x4], t: usize) {
+///
+///     // this is the core expression
+///     work[t] = sha256msg2(sha256msg1(work[t - 4], work[t - 3]) +
+///                          sha256load(work[t - 2], work[t - 1]),
+///                          work[t - 1])
+/// }
+/// ```
+///
+/// instead of 4 rounds of:
+///
+/// ```ignore
+/// fn schedule_work(w: &mut [u32], t: usize) {
+///     w[t] = sigma1!(w[t - 2]) + w[t - 7] + sigma0!(w[t - 15]) + w[t - 16];
+/// }
+/// ```
+///
+/// and the digest-related instructions allow 4 rounds to be calculated as:
+///
+/// ```ignore
+/// use std::simd::u32x4;
+/// use self::crypto::sha2::{K32X4,
+///     sha256rnds2,
+///     sha256swap
+/// };
+///
+/// fn rounds4(state: &mut [u32; 8], work: &mut [u32x4], t: usize) {
+///     let [a, b, c, d, e, f, g, h]: [u32; 8] = *state;
+///
+///     // this is to illustrate the data order
+///     let mut abef = u32x4(a, b, e, f);
+///     let mut cdgh = u32x4(c, d, g, h);
+///     let temp = K32X4[t] + work[t];
+///
+///     // this is the core expression
+///     cdgh = sha256rnds2(cdgh, abef, temp);
+///     abef = sha256rnds2(abef, cdgh, sha256swap(temp));
+///
+///     *state = [abef.0, abef.1, cdgh.0, cdgh.1,
+///               abef.2, abef.3, cdgh.2, cdgh.3];
+/// }
+/// ```
+///
+/// instead of 4 rounds of:
+///
+/// ```ignore
+/// fn round(state: &mut [u32; 8], w: &mut [u32], t: usize) {
+///     let [a, b, c, mut d, e, f, g, mut h]: [u32; 8] = *state;
+///
+///     h += big_sigma1!(e) +   choose!(e, f, g) + K32[t] + w[t]; d += h;
+///     h += big_sigma0!(a) + majority!(a, b, c);
+///
+///     *state = [h, a, b, c, d, e, f, g];
+/// }
+/// ```
+///
+/// **NOTE**: It is important to note, however, that these instructions are not implemented
+/// by any CPU (at the time of this writing), and so they are emulated in this library
+/// until the instructions become more common, and gain support in LLVM (and GCC, etc.).
+///
+pub fn sha256_digest_block(state: &mut [u32; 8], block: &[u8/*; 64*/]) {
+    assert_eq!(block.len(), BLOCK_LEN*4);
+    let mut block2 = [0u32; BLOCK_LEN];
+    read_u32v_be(&mut block2[..], block);
+    sha256_digest_block_u32(state, &block2);
+}
+
+/// Not an intrinsic, but works like an unaligned load.
+#[inline]
+fn sha512load(v0: u64x2, v1: u64x2) -> u64x2 {
+    u64x2(v1.1, v0.0)
+}
+
+/// Performs 2 rounds of the SHA-512 message schedule update.
+pub fn sha512_schedule_x2(v0: u64x2, v1: u64x2, v4to5: u64x2, v7: u64x2) -> u64x2 {
+
+    // sigma 0
+    fn sigma0(x: u64) -> u64 {
+        ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7)
+    }
+
+    // sigma 1
+    fn sigma1(x: u64) -> u64 {
+        ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6)
+    }
+
+    let u64x2(w1, w0) 	= v0;
+    let u64x2(_, w2) 	= v1;
+    let u64x2(w10, w9) 	= v4to5;
+    let u64x2(w15, w14) = v7;
+
+    let w16 = sigma1(w14).wrapping_add(w9).wrapping_add(sigma0(w1)).wrapping_add(w0);
+    let w17 = sigma1(w15).wrapping_add(w10).wrapping_add(sigma0(w2)).wrapping_add(w1);
+
+    u64x2(w17, w16)
+}
+
+/// Performs one round of the SHA-512 message block digest.
+pub fn sha512_digest_round(ae: u64x2, bf: u64x2, cg: u64x2, dh: u64x2, wk0: u64) -> u64x2 {
+
+    macro_rules! big_sigma0 {
+        ($a:expr) => (($a.rotate_right(28) ^ $a.rotate_right(34) ^ $a.rotate_right(39)))
+    }
+    macro_rules! big_sigma1 {
+        ($a:expr) => (($a.rotate_right(14) ^ $a.rotate_right(18) ^ $a.rotate_right(41)))
+    }
+    macro_rules! bool3ary_202 {
+        ($a:expr, $b:expr, $c:expr) => ($c ^ ($a & ($b ^ $c)))
+    } // Choose, MD5F, SHA1C
+    macro_rules! bool3ary_232 {
+        ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
+    } // Majority, SHA1M
+
+    let u64x2(a0, e0) = ae;
+    let u64x2(b0, f0) = bf;
+    let u64x2(c0, g0) = cg;
+    let u64x2(d0, h0) = dh;
+
+    // a round
+    let x0 = big_sigma1!(e0).wrapping_add(bool3ary_202!(e0, f0, g0)).wrapping_add(wk0).wrapping_add(h0);
+    let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
+    let (a1, _, _, _, e1, _, _, _) = (
+        x0.wrapping_add(y0), a0, b0, c0,
+        x0.wrapping_add(d0), e0, f0, g0);
+
+    u64x2(a1, e1)
+}
+
+/// Process a block with the SHA-512 algorithm.
+pub fn sha512_digest_block_u64(state: &mut [u64; 8], block: &[u64; 16]) {
+    let k = &K64X2;
+
+    macro_rules! schedule {
+        ($v0:expr, $v1:expr, $v4:expr, $v5:expr, $v7:expr) => (
+             sha512_schedule_x2($v0, $v1, sha512load($v4, $v5), $v7)
+        )
+    }
+
+    macro_rules! rounds4 {
+        ($ae:ident, $bf:ident, $cg:ident, $dh:ident, $wk0:expr, $wk1:expr) => {
+            {
+                let u64x2(u, t) = $wk0;
+                let u64x2(w, v) = $wk1;
+
+                $dh = sha512_digest_round($ae, $bf, $cg, $dh, t);
+                $cg = sha512_digest_round($dh, $ae, $bf, $cg, u);
+                $bf = sha512_digest_round($cg, $dh, $ae, $bf, v);
+                $ae = sha512_digest_round($bf, $cg, $dh, $ae, w);
+            }
+        }
+    }
+
+    let mut ae = u64x2(state[0],
+                       state[4]);
+    let mut bf = u64x2(state[1],
+                       state[5]);
+    let mut cg = u64x2(state[2],
+                       state[6]);
+    let mut dh = u64x2(state[3],
+                       state[7]);
+
+    // Rounds 0..20
+    let (mut w1, mut w0) = (u64x2(block[3],
+                                  block[2]),
+                            u64x2(block[1],
+                                  block[0]));
+    rounds4!(ae, bf, cg, dh, k[0] + w0, k[1] + w1);
+    let (mut w3, mut w2) = (u64x2(block[7],
+                                  block[6]),
+                            u64x2(block[5],
+                                  block[4]));
+    rounds4!(ae, bf, cg, dh, k[2] + w2, k[3] + w3);
+    let (mut w5, mut w4) = (u64x2(block[11],
+                                  block[10]),
+                            u64x2(block[9],
+                                  block[8]));
+    rounds4!(ae, bf, cg, dh, k[4] + w4, k[5] + w5);
+    let (mut w7, mut w6) = (u64x2(block[15],
+                                  block[14]),
+                            u64x2(block[13],
+                                  block[12]));
+    rounds4!(ae, bf, cg, dh, k[6] + w6, k[7] + w7);
+    let mut w8 = schedule!(w0, w1, w4, w5, w7);
+    let mut w9 = schedule!(w1, w2, w5, w6, w8);
+    rounds4!(ae, bf, cg, dh, k[8] + w8, k[9] + w9);
+
+    // Rounds 20..40
+    w0 = schedule!(w2, w3, w6, w7, w9);
+    w1 = schedule!(w3, w4, w7, w8, w0);
+    rounds4!(ae, bf, cg, dh, k[10] + w0, k[11] + w1);
+    w2 = schedule!(w4, w5, w8, w9, w1);
+    w3 = schedule!(w5, w6, w9, w0, w2);
+    rounds4!(ae, bf, cg, dh, k[12] + w2, k[13] + w3);
+    w4 = schedule!(w6, w7, w0, w1, w3);
+    w5 = schedule!(w7, w8, w1, w2, w4);
+    rounds4!(ae, bf, cg, dh, k[14] + w4, k[15] + w5);
+    w6 = schedule!(w8, w9, w2, w3, w5);
+    w7 = schedule!(w9, w0, w3, w4, w6);
+    rounds4!(ae, bf, cg, dh, k[16] + w6, k[17] + w7);
+    w8 = schedule!(w0, w1, w4, w5, w7);
+    w9 = schedule!(w1, w2, w5, w6, w8);
+    rounds4!(ae, bf, cg, dh, k[18] + w8, k[19] + w9);
+
+    // Rounds 40..60
+    w0 = schedule!(w2, w3, w6, w7, w9);
+    w1 = schedule!(w3, w4, w7, w8, w0);
+    rounds4!(ae, bf, cg, dh, k[20] + w0, k[21] + w1);
+    w2 = schedule!(w4, w5, w8, w9, w1);
+    w3 = schedule!(w5, w6, w9, w0, w2);
+    rounds4!(ae, bf, cg, dh, k[22] + w2, k[23] + w3);
+    w4 = schedule!(w6, w7, w0, w1, w3);
+    w5 = schedule!(w7, w8, w1, w2, w4);
+    rounds4!(ae, bf, cg, dh, k[24] + w4, k[25] + w5);
+    w6 = schedule!(w8, w9, w2, w3, w5);
+    w7 = schedule!(w9, w0, w3, w4, w6);
+    rounds4!(ae, bf, cg, dh, k[26] + w6, k[27] + w7);
+    w8 = schedule!(w0, w1, w4, w5, w7);
+    w9 = schedule!(w1, w2, w5, w6, w8);
+    rounds4!(ae, bf, cg, dh, k[28] + w8, k[29] + w9);
+
+    // Rounds 60..80
+    w0 = schedule!(w2, w3, w6, w7, w9);
+    w1 = schedule!(w3, w4, w7, w8, w0);
+    rounds4!(ae, bf, cg, dh, k[30] + w0, k[31] + w1);
+    w2 = schedule!(w4, w5, w8, w9, w1);
+    w3 = schedule!(w5, w6, w9, w0, w2);
+    rounds4!(ae, bf, cg, dh, k[32] + w2, k[33] + w3);
+    w4 = schedule!(w6, w7, w0, w1, w3);
+    w5 = schedule!(w7, w8, w1, w2, w4);
+    rounds4!(ae, bf, cg, dh, k[34] + w4, k[35] + w5);
+    w6 = schedule!(w8, w9, w2, w3, w5);
+    w7 = schedule!(w9, w0, w3, w4, w6);
+    rounds4!(ae, bf, cg, dh, k[36] + w6, k[37] + w7);
+    w8 = schedule!(w0, w1, w4, w5, w7);
+    w9 = schedule!(w1, w2, w5, w6, w8);
+    rounds4!(ae, bf, cg, dh, k[38] + w8, k[39] + w9);
+
+    let u64x2(a, e) = ae;
+    let u64x2(b, f) = bf;
+    let u64x2(c, g) = cg;
+    let u64x2(d, h) = dh;
+
+    state[0] = state[0].wrapping_add(a);
+    state[1] = state[1].wrapping_add(b);
+    state[2] = state[2].wrapping_add(c);
+    state[3] = state[3].wrapping_add(d);
+    state[4] = state[4].wrapping_add(e);
+    state[5] = state[5].wrapping_add(f);
+    state[6] = state[6].wrapping_add(g);
+    state[7] = state[7].wrapping_add(h);
+}
+
+/// Process a block with the SHA-512 algorithm. (See more...)
+///
+/// Internally, this uses functions that resemble the new Intel SHA
+/// instruction set extensions, but since no architecture seems to
+/// have any designs, these may not be the final designs if and/or when
+/// there are instruction set extensions with SHA-512. So to summarize:
+/// SHA-1 and SHA-256 are being implemented in hardware soon (at the time
+/// of this writing), but it doesn't look like SHA-512 will be hardware
+/// accelerated any time soon.
+///
+/// # Implementation
+///
+/// These functions fall into two categories:
+/// message schedule calculation, and the message block 64-round digest calculation.
+/// The schedule-related functions allow 4 rounds to be calculated as:
+///
+/// ```ignore
+/// use std::simd::u64x2;
+/// use self::crypto::sha2::{
+///     sha512msg,
+///     sha512load
+/// };
+///
+/// fn schedule4_data(work: &mut [u64x2], w: &[u64]) {
+///
+///     // this is to illustrate the data order
+///     work[0] = u64x2(w[1], w[0]);
+///     work[1] = u64x2(w[3], w[2]);
+///     work[2] = u64x2(w[5], w[4]);
+///     work[3] = u64x2(w[7], w[6]);
+///     work[4] = u64x2(w[9], w[8]);
+///     work[5] = u64x2(w[11], w[10]);
+///     work[6] = u64x2(w[13], w[12]);
+///     work[7] = u64x2(w[15], w[14]);
+/// }
+///
+/// fn schedule4_work(work: &mut [u64x2], t: usize) {
+///
+///     // this is the core expression
+///     work[t] = sha512msg(work[t - 8],
+///                         work[t - 7],
+///                         sha512load(work[t - 4], work[t - 3]),
+///                         work[t - 1]);
+/// }
+/// ```
+///
+/// instead of 4 rounds of:
+///
+/// ```ignore
+/// fn schedule_work(w: &mut [u64], t: usize) {
+///     w[t] = sigma1!(w[t - 2]) + w[t - 7] + sigma0!(w[t - 15]) + w[t - 16];
+/// }
+/// ```
+///
+/// and the digest-related functions allow 4 rounds to be calculated as:
+///
+/// ```ignore
+/// use std::simd::u64x2;
+/// use self::crypto::sha2::{K64X2, sha512rnd};
+///
+/// fn rounds4(state: &mut [u64; 8], work: &mut [u64x2], t: usize) {
+///     let [a, b, c, d, e, f, g, h]: [u64; 8] = *state;
+///
+///     // this is to illustrate the data order
+///     let mut ae = u64x2(a, e);
+///     let mut bf = u64x2(b, f);
+///     let mut cg = u64x2(c, g);
+///     let mut dh = u64x2(d, h);
+///     let u64x2(w1, w0) = K64X2[2*t]     + work[2*t];
+///     let u64x2(w3, w2) = K64X2[2*t + 1] + work[2*t + 1];
+///
+///     // this is the core expression
+///     dh = sha512rnd(ae, bf, cg, dh, w0);
+///     cg = sha512rnd(dh, ae, bf, cg, w1);
+///     bf = sha512rnd(cg, dh, ae, bf, w2);
+///     ae = sha512rnd(bf, cg, dh, ae, w3);
+///
+///     *state = [ae.0, bf.0, cg.0, dh.0,
+///               ae.1, bf.1, cg.1, dh.1];
+/// }
+/// ```
+///
+/// instead of 4 rounds of:
+///
+/// ```ignore
+/// fn round(state: &mut [u64; 8], w: &mut [u64], t: usize) {
+///     let [a, b, c, mut d, e, f, g, mut h]: [u64; 8] = *state;
+///
+///     h += big_sigma1!(e) +   choose!(e, f, g) + K64[t] + w[t]; d += h;
+///     h += big_sigma0!(a) + majority!(a, b, c);
+///
+///     *state = [h, a, b, c, d, e, f, g];
+/// }
+/// ```
+///
+pub fn sha512_digest_block(state: &mut [u64; 8], block: &[u8/*; 128*/]) {
+    assert_eq!(block.len(), BLOCK_LEN*8);
+    let mut block2 = [0u64; BLOCK_LEN];
+    read_u64v_be(&mut block2[..], block);
+    sha512_digest_block_u64(state, &block2);
+}
+
+// A structure that represents that state of a digest computation for the SHA-2 512 family
+// of digest functions
+#[derive(Copy, Clone)]
+struct Engine512State {
+    h: [u64; 8]
+}
+
+impl Engine512State {
+    fn new(h: &[u64; 8]) -> Engine512State {
+        Engine512State {
+            h: *h
+        }
+    }
+
+    fn reset(&mut self, h: &[u64; STATE_LEN]) {
+        self.h = *h;
+    }
+
+    pub fn process_block(&mut self, data: &[u8]) {
+        sha512_digest_block(&mut self.h, data);
+    }
+}
+
+/// Constants necessary for SHA-512 family of digests.
+pub const K64: [u64; 80] = [
+    0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
+    0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
+    0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+    0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
+    0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
+    0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+    0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
+    0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
+    0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+    0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
+    0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
+    0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+    0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
+    0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
+    0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+    0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
+    0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
+    0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+    0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
+    0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+];
+
+/// Constants necessary for SHA-512 family of digests.
+pub const K64X2: [u64x2; 40] = [
+    u64x2(K64[1], K64[0]), u64x2(K64[3], K64[2]), u64x2(K64[5], K64[4]), u64x2(K64[7], K64[6]),
+    u64x2(K64[9], K64[8]), u64x2(K64[11], K64[10]), u64x2(K64[13], K64[12]), u64x2(K64[15], K64[14]),
+    u64x2(K64[17], K64[16]), u64x2(K64[19], K64[18]), u64x2(K64[21], K64[20]), u64x2(K64[23], K64[22]),
+    u64x2(K64[25], K64[24]), u64x2(K64[27], K64[26]), u64x2(K64[29], K64[28]), u64x2(K64[31], K64[30]),
+    u64x2(K64[33], K64[32]), u64x2(K64[35], K64[34]), u64x2(K64[37], K64[36]), u64x2(K64[39], K64[38]),
+    u64x2(K64[41], K64[40]), u64x2(K64[43], K64[42]), u64x2(K64[45], K64[44]), u64x2(K64[47], K64[46]),
+    u64x2(K64[49], K64[48]), u64x2(K64[51], K64[50]), u64x2(K64[53], K64[52]), u64x2(K64[55], K64[54]),
+    u64x2(K64[57], K64[56]), u64x2(K64[59], K64[58]), u64x2(K64[61], K64[60]), u64x2(K64[63], K64[62]),
+    u64x2(K64[65], K64[64]), u64x2(K64[67], K64[66]), u64x2(K64[69], K64[68]), u64x2(K64[71], K64[70]),
+    u64x2(K64[73], K64[72]), u64x2(K64[75], K64[74]), u64x2(K64[77], K64[76]), u64x2(K64[79], K64[78])
+];
+
+// A structure that keeps track of the state of the Sha-512 operation and contains the logic
+// necessary to perform the final calculations.
+#[derive(Copy, Clone)]
+struct Engine512 {
+    length_bits: (u64, u64),
+    buffer: FixedBuffer128,
+    state: Engine512State,
+    finished: bool,
+}
+
+impl Engine512 {
+    fn new(h: &[u64; STATE_LEN]) -> Engine512 {
+        Engine512 {
+            length_bits: (0, 0),
+            buffer: FixedBuffer128::new(),
+            state: Engine512State::new(h),
+            finished: false
+        }
+    }
+
+    fn reset(&mut self, h: &[u64; STATE_LEN]) {
+        self.length_bits = (0, 0);
+        self.buffer.reset();
+        self.state.reset(h);
+        self.finished = false;
+    }
+
+    fn input(&mut self, input: &[u8]) {
+        assert!(!self.finished);
+        // Assumes that input.len() can be converted to u64 without overflow
+        self.length_bits = add_bytes_to_bits_tuple(self.length_bits, input.len() as u64);
+        let self_state = &mut self.state;
+        self.buffer.input(input, |input: &[u8]| { self_state.process_block(input) });
+    }
+
+    fn finish(&mut self) {
+        if self.finished {
+            return;
+        }
+
+        let self_state = &mut self.state;
+        self.buffer.standard_padding(16, |input: &[u8]| { self_state.process_block(input) });
+        match self.length_bits {
+            (hi, low) => {
+                write_u64_be(self.buffer.next(8), hi);
+                write_u64_be(self.buffer.next(8), low);
+            }
+        }
+        self_state.process_block(self.buffer.full_buffer());
+
+        self.finished = true;
+    }
+}
+
+
+/// The SHA-512 hash algorithm with the SHA-512 initial hash value.
+#[derive(Copy, Clone)]
+pub struct Sha512 {
+    engine: Engine512
+}
+
+impl Sha512 {
+    /**
+     * Construct an new instance of a SHA-512 digest.
+     */
+    pub fn new() -> Sha512 {
+        Sha512 {
+            engine: Engine512::new(&H512)
+        }
+    }
+}
+
+impl Digest for Sha512 {
+    fn input(&mut self, d: &[u8]) {
+        self.engine.input(d);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        self.engine.finish();
+
+        write_u64_be(&mut out[0..8], self.engine.state.h[0]);
+        write_u64_be(&mut out[8..16], self.engine.state.h[1]);
+        write_u64_be(&mut out[16..24], self.engine.state.h[2]);
+        write_u64_be(&mut out[24..32], self.engine.state.h[3]);
+        write_u64_be(&mut out[32..40], self.engine.state.h[4]);
+        write_u64_be(&mut out[40..48], self.engine.state.h[5]);
+        write_u64_be(&mut out[48..56], self.engine.state.h[6]);
+        write_u64_be(&mut out[56..64], self.engine.state.h[7]);
+    }
+
+    fn reset(&mut self) {
+        self.engine.reset(&H512);
+    }
+
+    fn output_bits(&self) -> usize { 512 }
+
+    fn block_size(&self) -> usize { 128 }
+}
+
+static H512: [u64; STATE_LEN] = [
+    0x6a09e667f3bcc908,
+    0xbb67ae8584caa73b,
+    0x3c6ef372fe94f82b,
+    0xa54ff53a5f1d36f1,
+    0x510e527fade682d1,
+    0x9b05688c2b3e6c1f,
+    0x1f83d9abfb41bd6b,
+    0x5be0cd19137e2179
+];
+
+
+/// The SHA-512 hash algorithm with the SHA-384 initial hash value. The result is truncated to 384 bits.
+#[derive(Copy, Clone)]
+pub struct Sha384 {
+    engine: Engine512
+}
+
+impl Sha384 {
+    /**
+     * Construct an new instance of a SHA-384 digest.
+     */
+    pub fn new() -> Sha384 {
+        Sha384 {
+            engine: Engine512::new(&H384)
+        }
+    }
+}
+
+impl Digest for Sha384 {
+    fn input(&mut self, d: &[u8]) {
+        self.engine.input(d);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        self.engine.finish();
+
+        write_u64_be(&mut out[0..8], self.engine.state.h[0]);
+        write_u64_be(&mut out[8..16], self.engine.state.h[1]);
+        write_u64_be(&mut out[16..24], self.engine.state.h[2]);
+        write_u64_be(&mut out[24..32], self.engine.state.h[3]);
+        write_u64_be(&mut out[32..40], self.engine.state.h[4]);
+        write_u64_be(&mut out[40..48], self.engine.state.h[5]);
+    }
+
+    fn reset(&mut self) {
+        self.engine.reset(&H384);
+    }
+
+    fn output_bits(&self) -> usize { 384 }
+
+    fn block_size(&self) -> usize { 128 }
+}
+
+static H384: [u64; STATE_LEN] = [
+    0xcbbb9d5dc1059ed8,
+    0x629a292a367cd507,
+    0x9159015a3070dd17,
+    0x152fecd8f70e5939,
+    0x67332667ffc00b31,
+    0x8eb44a8768581511,
+    0xdb0c2e0d64f98fa7,
+    0x47b5481dbefa4fa4
+];
+
+
+/// The SHA-512 hash algorithm with the SHA-512/256 initial hash value. The result is truncated to 256 bits.
+#[derive(Clone, Copy)]
+pub struct Sha512Trunc256 {
+    engine: Engine512
+}
+
+impl Sha512Trunc256 {
+    /**
+     * Construct an new instance of a SHA-512/256 digest.
+     */
+    pub fn new() -> Sha512Trunc256 {
+        Sha512Trunc256 {
+            engine: Engine512::new(&H512_TRUNC_256)
+        }
+    }
+}
+
+impl Digest for Sha512Trunc256 {
+    fn input(&mut self, d: &[u8]) {
+        self.engine.input(d);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        self.engine.finish();
+
+        write_u64_be(&mut out[0..8], self.engine.state.h[0]);
+        write_u64_be(&mut out[8..16], self.engine.state.h[1]);
+        write_u64_be(&mut out[16..24], self.engine.state.h[2]);
+        write_u64_be(&mut out[24..32], self.engine.state.h[3]);
+    }
+
+    fn reset(&mut self) {
+        self.engine.reset(&H512_TRUNC_256);
+    }
+
+    fn output_bits(&self) -> usize { 256 }
+
+    fn block_size(&self) -> usize { 128 }
+}
+
+static H512_TRUNC_256: [u64; STATE_LEN] = [
+    0x22312194fc2bf72c,
+    0x9f555fa3c84c64c2,
+    0x2393b86b6f53b151,
+    0x963877195940eabd,
+    0x96283ee2a88effe3,
+    0xbe5e1e2553863992,
+    0x2b0199fc2c85b8aa,
+    0x0eb72ddc81c52ca2
+];
+
+
+/// The SHA-512 hash algorithm with the SHA-512/224 initial hash value. The result is truncated to 224 bits.
+#[derive(Clone, Copy)]
+pub struct Sha512Trunc224 {
+    engine: Engine512
+}
+
+impl Sha512Trunc224 {
+    /**
+     * Construct an new instance of a SHA-512/224 digest.
+     */
+    pub fn new() -> Sha512Trunc224 {
+        Sha512Trunc224 {
+            engine: Engine512::new(&H512_TRUNC_224)
+        }
+    }
+}
+
+impl Digest for Sha512Trunc224 {
+    fn input(&mut self, d: &[u8]) {
+        self.engine.input(d);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        self.engine.finish();
+
+        write_u64_be(&mut out[0..8], self.engine.state.h[0]);
+        write_u64_be(&mut out[8..16], self.engine.state.h[1]);
+        write_u64_be(&mut out[16..24], self.engine.state.h[2]);
+        write_u32_be(&mut out[24..28], (self.engine.state.h[3] >> 32) as u32);
+    }
+
+    fn reset(&mut self) {
+        self.engine.reset(&H512_TRUNC_224);
+    }
+
+    fn output_bits(&self) -> usize { 224 }
+
+    fn block_size(&self) -> usize { 128 }
+}
+
+static H512_TRUNC_224: [u64; STATE_LEN] = [
+    0x8c3d37c819544da2,
+    0x73e1996689dcd4d6,
+    0x1dfab7ae32ff9c82,
+    0x679dd514582f9fcf,
+    0x0f6d2b697bd44da8,
+    0x77e36f7304c48942,
+    0x3f9d85a86a1d36c8,
+    0x1112e6ad91d692a1,
+];
+
+
+// A structure that represents that state of a digest computation for the SHA-2 512 family of digest
+// functions
+#[derive(Clone, Copy)]
+struct Engine256State {
+    h: [u32; 8],
+}
+
+impl Engine256State {
+    fn new(h: &[u32; STATE_LEN]) -> Engine256State {
+        Engine256State {
+            h: *h
+        }
+    }
+
+    fn reset(&mut self, h: &[u32; STATE_LEN]) {
+        self.h = *h;
+    }
+
+    pub fn process_block(&mut self, data: &[u8]) {
+        sha256_digest_block(&mut self.h, data);
+    }
+}
+
+/// Constants necessary for SHA-256 family of digests.
+pub const K32: [u32; 64] = [
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+];
+
+/// Constants necessary for SHA-256 family of digests.
+pub const K32X4: [u32x4; 16] = [
+    u32x4(K32[3], K32[2], K32[1], K32[0]),
+    u32x4(K32[7], K32[6], K32[5], K32[4]),
+    u32x4(K32[11], K32[10], K32[9], K32[8]),
+    u32x4(K32[15], K32[14], K32[13], K32[12]),
+    u32x4(K32[19], K32[18], K32[17], K32[16]),
+    u32x4(K32[23], K32[22], K32[21], K32[20]),
+    u32x4(K32[27], K32[26], K32[25], K32[24]),
+    u32x4(K32[31], K32[30], K32[29], K32[28]),
+    u32x4(K32[35], K32[34], K32[33], K32[32]),
+    u32x4(K32[39], K32[38], K32[37], K32[36]),
+    u32x4(K32[43], K32[42], K32[41], K32[40]),
+    u32x4(K32[47], K32[46], K32[45], K32[44]),
+    u32x4(K32[51], K32[50], K32[49], K32[48]),
+    u32x4(K32[55], K32[54], K32[53], K32[52]),
+    u32x4(K32[59], K32[58], K32[57], K32[56]),
+    u32x4(K32[63], K32[62], K32[61], K32[60]),
+];
+
+// A structure that keeps track of the state of the Sha-256 operation and contains the logic
+// necessary to perform the final calculations.
+#[derive(Clone, Copy)]
+struct Engine256 {
+    length_bits: u64,
+    buffer: FixedBuffer64,
+    state: Engine256State,
+    finished: bool,
+}
+
+impl Engine256 {
+    fn new(h: &[u32; STATE_LEN]) -> Engine256 {
+        Engine256 {
+            length_bits: 0,
+            buffer: FixedBuffer64::new(),
+            state: Engine256State::new(h),
+            finished: false
+        }
+    }
+
+    fn reset(&mut self, h: &[u32; STATE_LEN]) {
+        self.length_bits = 0;
+        self.buffer.reset();
+        self.state.reset(h);
+        self.finished = false;
+    }
+
+    fn input(&mut self, input: &[u8]) {
+        assert!(!self.finished);
+        // Assumes that input.len() can be converted to u64 without overflow
+        self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64);
+        let self_state = &mut self.state;
+        self.buffer.input(input, |input: &[u8]| { self_state.process_block(input) });
+    }
+
+    fn finish(&mut self) {
+        if self.finished {
+            return;
+        }
+
+        let self_state = &mut self.state;
+        self.buffer.standard_padding(8, |input: &[u8]| { self_state.process_block(input) });
+        write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 );
+        write_u32_be(self.buffer.next(4), self.length_bits as u32);
+        self_state.process_block(self.buffer.full_buffer());
+
+        self.finished = true;
+    }
+}
+
+
+/// The SHA-256 hash algorithm with the SHA-256 initial hash value.
+#[derive(Clone, Copy)]
+pub struct Sha256 {
+    engine: Engine256
+}
+
+impl Sha256 {
+    /**
+     * Construct an new instance of a SHA-256 digest.
+     */
+    pub fn new() -> Sha256 {
+        Sha256 {
+            engine: Engine256::new(&H256)
+        }
+    }
+}
+
+impl Digest for Sha256 {
+    fn input(&mut self, d: &[u8]) {
+        self.engine.input(d);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        self.engine.finish();
+
+        write_u32_be(&mut out[0..4], self.engine.state.h[0]);
+        write_u32_be(&mut out[4..8], self.engine.state.h[1]);
+        write_u32_be(&mut out[8..12], self.engine.state.h[2]);
+        write_u32_be(&mut out[12..16], self.engine.state.h[3]);
+        write_u32_be(&mut out[16..20], self.engine.state.h[4]);
+        write_u32_be(&mut out[20..24], self.engine.state.h[5]);
+        write_u32_be(&mut out[24..28], self.engine.state.h[6]);
+        write_u32_be(&mut out[28..32], self.engine.state.h[7]);
+    }
+
+    fn reset(&mut self) {
+        self.engine.reset(&H256);
+    }
+
+    fn output_bits(&self) -> usize { 256 }
+
+    fn block_size(&self) -> usize { 64 }
+}
+
+static H256: [u32; STATE_LEN] = [
+    0x6a09e667,
+    0xbb67ae85,
+    0x3c6ef372,
+    0xa54ff53a,
+    0x510e527f,
+    0x9b05688c,
+    0x1f83d9ab,
+    0x5be0cd19
+];
+
+
+/// The SHA-256 hash algorithm with the SHA-224 initial hash value. The result is truncated to 224 bits.
+#[derive(Clone, Copy)]
+pub struct Sha224 {
+    engine: Engine256
+}
+
+impl Sha224 {
+    /**
+     * Construct an new instance of a SHA-224 digest.
+     */
+    pub fn new() -> Sha224 {
+        Sha224 {
+            engine: Engine256::new(&H224)
+        }
+    }
+}
+
+impl Digest for Sha224 {
+    fn input(&mut self, d: &[u8]) {
+        self.engine.input(d);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        self.engine.finish();
+        write_u32_be(&mut out[0..4], self.engine.state.h[0]);
+        write_u32_be(&mut out[4..8], self.engine.state.h[1]);
+        write_u32_be(&mut out[8..12], self.engine.state.h[2]);
+        write_u32_be(&mut out[12..16], self.engine.state.h[3]);
+        write_u32_be(&mut out[16..20], self.engine.state.h[4]);
+        write_u32_be(&mut out[20..24], self.engine.state.h[5]);
+        write_u32_be(&mut out[24..28], self.engine.state.h[6]);
+    }
+
+    fn reset(&mut self) {
+        self.engine.reset(&H224);
+    }
+
+    fn output_bits(&self) -> usize { 224 }
+
+    fn block_size(&self) -> usize { 64 }
+}
+
+static H224: [u32; STATE_LEN] = [
+    0xc1059ed8,
+    0x367cd507,
+    0x3070dd17,
+    0xf70e5939,
+    0xffc00b31,
+    0x68581511,
+    0x64f98fa7,
+    0xbefa4fa4
+];
+
+
+#[cfg(test)]
+mod tests {
+    use cryptoutil::test::test_digest_1million_random;
+    use digest::Digest;
+    use sha2::{Sha512, Sha384, Sha512Trunc256, Sha512Trunc224, Sha256, Sha224};
+
+    struct Test {
+        input: &'static str,
+        output_str: &'static str,
+    }
+
+    fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
+        // Test that it works when accepting the message all at once
+        for t in tests.iter() {
+            sh.input_str(t.input);
+
+            let out_str = sh.result_str();
+            assert!(&out_str[..] == t.output_str);
+
+            sh.reset();
+        }
+
+        // Test that it works when accepting the message in pieces
+        for t in tests.iter() {
+            let len = t.input.len();
+            let mut left = len;
+            while left > 0 {
+                let take = (left + 1) / 2;
+                sh.input_str(&t.input[len - left..take + len - left]);
+                left = left - take;
+            }
+
+            let out_str = sh.result_str();
+            assert!(&out_str[..] == t.output_str);
+
+            sh.reset();
+        }
+    }
+
+    #[test]
+    fn test_sha512() {
+        // Examples from wikipedia
+        let wikipedia_tests = vec![
+            Test {
+                input: "",
+                output_str: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output_str: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog.",
+                output_str: "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed"
+            },
+        ];
+
+        let tests = wikipedia_tests;
+
+        let mut sh = Box::new(Sha512::new());
+
+        test_hash(&mut *sh, &tests[..]);
+    }
+
+    #[test]
+    fn test_sha384() {
+        // Examples from wikipedia
+        let wikipedia_tests = vec![
+            Test {
+                input: "",
+                output_str: "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output_str: "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog.",
+                output_str: "ed892481d8272ca6df370bf706e4d7bc1b5739fa2177aae6c50e946678718fc67a7af2819a021c2fc34e91bdb63409d7"
+            },
+        ];
+
+        let tests = wikipedia_tests;
+
+        let mut sh = Box::new(Sha384::new());
+
+        test_hash(&mut *sh, &tests[..]);
+    }
+
+    #[test]
+    fn test_sha512_256() {
+        // Examples from wikipedia
+        let wikipedia_tests = vec![
+            Test {
+                input: "",
+                output_str: "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output_str: "dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog.",
+                output_str: "1546741840f8a492b959d9b8b2344b9b0eb51b004bba35c0aebaac86d45264c3"
+            },
+        ];
+
+        let tests = wikipedia_tests;
+
+        let mut sh = Box::new(Sha512Trunc256::new());
+
+        test_hash(&mut *sh, &tests[..]);
+    }
+
+    #[test]
+    fn test_sha512_224() {
+        // Examples from wikipedia
+        let wikipedia_tests = vec![
+            Test {
+                input: "",
+                output_str: "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output_str: "944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog.",
+                output_str: "6d6a9279495ec4061769752e7ff9c68b6b0b3c5a281b7917ce0572de"
+            },
+        ];
+
+        let tests = wikipedia_tests;
+
+        let mut sh = Box::new(Sha512Trunc224::new());
+
+        test_hash(&mut *sh, &tests[..]);
+    }
+
+    #[test]
+    fn test_sha256() {
+        // Examples from wikipedia
+        let wikipedia_tests = vec![
+            Test {
+                input: "",
+                output_str: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output_str: "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog.",
+                output_str: "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"
+            },
+        ];
+
+        let tests = wikipedia_tests;
+
+        let mut sh = Box::new(Sha256::new());
+
+        test_hash(&mut *sh, &tests[..]);
+    }
+
+    #[test]
+    fn test_sha224() {
+        // Examples from wikipedia
+        let wikipedia_tests = vec![
+            Test {
+                input: "",
+                output_str: "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog",
+                output_str: "730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525"
+            },
+            Test {
+                input: "The quick brown fox jumps over the lazy dog.",
+                output_str: "619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4c"
+            },
+        ];
+
+        let tests = wikipedia_tests;
+
+        let mut sh = Box::new(Sha224::new());
+
+        test_hash(&mut *sh, &tests[..]);
+    }
+
+    #[test]
+    fn test_1million_random_sha512() {
+        let mut sh = Sha512::new();
+        test_digest_1million_random(
+            &mut sh,
+            128,
+            "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
+        }
+
+    #[test]
+    fn test_1million_random_sha256() {
+        let mut sh = Sha256::new();
+        test_digest_1million_random(
+            &mut sh,
+            64,
+            "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+    }
+}
+
+
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use digest::Digest;
+    use sha2::{STATE_LEN, BLOCK_LEN};
+    use sha2::{Sha256, Sha512, sha256_digest_block_u32, sha512_digest_block_u64};
+
+    #[bench]
+    pub fn sha256_block(bh: & mut Bencher) {
+        let mut state = [0u32; STATE_LEN];
+        let words = [1u32; BLOCK_LEN];
+        bh.iter( || {
+            sha256_digest_block_u32(&mut state, &words);
+        });
+        bh.bytes = 64u64;
+    }
+
+    #[bench]
+    pub fn sha512_block(bh: & mut Bencher) {
+        let mut state = [0u64; STATE_LEN];
+        let words = [1u64; BLOCK_LEN];
+        bh.iter( || {
+            sha512_digest_block_u64(&mut state, &words);
+        });
+        bh.bytes = 128u64;
+    }
+
+    #[bench]
+    pub fn sha256_10(bh: & mut Bencher) {
+        let mut sh = Sha256::new();
+        let bytes = [1u8; 10];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn sha256_1k(bh: & mut Bencher) {
+        let mut sh = Sha256::new();
+        let bytes = [1u8; 1024];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn sha256_64k(bh: & mut Bencher) {
+        let mut sh = Sha256::new();
+        let bytes = [1u8; 65536];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn sha512_10(bh: & mut Bencher) {
+        let mut sh = Sha512::new();
+        let bytes = [1u8; 10];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn sha512_1k(bh: & mut Bencher) {
+        let mut sh = Sha512::new();
+        let bytes = [1u8; 1024];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+    #[bench]
+    pub fn sha512_64k(bh: & mut Bencher) {
+        let mut sh = Sha512::new();
+        let bytes = [1u8; 65536];
+        bh.iter( || {
+            sh.input(&bytes);
+        });
+        bh.bytes = bytes.len() as u64;
+    }
+
+}
diff --git a/third_party/rust-crypto/src/sha3.rs b/third_party/rust-crypto/src/sha3.rs
new file mode 100644
index 0000000..bade54d
--- /dev/null
+++ b/third_party/rust-crypto/src/sha3.rs
@@ -0,0 +1,6771 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+An implementation of the SHA-3 cryptographic hash algorithms.
+
+There are 6 standard algorithms specified in the SHA-3 standard:
+
+ * `SHA3-224`
+ * `SHA3-256`
+ * `SHA3-384`
+ * `SHA3-512`
+ * `SHAKE128`, an extendable output function (XOF)
+ * `SHAKE256`, an extendable output function (XOF)
+ * `Keccak224`, `Keccak256`, `Keccak384`, `Keccak512` (NIST submission without padding changes)
+
+Based on an [implementation by Sébastien Martini](https://github.com/seb-m/crypto.rs/blob/master/src/sha3.rs)
+
+# Usage
+
+An example of using `SHA3-256` is:
+
+```rust
+use self::crypto::digest::Digest;
+use self::crypto::sha3::Sha3;
+
+// create a SHA3-256 object
+let mut hasher = Sha3::sha3_256();
+
+// write input message
+hasher.input_str("abc");
+
+// read hash digest
+let hex = hasher.result_str();
+
+assert_eq!(hex, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532");
+```
+
+ */
+
+use std::prelude::v1::*;
+use std::cmp;
+
+use digest::Digest;
+use cryptoutil::{write_u64v_le, read_u64v_le, zero};
+
+const B: usize = 200;
+const NROUNDS: usize = 24;
+const RC: [u64; 24] = [
+    0x0000000000000001,
+    0x0000000000008082,
+    0x800000000000808a,
+    0x8000000080008000,
+    0x000000000000808b,
+    0x0000000080000001,
+    0x8000000080008081,
+    0x8000000000008009,
+    0x000000000000008a,
+    0x0000000000000088,
+    0x0000000080008009,
+    0x000000008000000a,
+    0x000000008000808b,
+    0x800000000000008b,
+    0x8000000000008089,
+    0x8000000000008003,
+    0x8000000000008002,
+    0x8000000000000080,
+    0x000000000000800a,
+    0x800000008000000a,
+    0x8000000080008081,
+    0x8000000000008080,
+    0x0000000080000001,
+    0x8000000080008008
+];
+const ROTC: [usize; 24] = [
+    1, 3, 6, 10, 15, 21, 28, 36,
+    45, 55, 2, 14, 27, 41, 56, 8,
+    25, 43, 62, 18, 39, 61, 20, 44
+];
+const PIL: [usize; 24] = [
+    10, 7, 11, 17, 18, 3, 5, 16,
+    8, 21, 24, 4, 15, 23, 19, 13,
+    12, 2, 20, 14, 22, 9, 6, 1
+];
+const M5: [usize; 10] = [
+    0, 1, 2, 3, 4, 0, 1, 2, 3, 4
+];
+
+#[inline]
+fn rotl64(v: u64, n: usize) -> u64 {
+    ((v << (n % 64)) & 0xffffffffffffffff) ^ (v >> (64 - (n % 64)))
+}
+
+// Code based on Keccak-compact64.c from ref implementation.
+fn keccak_f(state: &mut [u8]) {
+    assert!(state.len() == B);
+
+    let mut s: [u64; 25] = [0; 25];
+    let mut t: [u64; 1] = [0; 1];
+    let mut c: [u64; 5] = [0; 5];
+
+    read_u64v_le(&mut s, state);
+
+    for round in 0..NROUNDS {
+        // Theta
+        for x in 0..5 {
+            c[x] = s[x] ^ s[5 + x] ^ s[10 + x] ^ s[15 + x] ^ s[20 + x];
+        }
+        for x in 0..5 {
+            t[0] = c[M5[x + 4]] ^ rotl64(c[M5[x + 1]], 1);
+            for y in 0..5 {
+                s[y * 5 + x] = s[y * 5 + x] ^ t[0];
+            }
+        }
+
+        // Rho Pi
+        t[0] = s[1];
+        for x in 0..24 {
+            c[0] = s[PIL[x]];
+            s[PIL[x]] = rotl64(t[0], ROTC[x]);
+            t[0] = c[0];
+        }
+
+        // Chi
+        for y in 0..5 {
+            for x in 0..5 {
+                c[x] = s[y * 5 + x];
+            }
+            for x in 0..5 {
+                s[y * 5 + x] = c[x] ^ (!c[M5[x + 1]] & c[M5[x + 2]]);
+            }
+        }
+
+        // Iota
+        s[0] = s[0] ^ RC[round];
+    }
+
+    write_u64v_le(state, &s);
+}
+
+
+/// SHA-3 Modes.
+#[allow(non_camel_case_types)]
+#[derive(Debug, Copy, Clone)]
+pub enum Sha3Mode {
+    Sha3_224,
+    Sha3_256,
+    Sha3_384,
+    Sha3_512,
+    Shake128,
+    Shake256,
+    Keccak224,
+    Keccak256,
+    Keccak384,
+    Keccak512,
+}
+
+impl Sha3Mode {
+    /// Return the expected hash size in bytes specified for `mode`, or 0
+    /// for modes with variable output as for shake functions.
+    pub fn digest_length(&self) -> usize {
+        match *self {
+            Sha3Mode::Sha3_224 | Sha3Mode::Keccak224 => 28,
+            Sha3Mode::Sha3_256 | Sha3Mode::Keccak256 => 32,
+            Sha3Mode::Sha3_384 | Sha3Mode::Keccak384 => 48,
+            Sha3Mode::Sha3_512 | Sha3Mode::Keccak512 => 64,
+            Sha3Mode::Shake128 | Sha3Mode::Shake256 => 0
+        }
+    }
+
+    /// Return `true` if `mode` is a SHAKE mode.
+    pub fn is_shake(&self) -> bool {
+        match *self {
+            Sha3Mode::Shake128 | Sha3Mode::Shake256 => true,
+            _ => false
+        }
+    }
+
+    /// Return `true` if `mode` is a Keccak mode.
+    pub fn is_keccak(&self) -> bool {
+        match *self {
+            Sha3Mode::Keccak224 | Sha3Mode::Keccak256 | Sha3Mode::Keccak384 | Sha3Mode::Keccak512 => true,
+            _ => false
+        }
+    }
+
+    /// Return the capacity in bytes.
+    fn capacity(&self) -> usize {
+        match *self {
+            Sha3Mode::Sha3_224 | Sha3Mode::Keccak224 => 56,
+            Sha3Mode::Sha3_256 | Sha3Mode::Keccak256 => 64,
+            Sha3Mode::Sha3_384 | Sha3Mode::Keccak384 => 96,
+            Sha3Mode::Sha3_512 | Sha3Mode::Keccak512 => 128,
+            Sha3Mode::Shake128 => 32,
+            Sha3Mode::Shake256 => 64
+        }
+    }
+}
+
+
+pub struct Sha3 {
+    state: [u8; B],  // B bytes
+    mode: Sha3Mode,
+    can_absorb: bool,  // Can absorb
+    can_squeeze: bool,  // Can squeeze
+    offset: usize  // Enqueued bytes in state for absorb phase
+                   // Squeeze offset for squeeze phase
+}
+
+impl Sha3 {
+    /// New SHA-3 instanciated from specified SHA-3 `mode`.
+    pub fn new(mode: Sha3Mode) -> Sha3 {
+        Sha3 {
+            state: [0; B],
+            mode: mode,
+            can_absorb: true,
+            can_squeeze: true,
+            offset: 0
+        }
+    }
+
+    /// New SHA3-224 instance.
+    pub fn sha3_224() -> Sha3 {
+        Sha3::new(Sha3Mode::Sha3_224)
+    }
+
+    /// New SHA3-256 instance.
+    pub fn sha3_256() -> Sha3 {
+        Sha3::new(Sha3Mode::Sha3_256)
+    }
+
+    /// New SHA3-384 instance.
+    pub fn sha3_384() -> Sha3 {
+        Sha3::new(Sha3Mode::Sha3_384)
+    }
+
+    /// New SHA3-512 instance.
+    pub fn sha3_512() -> Sha3 {
+        Sha3::new(Sha3Mode::Sha3_512)
+    }
+
+    /// New SHAKE-128 instance.
+    pub fn shake_128() -> Sha3 {
+        Sha3::new(Sha3Mode::Shake128)
+    }
+
+    /// New SHAKE-256 instance.
+    pub fn shake_256() -> Sha3 {
+        Sha3::new(Sha3Mode::Shake256)
+    }
+
+    /// New Keccak224 instance.
+    pub fn keccak224() -> Sha3 {
+        Sha3::new(Sha3Mode::Keccak224)
+    }
+
+    /// New Keccak256 instance.
+    pub fn keccak256() -> Sha3 {
+        Sha3::new(Sha3Mode::Keccak256)
+    }
+
+    /// New Keccak384 instance.
+    pub fn keccak384() -> Sha3 {
+        Sha3::new(Sha3Mode::Keccak384)
+    }
+
+    /// New Keccak512 instance.
+    pub fn keccak512() -> Sha3 {
+        Sha3::new(Sha3Mode::Keccak512)
+    }
+
+    fn finalize(&mut self) {
+        assert!(self.can_absorb);
+
+        let output_bits = self.output_bits();
+
+        let ds_len = if self.mode.is_keccak() {
+            0
+        } else if output_bits != 0 {
+            2
+        } else {
+            4
+        };
+
+        fn set_domain_sep(out_len: usize, buf: &mut [u8]) {
+            assert!(buf.len() > 0);
+            if out_len != 0 {
+                // 01...
+                buf[0] &= 0xfe;
+                buf[0] |= 0x2;
+            } else {
+                // 1111...
+                buf[0] |= 0xf;
+            }
+        }
+
+        // All parameters are expected to be in bits.
+        fn pad_len(ds_len: usize, offset: usize, rate: usize) -> usize {
+            assert!(rate % 8 == 0 && offset % 8 == 0);
+            let r: i64 = rate as i64;
+            let m: i64 = (offset + ds_len) as i64;
+            let zeros = (((-m - 2) + 2 * r) % r) as usize;
+            assert!((m as usize + zeros + 2) % 8 == 0);
+            (ds_len as usize + zeros + 2) / 8
+        }
+
+        fn set_pad(offset: usize, buf: &mut [u8]) {
+            assert!(buf.len() as f32 >= ((offset + 2) as f32 / 8.0).ceil());
+            let s = offset / 8;
+            let buflen = buf.len();
+            buf[s] |= 1 << (offset % 8);
+            for i in (offset % 8) + 1..8 {
+                buf[s] &= !(1 << i);
+            }
+            for i in s + 1..buf.len() {
+                buf[i] = 0;
+            }
+            buf[buflen - 1] |= 0x80;
+        }
+
+        let p_len = pad_len(ds_len, self.offset * 8, self.rate() * 8);
+
+        let mut p: Vec<u8> = vec![0; p_len];
+
+        if ds_len != 0 {
+            set_domain_sep(self.output_bits(), &mut p);
+        }
+
+        set_pad(ds_len, &mut p);
+
+        self.input(&p);
+        self.can_absorb = false;
+    }
+
+    fn rate(&self) -> usize {
+        B - self.mode.capacity()
+    }
+}
+
+impl Digest for Sha3 {
+    fn input(&mut self, data: &[u8]) {
+        if !self.can_absorb {
+            panic!("Invalid state, absorb phase already finalized.");
+        }
+
+        let r = self.rate();
+        assert!(self.offset < r);
+
+        let in_len = data.len();
+        let mut in_pos: usize = 0;
+
+        // Absorb
+        while in_pos < in_len {
+            let offset = self.offset;
+            let nread = cmp::min(r - offset, in_len - in_pos);
+            for i in 0..nread {
+                self.state[offset + i] = self.state[offset + i] ^ data[in_pos + i];
+            }
+            in_pos += nread;
+
+            if offset + nread != r {
+                self.offset += nread;
+                break;
+            }
+
+            self.offset = 0;
+            keccak_f(&mut self.state);
+        }
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        if !self.can_squeeze {
+            panic!("Nothing left to squeeze.");
+        }
+
+        if self.can_absorb {
+            self.finalize();
+        }
+
+        let r = self.rate();
+        let out_len = self.mode.digest_length();
+        if out_len != 0 {
+            assert!(self.offset < out_len);
+        } else {
+            assert!(self.offset < r);
+        }
+
+        let in_len = out.len();
+        let mut in_pos: usize = 0;
+
+        // Squeeze
+        while in_pos < in_len {
+            let offset = self.offset % r;
+            let mut nread = cmp::min(r - offset, in_len - in_pos);
+            if out_len != 0 {
+                nread = cmp::min(nread, out_len - self.offset);
+            }
+
+            for i in 0..nread {
+                out[in_pos + i] = self.state[offset + i];
+            }
+            in_pos += nread;
+
+            if offset + nread != r {
+                self.offset += nread;
+                break;
+            }
+
+            if out_len == 0 {
+                self.offset = 0;
+            } else {
+                self.offset += nread;
+            }
+
+            keccak_f(&mut self.state);
+        }
+
+        if out_len != 0 && out_len == self.offset {
+            self.can_squeeze = false;
+        }
+    }
+
+    fn reset(&mut self) {
+        self.can_absorb = true;
+        self.can_squeeze = true;
+        self.offset = 0;
+
+        zero(&mut self.state);
+    }
+
+    fn output_bits(&self) -> usize {
+        self.mode.digest_length() * 8
+    }
+
+    fn block_size(&self) -> usize {
+        B - self.mode.capacity()
+    }
+}
+
+impl Copy for Sha3 {
+
+}
+
+impl Clone for Sha3 {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+
+
+#[cfg(test)]
+mod tests {
+    use digest::Digest;
+    use sha3::{Sha3, Sha3Mode};
+    use serialize::hex::{FromHex, ToHex};
+
+    struct Test {
+        input: &'static str,
+        output_str: &'static str,
+    }
+
+    fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
+        // Test that it works when accepting the message all at once
+        for t in tests.iter() {
+            sh.input(&t.input.from_hex().unwrap());
+
+            let mut out_str = vec![0u8; t.output_str.len() / 2];
+
+            sh.result(&mut out_str);
+            println!("{}", &out_str.to_hex());
+            assert!(&out_str.to_hex() == t.output_str);
+
+            sh.reset();
+        }
+
+        // Test that it works when accepting the message in pieces
+        for t in tests.iter() {
+            let len = t.input.len() / 2;
+            let mut left = len;
+            while left > 0 {
+                let take = (left + 1) / 2;
+                sh.input(&t.input.from_hex().unwrap()[len - left..take + len - left]);
+                left = left - take;
+            }
+
+            let mut out_str = vec![0u8; t.output_str.len() / 2];
+
+            sh.result(&mut out_str);
+
+            assert!(&out_str.to_hex() == t.output_str);
+
+            sh.reset();
+        }
+    }
+
+    #[test]
+    fn test_keccak_224() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd"
+            },
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Keccak224));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_keccak_256() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
+            },
+            Test {
+                input: "cc",
+                output_str: "eead6dbfc7340a56caedc044696a168870549a6a7f6f56961e84a54bd9970b8a"
+            },
+            Test {
+                input: "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7",
+                output_str: "574271cd13959e8ddeae5bfbdb02a3fdf54f2babfd0cbeb893082a974957d0c1"
+            }
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Keccak256));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_keccak_384() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff"
+            },
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Keccak384));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_keccak_512() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e"
+            },
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Keccak512));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_sha3_224() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"
+            },
+            Test {
+                input: "cc",
+                output_str: "df70adc49b2e76eee3a6931b93fa41841c3af2cdf5b32a18b5478c39"
+            },
+            Test {
+                input: "41fb",
+                output_str: "bff295861daedf33e70519b1e2bcb4c2e9fe3364d789bc3b17301c15"
+            },
+            Test {
+                input: "1f877c",
+                output_str: "14889df49c076a9af2f4bcb16339bcc45a24ebf9ce4dcdce7ec17217"
+            },
+            Test {
+                input: "c1ecfdfc",
+                output_str: "a33c58df8a8026f0f9591966bd6d00eed3b1e829580ab9be268caf39"
+            },
+            Test {
+                input: "21f134ac57",
+                output_str: "10e580a32199596169331ad43cfcf10264f81565037040028a06b458"
+            },
+            Test {
+                input: "c6f50bb74e29",
+                output_str: "fe52c30c95c1e5193207e97d355fde09453482708c0876aa961508f0"
+            },
+            Test {
+                input: "119713cc83eeef",
+                output_str: "8b449849cb7c4776c593de58fd5c2e322cb5316be08a75057a01ed6a"
+            },
+            Test {
+                input: "4a4f202484512526",
+                output_str: "01386cdd70589b3b34941efe16b85071e9ba948179922044f640868e"
+            },
+            Test {
+                input: "1f66ab4185ed9b6375",
+                output_str: "86953d0864019c81fd3a805357a162fd76a13a7cbf6ff0d635015d0e"
+            },
+            Test {
+                input: "eed7422227613b6f53c9",
+                output_str: "e56fc2a5a58709031df02a2e46ad95f93583e2745630540d8d97f703"
+            },
+            Test {
+                input: "eaeed5cdffd89dece455f1",
+                output_str: "1d783c37c32a2b71b504bcaa05fc00b639f1fae7e8d8e3f3bc49f041"
+            },
+            Test {
+                input: "5be43c90f22902e4fe8ed2d3",
+                output_str: "54c7e4bf3c73e192ade223dfea86f2d04acf953612731958f854c7bd"
+            },
+            Test {
+                input: "a746273228122f381c3b46e4f1",
+                output_str: "77e51ceada2aa1cbbf95acd821008b57e946f7940223b19f0c53e62e"
+            },
+            Test {
+                input: "3c5871cd619c69a63b540eb5a625",
+                output_str: "9ed59ed155e97154e067fa0f5a130839b57bdbda6feb82dabe006f00"
+            },
+            Test {
+                input: "fa22874bcc068879e8ef11a69f0722",
+                output_str: "81b3e56cfeee8e9138d3bfe24bb7ccdfd4b50d0b8ca11ae7d4b0c960"
+            },
+            Test {
+                input: "52a608ab21ccdd8a4457a57ede782176",
+                output_str: "b1571bed52e54eef377d99df7be4bc6682c43387f2bf9acc92df608f"
+            },
+            Test {
+                input: "82e192e4043ddcd12ecf52969d0f807eed",
+                output_str: "08045cf78d238d56972f1c850414bc404fc6dcb11f8d8210d034c610"
+            },
+            Test {
+                input: "75683dcb556140c522543bb6e9098b21a21e",
+                output_str: "9ffd840c550ad23971eb5ce89ae2fd6222abfb7f0aafd7eb0005716b"
+            },
+            Test {
+                input: "06e4efe45035e61faaf4287b4d8d1f12ca97e5",
+                output_str: "72decb5ea1b25a2daaeb234a8d96e0f57211426666a2ee76b2385c62"
+            },
+            Test {
+                input: "e26193989d06568fe688e75540aea06747d9f851",
+                output_str: "a589936370a3d20039c469d44a1c26e62823ab28cc50175a9897f98e"
+            },
+            Test {
+                input: "d8dc8fdefbdce9d44e4cbafe78447bae3b5436102a",
+                output_str: "96f43401ad49c58d887020f395bdd01f6dad04128a85b17780408c37"
+            },
+            Test {
+                input: "57085fd7e14216ab102d8317b0cb338a786d5fc32d8f",
+                output_str: "a3a0f0c552e7cd2723fe22e1d5719e213d9a3da1db99e32efffd0f46"
+            },
+            Test {
+                input: "a05404df5dbb57697e2c16fa29defac8ab3560d6126fa0",
+                output_str: "e991f4a14b56dc6b224ef352ae8bc8cae8b1af1c25c6733dfb7ffe1f"
+            },
+            Test {
+                input: "aecbb02759f7433d6fcb06963c74061cd83b5b3ffa6f13c6",
+                output_str: "718866c21cbe3f291364c07b36078a6bf0b8258b0ec155e2e2b1af23"
+            },
+            Test {
+                input: "aafdc9243d3d4a096558a360cc27c8d862f0be73db5e88aa55",
+                output_str: "23606d06fd8f87c2205abb5fd04c33eba30509955200566a0f772b49"
+            },
+            Test {
+                input: "7bc84867f6f9e9fdc3e1046cae3a52c77ed485860ee260e30b15",
+                output_str: "05935f0ad2264475df34fa96f6a9118c32b217e86169eb7ade4e2fdb"
+            },
+            Test {
+                input: "fac523575a99ec48279a7a459e98ff901918a475034327efb55843",
+                output_str: "fbec83cbdb6d08c7bfddc2e37f73b16dc92926a5c23dab41deebfb1b"
+            },
+            Test {
+                input: "0f8b2d8fcfd9d68cffc17ccfb117709b53d26462a3f346fb7c79b85e",
+                output_str: "1e693b0bce2372550daef35b14f13ab43441ed6742dee3e86fd1d8ef"
+            },
+            Test {
+                input: "a963c3e895ff5a0be4824400518d81412f875fa50521e26e85eac90c04",
+                output_str: "1781f1344dc17f678571f4e5df3998b1d38b1d83602b53b9b6f283d6"
+            },
+            Test {
+                input: "03a18688b10cc0edf83adf0a84808a9718383c4070c6c4f295098699ac2c",
+                output_str: "03b74b7d8fc1f23f76bab2b6c35f292c15506de64978fcf6d9973fce"
+            },
+            Test {
+                input: "84fb51b517df6c5accb5d022f8f28da09b10232d42320ffc32dbecc3835b29",
+                output_str: "6a6857fba903b9da2753690c39c548be008e22ebb372eeaa16c85918"
+            },
+            Test {
+                input: "9f2fcc7c90de090d6b87cd7e9718c1ea6cb21118fc2d5de9f97e5db6ac1e9c10",
+                output_str: "887921848ad98458f3db3e0ecd5ad5db1f0bf9f2d0ca08601074d597"
+            },
+            Test {
+                input: "de8f1b3faa4b7040ed4563c3b8e598253178e87e4d0df75e4ff2f2dedd5a0be046",
+                output_str: "e0573ad706b44d8c4d204f884b95ab18913e76f41cf29a16dbe34794"
+            },
+            Test {
+                input: "62f154ec394d0bc757d045c798c8b87a00e0655d0481a7d2d9fb58d93aedc676b5a0",
+                output_str: "ba31233099055483c99f7ad82d0d24af487ed4b53fff1a892a55ddb3"
+            },
+            Test {
+                input: "b2dcfe9ff19e2b23ce7da2a4207d3e5ec7c6112a8a22aec9675a886378e14e5bfbad4e",
+                output_str: "befaa1cb47cf78ddd4e096b861bc340b776f52e351ebe378ade305ba"
+            },
+            Test {
+                input: "47f5697ac8c31409c0868827347a613a3562041c633cf1f1f86865a576e02835ed2c2492",
+                output_str: "f1e7a1b28ea4d6fb86570f66911e3258c3f49f891654fbce9bc79b8b"
+            },
+            Test {
+                input: "512a6d292e67ecb2fe486bfe92660953a75484ff4c4f2eca2b0af0edcdd4339c6b2ee4e542",
+                output_str: "c2b31746446934fe29e84cfb5c25b03be33e9004f74e91c1af0db789"
+            },
+            Test {
+                input: "973cf2b4dcf0bfa872b41194cb05bb4e16760a1840d8343301802576197ec19e2a1493d8f4fb",
+                output_str: "3a80645fe4271346aaedc3ae5011b75df163fad3ee6128d87f3d9da3"
+            },
+            Test {
+                input: "80beebcd2e3f8a9451d4499961c9731ae667cdc24ea020ce3b9aa4bbc0a7f79e30a934467da4b0",
+                output_str: "3c5ebe43a2571bcef25e4ea67a4ca9838770d23599059955af93ff83"
+            },
+            Test {
+                input: "7abaa12ec2a7347674e444140ae0fb659d08e1c66decd8d6eae925fa451d65f3c0308e29446b8ed3",
+                output_str: "af71dab0f33d3b48733ad6335ca609398d894e6fa96f5510ae73e5d2"
+            },
+            Test {
+                input: "c88dee9927679b8af422abcbacf283b904ff31e1cac58c7819809f65d5807d46723b20f67ba610c2b7",
+                output_str: "dd7512daa0c634cc1588870b84691d7de2c182e5570d57868e7dda5d"
+            },
+            Test {
+                input: "01e43fe350fcec450ec9b102053e6b5d56e09896e0ddd9074fe138e6038210270c834ce6eadc2bb86bf6",
+                output_str: "6cb4f9292ba33ca8d293b7a7ef76619e77309ba2178cd4a130bf9218"
+            },
+            Test {
+                input: "337023370a48b62ee43546f17c4ef2bf8d7ecd1d49f90bab604b839c2e6e5bd21540d29ba27ab8e309a4b7",
+                output_str: "a9b8435e55fc50fe935ec96798a629c13e856c3c5cfd248126976e0d"
+            },
+            Test {
+                input: "6892540f964c8c74bd2db02c0ad884510cb38afd4438af31fc912756f3efec6b32b58ebc38fc2a6b913596a8",
+                output_str: "93e79850622b91f729ab056ea402e27f01b5323158111b29362a96d5"
+            },
+            Test {
+                input: "f5961dfd2b1ffffda4ffbf30560c165bfedab8ce0be525845deb8dc61004b7db38467205f5dcfb34a2acfe96c0",
+                output_str: "7e51d5531382490670115de13137cb3adb6e7621b7d9eca8170faa96"
+            },
+            Test {
+                input: "ca061a2eb6ceed8881ce2057172d869d73a1951e63d57261384b80ceb5451e77b06cf0f5a0ea15ca907ee1c27eba",
+                output_str: "95c35037a8076926fc5c421c35160ac5fe533a2782f20f2d3f4b1b7d"
+            },
+            Test {
+                input: "1743a77251d69242750c4f1140532cd3c33f9b5ccdf7514e8584d4a5f9fbd730bcf84d0d4726364b9bf95ab251d9bb",
+                output_str: "bf024a4fe480636118fcc85b807704d59b64d16a150aa53cde41f030"
+            },
+            Test {
+                input: "d8faba1f5194c4db5f176fabfff856924ef627a37cd08cf55608bba8f1e324d7c7f157298eabc4dce7d89ce5162499f9",
+                output_str: "b7a51fbb084deeb55136efd7260e5b112e3c40d1a2d14b142df930df"
+            },
+            Test {
+                input: "be9684be70340860373c9c482ba517e899fc81baaa12e5c6d7727975d1d41ba8bef788cdb5cf4606c9c1c7f61aed59f97d",
+                output_str: "61cf830a2c4f8f48bc643f97a25f822c013f73bdf4cb4194bc8d55df"
+            },
+            Test {
+                input: "7e15d2b9ea74ca60f66c8dfab377d9198b7b16deb6a1ba0ea3c7ee2042f89d3786e779cf053c77785aa9e692f821f14a7f51",
+                output_str: "d87f62ea811a2f6bf3c5fde13475b9c676620c0184f87149dc8686c8"
+            },
+            Test {
+                input: "9a219be43713bd578015e9fda66c0f2d83cac563b776ab9f38f3e4f7ef229cb443304fba401efb2bdbd7ece939102298651c86",
+                output_str: "028a639c7ec0ba1dcec0b689aa26e2c0167622462669a5c52031602b"
+            },
+            Test {
+                input: "c8f2b693bd0d75ef99caebdc22adf4088a95a3542f637203e283bbc3268780e787d68d28cc3897452f6a22aa8573ccebf245972a",
+                output_str: "908ef28ab2b6cbb449b9af7fa78b3d90e019c3916562eb4819a0c87f"
+            },
+            Test {
+                input: "ec0f99711016c6a2a07ad80d16427506ce6f441059fd269442baaa28c6ca037b22eeac49d5d894c0bf66219f2c08e9d0e8ab21de52",
+                output_str: "6ac84149f890e1352c6d7397dac3b3773947b3757e8ed4ec059ef899"
+            },
+            Test {
+                input: "0dc45181337ca32a8222fe7a3bf42fc9f89744259cff653504d6051fe84b1a7ffd20cb47d4696ce212a686bb9be9a8ab1c697b6d6a33",
+                output_str: "45da27715cd75f5875beb7d914cf7488240d1b1f975d430d2f49e9bf"
+            },
+            Test {
+                input: "de286ba4206e8b005714f80fb1cdfaebde91d29f84603e4a3ebc04686f99a46c9e880b96c574825582e8812a26e5a857ffc6579f63742f",
+                output_str: "63afbabbec072140dfcefe64cf7bc9534dca10956042e31dbe58d0a5"
+            },
+            Test {
+                input: "eebcc18057252cbf3f9c070f1a73213356d5d4bc19ac2a411ec8cdeee7a571e2e20eaf61fd0c33a0ffeb297ddb77a97f0a415347db66bcaf",
+                output_str: "6487193d9cbe593b3daa50d4dfdf7dd2612300bb93cb39e3eefa1afa"
+            },
+            Test {
+                input: "416b5cdc9fe951bd361bd7abfc120a5054758eba88fdd68fd84e39d3b09ac25497d36b43cbe7b85a6a3cebda8db4e5549c3ee51bb6fcb6ac1e",
+                output_str: "0dec25be3277e27d4f784ad5ff8f79d61d9a309bd693513acbeed12f"
+            },
+            Test {
+                input: "5c5faf66f32e0f8311c32e8da8284a4ed60891a5a7e50fb2956b3cbaa79fc66ca376460e100415401fc2b8518c64502f187ea14bfc9503759705",
+                output_str: "130b67c6d1a5616227abd73abf6feb70fce1d5a4bf3338c6dccb39d5"
+            },
+            Test {
+                input: "7167e1e02be1a7ca69d788666f823ae4eef39271f3c26a5cf7cee05bca83161066dc2e217b330df821103799df6d74810eed363adc4ab99f36046a",
+                output_str: "3abb5acb8485e20bb620d4a030b9c25d3156a9b26893ae007c79f305"
+            },
+            Test {
+                input: "2fda311dbba27321c5329510fae6948f03210b76d43e7448d1689a063877b6d14c4f6d0eaa96c150051371f7dd8a4119f7da5c483cc3e6723c01fb7d",
+                output_str: "922e216529a95305307e908c69367ebb9ad931eca314563ac36aab80"
+            },
+            Test {
+                input: "95d1474a5aab5d2422aca6e481187833a6212bd2d0f91451a67dd786dfc91dfed51b35f47e1deb8a8ab4b9cb67b70179cc26f553ae7b569969ce151b8d",
+                output_str: "c72e93a2c39abcd90ab11cd3f15d59da3c23c0f17c4e26c9c5890887"
+            },
+            Test {
+                input: "c71bd7941f41df044a2927a8ff55b4b467c33d089f0988aa253d294addbdb32530c0d4208b10d9959823f0c0f0734684006df79f7099870f6bf53211a88d",
+                output_str: "cccc3b59f28c3fc462dc0a696150f5aea62da0aba97c476bd0d866c1"
+            },
+            Test {
+                input: "f57c64006d9ea761892e145c99df1b24640883da79d9ed5262859dcda8c3c32e05b03d984f1ab4a230242ab6b78d368dc5aaa1e6d3498d53371e84b0c1d4ba",
+                output_str: "28cfd0c6f0208d24aaa69e6c39f5257c13303e91c2d683a9af29b973"
+            },
+            Test {
+                input: "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7",
+                output_str: "c154607f986f9bf902d831293c8386d36b201eaba6f6fb0b678b4b81"
+            },
+            Test {
+                input: "16e8b3d8f988e9bb04de9c96f2627811c973ce4a5296b4772ca3eefeb80a652bdf21f50df79f32db23f9f73d393b2d57d9a0297f7a2f2e79cfda39fa393df1ac00",
+                output_str: "95e87ac90f541ab90cbcf7fd7e0e0c152cef78d5ee1830e9ed8a1ed7"
+            },
+            Test {
+                input: "fc424eeb27c18a11c01f39c555d8b78a805b88dba1dc2a42ed5e2c0ec737ff68b2456d80eb85e11714fa3f8eabfb906d3c17964cb4f5e76b29c1765db03d91be37fc",
+                output_str: "35bd7d02541d6d4b10ace6029a24c07a38fd563aba227f0f776ea5e2"
+            },
+            Test {
+                input: "abe3472b54e72734bdba7d9158736464251c4f21b33fbbc92d7fac9a35c4e3322ff01d2380cbaa4ef8fb07d21a2128b7b9f5b6d9f34e13f39c7ffc2e72e47888599ba5",
+                output_str: "99decb8cf1d474970b3cfa87fa462b75e3287b98b4be4093429e22d6"
+            },
+            Test {
+                input: "36f9f0a65f2ca498d739b944d6eff3da5ebba57e7d9c41598a2b0e4380f3cf4b479ec2348d015ffe6256273511154afcf3b4b4bf09d6c4744fdd0f62d75079d440706b05",
+                output_str: "8c20fd3d8e08235b01727a4df44d86e71e824f14b0c2fe4e8da7f1bb"
+            },
+            Test {
+                input: "abc87763cae1ca98bd8c5b82caba54ac83286f87e9610128ae4de68ac95df5e329c360717bd349f26b872528492ca7c94c2c1e1ef56b74dbb65c2ac351981fdb31d06c77a4",
+                output_str: "e29e68439aecde56f5297fb935dc7dbe63d61ce360a19629195bd8aa"
+            },
+            Test {
+                input: "94f7ca8e1a54234c6d53cc734bb3d3150c8ba8c5f880eab8d25fed13793a9701ebe320509286fd8e422e931d99c98da4df7e70ae447bab8cffd92382d8a77760a259fc4fbd72",
+                output_str: "5d2164da84e7707cd1e789711a664ab2ebcf66eba899a909a1d0cbec"
+            },
+            Test {
+                input: "13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d",
+                output_str: "fa263b093ea3f96b52db6251ea25a5254ada5b54d476cb0794d38889"
+            },
+            Test {
+                input: "1eed9cba179a009ec2ec5508773dd305477ca117e6d569e66b5f64c6bc64801ce25a8424ce4a26d575b8a6fb10ead3fd1992edddeec2ebe7150dc98f63adc3237ef57b91397aa8a7",
+                output_str: "d803e320a9865ebf3555e8a3e3134768a2ee1b3e59fa15f35c2ec550"
+            },
+            Test {
+                input: "ba5b67b5ec3a3ffae2c19dd8176a2ef75c0cd903725d45c9cb7009a900c0b0ca7a2967a95ae68269a6dbf8466c7b6844a1d608ac661f7eff00538e323db5f2c644b78b2d48de1a08aa",
+                output_str: "102925b63b3e9395f88124c3bfa777f29a5b41c13b62add7c271cd6e"
+            },
+            Test {
+                input: "0efa26ac5673167dcacab860932ed612f65ff49b80fa9ae65465e5542cb62075df1c5ae54fba4db807be25b070033efa223bdd5b1d3c94c6e1909c02b620d4b1b3a6c9fed24d70749604",
+                output_str: "6c4e83cd9258205f3c2bcf64149f4acdcee7742cb2d36038537171bd"
+            },
+            Test {
+                input: "bbfd933d1fd7bf594ac7f435277dc17d8d5a5b8e4d13d96d2f64e771abbd51a5a8aea741beccbddb177bcea05243ebd003cfdeae877cca4da94605b67691919d8b033f77d384ca01593c1b",
+                output_str: "c74c9ebb2ef9a9822a6228bd1186dcc4411bc59ec938df27e54b0815"
+            },
+            Test {
+                input: "90078999fd3c35b8afbf4066cbde335891365f0fc75c1286cdd88fa51fab94f9b8def7c9ac582a5dbcd95817afb7d1b48f63704e19c2baa4df347f48d4a6d603013c23f1e9611d595ebac37c",
+                output_str: "d23420f9985d66f097d43a0fb2434149d2b33f21b5bad6cfc250e072"
+            },
+            Test {
+                input: "64105eca863515c20e7cfbaa0a0b8809046164f374d691cdbd6508aaabc1819f9ac84b52bafc1b0fe7cddbc554b608c01c8904c669d8db316a0953a4c68ece324ec5a49ffdb59a1bd6a292aa0e",
+                output_str: "102edd2e946f33dd7aa553ea4ce4e659c7b240e1e28bc66200845d87"
+            },
+            Test {
+                input: "d4654be288b9f3b711c2d02015978a8cc57471d5680a092aa534f7372c71ceaab725a383c4fcf4d8deaa57fca3ce056f312961eccf9b86f14981ba5bed6ab5b4498e1f6c82c6cae6fc14845b3c8a",
+                output_str: "7c8eb98b7338403c013d65c0b5bb4b5d2cbf539cb1109cf447fa6650"
+            },
+            Test {
+                input: "12d9394888305ac96e65f2bf0e1b18c29c90fe9d714dd59f651f52b88b3008c588435548066ea2fc4c101118c91f32556224a540de6efddbca296ef1fb00341f5b01fecfc146bdb251b3bdad556cd2",
+                output_str: "c7b07de91efce42dab78199ee2eb3014a494994236a12b3de2330c25"
+            },
+            Test {
+                input: "871a0d7a5f36c3da1dfce57acd8ab8487c274fad336bc137ebd6ff4658b547c1dcfab65f037aa58f35ef16aff4abe77ba61f65826f7be681b5b6d5a1ea8085e2ae9cd5cf0991878a311b549a6d6af230",
+                output_str: "2fcef2594ae855de4fc66dccc517a659118b3a9f2e5fe638980adbfb"
+            },
+            Test {
+                input: "e90b4ffef4d457bc7711ff4aa72231ca25af6b2e206f8bf859d8758b89a7cd36105db2538d06da83bad5f663ba11a5f6f61f236fd5f8d53c5e89f183a3cec615b50c7c681e773d109ff7491b5cc22296c5",
+                output_str: "d45873f0453cbf38156a1384e33e5c76588b7bfb48a709b3943d9186"
+            },
+            Test {
+                input: "e728de62d75856500c4c77a428612cd804f30c3f10d36fb219c5ca0aa30726ab190e5f3f279e0733d77e7267c17be27d21650a9a4d1e32f649627638dbada9702c7ca303269ed14014b2f3cf8b894eac8554",
+                output_str: "3543add5b7edfc83afe7c1f2d55140aedb858304628109fd077b3860"
+            },
+            Test {
+                input: "6348f229e7b1df3b770c77544e5166e081850fa1c6c88169db74c76e42eb983facb276ad6a0d1fa7b50d3e3b6fcd799ec97470920a7abed47d288ff883e24ca21c7f8016b93bb9b9e078bdb9703d2b781b616e",
+                output_str: "36784f114958d8b5b625dd89a4e3973a113e5d1610dfa55b4fb45aec"
+            },
+            Test {
+                input: "4b127fde5de733a1680c2790363627e63ac8a3f1b4707d982caea258655d9bf18f89afe54127482ba01e08845594b671306a025c9a5c5b6f93b0a39522dc877437be5c2436cbf300ce7ab6747934fcfc30aeaaf6",
+                output_str: "4187feaed4fbd3d505a96a8d60668a88172e4f7c8451a4a6802c5747"
+            },
+            Test {
+                input: "08461f006cff4cc64b752c957287e5a0faabc05c9bff89d23fd902d324c79903b48fcb8f8f4b01f3e4ddb483593d25f000386698f5ade7faade9615fdc50d32785ea51d49894e45baa3dc707e224688c6408b68b11",
+                output_str: "6e4766db4e9d1102cee6dfe0ae2221321b9c0fe707f0a7825d7557ec"
+            },
+            Test {
+                input: "68c8f8849b120e6e0c9969a5866af591a829b92f33cd9a4a3196957a148c49138e1e2f5c7619a6d5edebe995acd81ec8bb9c7b9cfca678d081ea9e25a75d39db04e18d475920ce828b94e72241f24db72546b352a0e4",
+                output_str: "e1fc972bfb294185f1980ca2938655fb583e812ad3d64fa5a4cf703e"
+            },
+            Test {
+                input: "b8d56472954e31fb54e28fca743f84d8dc34891cb564c64b08f7b71636debd64ca1edbdba7fc5c3e40049ce982bba8c7e0703034e331384695e9de76b5104f2fbc4535ecbeebc33bc27f29f18f6f27e8023b0fbb6f563c",
+                output_str: "f6f28e3b65b684c9d9506061980046061390ccde2458a20f9b086be5"
+            },
+            Test {
+                input: "0d58ac665fa84342e60cefee31b1a4eacdb092f122dfc68309077aed1f3e528f578859ee9e4cefb4a728e946324927b675cd4f4ac84f64db3dacfe850c1dd18744c74ceccd9fe4dc214085108f404eab6d8f452b5442a47d",
+                output_str: "f686d2b1386b02b08f6b02bd5d50206d5e138440cb0d93ebcc3b32a7"
+            },
+            Test {
+                input: "1755e2d2e5d1c1b0156456b539753ff416651d44698e87002dcf61dcfa2b4e72f264d9ad591df1fdee7b41b2eb00283c5aebb3411323b672eaa145c5125185104f20f335804b02325b6dea65603f349f4d5d8b782dd3469ccd",
+                output_str: "46483375d112fc2be7f611be4b98dfada38892c43cefa586726b48bb"
+            },
+            Test {
+                input: "b180de1a611111ee7584ba2c4b020598cd574ac77e404e853d15a101c6f5a2e5c801d7d85dc95286a1804c870bb9f00fd4dcb03aa8328275158819dcad7253f3e3d237aeaa7979268a5db1c6ce08a9ec7c2579783c8afc1f91a7",
+                output_str: "e1e9ad568ae5b0d9731400ba4fc7df0321a04ea41393ba6979c7179c"
+            },
+            Test {
+                input: "cf3583cbdfd4cbc17063b1e7d90b02f0e6e2ee05f99d77e24e560392535e47e05077157f96813544a17046914f9efb64762a23cf7a49fe52a0a4c01c630cfe8727b81fb99a89ff7cc11dca5173057e0417b8fe7a9efba6d95c555f",
+                output_str: "133f31d9fbc1b2a33f1c98bfe21e129e0716a69ee27408743fff17ac"
+            },
+            Test {
+                input: "072fc02340ef99115bad72f92c01e4c093b9599f6cfc45cb380ee686cb5eb019e806ab9bd55e634ab10aa62a9510cc0672cd3eddb589c7df2b67fcd3329f61b1a4441eca87a33c8f55da4fbbad5cf2b2527b8e983bb31a2fadec7523",
+                output_str: "31328f04ca64e8521a36a8943c33ceb95be1b9080f4533d6da07606d"
+            },
+            Test {
+                input: "76eecf956a52649f877528146de33df249cd800e21830f65e90f0f25ca9d6540fde40603230eca6760f1139c7f268deba2060631eea92b1fff05f93fd5572fbe29579ecd48bc3a8d6c2eb4a6b26e38d6c5fbf2c08044aeea470a8f2f26",
+                output_str: "add374b1d279469c08e7b27ae3ff1b04c3d0fb3ef6e59aa3af86660b"
+            },
+            Test {
+                input: "7adc0b6693e61c269f278e6944a5a2d8300981e40022f839ac644387bfac9086650085c2cdc585fea47b9d2e52d65a2b29a7dc370401ef5d60dd0d21f9e2b90fae919319b14b8c5565b0423cefb827d5f1203302a9d01523498a4db10374",
+                output_str: "fed7fde894d92cc3bb68fcc396b5eb00c4156f04fc9ced99d12cfa5b"
+            },
+            Test {
+                input: "e1fffa9826cce8b86bccefb8794e48c46cdf372013f782eced1e378269b7be2b7bf51374092261ae120e822be685f2e7a83664bcfbe38fe8633f24e633ffe1988e1bc5acf59a587079a57a910bda60060e85b5f5b6f776f0529639d9cce4bd",
+                output_str: "17fc0327de474c78f538b4f3981674ff470aa42ef3b82c0cc34de6da"
+            },
+            Test {
+                input: "69f9abba65592ee01db4dce52dbab90b08fc04193602792ee4daa263033d59081587b09bbe49d0b49c9825d22840b2ff5d9c5155f975f8f2c2e7a90c75d2e4a8040fe39f63bbafb403d9e28cc3b86e04e394a9c9e8065bd3c85fa9f0c7891600",
+                output_str: "88fefbe8995e296a9dee4da2b414d5a7e134045639a6b176c2d736ed"
+            },
+            Test {
+                input: "38a10a352ca5aedfa8e19c64787d8e9c3a75dbf3b8674bfab29b5dbfc15a63d10fae66cd1a6e6d2452d557967eaad89a4c98449787b0b3164ca5b717a93f24eb0b506ceb70cbbcb8d72b2a72993f909aad92f044e0b5a2c9ac9cb16a0ca2f81f49",
+                output_str: "c002732f6f38ab83828921f5fcb4a8ce1fc561b0e9fa214c5ff02192"
+            },
+            Test {
+                input: "6d8c6e449bc13634f115749c248c17cd148b72157a2c37bf8969ea83b4d6ba8c0ee2711c28ee11495f43049596520ce436004b026b6c1f7292b9c436b055cbb72d530d860d1276a1502a5140e3c3f54a93663e4d20edec32d284e25564f624955b52",
+                output_str: "44e9002f9d97d98bb439afc361f93bb959523e73136a2c65b2e2b066"
+            },
+            Test {
+                input: "6efcbcaf451c129dbe00b9cef0c3749d3ee9d41c7bd500ade40cdc65dedbbbadb885a5b14b32a0c0d087825201e303288a733842fa7e599c0c514e078f05c821c7a4498b01c40032e9f1872a1c925fa17ce253e8935e4c3c71282242cb716b2089ccc1",
+                output_str: "2bff16cba9e50762d2288eb780078462c086f4cbf59479f5387a0b27"
+            },
+            Test {
+                input: "433c5303131624c0021d868a30825475e8d0bd3052a022180398f4ca4423b98214b6beaac21c8807a2c33f8c93bd42b092cc1b06cedf3224d5ed1ec29784444f22e08a55aa58542b524b02cd3d5d5f6907afe71c5d7462224a3f9d9e53e7e0846dcbb4ce",
+                output_str: "5efdc3caa22ee2c2eb632d4c6645ce3ec63960dfd69a04bbe01156c5"
+            },
+            Test {
+                input: "a873e0c67ca639026b6683008f7aa6324d4979550e9bce064ca1e1fb97a30b147a24f3f666c0a72d71348ede701cf2d17e2253c34d1ec3b647dbcef2f879f4eb881c4830b791378c901eb725ea5c172316c6d606e0af7df4df7f76e490cd30b2badf45685f",
+                output_str: "e8fb64a74387c9a3e1ac4abc82d3591b6b349f2e5cde6584d8d7c371"
+            },
+            Test {
+                input: "006917b64f9dcdf1d2d87c8a6173b64f6587168e80faa80f82d84f60301e561e312d9fbce62f39a6fb476e01e925f26bcc91de621449be6504c504830aae394096c8fc7694651051365d4ee9070101ec9b68086f2ea8f8ab7b811ea8ad934d5c9b62c60a4771",
+                output_str: "db224bccf5ca86dfba3ea372e2269750b532409ea004e82d4b5835e8"
+            },
+            Test {
+                input: "f13c972c52cb3cc4a4df28c97f2df11ce089b815466be88863243eb318c2adb1a417cb1041308598541720197b9b1cb5ba2318bd5574d1df2174af14884149ba9b2f446d609df240ce335599957b8ec80876d9a085ae084907bc5961b20bf5f6ca58d5dab38adb",
+                output_str: "4e28867dcef3a7b759ca24d8107beb0cbf9db0f10a3c410a9b4ba8c8"
+            },
+            Test {
+                input: "e35780eb9799ad4c77535d4ddb683cf33ef367715327cf4c4a58ed9cbdcdd486f669f80189d549a9364fa82a51a52654ec721bb3aab95dceb4a86a6afa93826db923517e928f33e3fba850d45660ef83b9876accafa2a9987a254b137c6e140a21691e1069413848",
+                output_str: "5c0c2df13a1fd6762b6e50fb3e080e649c3a7a8dda415c42fb637136"
+            },
+            Test {
+                input: "64ec021c9585e01ffe6d31bb50d44c79b6993d72678163db474947a053674619d158016adb243f5c8d50aa92f50ab36e579ff2dabb780a2b529370daa299207cfbcdd3a9a25006d19c4f1fe33e4b1eaec315d8c6ee1e730623fd1941875b924eb57d6d0c2edc4e78d6",
+                output_str: "36f5630ec2829b0fbad84f150932e46647edcc454e06b23166661d60"
+            },
+            Test {
+                input: "5954bab512cf327d66b5d9f296180080402624ad7628506b555eea8382562324cf452fba4a2130de3e165d11831a270d9cb97ce8c2d32a96f50d71600bb4ca268cf98e90d6496b0a6619a5a8c63db6d8a0634dfc6c7ec8ea9c006b6c456f1b20cd19e781af20454ac880",
+                output_str: "dac2594bcd357e63928a21e98348f27d0fa2c70eb07c7e8e93d6d84e"
+            },
+            Test {
+                input: "03d9f92b2c565709a568724a0aff90f8f347f43b02338f94a03ed32e6f33666ff5802da4c81bdce0d0e86c04afd4edc2fc8b4141c2975b6f07639b1994c973d9a9afce3d9d365862003498513bfa166d2629e314d97441667b007414e739d7febf0fe3c32c17aa188a8683",
+                output_str: "24970df3cf8c9e30dcbe661817ff74538ad43bc90b149ed7cab7811b"
+            },
+            Test {
+                input: "f31e8b4f9e0621d531d22a380be5d9abd56faec53cbd39b1fab230ea67184440e5b1d15457bd25f56204fa917fa48e669016cb48c1ffc1e1e45274b3b47379e00a43843cf8601a5551411ec12503e5aac43d8676a1b2297ec7a0800dbfee04292e937f21c005f17411473041",
+                output_str: "ad9bf420d2b570ebe7923a76b253f156f3513712955bcbb9a87394db"
+            },
+            Test {
+                input: "758ea3fea738973db0b8be7e599bbef4519373d6e6dcd7195ea885fc991d896762992759c2a09002912fb08e0cb5b76f49162aeb8cf87b172cf3ad190253df612f77b1f0c532e3b5fc99c2d31f8f65011695a087a35ee4eee5e334c369d8ee5d29f695815d866da99df3f79403",
+                output_str: "2f60928263fe1d5fa5136da8de1d2c3b60bd4b700a3e2c256e9536ef"
+            },
+            Test {
+                input: "47c6e0c2b74948465921868804f0f7bd50dd323583dc784f998a93cd1ca4c6ef84d41dc81c2c40f34b5bee6a93867b3bdba0052c5f59e6f3657918c382e771d33109122cc8bb0e1e53c4e3d13b43ce44970f5e0c079d2ad7d7a3549cd75760c21bb15b447589e86e8d76b1e9ced2",
+                output_str: "bfb40f7e7f81f2fec7644e08fbc99c768adc6314b8ccd833332f1bf8"
+            },
+            Test {
+                input: "f690a132ab46b28edfa6479283d6444e371c6459108afd9c35dbd235e0b6b6ff4c4ea58e7554bd002460433b2164ca51e868f7947d7d7a0d792e4abf0be5f450853cc40d85485b2b8857ea31b5ea6e4ccfa2f3a7ef3380066d7d8979fdac618aad3d7e886dea4f005ae4ad05e5065f",
+                output_str: "190e9fda8a7d78343ff24ade9fee69650c7631ad6329d17d4bd575db"
+            },
+            Test {
+                input: "58d6a99bc6458824b256916770a8417040721cccfd4b79eacd8b65a3767ce5ba7e74104c985ac56b8cc9aebd16febd4cda5adb130b0ff2329cc8d611eb14dac268a2f9e633c99de33997fea41c52a7c5e1317d5b5daed35eba7d5a60e45d1fa7eaabc35f5c2b0a0f2379231953322c4e",
+                output_str: "e26cd20b87083cb9f246d216e3da51ef7c5519b483db439d37256dbe"
+            },
+            Test {
+                input: "befab574396d7f8b6705e2d5b58b2c1c820bb24e3f4bae3e8fbcd36dbf734ee14e5d6ab972aedd3540235466e825850ee4c512ea9795abfd33f330d9fd7f79e62bbb63a6ea85de15beaeea6f8d204a28956059e2632d11861dfb0e65bc07ac8a159388d5c3277e227286f65ff5e5b5aec1",
+                output_str: "6caf807f6abc1a7721a5f209fc09fd00474b9e2a77ef7b57e1320271"
+            },
+            Test {
+                input: "8e58144fa9179d686478622ce450c748260c95d1ba43b8f9b59abeca8d93488da73463ef40198b4d16fb0b0707201347e0506ff19d01bea0f42b8af9e71a1f1bd168781069d4d338fdef00bf419fbb003031df671f4a37979564f69282de9c65407847dd0da505ab1641c02dea4f0d834986",
+                output_str: "64cd5291a1a0807ba7c14103a0f46c636795f8f8d3a12e59e88d9c51"
+            },
+            Test {
+                input: "b55c10eae0ec684c16d13463f29291bf26c82e2fa0422a99c71db4af14dd9c7f33eda52fd73d017cc0f2dbe734d831f0d820d06d5f89dacc485739144f8cfd4799223b1aff9031a105cb6a029ba71e6e5867d85a554991c38df3c9ef8c1e1e9a7630be61caabca69280c399c1fb7a12d12aefc",
+                output_str: "29491256a80bf1a9325348b5841edc726fa8a53117268c47f74b5e49"
+            },
+            Test {
+                input: "2eeea693f585f4ed6f6f8865bbae47a6908aecd7c429e4bec4f0de1d0ca0183fa201a0cb14a529b7d7ac0e6ff6607a3243ee9fb11bcf3e2304fe75ffcddd6c5c2e2a4cd45f63c962d010645058d36571404a6d2b4f44755434d76998e83409c3205aa1615db44057db991231d2cb42624574f545",
+                output_str: "a523449b770a8de3b39cd446046149feaee327d6d5b39929b9aac915"
+            },
+            Test {
+                input: "dab11dc0b047db0420a585f56c42d93175562852428499f66a0db811fcdddab2f7cdffed1543e5fb72110b64686bc7b6887a538ad44c050f1e42631bc4ec8a9f2a047163d822a38989ee4aab01b4c1f161b062d873b1cfa388fd301514f62224157b9bef423c7783b7aac8d30d65cd1bba8d689c2d",
+                output_str: "abb2fce213ce164c94ab7a763c21f638a3bb8d72f802deadacc023ae"
+            },
+            Test {
+                input: "42e99a2f80aee0e001279a2434f731e01d34a44b1a8101726921c0590c30f3120eb83059f325e894a5ac959dca71ce2214799916424e859d27d789437b9d27240bf8c35adbafcecc322b48aa205b293962d858652abacbd588bcf6cbc388d0993bd622f96ed54614c25b6a9aa527589eaaffcf17ddf7",
+                output_str: "c40d969f7218d71b904c4e4eaceb0473ba0a2e7339649da5dfeb8938"
+            },
+            Test {
+                input: "3c9b46450c0f2cae8e3823f8bdb4277f31b744ce2eb17054bddc6dff36af7f49fb8a2320cc3bdf8e0a2ea29ad3a55de1165d219adeddb5175253e2d1489e9b6fdd02e2c3d3a4b54d60e3a47334c37913c5695378a669e9b72dec32af5434f93f46176ebf044c4784467c700470d0c0b40c8a088c815816",
+                output_str: "2eb28fdf458d4fecb5b441d910b576f630e666bbf30aac90ab64425b"
+            },
+            Test {
+                input: "d1e654b77cb155f5c77971a64df9e5d34c26a3cad6c7f6b300d39deb1910094691adaa095be4ba5d86690a976428635d5526f3e946f7dc3bd4dbc78999e653441187a81f9adcd5a3c5f254bc8256b0158f54673dcc1232f6e918ebfc6c51ce67eaeb042d9f57eec4bfe910e169af78b3de48d137df4f2840",
+                output_str: "a3387b2fa23a13bfae77895f1f93935a0710ee3a027ff0d6399d8ecc"
+            },
+            Test {
+                input: "626f68c18a69a6590159a9c46be03d5965698f2dac3de779b878b3d9c421e0f21b955a16c715c1ec1e22ce3eb645b8b4f263f60660ea3028981eebd6c8c3a367285b691c8ee56944a7cd1217997e1d9c21620b536bdbd5de8925ff71dec6fbc06624ab6b21e329813de90d1e572dfb89a18120c3f606355d25",
+                output_str: "75755f46c2fc86bd4aae75919c6ca5b1a7375e466ca3170f70eee490"
+            },
+            Test {
+                input: "651a6fb3c4b80c7c68c6011675e6094eb56abf5fc3057324ebc6477825061f9f27e7a94633abd1fa598a746e4a577caf524c52ec1788471f92b8c37f23795ca19d559d446cab16cbcdce90b79fa1026cee77bf4ab1b503c5b94c2256ad75b3eac6fd5dcb96aca4b03a834bfb4e9af988cecbf2ae597cb9097940",
+                output_str: "7184c69ee1c43fd564102cd68ef898d5d0d8264b9b0d044691bc18af"
+            },
+            Test {
+                input: "8aaf072fce8a2d96bc10b3c91c809ee93072fb205ca7f10abd82ecd82cf040b1bc49ea13d1857815c0e99781de3adbb5443ce1c897e55188ceaf221aa9681638de05ae1b322938f46bce51543b57ecdb4c266272259d1798de13be90e10efec2d07484d9b21a3870e2aa9e06c21aa2d0c9cf420080a80a91dee16f",
+                output_str: "f50cf78ff46513c905399cc2510681a90ce089fced40fbc9cf218ca4"
+            },
+            Test {
+                input: "53f918fd00b1701bd504f8cdea803acca21ac18c564ab90c2a17da592c7d69688f6580575395551e8cd33e0fef08ca6ed4588d4d140b3e44c032355df1c531564d7f4835753344345a6781e11cd5e095b73df5f82c8ae3ad00877936896671e947cc52e2b29dcd463d90a0c9929128da222b5a211450bbc0e02448e2",
+                output_str: "f2aabe18d7b4dd8e4dc0ac8dcf4e9019c7c9af33d4b952da41219fe5"
+            },
+            Test {
+                input: "a64599b8a61b5ccec9e67aed69447459c8da3d1ec6c7c7c82a7428b9b584fa67e90f68e2c00fbbed4613666e5168da4a16f395f7a3c3832b3b134bfc9cbaa95d2a0fe252f44ac6681eb6d40ab91c1d0282fed6701c57463d3c5f2bb8c6a7301fb4576aa3b5f15510db8956ff77478c26a7c09bea7b398cfc83503f538e",
+                output_str: "ac5d00d177e71d7b9a97270e6200e4d3d07851eb2e58b12be0beed95"
+            },
+            Test {
+                input: "0e3ab0e054739b00cdb6a87bd12cae024b54cb5e550e6c425360c2e87e59401f5ec24ef0314855f0f56c47695d56a7fb1417693af2a1ed5291f2fee95f75eed54a1b1c2e81226fbff6f63ade584911c71967a8eb70933bc3f5d15bc91b5c2644d9516d3c3a8c154ee48e118bd1442c043c7a0dba5ac5b1d5360aae5b9065",
+                output_str: "cb7979b4c6c2826cdef7e1aada85f8c4546dd59d29fc0aea444f8077"
+            },
+            Test {
+                input: "a62fc595b4096e6336e53fcdfc8d1cc175d71dac9d750a6133d23199eaac288207944cea6b16d27631915b4619f743da2e30a0c00bbdb1bbb35ab852ef3b9aec6b0a8dcc6e9e1abaa3ad62ac0a6c5de765de2c3711b769e3fde44a74016fff82ac46fa8f1797d3b2a726b696e3dea5530439acee3a45c2a51bc32dd055650b",
+                output_str: "f9d8ccf6684693c40c81ebbd006c49984fbaf3a2b2e905abe60765dd"
+            },
+            Test {
+                input: "2b6db7ced8665ebe9deb080295218426bdaa7c6da9add2088932cdffbaa1c14129bccdd70f369efb149285858d2b1d155d14de2fdb680a8b027284055182a0cae275234cc9c92863c1b4ab66f304cf0621cd54565f5bff461d3b461bd40df28198e3732501b4860eadd503d26d6e69338f4e0456e9e9baf3d827ae685fb1d817",
+                output_str: "ed1f6387a7be090277b65a5fcd7040c7be0eeaf0fd7f14968097873b"
+            },
+            Test {
+                input: "10db509b2cdcaba6c062ae33be48116a29eb18e390e1bbada5ca0a2718afbcd23431440106594893043cc7f2625281bf7de2655880966a23705f0c5155c2f5cca9f2c2142e96d0a2e763b70686cd421b5db812daced0c6d65035fde558e94f26b3e6dde5bd13980cc80292b723013bd033284584bff27657871b0cf07a849f4ae2",
+                output_str: "0a27ce6973cb22a8b10057a8e7a654058b71e6d8c69c653415ff0c81"
+            },
+            Test {
+                input: "9334de60c997bda6086101a6314f64e4458f5ff9450c509df006e8c547983c651ca97879175aaba0c539e82d05c1e02c480975cbb30118121061b1ebac4f8d9a3781e2db6b18042e01ecf9017a64a0e57447ec7fcbe6a7f82585f7403ee2223d52d37b4bf426428613d6b4257980972a0acab508a7620c1cb28eb4e9d30fc41361ec",
+                output_str: "be3be49980f43fb6598be921d7d8fda1f397f605d9708c5d125c4e9f"
+            },
+            Test {
+                input: "e88ab086891693aa535ceb20e64c7ab97c7dd3548f3786339897a5f0c39031549ca870166e477743ccfbe016b4428d89738e426f5ffe81626137f17aecff61b72dbee2dc20961880cfe281dfab5ee38b1921881450e16032de5e4d55ad8d4fca609721b0692bac79be5a06e177fe8c80c0c83519fb3347de9f43d5561cb8107b9b5edc",
+                output_str: "932137bf2cd32ddfd3ba80c525268730b6f7458601b5296aeb325183"
+            },
+            Test {
+                input: "fd19e01a83eb6ec810b94582cb8fbfa2fcb992b53684fb748d2264f020d3b960cb1d6b8c348c2b54a9fcea72330c2aaa9a24ecdb00c436abc702361a82bb8828b85369b8c72ece0082fe06557163899c2a0efa466c33c04343a839417057399a63a3929be1ee4805d6ce3e5d0d0967fe9004696a5663f4cac9179006a2ceb75542d75d68",
+                output_str: "796698ce24efcda8214d161138f3c7da6d7615e4cf1dac63b69941f9"
+            },
+            Test {
+                input: "59ae20b6f7e0b3c7a989afb28324a40fca25d8651cf1f46ae383ef6d8441587aa1c04c3e3bf88e8131ce6145cfb8973d961e8432b202fa5af3e09d625faad825bc19da9b5c6c20d02abda2fcc58b5bd3fe507bf201263f30543819510c12bc23e2ddb4f711d087a86edb1b355313363a2de996b891025e147036087401ccf3ca7815bf3c49",
+                output_str: "b216930e158d65fb1ff424f9eab6cd28996231ef5ee1d65dbe29d370"
+            },
+            Test {
+                input: "77ee804b9f3295ab2362798b72b0a1b2d3291dceb8139896355830f34b3b328561531f8079b79a6e9980705150866402fdc176c05897e359a6cb1a7ab067383eb497182a7e5aef7038e4c96d133b2782917417e391535b5e1b51f47d8ed7e4d4025fe98dc87b9c1622614bff3d1029e68e372de719803857ca52067cddaad958951cb2068cc6",
+                output_str: "af6c676a62288b2d25a862f8866b262a74e3d2a0d414b966ce601e14"
+            },
+            Test {
+                input: "b771d5cef5d1a41a93d15643d7181d2a2ef0a8e84d91812f20ed21f147bef732bf3a60ef4067c3734b85bc8cd471780f10dc9e8291b58339a677b960218f71e793f2797aea349406512829065d37bb55ea796fa4f56fd8896b49b2cd19b43215ad967c712b24e5032d065232e02c127409d2ed4146b9d75d763d52db98d949d3b0fed6a8052fbb",
+                output_str: "418c83eb01881b4f38544665201dd05c939ca047d31834f637342342"
+            },
+            Test {
+                input: "b32d95b0b9aad2a8816de6d06d1f86008505bd8c14124f6e9a163b5a2ade55f835d0ec3880ef50700d3b25e42cc0af050ccd1be5e555b23087e04d7bf9813622780c7313a1954f8740b6ee2d3f71f768dd417f520482bd3a08d4f222b4ee9dbd015447b33507dd50f3ab4247c5de9a8abd62a8decea01e3b87c8b927f5b08beb37674c6f8e380c04",
+                output_str: "64d78817714fe05272d3805e6e19056b1649036cdcd5094fd1cc890a"
+            },
+            Test {
+                input: "04410e31082a47584b406f051398a6abe74e4da59bb6f85e6b49e8a1f7f2ca00dfba5462c2cd2bfde8b64fb21d70c083f11318b56a52d03b81cac5eec29eb31bd0078b6156786da3d6d8c33098c5c47bb67ac64db14165af65b44544d806dde5f487d5373c7f9792c299e9686b7e5821e7c8e2458315b996b5677d926dac57b3f22da873c601016a0d",
+                output_str: "2c4e7c537d0e2af2261a669bc24bd0df16d2c72a7f98d7a5ef6a8150"
+            },
+            Test {
+                input: "8b81e9badde026f14d95c019977024c9e13db7a5cd21f9e9fc491d716164bbacdc7060d882615d411438aea056c340cdf977788f6e17d118de55026855f93270472d1fd18b9e7e812bae107e0dfde7063301b71f6cfe4e225cab3b232905a56e994f08ee2891ba922d49c3dafeb75f7c69750cb67d822c96176c46bd8a29f1701373fb09a1a6e3c7158f",
+                output_str: "df1fcb80ab380ca33bdb61f96adab334937e190f03c1b78b219e50f8"
+            },
+            Test {
+                input: "fa6eed24da6666a22208146b19a532c2ec9ba94f09f1def1e7fc13c399a48e41acc2a589d099276296348f396253b57cb0e40291bd282773656b6e0d8bea1cda084a3738816a840485fcf3fb307f777fa5feac48695c2af4769720258c77943fb4556c362d9cba8bf103aeb9034baa8ea8bfb9c4f8e6742ce0d52c49ea8e974f339612e830e9e7a9c29065",
+                output_str: "0dd77ada384cab6a7aced19cfc8048c2566d4303e2010c98d16a0516"
+            },
+            Test {
+                input: "9bb4af1b4f09c071ce3cafa92e4eb73ce8a6f5d82a85733440368dee4eb1cbc7b55ac150773b6fe47dbe036c45582ed67e23f4c74585dab509df1b83610564545642b2b1ec463e18048fc23477c6b2aa035594ecd33791af6af4cbc2a1166aba8d628c57e707f0b0e8707caf91cd44bdb915e0296e0190d56d33d8dde10b5b60377838973c1d943c22ed335e",
+                output_str: "b256d0d6b6d6a72e113d105ad9601c91933d53b20a30d8e2cf33f96d"
+            },
+            Test {
+                input: "2167f02118cc62043e9091a647cadbed95611a521fe0d64e8518f16c808ab297725598ae296880a773607a798f7c3cfce80d251ebec6885015f9abf7eaabae46798f82cb5926de5c23f44a3f9f9534b3c6f405b5364c2f8a8bdc5ca49c749bed8ce4ba48897062ae8424ca6dde5f55c0e42a95d1e292ca54fb46a84fbc9cd87f2d0c9e7448de3043ae22fdd229",
+                output_str: "b95f72512546e4af685931246717bc482bfe922789a26eef01bde82d"
+            },
+            Test {
+                input: "94b7fa0bc1c44e949b1d7617d31b4720cbe7ca57c6fa4f4094d4761567e389ecc64f6968e4064df70df836a47d0c713336b5028b35930d29eb7a7f9a5af9ad5cf441745baec9bb014ceeff5a41ba5c1ce085feb980bab9cf79f2158e03ef7e63e29c38d7816a84d4f71e0f548b7fc316085ae38a060ff9b8dec36f91ad9ebc0a5b6c338cbb8f6659d342a24368cf",
+                output_str: "628238a9532727cc83f8fdced11d138a17eee4822c5d3549157d6d5e"
+            },
+            Test {
+                input: "ea40e83cb18b3a242c1ecc6ccd0b7853a439dab2c569cfc6dc38a19f5c90acbf76aef9ea3742ff3b54ef7d36eb7ce4ff1c9ab3bc119cff6be93c03e208783335c0ab8137be5b10cdc66ff3f89a1bddc6a1eed74f504cbe7290690bb295a872b9e3fe2cee9e6c67c41db8efd7d863cf10f840fe618e7936da3dca5ca6df933f24f6954ba0801a1294cd8d7e66dfafec",
+                output_str: "ab0fd308590574d6f6130232d9fafa9ffcfea78579a6a8f67c590420"
+            },
+            Test {
+                input: "157d5b7e4507f66d9a267476d33831e7bb768d4d04cc3438da12f9010263ea5fcafbde2579db2f6b58f911d593d5f79fb05fe3596e3fa80ff2f761d1b0e57080055c118c53e53cdb63055261d7c9b2b39bd90acc32520cbbdbda2c4fd8856dbcee173132a2679198daf83007a9b5c51511ae49766c792a29520388444ebefe28256fb33d4260439cba73a9479ee00c63",
+                output_str: "d5134200dc98f4ca480cd24d24497737252b55977ae5a869ba27089d"
+            },
+            Test {
+                input: "836b34b515476f613fe447a4e0c3f3b8f20910ac89a3977055c960d2d5d2b72bd8acc715a9035321b86703a411dde0466d58a59769672aa60ad587b8481de4bba552a1645779789501ec53d540b904821f32b0bd1855b04e4848f9f8cfe9ebd8911be95781a759d7ad9724a7102dbe576776b7c632bc39b9b5e19057e226552a5994c1dbb3b5c7871a11f5537011044c53",
+                output_str: "494cbc9b649e48ec5ad7364aeb9c8edf4a4f400789ef203f7b818a44"
+            },
+            Test {
+                input: "cc7784a4912a7ab5ad3620aab29ba87077cd3cb83636adc9f3dc94f51edf521b2161ef108f21a0a298557981c0e53ce6ced45bdf782c1ef200d29bab81dd6460586964edab7cebdbbec75fd7925060f7da2b853b2b089588fa0f8c16ec6498b14c55dcee335cb3a91d698e4d393ab8e8eac0825f8adebeee196df41205c011674e53426caa453f8de1cbb57932b0b741d4c6",
+                output_str: "7ff8a28ab12074102aef3efb8904284b617237322a2bf701c9fcfefc"
+            },
+            Test {
+                input: "7639b461fff270b2455ac1d1afce782944aea5e9087eb4a39eb96bb5c3baaf0e868c8526d3404f9405e79e77bfac5ffb89bf1957b523e17d341d7323c302ea7083872dd5e8705694acdda36d5a1b895aaa16eca6104c82688532c8bfe1790b5dc9f4ec5fe95baed37e1d287be710431f1e5e8ee105bc42ed37d74b1e55984bf1c09fe6a1fa13ef3b96faeaed6a2a1950a12153",
+                output_str: "50cdbeab4bbaa0861f3e364af520f9d8b54e79e3871abca7bbb2bae5"
+            },
+            Test {
+                input: "eb6513fc61b30cfba58d4d7e80f94d14589090cf1d80b1df2e68088dc6104959ba0d583d585e9578ab0aec0cf36c48435eb52ed9ab4bbce7a5abe679c97ae2dbe35e8cc1d45b06dda3cf418665c57cbee4bbb47fa4caf78f4ee656fec237fe4eebbafa206e1ef2bd0ee4ae71bd0e9b2f54f91daadf1febfd7032381d636b733dcb3bf76fb14e23aff1f68ed3dbcf75c9b99c6f26",
+                output_str: "29b6b523c82f499078c73630ba38227bbd08ef1a2d67b425c058def5"
+            },
+            Test {
+                input: "1594d74bf5dde444265d4c04dad9721ff3e34cbf622daf341fe16b96431f6c4df1f760d34f296eb97d98d560ad5286fec4dce1724f20b54fd7df51d4bf137add656c80546fb1bf516d62ee82baa992910ef4cc18b70f3f8698276fcfb44e0ec546c2c39cfd8ee91034ff9303058b4252462f86c823eb15bf481e6b79cc3a02218595b3658e8b37382bd5048eaed5fd02c37944e73b",
+                output_str: "93ce0c8d4355300d4e63d6599129dea7420e5b609dbb35be432b12b5"
+            },
+            Test {
+                input: "4cfa1278903026f66fedd41374558be1b585d03c5c55dac94361df286d4bd39c7cb8037ed3b267b07c346626449d0cc5b0dd2cf221f7e4c3449a4be99985d2d5e67bff2923357ddeab5abcb4619f3a3a57b2cf928a022eb27676c6cf805689004fca4d41ea6c2d0a4789c7605f7bb838dd883b3ad3e6027e775bcf262881428099c7fff95b14c095ea130e0b9938a5e22fc52650f591",
+                output_str: "d02896d957b599869f2b2a4992a49eef7ab1308f456c78c809bdac88"
+            },
+            Test {
+                input: "d3e65cb92cfa79662f6af493d696a07ccf32aaadcceff06e73e8d9f6f909209e66715d6e978788c49efb9087b170ecf3aa86d2d4d1a065ae0efc8924f365d676b3cb9e2bec918fd96d0b43dee83727c9a93bf56ca2b2e59adba85696546a815067fc7a78039629d4948d157e7b0d826d1bf8e81237bab7321312fdaa4d521744f988db6fdf04549d0fdca393d639c729af716e9c8bba48",
+                output_str: "181e2301f629a569271bb740d32b1d3bd25acb179e9aebef98009ed4"
+            },
+            Test {
+                input: "842cc583504539622d7f71e7e31863a2b885c56a0ba62db4c2a3f2fd12e79660dc7205ca29a0dc0a87db4dc62ee47a41db36b9ddb3293b9ac4baae7df5c6e7201e17f717ab56e12cad476be49608ad2d50309e7d48d2d8de4fa58ac3cfeafeee48c0a9eec88498e3efc51f54d300d828dddccb9d0b06dd021a29cf5cb5b2506915beb8a11998b8b886e0f9b7a80e97d91a7d01270f9a7717",
+                output_str: "5cd017b269a6366c789d9cecaef3ee9c3575181a084266d78a028db7"
+            },
+            Test {
+                input: "6c4b0a0719573e57248661e98febe326571f9a1ca813d3638531ae28b4860f23c3a3a8ac1c250034a660e2d71e16d3acc4bf9ce215c6f15b1c0fc7e77d3d27157e66da9ceec9258f8f2bf9e02b4ac93793dd6e29e307ede3695a0df63cbdc0fc66fb770813eb149ca2a916911bee4902c47c7802e69e405fe3c04ceb5522792a5503fa829f707272226621f7c488a7698c0d69aa561be9f378",
+                output_str: "ac280a211c98a07f6fcbb719f250e3e5a6ba2c93a833976c9f3147eb"
+            },
+            Test {
+                input: "51b7dbb7ce2ffeb427a91ccfe5218fd40f9e0b7e24756d4c47cd55606008bdc27d16400933906fd9f30effdd4880022d081155342af3fb6cd53672ab7fb5b3a3bcbe47be1fd3a2278cae8a5fd61c1433f7d350675dd21803746cadca574130f01200024c6340ab0cc2cf74f2234669f34e9009ef2eb94823d62b31407f4ba46f1a1eec41641e84d77727b59e746b8a671bef936f05be820759fa",
+                output_str: "c284c9308a28b6d29ccaa7853f8c41badcddbc1aa4e99481a6ee2f4d"
+            },
+            Test {
+                input: "83599d93f5561e821bd01a472386bc2ff4efbd4aed60d5821e84aae74d8071029810f5e286f8f17651cd27da07b1eb4382f754cd1c95268783ad09220f5502840370d494beb17124220f6afce91ec8a0f55231f9652433e5ce3489b727716cf4aeba7dcda20cd29aa9a859201253f948dd94395aba9e3852bd1d60dda7ae5dc045b283da006e1cbad83cc13292a315db5553305c628dd091146597",
+                output_str: "3d9a979b34d45569e1c98d09dc62d03616c0251c41a8b90138750f1e"
+            },
+            Test {
+                input: "2be9bf526c9d5a75d565dd11ef63b979d068659c7f026c08bea4af161d85a462d80e45040e91f4165c074c43ac661380311a8cbed59cc8e4c4518e80cd2c78ab1cabf66bff83eab3a80148550307310950d034a6286c93a1ece8929e6385c5e3bb6ea8a7c0fb6d6332e320e71cc4eb462a2a62e2bfe08f0ccad93e61bedb5dd0b786a728ab666f07e0576d189c92bf9fb20dca49ac2d3956d47385e2",
+                output_str: "8ddc9f1e0f94c1247a67d6119a9169762c6c7f1ec7f611d61353ab30"
+            },
+            Test {
+                input: "ca76d3a12595a817682617006848675547d3e8f50c2210f9af906c0e7ce50b4460186fe70457a9e879e79fd4d1a688c70a347361c847ba0dd6aa52936eaf8e58a1be2f5c1c704e20146d366aeb3853bed9de9befe9569ac8aaea37a9fb7139a1a1a7d5c748605a8defb297869ebedd71d615a5da23496d11e11abbb126b206fa0a7797ee7de117986012d0362dcef775c2fe145ada6bda1ccb326bf644",
+                output_str: "46eda2622d49b9148b40b6014c75a4086eb9dd4740f0dd591aca53b2"
+            },
+            Test {
+                input: "f76b85dc67421025d64e93096d1d712b7baf7fb001716f02d33b2160c2c882c310ef13a576b1c2d30ef8f78ef8d2f465007109aad93f74cb9e7d7bef7c9590e8af3b267c89c15db238138c45833c98cc4a471a7802723ef4c744a853cf80a0c2568dd4ed58a2c9644806f42104cee53628e5bdf7b63b0b338e931e31b87c24b146c6d040605567ceef5960df9e022cb469d4c787f4cba3c544a1ac91f95f",
+                output_str: "57cfa137968c39eaa12533044b8265bb903ec16c8d17b6cf1f106c57"
+            },
+            Test {
+                input: "25b8c9c032ea6bcd733ffc8718fbb2a503a4ea8f71dea1176189f694304f0ff68e862a8197b839957549ef243a5279fc2646bd4c009b6d1edebf24738197abb4c992f6b1dc9ba891f570879accd5a6b18691a93c7d0a8d38f95b639c1daeb48c4c2f15ccf5b9d508f8333c32de78781b41850f261b855c4bebcc125a380c54d501c5d3bd07e6b52102116088e53d76583b0161e2a58d0778f091206aabd5a1",
+                output_str: "8730c219e19d9d37cb7a63a4ddd55e84dcb0236ef7c8828b2a23c9b9"
+            },
+            Test {
+                input: "21cfdc2a7ccb7f331b3d2eefff37e48ad9fa9c788c3f3c200e0173d99963e1cbca93623b264e920394ae48bb4c3a5bb96ffbc8f0e53f30e22956adabc2765f57fb761e147ecbf8567533db6e50c8a1f894310a94edf806dd8ca6a0e141c0fa7c9fae6c6ae65f18c93a8529e6e5b553bf55f25be2e80a9882bd37f145fecbeb3d447a3c4e46c21524cc55cdd62f521ab92a8ba72b897996c49bb273198b7b1c9e",
+                output_str: "61c01fb4a010f319d193cb6d36063751950a1a8f93539bea32f84ea1"
+            },
+            Test {
+                input: "4e452ba42127dcc956ef4f8f35dd68cb225fb73b5bc7e1ec5a898bba2931563e74faff3b67314f241ec49f4a7061e3bd0213ae826bab380f1f14faab8b0efddd5fd1bb49373853a08f30553d5a55ccbbb8153de4704f29ca2bdeef0419468e05dd51557ccc80c0a96190bbcc4d77ecff21c66bdf486459d427f986410f883a80a5bcc32c20f0478bb9a97a126fc5f95451e40f292a4614930d054c851acd019ccf",
+                output_str: "1459044df9c26f5e240f6a6b9380734cad84b6592fc9693ddd9f974e"
+            },
+            Test {
+                input: "fa85671df7dadf99a6ffee97a3ab9991671f5629195049880497487867a6c446b60087fac9a0f2fcc8e3b24e97e42345b93b5f7d3691829d3f8ccd4bb36411b85fc2328eb0c51cb3151f70860ad3246ce0623a8dc8b3c49f958f8690f8e3860e71eb2b1479a5cea0b3f8befd87acaf5362435eaeccb52f38617bc6c5c2c6e269ead1fbd69e941d4ad2012da2c5b21bcfbf98e4a77ab2af1f3fda3233f046d38f1dc8",
+                output_str: "eb5cc00173239851f3960edac336005109189dfc04b29ca4cdde5bc1"
+            },
+            Test {
+                input: "e90847ae6797fbc0b6b36d6e588c0a743d725788ca50b6d792352ea8294f5ba654a15366b8e1b288d84f5178240827975a763bc45c7b0430e8a559df4488505e009c63da994f1403f407958203cebb6e37d89c94a5eacf6039a327f6c4dbbc7a2a307d976aa39e41af6537243fc218dfa6ab4dd817b6a397df5ca69107a9198799ed248641b63b42cb4c29bfdd7975ac96edfc274ac562d0474c60347a078ce4c25e88",
+                output_str: "a640d4841390f47dc47d4bfcf130fcf51c5f2d491f91c13374ce5965"
+            },
+            Test {
+                input: "f6d5c2b6c93954fc627602c00c4ca9a7d3ed12b27173f0b2c9b0e4a5939398a665e67e69d0b12fb7e4ceb253e8083d1ceb724ac07f009f094e42f2d6f2129489e846eaff0700a8d4453ef453a3eddc18f408c77a83275617fabc4ea3a2833aa73406c0e966276079d38e8e38539a70e194cc5513aaa457c699383fd1900b1e72bdfb835d1fd321b37ba80549b078a49ea08152869a918ca57f5b54ed71e4fd3ac5c06729",
+                output_str: "85bb3ed98c4808d8f67c722c9119c54e6543b29e57bd4fb5cbc878c7"
+            },
+            Test {
+                input: "cf8562b1bed89892d67ddaaf3deeb28246456e972326dbcdb5cf3fb289aca01e68da5d59896e3a6165358b071b304d6ab3d018944be5049d5e0e2bb819acf67a6006111089e6767132d72dd85beddcbb2d64496db0cc92955ab4c6234f1eea24f2d51483f2e209e4589bf9519fac51b4d061e801125e605f8093bb6997bc163d551596fe4ab7cfae8fb9a90f6980480ce0c229fd1675409bd788354daf316240cfe0af93eb",
+                output_str: "50b7d0acb93211e0fc935f970bc43a00be829d6b3c137d4a7e3b2bc1"
+            },
+            Test {
+                input: "2ace31abb0a2e3267944d2f75e1559985db7354c6e605f18dc8470423fca30b7331d9b33c4a4326783d1caae1b4f07060eff978e4746bf0c7e30cd61040bd5ec2746b29863eb7f103ebda614c4291a805b6a4c8214230564a0557bc7102e0bd3ed23719252f7435d64d210ee2aafc585be903fa41e1968c50fd5d5367926df7a05e3a42cf07e656ff92de73b036cf8b19898c0cb34557c0c12c2d8b84e91181af467bc75a9d1",
+                output_str: "7cdc1782b39fc0eeb1f874d97c88051cf10508e0875fa173ac41cc8e"
+            },
+            Test {
+                input: "0d8d09aed19f1013969ce5e7eb92f83a209ae76be31c754844ea9116ceb39a22ebb6003017bbcf26555fa6624185187db8f0cb3564b8b1c06bf685d47f3286eda20b83358f599d2044bbf0583fab8d78f854fe0a596183230c5ef8e54426750eaf2cc4e29d3bdd037e734d863c2bd9789b4c243096138f7672c232314effdfc6513427e2da76916b5248933be312eb5dde4cf70804fb258ac5fb82d58d08177ac6f4756017fff5",
+                output_str: "ee5d508a4e75900193e99a04b8d838a18dedfcc431e7af3182a47dd6"
+            },
+            Test {
+                input: "c3236b73deb7662bf3f3daa58f137b358ba610560ef7455785a9befdb035a066e90704f929bd9689cef0ce3bda5acf4480bceb8d09d10b098ad8500d9b6071dfc3a14af6c77511d81e3aa8844986c3bea6f469f9e02194c92868cd5f51646256798ff0424954c1434bdfed9facb390b07d342e992936e0f88bfd0e884a0ddb679d0547ccdec6384285a45429d115ac7d235a717242021d1dc35641f5f0a48e8445dba58e6cb2c8ea",
+                output_str: "5942ba8b58a355f2aef07e29f8f9971301e877fa32d7025df552b1eb"
+            },
+            Test {
+                input: "b39feb8283eadc63e8184b51df5ae3fd41aac8a963bb0be1cd08aa5867d8d910c669221e73243360646f6553d1ca05a84e8dc0de05b6419ec349ca994480193d01c92525f3fb3dcefb08afc6d26947bdbbfd85193f53b50609c6140905c53a6686b58e53a319a57b962331ede98149af3de3118a819da4d76706a0424b4e1d2910b0ed26af61d150ebcb46595d4266a0bd7f651ba47d0c7f179ca28545007d92e8419d48fdfbd744ce",
+                output_str: "29240a9e973888b98a3a836933855d41d8abb6c3806a626c3df18f6c"
+            },
+            Test {
+                input: "a983d54f503803e8c7999f4edbbe82e9084f422143a932ddddc47a17b0b7564a7f37a99d0786e99476428d29e29d3c197a72bfab1342c12a0fc4787fd7017d7a6174049ea43b5779169ef7472bdbbd941dcb82fc73aac45a8a94c9f2bd3477f61fd3b796f02a1b8264a214c6fea74b7051b226c722099ec7883a462b83b6afdd4009248b8a237f605fe5a08fe7d8b45321421ebba67bd70a0b00ddbf94baab7f359d5d1eea105f28dcfb",
+                output_str: "9af178b1dd3cefc96227a289175bb61d9f6b0b352d7804f5e07ea45d"
+            },
+            Test {
+                input: "e4d1c1897a0a866ce564635b74222f9696bf2c7f640dd78d7e2aca66e1b61c642bb03ea7536aae597811e9bf4a7b453ede31f97b46a5f0ef51a071a2b3918df16b152519ae3776f9f1edab4c2a377c3292e96408359d3613844d5eb393000283d5ad3401a318b12fd1474b8612f2bb50fb6a8b9e023a54d7dde28c43d6d8854c8d9d1155935c199811dbfc87e9e0072e90eb88681cc7529714f8fb8a2c9d88567adfb974ee205a9bf7b848",
+                output_str: "f543b4d423eaac86338bb6d8c6181ad6dc0a25733953ced7eb8377f3"
+            },
+            Test {
+                input: "b10c59723e3dcadd6d75df87d0a1580e73133a9b7d00cb95ec19f5547027323be75158b11f80b6e142c6a78531886d9047b08e551e75e6261e79785366d7024bd7cd9cf322d9be7d57fb661069f2481c7bb759cd71b4b36ca2bc2df6d3a328faebdb995a9794a8d72155ed551a1f87c80bf6059b43fc764900b18a1c2441f7487743cf84e565f61f8dd2ece6b6ccc9444049197aaaf53e926fbee3bfca8be588ec77f29d211be89de18b15f6",
+                output_str: "77b4079eee9d9e3fda051ee0ca430b4df011d056612c1af446a187c2"
+            },
+            Test {
+                input: "db11f609baba7b0ca634926b1dd539c8cbada24967d7add4d9876f77c2d80c0f4dcefbd7121548373582705cca2495bd2a43716fe64ed26d059cfb566b3364bd49ee0717bdd9810dd14d8fad80dbbdc4cafb37cc60fb0fe2a80fb4541b8ca9d59dce457738a9d3d8f641af8c3fd6da162dc16fc01aac527a4a0255b4d231c0be50f44f0db0b713af03d968fe7f0f61ed0824c55c4b5265548febd6aad5c5eedf63efe793489c39b8fd29d104ce",
+                output_str: "987d30120c9aa4964650a6a730e99c86f7fbddb4ea8d6b4815ee4ebf"
+            },
+            Test {
+                input: "bebd4f1a84fc8b15e4452a54bd02d69e304b7f32616aadd90537937106ae4e28de9d8aab02d19bc3e2fde1d651559e296453e4dba94370a14dbbb2d1d4e2022302ee90e208321efcd8528ad89e46dc839ea9df618ea8394a6bff308e7726bae0c19bcd4be52da6258e2ef4e96aa21244429f49ef5cb486d7ff35cac1bacb7e95711944bccb2ab34700d42d1eb38b5d536b947348a458ede3dc6bd6ec547b1b0cae5b257be36a7124e1060c170ffa",
+                output_str: "46193359397bc3eacd69bff410203583382de93ecc4d80dcfb4fc51d"
+            },
+            Test {
+                input: "5aca56a03a13784bdc3289d9364f79e2a85c12276b49b92db0adaa4f206d5028f213f678c3510e111f9dc4c1c1f8b6acb17a6413aa227607c515c62a733817ba5e762cc6748e7e0d6872c984d723c9bb3b117eb8963185300a80bfa65cde495d70a46c44858605fccbed086c2b45cef963d33294dbe9706b13af22f1b7c4cd5a001cfec251fba18e722c6e1c4b1166918b4f6f48a98b64b3c07fc86a6b17a6d0480ab79d4e6415b520f1c484d675b1",
+                output_str: "0bc29107c7e25d44f8ce83a415b1de5df38a6719769606762b7192c2"
+            },
+            Test {
+                input: "a5aad0e4646a32c85cfcac73f02fc5300f1982fabb2f2179e28303e447854094cdfc854310e5c0f60993ceff54d84d6b46323d930adb07c17599b35b505f09e784bca5985e0172257797fb53649e2e9723efd16865c31b5c3d5113b58bb0bfc8920fabdda086d7537e66d709d050bd14d0c960873f156fad5b3d3840cdfcdc9be6af519db262a27f40896ab25cc39f96984d650611c0d5a3080d5b3a1bf186abd42956588b3b58cd948970d298776060",
+                output_str: "b485644c32283b280179f7c9714350f0b3acfd7c45a247bf3b6cdb07"
+            },
+            Test {
+                input: "06cbbe67e94a978203ead6c057a1a5b098478b4b4cbef5a97e93c8e42f5572713575fc2a884531d7622f8f879387a859a80f10ef02708cd8f7413ab385afc357678b9578c0ebf641ef076a1a30f1f75379e9dcb2a885bdd295905ee80c0168a62a9597d10cf12dd2d8cee46645c7e5a141f6e0e23aa482abe5661c16e69ef1e28371e2e236c359ba4e92c25626a7b7ff13f6ea4ae906e1cfe163e91719b1f750a96cbde5fbc953d9e576cd216afc90323a",
+                output_str: "f384542499efd23381debcd9124c539c40bfa70e517280f56a0920e1"
+            },
+            Test {
+                input: "f1c528cf7739874707d4d8ad5b98f7c77169de0b57188df233b2dc8a5b31eda5db4291dd9f68e6bad37b8d7f6c9c0044b3bf74bbc3d7d1798e138709b0d75e7c593d3cccdc1b20c7174b4e692add820ace262d45ccfae2077e878796347168060a162ecca8c38c1a88350bd63bb539134f700fd4addd5959e255337daa06bc86358fabcbefdfb5bc889783d843c08aadc6c4f6c36f65f156e851c9a0f917e4a367b5ad93d874812a1de6a7b93cd53ad97232",
+                output_str: "d12e3884bc8cf9175d1778e8a3aaa119e4a897738f8d81b1278bc448"
+            },
+            Test {
+                input: "9d9f3a7ecd51b41f6572fd0d0881e30390dfb780991dae7db3b47619134718e6f987810e542619dfaa7b505c76b7350c6432d8bf1cfebdf1069b90a35f0d04cbdf130b0dfc7875f4a4e62cdb8e525aadd7ce842520a482ac18f09442d78305fe85a74e39e760a4837482ed2f437dd13b2ec1042afcf9decdc3e877e50ff4106ad10a525230d11920324a81094da31deab6476aa42f20c84843cfc1c58545ee80352bdd3740dd6a16792ae2d86f11641bb717c2",
+                output_str: "d8a348264d48045d4482f3fe002c1a1f36d4df0d5e47fac5125c7947"
+            },
+            Test {
+                input: "5179888724819fbad3afa927d3577796660e6a81c52d98e9303261d5a4a83232f6f758934d50aa83ff9e20a5926dfebaac49529d006eb923c5ae5048ed544ec471ed7191edf46363383824f915769b3e688094c682b02151e5ee01e510b431c8865aff8b6b6f2f59cb6d129da79e97c6d2b8fa6c6da3f603199d2d1bcab547682a81cd6cf65f6551121391d78bcc23b5bd0e922ec6d8bf97c952e84dd28aef909aba31edb903b28fbfc33b7703cd996215a11238",
+                output_str: "6865464c6a230b4bf64ba33bf97459d1d22dafb19e08f4b7dace02ff"
+            },
+            Test {
+                input: "576ef3520d30b7a4899b8c0d5e359e45c5189add100e43be429a02fb3de5ff4f8fd0e79d9663acca72cd29c94582b19292a557c5b1315297d168fbb54e9e2ecd13809c2b5fce998edc6570545e1499dbe7fb74d47cd7f35823b212b05bf3f5a79caa34224fdd670d335fcb106f5d92c3946f44d3afcbae2e41ac554d8e6759f332b76be89a0324aa12c5482d1ea3ee89ded4936f3e3c080436f539fa137e74c6d3389bdf5a45074c47bc7b20b0948407a66d855e2f",
+                output_str: "19d33cd354a13ab2a44044154bd865f117ef8a887fbd0570a8a4ca80"
+            },
+            Test {
+                input: "0df2152fa4f4357c8741529dd77e783925d3d76e95bafa2b542a2c33f3d1d117d159cf473f82310356fee4c90a9e505e70f8f24859656368ba09381fa245eb6c3d763f3093f0c89b972e66b53d59406d9f01aea07f8b3b615cac4ee4d05f542e7d0dab45d67ccccd3a606ccbeb31ea1fa7005ba07176e60dab7d78f6810ef086f42f08e595f0ec217372b98970cc6321576d92ce38f7c397a403bada1548d205c343ac09deca86325373c3b76d9f32028fea8eb32515",
+                output_str: "e438ae4153463b333ae4fe57bf131505c8c04a534a39a20574155e49"
+            },
+            Test {
+                input: "3e15350d87d6ebb5c8ad99d42515cfe17980933c7a8f6b8bbbf0a63728cefaad2052623c0bd5931839112a48633fb3c2004e0749c87a41b26a8b48945539d1ff41a4b269462fd199bfecd45374756f55a9116e92093ac99451aefb2af9fd32d6d7f5fbc7f7a540d5097c096ebc3b3a721541de073a1cc02f7fb0fb1b9327fb0b1218ca49c9487ab5396622a13ae546c97abdef6b56380dda7012a8384091b6656d0ab272d363cea78163ff765cdd13ab1738b940d16cae",
+                output_str: "454796c7219c6f7e88508dfc13668b81748211bd016d84b59293b445"
+            },
+            Test {
+                input: "c38d6b0b757cb552be40940ece0009ef3b0b59307c1451686f1a22702922800d58bce7a636c1727ee547c01b214779e898fc0e560f8ae7f61bef4d75eaa696b921fd6b735d171535e9edd267c192b99880c87997711002009095d8a7a437e258104a41a505e5ef71e5613ddd2008195f0c574e6ba3fe40099cfa116e5f1a2fa8a6da04badcb4e2d5d0de31fdc4800891c45781a0aac7c907b56d631fca5ce8b2cde620d11d1777ed9fa603541de794ddc5758fcd5fad78c0",
+                output_str: "ce158aed6ed3c9d4432e2422af8d255ab1f3898f6f5b5c5a1478552c"
+            },
+            Test {
+                input: "8d2de3f0b37a6385c90739805b170057f091cd0c7a0bc951540f26a5a75b3e694631bb64c7635eed316f51318e9d8de13c70a2aba04a14836855f35e480528b776d0a1e8a23b547c8b8d6a0d09b241d3be9377160cca4e6793d00a515dc2992cb7fc741daca171431da99cce6f7789f129e2ac5cf65b40d703035cd2185bb936c82002daf8cbc27a7a9e554b06196630446a6f0a14ba155ed26d95bd627b7205c072d02b60db0fd7e49ea058c2e0ba202daff0de91e845cf79",
+                output_str: "a0a21d95e640f13b25652484e244be1b373e9b0609b685efce48107a"
+            },
+            Test {
+                input: "c464bbdad275c50dcd983b65ad1019b9ff85a1e71c807f3204bb2c921dc31fbcd8c5fc45868ae9ef85b6c9b83bba2a5a822201ed68586ec5ec27fb2857a5d1a2d09d09115f22dcc39fe61f5e1ba0ff6e8b4acb4c6da748be7f3f0839739394ff7fa8e39f7f7e84a33c3866875c01bcb1263c9405d91908e9e0b50e7459fabb63d8c6bbb73d8e3483c099b55bc30ff092ff68b6adedfd477d63570c9f5515847f36e24ba0b705557130cec57ebad1d0b31a378e91894ee26e3a04",
+                output_str: "ca8cb1359f0b05e2ff9414cce0de6d2cb4d05b08354c2119a87342ca"
+            },
+            Test {
+                input: "8b8d68bb8a75732fe272815a68a1c9c5aa31b41dedc8493e76525d1d013d33cebd9e21a5bb95db2616976a8c07fcf411f5f6bc6f7e0b57aca78cc2790a6f9b898858ac9c79b165ff24e66677531e39f572be5d81eb3264524181115f32780257bfb9aeec6af12af28e587cac068a1a2953b59ad680f4c245b2e3ec36f59940d37e1d3db38e13edb29b5c0f404f6ff87f80fc8be7a225ff22fbb9c8b6b1d7330c57840d24bc75b06b80d30dad6806544d510af6c4785e823ac3e0b8",
+                output_str: "0dddd152cf063f0f505b518eb8db755704f45c9735780ec3a898a923"
+            },
+            Test {
+                input: "6b018710446f368e7421f1bc0ccf562d9c1843846bc8d98d1c9bf7d9d6fcb48bfc3bf83b36d44c4fa93430af75cd190bde36a7f92f867f58a803900df8018150384d85d82132f123006ac2aeba58e02a037fe6afbd65eca7c44977dd3dc74f48b6e7a1bfd5cc4dcf24e4d52e92bd4455848e4928b0eac8b7476fe3cc03e862aa4dff4470dbfed6de48e410f25096487ecfc32a27277f3f5023b2725ade461b1355889554a8836c9cf53bd767f5737d55184eea1ab3f53edd0976c485",
+                output_str: "57397bb1f84711641e94f413f5d73556b96ba5cfe15f709528626d07"
+            },
+            Test {
+                input: "c9534a24714bd4be37c88a3da1082eda7cabd154c309d7bd670dccd95aa535594463058a29f79031d6ecaa9f675d1211e9359be82669a79c855ea8d89dd38c2c761ddd0ec0ce9e97597432e9a1beae062cdd71edfdfd464119be9e69d18a7a7fd7ce0e2106f0c8b0abf4715e2ca48ef9f454dc203c96656653b727083513f8efb86e49c513bb758b3b052fe21f1c05bb33c37129d6cc81f1aef6adc45b0e8827a830fe545cf57d0955802c117d23ccb55ea28f95c0d8c2f9c5a242b33f",
+                output_str: "68f6ac4289fd5214263130830fda4da601b88b1f8533eac07a0338d9"
+            },
+            Test {
+                input: "07906c87297b867abf4576e9f3cc7f82f22b154afcbf293b9319f1b0584da6a40c27b32e0b1b7f412c4f1b82480e70a9235b12ec27090a5a33175a2bb28d8adc475cefe33f7803f8ce27967217381f02e67a3b4f84a71f1c5228e0c2ad971373f6f672624fcea8d1a9f85170fad30fa0bbd25035c3b41a6175d467998bd1215f6f3866f53847f9cf68ef3e2fbb54bc994de2302b829c5eea68ec441fcbafd7d16ae4fe9fff98bf00e5bc2ad54dd91ff9fda4dd77b6c754a91955d1fbaad0",
+                output_str: "f145c45212392894e7f1c4e52728470f8a2d961514869990efbe8232"
+            },
+            Test {
+                input: "588e94b9054abc2189df69b8ba34341b77cdd528e7860e5defcaa79b0c9a452ad4b82aa306be84536eb7cedcbe058d7b84a6aef826b028b8a0271b69ac3605a9635ea9f5ea0aa700f3eb7835bc54611b922964300c953efe7491e3677c2cebe0822e956cd16433b02c68c4a23252c3f9e151a416b4963257b783e038f6b4d5c9f110f871652c7a649a7bcedcbccc6f2d0725bb903cc196ba76c76aa9f10a190b1d1168993baa9ffc96a1655216773458bec72b0e39c9f2c121378feab4e76a",
+                output_str: "38ce7100e92ee4b65cc831915a06cfc2101990cb68e1004f7e9017d4"
+            },
+            Test {
+                input: "08959a7e4baae874928813364071194e2939772f20db7c3157078987c557c2a6d5abe68d520eef3dc491692e1e21bcd880adebf63bb4213b50897fa005256ed41b5690f78f52855c8d9168a4b666fce2da2b456d7a7e7c17ab5f2fb1ee90b79e698712e963715983fd07641ae4b4e9dc73203fac1ae11fa1f8c7941fcc82eab247addb56e2638447e9d609e610b60ce086656aaebf1da3c8a231d7d94e2fd0afe46b391ff14a72eaeb3f44ad4df85866def43d4781a0b3578bc996c87970b132",
+                output_str: "bd63ca84dac8bc586d0f0be352dbbba1f4cb430deaa8119b8da13c06"
+            },
+            Test {
+                input: "cb2a234f45e2ecd5863895a451d389a369aab99cfef0d5c9ffca1e6e63f763b5c14fb9b478313c8e8c0efeb3ac9500cf5fd93791b789e67eac12fd038e2547cc8e0fc9db591f33a1e4907c64a922dda23ec9827310b306098554a4a78f050262db5b545b159e1ff1dca6eb734b872343b842c57eafcfda8405eedbb48ef32e99696d135979235c3a05364e371c2d76f1902f1d83146df9495c0a6c57d7bf9ee77e80f9787aee27be1fe126cdc9ef893a4a7dcbbc367e40fe4e1ee90b42ea25af01",
+                output_str: "7ee4eaea6127c68efce66991b8f0851fe072df3b1e0b5d07e3a4be06"
+            },
+            Test {
+                input: "d16beadf02ab1d4dc6f88b8c4554c51e866df830b89c06e786a5f8757e8909310af51c840efe8d20b35331f4355d80f73295974653ddd620cdde4730fb6c8d0d2dcb2b45d92d4fbdb567c0a3e86bd1a8a795af26fbf29fc6c65941cddb090ff7cd230ac5268ab4606fccba9eded0a2b5d014ee0c34f0b2881ac036e24e151be89eeb6cd9a7a790afccff234d7cb11b99ebf58cd0c589f20bdac4f9f0e28f75e3e04e5b3debce607a496d848d67fa7b49132c71b878fd5557e082a18eca1fbda94d4b",
+                output_str: "7f3ee578b0410687eaf536f9ec7d654b75f504c104b78793c4cf90d5"
+            },
+            Test {
+                input: "8f65f6bc59a85705016e2bae7fe57980de3127e5ab275f573d334f73f8603106ec3553016608ef2dd6e69b24be0b7113bf6a760ba6e9ce1c48f9e186012cf96a1d4849d75df5bb8315387fd78e9e153e76f8ba7ec6c8849810f59fb4bb9b004318210b37f1299526866f44059e017e22e96cbe418699d014c6ea01c9f0038b10299884dbec3199bb05adc94e955a1533219c1115fed0e5f21228b071f40dd57c4240d98d37b73e412fe0fa4703120d7c0c67972ed233e5deb300a22605472fa3a3ba86",
+                output_str: "c9c26396e560cd1e6824d9e56e179fcc8aac4c0d932f7632ba594d4c"
+            },
+            Test {
+                input: "84891e52e0d451813210c3fd635b39a03a6b7a7317b221a7abc270dfa946c42669aacbbbdf801e1584f330e28c729847ea14152bd637b3d0f2b38b4bd5bf9c791c58806281103a3eabbaede5e711e539e6a8b2cf297cf351c078b4fa8f7f35cf61bebf8814bf248a01d41e86c5715ea40c63f7375379a7eb1d78f27622fb468ab784aaaba4e534a6dfd1df6fa15511341e725ed2e87f98737ccb7b6a6dfae416477472b046bf1811187d151bfa9f7b2bf9acdb23a3be507cdf14cfdf517d2cb5fb9e4ab6",
+                output_str: "ef30652e3c6ea4ec214472bf96e5f30dca1d31a78eb422734615eaf1"
+            },
+            Test {
+                input: "fdd7a9433a3b4afabd7a3a5e3457e56debf78e84b7a0b0ca0e8c6d53bd0c2dae31b2700c6128334f43981be3b213b1d7a118d59c7e6b6493a86f866a1635c12859cfb9ad17460a77b4522a5c1883c3d6acc86e6162667ec414e9a104aa892053a2b1d72165a855bacd8faf8034a5dd9b716f47a0818c09bb6baf22aa503c06b4ca261f557761989d2afbd88b6a678ad128af68672107d0f1fc73c5ca740459297b3292b281e93bceb761bde7221c3a55708e5ec84472cddcaa84ecf23723cc0991355c6280",
+                output_str: "5a964bf38eb347684220a3e83eb1efcb641c8f911cb068a774b25b8c"
+            },
+            Test {
+                input: "70a40bfbef92277a1aad72f6b79d0177197c4ebd432668cfec05d099accb651062b5dff156c0b27336687a94b26679cfdd9daf7ad204338dd9c4d14114033a5c225bd11f217b5f4732da167ee3f939262d4043fc9cba92303b7b5e96aea12adda64859df4b86e9ee0b58e39091e6b188b408ac94e1294a8911245ee361e60e601eff58d1d37639f3753bec80ebb4efde25817436076623fc65415fe51d1b0280366d12c554d86743f3c3b6572e400361a60726131441ba493a83fbe9afda90f7af1ae717238d",
+                output_str: "07413665edcb8a35021874984910b498cf74823050640243ae7c84cd"
+            },
+            Test {
+                input: "74356e449f4bf8644f77b14f4d67cb6bd9c1f5ae357621d5b8147e562b65c66585caf2e491b48529a01a34d226d436959153815380d5689e30b35357cdac6e08d3f2b0e88e200600d62bd9f5eaf488df86a4470ea227006182e44809009868c4c280c43d7d64a5268fa719074960087b3a6abc837882f882c837834535929389a12b2c78187e2ea07ef8b8eef27dc85002c3ae35f1a50bee6a1c48ba7e175f3316670b27983472aa6a61eed0a683a39ee323080620ea44a9f74411ae5ce99030528f9ab49c79f2",
+                output_str: "fcc9ead160832f5f0fafed6381afd57fe1335fbfb05b7fb1f0075d37"
+            },
+            Test {
+                input: "8c3798e51bc68482d7337d3abb75dc9ffe860714a9ad73551e120059860dde24ab87327222b64cf774415a70f724cdf270de3fe47dda07b61c9ef2a3551f45a5584860248fabde676e1cd75f6355aa3eaeabe3b51dc813d9fb2eaa4f0f1d9f834d7cad9c7c695ae84b329385bc0bef895b9f1edf44a03d4b410cc23a79a6b62e4f346a5e8dd851c2857995ddbf5b2d717aeb847310e1f6a46ac3d26a7f9b44985af656d2b7c9406e8a9e8f47dcb4ef6b83caacf9aefb6118bfcff7e44bef6937ebddc89186839b77",
+                output_str: "ec5c6db60b0834fb2e0e7106aeeafb9e614be093c847018214d8a5db"
+            },
+            Test {
+                input: "fa56bf730c4f8395875189c10c4fb251605757a8fecc31f9737e3c2503b02608e6731e85d7a38393c67de516b85304824bfb135e33bf22b3a23b913bf6acd2b7ab85198b8187b2bcd454d5e3318cacb32fd6261c31ae7f6c54ef6a7a2a4c9f3ecb81ce3555d4f0ad466dd4c108a90399d70041997c3b25345a9653f3c9a6711ab1b91d6a9d2216442da2c973cbd685ee7643bfd77327a2f7ae9cb283620a08716dfb462e5c1d65432ca9d56a90e811443cd1ecb8f0de179c9cb48ba4f6fec360c66f252f6e64edc96b",
+                output_str: "0d5f6de16b7cbba49c28654f2ae98163257e7b6b500a3801eef0733f"
+            },
+            Test {
+                input: "b6134f9c3e91dd8000740d009dd806240811d51ab1546a974bcb18d344642baa5cd5903af84d58ec5ba17301d5ec0f10ccd0509cbb3fd3fff9172d193af0f782252fd1338c7244d40e0e42362275b22d01c4c3389f19dd69bdf958ebe28e31a4ffe2b5f18a87831cfb7095f58a87c9fa21db72ba269379b2dc2384b3da953c7925761fed324620acea435e52b424a7723f6a2357374157a34cd8252351c25a1b232826cefe1bd3e70ffc15a31e7c0598219d7f00436294d11891b82497bc78aa5363892a2495df8c1eef",
+                output_str: "7b7e1fc4d3833ed87fd166f909f5c2566dc0e95b17ac834f1e9e3dad"
+            },
+            Test {
+                input: "c941cdb9c28ab0a791f2e5c8e8bb52850626aa89205bec3a7e22682313d198b1fa33fc7295381354858758ae6c8ec6fac3245c6e454d16fa2f51c4166fab51df272858f2d603770c40987f64442d487af49cd5c3991ce858ea2a60dab6a65a34414965933973ac2457089e359160b7cdedc42f29e10a91921785f6b7224ee0b349393cdcff6151b50b377d609559923d0984cda6000829b916ab6896693ef6a2199b3c22f7dc5500a15b8258420e314c222bc000bc4e5413e6dd82c993f8330f5c6d1be4bc79f08a1a0a46",
+                output_str: "c6ac9d5464855e5c2f83f2a56f9a992137da47ec05c541295f8c43e7"
+            },
+            Test {
+                input: "4499efffac4bcea52747efd1e4f20b73e48758be915c88a1ffe5299b0b005837a46b2f20a9cb3c6e64a9e3c564a27c0f1c6ad1960373036ec5bfe1a8fc6a435c2185ed0f114c50e8b3e4c7ed96b06a036819c9463e864a58d6286f785e32a804443a56af0b4df6abc57ed5c2b185ddee8489ea080deeee66aa33c2e6dab36251c402682b6824821f998c32163164298e1fafd31babbcffb594c91888c6219079d907fdb438ed89529d6d96212fd55abe20399dbefd342248507436931cdead496eb6e4a80358acc78647d043",
+                output_str: "4ee2f93c18974d978dd3a1cbf8b1dac473807067b8807d026182b901"
+            },
+            Test {
+                input: "eecbb8fdfa4da62170fd06727f697d81f83f601ff61e478105d3cb7502f2c89bf3e8f56edd469d049807a38882a7eefbc85fc9a950952e9fa84b8afebd3ce782d4da598002827b1eb98882ea1f0a8f7aa9ce013a6e9bc462fb66c8d4a18da21401e1b93356eb12f3725b6db1684f2300a98b9a119e5d27ff704affb618e12708e77e6e5f34139a5a41131fd1d6336c272a8fc37080f041c71341bee6ab550cb4a20a6ddb6a8e0299f2b14bc730c54b8b1c1c487b494bdccfd3a53535ab2f231590bf2c4062fd2ad58f906a2d0d",
+                output_str: "d64aee17ed8e2b85e6b097db49554d356f032a34a15b7e844ec8d889"
+            },
+            Test {
+                input: "e64f3e4ace5c8418d65fec2bc5d2a303dd458034736e3b0df719098be7a206deaf52d6ba82316caf330ef852375188cde2b39cc94aa449578a7e2a8e3f5a9d68e816b8d16889fbc0ebf0939d04f63033ae9ae2bdab73b88c26d6bd25ee460ee1ef58fb0afa92cc539f8c76d3d097e7a6a63ebb9b5887edf3cf076028c5bbd5b9db3211371ad3fe121d4e9bf44229f4e1ecf5a0f9f0eba4d5ceb72878ab22c3f0eb5a625323ac66f7061f4a81fac834471e0c59553f108475fe290d43e6a055ae3ee46fb67422f814a68c4be3e8c9",
+                output_str: "1bddc92be89a672c1bd956b450b9d7b47b4bb0bc58ac51f15f7e054d"
+            },
+            Test {
+                input: "d2cb2d733033f9e91395312808383cc4f0ca974e87ec68400d52e96b3fa6984ac58d9ad0938dde5a973008d818c49607d9de2284e7618f1b8aed8372fbd52ed54557af4220fac09dfa8443011699b97d743f8f2b1aef3537ebb45dcc9e13dfb438428ee190a4efdb3caeb7f3933117bf63abdc7e57beb4171c7e1ad260ab0587806c4d137b6316b50abc9cce0dff3acada47bbb86be777e617bbe578ff4519844db360e0a96c6701290e76bb95d26f0f804c8a4f2717eac4e7de9f2cff3bbc55a17e776c0d02856032a6cd10ad2838",
+                output_str: "0c8ac240170c6546debf4bfb5b38f8f30ea5dc6ef86c166e8e136d6b"
+            },
+            Test {
+                input: "f2998955613dd414cc111df5ce30a995bb792e260b0e37a5b1d942fe90171a4ac2f66d4928d7ad377f4d0554cbf4c523d21f6e5f379d6f4b028cdcb9b1758d3b39663242ff3cb6ede6a36a6f05db3bc41e0d861b384b6dec58bb096d0a422fd542df175e1be1571fb52ae66f2d86a2f6824a8cfaacbac4a7492ad0433eeb15454af8f312b3b2a577750e3efbd370e8a8cac1582581971fba3ba4bd0d76e718dacf8433d33a59d287f8cc92234e7a271041b526e389efb0e40b6a18b3aaf658e82ed1c78631fd23b4c3eb27c3faec8685",
+                output_str: "2fd9fdfd244b0a7342f886b87b3dddce54c8870fb26a71a8f6520231"
+            },
+            Test {
+                input: "447797e2899b72a356ba55bf4df3acca6cdb1041eb477bd1834a9f9acbc340a294d729f2f97df3a610be0ff15edb9c6d5db41644b9874360140fc64f52aa03f0286c8a640670067a84e017926a70438db1bb361defee7317021425f8821def26d1efd77fc853b818545d055adc9284796e583c76e6fe74c9ac2587aa46aa8f8804f2feb5836cc4b3ababab8429a5783e17d5999f32242eb59ef30cd7adabc16d72dbdb097623047c98989f88d14eaf02a7212be16ec2d07981aaa99949ddf89ecd90333a77bc4e1988a82abf7c7caf3291",
+                output_str: "1b6be19d72199bf75fd4075e54975afa0433b9bf515bd300ce543d41"
+            },
+            Test {
+                input: "9f2c18ade9b380c784e170fb763e9aa205f64303067eb1bcea93df5dac4bf5a2e00b78195f808df24fc76e26cb7be31dc35f0844cded1567bba29858cffc97fb29010331b01d6a3fb3159cc1b973d255da9843e34a0a4061cabdb9ed37f241bfabb3c20d32743f4026b59a4ccc385a2301f83c0b0a190b0f2d01acb8f0d41111e10f2f4e149379275599a52dc089b35fdd5234b0cfb7b6d8aebd563ca1fa653c5c021dfd6f5920e6f18bfafdbecbf0ab00281333ed50b9a999549c1c8f8c63d7626c48322e9791d5ff72294049bde91e73f8",
+                output_str: "a46b89b64b0c7930dd45f5b2582fd79c7ad90a58c94c52f9bfa55cfc"
+            },
+            Test {
+                input: "ae159f3fa33619002ae6bcce8cbbdd7d28e5ed9d61534595c4c9f43c402a9bb31f3b301cbfd4a43ce4c24cd5c9849cc6259eca90e2a79e01ffbac07ba0e147fa42676a1d668570e0396387b5bcd599e8e66aaed1b8a191c5a47547f61373021fa6deadcb55363d233c24440f2c73dbb519f7c9fa5a8962efd5f6252c0407f190dfefad707f3c7007d69ff36b8489a5b6b7c557e79dd4f50c06511f599f56c896b35c917b63ba35c6ff8092baf7d1658e77fc95d8a6a43eeb4c01f33f03877f92774be89c1114dd531c011e53a34dc248a2f0e6",
+                output_str: "21f0d8855387241d71a712e5f5682c156b9fd2aa6284294718853f0a"
+            },
+            Test {
+                input: "3b8e97c5ffc2d6a40fa7de7fcefc90f3b12c940e7ab415321e29ee692dfac799b009c99dcddb708fce5a178c5c35ee2b8617143edc4c40b4d313661f49abdd93cea79d117518805496fe6acf292c4c2a1f76b403a97d7c399daf85b46ad84e16246c67d6836757bde336c290d5d401e6c1386ab32797af6bb251e9b2d8fe754c47482b72e0b394eab76916126fd68ea7d65eb93d59f5b4c5ac40f7c3b37e7f3694f29424c24af8c8f0ef59cd9dbf1d28e0e10f799a6f78cad1d45b9db3d7dee4a7059abe99182714983b9c9d44d7f5643596d4f3",
+                output_str: "82ee85541d7a5b2a2b290003c3ee46574d58a7ddd54fbc210f8fea57"
+            },
+            Test {
+                input: "3434ec31b10fafdbfeec0dd6bd94e80f7ba9dca19ef075f7eb017512af66d6a4bcf7d16ba0819a1892a6372f9b35bcc7ca8155ee19e8428bc22d214856ed5fa9374c3c09bde169602cc219679f65a1566fc7316f4cc3b631a18fb4449fa6afa16a3db2bc4212eff539c67cf184680826535589c7111d73bffce431b4c40492e763d9279560aaa38eb2dc14a212d723f994a1fe656ff4dd14551ce4e7c621b2aa5604a10001b2878a897a28a08095c325e10a26d2fb1a75bfd64c250309bb55a44f23bbac0d5516a1c687d3b41ef2fbbf9cc56d4739",
+                output_str: "278dd8a3f3208191cff658b8d6db35e133a16e47aa375edb92c6a737"
+            },
+            Test {
+                input: "7c7953d81c8d208fd1c97681d48f49dd003456de60475b84070ef4847c333b74575b1fc8d2a186964485a3b8634feaa3595aaa1a2f4595a7d6b6153563dee31bbac443c8a33eed6d5d956a980a68366c2527b550ee950250dfb691eacbd5d56ae14b970668be174c89df2fea43ae52f13142639c884fd62a3683c0c3792f0f24ab1318bcb27e21f4737fab62c77ea38bc8fd1cf41f7dab64c13febe7152bf5bb7ab5a78f5346d43cc741cb6f72b7b8980f268b68bf62abdfb1577a52438fe14b591498cc95f071228460c7c5d5ceb4a7bde588e7f21c",
+                output_str: "b50527711c047def70b17cf20f970bed79c1c1b95275c2784c3903de"
+            },
+            Test {
+                input: "7a6a4f4fdc59a1d223381ae5af498d74b7252ecf59e389e49130c7eaee626e7bd9897effd92017f4ccde66b0440462cdedfd352d8153e6a4c8d7a0812f701cc737b5178c2556f07111200eb627dbc299caa792dfa58f35935299fa3a3519e9b03166dffa159103ffa35e8577f7c0a86c6b46fe13db8e2cdd9dcfba85bdddcce0a7a8e155f81f712d8e9fe646153d3d22c811bd39f830433b2213dd46301941b59293fd0a33e2b63adbd95239bc01315c46fdb678875b3c81e053a40f581cfbec24a1404b1671a1b88a6d06120229518fb13a74ca0ac5ae",
+                output_str: "f77cb5275212c92fa0dad921b65f50814822e3d6d584c89528990f02"
+            },
+            Test {
+                input: "d9faa14cebe9b7de551b6c0765409a33938562013b5e8e0e1e0a6418df7399d0a6a771fb81c3ca9bd3bb8e2951b0bc792525a294ebd1083688806fe5e7f1e17fd4e3a41d00c89e8fcf4a363caedb1acb558e3d562f1302b3d83bb886ed27b76033798131dab05b4217381eaaa7ba15ec820bb5c13b516dd640eaec5a27d05fdfca0f35b3a5312146806b4c0275bcd0aaa3b2017f346975db566f9b4d137f4ee10644c2a2da66deeca5342e236495c3c6280528bfd32e90af4cd9bb908f34012b52b4bc56d48cc8a6b59bab014988eabd12e1a0a1c2e170e7",
+                output_str: "76ca9e685dfadc67576d44e8c1a82e8cf7e92fb0a81fe49e21108e09"
+            },
+            Test {
+                input: "2d8427433d0c61f2d96cfe80cf1e932265a191365c3b61aaa3d6dcc039f6ba2ad52a6a8cc30fc10f705e6b7705105977fa496c1c708a277a124304f1fc40911e7441d1b5e77b951aad7b01fd5db1b377d165b05bbf898042e39660caf8b279fe5229d1a8db86c0999ed65e53d01ccbc4b43173ccf992b3a14586f6ba42f5fe30afa8ae40c5df29966f9346da5f8b35f16a1de3ab6de0f477d8d8660918060e88b9b9e9ca6a4207033b87a812dbf5544d39e4882010f82b6ce005f8e8ff6fe3c3806bc2b73c2b83afb704345629304f9f86358712e9fae3ca3e",
+                output_str: "abd313bc70b7fab0ebc167d739b54c97389e752ee1a313b12673f51c"
+            },
+            Test {
+                input: "5e19d97887fcaac0387e22c6f803c34a3dacd2604172433f7a8a7a526ca4a2a1271ecfc5d5d7be5ac0d85d921095350dfc65997d443c21c8094e0a3fefd2961bcb94aed03291ae310ccda75d8ace4bc7d89e7d3e5d1650bda5d668b8b50bfc8e608e184f4d3a9a2badc4ff5f07e0c0bc8a9f2e0b2a26fd6d8c550008faaab75fd71af2a424bec9a7cd9d83fad4c8e9319115656a8717d3b523a68ff8004258b9990ed362308461804ba3e3a7e92d8f2ffae5c2fba55ba5a3c27c0a2f71bd711d2fe1799c2adb31b200035481e9ee5c4adf2ab9c0fa50b23975cf",
+                output_str: "f79f6356328c580b811fea81c5ed90a303caf34a09beb143be450d42"
+            },
+            Test {
+                input: "c8e976ab4638909387ce3b8d4e510c3230e5690e02c45093b1d297910abc481e56eea0f296f98379dfc9080af69e73b2399d1c143bee80ae1328162ce1ba7f6a8374679b20aacd380eb4e61382c99998704d62701afa914f9a2705cdb065885f50d086c3eb5753700c387118bb142f3e6da1e988dfb31ac75d7368931e45d1391a274b22f83ceb072f9bcabc0b216685bfd789f5023971024b1878a205442522f9ea7d8797a4102a3df41703768251fd5e017c85d1200a464118aa35654e7ca39f3c375b8ef8cbe7534dbc64bc20befb417cf60ec92f63d9ee7397",
+                output_str: "299d62f8df5eade6871883b033b830a9952a74b12f3d55af798c6997"
+            },
+            Test {
+                input: "7145fa124b7429a1fc2231237a949ba7201bcc1822d3272de005b682398196c25f7e5cc2f289fbf44415f699cb7fe6757791b1443410234ae061edf623359e2b4e32c19bf88450432dd01caa5eb16a1dc378f391ca5e3c4e5f356728bddd4975db7c890da8bbc84cc73ff244394d0d48954978765e4a00b593f70f2ca082673a261ed88dbcef1127728d8cd89bc2c597e9102ced6010f65fa75a14ebe467fa57ce3bd4948b6867d74a9df5c0ec6f530cbf2ee61ce6f06bc8f2864dff5583776b31df8c7ffcb61428a56bf7bd37188b4a5123bbf338393af46eda85e6",
+                output_str: "82ba2b8d65e14fdac51f609f888881db8070a0b70d7892c009a1ad28"
+            },
+            Test {
+                input: "7fdfadcc9d29bad23ae038c6c65cda1aef757221b8872ed3d75ff8df7da0627d266e224e812c39f7983e4558bfd0a1f2bef3feb56ba09120ef762917b9c093867948547aee98600d10d87b20106878a8d22c64378bf634f7f75900c03986b077b0bf8b740a82447b61b99fee5376c5eb6680ec9e3088f0bdd0c56883413d60c1357d3c811950e5890e7600103c916341b80c743c6a852b7b4fb60c3ba21f3bc15b8382437a68454779cf3cd7f9f90ccc8ef28d0b706535b1e4108eb5627bb45d719cb046839aee311ca1abdc8319e050d67972cb35a6b1601b25dbf487",
+                output_str: "f8e5218db087d38b1c773247fc22704c1fbdb20b1500e26afa0b7572"
+            },
+            Test {
+                input: "988638219fd3095421f826f56e4f09e356296b628c3ce6930c9f2e758fd1a80c8273f2f61e4daae65c4f110d3e7ca0965ac7d24e34c0dc4ba2d6ff0bf5bbe93b3585f354d7543cb542a1aa54674d375077f2d360a8f4d42f3db131c3b7ab7306267ba107659864a90c8c909460a73621d1f5d9d3fd95beb19b23db1cb6c0d0fba91d36891529b8bd8263caa1bab56a4affaed44962df096d8d5b1eb845ef31188b3e10f1af811a13f156beb7a288aae593ebd1471b624aa1a7c6adf01e2200b3d72d88a3aed3100c88231e41efc376906f0b580dc895f080fda5741db1cb",
+                output_str: "fa602f09b28f8679771e9c3966032b80fa2f0f33e84f3ed69be7ae9c"
+            },
+            Test {
+                input: "5aab62756d307a669d146aba988d9074c5a159b3de85151a819b117ca1ff6597f6156e80fdd28c9c3176835164d37da7da11d94e09add770b68a6e081cd22ca0c004bfe7cd283bf43a588da91f509b27a6584c474a4a2f3ee0f1f56447379240a5ab1fb77fdca49b305f07ba86b62756fb9efb4fc225c86845f026ea542076b91a0bc2cdd136e122c659be259d98e5841df4c2f60330d4d8cdee7bf1a0a244524eecc68ff2aef5bf0069c9e87a11c6e519de1a4062a10c83837388f7ef58598a3846f49d499682b683c4a062b421594fafbc1383c943ba83bdef515efcf10d",
+                output_str: "c8d7568889dd6fcbc3b8874ed79051875d3ce29102df0c5dac8aeb8a"
+            },
+            Test {
+                input: "47b8216aa0fbb5d67966f2e82c17c07aa2d6327e96fcd83e3de7333689f3ee79994a1bf45082c4d725ed8d41205cb5bcdf5c341f77facb1da46a5b9b2cbc49eadf786bcd881f371a95fa17df73f606519aea0ff79d5a11427b98ee7f13a5c00637e2854134691059839121fea9abe2cd1bcbbbf27c74caf3678e05bfb1c949897ea01f56ffa4dafbe8644611685c617a3206c7a7036e4ac816799f693dafe7f19f303ce4eba09d21e03610201bfc665b72400a547a1e00fa9b7ad8d84f84b34aef118515e74def11b9188bd1e1f97d9a12c30132ec2806339bdadacda2fd8b78",
+                output_str: "d83b06d509d332164087c0c3fa50b2264cb27f66d746b0470166cbc2"
+            },
+            Test {
+                input: "8cff1f67fe53c098896d9136389bd8881816ccab34862bb67a656e3d98896f3ce6ffd4da73975809fcdf9666760d6e561c55238b205d8049c1cedeef374d1735daa533147bfa960b2cce4a4f254176bb4d1bd1e89654432b8dbe1a135c42115b394b024856a2a83dc85d6782be4b444239567ccec4b184d4548eae3ff6a192f343292ba2e32a0f267f31cc26719eb85245d415fb897ac2da433ee91a99424c9d7f1766a44171d1651001c38fc79294accc68ceb5665d36218454d3ba169ae058a831338c17743603f81ee173bfc0927464f9bd728dee94c6aeab7aae6ee3a627e8",
+                output_str: "386147b0cf2365346e9846d3f3a7dceeb6e3665ba7d1593c08b2b582"
+            },
+            Test {
+                input: "eacd07971cff9b9939903f8c1d8cbb5d4db1b548a85d04e037514a583604e787f32992bf2111b97ac5e8a938233552731321522ab5e8583561260b7d13ebeef785b23a41fd8576a6da764a8ed6d822d4957a545d5244756c18aa80e1aad4d1f9c20d259dee1711e2cc8fd013169fb7cc4ce38b362f8e0936ae9198b7e838dcea4f7a5b9429bb3f6bbcf2dc92565e3676c1c5e6eb3dd2a0f86aa23edd3d0891f197447692794b3dfa269611ad97f72b795602b4fdb198f3fd3eb41b415064256e345e8d8c51c555dc8a21904a9b0f1ad0effab7786aac2da3b196507e9f33ca356427",
+                output_str: "a69c0c18a712408d8fa2389acabc3bf6f6412f69783e9f37960d0b56"
+            },
+            Test {
+                input: "23ac4e9a42c6ef45c3336ce6dfc2ff7de8884cd23dc912fef0f7756c09d335c189f3ad3a23697abda851a81881a0c8ccafc980ab2c702564c2be15fe4c4b9f10dfb2248d0d0cb2e2887fd4598a1d4acda897944a2ffc580ff92719c95cf2aa42dc584674cb5a9bc5765b9d6ddf5789791d15f8dd925aa12bffafbce60827b490bb7df3dda6f2a143c8bf96abc903d83d59a791e2d62814a89b8080a28060568cf24a80ae61179fe84e0ffad00388178cb6a617d37efd54cc01970a4a41d1a8d3ddce46edbba4ab7c90ad565398d376f431189ce8c1c33e132feae6a8cd17a61c630012",
+                output_str: "0699fd35416d83791dc8e656f22718b09da9e3df6e7f37a250e22dcd"
+            },
+            Test {
+                input: "0172df732282c9d488669c358e3492260cbe91c95cfbc1e3fea6c4b0ec129b45f242ace09f152fc6234e1bee8aab8cd56e8b486e1dcba9c05407c2f95da8d8f1c0af78ee2ed82a3a79ec0cb0709396ee62aadb84f8a4ee8a7ccca3c1ee84e302a09ea802204afecf04097e67d0f8e8a9d2651126c0a598a37081e42d168b0ae8a71951c524259e4e2054e535b779679bdade566fe55700858618e626b4a0faf895bcce9011504a49e05fd56127eae3d1f8917afb548ecadabda1020111fec9314c413498a360b08640549a22cb23c731ace743252a8227a0d2689d4c6001606678dfb921",
+                output_str: "bf6a3598a15e28b776229f4d124d403fad9d0fbc2b7668c95d8b5046"
+            },
+            Test {
+                input: "3875b9240cf3e0a8b59c658540f26a701cf188496e2c2174788b126fd29402d6a75453ba0635284d08835f40051a2a9683dc92afb9383719191231170379ba6f4adc816fecbb0f9c446b785bf520796841e58878b73c58d3ebb097ce4761fdeabe15de2f319dfbaf1742cdeb389559c788131a6793e193856661376c81ce9568da19aa6925b47ffd77a43c7a0e758c37d69254909ff0fbd415ef8eb937bcd49f91468b49974c07dc819abd67395db0e05874ff83dddab895344abd0e7111b2df9e58d76d85ad98106b36295826be04d435615595605e4b4bb824b33c4afeb5e7bb0d19f909",
+                output_str: "56f8e9f69a399e528996c463d65f20db41406533c7df2ba1afa2494a"
+            },
+            Test {
+                input: "747cc1a59fefba94a9c75ba866c30dc5c1cb0c0f8e9361d98484956dd5d1a40f6184afbe3dac9f76028d1caeccfbf69199c6ce2b4c092a3f4d2a56fe5a33a00757f4d7dee5dfb0524311a97ae0668a47971b95766e2f6dd48c3f57841f91f04a00ad5ea70f2d479a2620dc5cd78eaab3a3b011719b7e78d19ddf70d9423798af77517ebc55392fcd01fc600d8d466b9e7a7a85bf33f9cc5419e9bd874ddfd60981150ddaf8d7febaa4374f0872a5628d318000311e2f5655365ad4d407c20e5c04df17a222e7deec79c5ab1116d8572f91cd06e1ccc7ced53736fc867fd49ecebe6bf8082e8a",
+                output_str: "9904d57dedb935427f235a0009612235f14e9426b218e028f87b3c0c"
+            },
+            Test {
+                input: "57af971fccaec97435dc2ec9ef0429bcedc6b647729ea168858a6e49ac1071e706f4a5a645ca14e8c7746d65511620682c906c8b86ec901f3dded4167b3f00b06cbfac6aee3728051b3e5ff10b4f9ed8bd0b8da94303c833755b3ca3aeddf0b54bc8d6632138b5d25bab03d17b3458a9d782108006f5bb7de75b5c0ba854b423d8bb801e701e99dc4feaad59bc1c7112453b04d33ea3635639fb802c73c2b71d58a56bbd671b18fe34ed2e3dca38827d63fdb1d4fb3285405004b2b3e26081a8ff08cd6d2b08f8e7b7e90a2ab1ed7a41b1d0128522c2f8bff56a7fe67969422ce839a9d4608f03",
+                output_str: "ff7013679ab2be65aedd09739f56f8dd0072738b86e71a2470476c8c"
+            },
+            Test {
+                input: "04e16dedc1227902baaf332d3d08923601bdd64f573faa1bb7201918cfe16b1e10151dae875da0c0d63c59c3dd050c4c6a874011b018421afc4623ab0381831b2da2a8ba42c96e4f70864ac44e106f94311051e74c77c1291bf5db9539e69567bf6a11cf6932bbbad33f8946bf5814c066d851633d1a513510039b349939bfd42b858c21827c8ff05f1d09b1b0765dc78a135b5ca4dfba0801bcaddfa175623c8b647eacfb4444b85a44f73890607d06d507a4f8393658788669f6ef4deb58d08c50ca0756d5e2f49d1a7ad73e0f0b3d3b5f090acf622b1878c59133e4a848e05153592ea81c6fbf",
+                output_str: "9dfb6a854a33914eae1596dcd2be363a96e7e088be520f60e5a65c7f"
+            },
+            Test {
+                input: "7c815c384eee0f288ece27cced52a01603127b079c007378bc5d1e6c5e9e6d1c735723acbbd5801ac49854b2b569d4472d33f40bbb8882956245c366dc3582d71696a97a4e19557e41e54dee482a14229005f93afd2c4a7d8614d10a97a9dfa07f7cd946fa45263063ddd29db8f9e34db60daa32684f0072ea2a9426ecebfa5239fb67f29c18cbaa2af6ed4bf4283936823ac1790164fec5457a9cba7c767ca59392d94cab7448f50eb34e9a93a80027471ce59736f099c886dea1ab4cba4d89f5fc7ae2f21ccd27f611eca4626b2d08dc22382e92c1efb2f6afdc8fdc3d2172604f5035c46b8197d3",
+                output_str: "c27e80c373b216703d3d9e67223cfc5497c3e74455d49b049ae3f5f4"
+            },
+            Test {
+                input: "e29d505158dbdd937d9e3d2145658ee6f5992a2fc790f4f608d9cdb44a091d5b94b88e81fac4fdf5c49442f13b911c55886469629551189eaff62488f1a479b7db11a1560e198ddccccf50159093425ff7f1cb8d1d1246d0978764087d6bac257026b090efae8cec5f22b6f21c59ace1ac7386f5b8837ca6a12b6fbf5534dd0560ef05ca78104d3b943ddb220feaec89aa5e692a00f822a2ab9a2fe60350d75e7be16ff2526dc643872502d01f42f188abed0a6e9a6f5fd0d1ce7d5755c9ffa66b0af0b20bd806f08e06156690d81ac811778ca3dac2c249b96002017fce93e507e3b953acf99964b847",
+                output_str: "3a189630f53c567b1c1825794d50def901a00e7f3728ecf2bbe00d90"
+            },
+            Test {
+                input: "d85588696f576e65eca0155f395f0cfacd83f36a99111ed5768df2d116d2121e32357ba4f54ede927f189f297d3a97fad4e9a0f5b41d8d89dd7fe20156799c2b7b6bf9c957ba0d6763f5c3bc5129747bbb53652b49290cff1c87e2cdf2c4b95d8aaee09bc8fbfa6883e62d237885810491bfc101f1d8c636e3d0ede838ad05c207a3df4fad76452979eb99f29afaecedd1c63b8d36cf378454a1bb67a741c77ac6b6b3f95f4f02b64dabc15438613ea49750df42ee90101f115aa9abb9ff64324dde9dabbb01054e1bd6b4bcdc7930a44c2300d87ca78c06924d0323ad7887e46c90e8c4d100acd9eed21e",
+                output_str: "2585bd8d9158d6952bee95b004f5fed70faf061b68ab2d6a40469be7"
+            },
+            Test {
+                input: "3a12f8508b40c32c74492b66323375dcfe49184c78f73179f3314b79e63376b8ac683f5a51f1534bd729b02b04d002f55cbd8e8fc9b5ec1ea6bbe6a0d0e7431518e6ba45d124035f9d3dce0a8bb7bf1430a9f657e0b4ea9f20eb20c786a58181a1e20a96f1628f8728a13bdf7a4b4b32fc8aa7054cc4881ae7fa19afa65c6c3ee1b3ade3192af42054a8a911b8ec1826865d46d93f1e7c5e2b7813c92a506e53886f3d4701bb93d2a681ad109c845904bb861af8af0646b6e399b38b614051d34f6842563a0f37ec00cb3d865fc5d746c4987de2a65071100883a2a9c7a2bfe1e2dd603d9ea24dc7c5fd06be",
+                output_str: "7e64f3c5895d0586cc5b543b27de1b66a935171e2e7f3ca48dd3718e"
+            },
+            Test {
+                input: "1861edce46fa5ad17e1ff1deae084dec580f97d0a67885dfe834b9dfac1ae076742ce9e267512ca51f6df5a455af0c5fd6abf94acea103a3370c354485a7846fb84f3ac7c2904b5b2fbf227002ce512133bb7e1c4e50057bfd1e44db33c7cdb969a99e284b184f50a14b068a1fc5009d9b298dbe92239572a7627aac02abe8f3e3b473417f36d4d2505d16b7577f4526c9d94a270a2dfe450d06da8f6fa956879a0a55cfe99e742ea555ea477ba3e9b44ccd508c375423611af92e55345dc215779b2d5119eba49c71d49b9fe3f1569fa24e5ca3e332d042422a8b8158d3ec66a80012976f31ffdf305f0c9c5e",
+                output_str: "0f837708e010375af87f75415ed69988fe60eb2f2669ad051fa99727"
+            },
+            Test {
+                input: "08d0ffde3a6e4ef65608ea672e4830c12943d7187ccff08f4941cfc13e545f3b9c7ad5eebbe2b01642b486caf855c2c73f58c1e4e3391da8e2d63d96e15fd84953ae5c231911b00ad6050cd7aafdaac9b0f663ae6aab45519d0f5391a541707d479034e73a6ad805ae3598096af078f1393301493d663dd71f83869ca27ba508b7e91e81e128c1716dc3acfe3084b2201e04cf8006617eecf1b640474a5d45cfde9f4d3ef92d6d055b909892194d8a8218db6d8203a84261d200d71473d7488f3427416b6896c137d455f231071cacbc86e0415ab88aec841d96b7b8af41e05bb461a40645bf176601f1e760de5f",
+                output_str: "c79de39778593810c03583d5962b36e04f343653074766d157a15993"
+            },
+            Test {
+                input: "d782abb72a5be3392757be02d3e45be6e2099d6f000d042c8a543f50ed6ebc055a7f133b0dd8e9bc348536edcaae2e12ec18e8837df7a1b3c87ec46d50c241dee820fd586197552dc20beea50f445a07a38f1768a39e2b2ff05dddedf751f1def612d2e4d810daa3a0cc904516f9a43af660315385178a529e51f8aae141808c8bc5d7b60cac26bb984ac1890d0436ef780426c547e94a7b08f01acbfc4a3825eae04f520a9016f2fb8bf5165ed12736fc71e36a49a73614739eaa3ec834069b1b40f1350c2b3ab885c02c640b9f7686ed5f99527e41cfcd796fe4c256c9173186c226169ff257954ebda81c0e5f99",
+                output_str: "95cc811cc56521a40e3ced8d9a230e2101e8061fb01e388b9964bf29"
+            },
+            Test {
+                input: "5fce8109a358570e40983e1184e541833bb9091e280f258cfb144387b05d190e431cb19baa67273ba0c58abe91308e1844dcd0b3678baa42f335f2fa05267a0240b3c718a5942b3b3e3bfa98a55c25a1466e8d7a603722cb2bbf03afa54cd769a99f310735ee5a05dae2c22d397bd95635f58c48a67f90e1b73aafcd3f82117f0166657838691005b18da6f341d6e90fc1cdb352b30fae45d348294e501b63252de14740f2b85ae5299ddec3172de8b6d0ba219a20a23bb5e10ff434d39db3f583305e9f5c039d98569e377b75a70ab837d1df269b8a4b566f40bb91b577455fd3c356c914fa06b9a7ce24c7317a172d",
+                output_str: "2ebe13f12ec43e3f6b0506d7ab216e1c311394f7c89d69a920cd00c0"
+            },
+            Test {
+                input: "6172f1971a6e1e4e6170afbad95d5fec99bf69b24b674bc17dd78011615e502de6f56b86b1a71d3f4348087218ac7b7d09302993be272e4a591968aef18a1262d665610d1070ee91cc8da36e1f841a69a7a682c580e836941d21d909a3afc1f0b963e1ca5ab193e124a1a53df1c587470e5881fb54dae1b0d840f0c8f9d1b04c645ba1041c7d8dbf22030a623aa15638b3d99a2c400ff76f3252079af88d2b37f35ee66c1ad7801a28d3d388ac450b97d5f0f79e4541755356b3b1a5696b023f39ab7ab5f28df4202936bc97393b93bc915cb159ea1bd7a0a414cb4b7a1ac3af68f50d79f0c9c7314e750f7d02faa58bfa",
+                output_str: "820101f5435d86e19bec58ed0e1c7e630fe82dd92d7704e414802a16"
+            },
+            Test {
+                input: "5668ecd99dfbe215c4118398ac9c9eaf1a1433fab4ccdd3968064752b625ea944731f75d48a27d047d67547f14dd0ffaa55fa5e29f7af0d161d85eafc4f2029b717c918eab9d304543290bdba7158b68020c0ba4e079bc95b5bc0fc044a992b94b4ccd3bd66d0eabb5dbbab904d62e00752c4e3b0091d773bcf4c14b4377da3efff824b1cb2fa01b32d1e46c909e626ed2dae920f4c7dbeb635bc754facbd8d49beba3f23c1c41ccbfcd0ee0c114e69737f5597c0bf1d859f0c767e18002ae8e39c26261ffde2920d3d0baf0e906138696cfe5b7e32b600f45df3aaa39932f3a7df95b60fa8712a2271fcaf3911ce7b511b1",
+                output_str: "b1cf54f51f81fdb5b649bb6115126149296278bff3d5395cf5f112d4"
+            },
+            Test {
+                input: "03d625488354df30e3f875a68edfcf340e8366a8e1ab67f9d5c5486a96829dfac0578289082b2a62117e1cf418b43b90e0adc881fc6ae8105c888e9ecd21aea1c9ae1a4038dfd17378fed71d02ae492087d7cdcd98f746855227967cb1ab4714261ee3bead3f4db118329d3ebef4bc48a875c19ba763966da0ebea800e01b2f50b00e9dd4caca6dcb314d00184ef71ea2391d760c950710db4a70f9212ffc54861f9dc752ce18867b8ad0c48df8466ef7231e7ac567f0eb55099e622ebb86cb237520190a61c66ad34f1f4e289cb3282ae3eaac6152ed24d2c92bae5a7658252a53c49b7b02dfe54fdb2e90074b6cf310ac661",
+                output_str: "b602722d1b9f31b9c5091e0ff720f1d1a8a51eb6f95ed3b412de063d"
+            },
+            Test {
+                input: "2edc282ffb90b97118dd03aaa03b145f363905e3cbd2d50ecd692b37bf000185c651d3e9726c690d3773ec1e48510e42b17742b0b0377e7de6b8f55e00a8a4db4740cee6db0830529dd19617501dc1e9359aa3bcf147e0a76b3ab70c4984c13e339e6806bb35e683af8527093670859f3d8a0fc7d493bcba6bb12b5f65e71e705ca5d6c948d66ed3d730b26db395b3447737c26fad089aa0ad0e306cb28bf0acf106f89af3745f0ec72d534968cca543cd2ca50c94b1456743254e358c1317c07a07bf2b0eca438a709367fafc89a57239028fc5fecfd53b8ef958ef10ee0608b7f5cb9923ad97058ec067700cc746c127a61ee3",
+                output_str: "1368454e849f2d2299077f40826b4072e6fee49b2062cb8e3b4523c9"
+            },
+            Test {
+                input: "90b28a6aa1fe533915bcb8e81ed6cacdc10962b7ff82474f845eeb86977600cf70b07ba8e3796141ee340e3fce842a38a50afbe90301a3bdcc591f2e7d9de53e495525560b908c892439990a2ca2679c5539ffdf636777ad9c1cdef809cda9e8dcdb451abb9e9c17efa4379abd24b182bd981cafc792640a183b61694301d04c5b3eaad694a6bd4cc06ef5da8fa23b4fa2a64559c5a68397930079d250c51bcf00e2b16a6c49171433b0aadfd80231276560b80458dd77089b7a1bbcc9e7e4b9f881eacd6c92c4318348a13f4914eb27115a1cfc5d16d7fd94954c3532efaca2cab025103b2d02c6fd71da3a77f417d7932685888a",
+                output_str: "5765b70574f93341c1cc4acb34f645b5d97b81d4ce8f38c3862f6c19"
+            },
+            Test {
+                input: "2969447d175490f2aa9bb055014dbef2e6854c95f8d60950bfe8c0be8de254c26b2d31b9e4de9c68c9adf49e4ee9b1c2850967f29f5d08738483b417bb96b2a56f0c8aca632b552059c59aac3f61f7b45c966b75f1d9931ff4e596406378cee91aaa726a3a84c33f37e9cdbe626b5745a0b06064a8a8d56e53aaf102d23dd9df0a3fdf7a638509a6761a33fa42fa8ddbd8e16159c93008b53765019c3f0e9f10b144ce2ac57f5d7297f9c9949e4ff68b70d339f87501ce8550b772f32c6da8ad2ce2100a895d8b08fa1eead7c376b407709703c510b50f87e73e43f8e7348f87c3832a547ef2bbe5799abedcf5e1f372ea809233f006",
+                output_str: "b8fb318245b4042222b4063a053f15da6b894f22736f3f9e26f72175"
+            },
+            Test {
+                input: "721645633a44a2c78b19024eaecf58575ab23c27190833c26875dc0f0d50b46aea9c343d82ea7d5b3e50ec700545c615daeaea64726a0f05607576dcd396d812b03fb6551c641087856d050b10e6a4d5577b82a98afb89cee8594c9dc19e79feff0382fcfd127f1b803a4b9946f4ac9a4378e1e6e041b1389a53e3450cd32d9d2941b0cbabdb50da8ea2513145164c3ab6bcbd251c448d2d4b087ac57a59c2285d564f16da4ed5e607ed979592146ffb0ef3f3db308fb342df5eb5924a48256fc763141a278814c82d6d6348577545870ae3a83c7230ac02a1540fe1798f7ef09e335a865a2ae0949b21e4f748fb8a51f44750e213a8fb",
+                output_str: "353622e92c7907f5563baf8f4e7af0c2f872f4fb583b01af9eb3d907"
+            },
+            Test {
+                input: "6b860d39725a14b498bb714574b4d37ca787404768f64c648b1751b353ac92bac2c3a28ea909fdf0423336401a02e63ec24325300d823b6864bb701f9d7c7a1f8ec9d0ae3584aa6dd62ea1997cd831b4babd9a4da50932d4efda745c61e4130890e156aee6113716daf95764222a91187db2effea49d5d0596102d619bd26a616bbfda8335505fbb0d90b4c180d1a2335b91538e1668f9f9642790b4e55f9cab0fe2bdd2935d001ee6419abab5457880d0dbff20ed8758f4c20fe759efb33141cf0e892587fe8187e5fbc57786b7e8b089612c936dfc03d27efbbe7c8673f1606bd51d5ff386f4a7ab68edf59f385eb1291f117bfe717399",
+                output_str: "87215af73d5cde98b355479afb82a511180b7dc3d5342c88e133aed8"
+            },
+            Test {
+                input: "6a01830af3889a25183244decb508bd01253d5b508ab490d3124afbf42626b2e70894e9b562b288d0a2450cfacf14a0ddae5c04716e5a0082c33981f6037d23d5e045ee1ef2283fb8b6378a914c5d9441627a722c282ff452e25a7ea608d69cee4393a0725d17963d0342684f255496d8a18c2961145315130549311fc07f0312fb78e6077334f87eaa873bee8aa95698996eb21375eb2b4ef53c14401207deb4568398e5dd9a7cf97e8c9663e23334b46912f8344c19efcf8c2ba6f04325f1a27e062b62a58d0766fc6db4d2c6a1928604b0175d872d16b7908ebc041761187cc785526c2a3873feac3a642bb39f5351550af9770c328af7b",
+                output_str: "25ae852dba36b8d58a94dd5cfd8345141ff57e7db7d7816c4f7252bb"
+            },
+            Test {
+                input: "b3c5e74b69933c2533106c563b4ca20238f2b6e675e8681e34a389894785bdade59652d4a73d80a5c85bd454fd1e9ffdad1c3815f5038e9ef432aac5c3c4fe840cc370cf86580a6011778bbedaf511a51b56d1a2eb68394aa299e26da9ada6a2f39b9faff7fba457689b9c1a577b2a1e505fdf75c7a0a64b1df81b3a356001bf0df4e02a1fc59f651c9d585ec6224bb279c6beba2966e8882d68376081b987468e7aed1ef90ebd090ae825795cdca1b4f09a979c8dfc21a48d8a53cdbb26c4db547fc06efe2f9850edd2685a4661cb4911f165d4b63ef25b87d0a96d3dff6ab0758999aad214d07bd4f133a6734fde445fe474711b69a98f7e2b",
+                output_str: "ece0394418f066f55023797551e06f6a7d1645682aa4d9dd75af8e76"
+            },
+            Test {
+                input: "83af34279ccb5430febec07a81950d30f4b66f484826afee7456f0071a51e1bbc55570b5cc7ec6f9309c17bf5befdd7c6ba6e968cf218a2b34bd5cf927ab846e38a40bbd81759e9e33381016a755f699df35d660007b5eadf292feefb735207ebf70b5bd17834f7bfa0e16cb219ad4af524ab1ea37334aa66435e5d397fc0a065c411ebbce32c240b90476d307ce802ec82c1c49bc1bec48c0675ec2a6c6f3ed3e5b741d13437095707c565e10d8a20b8c20468ff9514fcf31b4249cd82dcee58c0a2af538b291a87e3390d737191a07484a5d3f3fb8c8f15ce056e5e5f8febe5e1fb59d6740980aa06ca8a0c20f5712b4cde5d032e92ab89f0ae1",
+                output_str: "84a4bd2e3fa26c4fb01fe81953398f5b4b5704944354b51b887fd990"
+            },
+            Test {
+                input: "a7ed84749ccc56bb1dfba57119d279d412b8a986886d810f067af349e8749e9ea746a60b03742636c464fc1ee233acc52c1983914692b64309edfdf29f1ab912ec3e8da074d3f1d231511f5756f0b6eead3e89a6a88fe330a10face267bffbfc3e3090c7fd9a850561f363ad75ea881e7244f80ff55802d5ef7a1a4e7b89fcfa80f16df54d1b056ee637e6964b9e0ffd15b6196bdd7db270c56b47251485348e49813b4eb9ed122a01b3ea45ad5e1a929df61d5c0f3e77e1fdc356b63883a60e9cbb9fc3e00c2f32dbd469659883f690c6772e335f617bc33f161d6f6984252ee12e62b6000ac5231e0c9bc65be223d8dfd94c5004a101af9fd6c0fb",
+                output_str: "170c413863d9f4e8c0b87a8532416b10a69c348d3a144658eaeef0ed"
+            },
+            Test {
+                input: "a6fe30dcfcda1a329e82ab50e32b5f50eb25c873c5d2305860a835aecee6264aa36a47429922c4b8b3afd00da16035830edb897831c4e7b00f2c23fc0b15fdc30d85fb70c30c431c638e1a25b51caf1d7e8b050b7f89bfb30f59f0f20fecff3d639abc4255b3868fc45dd81e47eb12ab40f2aac735df5d1dc1ad997cefc4d836b854cee9ac02900036f3867fe0d84afff37bde3308c2206c62c4743375094108877c73b87b2546fe05ea137bedfc06a2796274099a0d554da8f7d7223a48cbf31b7decaa1ebc8b145763e3673168c1b1b715c1cd99ecd3ddb238b06049885ecad9347c2436dff32c771f34a38587a44a82c5d3d137a03caa27e66c8ff6",
+                output_str: "d8c257db76536f7ef1dcfb24976eb716d9491cd8651e0254e7c4a5bb"
+            },
+            Test {
+                input: "83167ff53704c3aa19e9fb3303539759c46dd4091a52ddae9ad86408b69335989e61414bc20ab4d01220e35241eff5c9522b079fba597674c8d716fe441e566110b6211531ceccf8fd06bc8e511d00785e57788ed9a1c5c73524f01830d2e1148c92d0edc97113e3b7b5cd3049627abdb8b39dd4d6890e0ee91993f92b03354a88f52251c546e64434d9c3d74544f23fb93e5a2d2f1fb15545b4e1367c97335b0291944c8b730ad3d4789273fa44fb98d78a36c3c3764abeeac7c569c1e43a352e5b770c3504f87090dee075a1c4c85c0c39cf421bdcc615f9eff6cb4fe6468004aece5f30e1ecc6db22ad9939bb2b0ccc96521dfbf4ae008b5b46bc006e",
+                output_str: "f81d8ee40869bb38a13a4f75588fa3308068dd1cdc27267d66fac198"
+            },
+            Test {
+                input: "3a3a819c48efde2ad914fbf00e18ab6bc4f14513ab27d0c178a188b61431e7f5623cb66b23346775d386b50e982c493adbbfc54b9a3cd383382336a1a0b2150a15358f336d03ae18f666c7573d55c4fd181c29e6ccfde63ea35f0adf5885cfc0a3d84a2b2e4dd24496db789e663170cef74798aa1bbcd4574ea0bba40489d764b2f83aadc66b148b4a0cd95246c127d5871c4f11418690a5ddf01246a0c80a43c70088b6183639dcfda4125bd113a8f49ee23ed306faac576c3fb0c1e256671d817fc2534a52f5b439f72e424de376f4c565cca82307dd9ef76da5b7c4eb7e085172e328807c02d011ffbf33785378d79dc266f6a5be6bb0e4a92eceebaeb1",
+                output_str: "94689ea9f347dda8dd798a858605868743c6bd03a6a65c6085d52bed"
+            }
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Sha3_224));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_sha3_256() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"
+            },
+            Test {
+                input: "cc",
+                output_str: "677035391cd3701293d385f037ba32796252bb7ce180b00b582dd9b20aaad7f0"
+            },
+            Test {
+                input: "41fb",
+                output_str: "39f31b6e653dfcd9caed2602fd87f61b6254f581312fb6eeec4d7148fa2e72aa"
+            },
+            Test {
+                input: "1f877c",
+                output_str: "bc22345e4bd3f792a341cf18ac0789f1c9c966712a501b19d1b6632ccd408ec5"
+            },
+            Test {
+                input: "c1ecfdfc",
+                output_str: "c5859be82560cc8789133f7c834a6ee628e351e504e601e8059a0667ff62c124"
+            },
+            Test {
+                input: "21f134ac57",
+                output_str: "55bd9224af4eed0d121149e37ff4d7dd5be24bd9fbe56e0171e87db7a6f4e06d"
+            },
+            Test {
+                input: "c6f50bb74e29",
+                output_str: "ae0cbc757d4ab088e172abfd8746289950f92d38a25295658dbf744b5635af04"
+            },
+            Test {
+                input: "119713cc83eeef",
+                output_str: "e340c9a44373efcc212f3cb66a047ac34c87ff1c58c4a14b16a2bfc34698bb1d"
+            },
+            Test {
+                input: "4a4f202484512526",
+                output_str: "ba4fb009d57a5ceb85fc64d54e5c55a55854b41cc47ad15294bc41f32165dfba"
+            },
+            Test {
+                input: "1f66ab4185ed9b6375",
+                output_str: "b9886ef905c8bdd272eda8298865e0769869f1c964460d1aa9d7a0c687707ccd"
+            },
+            Test {
+                input: "eed7422227613b6f53c9",
+                output_str: "fab8f88d3191e21a725b21c63a02cad3fa7c450ef8584b94cfa382f393422455"
+            },
+            Test {
+                input: "eaeed5cdffd89dece455f1",
+                output_str: "9363acd3f48bb91a8998aa0e8df75c971770a16a71e7d2334409734cd7d0a9ee"
+            },
+            Test {
+                input: "5be43c90f22902e4fe8ed2d3",
+                output_str: "16932f6f65deaad5780e25ab410c66b0e4198eba9f4ed1a25ee24f7879faefe2"
+            },
+            Test {
+                input: "a746273228122f381c3b46e4f1",
+                output_str: "1c28100e0ef50671c7ea3e024fa3ba9da2ebddb4de264c3a2426c36ad3f91c61"
+            },
+            Test {
+                input: "3c5871cd619c69a63b540eb5a625",
+                output_str: "8183be4875fab7ec5f99ed94f5f900cf1d6b953d8f71e1e7cc008687980e613a"
+            },
+            Test {
+                input: "fa22874bcc068879e8ef11a69f0722",
+                output_str: "3b1a6d21fe44691dac4eb7c593a6d8523cb606e63cf00e94d711a574248daca5"
+            },
+            Test {
+                input: "52a608ab21ccdd8a4457a57ede782176",
+                output_str: "2c7e7cb356fdc68ec8927e499d2a6bae2b781817919c829ebbe8225baed46967"
+            },
+            Test {
+                input: "82e192e4043ddcd12ecf52969d0f807eed",
+                output_str: "c7b12eff692d842110cc39ac60616707acb3f9b0f1cb361b94577efc529ca26c"
+            },
+            Test {
+                input: "75683dcb556140c522543bb6e9098b21a21e",
+                output_str: "493ebaebc04776f4e067555afa09b58c850fdf1b0e22d4bf006ce41c091dc762"
+            },
+            Test {
+                input: "06e4efe45035e61faaf4287b4d8d1f12ca97e5",
+                output_str: "1d01f3120ecfbdd28dce44317666cf864f52391b9eca3843db45667c2e0a98ad"
+            },
+            Test {
+                input: "e26193989d06568fe688e75540aea06747d9f851",
+                output_str: "2c1e61e5d45203f27b86f1293a80bab34192daf42b8623b12005b2fb1c18acb1"
+            },
+            Test {
+                input: "d8dc8fdefbdce9d44e4cbafe78447bae3b5436102a",
+                output_str: "ad0e3f29767067e929d1cecd95582df8f2a9beb92eaa27eeb315f620365a9244"
+            },
+            Test {
+                input: "57085fd7e14216ab102d8317b0cb338a786d5fc32d8f",
+                output_str: "2b4eb5de20e86074cabb55bfa63a5c8c6ae15679302061845b9cf233e17c906b"
+            },
+            Test {
+                input: "a05404df5dbb57697e2c16fa29defac8ab3560d6126fa0",
+                output_str: "6ae04c6c6f3651f1f64c0ad69733990b41747c93f87acb813bb25bb1fc0eff07"
+            },
+            Test {
+                input: "aecbb02759f7433d6fcb06963c74061cd83b5b3ffa6f13c6",
+                output_str: "40f9f55bc55da466bc3dc1f89835a64094572de73d64ed6646a1d3b667be70a9"
+            },
+            Test {
+                input: "aafdc9243d3d4a096558a360cc27c8d862f0be73db5e88aa55",
+                output_str: "c64becf7b75fc885d5853924f2b7d37abcefd3da126bb817697e1a09152b1ebe"
+            },
+            Test {
+                input: "7bc84867f6f9e9fdc3e1046cae3a52c77ed485860ee260e30b15",
+                output_str: "57d46a6bc8fab33601538dad27f98c66443032cc3912434c28eb88d0af44c52c"
+            },
+            Test {
+                input: "fac523575a99ec48279a7a459e98ff901918a475034327efb55843",
+                output_str: "7c956503d5b4dbb764ff8e66fa74ce0f9132da90ea3543f669c9dd08e413e33c"
+            },
+            Test {
+                input: "0f8b2d8fcfd9d68cffc17ccfb117709b53d26462a3f346fb7c79b85e",
+                output_str: "6de164a9626d5a4f54d854ac158994f35a8e362ecc753f55182790934a2e0d06"
+            },
+            Test {
+                input: "a963c3e895ff5a0be4824400518d81412f875fa50521e26e85eac90c04",
+                output_str: "b760312bd1b279fc672479d21c5ed349e5fe96f08940237b4515452721c49a16"
+            },
+            Test {
+                input: "03a18688b10cc0edf83adf0a84808a9718383c4070c6c4f295098699ac2c",
+                output_str: "94fc255de4ef19c0da4b09b2e2fac21f20048b46f17c30685abe40d5c743f375"
+            },
+            Test {
+                input: "84fb51b517df6c5accb5d022f8f28da09b10232d42320ffc32dbecc3835b29",
+                output_str: "39a4a0ffc4603698ae0a4f3d24b1bc42ac7a2d7d923e7a5d602453e82d5323c5"
+            },
+            Test {
+                input: "9f2fcc7c90de090d6b87cd7e9718c1ea6cb21118fc2d5de9f97e5db6ac1e9c10",
+                output_str: "2f1a5f7159e34ea19cddc70ebf9b81f1a66db40615d7ead3cc1f1b954d82a3af"
+            },
+            Test {
+                input: "de8f1b3faa4b7040ed4563c3b8e598253178e87e4d0df75e4ff2f2dedd5a0be046",
+                output_str: "1c57fe0e38cd3a124eaa6cd87f70a079bccc073a341e8c0eb1976fb3a3f7b774"
+            },
+            Test {
+                input: "62f154ec394d0bc757d045c798c8b87a00e0655d0481a7d2d9fb58d93aedc676b5a0",
+                output_str: "a905603b186ef4f2d5b2d1bcfda504c68ed5eb9b0c7b7ea2a001575f5aa69e68"
+            },
+            Test {
+                input: "b2dcfe9ff19e2b23ce7da2a4207d3e5ec7c6112a8a22aec9675a886378e14e5bfbad4e",
+                output_str: "fffd39f7c451788eb0316f429ea0a7c0ac8091657aca28f1560ed5775e8c4c12"
+            },
+            Test {
+                input: "47f5697ac8c31409c0868827347a613a3562041c633cf1f1f86865a576e02835ed2c2492",
+                output_str: "6f55becd168e0939ba2fa090257b1727fc66491a44493279a5beacb9e3435324"
+            },
+            Test {
+                input: "512a6d292e67ecb2fe486bfe92660953a75484ff4c4f2eca2b0af0edcdd4339c6b2ee4e542",
+                output_str: "84649bffcd48527b9288e8da5f52fbab2604dc5a91c4b0b87d477dbd7b40b6ae"
+            },
+            Test {
+                input: "973cf2b4dcf0bfa872b41194cb05bb4e16760a1840d8343301802576197ec19e2a1493d8f4fb",
+                output_str: "d4055b4e3e2aea1c67cc99fd409d574e53e1e296cf9eef73c472ab92a6cb6609"
+            },
+            Test {
+                input: "80beebcd2e3f8a9451d4499961c9731ae667cdc24ea020ce3b9aa4bbc0a7f79e30a934467da4b0",
+                output_str: "5694ca2f3b9962226a87163ab38325bcdc898a732dfeb2c36db4eb88616b8741"
+            },
+            Test {
+                input: "7abaa12ec2a7347674e444140ae0fb659d08e1c66decd8d6eae925fa451d65f3c0308e29446b8ed3",
+                output_str: "8cf287ad03ab4a74086620cfa4cce74f48fa5cdb15ec02b1f721736a4f849e60"
+            },
+            Test {
+                input: "c88dee9927679b8af422abcbacf283b904ff31e1cac58c7819809f65d5807d46723b20f67ba610c2b7",
+                output_str: "c5d5af22a4df9acd0c056fa30d8e240b679a20d4d2630260f779ff815ca82d7d"
+            },
+            Test {
+                input: "01e43fe350fcec450ec9b102053e6b5d56e09896e0ddd9074fe138e6038210270c834ce6eadc2bb86bf6",
+                output_str: "0ac75279adff65660464550a283fecd4e0610d88f35574c3d7ac5d22262a2fe8"
+            },
+            Test {
+                input: "337023370a48b62ee43546f17c4ef2bf8d7ecd1d49f90bab604b839c2e6e5bd21540d29ba27ab8e309a4b7",
+                output_str: "81917ae290dbba17289a8a67e5c2e8b12d3dde0efe9f990198a1763ff4f3dda7"
+            },
+            Test {
+                input: "6892540f964c8c74bd2db02c0ad884510cb38afd4438af31fc912756f3efec6b32b58ebc38fc2a6b913596a8",
+                output_str: "138e75e72fddd927e591315af8d3aba280efa36230a3309a97bcde5a78c31589"
+            },
+            Test {
+                input: "f5961dfd2b1ffffda4ffbf30560c165bfedab8ce0be525845deb8dc61004b7db38467205f5dcfb34a2acfe96c0",
+                output_str: "21bcdad3fef3e5b859cb0912a2991efa661bad812747292ef0f79a8fcc6b4e98"
+            },
+            Test {
+                input: "ca061a2eb6ceed8881ce2057172d869d73a1951e63d57261384b80ceb5451e77b06cf0f5a0ea15ca907ee1c27eba",
+                output_str: "8d6fd9c559b0b4948f91337916084c0082a16a0755b0a00811096e973e48b3c8"
+            },
+            Test {
+                input: "1743a77251d69242750c4f1140532cd3c33f9b5ccdf7514e8584d4a5f9fbd730bcf84d0d4726364b9bf95ab251d9bb",
+                output_str: "1dd23ae7aadd61e712bdd82bd60a70dd9d66c9fd79dbfd8669e3eaabf7901cdc"
+            },
+            Test {
+                input: "d8faba1f5194c4db5f176fabfff856924ef627a37cd08cf55608bba8f1e324d7c7f157298eabc4dce7d89ce5162499f9",
+                output_str: "34f8607ec10c092c1ba0b6565ce6197062c4e1a35a8e8c723e48a2d2416c3790"
+            },
+            Test {
+                input: "be9684be70340860373c9c482ba517e899fc81baaa12e5c6d7727975d1d41ba8bef788cdb5cf4606c9c1c7f61aed59f97d",
+                output_str: "19a8577fc90fae5d6a6b2e0c1ff155515502cfa1757029c09bebbfa263d9a363"
+            },
+            Test {
+                input: "7e15d2b9ea74ca60f66c8dfab377d9198b7b16deb6a1ba0ea3c7ee2042f89d3786e779cf053c77785aa9e692f821f14a7f51",
+                output_str: "9d9dbb4ce7d01d009e72a66051acc16805e49f598cbe430c5d4c22a881a64b3f"
+            },
+            Test {
+                input: "9a219be43713bd578015e9fda66c0f2d83cac563b776ab9f38f3e4f7ef229cb443304fba401efb2bdbd7ece939102298651c86",
+                output_str: "13f0d951b64481135466cfccbe52418cc1d03fb16b5b696c35d724f6f55cbb6d"
+            },
+            Test {
+                input: "c8f2b693bd0d75ef99caebdc22adf4088a95a3542f637203e283bbc3268780e787d68d28cc3897452f6a22aa8573ccebf245972a",
+                output_str: "fb2fe7b00b75c42305cf31de14d98f904e8c46dc57bb6f94c282ca8c13dc45db"
+            },
+            Test {
+                input: "ec0f99711016c6a2a07ad80d16427506ce6f441059fd269442baaa28c6ca037b22eeac49d5d894c0bf66219f2c08e9d0e8ab21de52",
+                output_str: "d54cbf7d5c80ae11a0d0bad4e95ab18b5f07c970621f3936447a48eef818d06e"
+            },
+            Test {
+                input: "0dc45181337ca32a8222fe7a3bf42fc9f89744259cff653504d6051fe84b1a7ffd20cb47d4696ce212a686bb9be9a8ab1c697b6d6a33",
+                output_str: "ff050a45adeef4cfc7d964102ba877c80320a37794893e6865965ec2547cd4c9"
+            },
+            Test {
+                input: "de286ba4206e8b005714f80fb1cdfaebde91d29f84603e4a3ebc04686f99a46c9e880b96c574825582e8812a26e5a857ffc6579f63742f",
+                output_str: "1bc1bcc70f638958db1006af37b02ebd8954ec59b3acbad12eacedbc5b21e908"
+            },
+            Test {
+                input: "eebcc18057252cbf3f9c070f1a73213356d5d4bc19ac2a411ec8cdeee7a571e2e20eaf61fd0c33a0ffeb297ddb77a97f0a415347db66bcaf",
+                output_str: "f7bde239ad087aa7dabe42cc4d3c49380a026cd239a7faaf34a2233469a44a4d"
+            },
+            Test {
+                input: "416b5cdc9fe951bd361bd7abfc120a5054758eba88fdd68fd84e39d3b09ac25497d36b43cbe7b85a6a3cebda8db4e5549c3ee51bb6fcb6ac1e",
+                output_str: "ef845aac2aaf0a793108204ff380e0a30f2558e7acde4531ab22f8ec79e26a69"
+            },
+            Test {
+                input: "5c5faf66f32e0f8311c32e8da8284a4ed60891a5a7e50fb2956b3cbaa79fc66ca376460e100415401fc2b8518c64502f187ea14bfc9503759705",
+                output_str: "26db514e01e034c678b636d40ba367da2f37f67078bb576ff2b8559b3517484d"
+            },
+            Test {
+                input: "7167e1e02be1a7ca69d788666f823ae4eef39271f3c26a5cf7cee05bca83161066dc2e217b330df821103799df6d74810eed363adc4ab99f36046a",
+                output_str: "5dbd4b558463196211465c1fc32401fc2d8e41ebc5e6badd1d8f7c4f090f728f"
+            },
+            Test {
+                input: "2fda311dbba27321c5329510fae6948f03210b76d43e7448d1689a063877b6d14c4f6d0eaa96c150051371f7dd8a4119f7da5c483cc3e6723c01fb7d",
+                output_str: "355c79fd6e6fa88ed402b6979fde1ed805498abeb101f4231b5d64d1439d552d"
+            },
+            Test {
+                input: "95d1474a5aab5d2422aca6e481187833a6212bd2d0f91451a67dd786dfc91dfed51b35f47e1deb8a8ab4b9cb67b70179cc26f553ae7b569969ce151b8d",
+                output_str: "3d9c9bf09d88211c7e0056112d073ee85d00acaa4da7a668fa017b3273cd4d4b"
+            },
+            Test {
+                input: "c71bd7941f41df044a2927a8ff55b4b467c33d089f0988aa253d294addbdb32530c0d4208b10d9959823f0c0f0734684006df79f7099870f6bf53211a88d",
+                output_str: "67980d28e2e658e7a24a2593a28167a13d907d06f47729d47ca4fe1772f8b3df"
+            },
+            Test {
+                input: "f57c64006d9ea761892e145c99df1b24640883da79d9ed5262859dcda8c3c32e05b03d984f1ab4a230242ab6b78d368dc5aaa1e6d3498d53371e84b0c1d4ba",
+                output_str: "a8df6b76df41994f7593f1a81967e77ee180e31183d1c4a569db854e61e99b05"
+            },
+            Test {
+                input: "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7",
+                output_str: "27a6441ee939b46e2c378d7afeb0e891c47a28120e488eff0ab71af08788ceb3"
+            },
+            Test {
+                input: "16e8b3d8f988e9bb04de9c96f2627811c973ce4a5296b4772ca3eefeb80a652bdf21f50df79f32db23f9f73d393b2d57d9a0297f7a2f2e79cfda39fa393df1ac00",
+                output_str: "c4bb067383002db44ca773918bb74104b604a583e12b06be56c270f8b43512f2"
+            },
+            Test {
+                input: "fc424eeb27c18a11c01f39c555d8b78a805b88dba1dc2a42ed5e2c0ec737ff68b2456d80eb85e11714fa3f8eabfb906d3c17964cb4f5e76b29c1765db03d91be37fc",
+                output_str: "ae773915ca642d80413330c9e0ee9bd06653c0023c5c0277100f3b1526eaa51d"
+            },
+            Test {
+                input: "abe3472b54e72734bdba7d9158736464251c4f21b33fbbc92d7fac9a35c4e3322ff01d2380cbaa4ef8fb07d21a2128b7b9f5b6d9f34e13f39c7ffc2e72e47888599ba5",
+                output_str: "1cf9d6ce9cb658556b76cd7eba3e51393699ad500b1ab3f56172748db7f59667"
+            },
+            Test {
+                input: "36f9f0a65f2ca498d739b944d6eff3da5ebba57e7d9c41598a2b0e4380f3cf4b479ec2348d015ffe6256273511154afcf3b4b4bf09d6c4744fdd0f62d75079d440706b05",
+                output_str: "8d60e889e2b1020dad4b523301f5f6bbab6c781af276085af6765546fcfb95ac"
+            },
+            Test {
+                input: "abc87763cae1ca98bd8c5b82caba54ac83286f87e9610128ae4de68ac95df5e329c360717bd349f26b872528492ca7c94c2c1e1ef56b74dbb65c2ac351981fdb31d06c77a4",
+                output_str: "dd4ff4b530552f48af9a7530a6464819ed1a5b733084f709e41daf1acb35ecfd"
+            },
+            Test {
+                input: "94f7ca8e1a54234c6d53cc734bb3d3150c8ba8c5f880eab8d25fed13793a9701ebe320509286fd8e422e931d99c98da4df7e70ae447bab8cffd92382d8a77760a259fc4fbd72",
+                output_str: "7ac8d4bb53fc434dd8712daefeb474668f541418e6f617dba523d8392eb0766e"
+            },
+            Test {
+                input: "13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d",
+                output_str: "f7b0e15a63232a2b800b23b311d357617ddfd1293e1ffe3f772692ade3427152"
+            },
+            Test {
+                input: "1eed9cba179a009ec2ec5508773dd305477ca117e6d569e66b5f64c6bc64801ce25a8424ce4a26d575b8a6fb10ead3fd1992edddeec2ebe7150dc98f63adc3237ef57b91397aa8a7",
+                output_str: "b3d05af7e8c406a7c2709223791d3f5f4b3129329993220053a36293ac2b0e06"
+            },
+            Test {
+                input: "ba5b67b5ec3a3ffae2c19dd8176a2ef75c0cd903725d45c9cb7009a900c0b0ca7a2967a95ae68269a6dbf8466c7b6844a1d608ac661f7eff00538e323db5f2c644b78b2d48de1a08aa",
+                output_str: "6c47e2ea4ba29e17792defc4b707754c4664bde15168a5100bf881ec7c02b258"
+            },
+            Test {
+                input: "0efa26ac5673167dcacab860932ed612f65ff49b80fa9ae65465e5542cb62075df1c5ae54fba4db807be25b070033efa223bdd5b1d3c94c6e1909c02b620d4b1b3a6c9fed24d70749604",
+                output_str: "82a66bed668dcc14af12c14c976ce650049e9d1d9969b83d1dd3b6f1c07d252b"
+            },
+            Test {
+                input: "bbfd933d1fd7bf594ac7f435277dc17d8d5a5b8e4d13d96d2f64e771abbd51a5a8aea741beccbddb177bcea05243ebd003cfdeae877cca4da94605b67691919d8b033f77d384ca01593c1b",
+                output_str: "2f21d07d7b10683b9ac7a63e9fcc70cf9f887cb905f9bff5332551288b288524"
+            },
+            Test {
+                input: "90078999fd3c35b8afbf4066cbde335891365f0fc75c1286cdd88fa51fab94f9b8def7c9ac582a5dbcd95817afb7d1b48f63704e19c2baa4df347f48d4a6d603013c23f1e9611d595ebac37c",
+                output_str: "80202f01e7140db4fee490dcc50afafdf6a48ca33d362c7875b8e8db9c9d0655"
+            },
+            Test {
+                input: "64105eca863515c20e7cfbaa0a0b8809046164f374d691cdbd6508aaabc1819f9ac84b52bafc1b0fe7cddbc554b608c01c8904c669d8db316a0953a4c68ece324ec5a49ffdb59a1bd6a292aa0e",
+                output_str: "b2330a189047e3117479a2f20b3407a7d119e4ad431fe06ff1ff2a106f2ab3a2"
+            },
+            Test {
+                input: "d4654be288b9f3b711c2d02015978a8cc57471d5680a092aa534f7372c71ceaab725a383c4fcf4d8deaa57fca3ce056f312961eccf9b86f14981ba5bed6ab5b4498e1f6c82c6cae6fc14845b3c8a",
+                output_str: "bb9b9bb685c241f8d63fdbf0dbaabcef7075add7ba405a2fffe7ad5b23e021c7"
+            },
+            Test {
+                input: "12d9394888305ac96e65f2bf0e1b18c29c90fe9d714dd59f651f52b88b3008c588435548066ea2fc4c101118c91f32556224a540de6efddbca296ef1fb00341f5b01fecfc146bdb251b3bdad556cd2",
+                output_str: "f8316a367aa0316da3562f319d522e81f4a8bd2e2108d2532126f4a903704ba3"
+            },
+            Test {
+                input: "871a0d7a5f36c3da1dfce57acd8ab8487c274fad336bc137ebd6ff4658b547c1dcfab65f037aa58f35ef16aff4abe77ba61f65826f7be681b5b6d5a1ea8085e2ae9cd5cf0991878a311b549a6d6af230",
+                output_str: "89e3ebd02b229cd759612a5521d867ab2a1594bc0b1fe6a78b7954ccc84caf03"
+            },
+            Test {
+                input: "e90b4ffef4d457bc7711ff4aa72231ca25af6b2e206f8bf859d8758b89a7cd36105db2538d06da83bad5f663ba11a5f6f61f236fd5f8d53c5e89f183a3cec615b50c7c681e773d109ff7491b5cc22296c5",
+                output_str: "2e7cc875305ea6bb9c2fc770b9d84fd93b96405df9b93307f6b5de26e135724c"
+            },
+            Test {
+                input: "e728de62d75856500c4c77a428612cd804f30c3f10d36fb219c5ca0aa30726ab190e5f3f279e0733d77e7267c17be27d21650a9a4d1e32f649627638dbada9702c7ca303269ed14014b2f3cf8b894eac8554",
+                output_str: "ecab75f28a728429cb433ec13310d1b850ccf522c38d2fa6dfa489963d6d6ca7"
+            },
+            Test {
+                input: "6348f229e7b1df3b770c77544e5166e081850fa1c6c88169db74c76e42eb983facb276ad6a0d1fa7b50d3e3b6fcd799ec97470920a7abed47d288ff883e24ca21c7f8016b93bb9b9e078bdb9703d2b781b616e",
+                output_str: "021c9459d1451f3da4c07c029a8681945c87c5bebc6c30da1d95c5c49d8ab95c"
+            },
+            Test {
+                input: "4b127fde5de733a1680c2790363627e63ac8a3f1b4707d982caea258655d9bf18f89afe54127482ba01e08845594b671306a025c9a5c5b6f93b0a39522dc877437be5c2436cbf300ce7ab6747934fcfc30aeaaf6",
+                output_str: "4642e21622f15b09b9413659680116bf2f96cac2384b8c79f1328d5dd36d7a01"
+            },
+            Test {
+                input: "08461f006cff4cc64b752c957287e5a0faabc05c9bff89d23fd902d324c79903b48fcb8f8f4b01f3e4ddb483593d25f000386698f5ade7faade9615fdc50d32785ea51d49894e45baa3dc707e224688c6408b68b11",
+                output_str: "8daa47c3572157266ad0276d5926aff2872f06b0cd7b974a80d7a6827d41d782"
+            },
+            Test {
+                input: "68c8f8849b120e6e0c9969a5866af591a829b92f33cd9a4a3196957a148c49138e1e2f5c7619a6d5edebe995acd81ec8bb9c7b9cfca678d081ea9e25a75d39db04e18d475920ce828b94e72241f24db72546b352a0e4",
+                output_str: "345365232ce9afc655dce4bac23f43c8acbdf9016d4bc2344be8d396a4919c34"
+            },
+            Test {
+                input: "b8d56472954e31fb54e28fca743f84d8dc34891cb564c64b08f7b71636debd64ca1edbdba7fc5c3e40049ce982bba8c7e0703034e331384695e9de76b5104f2fbc4535ecbeebc33bc27f29f18f6f27e8023b0fbb6f563c",
+                output_str: "f52e102e57293878c28f29deb47792324fe455a62fa7441aabcc16a9cfc40ffa"
+            },
+            Test {
+                input: "0d58ac665fa84342e60cefee31b1a4eacdb092f122dfc68309077aed1f3e528f578859ee9e4cefb4a728e946324927b675cd4f4ac84f64db3dacfe850c1dd18744c74ceccd9fe4dc214085108f404eab6d8f452b5442a47d",
+                output_str: "2b89aa88b1b7f9f8ea461c4c5cae4829125f45f5697deadb8db2e964524c0d91"
+            },
+            Test {
+                input: "1755e2d2e5d1c1b0156456b539753ff416651d44698e87002dcf61dcfa2b4e72f264d9ad591df1fdee7b41b2eb00283c5aebb3411323b672eaa145c5125185104f20f335804b02325b6dea65603f349f4d5d8b782DD3469CCD",
+                output_str: "3f3092365982c0b4278055beee9032ff9d1060e03c3b087e1a6197defc707e1a"
+            },
+            Test {
+                input: "b180de1a611111ee7584ba2c4b020598cd574ac77e404e853d15a101c6f5a2e5c801d7d85dc95286a1804c870bb9f00fd4dcb03aa8328275158819dcad7253f3e3d237aeaa7979268a5db1c6ce08a9ec7c2579783C8AFC1F91A7",
+                output_str: "3c74aae2f340a24178cbab51004cba1aac3d91133c300715ea82c177269c0556"
+            },
+            Test {
+                input: "cf3583cbdfd4cbc17063b1e7d90b02f0e6e2ee05f99d77e24e560392535e47e05077157f96813544a17046914f9efb64762a23cf7a49fe52a0a4c01c630cfe8727b81fb99a89ff7cc11dca5173057e0417b8fe7a9EFBA6D95C555F",
+                output_str: "0157c4ba44618ded11e9800afa07a0d5b6c711fc16a576c5edb71c4cc6894f82"
+            },
+            Test {
+                input: "072fc02340ef99115bad72f92c01e4c093b9599f6cfc45cb380ee686cb5eb019e806ab9bd55e634ab10aa62a9510cc0672cd3eddb589c7df2b67fcd3329f61b1a4441eca87a33c8f55da4fbbad5cf2b2527b8e983BB31A2FADEC7523",
+                output_str: "8d53dba107aaacb8422d6667f6778839f8965f8e4c8f4a851284cc91168a9030"
+            },
+            Test {
+                input: "76eecf956a52649f877528146de33df249cd800e21830f65e90f0f25ca9d6540fde40603230eca6760f1139c7f268deba2060631eea92b1fff05f93fd5572fbe29579ecd48bc3a8d6c2eb4a6b26e38d6c5fbf2c08044AEEA470A8F2F26",
+                output_str: "5163f02233e332ad9be32c2346c9fcfe39afa5fbe9bc1cfeb92f4920155b20ec"
+            },
+            Test {
+                input: "7adc0b6693e61c269f278e6944a5a2d8300981e40022f839ac644387bfac9086650085c2cdc585fea47b9d2e52d65a2b29a7dc370401ef5d60dd0d21f9e2b90fae919319b14b8c5565b0423cefb827d5f1203302a9D01523498A4DB10374",
+                output_str: "faaf0e95217ca4b1568751ef2e4cd341d9ec33e16600bf09b92c6f1a6df84d2e"
+            },
+            Test {
+                input: "e1fffa9826cce8b86bccefb8794e48c46cdf372013f782eced1e378269b7be2b7bf51374092261ae120e822be685f2e7a83664bcfbe38fe8633f24e633ffe1988e1bc5acf59a587079a57a910bda60060e85b5f5b6F776F0529639D9CCE4BD",
+                output_str: "b2c175d9d92aaa9ee72672f995b8dfd2daaf6555a0327a508218a9b447f00be8"
+            },
+            Test {
+                input: "69f9abba65592ee01db4dce52dbab90b08fc04193602792ee4daa263033d59081587b09bbe49d0b49c9825d22840b2ff5d9c5155f975f8f2c2e7a90c75d2e4a8040fe39f63bbafb403d9e28cc3b86e04e394a9c9e8065BD3C85FA9F0C7891600",
+                output_str: "fb5388122306d37cee790cad1d3cddba8e9a93d5f9d78288b052482739c883fd"
+            },
+            Test {
+                input: "38a10a352ca5aedfa8e19c64787d8e9c3a75dbf3b8674bfab29b5dbfc15a63d10fae66cd1a6e6d2452d557967eaad89a4c98449787b0b3164ca5b717a93f24eb0b506ceb70cbbcb8d72b2a72993f909aad92f044e0B5A2C9AC9CB16A0CA2F81F49",
+                output_str: "1c2f8d418ff6718b18dd4c756dcc8ed0f4755e8c22497a6cc19f8d7ae7fd2da7"
+            },
+            Test {
+                input: "6d8c6e449bc13634f115749c248c17cd148b72157a2c37bf8969ea83b4d6ba8c0ee2711c28ee11495f43049596520ce436004b026b6c1f7292b9c436b055cbb72d530d860d1276a1502a5140e3c3f54a93663e4d20EDEC32D284E25564F624955B52",
+                output_str: "7ea8116e6434c1caa049069dbbd9b6f0e9dc6cdfd6a889343d3b2652803078fc"
+            },
+            Test {
+                input: "6efcbcaf451c129dbe00b9cef0c3749d3ee9d41c7bd500ade40cdc65dedbbbadb885a5b14b32a0c0d087825201e303288a733842fa7e599c0c514e078f05c821c7a4498b01c40032e9f1872a1c925fa17ce253e8935E4C3C71282242CB716B2089CCC1",
+                output_str: "736d888751faac4d8e78b45b95abb15d40d98d8038c7225be0f523d5439ea5b6"
+            },
+            Test {
+                input: "433c5303131624c0021d868a30825475e8d0bd3052a022180398f4ca4423b98214b6beaac21c8807a2c33f8c93bd42b092cc1b06cedf3224d5ed1ec29784444f22e08a55aa58542b524b02cd3d5d5f6907afe71c5D7462224A3F9D9E53E7E0846DCBB4CE",
+                output_str: "90e10b1ca8d352794d7dbd7bae410bef25f0ec7d080e053f48674237e33ea45f"
+            },
+            Test {
+                input: "a873e0c67ca639026b6683008f7aa6324d4979550e9bce064ca1e1fb97a30b147a24f3f666c0a72d71348ede701cf2d17e2253c34d1ec3b647dbcef2f879f4eb881c4830b791378c901eb725ea5c172316c6d606e0AF7DF4DF7F76E490CD30B2BADF45685F",
+                output_str: "8a0a8d6d55cccbe05ec74dc273b16d66c9b9006665eecb5b6023d2ea39c64554"
+            },
+            Test {
+                input: "006917b64f9dcdf1d2d87c8a6173b64f6587168e80faa80f82d84f60301e561e312d9fbce62f39a6fb476e01e925f26bcc91de621449be6504c504830aae394096c8fc7694651051365d4ee9070101ec9b68086f2EA8F8AB7B811EA8AD934D5C9B62C60A4771",
+                output_str: "122895d63aa6030fc8f23940c528e7a5d9c7fb170a79fe7bc42360ce50e25b7a"
+            },
+            Test {
+                input: "f13c972c52cb3cc4a4df28c97f2df11ce089b815466be88863243eb318c2adb1a417cb1041308598541720197b9b1cb5ba2318bd5574d1df2174af14884149ba9b2f446d609df240ce335599957b8ec80876d9a085AE084907BC5961B20BF5F6CA58D5DAB38ADB",
+                output_str: "3e04ee539505c52d814cab3c5cdd7df2d6eee627ea44188153ea6b8c8be5f6c2"
+            },
+            Test {
+                input: "e35780eb9799ad4c77535d4ddb683cf33ef367715327cf4c4a58ed9cbdcdd486f669f80189d549a9364fa82a51a52654ec721bb3aab95dceb4a86a6afa93826db923517e928f33e3fba850d45660ef83b9876accaFA2A9987A254B137C6E140A21691E1069413848",
+                output_str: "e360b424a5c06704d148352e04f4651f8d3b385c01f24fda09d266d4ed7ff662"
+            },
+            Test {
+                input: "64ec021c9585e01ffe6d31bb50d44c79b6993d72678163db474947a053674619d158016adb243f5c8d50aa92f50ab36e579ff2dabb780a2b529370daa299207cfbcdd3a9a25006d19c4f1fe33e4b1eaec315d8c6eE1E730623FD1941875B924EB57D6D0C2EDC4E78D6",
+                output_str: "0d3becb9e1b4ae1f15c9ee98732b4796e99fd799f76ed7332a68ab36c77a1ef9"
+            },
+            Test {
+                input: "5954bab512cf327d66b5d9f296180080402624ad7628506b555eea8382562324cf452fba4a2130de3e165d11831a270d9cb97ce8c2d32a96f50d71600bb4ca268cf98e90d6496b0a6619a5a8c63db6d8a0634dfc6C7EC8EA9C006B6C456F1B20CD19E781AF20454AC880",
+                output_str: "3aadd7e2086d383832489aa3088e903f5c6fa8e38df2cf876e0b4dcddca5c923"
+            },
+            Test {
+                input: "03d9f92b2c565709a568724a0aff90f8f347f43b02338f94a03ed32e6f33666ff5802da4c81bdce0d0e86c04afd4edc2fc8b4141c2975b6f07639b1994c973d9a9afce3d9d365862003498513bfa166d2629e314d97441667B007414E739D7FEBF0FE3C32C17AA188A8683",
+                output_str: "715ced5776a802eb8ee02c9d46543ff46fe7a9cd192fa7d4ffb6e81427fe1b71"
+            },
+            Test {
+                input: "f31e8b4f9e0621d531d22a380be5d9abd56faec53cbd39b1fab230ea67184440e5b1d15457bd25f56204fa917fa48e669016cb48c1ffc1e1e45274b3b47379e00a43843cf8601a5551411ec12503e5aac43d8676a1B2297EC7A0800DBFEE04292E937F21C005F17411473041",
+                output_str: "dde61f8be25b8b23e1212c1c0b8a85a0d02d8548bb17d377133e3c06ddb58ca2"
+            },
+            Test {
+                input: "758ea3fea738973db0b8be7e599bbef4519373d6e6dcd7195ea885fc991d896762992759c2a09002912fb08e0cb5b76f49162aeb8cf87b172cf3ad190253df612f77b1f0c532e3b5fc99c2d31f8f65011695a087a35EE4EEE5E334C369D8EE5D29F695815D866DA99DF3F79403",
+                output_str: "059f2bedf4a6eefb95fc5c0ae17556ce8bddc5e1880fab2f688a03a46bb28c5f"
+            },
+            Test {
+                input: "47c6e0c2b74948465921868804f0f7bd50dd323583dc784f998a93cd1ca4c6ef84d41dc81c2c40f34b5bee6a93867b3bdba0052c5f59e6f3657918c382e771d33109122cc8bb0e1e53c4e3d13b43ce44970f5e0c079D2AD7D7A3549CD75760C21BB15B447589E86E8D76B1E9CED2",
+                output_str: "125b0ee7870a6f7eb4fd965d9e0b90d79fffbc54a2018f4c68224682f3603f3f"
+            },
+            Test {
+                input: "f690a132ab46b28edfa6479283d6444e371c6459108afd9c35dbd235e0b6b6ff4c4ea58e7554bd002460433b2164ca51e868f7947d7d7a0d792e4abf0be5f450853cc40d85485b2b8857ea31b5ea6e4ccfa2f3a7eF3380066D7D8979FDAC618AAD3D7E886DEA4F005AE4AD05E5065F",
+                output_str: "9a78e0b5a34cbf1716f14cf7b67efdc4540a75cc646538a11a8efd9d7cd7529f"
+            },
+            Test {
+                input: "58d6a99bc6458824b256916770a8417040721cccfd4b79eacd8b65a3767ce5ba7e74104c985ac56b8cc9aebd16febd4cda5adb130b0ff2329cc8d611eb14dac268a2f9e633c99de33997fea41c52a7c5e1317d5b5DAED35EBA7D5A60E45D1FA7EAABC35F5C2B0A0F2379231953322C4E",
+                output_str: "42305a251a8009edfd62c7d91910b96b9b5dd8fda5b1326fe41ef6eef978d1be"
+            },
+            Test {
+                input: "befab574396d7f8b6705e2d5b58b2c1c820bb24e3f4bae3e8fbcd36dbf734ee14e5d6ab972aedd3540235466e825850ee4c512ea9795abfd33f330d9fd7f79e62bbb63a6ea85de15beaeea6f8d204a28956059e2632D11861DFB0E65BC07AC8A159388D5C3277E227286F65FF5E5B5AEC1",
+                output_str: "6b9e8f3e82ea174ebc88a53c5ded06271d38f79e9cec571a9d195ef549102eb8"
+            },
+            Test {
+                input: "8e58144fa9179d686478622ce450c748260c95d1ba43b8f9b59abeca8d93488da73463ef40198b4d16fb0b0707201347e0506ff19d01bea0f42b8af9e71a1f1bd168781069d4d338fdef00bf419fbb003031df671F4A37979564F69282DE9C65407847DD0DA505AB1641C02DEA4F0D834986",
+                output_str: "358de4c1ed30f48b084f961f653febc69318f93883612d5a04b9139a14ec702e"
+            },
+            Test {
+                input: "b55c10eae0ec684c16d13463f29291bf26c82e2fa0422a99c71db4af14dd9c7f33eda52fd73d017cc0f2dbe734d831f0d820d06d5f89dacc485739144f8cfd4799223b1aff9031a105cb6a029ba71e6e5867d85a554991C38DF3C9EF8C1E1E9A7630BE61CAABCA69280C399C1FB7A12D12AEFC",
+                output_str: "4a7bd18ae10eb9458924aa5ca00d3f634ab9753628107f15ff2bf24ccd3b94f4"
+            },
+            Test {
+                input: "2eeea693f585f4ed6f6f8865bbae47a6908aecd7c429e4bec4f0de1d0ca0183fa201a0cb14a529b7d7ac0e6ff6607a3243ee9fb11bcf3e2304fe75ffcddd6c5c2e2a4cd45f63c962d010645058d36571404a6d2b4F44755434D76998E83409C3205AA1615DB44057DB991231D2CB42624574F545",
+                output_str: "9889e4b3b1294a01556fa9de6a6a508a9a763d5133fdcd4937b6bb23ca3e1901"
+            },
+            Test {
+                input: "dab11dc0b047db0420a585f56c42d93175562852428499f66a0db811fcdddab2f7cdffed1543e5fb72110b64686bc7b6887a538ad44c050f1e42631bc4ec8a9f2a047163d822a38989ee4aab01b4c1f161b062d873B1CFA388FD301514F62224157B9BEF423C7783B7AAC8D30D65CD1BBA8D689C2D",
+                output_str: "3d02b41985bdd1835cb474fb364c25c2cca9da0ed2fbbab75524b410903815b9"
+            },
+            Test {
+                input: "42e99a2f80aee0e001279a2434f731e01d34a44b1a8101726921c0590c30f3120eb83059f325e894a5ac959dca71ce2214799916424e859d27d789437b9d27240bf8c35adbafcecc322b48aa205b293962d858652ABACBD588BCF6CBC388D0993BD622F96ED54614C25B6A9AA527589EAAFFCF17DDF7",
+                output_str: "1cd92039be4580c686796d5900eed431ebad6ea566e9244e76ba6873efcb49ab"
+            },
+            Test {
+                input: "3c9b46450c0f2cae8e3823f8bdb4277f31b744ce2eb17054bddc6dff36af7f49fb8a2320cc3bdf8e0a2ea29ad3a55de1165d219adeddb5175253e2d1489e9b6fdd02e2c3d3a4b54d60e3a47334c37913c5695378a669E9B72DEC32AF5434F93F46176EBF044C4784467C700470D0C0B40C8A088C815816",
+                output_str: "680c70b243163be6e58ed3b8e2d85e6894e5e89501c444c8c0a2d776acad8599"
+            },
+            Test {
+                input: "d1e654b77cb155f5c77971a64df9e5d34c26a3cad6c7f6b300d39deb1910094691adaa095be4ba5d86690a976428635d5526f3e946f7dc3bd4dbc78999e653441187a81f9adcd5a3c5f254bc8256b0158f54673dcC1232F6E918EBFC6C51CE67EAEB042D9F57EEC4BFE910E169AF78B3DE48D137DF4F2840",
+                output_str: "d65e823d2ce4effb9b27dbbf6efcda738ad152fbb12d2108d2ec6d050a3fb295"
+            },
+            Test {
+                input: "626f68c18a69a6590159a9c46be03d5965698f2dac3de779b878b3d9c421e0f21b955a16c715c1ec1e22ce3eb645b8b4f263f60660ea3028981eebd6c8c3a367285b691c8ee56944a7cd1217997e1d9c21620b536BDBD5DE8925FF71DEC6FBC06624AB6B21E329813DE90D1E572DFB89A18120C3F606355D25",
+                output_str: "ce6d2dd8d5441fc15b888fed72061e129125431bedea32e00ee0a7655c06c358"
+            },
+            Test {
+                input: "651a6fb3c4b80c7c68c6011675e6094eb56abf5fc3057324ebc6477825061f9f27e7a94633abd1fa598a746e4a577caf524c52ec1788471f92b8c37f23795ca19d559d446cab16cbcdce90b79fa1026cee77bf4ab1B503C5B94C2256AD75B3EAC6FD5DCB96ACA4B03A834BFB4E9AF988CECBF2AE597CB9097940",
+                output_str: "280713c0fa7160289fbfee5aa580ad82512839153dae47de0d154384a4d8b3ed"
+            },
+            Test {
+                input: "8aaf072fce8a2d96bc10b3c91c809ee93072fb205ca7f10abd82ecd82cf040b1bc49ea13d1857815c0e99781de3adbb5443ce1c897e55188ceaf221aa9681638de05ae1b322938f46bce51543b57ecdb4c266272259D1798DE13BE90E10EFEC2D07484D9B21A3870E2AA9E06C21AA2D0C9CF420080A80A91DEE16F",
+                output_str: "721fd872696f21deaa9595c0cee7bc07249601927c96a65826b4887cdba1ae96"
+            },
+            Test {
+                input: "53f918fd00b1701bd504f8cdea803acca21ac18c564ab90c2a17da592c7d69688f6580575395551e8cd33e0fef08ca6ed4588d4d140b3e44c032355df1c531564d7f4835753344345a6781e11cd5e095b73df5f82C8AE3AD00877936896671E947CC52E2B29DCD463D90A0C9929128DA222B5A211450BBC0E02448E2",
+                output_str: "b53af8620b39cad2d698a176a070aeaa9fb67bd0335c3485a3b6c73a71dc5c5c"
+            },
+            Test {
+                input: "a64599b8a61b5ccec9e67aed69447459c8da3d1ec6c7c7c82a7428b9b584fa67e90f68e2c00fbbed4613666e5168da4a16f395f7a3c3832b3b134bfc9cbaa95d2a0fe252f44ac6681eb6d40ab91c1d0282fed6701C57463D3C5F2BB8C6A7301FB4576AA3B5F15510DB8956FF77478C26A7C09BEA7B398CFC83503F538E",
+                output_str: "78a18bf0a52e6f77f15f7ffe4ca3c999e57e1c3f6bf10950581f403450edb797"
+            },
+            Test {
+                input: "0e3ab0e054739b00cdb6a87bd12cae024b54cb5e550e6c425360c2e87e59401f5ec24ef0314855f0f56c47695d56a7fb1417693af2a1ed5291f2fee95f75eed54a1b1c2e81226fbff6f63ade584911c71967a8eb70933BC3F5D15BC91B5C2644D9516D3C3A8C154EE48E118BD1442C043C7A0DBA5AC5B1D5360AAE5B9065",
+                output_str: "a7f0151eee6b21fe827e69256d560e1ea8d939b80962fc7fa8610ac189402ad2"
+            },
+            Test {
+                input: "a62fc595b4096e6336e53fcdfc8d1cc175d71dac9d750a6133d23199eaac288207944cea6b16d27631915b4619f743da2e30a0c00bbdb1bbb35ab852ef3b9aec6b0a8dcc6e9e1abaa3ad62ac0a6c5de765de2c3711B769E3FDE44A74016FFF82AC46FA8F1797D3B2A726B696E3DEA5530439ACEE3A45C2A51BC32DD055650B",
+                output_str: "0a09c4b18f5117f0e45d43e235bb14e55b162e99eb3744165196d04a854229f9"
+            },
+            Test {
+                input: "2b6db7ced8665ebe9deb080295218426bdaa7c6da9add2088932cdffbaa1c14129bccdd70f369efb149285858d2b1d155d14de2fdb680a8b027284055182a0cae275234cc9c92863c1b4ab66f304cf0621cd54565F5BFF461D3B461BD40DF28198E3732501B4860EADD503D26D6E69338F4E0456E9E9BAF3D827AE685FB1D817",
+                output_str: "b7d031aa69b7b4d26a35b896d761314f1d61eb12dcc1e72aaf61b9cd48003af9"
+            },
+            Test {
+                input: "10db509b2cdcaba6c062ae33be48116a29eb18e390e1bbada5ca0a2718afbcd23431440106594893043cc7f2625281bf7de2655880966a23705f0c5155c2f5cca9f2c2142e96d0a2e763b70686cd421b5db812dacED0C6D65035FDE558E94F26B3E6DDE5BD13980CC80292B723013BD033284584BFF27657871B0CF07A849F4AE2",
+                output_str: "ec0858c9d017a2d3727caade7e4872684f17b822cafecda445a15cf30fac8cf0"
+            },
+            Test {
+                input: "9334de60c997bda6086101a6314f64e4458f5ff9450c509df006e8c547983c651ca97879175aaba0c539e82d05c1e02c480975cbb30118121061b1ebac4f8d9a3781e2db6b18042e01ecf9017a64a0e57447ec7fcBE6A7F82585F7403EE2223D52D37B4BF426428613D6B4257980972A0ACAB508A7620C1CB28EB4E9D30FC41361EC",
+                output_str: "71e1d610b576063f2b12f691220beadf506bec0a3a086bbe5864fb54f93db556"
+            },
+            Test {
+                input: "e88ab086891693aa535ceb20e64c7ab97c7dd3548f3786339897a5f0c39031549ca870166e477743ccfbe016b4428d89738e426f5ffe81626137f17aecff61b72dbee2dc20961880cfe281dfab5ee38b1921881450E16032DE5E4D55AD8D4FCA609721B0692BAC79BE5A06E177FE8C80C0C83519FB3347DE9F43D5561CB8107B9B5EDC",
+                output_str: "72a8a7493309080accca2a2a21d641f2b9685b7362be496dc7bc330659f8cfe1"
+            },
+            Test {
+                input: "fd19e01a83eb6ec810b94582cb8fbfa2fcb992b53684fb748d2264f020d3b960cb1d6b8c348c2b54a9fcea72330c2aaa9a24ecdb00c436abc702361a82bb8828b85369b8c72ece0082fe06557163899c2a0efa466C33C04343A839417057399A63A3929BE1EE4805D6CE3E5D0D0967FE9004696A5663F4CAC9179006A2CEB75542D75D68",
+                output_str: "af19e988d37e2577da4f43463789b73625d354fcccbd10cd2c61fbdc8bb01827"
+            },
+            Test {
+                input: "59ae20b6f7e0b3c7a989afb28324a40fca25d8651cf1f46ae383ef6d8441587aa1c04c3e3bf88e8131ce6145cfb8973d961e8432b202fa5af3e09d625faad825bc19da9b5c6c20d02abda2fcc58b5bd3fe507bf201263F30543819510C12BC23E2DDB4F711D087A86EDB1B355313363A2DE996B891025E147036087401CCF3CA7815BF3C49",
+                output_str: "f1e9b9cef2b37e4ec3a0fcd5eff5bf7e3d49100aebf018dc92fb6a40e4297704"
+            },
+            Test {
+                input: "77ee804b9f3295ab2362798b72b0a1b2d3291dceb8139896355830f34b3b328561531f8079b79a6e9980705150866402fdc176c05897e359a6cb1a7ab067383eb497182a7e5aef7038e4c96d133b2782917417e391535B5E1B51F47D8ED7E4D4025FE98DC87B9C1622614BFF3D1029E68E372DE719803857CA52067CDDAAD958951CB2068CC6",
+                output_str: "dd3ebe0cca0cad3af72af73fb49d40dbdcc4b1f1ff465ccaefe672f77992aca0"
+            },
+            Test {
+                input: "b771d5cef5d1a41a93d15643d7181d2a2ef0a8e84d91812f20ed21f147bef732bf3a60ef4067c3734b85bc8cd471780f10dc9e8291b58339a677b960218f71e793f2797aea349406512829065d37bb55ea796fa4f56FD8896B49B2CD19B43215AD967C712B24E5032D065232E02C127409D2ED4146B9D75D763D52DB98D949D3B0FED6A8052FBB",
+                output_str: "a19eee92bb2097b64e823d597798aa18be9b7c736b8059abfd6779ac35ac81b5"
+            },
+            Test {
+                input: "b32d95b0b9aad2a8816de6d06d1f86008505bd8c14124f6e9a163b5a2ade55f835d0ec3880ef50700d3b25e42cc0af050ccd1be5e555b23087e04d7bf9813622780c7313a1954f8740b6ee2d3f71f768dd417f520482BD3A08D4F222B4EE9DBD015447B33507DD50F3AB4247C5DE9A8ABD62A8DECEA01E3B87C8B927F5B08BEB37674C6F8E380C04",
+                output_str: "df673f4105379ff6b755eeab20ceb0dc77b5286364fe16c59cc8a907aff07732"
+            },
+            Test {
+                input: "04410e31082a47584b406f051398a6abe74e4da59bb6f85e6b49e8a1f7f2ca00dfba5462c2cd2bfde8b64fb21d70c083f11318b56a52d03b81cac5eec29eb31bd0078b6156786da3d6d8c33098c5c47bb67ac64db14165AF65B44544D806DDE5F487D5373C7F9792C299E9686B7E5821E7C8E2458315B996B5677D926DAC57B3F22DA873C601016A0D",
+                output_str: "d52432cf3b6b4b949aa848e058dcd62d735e0177279222e7ac0af8504762faa0"
+            },
+            Test {
+                input: "8b81e9badde026f14d95c019977024c9e13db7a5cd21f9e9fc491d716164bbacdc7060d882615d411438aea056c340cdf977788f6e17d118de55026855f93270472d1fd18b9e7e812bae107e0dfde7063301b71f6CFE4E225CAB3B232905A56E994F08EE2891BA922D49C3DAFEB75F7C69750CB67D822C96176C46BD8A29F1701373FB09A1A6E3C7158F",
+                output_str: "07e65754d62e01b9a049d15dec0d09c02f479ca2aeb4b18e37070b20f85a1b26"
+            },
+            Test {
+                input: "fa6eed24da6666a22208146b19a532c2ec9ba94f09f1def1e7fc13c399a48e41acc2a589d099276296348f396253b57cb0e40291bd282773656b6e0d8bea1cda084a3738816a840485fcf3fb307f777fa5feac48695C2AF4769720258C77943FB4556C362D9CBA8BF103AEB9034BAA8EA8BFB9C4F8E6742CE0D52C49EA8E974F339612E830E9E7A9C29065",
+                output_str: "17a461b8ee507abcfed51a50ef14891309fe402c569d94394ca7a3031befcd50"
+            },
+            Test {
+                input: "9bb4af1b4f09c071ce3cafa92e4eb73ce8a6f5d82a85733440368dee4eb1cbc7b55ac150773b6fe47dbe036c45582ed67e23f4c74585dab509df1b83610564545642b2b1ec463e18048fc23477c6b2aa035594ecd33791AF6AF4CBC2A1166ABA8D628C57E707F0B0E8707CAF91CD44BDB915E0296E0190D56D33D8DDE10B5B60377838973C1D943C22ED335E",
+                output_str: "a03c6b5b51ae4aa00912af1cfb6c7b960ef58036156497cc567b1369149a5949"
+            },
+            Test {
+                input: "2167f02118cc62043e9091a647cadbed95611a521fe0d64e8518f16c808ab297725598ae296880a773607a798f7c3cfce80d251ebec6885015f9abf7eaabae46798f82cb5926de5c23f44a3f9f9534b3c6f405b5364C2F8A8BDC5CA49C749BED8CE4BA48897062AE8424CA6DDE5F55C0E42A95D1E292CA54FB46A84FBC9CD87F2D0C9E7448DE3043AE22FDD229",
+                output_str: "14c69c5eabdefc9e3a1461a379ec92c32bc6b69071029cb3655159db1a5251a7"
+            },
+            Test {
+                input: "94b7fa0bc1c44e949b1d7617d31b4720cbe7ca57c6fa4f4094d4761567e389ecc64f6968e4064df70df836a47d0c713336b5028b35930d29eb7a7f9a5af9ad5cf441745baec9bb014ceeff5a41ba5c1ce085feb980BAB9CF79F2158E03EF7E63E29C38D7816A84D4F71E0F548B7FC316085AE38A060FF9B8DEC36F91AD9EBC0A5B6C338CBB8F6659D342A24368CF",
+                output_str: "3cbe06887c8ae360e957eb08ca577834c457fadf418d0cb73967fa827a22a4d7"
+            },
+            Test {
+                input: "ea40e83cb18b3a242c1ecc6ccd0b7853a439dab2c569cfc6dc38a19f5c90acbf76aef9ea3742ff3b54ef7d36eb7ce4ff1c9ab3bc119cff6be93c03e208783335c0ab8137be5b10cdc66ff3f89a1bddc6a1eed74f504CBE7290690BB295A872B9E3FE2CEE9E6C67C41DB8EFD7D863CF10F840FE618E7936DA3DCA5CA6DF933F24F6954BA0801A1294CD8D7E66DFAFEC",
+                output_str: "e58a947e98d6dd7e932d2fe02d9992e6118c0c2c606bdcda06e7943d2c95e0e5"
+            },
+            Test {
+                input: "157d5b7e4507f66d9a267476d33831e7bb768d4d04cc3438da12f9010263ea5fcafbde2579db2f6b58f911d593d5f79fb05fe3596e3fa80ff2f761d1b0e57080055c118c53e53cdb63055261d7c9b2b39bd90acc32520CBBDBDA2C4FD8856DBCEE173132A2679198DAF83007A9B5C51511AE49766C792A29520388444EBEFE28256FB33D4260439CBA73A9479EE00C63",
+                output_str: "a936fb9af87fb67857b3ead5c76226ad84da47678f3c2ffe5a39fdb5f7e63ffb"
+            },
+            Test {
+                input: "836b34b515476f613fe447a4e0c3f3b8f20910ac89a3977055c960d2d5d2b72bd8acc715a9035321b86703a411dde0466d58a59769672aa60ad587b8481de4bba552a1645779789501ec53d540b904821f32b0bd1855B04E4848F9F8CFE9EBD8911BE95781A759D7AD9724A7102DBE576776B7C632BC39B9B5E19057E226552A5994C1DBB3B5C7871A11F5537011044C53",
+                output_str: "3a654b88f88086c2751edae6d39248143cf6235c6b0b7969342c45a35194b67e"
+            },
+            Test {
+                input: "cc7784a4912a7ab5ad3620aab29ba87077cd3cb83636adc9f3dc94f51edf521b2161ef108f21a0a298557981c0e53ce6ced45bdf782c1ef200d29bab81dd6460586964edab7cebdbbec75fd7925060f7da2b853b2B089588FA0F8C16EC6498B14C55DCEE335CB3A91D698E4D393AB8E8EAC0825F8ADEBEEE196DF41205C011674E53426CAA453F8DE1CBB57932B0B741D4C6",
+                output_str: "19a3cb3e8551f08fbba5db614e268f63d1f6a0c3689bbe973d59d35bb4f455d0"
+            },
+            Test {
+                input: "7639b461fff270b2455ac1d1afce782944aea5e9087eb4a39eb96bb5c3baaf0e868c8526d3404f9405e79e77bfac5ffb89bf1957b523e17d341d7323c302ea7083872dd5e8705694acdda36d5a1b895aaa16eca6104C82688532C8BFE1790B5DC9F4EC5FE95BAED37E1D287BE710431F1E5E8EE105BC42ED37D74B1E55984BF1C09FE6A1FA13EF3B96FAEAED6A2A1950A12153",
+                output_str: "ca8cfb13973ff8597d6aaa806bd32e82f4ea68bac3fb543f26687de4b9cbe8bd"
+            },
+            Test {
+                input: "eb6513fc61b30cfba58d4d7e80f94d14589090cf1d80b1df2e68088dc6104959ba0d583d585e9578ab0aec0cf36c48435eb52ed9ab4bbce7a5abe679c97ae2dbe35e8cc1d45b06dda3cf418665c57cbee4bbb47fa4CAF78F4EE656FEC237FE4EEBBAFA206E1EF2BD0EE4AE71BD0E9B2F54F91DAADF1FEBFD7032381D636B733DCB3BF76FB14E23AFF1F68ED3DBCF75C9B99C6F26",
+                output_str: "9ae670fa85ab5c6b3bc76797cf24cd385110708137b6f8efd8d1a21c39881c18"
+            },
+            Test {
+                input: "1594d74bf5dde444265d4c04dad9721ff3e34cbf622daf341fe16b96431f6c4df1f760d34f296eb97d98d560ad5286fec4dce1724f20b54fd7df51d4bf137add656c80546fb1bf516d62ee82baa992910ef4cc18b70F3F8698276FCFB44E0EC546C2C39CFD8EE91034FF9303058B4252462F86C823EB15BF481E6B79CC3A02218595B3658E8B37382BD5048EAED5FD02C37944E73B",
+                output_str: "e32df6218ba75fd4788a7e5727a7d68c5829c49346683fc213e433af3dba5ab5"
+            },
+            Test {
+                input: "4cfa1278903026f66fedd41374558be1b585d03c5c55dac94361df286d4bd39c7cb8037ed3b267b07c346626449d0cc5b0dd2cf221f7e4c3449a4be99985d2d5e67bff2923357ddeab5abcb4619f3a3a57b2cf928A022EB27676C6CF805689004FCA4D41EA6C2D0A4789C7605F7BB838DD883B3AD3E6027E775BCF262881428099C7FFF95B14C095EA130E0B9938A5E22FC52650F591",
+                output_str: "028173e3c6c392e5d13af748f3788d43449bc5dd5953124ea5edf3930275f665"
+            },
+            Test {
+                input: "d3e65cb92cfa79662f6af493d696a07ccf32aaadcceff06e73e8d9f6f909209e66715d6e978788c49efb9087b170ecf3aa86d2d4d1a065ae0efc8924f365d676b3cb9e2bec918fd96d0b43dee83727c9a93bf56ca2B2E59ADBA85696546A815067FC7A78039629D4948D157E7B0D826D1BF8E81237BAB7321312FDAA4D521744F988DB6FDF04549D0FDCA393D639C729AF716E9C8BBA48",
+                output_str: "97450fc46f2e5df8f81623b1cca43fa50f51ea735e4421d7dff66314d8e211bc"
+            },
+            Test {
+                input: "842cc583504539622d7f71e7e31863a2b885c56a0ba62db4c2a3f2fd12e79660dc7205ca29a0dc0a87db4dc62ee47a41db36b9ddb3293b9ac4baae7df5c6e7201e17f717ab56e12cad476be49608ad2d50309e7d48D2D8DE4FA58AC3CFEAFEEE48C0A9EEC88498E3EFC51F54D300D828DDDCCB9D0B06DD021A29CF5CB5B2506915BEB8A11998B8B886E0F9B7A80E97D91A7D01270F9A7717",
+                output_str: "ab4e5a70390577f8ae260d53cb0e70914f8b9398abaa841f7807f1476046c64f"
+            },
+            Test {
+                input: "6c4b0a0719573e57248661e98febe326571f9a1ca813d3638531ae28b4860f23c3a3a8ac1c250034a660e2d71e16d3acc4bf9ce215c6f15b1c0fc7e77d3d27157e66da9ceec9258f8f2bf9e02b4ac93793dd6e29e307EDE3695A0DF63CBDC0FC66FB770813EB149CA2A916911BEE4902C47C7802E69E405FE3C04CEB5522792A5503FA829F707272226621F7C488A7698C0D69AA561BE9F378",
+                output_str: "8118f2c157df1250db43b31183f442f89b322e496918838c5b668f9647ac6d6b"
+            },
+            Test {
+                input: "51b7dbb7ce2ffeb427a91ccfe5218fd40f9e0b7e24756d4c47cd55606008bdc27d16400933906fd9f30effdd4880022d081155342af3fb6cd53672ab7fb5b3a3bcbe47be1fd3a2278cae8a5fd61c1433f7d350675DD21803746CADCA574130F01200024C6340AB0CC2CF74F2234669F34E9009EF2EB94823D62B31407F4BA46F1A1EEC41641E84D77727B59E746B8A671BEF936F05BE820759FA",
+                output_str: "736e30accc5559188412c797a1a5be61d1f90f149401f631597944155a85faf7"
+            },
+            Test {
+                input: "83599d93f5561e821bd01a472386bc2ff4efbd4aed60d5821e84aae74d8071029810f5e286f8f17651cd27da07b1eb4382f754cd1c95268783ad09220f5502840370d494beb17124220f6afce91ec8a0f55231f9652433E5CE3489B727716CF4AEBA7DCDA20CD29AA9A859201253F948DD94395ABA9E3852BD1D60DDA7AE5DC045B283DA006E1CBAD83CC13292A315DB5553305C628DD091146597",
+                output_str: "9599deeccc698a24a461a7419e91939c741613f4ce887dba89dc7e327c51f5bf"
+            },
+            Test {
+                input: "2be9bf526c9d5a75d565dd11ef63b979d068659c7f026c08bea4af161d85a462d80e45040e91f4165c074c43ac661380311a8cbed59cc8e4c4518e80cd2c78ab1cabf66bff83eab3a80148550307310950d034a6286C93A1ECE8929E6385C5E3BB6EA8A7C0FB6D6332E320E71CC4EB462A2A62E2BFE08F0CCAD93E61BEDB5DD0B786A728AB666F07E0576D189C92BF9FB20DCA49AC2D3956D47385E2",
+                output_str: "be0d871606a4c129cef616f438600d5cbc0e9f49d2adc8a86571c192361c3f4f"
+            },
+            Test {
+                input: "ca76d3a12595a817682617006848675547d3e8f50c2210f9af906c0e7ce50b4460186fe70457a9e879e79fd4d1a688c70a347361c847ba0dd6aa52936eaf8e58a1be2f5c1c704e20146d366aeb3853bed9de9befe9569AC8AAEA37A9FB7139A1A1A7D5C748605A8DEFB297869EBEDD71D615A5DA23496D11E11ABBB126B206FA0A7797EE7DE117986012D0362DCEF775C2FE145ADA6BDA1CCB326BF644",
+                output_str: "4d30600c60ed94a0d2bcc17571a19bd0170cdacac78d0421e0bbae2a36a48b6d"
+            },
+            Test {
+                input: "f76b85dc67421025d64e93096d1d712b7baf7fb001716f02d33b2160c2c882c310ef13a576b1c2d30ef8f78ef8d2f465007109aad93f74cb9e7d7bef7c9590e8af3b267c89c15db238138c45833c98cc4a471a7802723EF4C744A853CF80A0C2568DD4ED58A2C9644806F42104CEE53628E5BDF7B63B0B338E931E31B87C24B146C6D040605567CEEF5960DF9E022CB469D4C787F4CBA3C544A1AC91F95F",
+                output_str: "3bd6fb72764f7ad4391b7b40aea424abd5f5561ac56f9e072c753d6090fa4bfb"
+            },
+            Test {
+                input: "25b8c9c032ea6bcd733ffc8718fbb2a503a4ea8f71dea1176189f694304f0ff68e862a8197b839957549ef243a5279fc2646bd4c009b6d1edebf24738197abb4c992f6b1dc9ba891f570879accd5a6b18691a93c7D0A8D38F95B639C1DAEB48C4C2F15CCF5B9D508F8333C32DE78781B41850F261B855C4BEBCC125A380C54D501C5D3BD07E6B52102116088E53D76583B0161E2A58D0778F091206AABD5A1",
+                output_str: "6689bb25baee0c582f8f1b0c87073be366644da859313becf446435d2f6e899e"
+            },
+            Test {
+                input: "21cfdc2a7ccb7f331b3d2eefff37e48ad9fa9c788c3f3c200e0173d99963e1cbca93623b264e920394ae48bb4c3a5bb96ffbc8f0e53f30e22956adabc2765f57fb761e147ecbf8567533db6e50c8a1f894310a94eDF806DD8CA6A0E141C0FA7C9FAE6C6AE65F18C93A8529E6E5B553BF55F25BE2E80A9882BD37F145FECBEB3D447A3C4E46C21524CC55CDD62F521AB92A8BA72B897996C49BB273198B7B1C9E",
+                output_str: "2628ddc7758208aa9f1e49497224eb268c6d2bcdaab4820de9c16a65c6f6017a"
+            },
+            Test {
+                input: "4e452ba42127dcc956ef4f8f35dd68cb225fb73b5bc7e1ec5a898bba2931563e74faff3b67314f241ec49f4a7061e3bd0213ae826bab380f1f14faab8b0efddd5fd1bb49373853a08f30553d5a55ccbbb8153de4704F29CA2BDEEF0419468E05DD51557CCC80C0A96190BBCC4D77ECFF21C66BDF486459D427F986410F883A80A5BCC32C20F0478BB9A97A126FC5F95451E40F292A4614930D054C851ACD019CCF",
+                output_str: "df448936ee72d9fe6ccfb37d183aafddc7908e016271afa81ec083a10a144f5d"
+            },
+            Test {
+                input: "fa85671df7dadf99a6ffee97a3ab9991671f5629195049880497487867a6c446b60087fac9a0f2fcc8e3b24e97e42345b93b5f7d3691829d3f8ccd4bb36411b85fc2328eb0c51cb3151f70860ad3246ce0623a8dc8B3C49F958F8690F8E3860E71EB2B1479A5CEA0B3F8BEFD87ACAF5362435EAECCB52F38617BC6C5C2C6E269EAD1FBD69E941D4AD2012DA2C5B21BCFBF98E4A77AB2AF1F3FDA3233F046D38F1DC8",
+                output_str: "2bb4cec22a4fecd83fbbbad1e3835343e36c6cb66c26964a432ec4c70f3e17b4"
+            },
+            Test {
+                input: "e90847ae6797fbc0b6b36d6e588c0a743d725788ca50b6d792352ea8294f5ba654a15366b8e1b288d84f5178240827975a763bc45c7b0430e8a559df4488505e009c63da994f1403f407958203cebb6e37d89c94a5EACF6039A327F6C4DBBC7A2A307D976AA39E41AF6537243FC218DFA6AB4DD817B6A397DF5CA69107A9198799ED248641B63B42CB4C29BFDD7975AC96EDFC274AC562D0474C60347A078CE4C25E88",
+                output_str: "1462f2ea1c3580c0a2e8c0b30c27a608d82cd707f6d1a0aad5cc7c3d1b8d6c30"
+            },
+            Test {
+                input: "f6d5c2b6c93954fc627602c00c4ca9a7d3ed12b27173f0b2c9b0e4a5939398a665e67e69d0b12fb7e4ceb253e8083d1ceb724ac07f009f094e42f2d6f2129489e846eaff0700a8d4453ef453a3eddc18f408c77a83275617FABC4EA3A2833AA73406C0E966276079D38E8E38539A70E194CC5513AAA457C699383FD1900B1E72BDFB835D1FD321B37BA80549B078A49EA08152869A918CA57F5B54ED71E4FD3AC5C06729",
+                output_str: "617b412ed64f56d6db36b7e52ead618d95a091d65052c3f376a532d8bbdaf7c7"
+            },
+            Test {
+                input: "cf8562b1bed89892d67ddaaf3deeb28246456e972326dbcdb5cf3fb289aca01e68da5d59896e3a6165358b071b304d6ab3d018944be5049d5e0e2bb819acf67a6006111089e6767132d72dd85beddcbb2d64496db0CC92955AB4C6234F1EEA24F2D51483F2E209E4589BF9519FAC51B4D061E801125E605F8093BB6997BC163D551596FE4AB7CFAE8FB9A90F6980480CE0C229FD1675409BD788354DAF316240CFE0AF93EB",
+                output_str: "82c541ea5cb15d1a4125f536825938c2358eec2bddc5d1cc4042de3af036ca55"
+            },
+            Test {
+                input: "2ace31abb0a2e3267944d2f75e1559985db7354c6e605f18dc8470423fca30b7331d9b33c4a4326783d1caae1b4f07060eff978e4746bf0c7e30cd61040bd5ec2746b29863eb7f103ebda614c4291a805b6a4c8214230564A0557BC7102E0BD3ED23719252F7435D64D210EE2AAFC585BE903FA41E1968C50FD5D5367926DF7A05E3A42CF07E656FF92DE73B036CF8B19898C0CB34557C0C12C2D8B84E91181AF467BC75A9D1",
+                output_str: "684bb7932433218c616f0590b039cefac972828470647d1591ceac889c893272"
+            },
+            Test {
+                input: "0d8d09aed19f1013969ce5e7eb92f83a209ae76be31c754844ea9116ceb39a22ebb6003017bbcf26555fa6624185187db8f0cb3564b8b1c06bf685d47f3286eda20b83358f599d2044bbf0583fab8d78f854fe0a596183230C5EF8E54426750EAF2CC4E29D3BDD037E734D863C2BD9789B4C243096138F7672C232314EFFDFC6513427E2DA76916B5248933BE312EB5DDE4CF70804FB258AC5FB82D58D08177AC6F4756017FFF5",
+                output_str: "508b2af376ba6467cf982c767c848d2bda8d068a53416f074a0c98c473d02f6b"
+            },
+            Test {
+                input: "c3236b73deb7662bf3f3daa58f137b358ba610560ef7455785a9befdb035a066e90704f929bd9689cef0ce3bda5acf4480bceb8d09d10b098ad8500d9b6071dfc3a14af6c77511d81e3aa8844986c3bea6f469f9e02194C92868CD5F51646256798FF0424954C1434BDFED9FACB390B07D342E992936E0F88BFD0E884A0DDB679D0547CCDEC6384285A45429D115AC7D235A717242021D1DC35641F5F0A48E8445DBA58E6CB2C8EA",
+                output_str: "55e228bcbda7061642d004373d4e6407b72a37381d1beffcbfbf9f5f6ea093ea"
+            },
+            Test {
+                input: "b39feb8283eadc63e8184b51df5ae3fd41aac8a963bb0be1cd08aa5867d8d910c669221e73243360646f6553d1ca05a84e8dc0de05b6419ec349ca994480193d01c92525f3fb3dcefb08afc6d26947bdbbfd85193F53B50609C6140905C53A6686B58E53A319A57B962331EDE98149AF3DE3118A819DA4D76706A0424B4E1D2910B0ED26AF61D150EBCB46595D4266A0BD7F651BA47D0C7F179CA28545007D92E8419D48FDFBD744CE",
+                output_str: "0523c09bbcffe418d3fcd22c6abf95abfb38f94ce5562b8bfcd2eea9fb729041"
+            },
+            Test {
+                input: "a983d54f503803e8c7999f4edbbe82e9084f422143a932ddddc47a17b0b7564a7f37a99d0786e99476428d29e29d3c197a72bfab1342c12a0fc4787fd7017d7a6174049ea43b5779169ef7472bdbbd941dcb82fc73AAC45A8A94C9F2BD3477F61FD3B796F02A1B8264A214C6FEA74B7051B226C722099EC7883A462B83B6AFDD4009248B8A237F605FE5A08FE7D8B45321421EBBA67BD70A0B00DDBF94BAAB7F359D5D1EEA105F28DCFB",
+                output_str: "dcbc258241aded3799996c2ad6ed0e3d74cfcc67749d3480b2a9a78e5f8aff82"
+            },
+            Test {
+                input: "e4d1c1897a0a866ce564635b74222f9696bf2c7f640dd78d7e2aca66e1b61c642bb03ea7536aae597811e9bf4a7b453ede31f97b46a5f0ef51a071a2b3918df16b152519ae3776f9f1edab4c2a377c3292e96408359D3613844D5EB393000283D5AD3401A318B12FD1474B8612F2BB50FB6A8B9E023A54D7DDE28C43D6D8854C8D9D1155935C199811DBFC87E9E0072E90EB88681CC7529714F8FB8A2C9D88567ADFB974EE205A9BF7B848",
+                output_str: "cbe8318e7b2fe72bfcd2530cccecea4018b1587f483b73f50ce5e84ced65e093"
+            },
+            Test {
+                input: "b10c59723e3dcadd6d75df87d0a1580e73133a9b7d00cb95ec19f5547027323be75158b11f80b6e142c6a78531886d9047b08e551e75e6261e79785366d7024bd7cd9cf322d9be7d57fb661069f2481c7bb759cd71B4B36CA2BC2DF6D3A328FAEBDB995A9794A8D72155ED551A1F87C80BF6059B43FC764900B18A1C2441F7487743CF84E565F61F8DD2ECE6B6CCC9444049197AAAF53E926FBEE3BFCA8BE588EC77F29D211BE89DE18B15F6",
+                output_str: "8cea2960087048e6e6d47e31554f305fcc81e03e90ba8f8332dd86c6b6b38e03"
+            },
+            Test {
+                input: "db11f609baba7b0ca634926b1dd539c8cbada24967d7add4d9876f77c2d80c0f4dcefbd7121548373582705cca2495bd2a43716fe64ed26d059cfb566b3364bd49ee0717bdd9810dd14d8fad80dbbdc4cafb37cc60FB0FE2A80FB4541B8CA9D59DCE457738A9D3D8F641AF8C3FD6DA162DC16FC01AAC527A4A0255B4D231C0BE50F44F0DB0B713AF03D968FE7F0F61ED0824C55C4B5265548FEBD6AAD5C5EEDF63EFE793489C39B8FD29D104CE",
+                output_str: "44e276991e5382bd7eb5adcf1f79362804d346bedfc6916f4dca4b57240e9c99"
+            },
+            Test {
+                input: "bebd4f1a84fc8b15e4452a54bd02d69e304b7f32616aadd90537937106ae4e28de9d8aab02d19bc3e2fde1d651559e296453e4dba94370a14dbbb2d1d4e2022302ee90e208321efcd8528ad89e46dc839ea9df618EA8394A6BFF308E7726BAE0C19BCD4BE52DA6258E2EF4E96AA21244429F49EF5CB486D7FF35CAC1BACB7E95711944BCCB2AB34700D42D1EB38B5D536B947348A458EDE3DC6BD6EC547B1B0CAE5B257BE36A7124E1060C170FFA",
+                output_str: "80891a086af385025068799f192411c689cc4e0d9a59f3f41dbb02a343f1a759"
+            },
+            Test {
+                input: "5aca56a03a13784bdc3289d9364f79e2a85c12276b49b92db0adaa4f206d5028f213f678c3510e111f9dc4c1c1f8b6acb17a6413aa227607c515c62a733817ba5e762cc6748e7e0d6872c984d723c9bb3b117eb8963185300A80BFA65CDE495D70A46C44858605FCCBED086C2B45CEF963D33294DBE9706B13AF22F1B7C4CD5A001CFEC251FBA18E722C6E1C4B1166918B4F6F48A98B64B3C07FC86A6B17A6D0480AB79D4E6415B520F1C484D675B1",
+                output_str: "77ddf034b7dfd6b292aa3b0c1e552f47b1d8c23078042cc58bb3dd4720b9ee4d"
+            },
+            Test {
+                input: "a5aad0e4646a32c85cfcac73f02fc5300f1982fabb2f2179e28303e447854094cdfc854310e5c0f60993ceff54d84d6b46323d930adb07c17599b35b505f09e784bca5985e0172257797fb53649e2e9723efd16865C31B5C3D5113B58BB0BFC8920FABDDA086D7537E66D709D050BD14D0C960873F156FAD5B3D3840CDFCDC9BE6AF519DB262A27F40896AB25CC39F96984D650611C0D5A3080D5B3A1BF186ABD42956588B3B58CD948970D298776060",
+                output_str: "23d2688d867a18040e82f7876acf04dc3a9c0140fedd93ebe7adf920b2f83da4"
+            },
+            Test {
+                input: "06cbbe67e94a978203ead6c057a1a5b098478b4b4cbef5a97e93c8e42f5572713575fc2a884531d7622f8f879387a859a80f10ef02708cd8f7413ab385afc357678b9578c0ebf641ef076a1a30f1f75379e9dcb2a885BDD295905EE80C0168A62A9597D10CF12DD2D8CEE46645C7E5A141F6E0E23AA482ABE5661C16E69EF1E28371E2E236C359BA4E92C25626A7B7FF13F6EA4AE906E1CFE163E91719B1F750A96CBDE5FBC953D9E576CD216AFC90323A",
+                output_str: "2df666fc5d4ead1c3b10b9f8d4bb81aea4f93d3873d5ce5cfbac4b69435e1b7c"
+            },
+            Test {
+                input: "f1c528cf7739874707d4d8ad5b98f7c77169de0b57188df233b2dc8a5b31eda5db4291dd9f68e6bad37b8d7f6c9c0044b3bf74bbc3d7d1798e138709b0d75e7c593d3cccdc1b20c7174b4e692add820ace262d45cCFAE2077E878796347168060A162ECCA8C38C1A88350BD63BB539134F700FD4ADDD5959E255337DAA06BC86358FABCBEFDFB5BC889783D843C08AADC6C4F6C36F65F156E851C9A0F917E4A367B5AD93D874812A1DE6A7B93CD53AD97232",
+                output_str: "af0c5474528032e2629b8fbb0e34405f7f251d41e73b5667be3c07ccb2c1c953"
+            },
+            Test {
+                input: "9d9f3a7ecd51b41f6572fd0d0881e30390dfb780991dae7db3b47619134718e6f987810e542619dfaa7b505c76b7350c6432d8bf1cfebdf1069b90a35f0d04cbdf130b0dfc7875f4a4e62cdb8e525aadd7ce842520A482AC18F09442D78305FE85A74E39E760A4837482ED2F437DD13B2EC1042AFCF9DECDC3E877E50FF4106AD10A525230D11920324A81094DA31DEAB6476AA42F20C84843CFC1C58545EE80352BDD3740DD6A16792AE2D86F11641BB717C2",
+                output_str: "9bbef7a75391354a388aaa7ca035dc62d3231b80091bb7748f76e52d8e9f20f0"
+            },
+            Test {
+                input: "5179888724819fbad3afa927d3577796660e6a81c52d98e9303261d5a4a83232f6f758934d50aa83ff9e20a5926dfebaac49529d006eb923c5ae5048ed544ec471ed7191edf46363383824f915769b3e688094c682B02151E5EE01E510B431C8865AFF8B6B6F2F59CB6D129DA79E97C6D2B8FA6C6DA3F603199D2D1BCAB547682A81CD6CF65F6551121391D78BCC23B5BD0E922EC6D8BF97C952E84DD28AEF909ABA31EDB903B28FBFC33B7703CD996215A11238",
+                output_str: "b108457a6bd331be43c9fe1e2a02e8c744c2bcc927a9c3c486f110dccf907f6b"
+            },
+            Test {
+                input: "576ef3520d30b7a4899b8c0d5e359e45c5189add100e43be429a02fb3de5ff4f8fd0e79d9663acca72cd29c94582b19292a557c5b1315297d168fbb54e9e2ecd13809c2b5fce998edc6570545e1499dbe7fb74d47CD7F35823B212B05BF3F5A79CAA34224FDD670D335FCB106F5D92C3946F44D3AFCBAE2E41AC554D8E6759F332B76BE89A0324AA12C5482D1EA3EE89DED4936F3E3C080436F539FA137E74C6D3389BDF5A45074C47BC7B20B0948407A66D855E2F",
+                output_str: "a61109838dfa5b146df4e6c3bdbc7a477be36b6228ebd91025012af4cc0eb409"
+            },
+            Test {
+                input: "0df2152fa4f4357c8741529dd77e783925d3d76e95bafa2b542a2c33f3d1d117d159cf473f82310356fee4c90a9e505e70f8f24859656368ba09381fa245eb6c3d763f3093f0c89b972e66b53d59406d9f01aea07F8B3B615CAC4EE4D05F542E7D0DAB45D67CCCCD3A606CCBEB31EA1FA7005BA07176E60DAB7D78F6810EF086F42F08E595F0EC217372B98970CC6321576D92CE38F7C397A403BADA1548D205C343AC09DECA86325373C3B76D9F32028FEA8EB32515",
+                output_str: "4f0f30c890b0ab404961158573538fe9a2b234b94a0991f26d5ea04fddc9c565"
+            },
+            Test {
+                input: "3e15350d87d6ebb5c8ad99d42515cfe17980933c7a8f6b8bbbf0a63728cefaad2052623c0bd5931839112a48633fb3c2004e0749c87a41b26a8b48945539d1ff41a4b269462fd199bfecd45374756f55a9116e92093AC99451AEFB2AF9FD32D6D7F5FBC7F7A540D5097C096EBC3B3A721541DE073A1CC02F7FB0FB1B9327FB0B1218CA49C9487AB5396622A13AE546C97ABDEF6B56380DDA7012A8384091B6656D0AB272D363CEA78163FF765CDD13AB1738B940D16CAE",
+                output_str: "85459cfb0289599cdd67c473a0ba6da616c608e367f58c50a03562424dcf1d06"
+            },
+            Test {
+                input: "c38d6b0b757cb552be40940ece0009ef3b0b59307c1451686f1a22702922800d58bce7a636c1727ee547c01b214779e898fc0e560f8ae7f61bef4d75eaa696b921fd6b735d171535e9edd267c192b99880c87997711002009095D8A7A437E258104A41A505E5EF71E5613DDD2008195F0C574E6BA3FE40099CFA116E5F1A2FA8A6DA04BADCB4E2D5D0DE31FDC4800891C45781A0AAC7C907B56D631FCA5CE8B2CDE620D11D1777ED9FA603541DE794DDC5758FCD5FAD78C0",
+                output_str: "5539d2e52a5a1bb3c246b0158356e2b2782fc13c10248937a0c4a40b091f6247"
+            },
+            Test {
+                input: "8d2de3f0b37a6385c90739805b170057f091cd0c7a0bc951540f26a5a75b3e694631bb64c7635eed316f51318e9d8de13c70a2aba04a14836855f35e480528b776d0a1e8a23b547c8b8d6a0d09b241d3be9377160CCA4E6793D00A515DC2992CB7FC741DACA171431DA99CCE6F7789F129E2AC5CF65B40D703035CD2185BB936C82002DAF8CBC27A7A9E554B06196630446A6F0A14BA155ED26D95BD627B7205C072D02B60DB0FD7E49EA058C2E0BA202DAFF0DE91E845CF79",
+                output_str: "6d63419207b99d4db1add795d852a8daac11b789af0c7d6353036cb23f6428b4"
+            },
+            Test {
+                input: "c464bbdad275c50dcd983b65ad1019b9ff85a1e71c807f3204bb2c921dc31fbcd8c5fc45868ae9ef85b6c9b83bba2a5a822201ed68586ec5ec27fb2857a5d1a2d09d09115f22dcc39fe61f5e1ba0ff6e8b4acb4c6DA748BE7F3F0839739394FF7FA8E39F7F7E84A33C3866875C01BCB1263C9405D91908E9E0B50E7459FABB63D8C6BBB73D8E3483C099B55BC30FF092FF68B6ADEDFD477D63570C9F5515847F36E24BA0B705557130CEC57EBAD1D0B31A378E91894EE26E3A04",
+                output_str: "d2090dae0fc201b2b9c03dd482a8eb1ffd3cf70c55f98d6f39a41b8bdac27a17"
+            },
+            Test {
+                input: "8b8d68bb8a75732fe272815a68a1c9c5aa31b41dedc8493e76525d1d013d33cebd9e21a5bb95db2616976a8c07fcf411f5f6bc6f7e0b57aca78cc2790a6f9b898858ac9c79b165ff24e66677531e39f572be5d81eB3264524181115F32780257BFB9AEEC6AF12AF28E587CAC068A1A2953B59AD680F4C245B2E3EC36F59940D37E1D3DB38E13EDB29B5C0F404F6FF87F80FC8BE7A225FF22FBB9C8B6B1D7330C57840D24BC75B06B80D30DAD6806544D510AF6C4785E823AC3E0B8",
+                output_str: "c9e8f96ba75eaf371dca35dc69138eca8cb3f2823f3be551d9dc8aa6a4ed4169"
+            },
+            Test {
+                input: "6b018710446f368e7421f1bc0ccf562d9c1843846bc8d98d1c9bf7d9d6fcb48bfc3bf83b36d44c4fa93430af75cd190bde36a7f92f867f58a803900df8018150384d85d82132f123006ac2aeba58e02a037fe6afbD65ECA7C44977DD3DC74F48B6E7A1BFD5CC4DCF24E4D52E92BD4455848E4928B0EAC8B7476FE3CC03E862AA4DFF4470DBFED6DE48E410F25096487ECFC32A27277F3F5023B2725ADE461B1355889554A8836C9CF53BD767F5737D55184EEA1AB3F53EDD0976C485",
+                output_str: "233b0bc28143c32a668b0ab5d76be5712c0387056fb0e79f2c2f7f1c31e4a86a"
+            },
+            Test {
+                input: "c9534a24714bd4be37c88a3da1082eda7cabd154c309d7bd670dccd95aa535594463058a29f79031d6ecaa9f675d1211e9359be82669a79c855ea8d89dd38c2c761ddd0ec0ce9e97597432e9a1beae062cdd71edfDFD464119BE9E69D18A7A7FD7CE0E2106F0C8B0ABF4715E2CA48EF9F454DC203C96656653B727083513F8EFB86E49C513BB758B3B052FE21F1C05BB33C37129D6CC81F1AEF6ADC45B0E8827A830FE545CF57D0955802C117D23CCB55EA28F95C0D8C2F9C5A242B33F",
+                output_str: "b79b5f8182d3fb4abab63e7cb26a8e0865ae8d79bd4c514ad8917d5ecb7fed8f"
+            },
+            Test {
+                input: "07906c87297b867abf4576e9f3cc7f82f22b154afcbf293b9319f1b0584da6a40c27b32e0b1b7f412c4f1b82480e70a9235b12ec27090a5a33175a2bb28d8adc475cefe33f7803f8ce27967217381f02e67a3b4f84A71F1C5228E0C2AD971373F6F672624FCEA8D1A9F85170FAD30FA0BBD25035C3B41A6175D467998BD1215F6F3866F53847F9CF68EF3E2FBB54BC994DE2302B829C5EEA68EC441FCBAFD7D16AE4FE9FFF98BF00E5BC2AD54DD91FF9FDA4DD77B6C754A91955D1FBAAD0",
+                output_str: "f680198de2943d20e9d809fd8312d674c9a250da22ba6e920e408f6f2c0e0739"
+            },
+            Test {
+                input: "588e94b9054abc2189df69b8ba34341b77cdd528e7860e5defcaa79b0c9a452ad4b82aa306be84536eb7cedcbe058d7b84a6aef826b028b8a0271b69ac3605a9635ea9f5ea0aa700f3eb7835bc54611b922964300C953EFE7491E3677C2CEBE0822E956CD16433B02C68C4A23252C3F9E151A416B4963257B783E038F6B4D5C9F110F871652C7A649A7BCEDCBCCC6F2D0725BB903CC196BA76C76AA9F10A190B1D1168993BAA9FFC96A1655216773458BEC72B0E39C9F2C121378FEAB4E76A",
+                output_str: "a190dd73556086ea70bc31022d6a4f95d89dc099e2030c19311cc8988281278f"
+            },
+            Test {
+                input: "08959a7e4baae874928813364071194e2939772f20db7c3157078987c557c2a6d5abe68d520eef3dc491692e1e21bcd880adebf63bb4213b50897fa005256ed41b5690f78f52855c8d9168a4b666fce2da2b456d7A7E7C17AB5F2FB1EE90B79E698712E963715983FD07641AE4B4E9DC73203FAC1AE11FA1F8C7941FCC82EAB247ADDB56E2638447E9D609E610B60CE086656AAEBF1DA3C8A231D7D94E2FD0AFE46B391FF14A72EAEB3F44AD4DF85866DEF43D4781A0B3578BC996C87970B132",
+                output_str: "21166064c52b588c1ec7ea6df1905a2b59bad499b470f308a26b6e354ddfe58f"
+            },
+            Test {
+                input: "cb2a234f45e2ecd5863895a451d389a369aab99cfef0d5c9ffca1e6e63f763b5c14fb9b478313c8e8c0efeb3ac9500cf5fd93791b789e67eac12fd038e2547cc8e0fc9db591f33a1e4907c64a922dda23ec9827310B306098554A4A78F050262DB5B545B159E1FF1DCA6EB734B872343B842C57EAFCFDA8405EEDBB48EF32E99696D135979235C3A05364E371C2D76F1902F1D83146DF9495C0A6C57D7BF9EE77E80F9787AEE27BE1FE126CDC9EF893A4A7DCBBC367E40FE4E1EE90B42EA25AF01",
+                output_str: "051e19906464ec7fdc3d37ee3bcef63438ec5edbea5aa202a24b7f7190b689e0"
+            },
+            Test {
+                input: "d16beadf02ab1d4dc6f88b8c4554c51e866df830b89c06e786a5f8757e8909310af51c840efe8d20b35331f4355d80f73295974653ddd620cdde4730fb6c8d0d2dcb2b45d92d4fbdb567c0a3e86bd1a8a795af26fBF29FC6C65941CDDB090FF7CD230AC5268AB4606FCCBA9EDED0A2B5D014EE0C34F0B2881AC036E24E151BE89EEB6CD9A7A790AFCCFF234D7CB11B99EBF58CD0C589F20BDAC4F9F0E28F75E3E04E5B3DEBCE607A496D848D67FA7B49132C71B878FD5557E082A18ECA1FBDA94D4B",
+                output_str: "18fe66c0cd095c9cc811f5410b5cfdc1b152ae3cab0c3328974e7d4bbeb40053"
+            },
+            Test {
+                input: "8f65f6bc59a85705016e2bae7fe57980de3127e5ab275f573d334f73f8603106ec3553016608ef2dd6e69b24be0b7113bf6a760ba6e9ce1c48f9e186012cf96a1d4849d75df5bb8315387fd78e9e153e76f8ba7ec6C8849810F59FB4BB9B004318210B37F1299526866F44059E017E22E96CBE418699D014C6EA01C9F0038B10299884DBEC3199BB05ADC94E955A1533219C1115FED0E5F21228B071F40DD57C4240D98D37B73E412FE0FA4703120D7C0C67972ED233E5DEB300A22605472FA3A3BA86",
+                output_str: "bdb42638921199d604294b5578cebaccdf132e1d7af7675b7768e50553fcb604"
+            },
+            Test {
+                input: "84891e52e0d451813210c3fd635b39a03a6b7a7317b221a7abc270dfa946c42669aacbbbdf801e1584f330e28c729847ea14152bd637b3d0f2b38b4bd5bf9c791c58806281103a3eabbaede5e711e539e6a8b2cf297CF351C078B4FA8F7F35CF61BEBF8814BF248A01D41E86C5715EA40C63F7375379A7EB1D78F27622FB468AB784AAABA4E534A6DFD1DF6FA15511341E725ED2E87F98737CCB7B6A6DFAE416477472B046BF1811187D151BFA9F7B2BF9ACDB23A3BE507CDF14CFDF517D2CB5FB9E4AB6",
+                output_str: "cbd88209b530018a856c5c2321d7e485511ca1513661f1fde1fa06f4603de117"
+            },
+            Test {
+                input: "fdd7a9433a3b4afabd7a3a5e3457e56debf78e84b7a0b0ca0e8c6d53bd0c2dae31b2700c6128334f43981be3b213b1d7a118d59c7e6b6493a86f866a1635c12859cfb9ad17460a77b4522a5c1883c3d6acc86e6162667EC414E9A104AA892053A2B1D72165A855BACD8FAF8034A5DD9B716F47A0818C09BB6BAF22AA503C06B4CA261F557761989D2AFBD88B6A678AD128AF68672107D0F1FC73C5CA740459297B3292B281E93BCEB761BDE7221C3A55708E5EC84472CDDCAA84ECF23723CC0991355C6280",
+                output_str: "f0c4c1374f33a91dc657f8a3fa51763cbd0fba1cafdd2c595ed302aab1ab75a9"
+            },
+            Test {
+                input: "70a40bfbef92277a1aad72f6b79d0177197c4ebd432668cfec05d099accb651062b5dff156c0b27336687a94b26679cfdd9daf7ad204338dd9c4d14114033a5c225bd11f217b5f4732da167ee3f939262d4043fc9CBA92303B7B5E96AEA12ADDA64859DF4B86E9EE0B58E39091E6B188B408AC94E1294A8911245EE361E60E601EFF58D1D37639F3753BEC80EBB4EFDE25817436076623FC65415FE51D1B0280366D12C554D86743F3C3B6572E400361A60726131441BA493A83FBE9AFDA90F7AF1AE717238D",
+                output_str: "f2157c165eebdfd04451e9e6cf0b112bb148eb9c40e8b2427ee8ea57e60d5dd6"
+            },
+            Test {
+                input: "74356e449f4bf8644f77b14f4d67cb6bd9c1f5ae357621d5b8147e562b65c66585caf2e491b48529a01a34d226d436959153815380d5689e30b35357cdac6e08d3f2b0e88e200600d62bd9f5eaf488df86a4470ea227006182E44809009868C4C280C43D7D64A5268FA719074960087B3A6ABC837882F882C837834535929389A12B2C78187E2EA07EF8B8EEF27DC85002C3AE35F1A50BEE6A1C48BA7E175F3316670B27983472AA6A61EED0A683A39EE323080620EA44A9F74411AE5CE99030528F9AB49C79F2",
+                output_str: "0836abbf77ef78e162de8fb664b9996d5a03919b741eb4a3f02e7b97826569fa"
+            },
+            Test {
+                input: "8c3798e51bc68482d7337d3abb75dc9ffe860714a9ad73551e120059860dde24ab87327222b64cf774415a70f724cdf270de3fe47dda07b61c9ef2a3551f45a5584860248fabde676e1cd75f6355aa3eaeabe3b51DC813D9FB2EAA4F0F1D9F834D7CAD9C7C695AE84B329385BC0BEF895B9F1EDF44A03D4B410CC23A79A6B62E4F346A5E8DD851C2857995DDBF5B2D717AEB847310E1F6A46AC3D26A7F9B44985AF656D2B7C9406E8A9E8F47DCB4EF6B83CAACF9AEFB6118BFCFF7E44BEF6937EBDDC89186839B77",
+                output_str: "84970c79316e89b70e2b186a69db1a4c3e33c7a376b45c1b79bd346dd33ef4ce"
+            },
+            Test {
+                input: "fa56bf730c4f8395875189c10c4fb251605757a8fecc31f9737e3c2503b02608e6731e85d7a38393c67de516b85304824bfb135e33bf22b3a23b913bf6acd2b7ab85198b8187b2bcd454d5e3318cacb32fd6261c31AE7F6C54EF6A7A2A4C9F3ECB81CE3555D4F0AD466DD4C108A90399D70041997C3B25345A9653F3C9A6711AB1B91D6A9D2216442DA2C973CBD685EE7643BFD77327A2F7AE9CB283620A08716DFB462E5C1D65432CA9D56A90E811443CD1ECB8F0DE179C9CB48BA4F6FEC360C66F252F6E64EDC96B",
+                output_str: "06ed2ebc419d053949e88cc9c040b1ebce74375ad0ce09c0cd4d562c62f8497d"
+            },
+            Test {
+                input: "b6134f9c3e91dd8000740d009dd806240811d51ab1546a974bcb18d344642baa5cd5903af84d58ec5ba17301d5ec0f10ccd0509cbb3fd3fff9172d193af0f782252fd1338c7244d40e0e42362275b22d01c4c3389F19DD69BDF958EBE28E31A4FFE2B5F18A87831CFB7095F58A87C9FA21DB72BA269379B2DC2384B3DA953C7925761FED324620ACEA435E52B424A7723F6A2357374157A34CD8252351C25A1B232826CEFE1BD3E70FFC15A31E7C0598219D7F00436294D11891B82497BC78AA5363892A2495DF8C1EEF",
+                output_str: "cf9060af3e4ed47316acf51e5b92123cdc4827bd4aef991588dcd8078b9eea40"
+            },
+            Test {
+                input: "c941cdb9c28ab0a791f2e5c8e8bb52850626aa89205bec3a7e22682313d198b1fa33fc7295381354858758ae6c8ec6fac3245c6e454d16fa2f51c4166fab51df272858f2d603770c40987f64442d487af49cd5c3991CE858EA2A60DAB6A65A34414965933973AC2457089E359160B7CDEDC42F29E10A91921785F6B7224EE0B349393CDCFF6151B50B377D609559923D0984CDA6000829B916AB6896693EF6A2199B3C22F7DC5500A15B8258420E314C222BC000BC4E5413E6DD82C993F8330F5C6D1BE4BC79F08A1A0A46",
+                output_str: "63e407300f99ff2360f02aae0ada35f6c1a90aed2c63282b23a7990bae307254"
+            },
+            Test {
+                input: "4499efffac4bcea52747efd1e4f20b73e48758be915c88a1ffe5299b0b005837a46b2f20a9cb3c6e64a9e3c564a27c0f1c6ad1960373036ec5bfe1a8fc6a435c2185ed0f114c50e8b3e4c7ed96b06a036819c9463E864A58D6286F785E32A804443A56AF0B4DF6ABC57ED5C2B185DDEE8489EA080DEEEE66AA33C2E6DAB36251C402682B6824821F998C32163164298E1FAFD31BABBCFFB594C91888C6219079D907FDB438ED89529D6D96212FD55ABE20399DBEFD342248507436931CDEAD496EB6E4A80358ACC78647D043",
+                output_str: "427741570d5e21590e5045a8450216365ba95c2e72455a3dbd694f13155de1b7"
+            },
+            Test {
+                input: "eecbb8fdfa4da62170fd06727f697d81f83f601ff61e478105d3cb7502f2c89bf3e8f56edd469d049807a38882a7eefbc85fc9a950952e9fa84b8afebd3ce782d4da598002827b1eb98882ea1f0a8f7aa9ce013a6E9BC462FB66C8D4A18DA21401E1B93356EB12F3725B6DB1684F2300A98B9A119E5D27FF704AFFB618E12708E77E6E5F34139A5A41131FD1D6336C272A8FC37080F041C71341BEE6AB550CB4A20A6DDB6A8E0299F2B14BC730C54B8B1C1C487B494BDCCFD3A53535AB2F231590BF2C4062FD2AD58F906A2D0D",
+                output_str: "b5e60a019e8414d470ae702738bc358f1c80bb6ff7bde4f2dbb56c299c764b16"
+            },
+            Test {
+                input: "e64f3e4ace5c8418d65fec2bc5d2a303dd458034736e3b0df719098be7a206deaf52d6ba82316caf330ef852375188cde2b39cc94aa449578a7e2a8e3f5a9d68e816b8d16889fbc0ebf0939d04f63033ae9ae2bdaB73B88C26D6BD25EE460EE1EF58FB0AFA92CC539F8C76D3D097E7A6A63EBB9B5887EDF3CF076028C5BBD5B9DB3211371AD3FE121D4E9BF44229F4E1ECF5A0F9F0EBA4D5CEB72878AB22C3F0EB5A625323AC66F7061F4A81FAC834471E0C59553F108475FE290D43E6A055AE3EE46FB67422F814A68C4BE3E8C9",
+                output_str: "c986bdae9b13fbc92793619e4970abc33398f2b5a57a6cbb40a622592e2695df"
+            },
+            Test {
+                input: "d2cb2d733033f9e91395312808383cc4f0ca974e87ec68400d52e96b3fa6984ac58d9ad0938dde5a973008d818c49607d9de2284e7618f1b8aed8372fbd52ed54557af4220fac09dfa8443011699b97d743f8f2b1AEF3537EBB45DCC9E13DFB438428EE190A4EFDB3CAEB7F3933117BF63ABDC7E57BEB4171C7E1AD260AB0587806C4D137B6316B50ABC9CCE0DFF3ACADA47BBB86BE777E617BBE578FF4519844DB360E0A96C6701290E76BB95D26F0F804C8A4F2717EAC4E7DE9F2CFF3BBC55A17E776C0D02856032A6CD10AD2838",
+                output_str: "224c7fc8a0ec3895e8969ce7c7f7ecaa54fe2eec9ab3120726106f22aa297541"
+            },
+            Test {
+                input: "f2998955613dd414cc111df5ce30a995bb792e260b0e37a5b1d942fe90171a4ac2f66d4928d7ad377f4d0554cbf4c523d21f6e5f379d6f4b028cdcb9b1758d3b39663242ff3cb6ede6a36a6f05db3bc41e0d861b384B6DEC58BB096D0A422FD542DF175E1BE1571FB52AE66F2D86A2F6824A8CFAACBAC4A7492AD0433EEB15454AF8F312B3B2A577750E3EFBD370E8A8CAC1582581971FBA3BA4BD0D76E718DACF8433D33A59D287F8CC92234E7A271041B526E389EFB0E40B6A18B3AAF658E82ED1C78631FD23B4C3EB27C3FAEC8685",
+                output_str: "faf5e3b7a64629ffeee07a67ed77a3a4f67f18c9381fe9b19f6ee601f5fb99af"
+            },
+            Test {
+                input: "447797e2899b72a356ba55bf4df3acca6cdb1041eb477bd1834a9f9acbc340a294d729f2f97df3a610be0ff15edb9c6d5db41644b9874360140fc64f52aa03f0286c8a640670067a84e017926a70438db1bb361deFEE7317021425F8821DEF26D1EFD77FC853B818545D055ADC9284796E583C76E6FE74C9AC2587AA46AA8F8804F2FEB5836CC4B3ABABAB8429A5783E17D5999F32242EB59EF30CD7ADABC16D72DBDB097623047C98989F88D14EAF02A7212BE16EC2D07981AAA99949DDF89ECD90333A77BC4E1988A82ABF7C7CAF3291",
+                output_str: "a8a98e6b3a005fcb319fee58c5457d04b69d59f53873f6fcc6065d68f880833f"
+            },
+            Test {
+                input: "9f2c18ade9b380c784e170fb763e9aa205f64303067eb1bcea93df5dac4bf5a2e00b78195f808df24fc76e26cb7be31dc35f0844cded1567bba29858cffc97fb29010331b01d6a3fb3159cc1b973d255da9843e34A0A4061CABDB9ED37F241BFABB3C20D32743F4026B59A4CCC385A2301F83C0B0A190B0F2D01ACB8F0D41111E10F2F4E149379275599A52DC089B35FDD5234B0CFB7B6D8AEBD563CA1FA653C5C021DFD6F5920E6F18BFAFDBECBF0AB00281333ED50B9A999549C1C8F8C63D7626C48322E9791D5FF72294049BDE91E73F8",
+                output_str: "c89f2b346127eab9e28095dc44918c1a1aaeae04861c1dd0144a1ee07f823c18"
+            },
+            Test {
+                input: "ae159f3fa33619002ae6bcce8cbbdd7d28e5ed9d61534595c4c9f43c402a9bb31f3b301cbfd4a43ce4c24cd5c9849cc6259eca90e2a79e01ffbac07ba0e147fa42676a1d668570e0396387b5bcd599e8e66aaed1b8A191C5A47547F61373021FA6DEADCB55363D233C24440F2C73DBB519F7C9FA5A8962EFD5F6252C0407F190DFEFAD707F3C7007D69FF36B8489A5B6B7C557E79DD4F50C06511F599F56C896B35C917B63BA35C6FF8092BAF7D1658E77FC95D8A6A43EEB4C01F33F03877F92774BE89C1114DD531C011E53A34DC248A2F0E6",
+                output_str: "e7a81acbef35d7b24b706549b41abd82628ccff9acf41f2c8add28743688ae01"
+            },
+            Test {
+                input: "3b8e97c5ffc2d6a40fa7de7fcefc90f3b12c940e7ab415321e29ee692dfac799b009c99dcddb708fce5a178c5c35ee2b8617143edc4c40b4d313661f49abdd93cea79d117518805496fe6acf292c4c2a1f76b403a97D7C399DAF85B46AD84E16246C67D6836757BDE336C290D5D401E6C1386AB32797AF6BB251E9B2D8FE754C47482B72E0B394EAB76916126FD68EA7D65EB93D59F5B4C5AC40F7C3B37E7F3694F29424C24AF8C8F0EF59CD9DBF1D28E0E10F799A6F78CAD1D45B9DB3D7DEE4A7059ABE99182714983B9C9D44D7F5643596D4F3",
+                output_str: "d81249143a69ea1c9dc168b55ffe06d46d0fbc007065110353d76c6cce4ffe66"
+            },
+            Test {
+                input: "3434ec31b10fafdbfeec0dd6bd94e80f7ba9dca19ef075f7eb017512af66d6a4bcf7d16ba0819a1892a6372f9b35bcc7ca8155ee19e8428bc22d214856ed5fa9374c3c09bde169602cc219679f65a1566fc7316f4CC3B631A18FB4449FA6AFA16A3DB2BC4212EFF539C67CF184680826535589C7111D73BFFCE431B4C40492E763D9279560AAA38EB2DC14A212D723F994A1FE656FF4DD14551CE4E7C621B2AA5604A10001B2878A897A28A08095C325E10A26D2FB1A75BFD64C250309BB55A44F23BBAC0D5516A1C687D3B41EF2FBBF9CC56D4739",
+                output_str: "aa8bbd4812142211212763bf8ee4d6e0aadafe5e528aea1fb1be118806e49f66"
+            },
+            Test {
+                input: "7c7953d81c8d208fd1c97681d48f49dd003456de60475b84070ef4847c333b74575b1fc8d2a186964485a3b8634feaa3595aaa1a2f4595a7d6b6153563dee31bbac443c8a33eed6d5d956a980a68366c2527b550eE950250DFB691EACBD5D56AE14B970668BE174C89DF2FEA43AE52F13142639C884FD62A3683C0C3792F0F24AB1318BCB27E21F4737FAB62C77EA38BC8FD1CF41F7DAB64C13FEBE7152BF5BB7AB5A78F5346D43CC741CB6F72B7B8980F268B68BF62ABDFB1577A52438FE14B591498CC95F071228460C7C5D5CEB4A7BDE588E7F21C",
+                output_str: "4089b181df5eca5f14dab1057aaaeecaba15f200fdda0de49357d6196faab44b"
+            },
+            Test {
+                input: "7a6a4f4fdc59a1d223381ae5af498d74b7252ecf59e389e49130c7eaee626e7bd9897effd92017f4ccde66b0440462cdedfd352d8153e6a4c8d7a0812f701cc737b5178c2556f07111200eb627dbc299caa792dfa58F35935299FA3A3519E9B03166DFFA159103FFA35E8577F7C0A86C6B46FE13DB8E2CDD9DCFBA85BDDDCCE0A7A8E155F81F712D8E9FE646153D3D22C811BD39F830433B2213DD46301941B59293FD0A33E2B63ADBD95239BC01315C46FDB678875B3C81E053A40F581CFBEC24A1404B1671A1B88A6D06120229518FB13A74CA0AC5AE",
+                output_str: "debf59bb233d05549853804fc67840821bd5802f87fc8a915b710d3e82070950"
+            },
+            Test {
+                input: "d9faa14cebe9b7de551b6c0765409a33938562013b5e8e0e1e0a6418df7399d0a6a771fb81c3ca9bd3bb8e2951b0bc792525a294ebd1083688806fe5e7f1e17fd4e3a41d00c89e8fcf4a363caedb1acb558e3d562F1302B3D83BB886ED27B76033798131DAB05B4217381EAAA7BA15EC820BB5C13B516DD640EAEC5A27D05FDFCA0F35B3A5312146806B4C0275BCD0AAA3B2017F346975DB566F9B4D137F4EE10644C2A2DA66DEECA5342E236495C3C6280528BFD32E90AF4CD9BB908F34012B52B4BC56D48CC8A6B59BAB014988EABD12E1A0A1C2E170E7",
+                output_str: "0fdba1c79f55f233a1217f522d6c81f777f330fadb565e1171f39e1788913342"
+            },
+            Test {
+                input: "2d8427433d0c61f2d96cfe80cf1e932265a191365c3b61aaa3d6dcc039f6ba2ad52a6a8cc30fc10f705e6b7705105977fa496c1c708a277a124304f1fc40911e7441d1b5e77b951aad7b01fd5db1b377d165b05bbF898042E39660CAF8B279FE5229D1A8DB86C0999ED65E53D01CCBC4B43173CCF992B3A14586F6BA42F5FE30AFA8AE40C5DF29966F9346DA5F8B35F16A1DE3AB6DE0F477D8D8660918060E88B9B9E9CA6A4207033B87A812DBF5544D39E4882010F82B6CE005F8E8FF6FE3C3806BC2B73C2B83AFB704345629304F9F86358712E9FAE3CA3E",
+                output_str: "ed45a06e95a6539270b02290d71005f01c55ba077414c3bcdb379537e6dbefc9"
+            },
+            Test {
+                input: "5e19d97887fcaac0387e22c6f803c34a3dacd2604172433f7a8a7a526ca4a2a1271ecfc5d5d7be5ac0d85d921095350dfc65997d443c21c8094e0a3fefd2961bcb94aed03291ae310ccda75d8ace4bc7d89e7d3e5D1650BDA5D668B8B50BFC8E608E184F4D3A9A2BADC4FF5F07E0C0BC8A9F2E0B2A26FD6D8C550008FAAAB75FD71AF2A424BEC9A7CD9D83FAD4C8E9319115656A8717D3B523A68FF8004258B9990ED362308461804BA3E3A7E92D8F2FFAE5C2FBA55BA5A3C27C0A2F71BD711D2FE1799C2ADB31B200035481E9EE5C4ADF2AB9C0FA50B23975CF",
+                output_str: "37e7cf6a9a31b0982b2479432b7838657741b0ee79adda1b287550eb325c78cc"
+            },
+            Test {
+                input: "c8e976ab4638909387ce3b8d4e510c3230e5690e02c45093b1d297910abc481e56eea0f296f98379dfc9080af69e73b2399d1c143bee80ae1328162ce1ba7f6a8374679b20aacd380eb4e61382c99998704d62701AFA914F9A2705CDB065885F50D086C3EB5753700C387118BB142F3E6DA1E988DFB31AC75D7368931E45D1391A274B22F83CEB072F9BCABC0B216685BFD789F5023971024B1878A205442522F9EA7D8797A4102A3DF41703768251FD5E017C85D1200A464118AA35654E7CA39F3C375B8EF8CBE7534DBC64BC20BEFB417CF60EC92F63D9EE7397",
+                output_str: "373704f641faf2b918e22e9142abf6b4ac71b6883ac4d7a075f626e947837d3f"
+            },
+            Test {
+                input: "7145fa124b7429a1fc2231237a949ba7201bcc1822d3272de005b682398196c25f7e5cc2f289fbf44415f699cb7fe6757791b1443410234ae061edf623359e2b4e32c19bf88450432dd01caa5eb16a1dc378f391cA5E3C4E5F356728BDDD4975DB7C890DA8BBC84CC73FF244394D0D48954978765E4A00B593F70F2CA082673A261ED88DBCEF1127728D8CD89BC2C597E9102CED6010F65FA75A14EBE467FA57CE3BD4948B6867D74A9DF5C0EC6F530CBF2EE61CE6F06BC8F2864DFF5583776B31DF8C7FFCB61428A56BF7BD37188B4A5123BBF338393AF46EDA85E6",
+                output_str: "ee5994b3d32bdae58e72566fc24b886461217fdd7273e1608f0b2926b7923546"
+            },
+            Test {
+                input: "7fdfadcc9d29bad23ae038c6c65cda1aef757221b8872ed3d75ff8df7da0627d266e224e812c39f7983e4558bfd0a1f2bef3feb56ba09120ef762917b9c093867948547aee98600d10d87b20106878a8d22c64378BF634F7F75900C03986B077B0BF8B740A82447B61B99FEE5376C5EB6680EC9E3088F0BDD0C56883413D60C1357D3C811950E5890E7600103C916341B80C743C6A852B7B4FB60C3BA21F3BC15B8382437A68454779CF3CD7F9F90CCC8EF28D0B706535B1E4108EB5627BB45D719CB046839AEE311CA1ABDC8319E050D67972CB35A6B1601B25DBF487",
+                output_str: "6a584f9f4acd8fc8e15dacd326291fe9311c20987225c51cf4251e52b47fa223"
+            },
+            Test {
+                input: "988638219fd3095421f826f56e4f09e356296b628c3ce6930c9f2e758fd1a80c8273f2f61e4daae65c4f110d3e7ca0965ac7d24e34c0dc4ba2d6ff0bf5bbe93b3585f354d7543cb542a1aa54674d375077f2d360a8F4D42F3DB131C3B7AB7306267BA107659864A90C8C909460A73621D1F5D9D3FD95BEB19B23DB1CB6C0D0FBA91D36891529B8BD8263CAA1BAB56A4AFFAED44962DF096D8D5B1EB845EF31188B3E10F1AF811A13F156BEB7A288AAE593EBD1471B624AA1A7C6ADF01E2200B3D72D88A3AED3100C88231E41EFC376906F0B580DC895F080FDA5741DB1CB",
+                output_str: "4f92839cddb0df31d16a0db53bbe07698a7c1912d5590d21155d45db1b48cab4"
+            },
+            Test {
+                input: "5aab62756d307a669d146aba988d9074c5a159b3de85151a819b117ca1ff6597f6156e80fdd28c9c3176835164d37da7da11d94e09add770b68a6e081cd22ca0c004bfe7cd283bf43a588da91f509b27a6584c474A4A2F3EE0F1F56447379240A5AB1FB77FDCA49B305F07BA86B62756FB9EFB4FC225C86845F026EA542076B91A0BC2CDD136E122C659BE259D98E5841DF4C2F60330D4D8CDEE7BF1A0A244524EECC68FF2AEF5BF0069C9E87A11C6E519DE1A4062A10C83837388F7EF58598A3846F49D499682B683C4A062B421594FAFBC1383C943BA83BDEF515EFCF10D",
+                output_str: "eafd661f343ae834c621e074ac6903a2e3e6324f365b3432dffa732f477ac129"
+            },
+            Test {
+                input: "47b8216aa0fbb5d67966f2e82c17c07aa2d6327e96fcd83e3de7333689f3ee79994a1bf45082c4d725ed8d41205cb5bcdf5c341f77facb1da46a5b9b2cbc49eadf786bcd881f371a95fa17df73f606519aea0ff79D5A11427B98EE7F13A5C00637E2854134691059839121FEA9ABE2CD1BCBBBF27C74CAF3678E05BFB1C949897EA01F56FFA4DAFBE8644611685C617A3206C7A7036E4AC816799F693DAFE7F19F303CE4EBA09D21E03610201BFC665B72400A547A1E00FA9B7AD8D84F84B34AEF118515E74DEF11B9188BD1E1F97D9A12C30132EC2806339BDADACDA2FD8B78",
+                output_str: "3dcec669c5d0176b1bdc002728d242c587dda03b3abfa6074523d3faef4820be"
+            },
+            Test {
+                input: "8cff1f67fe53c098896d9136389bd8881816ccab34862bb67a656e3d98896f3ce6ffd4da73975809fcdf9666760d6e561c55238b205d8049c1cedeef374d1735daa533147bfa960b2cce4a4f254176bb4d1bd1e89654432B8DBE1A135C42115B394B024856A2A83DC85D6782BE4B444239567CCEC4B184D4548EAE3FF6A192F343292BA2E32A0F267F31CC26719EB85245D415FB897AC2DA433EE91A99424C9D7F1766A44171D1651001C38FC79294ACCC68CEB5665D36218454D3BA169AE058A831338C17743603F81EE173BFC0927464F9BD728DEE94C6AEAB7AAE6EE3A627E8",
+                output_str: "4bdf731bbb3d0e2ab0eb3d972123a7a0a085e8a98ac6af8adbd335b37275ddff"
+            },
+            Test {
+                input: "eacd07971cff9b9939903f8c1d8cbb5d4db1b548a85d04e037514a583604e787f32992bf2111b97ac5e8a938233552731321522ab5e8583561260b7d13ebeef785b23a41fd8576a6da764a8ed6d822d4957a545d5244756C18AA80E1AAD4D1F9C20D259DEE1711E2CC8FD013169FB7CC4CE38B362F8E0936AE9198B7E838DCEA4F7A5B9429BB3F6BBCF2DC92565E3676C1C5E6EB3DD2A0F86AA23EDD3D0891F197447692794B3DFA269611AD97F72B795602B4FDB198F3FD3EB41B415064256E345E8D8C51C555DC8A21904A9B0F1AD0EFFAB7786AAC2DA3B196507E9F33CA356427",
+                output_str: "47f904feea607225cab2e3c52748878964bfedcfe068727de610f63421367bcf"
+            },
+            Test {
+                input: "23ac4e9a42c6ef45c3336ce6dfc2ff7de8884cd23dc912fef0f7756c09d335c189f3ad3a23697abda851a81881a0c8ccafc980ab2c702564c2be15fe4c4b9f10dfb2248d0d0cb2e2887fd4598a1d4acda897944a2FFC580FF92719C95CF2AA42DC584674CB5A9BC5765B9D6DDF5789791D15F8DD925AA12BFFAFBCE60827B490BB7DF3DDA6F2A143C8BF96ABC903D83D59A791E2D62814A89B8080A28060568CF24A80AE61179FE84E0FFAD00388178CB6A617D37EFD54CC01970A4A41D1A8D3DDCE46EDBBA4AB7C90AD565398D376F431189CE8C1C33E132FEAE6A8CD17A61C630012",
+                output_str: "324937607d9f16af815701749f0377b3281af9c5bb565d6f2b9611532b6bf044"
+            },
+            Test {
+                input: "0172df732282c9d488669c358e3492260cbe91c95cfbc1e3fea6c4b0ec129b45f242ace09f152fc6234e1bee8aab8cd56e8b486e1dcba9c05407c2f95da8d8f1c0af78ee2ed82a3a79ec0cb0709396ee62aadb84f8A4EE8A7CCCA3C1EE84E302A09EA802204AFECF04097E67D0F8E8A9D2651126C0A598A37081E42D168B0AE8A71951C524259E4E2054E535B779679BDADE566FE55700858618E626B4A0FAF895BCCE9011504A49E05FD56127EAE3D1F8917AFB548ECADABDA1020111FEC9314C413498A360B08640549A22CB23C731ACE743252A8227A0D2689D4C6001606678DFB921",
+                output_str: "b984c2d6b6fdc28574aad551fc16b68f85bf6cc480a15c128ae5616561d46721"
+            },
+            Test {
+                input: "3875b9240cf3e0a8b59c658540f26a701cf188496e2c2174788b126fd29402d6a75453ba0635284d08835f40051a2a9683dc92afb9383719191231170379ba6f4adc816fecbb0f9c446b785bf520796841e58878b73C58D3EBB097CE4761FDEABE15DE2F319DFBAF1742CDEB389559C788131A6793E193856661376C81CE9568DA19AA6925B47FFD77A43C7A0E758C37D69254909FF0FBD415EF8EB937BCD49F91468B49974C07DC819ABD67395DB0E05874FF83DDDAB895344ABD0E7111B2DF9E58D76D85AD98106B36295826BE04D435615595605E4B4BB824B33C4AFEB5E7BB0D19F909",
+                output_str: "91a5b9fc2dcc5faeda57d2e7a41e922dc32d572aebdf6d54cb8c3ae4245e8565"
+            },
+            Test {
+                input: "747cc1a59fefba94a9c75ba866c30dc5c1cb0c0f8e9361d98484956dd5d1a40f6184afbe3dac9f76028d1caeccfbf69199c6ce2b4c092a3f4d2a56fe5a33a00757f4d7dee5dfb0524311a97ae0668a47971b95766E2F6DD48C3F57841F91F04A00AD5EA70F2D479A2620DC5CD78EAAB3A3B011719B7E78D19DDF70D9423798AF77517EBC55392FCD01FC600D8D466B9E7A7A85BF33F9CC5419E9BD874DDFD60981150DDAF8D7FEBAA4374F0872A5628D318000311E2F5655365AD4D407C20E5C04DF17A222E7DEEC79C5AB1116D8572F91CD06E1CCC7CED53736FC867FD49ECEBE6BF8082E8A",
+                output_str: "97dca1050a465b60e91ebe26e29adb5a286a0582eee2e89b8b901954293f6146"
+            },
+            Test {
+                input: "57af971fccaec97435dc2ec9ef0429bcedc6b647729ea168858a6e49ac1071e706f4a5a645ca14e8c7746d65511620682c906c8b86ec901f3dded4167b3f00b06cbfac6aee3728051b3e5ff10b4f9ed8bd0b8da94303C833755B3CA3AEDDF0B54BC8D6632138B5D25BAB03D17B3458A9D782108006F5BB7DE75B5C0BA854B423D8BB801E701E99DC4FEAAD59BC1C7112453B04D33EA3635639FB802C73C2B71D58A56BBD671B18FE34ED2E3DCA38827D63FDB1D4FB3285405004B2B3E26081A8FF08CD6D2B08F8E7B7E90A2AB1ED7A41B1D0128522C2F8BFF56A7FE67969422CE839A9D4608F03",
+                output_str: "6d033d85daed3366d5f7d5e4f03b3d05b65778eeea074b0c683cffcd6f51d5bd"
+            },
+            Test {
+                input: "04e16dedc1227902baaf332d3d08923601bdd64f573faa1bb7201918cfe16b1e10151dae875da0c0d63c59c3dd050c4c6a874011b018421afc4623ab0381831b2da2a8ba42c96e4f70864ac44e106f94311051e74C77C1291BF5DB9539E69567BF6A11CF6932BBBAD33F8946BF5814C066D851633D1A513510039B349939BFD42B858C21827C8FF05F1D09B1B0765DC78A135B5CA4DFBA0801BCADDFA175623C8B647EACFB4444B85A44F73890607D06D507A4F8393658788669F6EF4DEB58D08C50CA0756D5E2F49D1A7AD73E0F0B3D3B5F090ACF622B1878C59133E4A848E05153592EA81C6FBF",
+                output_str: "01ebbb73410eebac665c3b40063d001f43dbe9d1722eb323fe08763d7ff0616c"
+            },
+            Test {
+                input: "7c815c384eee0f288ece27cced52a01603127b079c007378bc5d1e6c5e9e6d1c735723acbbd5801ac49854b2b569d4472d33f40bbb8882956245c366dc3582d71696a97a4e19557e41e54dee482a14229005f93afD2C4A7D8614D10A97A9DFA07F7CD946FA45263063DDD29DB8F9E34DB60DAA32684F0072EA2A9426ECEBFA5239FB67F29C18CBAA2AF6ED4BF4283936823AC1790164FEC5457A9CBA7C767CA59392D94CAB7448F50EB34E9A93A80027471CE59736F099C886DEA1AB4CBA4D89F5FC7AE2F21CCD27F611ECA4626B2D08DC22382E92C1EFB2F6AFDC8FDC3D2172604F5035C46B8197D3",
+                output_str: "8d3a49cb572ab99c9bf0231366bb017c9adf25479d35443a971e45787e738ce5"
+            },
+            Test {
+                input: "e29d505158dbdd937d9e3d2145658ee6f5992a2fc790f4f608d9cdb44a091d5b94b88e81fac4fdf5c49442f13b911c55886469629551189eaff62488f1a479b7db11a1560e198ddccccf50159093425ff7f1cb8d1D1246D0978764087D6BAC257026B090EFAE8CEC5F22B6F21C59ACE1AC7386F5B8837CA6A12B6FBF5534DD0560EF05CA78104D3B943DDB220FEAEC89AA5E692A00F822A2AB9A2FE60350D75E7BE16FF2526DC643872502D01F42F188ABED0A6E9A6F5FD0D1CE7D5755C9FFA66B0AF0B20BD806F08E06156690D81AC811778CA3DAC2C249B96002017FCE93E507E3B953ACF99964B847",
+                output_str: "fbb5a0ab1a3b4c4fa56adb1c9531eb9979c554903053013c20fefd3f57b5ccdb"
+            },
+            Test {
+                input: "d85588696f576e65eca0155f395f0cfacd83f36a99111ed5768df2d116d2121e32357ba4f54ede927f189f297d3a97fad4e9a0f5b41d8d89dd7fe20156799c2b7b6bf9c957ba0d6763f5c3bc5129747bbb53652b49290CFF1C87E2CDF2C4B95D8AAEE09BC8FBFA6883E62D237885810491BFC101F1D8C636E3D0EDE838AD05C207A3DF4FAD76452979EB99F29AFAECEDD1C63B8D36CF378454A1BB67A741C77AC6B6B3F95F4F02B64DABC15438613EA49750DF42EE90101F115AA9ABB9FF64324DDE9DABBB01054E1BD6B4BCDC7930A44C2300D87CA78C06924D0323AD7887E46C90E8C4D100ACD9EED21E",
+                output_str: "6b3dcc7ac6a5cb85b67fc71b4055d3798134deef26fd3eb03a042e0daa35cc85"
+            },
+            Test {
+                input: "3a12f8508b40c32c74492b66323375dcfe49184c78f73179f3314b79e63376b8ac683f5a51f1534bd729b02b04d002f55cbd8e8fc9b5ec1ea6bbe6a0d0e7431518e6ba45d124035f9d3dce0a8bb7bf1430a9f657e0B4EA9F20EB20C786A58181A1E20A96F1628F8728A13BDF7A4B4B32FC8AA7054CC4881AE7FA19AFA65C6C3EE1B3ADE3192AF42054A8A911B8EC1826865D46D93F1E7C5E2B7813C92A506E53886F3D4701BB93D2A681AD109C845904BB861AF8AF0646B6E399B38B614051D34F6842563A0F37EC00CB3D865FC5D746C4987DE2A65071100883A2A9C7A2BFE1E2DD603D9EA24DC7C5FD06BE",
+                output_str: "5d1dba8f1584ac3f36b3ac925ec13ac284013b9664965ab6265b942466b5d8ec"
+            },
+            Test {
+                input: "1861edce46fa5ad17e1ff1deae084dec580f97d0a67885dfe834b9dfac1ae076742ce9e267512ca51f6df5a455af0c5fd6abf94acea103a3370c354485a7846fb84f3ac7c2904b5b2fbf227002ce512133bb7e1c4E50057BFD1E44DB33C7CDB969A99E284B184F50A14B068A1FC5009D9B298DBE92239572A7627AAC02ABE8F3E3B473417F36D4D2505D16B7577F4526C9D94A270A2DFE450D06DA8F6FA956879A0A55CFE99E742EA555EA477BA3E9B44CCD508C375423611AF92E55345DC215779B2D5119EBA49C71D49B9FE3F1569FA24E5CA3E332D042422A8B8158D3EC66A80012976F31FFDF305F0C9C5E",
+                output_str: "89c6c86db0a889aa67d8cb085f9f4312645972d977c5b952d9f6243d7d3be4d5"
+            },
+            Test {
+                input: "08d0ffde3a6e4ef65608ea672e4830c12943d7187ccff08f4941cfc13e545f3b9c7ad5eebbe2b01642b486caf855c2c73f58c1e4e3391da8e2d63d96e15fd84953ae5c231911b00ad6050cd7aafdaac9b0f663ae6AAB45519D0F5391A541707D479034E73A6AD805AE3598096AF078F1393301493D663DD71F83869CA27BA508B7E91E81E128C1716DC3ACFE3084B2201E04CF8006617EECF1B640474A5D45CFDE9F4D3EF92D6D055B909892194D8A8218DB6D8203A84261D200D71473D7488F3427416B6896C137D455F231071CACBC86E0415AB88AEC841D96B7B8AF41E05BB461A40645BF176601F1E760DE5F",
+                output_str: "ac02432a5541c26238c6f99fadb2b23b5ffcad8f04bd4c3b9a6620cab1266e6b"
+            },
+            Test {
+                input: "d782abb72a5be3392757be02d3e45be6e2099d6f000d042c8a543f50ed6ebc055a7f133b0dd8e9bc348536edcaae2e12ec18e8837df7a1b3c87ec46d50c241dee820fd586197552dc20beea50f445a07a38f1768a39E2B2FF05DDDEDF751F1DEF612D2E4D810DAA3A0CC904516F9A43AF660315385178A529E51F8AAE141808C8BC5D7B60CAC26BB984AC1890D0436EF780426C547E94A7B08F01ACBFC4A3825EAE04F520A9016F2FB8BF5165ED12736FC71E36A49A73614739EAA3EC834069B1B40F1350C2B3AB885C02C640B9F7686ED5F99527E41CFCD796FE4C256C9173186C226169FF257954EBDA81C0E5F99",
+                output_str: "f55aa01deab12148e35759db818f1059351165e9e6f93d342f0abfca102e0801"
+            },
+            Test {
+                input: "5fce8109a358570e40983e1184e541833bb9091e280f258cfb144387b05d190e431cb19baa67273ba0c58abe91308e1844dcd0b3678baa42f335f2fa05267a0240b3c718a5942b3b3e3bfa98a55c25a1466e8d7a603722CB2BBF03AFA54CD769A99F310735EE5A05DAE2C22D397BD95635F58C48A67F90E1B73AAFCD3F82117F0166657838691005B18DA6F341D6E90FC1CDB352B30FAE45D348294E501B63252DE14740F2B85AE5299DDEC3172DE8B6D0BA219A20A23BB5E10FF434D39DB3F583305E9F5C039D98569E377B75A70AB837D1DF269B8A4B566F40BB91B577455FD3C356C914FA06B9A7CE24C7317A172D",
+                output_str: "7c0bda7cb42dadbd037f50a5f27e3ab5da258d4670f1bea90154c87c98136ba1"
+            },
+            Test {
+                input: "6172f1971a6e1e4e6170afbad95d5fec99bf69b24b674bc17dd78011615e502de6f56b86b1a71d3f4348087218ac7b7d09302993be272e4a591968aef18a1262d665610d1070ee91cc8da36e1f841a69a7a682c580E836941D21D909A3AFC1F0B963E1CA5AB193E124A1A53DF1C587470E5881FB54DAE1B0D840F0C8F9D1B04C645BA1041C7D8DBF22030A623AA15638B3D99A2C400FF76F3252079AF88D2B37F35EE66C1AD7801A28D3D388AC450B97D5F0F79E4541755356B3B1A5696B023F39AB7AB5F28DF4202936BC97393B93BC915CB159EA1BD7A0A414CB4B7A1AC3AF68F50D79F0C9C7314E750F7D02FAA58BFA",
+                output_str: "f60c53ba2132293b881f0513e7ab47fe9746ed4a6ac9cade61e6d802d5872372"
+            },
+            Test {
+                input: "5668ecd99dfbe215c4118398ac9c9eaf1a1433fab4ccdd3968064752b625ea944731f75d48a27d047d67547f14dd0ffaa55fa5e29f7af0d161d85eafc4f2029b717c918eab9d304543290bdba7158b68020c0ba4e079BC95B5BC0FC044A992B94B4CCD3BD66D0EABB5DBBAB904D62E00752C4E3B0091D773BCF4C14B4377DA3EFFF824B1CB2FA01B32D1E46C909E626ED2DAE920F4C7DBEB635BC754FACBD8D49BEBA3F23C1C41CCBFCD0EE0C114E69737F5597C0BF1D859F0C767E18002AE8E39C26261FFDE2920D3D0BAF0E906138696CFE5B7E32B600F45DF3AAA39932F3A7DF95B60FA8712A2271FCAF3911CE7B511B1",
+                output_str: "1c66b9a7c50ed77d179a0c437d5890c9835a13f90a73a01332ab0731a41a115e"
+            },
+            Test {
+                input: "03d625488354df30e3f875a68edfcf340e8366a8e1ab67f9d5c5486a96829dfac0578289082b2a62117e1cf418b43b90e0adc881fc6ae8105c888e9ecd21aea1c9ae1a4038dfd17378fed71d02ae492087d7cdcd98F746855227967CB1AB4714261EE3BEAD3F4DB118329D3EBEF4BC48A875C19BA763966DA0EBEA800E01B2F50B00E9DD4CACA6DCB314D00184EF71EA2391D760C950710DB4A70F9212FFC54861F9DC752CE18867B8AD0C48DF8466EF7231E7AC567F0EB55099E622EBB86CB237520190A61C66AD34F1F4E289CB3282AE3EAAC6152ED24D2C92BAE5A7658252A53C49B7B02DFE54FDB2E90074B6CF310AC661",
+                output_str: "48a00ba224ac5558f41a79f52137db9182a93f1045d43789e5913d7be40408c2"
+            },
+            Test {
+                input: "2edc282ffb90b97118dd03aaa03b145f363905e3cbd2d50ecd692b37bf000185c651d3e9726c690d3773ec1e48510e42b17742b0b0377e7de6b8f55e00a8a4db4740cee6db0830529dd19617501dc1e9359aa3bcf147E0A76B3AB70C4984C13E339E6806BB35E683AF8527093670859F3D8A0FC7D493BCBA6BB12B5F65E71E705CA5D6C948D66ED3D730B26DB395B3447737C26FAD089AA0AD0E306CB28BF0ACF106F89AF3745F0EC72D534968CCA543CD2CA50C94B1456743254E358C1317C07A07BF2B0ECA438A709367FAFC89A57239028FC5FECFD53B8EF958EF10EE0608B7F5CB9923AD97058EC067700CC746C127A61EE3",
+                output_str: "240a85eaf7f3016c192ad5e17e5f93b643fe3edba719f423693a34da3784827a"
+            },
+            Test {
+                input: "90b28a6aa1fe533915bcb8e81ed6cacdc10962b7ff82474f845eeb86977600cf70b07ba8e3796141ee340e3fce842a38a50afbe90301a3bdcc591f2e7d9de53e495525560b908c892439990a2ca2679c5539ffdf636777AD9C1CDEF809CDA9E8DCDB451ABB9E9C17EFA4379ABD24B182BD981CAFC792640A183B61694301D04C5B3EAAD694A6BD4CC06EF5DA8FA23B4FA2A64559C5A68397930079D250C51BCF00E2B16A6C49171433B0AADFD80231276560B80458DD77089B7A1BBCC9E7E4B9F881EACD6C92C4318348A13F4914EB27115A1CFC5D16D7FD94954C3532EFACA2CAB025103B2D02C6FD71DA3A77F417D7932685888A",
+                output_str: "2aa9d0a1d9b9b691b4b8641e68d454d2d9c34ce43a5b55dd57590716b8a46cf7"
+            },
+            Test {
+                input: "2969447d175490f2aa9bb055014dbef2e6854c95f8d60950bfe8c0be8de254c26b2d31b9e4de9c68c9adf49e4ee9b1c2850967f29f5d08738483b417bb96b2a56f0c8aca632b552059c59aac3f61f7b45c966b75f1D9931FF4E596406378CEE91AAA726A3A84C33F37E9CDBE626B5745A0B06064A8A8D56E53AAF102D23DD9DF0A3FDF7A638509A6761A33FA42FA8DDBD8E16159C93008B53765019C3F0E9F10B144CE2AC57F5D7297F9C9949E4FF68B70D339F87501CE8550B772F32C6DA8AD2CE2100A895D8B08FA1EEAD7C376B407709703C510B50F87E73E43F8E7348F87C3832A547EF2BBE5799ABEDCF5E1F372EA809233F006",
+                output_str: "58c469e1a76835cc1a897b885b1b2a33b0aabce4cfbb65523d2e0d08d6d1a413"
+            },
+            Test {
+                input: "721645633a44a2c78b19024eaecf58575ab23c27190833c26875dc0f0d50b46aea9c343d82ea7d5b3e50ec700545c615daeaea64726a0f05607576dcd396d812b03fb6551c641087856d050b10e6a4d5577b82a98AFB89CEE8594C9DC19E79FEFF0382FCFD127F1B803A4B9946F4AC9A4378E1E6E041B1389A53E3450CD32D9D2941B0CBABDB50DA8EA2513145164C3AB6BCBD251C448D2D4B087AC57A59C2285D564F16DA4ED5E607ED979592146FFB0EF3F3DB308FB342DF5EB5924A48256FC763141A278814C82D6D6348577545870AE3A83C7230AC02A1540FE1798F7EF09E335A865A2AE0949B21E4F748FB8A51F44750E213A8FB",
+                output_str: "6c8df81b1e1ed70a5413368018db9628b0e0b4563423c051a54d000aadde0c06"
+            },
+            Test {
+                input: "6b860d39725a14b498bb714574b4d37ca787404768f64c648b1751b353ac92bac2c3a28ea909fdf0423336401a02e63ec24325300d823b6864bb701f9d7c7a1f8ec9d0ae3584aa6dd62ea1997cd831b4babd9a4da50932D4EFDA745C61E4130890E156AEE6113716DAF95764222A91187DB2EFFEA49D5D0596102D619BD26A616BBFDA8335505FBB0D90B4C180D1A2335B91538E1668F9F9642790B4E55F9CAB0FE2BDD2935D001EE6419ABAB5457880D0DBFF20ED8758F4C20FE759EFB33141CF0E892587FE8187E5FBC57786B7E8B089612C936DFC03D27EFBBE7C8673F1606BD51D5FF386F4A7AB68EDF59F385EB1291F117BFE717399",
+                output_str: "108fff41d5bcf654071b4414e666fdebbe878c309d6ddc90afaf5c61df8559f0"
+            },
+            Test {
+                input: "6a01830af3889a25183244decb508bd01253d5b508ab490d3124afbf42626b2e70894e9b562b288d0a2450cfacf14a0ddae5c04716e5a0082c33981f6037d23d5e045ee1ef2283fb8b6378a914c5d9441627a722c282FF452E25A7EA608D69CEE4393A0725D17963D0342684F255496D8A18C2961145315130549311FC07F0312FB78E6077334F87EAA873BEE8AA95698996EB21375EB2B4EF53C14401207DEB4568398E5DD9A7CF97E8C9663E23334B46912F8344C19EFCF8C2BA6F04325F1A27E062B62A58D0766FC6DB4D2C6A1928604B0175D872D16B7908EBC041761187CC785526C2A3873FEAC3A642BB39F5351550AF9770C328AF7B",
+                output_str: "751eaaafa4aec8acd26606d6439c55b5c66ec7db807579edc68994b300f7a077"
+            },
+            Test {
+                input: "b3c5e74b69933c2533106c563b4ca20238f2b6e675e8681e34a389894785bdade59652d4a73d80a5c85bd454fd1e9ffdad1c3815f5038e9ef432aac5c3c4fe840cc370cf86580a6011778bbedaf511a51b56d1a2eB68394AA299E26DA9ADA6A2F39B9FAFF7FBA457689B9C1A577B2A1E505FDF75C7A0A64B1DF81B3A356001BF0DF4E02A1FC59F651C9D585EC6224BB279C6BEBA2966E8882D68376081B987468E7AED1EF90EBD090AE825795CDCA1B4F09A979C8DFC21A48D8A53CDBB26C4DB547FC06EFE2F9850EDD2685A4661CB4911F165D4B63EF25B87D0A96D3DFF6AB0758999AAD214D07BD4F133A6734FDE445FE474711B69A98F7E2B",
+                output_str: "90c2d5f8e26b0bddea719064bb02a6242f2cc5a42936b14fe17f861b47b7e186"
+            },
+            Test {
+                input: "83af34279ccb5430febec07a81950d30f4b66f484826afee7456f0071a51e1bbc55570b5cc7ec6f9309c17bf5befdd7c6ba6e968cf218a2b34bd5cf927ab846e38a40bbd81759e9e33381016a755f699df35d660007B5EADF292FEEFB735207EBF70B5BD17834F7BFA0E16CB219AD4AF524AB1EA37334AA66435E5D397FC0A065C411EBBCE32C240B90476D307CE802EC82C1C49BC1BEC48C0675EC2A6C6F3ED3E5B741D13437095707C565E10D8A20B8C20468FF9514FCF31B4249CD82DCEE58C0A2AF538B291A87E3390D737191A07484A5D3F3FB8C8F15CE056E5E5F8FEBE5E1FB59D6740980AA06CA8A0C20F5712B4CDE5D032E92AB89F0AE1",
+                output_str: "3298a95cfe59b9d6cab99c36dc1324194c09f97f08944a02d9574bbca3186b41"
+            },
+            Test {
+                input: "a7ed84749ccc56bb1dfba57119d279d412b8a986886d810f067af349e8749e9ea746a60b03742636c464fc1ee233acc52c1983914692b64309edfdf29f1ab912ec3e8da074d3f1d231511f5756f0b6eead3e89a6a88FE330A10FACE267BFFBFC3E3090C7FD9A850561F363AD75EA881E7244F80FF55802D5EF7A1A4E7B89FCFA80F16DF54D1B056EE637E6964B9E0FFD15B6196BDD7DB270C56B47251485348E49813B4EB9ED122A01B3EA45AD5E1A929DF61D5C0F3E77E1FDC356B63883A60E9CBB9FC3E00C2F32DBD469659883F690C6772E335F617BC33F161D6F6984252EE12E62B6000AC5231E0C9BC65BE223D8DFD94C5004A101AF9FD6C0FB",
+                output_str: "1c4172928cb10e16ab3cdb33f815103b000a6c7d62376cad29af03f4b2b0e103"
+            },
+            Test {
+                input: "a6fe30dcfcda1a329e82ab50e32b5f50eb25c873c5d2305860a835aecee6264aa36a47429922c4b8b3afd00da16035830edb897831c4e7b00f2c23fc0b15fdc30d85fb70c30c431c638e1a25b51caf1d7e8b050b7F89BFB30F59F0F20FECFF3D639ABC4255B3868FC45DD81E47EB12AB40F2AAC735DF5D1DC1AD997CEFC4D836B854CEE9AC02900036F3867FE0D84AFFF37BDE3308C2206C62C4743375094108877C73B87B2546FE05EA137BEDFC06A2796274099A0D554DA8F7D7223A48CBF31B7DECAA1EBC8B145763E3673168C1B1B715C1CD99ECD3DDB238B06049885ECAD9347C2436DFF32C771F34A38587A44A82C5D3D137A03CAA27E66C8FF6",
+                output_str: "f5cfb4df3f7c5a778f38a3b43b26479a0e8a49030c59ac19fb0cfa806081ca4a"
+            },
+            Test {
+                input: "83167ff53704c3aa19e9fb3303539759c46dd4091a52ddae9ad86408b69335989e61414bc20ab4d01220e35241eff5c9522b079fba597674c8d716fe441e566110b6211531ceccf8fd06bc8e511d00785e57788ed9A1C5C73524F01830D2E1148C92D0EDC97113E3B7B5CD3049627ABDB8B39DD4D6890E0EE91993F92B03354A88F52251C546E64434D9C3D74544F23FB93E5A2D2F1FB15545B4E1367C97335B0291944C8B730AD3D4789273FA44FB98D78A36C3C3764ABEEAC7C569C1E43A352E5B770C3504F87090DEE075A1C4C85C0C39CF421BDCC615F9EFF6CB4FE6468004AECE5F30E1ECC6DB22AD9939BB2B0CCC96521DFBF4AE008B5B46BC006E",
+                output_str: "06ab8fdbe4dce935e42003c17ff60ba236f43a843995b7fef3a29dfe0c82f1d4"
+            },
+            Test {
+                input: "3a3a819c48efde2ad914fbf00e18ab6bc4f14513ab27d0c178a188b61431e7f5623cb66b23346775d386b50e982c493adbbfc54b9a3cd383382336a1a0b2150a15358f336d03ae18f666c7573d55c4fd181c29e6cCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1",
+                output_str: "c11f3522a8fb7b3532d80b6d40023a92b489addad93bf5d64b23f35e9663521c"
+            }
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Sha3_256));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_sha3_384() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004",
+            },
+            Test {
+                input: "cc",
+                output_str: "5ee7f374973cd4bb3dc41e3081346798497ff6e36cb9352281dfe07d07fc530ca9ad8ef7aad56ef5d41be83d5e543807"
+            },
+            Test {
+                input: "41fb",
+                output_str: "1dd81609dcc290effd7ac0a95d4a20821580e56bd50dbd843920650be7a80a1719577da337cfdf86e51c764caa2e10bd"
+            },
+            Test {
+                input: "1f877c",
+                output_str: "14f6f486fb98ed46a4a198040da8079e79e448daacebe905fb4cf0df86ef2a7151f62fe095bf8516eb0677fe607734e2"
+            },
+            Test {
+                input: "c1ecfdfc",
+                output_str: "d92bbd604bdd24b9889508f8558b13e96595ac90bc8a441daf9b51d6abc14ffd0835fb9366e3912504264ce87e421cb8"
+            },
+            Test {
+                input: "21f134ac57",
+                output_str: "e248d6ff342d35a30ec230ba51cdb161025d6f1c251aca6ae3531f0682c164a1fc0725b1beff808a200c131557a22809"
+            },
+            Test {
+                input: "c6f50bb74e29",
+                output_str: "d6dd2ed08c1f644857a15dafaf80538bee597278c9abe047bfbabfb8b1fcb7543e80ae9f7143d00f4daaf39b138ab3ff"
+            },
+            Test {
+                input: "119713cc83eeef",
+                output_str: "49ca1eb8d71d1fdc7a72daa320c8f9ca543671c2cb8fe9b2638a8416df50a790a50d0bb6b88741d7816d6061f46aea89"
+            },
+            Test {
+                input: "4a4f202484512526",
+                output_str: "89dbf4c39b8fb46fdf0a6926cec0355a4bdbf9c6a446e140b7c8bd08ff6f489f205daf8effe160f437f67491ef897c23"
+            },
+            Test {
+                input: "1f66ab4185ed9b6375",
+                output_str: "d6154641d7d9df62f0cedc2bd64ee82412b3a80f6eace7c45f9703373379007eabf592d2d2116e093dc33dcbba4649e9"
+            },
+            Test {
+                input: "eed7422227613b6f53c9",
+                output_str: "2ee5df2591cfc4cb1e1d0bd8b28727f0fa5359a75f7819a92a3cb80ddb5708e4705177b981396b4818d11e3ca615ec93"
+            },
+            Test {
+                input: "eaeed5cdffd89dece455f1",
+                output_str: "786c3f73fb092be184fc2b19f5920f3d94f25d4523165ae82f9b39b2c724fd62dc9a3263091a239d5ef1ad562dd4fd26"
+            },
+            Test {
+                input: "5be43c90f22902e4fe8ed2d3",
+                output_str: "79188139ec2cad8d197d308b806cf383782c29a8c27ee29c5e31425b2dd18b2f5f491fbfb38d7078f58510125c064a0a"
+            },
+            Test {
+                input: "a746273228122f381c3b46e4f1",
+                output_str: "0c82b8c75c5d540e7d624928281fba8b8d0b1583d74f3f0ea4f200f1ce5475149c282e05db695dc67baf42deffdc3f55"
+            },
+            Test {
+                input: "3c5871cd619c69a63b540eb5a625",
+                output_str: "830d2325c001623edfea97ea1d0e65982d4ed7abb8e64ea61c85e9bc1882d11fc4153c30be63fc66f5fbce74bb394596"
+            },
+            Test {
+                input: "fa22874bcc068879e8ef11a69f0722",
+                output_str: "1dbe1bc60a9c6fbe10a727e2a6d397930d547ad2c390286948c3167ee77ff6e275ec8431c5ad4b4e4e5ae67a4bc88d05"
+            },
+            Test {
+                input: "52a608ab21ccdd8a4457a57ede782176",
+                output_str: "feee2ef332515284e0ba247c62f264199044d03877c58e54b51a62e39e91c27aaae384837eb9d479b4c0308cfc6b779b"
+            },
+            Test {
+                input: "82e192e4043ddcd12ecf52969d0f807eed",
+                output_str: "1888e953727cb837de40c69869560c20729c50638e4561b385937bfc4c297e789ea6c03efcf2df3290b1fd36be268c32"
+            },
+            Test {
+                input: "75683dcb556140c522543bb6e9098b21a21e",
+                output_str: "30de7b544265422ce689e667f48498f455e8bf1055653f21294ead7d2e898b05fa75eeca46dc2575c475c480aa49ca62"
+            },
+            Test {
+                input: "06e4efe45035e61faaf4287b4d8d1f12ca97e5",
+                output_str: "041b7c89bd4b582a7d20e579c6fdb18ba0c1251dabacc687af448eb49151bbc04adcb81d797d4bc51f03bfff230ffcc6"
+            },
+            Test {
+                input: "e26193989d06568fe688e75540aea06747d9f851",
+                output_str: "eaf751ee6e75aa2c56453f316c019bda7d7ae1fda03b79ac413bb1f2840d58aaaac77f2dc106d22f1a71157f9f841c4b"
+            },
+            Test {
+                input: "d8dc8fdefbdce9d44e4cbafe78447bae3b5436102a",
+                output_str: "16c4a7f7e8ba7ea13c59576be602f885e21be7c34b3ac05cac4262baad8aa3f95bd9260f13f08550ce331ec773ba758c"
+            },
+            Test {
+                input: "57085fd7e14216ab102d8317b0cb338a786d5fc32d8f",
+                output_str: "5119a4fc11daf2ef5deb7aeb35549162d9afc827392a8868e7f8594a5c194d9c8f6a430cb386b8d825cc6dab4edb742a"
+            },
+            Test {
+                input: "a05404df5dbb57697e2c16fa29defac8ab3560d6126fa0",
+                output_str: "a91f0170457e78b3bb15b0bdc0ff4efe8d7313d2725d8e8db875bcafbc11314126559f45e86e78136eb214ff02764cab"
+            },
+            Test {
+                input: "aecbb02759f7433d6fcb06963c74061cd83b5b3ffa6f13c6",
+                output_str: "98fe81746ccf7cfe5571d6d8b09943ecae44f606444f9dabf1a57fe4e871f6962266d18652fd4eebdbe492cfc5b2b21f"
+            },
+            Test {
+                input: "aafdc9243d3d4a096558a360cc27c8d862f0be73db5e88aa55",
+                output_str: "3dd9054c105c40798df45cfb5880f97a9536fa7bd13f1d816b8ee887fcbafc102a7d4bde9fe6e265538eec2525b50d89"
+            },
+            Test {
+                input: "7bc84867f6f9e9fdc3e1046cae3a52c77ed485860ee260e30b15",
+                output_str: "decd778b89b4295072dbf98689e2eb6066e406356ea4b7cad550019f4a2abb25163e9571d0adb9adc6a802b7e03c152c"
+            },
+            Test {
+                input: "fac523575a99ec48279a7a459e98ff901918a475034327efb55843",
+                output_str: "37f14b317d46bdb3e5dd6f68986a08a098c46b9d85d1f254a17878c008f97926c8a13c3838721cfe3a58076f3992f26c"
+            },
+            Test {
+                input: "0f8b2d8fcfd9d68cffc17ccfb117709b53d26462a3f346fb7c79b85e",
+                output_str: "641a7af13b889d1a0f1aa3e4e4ff8cc5903c47e1a52bdea257d80e37e596564ab33eead06717cdb6b706cb6986293d4f"
+            },
+            Test {
+                input: "a963c3e895ff5a0be4824400518d81412f875fa50521e26e85eac90c04",
+                output_str: "122b8b86103fe3c18ff28178a256acb0cab8518338d2cba697e3f560ecfee09b024b97d8d1f69632ad1f2c5f5628d3ef"
+            },
+            Test {
+                input: "03a18688b10cc0edf83adf0a84808a9718383c4070c6c4f295098699ac2c",
+                output_str: "f35a292e197007e28ce652a067173f3659c51b70438aa9e433081d3df71b4a11e3f3be5af32e2c08d23a0b44e30b0bdf"
+            },
+            Test {
+                input: "84fb51b517df6c5accb5d022f8f28da09b10232d42320ffc32dbecc3835b29",
+                output_str: "2ea596b446d5ccd8f0927a2e3790911e00f1f52cfbfc41f12290cbacd1c903c74deef840fd1398e12ee863acd92baebf"
+            },
+            Test {
+                input: "9f2fcc7c90de090d6b87cd7e9718c1ea6cb21118fc2d5de9f97e5db6ac1e9c10",
+                output_str: "baae7aaed4fbf42f9316c7e8f722eeb06a598b509f184b22fbd5a81c93d95fff711f5de90847b3248b6df76cabce07ee"
+            },
+            Test {
+                input: "de8f1b3faa4b7040ed4563c3b8e598253178e87e4d0df75e4ff2f2dedd5a0be046",
+                output_str: "32cfc8a18a7116d4b9029051941808c3b332efdb132c515f9110e19b8354355d94616c9965bc2d1f2489f8452af7fb2f"
+            },
+            Test {
+                input: "62f154ec394d0bc757d045c798c8b87a00e0655d0481a7d2d9fb58d93aedc676b5a0",
+                output_str: "73443ea38a8801395c044e3cbecd45dd62d6e304c5440fa9fe9651a438c010a76712759be20681f1416661e746e5eb77"
+            },
+            Test {
+                input: "b2dcfe9ff19e2b23ce7da2a4207d3e5ec7c6112a8a22aec9675a886378e14e5bfbad4e",
+                output_str: "6e82f460660f3d2cc33aa59a37f325eed0133fe29a9cb428a3c22572b6bf6c5da2d0d4645c49135653a049795d4e2ad0"
+            },
+            Test {
+                input: "47f5697ac8c31409c0868827347a613a3562041c633cf1f1f86865a576e02835ed2c2492",
+                output_str: "229160a61cf2842b37ea85788bb1ce8294ded9ead266359d61df3d6df98ee155ed03ab1a51d6291b41680a00553298eb"
+            },
+            Test {
+                input: "512a6d292e67ecb2fe486bfe92660953a75484ff4c4f2eca2b0af0edcdd4339c6b2ee4e542",
+                output_str: "f5d838dedf07ac3a5646221adc6ca59045976df9c33367fdaa0be3afc57eef0d434ee92cd618b3fa26c7eabd18d78772"
+            },
+            Test {
+                input: "973cf2b4dcf0bfa872b41194cb05bb4e16760a1840d8343301802576197ec19e2a1493d8f4fb",
+                output_str: "d41a324a1739bbcfc983a2b250750a1117e57bd26512cc5dca7066d8b972ad9eb0bb3c7e36b9b84fc0e8129b69cd3847"
+            },
+            Test {
+                input: "80beebcd2e3f8a9451d4499961c9731ae667cdc24ea020ce3b9aa4bbc0a7f79e30a934467da4b0",
+                output_str: "170d73baf77eae7a852a1bb19ba6665f9ef425a66f2649e959b5caa82d01fdb89c8c7fa6f40702f7c3391b146f6fa33e"
+            },
+            Test {
+                input: "7abaa12ec2a7347674e444140ae0fb659d08e1c66decd8d6eae925fa451d65f3c0308e29446b8ed3",
+                output_str: "a8f4a60a8ff5b3ebb4eadb9c46f1f403ab7ff632c7a11f80fc9153858b484291b3936713076955207d0c7e1964dc1346"
+            },
+            Test {
+                input: "c88dee9927679b8af422abcbacf283b904ff31e1cac58c7819809f65d5807d46723b20f67ba610c2b7",
+                output_str: "5815d78aca9600632239b7ce8385d7e837f883857601efb78f9c2dac9a96ae0bfd107526f268d06fb4227d4774a9e727"
+            },
+            Test {
+                input: "01e43fe350fcec450ec9b102053e6b5d56e09896e0ddd9074fe138e6038210270c834ce6eadc2bb86bf6",
+                output_str: "a5d91b01650d24b4753f41871fa700e997d5f1ef9c06d8f9b3a9b2d318716408e1566bb04b49b84e77f5f73d8f640541"
+            },
+            Test {
+                input: "337023370a48b62ee43546f17c4ef2bf8d7ecd1d49f90bab604b839c2e6e5bd21540d29ba27ab8e309a4b7",
+                output_str: "c7ba066881db931e9c674d74ce2309b3002c6d5bc22056c454261cdbc5d93fe310eadd755e41fb1d789fdb9a73fda28f"
+            },
+            Test {
+                input: "6892540f964c8c74bd2db02c0ad884510cb38afd4438af31fc912756f3efec6b32b58ebc38fc2a6b913596a8",
+                output_str: "a52ca3413bb83934b1ead4686f639b90c5ee3cb5be7e29a1a5293c868441d79be2ef246b427ffcf0568d4d01be54ff0d"
+            },
+            Test {
+                input: "f5961dfd2b1ffffda4ffbf30560c165bfedab8ce0be525845deb8dc61004b7db38467205f5dcfb34a2acfe96c0",
+                output_str: "13e60554fa18cef87ceabe147541886d97c2fb5f40f163d953306d2a26b013b33cb202d78aef49fd47e7ec1c745920cd"
+            },
+            Test {
+                input: "ca061a2eb6ceed8881ce2057172d869d73a1951e63d57261384b80ceb5451e77b06cf0f5a0ea15ca907ee1c27eba",
+                output_str: "e4e03ccba92bbd28182d005f69de4e71c61c62cd323decfb2addbeeff7ee74933aa7a167e4e1dbb3df7e5c91184f2d88"
+            },
+            Test {
+                input: "1743a77251d69242750c4f1140532cd3c33f9b5ccdf7514e8584d4a5f9fbd730bcf84d0d4726364b9bf95ab251d9bb",
+                output_str: "9b26e9bf13b6fc33fd335df976c8e1b781c800895ebd72e34f96eb875b41f04aaee825cd8f0eb6c43d803f4e6ef688a9"
+            },
+            Test {
+                input: "d8faba1f5194c4db5f176fabfff856924ef627a37cd08cf55608bba8f1e324d7c7f157298eabc4dce7d89ce5162499f9",
+                output_str: "a127fefcdd240f762cce3f5f1551fc7e1cdebc7950d1cd94c6888f490cb2285a10fd0ee797b168c5ca4761fa232aaf05"
+            },
+            Test {
+                input: "be9684be70340860373c9c482ba517e899fc81baaa12e5c6d7727975d1d41ba8bef788cdb5cf4606c9c1c7f61aed59f97d",
+                output_str: "feb5a24edb05bef846b0a1f3f48da212dfc2d0bac746890d4ad72fbe3a7b4ff8e2b542b827779467122271b1e0df2bd2"
+            },
+            Test {
+                input: "7e15d2b9ea74ca60f66c8dfab377d9198b7b16deb6a1ba0ea3c7ee2042f89d3786e779cf053c77785aa9e692f821f14a7f51",
+                output_str: "8da4f3d1a13197171b02e1ccb07bf51cdbabd833fdc3c3797a113cfa5c71795782c47ce36c389fbad461d0d5b59ca684"
+            },
+            Test {
+                input: "9a219be43713bd578015e9fda66c0f2d83cac563b776ab9f38f3e4f7ef229cb443304fba401efb2bdbd7ece939102298651c86",
+                output_str: "d19fe4a5f93bcd483daa7af8cb636807962d40af9a507dc4fa4e1fd480a6e8fa3c25fa30eb6b74979ee456c1644a5c1d"
+            },
+            Test {
+                input: "c8f2b693bd0d75ef99caebdc22adf4088a95a3542f637203e283bbc3268780e787d68d28cc3897452f6a22aa8573ccebf245972a",
+                output_str: "63ff3053ace687fb91070ca7fc6a51c259e13da8ac0dd741ab36d1fa930e3bb9ac6a1fad654f7238cfc4485c5f9f8252"
+            },
+            Test {
+                input: "ec0f99711016c6a2a07ad80d16427506ce6f441059fd269442baaa28c6ca037b22eeac49d5d894c0bf66219f2c08e9d0e8ab21de52",
+                output_str: "39dde02a319b5e869f4c51a1d30ff4d4d88ebe504c54f155aa5fad3316404fdbd1918074d35d14bac88d6f359108a1dc"
+            },
+            Test {
+                input: "0dc45181337ca32a8222fe7a3bf42fc9f89744259cff653504d6051fe84b1a7ffd20cb47d4696ce212a686bb9be9a8ab1c697b6d6a33",
+                output_str: "1959378f32117e58c0141160e16facfe336590196be805d149eb5aeea641f9bb119b3eddfefd817701c82d2f528b823e"
+            },
+            Test {
+                input: "de286ba4206e8b005714f80fb1cdfaebde91d29f84603e4a3ebc04686f99a46c9e880b96c574825582e8812a26e5a857ffc6579f63742f",
+                output_str: "7b172a9bb311b1375e15ece1c1e8f092becfafec9f3144e93f596eb7e6abfb34fcedb08eda7883ebbf40038b7a754f9f"
+            },
+            Test {
+                input: "eebcc18057252cbf3f9c070f1a73213356d5d4bc19ac2a411ec8cdeee7a571e2e20eaf61fd0c33a0ffeb297ddb77a97f0a415347db66bcaf",
+                output_str: "6ba32ecaaa0aa9c59e72173f2a7816ac51f313c467a017190db9832c6311ec23b8d56b7b220fa09a9081962efed5183e"
+            },
+            Test {
+                input: "416b5cdc9fe951bd361bd7abfc120a5054758eba88fdd68fd84e39d3b09ac25497d36b43cbe7b85a6a3cebda8db4e5549c3ee51bb6fcb6ac1e",
+                output_str: "55fdf2ec27d334b5b59efb9b6d518e25be0f5ff6379f7b97945f3e1235ec70295b39ebeabf70fcaf1e61edb1c21a4c06"
+            },
+            Test {
+                input: "5c5faf66f32e0f8311c32e8da8284a4ed60891a5a7e50fb2956b3cbaa79fc66ca376460e100415401fc2b8518c64502f187ea14bfc9503759705",
+                output_str: "d51a3f33919fe5da0efea6edad201f01fa8416c385a89d96df743d243a6aaba5b7690d187b95caffdacd1e85f56b813b"
+            },
+            Test {
+                input: "7167e1e02be1a7ca69d788666f823ae4eef39271f3c26a5cf7cee05bca83161066dc2e217b330df821103799df6d74810eed363adc4ab99f36046a",
+                output_str: "f1d6e8f95c497d5beafb4215e07cdb59e0e3709cf561618f67e301931d204c6ce477e0f750099584b645e2f718650813"
+            },
+            Test {
+                input: "2fda311dbba27321c5329510fae6948f03210b76d43e7448d1689a063877b6d14c4f6d0eaa96c150051371f7dd8a4119f7da5c483cc3e6723c01fb7d",
+                output_str: "b1d347d057ccd72867b12bf00bf511f87defcd0fa6adadaf4bb1ad790f06ecbb1f4488a0319b05c46a7874857370ce76"
+            },
+            Test {
+                input: "95d1474a5aab5d2422aca6e481187833a6212bd2d0f91451a67dd786dfc91dfed51b35f47e1deb8a8ab4b9cb67b70179cc26f553ae7b569969ce151b8d",
+                output_str: "4f192edfa54fece64ac0b3ec9e120b291ade99948805a87bbb04947e928bb5eba87e2ee599960c436ea7c7884187e78c"
+            },
+            Test {
+                input: "c71bd7941f41df044a2927a8ff55b4b467c33d089f0988aa253d294addbdb32530c0d4208b10d9959823f0c0f0734684006df79f7099870f6bf53211a88d",
+                output_str: "75e23fed3b59db6b1d3378b7e8772642cbbff7710d8a91b249bb6c68e384cd416f19ac1e8ed92b71d0ca303d247ee9bd"
+            },
+            Test {
+                input: "f57c64006d9ea761892e145c99df1b24640883da79d9ed5262859dcda8c3c32e05b03d984f1ab4a230242ab6b78d368dc5aaa1e6d3498d53371e84b0c1d4ba",
+                output_str: "c8d1e6be5485fc13bf433f11a580abbe89b12a66d0e5cb141e1d62cdc6a367725793fb25840b36cb7003f2e7df3e5f2f"
+            },
+            Test {
+                input: "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7",
+                output_str: "423ba134d3bcb5e440ac83372c7eddba3ae3bddf1222f505c19cde246ad76a2b0d07239a54e1d0934c9b3d29d49e5fbd"
+            },
+            Test {
+                input: "16e8b3d8f988e9bb04de9c96f2627811c973ce4a5296b4772ca3eefeb80a652bdf21f50df79f32db23f9f73d393b2d57d9a0297f7a2f2e79cfda39fa393df1ac00",
+                output_str: "662c4851d311a786de4cda7e9ea1eff0bfa462761ff6cf804e591ed9a15b0dc93a2bb6a6cffdc8d7d23a233a52c86ead"
+            },
+            Test {
+                input: "fc424eeb27c18a11c01f39c555d8b78a805b88dba1dc2a42ed5e2c0ec737ff68b2456d80eb85e11714fa3f8eabfb906d3c17964cb4f5e76b29c1765db03d91be37fc",
+                output_str: "5f54b1dafa67ed9b498125e064f0b07f54e754e3f30720dd4a471e9bb6e307f05fb69bc81d391f503c95c3bb671e6973"
+            },
+            Test {
+                input: "abe3472b54e72734bdba7d9158736464251c4f21b33fbbc92d7fac9a35c4e3322ff01d2380cbaa4ef8fb07d21a2128b7b9f5b6d9f34e13f39c7ffc2e72e47888599ba5",
+                output_str: "a21b55ded8fe41fb2b193fa490420a8b62fcae9a185da85e253daefe85270b6904ba4ecc76bb5128926fff9d79f728ad"
+            },
+            Test {
+                input: "36f9f0a65f2ca498d739b944d6eff3da5ebba57e7d9c41598a2b0e4380f3cf4b479ec2348d015ffe6256273511154afcf3b4b4bf09d6c4744fdd0f62d75079d440706b05",
+                output_str: "341be5677a05eed816a219669d680bbf185b31cf3eb0d289f90210fb1a7940d9bff4909320ae4e3b7274e5be479c46f1"
+            },
+            Test {
+                input: "abc87763cae1ca98bd8c5b82caba54ac83286f87e9610128ae4de68ac95df5e329c360717bd349f26b872528492ca7c94c2c1e1ef56b74dbb65c2ac351981fdb31d06c77a4",
+                output_str: "d70f78894e292b075a0fe56fb952b2ce87a94ca029347159fbb12b22103dd4dc4c265b7ae88950cca89c40b531437aa4"
+            },
+            Test {
+                input: "94f7ca8e1a54234c6d53cc734bb3d3150c8ba8c5f880eab8d25fed13793a9701ebe320509286fd8e422e931d99c98da4df7e70ae447bab8cffd92382d8a77760a259fc4fbd72",
+                output_str: "89bd6b7cc9adddffe46bf85c56b8ce66e1b1b46969b197adbf2e34b7059d8bb05f9f53bd1a58a7e0a66e5ef208bf5695"
+            },
+            Test {
+                input: "13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d",
+                output_str: "ae651ef50a20b0f496f104f56f845206ed544b28d0374cbb779146dff2ea5894eb29301fe33872f9b299a79c0c0f28c4"
+            },
+            Test {
+                input: "1eed9cba179a009ec2ec5508773dd305477ca117e6d569e66b5f64c6bc64801ce25a8424ce4a26d575b8a6fb10ead3fd1992edddeec2ebe7150dc98f63adc3237ef57b91397aa8a7",
+                output_str: "a842918dfbbf3bffccc527b6dd2c0df4eb3f100f0692727da77daf44a654876013b37031c493ac18950003eebd107a29"
+            },
+            Test {
+                input: "ba5b67b5ec3a3ffae2c19dd8176a2ef75c0cd903725d45c9cb7009a900c0b0ca7a2967a95ae68269a6dbf8466c7b6844a1d608ac661f7eff00538e323db5f2c644b78b2d48de1a08aa",
+                output_str: "20d16cc6af5b4d5aeccead09f300b1dc1da93a608370ee0b2cf15c316508b5ef8c9be27d0f7288617b1e529fc2932038"
+            },
+            Test {
+                input: "0efa26ac5673167dcacab860932ed612f65ff49b80fa9ae65465e5542cb62075df1c5ae54fba4db807be25b070033efa223bdd5b1d3c94c6e1909c02b620d4b1b3a6c9fed24d70749604",
+                output_str: "69a3bb36f52eb650c6e8242db05659573af811a1a5db908f773d65e74d327f5b65303dd0dd9bd07ff100d050e46fe97d"
+            },
+            Test {
+                input: "bbfd933d1fd7bf594ac7f435277dc17d8d5a5b8e4d13d96d2f64e771abbd51a5a8aea741beccbddb177bcea05243ebd003cfdeae877cca4da94605b67691919d8b033f77d384ca01593c1b",
+                output_str: "d239f2fa1675a1a031e2f6e8a53d6e2f37d081cdb029727b3acbdd7cbfc7d3581bde8d3068aa9a300ae12b7245124508"
+            },
+            Test {
+                input: "90078999fd3c35b8afbf4066cbde335891365f0fc75c1286cdd88fa51fab94f9b8def7c9ac582a5dbcd95817afb7d1b48f63704e19c2baa4df347f48d4a6d603013c23f1e9611d595ebac37c",
+                output_str: "2f8d747ddf64320297b44f8547ef42fce78a48f0a59a18db1cfb9f43c049628f97c0bb93adaab9617155272424f74027"
+            },
+            Test {
+                input: "64105eca863515c20e7cfbaa0a0b8809046164f374d691cdbd6508aaabc1819f9ac84b52bafc1b0fe7cddbc554b608c01c8904c669d8db316a0953a4c68ece324ec5a49ffdb59a1bd6a292aa0e",
+                output_str: "714be6f2f934e0b6fd69e392d99acc98592b015e48a1637262f99286502b06774783bb9f371c760c3eb78aeadfbd0df0"
+            },
+            Test {
+                input: "d4654be288b9f3b711c2d02015978a8cc57471d5680a092aa534f7372c71ceaab725a383c4fcf4d8deaa57fca3ce056f312961eccf9b86f14981ba5bed6ab5b4498e1f6c82c6cae6fc14845b3c8a",
+                output_str: "22a41b117464f7f49682e8139a0d5bd23fe00d1190b1b419f27b490b729b56bba9de649dd7c988b6b308038661e1c362"
+            },
+            Test {
+                input: "12d9394888305ac96e65f2bf0e1b18c29c90fe9d714dd59f651f52b88b3008c588435548066ea2fc4c101118c91f32556224a540de6efddbca296ef1fb00341f5b01fecfc146bdb251b3bdad556cd2",
+                output_str: "77780f3646d288291790f2a5f4aa9c98a64a1115306994cd65c7620dde06d35117ce4b79dae08b5b4e798459010941bb"
+            },
+            Test {
+                input: "871a0d7a5f36c3da1dfce57acd8ab8487c274fad336bc137ebd6ff4658b547c1dcfab65f037aa58f35ef16aff4abe77ba61f65826f7be681b5b6d5a1ea8085e2ae9cd5cf0991878a311b549a6d6af230",
+                output_str: "5ced3b7368582dd6debfe41d6affd82b72894b51ff4c4accba09c595b36e23e347ab4baab0e5191d86e26e6596d62e23"
+            },
+            Test {
+                input: "e90b4ffef4d457bc7711ff4aa72231ca25af6b2e206f8bf859d8758b89a7cd36105db2538d06da83bad5f663ba11a5f6f61f236fd5f8d53c5e89f183a3cec615b50c7c681e773d109ff7491b5cc22296c5",
+                output_str: "1410ef9abb8d98b1c65e113a61915b0e6933bc59da31c8fcc39b7165e715919184375d822a07c778f63431be2aeecd99"
+            },
+            Test {
+                input: "e728de62d75856500c4c77a428612cd804f30c3f10d36fb219c5ca0aa30726ab190e5f3f279e0733d77e7267c17be27d21650a9a4d1e32f649627638dbada9702c7ca303269ed14014b2f3cf8b894eac8554",
+                output_str: "330ed51b045471dea8cff26510d68494611ecfd614d49e5a9cc8846a132519bbcf49907691ac5accfc0528da0c14d49e"
+            },
+            Test {
+                input: "6348f229e7b1df3b770c77544e5166e081850fa1c6c88169db74c76e42eb983facb276ad6a0d1fa7b50d3e3b6fcd799ec97470920a7abed47d288ff883e24ca21c7f8016b93bb9b9e078bdb9703d2b781b616e",
+                output_str: "387111a206fc6488f78d41786886a9e5ec9f73e1131d92f290f68512320a408d5f63eaa5aba32d9853eb11b5b0887e62"
+            },
+            Test {
+                input: "4b127fde5de733a1680c2790363627e63ac8a3f1b4707d982caea258655d9bf18f89afe54127482ba01e08845594b671306a025c9a5c5b6f93b0a39522dc877437be5c2436cbf300ce7ab6747934fcfc30aeaaf6",
+                output_str: "78573f5d075200d3823194a71e55880f4fe78489234dbf3df3e3734cbcae8dc1d8c1ae95f9efa9903dc4c4581b59ddde"
+            },
+            Test {
+                input: "08461f006cff4cc64b752c957287e5a0faabc05c9bff89d23fd902d324c79903b48fcb8f8f4b01f3e4ddb483593d25f000386698f5ade7faade9615fdc50d32785ea51d49894e45baa3dc707e224688c6408b68b11",
+                output_str: "fdfe4f1b034733c2c94a7b36e2b52774a95c2bde22fcddfcef52f7fef7c67f08e2f7b9b8967e447f76ef91960da76288"
+            },
+            Test {
+                input: "68c8f8849b120e6e0c9969a5866af591a829b92f33cd9a4a3196957a148c49138e1e2f5c7619a6d5edebe995acd81ec8bb9c7b9cfca678d081ea9e25a75d39db04e18d475920ce828b94e72241f24db72546b352a0e4",
+                output_str: "48d66a4165aa54528ece89bd9aa00eab196f32dfdc4d76f236655835527aaa1642e6bf4edf24f030f5eeef07fa40f5d2"
+            },
+            Test {
+                input: "b8d56472954e31fb54e28fca743f84d8dc34891cb564c64b08f7b71636debd64ca1edbdba7fc5c3e40049ce982bba8c7e0703034e331384695e9de76b5104f2fbc4535ecbeebc33bc27f29f18f6f27e8023b0fbb6f563c",
+                output_str: "3c2575372ce1f380a6e66bb075fbae98fc2e6d3d267a20ff0313abc3de252e03fd5bdfa8bc2b79fc874ccda4abdbb4a6"
+            },
+            Test {
+                input: "0d58ac665fa84342e60cefee31b1a4eacdb092f122dfc68309077aed1f3e528f578859ee9e4cefb4a728e946324927b675cd4f4ac84f64db3dacfe850c1dd18744c74ceccd9fe4dc214085108f404eab6d8f452b5442a47d",
+                output_str: "0ee6aeca8dd80b74225ac4882e2bc1e6819c9b94f0d0bc0a1e21aabf4b11cb74db4734bc8d1179d7dcef535be9f3da28"
+            },
+            Test {
+                input: "1755e2d2e5d1c1b0156456b539753ff416651d44698e87002dcf61dcfa2b4e72f264d9ad591df1fdee7b41b2eb00283c5aebb3411323b672eaa145c5125185104f20f335804b02325b6dea65603f349f4d5d8b782dd3469ccd",
+                output_str: "8027e5044923f8eee1df184865cd97b635a78da199fd80ad3d343a5ae03d1b165e58d1b0bd093ef916a16d6641bda17c"
+            },
+            Test {
+                input: "b180de1a611111ee7584ba2c4b020598cd574ac77e404e853d15a101c6f5a2e5c801d7d85dc95286a1804c870bb9f00fd4dcb03aa8328275158819dcad7253f3e3d237aeaa7979268a5db1c6ce08a9ec7c2579783c8afc1f91a7",
+                output_str: "796818e047913d5afb4ae4c5b7c5d5ef699a3a9ebefb44462ee8fe603ca5628973369e4a9d8e10115fdd75c89707a8f9"
+            },
+            Test {
+                input: "cf3583cbdfd4cbc17063b1e7d90b02f0e6e2ee05f99d77e24e560392535e47e05077157f96813544a17046914f9efb64762a23cf7a49fe52a0a4c01c630cfe8727b81fb99a89ff7cc11dca5173057e0417b8fe7a9efba6d95c555f",
+                output_str: "1e96eff62e9f464b4802972fdac77c3ea1131b2822619d2c5d863e357d0945c17f93ede66af05d46e63c2857a54f67f4"
+            },
+            Test {
+                input: "072fc02340ef99115bad72f92c01e4c093b9599f6cfc45cb380ee686cb5eb019e806ab9bd55e634ab10aa62a9510cc0672cd3eddb589c7df2b67fcd3329f61b1a4441eca87a33c8f55da4fbbad5cf2b2527b8e983bb31a2fadec7523",
+                output_str: "4cc41c2fb7d71da1ad36d18029f755daf342e732ec31f0c06e27091307718acb53fa113ae508df38b8c96834de33f9f1"
+            },
+            Test {
+                input: "76eecf956a52649f877528146de33df249cd800e21830f65e90f0f25ca9d6540fde40603230eca6760f1139c7f268deba2060631eea92b1fff05f93fd5572fbe29579ecd48bc3a8d6c2eb4a6b26e38d6c5fbf2c08044aeea470a8f2f26",
+                output_str: "9a8d4b560421c82991bdfca0898a29a59bdb09d20f8a5b279096723bab382789f081ead50d273eca436c526aba6d5cfc"
+            },
+            Test {
+                input: "7adc0b6693e61c269f278e6944a5a2d8300981e40022f839ac644387bfac9086650085c2cdc585fea47b9d2e52d65a2b29a7dc370401ef5d60dd0d21f9e2b90fae919319b14b8c5565b0423cefb827d5f1203302a9d01523498a4db10374",
+                output_str: "367cb3fe03a3cbb50fae1fe7ea883a0ae53cbe772f709dc5505f3c907564c08fc49707cff9639b25c746b6039ff48ae9"
+            },
+            Test {
+                input: "e1fffa9826cce8b86bccefb8794e48c46cdf372013f782eced1e378269b7be2b7bf51374092261ae120e822be685f2e7a83664bcfbe38fe8633f24e633ffe1988e1bc5acf59a587079a57a910bda60060e85b5f5b6f776f0529639d9cce4bd",
+                output_str: "bbbd05d69d7a082fcda8ed535d7e4e5de1377bd91e72d42dc95295c9db780169e2f9620ec7a5aff959ff2d946fd20a72"
+            },
+            Test {
+                input: "69f9abba65592ee01db4dce52dbab90b08fc04193602792ee4daa263033d59081587b09bbe49d0b49c9825d22840b2ff5d9c5155f975f8f2c2e7a90c75d2e4a8040fe39f63bbafb403d9e28cc3b86e04e394a9c9e8065bd3c85fa9f0c7891600",
+                output_str: "be8bec0c2ec721e0c326037ce86a1518fb395c3a9802de01c3e234268ebb9ac9a39a6e404f25fb7febdcf1f7f25dc083"
+            },
+            Test {
+                input: "38a10a352ca5aedfa8e19c64787d8e9c3a75dbf3b8674bfab29b5dbfc15a63d10fae66cd1a6e6d2452d557967eaad89a4c98449787b0b3164ca5b717a93f24eb0b506ceb70cbbcb8d72b2a72993f909aad92f044e0b5a2c9ac9cb16a0ca2f81f49",
+                output_str: "2aeeaf292ad625221ba79a621217fd1b3f8978ba83fe7ff13b38574fcfaffbd207298854b6f9c27d6677494204221fda"
+            },
+            Test {
+                input: "6d8c6e449bc13634f115749c248c17cd148b72157a2c37bf8969ea83b4d6ba8c0ee2711c28ee11495f43049596520ce436004b026b6c1f7292b9c436b055cbb72d530d860d1276a1502a5140e3c3f54a93663e4d20edec32d284e25564f624955b52",
+                output_str: "9a1761c5759ce67c9c093ec5c831c1ff7cab64ac7c8002066edcaed044def57cea3ef6be98578363d2ce3d1f5ba448f8"
+            },
+            Test {
+                input: "6efcbcaf451c129dbe00b9cef0c3749d3ee9d41c7bd500ade40cdc65dedbbbadb885a5b14b32a0c0d087825201e303288a733842fa7e599c0c514e078f05c821c7a4498b01c40032e9f1872a1c925fa17ce253e8935e4c3c71282242cb716b2089ccc1",
+                output_str: "4a24a1af68db65c3977431ee81092c776f7cb33d6f08940100ea240a2d1f8623a41d07ce9937bcbec8ca1072a1a78e8b"
+            },
+            Test {
+                input: "433c5303131624c0021d868a30825475e8d0bd3052a022180398f4ca4423b98214b6beaac21c8807a2c33f8c93bd42b092cc1b06cedf3224d5ed1ec29784444f22e08a55aa58542b524b02cd3d5d5f6907afe71c5d7462224a3f9d9e53e7e0846dcbb4ce",
+                output_str: "928e94d19fc60065a5ef7e48018387c80f2d350f306d0f610173719d5c874d4a8acc340fead4be357e1f78124198ad77"
+            },
+            Test {
+                input: "a873e0c67ca639026b6683008f7aa6324d4979550e9bce064ca1e1fb97a30b147a24f3f666c0a72d71348ede701cf2d17e2253c34d1ec3b647dbcef2f879f4eb881c4830b791378c901eb725ea5c172316c6d606e0af7df4df7f76e490cd30b2badf45685f",
+                output_str: "78a18d62f8a7eff5c6dd75b8cb073fd30ee68c878c2ec58aad1c5dd0eb0ae43698a617bb0c670fce2aa098e0adf425b2"
+            },
+            Test {
+                input: "006917b64f9dcdf1d2d87c8a6173b64f6587168e80faa80f82d84f60301e561e312d9fbce62f39a6fb476e01e925f26bcc91de621449be6504c504830aae394096c8fc7694651051365d4ee9070101ec9b68086f2ea8f8ab7b811ea8ad934d5c9b62c60a4771",
+                output_str: "eeeb56c3e54fa833b985efa5923c3f0225f419664cedd898c79f64d72d2ad4b125a38be0201846c442eaf0051d516dc9"
+            },
+            Test {
+                input: "f13c972c52cb3cc4a4df28c97f2df11ce089b815466be88863243eb318c2adb1a417cb1041308598541720197b9b1cb5ba2318bd5574d1df2174af14884149ba9b2f446d609df240ce335599957b8ec80876d9a085ae084907bc5961b20bf5f6ca58d5dab38adb",
+                output_str: "0a834e111b4e840e787c19748465a47d88b3f0f3daaf15db25536bdc6078fa9c05e6c953830274223968847da8bfd20d"
+            },
+            Test {
+                input: "e35780eb9799ad4c77535d4ddb683cf33ef367715327cf4c4a58ed9cbdcdd486f669f80189d549a9364fa82a51a52654ec721bb3aab95dceb4a86a6afa93826db923517e928f33e3fba850d45660ef83b9876accafa2a9987a254b137c6e140a21691e1069413848",
+                output_str: "d1c0fa85c8d183beff99ad9d752b263e286b477f79f0710b010317017397813344b99daf3bb7b1bc5e8d722bac85943a"
+            },
+            Test {
+                input: "64ec021c9585e01ffe6d31bb50d44c79b6993d72678163db474947a053674619d158016adb243f5c8d50aa92f50ab36e579ff2dabb780a2b529370daa299207cfbcdd3a9a25006d19c4f1fe33e4b1eaec315d8c6ee1e730623fd1941875b924eb57d6d0c2edc4e78d6",
+                output_str: "6aedcf4426b2483c0d0d04695bcc052bedd04fa4d17a1bbb2797f6272fa476bfc138e4091409feb1ac0e8bff350a6663"
+            },
+            Test {
+                input: "5954bab512cf327d66b5d9f296180080402624ad7628506b555eea8382562324cf452fba4a2130de3e165d11831a270d9cb97ce8c2d32a96f50d71600bb4ca268cf98e90d6496b0a6619a5a8c63db6d8a0634dfc6c7ec8ea9c006b6c456f1b20cd19e781af20454ac880",
+                output_str: "acb7013ce75124388187dc0e7430cb74a314d601b6c8d7a7de5cf03197a84f7874ff058808575cb2f10185f561bb06b1"
+            },
+            Test {
+                input: "03d9f92b2c565709a568724a0aff90f8f347f43b02338f94a03ed32e6f33666ff5802da4c81bdce0d0e86c04afd4edc2fc8b4141c2975b6f07639b1994c973d9a9afce3d9d365862003498513bfa166d2629e314d97441667b007414e739d7febf0fe3c32c17aa188a8683",
+                output_str: "f947469db712ea26f25f709ff7879136ea2a79e0a2d0ed5ee4adf0e167f106bc410c93ae1d986ec211e0fd9a40741857"
+            },
+            Test {
+                input: "f31e8b4f9e0621d531d22a380be5d9abd56faec53cbd39b1fab230ea67184440e5b1d15457bd25f56204fa917fa48e669016cb48c1ffc1e1e45274b3b47379e00a43843cf8601a5551411ec12503e5aac43d8676a1b2297ec7a0800dbfee04292e937f21c005f17411473041",
+                output_str: "65989bf4ebbf4c21b3dd34551d3f6167910236671bb7f348dc552adb8028a468fa40ef4a8c1227a1a41c28105e64ac20"
+            },
+            Test {
+                input: "758ea3fea738973db0b8be7e599bbef4519373d6e6dcd7195ea885fc991d896762992759c2a09002912fb08e0cb5b76f49162aeb8cf87b172cf3ad190253df612f77b1f0c532e3b5fc99c2d31f8f65011695a087a35ee4eee5e334c369d8ee5d29f695815d866da99df3f79403",
+                output_str: "b77a69e373af0f733cdad399c9b12642a046e1a7893d3382943a8367d37740df53916f6daf90517b39621c14343754a2"
+            },
+            Test {
+                input: "47c6e0c2b74948465921868804f0f7bd50dd323583dc784f998a93cd1ca4c6ef84d41dc81c2c40f34b5bee6a93867b3bdba0052c5f59e6f3657918c382e771d33109122cc8bb0e1e53c4e3d13b43ce44970f5e0c079d2ad7d7a3549cd75760c21bb15b447589e86e8d76b1e9ced2",
+                output_str: "3d14b6fae6156e7876367897a49269181ea58cc3ca9621c0f81d6a5fb6f615680d909b29f6af7e62fad04d70046be997"
+            },
+            Test {
+                input: "f690a132ab46b28edfa6479283d6444e371c6459108afd9c35dbd235e0b6b6ff4c4ea58e7554bd002460433b2164ca51e868f7947d7d7a0d792e4abf0be5f450853cc40d85485b2b8857ea31b5ea6e4ccfa2f3a7ef3380066d7d8979fdac618aad3d7e886dea4f005ae4ad05e5065f",
+                output_str: "456ad01908e187ca2ce9e7a4daed8788c909e9bc974efd1c9a44ac36db9b6da985c947c7e0a47ab27bf10cd760fa48af"
+            },
+            Test {
+                input: "58d6a99bc6458824b256916770a8417040721cccfd4b79eacd8b65a3767ce5ba7e74104c985ac56b8cc9aebd16febd4cda5adb130b0ff2329cc8d611eb14dac268a2f9e633c99de33997fea41c52a7c5e1317d5b5daed35eba7d5a60e45d1fa7eaabc35f5c2b0a0f2379231953322c4e",
+                output_str: "c26bdac454e1adc0d090d0c5254a29966611b6673014cbaca24d26b6f63ec7e8f993ba3df7df89770e902d5f6574f6a8"
+            },
+            Test {
+                input: "befab574396d7f8b6705e2d5b58b2c1c820bb24e3f4bae3e8fbcd36dbf734ee14e5d6ab972aedd3540235466e825850ee4c512ea9795abfd33f330d9fd7f79e62bbb63a6ea85de15beaeea6f8d204a28956059e2632d11861dfb0e65bc07ac8a159388d5c3277e227286f65ff5e5b5aec1",
+                output_str: "1d85bf9aa2b6dcc3105e7d7f91069f01e4c998d6f03b77650d75839d65a7a049196fd935afeffdeb657bc8f96b7c17b5"
+            },
+            Test {
+                input: "8e58144fa9179d686478622ce450c748260c95d1ba43b8f9b59abeca8d93488da73463ef40198b4d16fb0b0707201347e0506ff19d01bea0f42b8af9e71a1f1bd168781069d4d338fdef00bf419fbb003031df671f4a37979564f69282de9c65407847dd0da505ab1641c02dea4f0d834986",
+                output_str: "085cfa581cf3f4f19416bee3ed5ac2544662aa51bdf1d2e348d9bcc27343487df20b18d9f6fb64565868504a6805d176"
+            },
+            Test {
+                input: "b55c10eae0ec684c16d13463f29291bf26c82e2fa0422a99c71db4af14dd9c7f33eda52fd73d017cc0f2dbe734d831f0d820d06d5f89dacc485739144f8cfd4799223b1aff9031a105cb6a029ba71e6e5867d85a554991c38df3c9ef8c1e1e9a7630be61caabca69280c399c1fb7a12d12aefc",
+                output_str: "376088f09039caa40bf19ff5e5f193fc9ecb6116a0acb3237aaab6cd807bd7af45d804d837a18d2bd9a8c3daa3a1d153"
+            },
+            Test {
+                input: "2eeea693f585f4ed6f6f8865bbae47a6908aecd7c429e4bec4f0de1d0ca0183fa201a0cb14a529b7d7ac0e6ff6607a3243ee9fb11bcf3e2304fe75ffcddd6c5c2e2a4cd45f63c962d010645058d36571404a6d2b4f44755434d76998e83409c3205aa1615db44057db991231d2cb42624574f545",
+                output_str: "cd40b35fbd90b04d0641f71088f7c6159d8eb16de8aae09f355877a0333b53150b81d36c5c2446bf5ac462ef84d4e572"
+            },
+            Test {
+                input: "dab11dc0b047db0420a585f56c42d93175562852428499f66a0db811fcdddab2f7cdffed1543e5fb72110b64686bc7b6887a538ad44c050f1e42631bc4ec8a9f2a047163d822a38989ee4aab01b4c1f161b062d873b1cfa388fd301514f62224157b9bef423c7783b7aac8d30d65cd1bba8d689c2d",
+                output_str: "db14442400597871fa56d10f53be7bb4002c44624c44e89c99b95122676a76ff28840285239e2e4fbfb751e4179577d8"
+            },
+            Test {
+                input: "42e99a2f80aee0e001279a2434f731e01d34a44b1a8101726921c0590c30f3120eb83059f325e894a5ac959dca71ce2214799916424e859d27d789437b9d27240bf8c35adbafcecc322b48aa205b293962d858652abacbd588bcf6cbc388d0993bd622f96ed54614c25b6a9aa527589eaaffcf17ddf7",
+                output_str: "4509adb6177bc6debca7e36948f07001159a57ec8cca2b76c770735c5bccc679da6ab4e64d915d0e1a754c3fda11b524"
+            },
+            Test {
+                input: "3c9b46450c0f2cae8e3823f8bdb4277f31b744ce2eb17054bddc6dff36af7f49fb8a2320cc3bdf8e0a2ea29ad3a55de1165d219adeddb5175253e2d1489e9b6fdd02e2c3d3a4b54d60e3a47334c37913c5695378a669e9b72dec32af5434f93f46176ebf044c4784467c700470d0c0b40c8a088c815816",
+                output_str: "193af71bdd228ab3e8ae50e1b1cbf1984b0af92aac5a71cbe618afd4187ded6b461411a39e72ea4e213fe0a5231c498d"
+            },
+            Test {
+                input: "d1e654b77cb155f5c77971a64df9e5d34c26a3cad6c7f6b300d39deb1910094691adaa095be4ba5d86690a976428635d5526f3e946f7dc3bd4dbc78999e653441187a81f9adcd5a3c5f254bc8256b0158f54673dcc1232f6e918ebfc6c51ce67eaeb042d9f57eec4bfe910e169af78b3de48d137df4f2840",
+                output_str: "3e419569a4197bb71baf416b38772eedd9c1d5a3252111609f0ff8a18a749d5a56143a14925a82cd35c44400a49afdfb"
+            },
+            Test {
+                input: "626f68c18a69a6590159a9c46be03d5965698f2dac3de779b878b3d9c421e0f21b955a16c715c1ec1e22ce3eb645b8b4f263f60660ea3028981eebd6c8c3a367285b691c8ee56944a7cd1217997e1d9c21620b536bdbd5de8925ff71dec6fbc06624ab6b21e329813de90d1e572dfb89a18120c3f606355d25",
+                output_str: "6215c070d0cb388a134766035c4ba95143e608d15caf742796304ffa1a62e55660ab9ab1f6538b4af1f3ea89be7d51ff"
+            },
+            Test {
+                input: "651a6fb3c4b80c7c68c6011675e6094eb56abf5fc3057324ebc6477825061f9f27e7a94633abd1fa598a746e4a577caf524c52ec1788471f92b8c37f23795ca19d559d446cab16cbcdce90b79fa1026cee77bf4ab1b503c5b94c2256ad75b3eac6fd5dcb96aca4b03a834bfb4e9af988cecbf2ae597cb9097940",
+                output_str: "0e27abad85255a66217722b7d4e032bf29f638bae965b99f8eaf309071ff8c107f5b6bbb6ab1985228e697de60595df6"
+            },
+            Test {
+                input: "8aaf072fce8a2d96bc10b3c91c809ee93072fb205ca7f10abd82ecd82cf040b1bc49ea13d1857815c0e99781de3adbb5443ce1c897e55188ceaf221aa9681638de05ae1b322938f46bce51543b57ecdb4c266272259d1798de13be90e10efec2d07484d9b21a3870e2aa9e06c21aa2d0c9cf420080a80a91dee16f",
+                output_str: "ab9fd51b3aa4cd944abb6cdb063708b2d1203d65a1a2ebb48e0c19722a18b9ef54d7a11f7684462b995b6d38cddc0463"
+            },
+            Test {
+                input: "53f918fd00b1701bd504f8cdea803acca21ac18c564ab90c2a17da592c7d69688f6580575395551e8cd33e0fef08ca6ed4588d4d140b3e44c032355df1c531564d7f4835753344345a6781e11cd5e095b73df5f82c8ae3ad00877936896671e947cc52e2b29dcd463d90a0c9929128da222b5a211450bbc0e02448e2",
+                output_str: "03945325ac50e56bc8b515576529abaa9a22bc2a7ced9142a75ce939a388af0022a4e75a33964bbb3580564e0af809d3"
+            },
+            Test {
+                input: "a64599b8a61b5ccec9e67aed69447459c8da3d1ec6c7c7c82a7428b9b584fa67e90f68e2c00fbbed4613666e5168da4a16f395f7a3c3832b3b134bfc9cbaa95d2a0fe252f44ac6681eb6d40ab91c1d0282fed6701c57463d3c5f2bb8c6a7301fb4576aa3b5f15510db8956ff77478c26a7c09bea7b398cfc83503f538e",
+                output_str: "59126910a3462e3b7ac22892f637d87d90686bc0a9bbd4a32e2c4c71a168ba685f2184560e125db3dc23d90b9e820f1a"
+            },
+            Test {
+                input: "0e3ab0e054739b00cdb6a87bd12cae024b54cb5e550e6c425360c2e87e59401f5ec24ef0314855f0f56c47695d56a7fb1417693af2a1ed5291f2fee95f75eed54a1b1c2e81226fbff6f63ade584911c71967a8eb70933bc3f5d15bc91b5c2644d9516d3c3a8c154ee48e118bd1442c043c7a0dba5ac5b1d5360aae5b9065",
+                output_str: "d3239a33baa55b0f21169e0fde6114b08106baf3f4ba0ca19d7b5cf44030057ac672ce529eb0f3bda36819967819aafa"
+            },
+            Test {
+                input: "a62fc595b4096e6336e53fcdfc8d1cc175d71dac9d750a6133d23199eaac288207944cea6b16d27631915b4619f743da2e30a0c00bbdb1bbb35ab852ef3b9aec6b0a8dcc6e9e1abaa3ad62ac0a6c5de765de2c3711b769e3fde44a74016fff82ac46fa8f1797d3b2a726b696e3dea5530439acee3a45c2a51bc32dd055650b",
+                output_str: "38a11581d874a574929c51f8dcc9e501900743864aec3ac0889e62c1071ca5f8b6ccf9c0bdb3bb365916eb4340973dc7"
+            },
+            Test {
+                input: "2b6db7ced8665ebe9deb080295218426bdaa7c6da9add2088932cdffbaa1c14129bccdd70f369efb149285858d2b1d155d14de2fdb680a8b027284055182a0cae275234cc9c92863c1b4ab66f304cf0621cd54565f5bff461d3b461bd40df28198e3732501b4860eadd503d26d6e69338f4e0456e9e9baf3d827ae685fb1d817",
+                output_str: "8fd01909381eb713803419361d8e82e92476a08edcc225bb8a135d215cb48d07b074624fcf2e73e666dba59334719839"
+            },
+            Test {
+                input: "10db509b2cdcaba6c062ae33be48116a29eb18e390e1bbada5ca0a2718afbcd23431440106594893043cc7f2625281bf7de2655880966a23705f0c5155c2f5cca9f2c2142e96d0a2e763b70686cd421b5db812daced0c6d65035fde558e94f26b3e6dde5bd13980cc80292b723013bd033284584bff27657871b0cf07a849f4ae2",
+                output_str: "5d7dc5fc9de88b1c0c46aa6d49273505ff7a76a179e31ab5d976a69d89b83dfa6deae9e1b93440ec055de1cc824d6b15"
+            },
+            Test {
+                input: "9334de60c997bda6086101a6314f64e4458f5ff9450c509df006e8c547983c651ca97879175aaba0c539e82d05c1e02c480975cbb30118121061b1ebac4f8d9a3781e2db6b18042e01ecf9017a64a0e57447ec7fcbe6a7f82585f7403ee2223d52d37b4bf426428613d6b4257980972a0acab508a7620c1cb28eb4e9d30fc41361ec",
+                output_str: "3d6bba145d7e69dbbb0f099d47a1f2138d4a00f26b07c62cf38471f0fb9ca022c61f7a769013a9bd8d5d87d8e01d9b4d"
+            },
+            Test {
+                input: "e88ab086891693aa535ceb20e64c7ab97c7dd3548f3786339897a5f0c39031549ca870166e477743ccfbe016b4428d89738e426f5ffe81626137f17aecff61b72dbee2dc20961880cfe281dfab5ee38b1921881450e16032de5e4d55ad8d4fca609721b0692bac79be5a06e177fe8c80c0c83519fb3347de9f43d5561cb8107b9b5edc",
+                output_str: "fbcef80dd06e7e0b3b7a5485ca5bc2b388cb91a2890f181c857b3e0abefd6065499d82dd55f3fcd17e351c0a3636b859"
+            },
+            Test {
+                input: "fd19e01a83eb6ec810b94582cb8fbfa2fcb992b53684fb748d2264f020d3b960cb1d6b8c348c2b54a9fcea72330c2aaa9a24ecdb00c436abc702361a82bb8828b85369b8c72ece0082fe06557163899c2a0efa466c33c04343a839417057399a63a3929be1ee4805d6ce3e5d0d0967fe9004696a5663f4cac9179006a2ceb75542d75d68",
+                output_str: "338aacbac8ac5bcc13fafc0ec6d2ecf4a871f9b09d7b1bc5bd6f8d7c9dd1354b8e28c68158a36551dddab8b684579ee1"
+            },
+            Test {
+                input: "59ae20b6f7e0b3c7a989afb28324a40fca25d8651cf1f46ae383ef6d8441587aa1c04c3e3bf88e8131ce6145cfb8973d961e8432b202fa5af3e09d625faad825bc19da9b5c6c20d02abda2fcc58b5bd3fe507bf201263f30543819510c12bc23e2ddb4f711d087a86edb1b355313363a2de996b891025e147036087401ccf3ca7815bf3c49",
+                output_str: "ffc98d84c268bd09cad09cd7b4bf9d35ede97ec55885e839e557d21ecc0e28a855000386e68faae3e64a19b443b2587d"
+            },
+            Test {
+                input: "77ee804b9f3295ab2362798b72b0a1b2d3291dceb8139896355830f34b3b328561531f8079b79a6e9980705150866402fdc176c05897e359a6cb1a7ab067383eb497182a7e5aef7038e4c96d133b2782917417e391535b5e1b51f47d8ed7e4d4025fe98dc87b9c1622614bff3d1029e68e372de719803857ca52067cddaad958951cb2068cc6",
+                output_str: "471465890c3b9c03edfbf0f6883d565740bada3b7628ad6a27f729c35c1a8666953e8b99d2c89ede0bd2d5d70fdef11b"
+            },
+            Test {
+                input: "b771d5cef5d1a41a93d15643d7181d2a2ef0a8e84d91812f20ed21f147bef732bf3a60ef4067c3734b85bc8cd471780f10dc9e8291b58339a677b960218f71e793f2797aea349406512829065d37bb55ea796fa4f56fd8896b49b2cd19b43215ad967c712b24e5032d065232e02c127409d2ed4146b9d75d763d52db98d949d3b0fed6a8052fbb",
+                output_str: "0f8ba7214de0e3a9e13c282bfa09cea782c31c052f516d0aaa403d97716e0d08b1f7f9bb4085b555740c813c4ece1b90"
+            },
+            Test {
+                input: "b32d95b0b9aad2a8816de6d06d1f86008505bd8c14124f6e9a163b5a2ade55f835d0ec3880ef50700d3b25e42cc0af050ccd1be5e555b23087e04d7bf9813622780c7313a1954f8740b6ee2d3f71f768dd417f520482bd3a08d4f222b4ee9dbd015447b33507dd50f3ab4247c5de9a8abd62a8decea01e3b87c8b927f5b08beb37674c6f8e380c04",
+                output_str: "cad2d28fbdcc3a5d71fb3adceec52313ad41d4ff1f915caa34ee127839dbf2e9a7b06e1c4ecd6255926c16c06e51efd0"
+            },
+            Test {
+                input: "04410e31082a47584b406f051398a6abe74e4da59bb6f85e6b49e8a1f7f2ca00dfba5462c2cd2bfde8b64fb21d70c083f11318b56a52d03b81cac5eec29eb31bd0078b6156786da3d6d8c33098c5c47bb67ac64db14165af65b44544d806dde5f487d5373c7f9792c299e9686b7e5821e7c8e2458315b996b5677d926dac57b3f22da873c601016a0d",
+                output_str: "5b192ebab47215a8e9fb8e4d561b220b1dc36707a3f085f7bb0175335c393251e3467f945570420c743365d0f09b9e09"
+            },
+            Test {
+                input: "8b81e9badde026f14d95c019977024c9e13db7a5cd21f9e9fc491d716164bbacdc7060d882615d411438aea056c340cdf977788f6e17d118de55026855f93270472d1fd18b9e7e812bae107e0dfde7063301b71f6cfe4e225cab3b232905a56e994f08ee2891ba922d49c3dafeb75f7c69750cb67d822c96176c46bd8a29f1701373fb09a1a6e3c7158f",
+                output_str: "df6f80b6d56cffa8545a27a245a50e6c2d117fc3598f465b6cd78560f4b3c7d2123f28f67ca9e65bfe0b7f566c57b9ef"
+            },
+            Test {
+                input: "fa6eed24da6666a22208146b19a532c2ec9ba94f09f1def1e7fc13c399a48e41acc2a589d099276296348f396253b57cb0e40291bd282773656b6e0d8bea1cda084a3738816a840485fcf3fb307f777fa5feac48695c2af4769720258c77943fb4556c362d9cba8bf103aeb9034baa8ea8bfb9c4f8e6742ce0d52c49ea8e974f339612e830e9e7a9c29065",
+                output_str: "ce97e9df08789d84151a95c8134f0db74e5d4e076e0c15966825c371b79b3192fd7c9c6bdae86b775804b5363d1152c7"
+            },
+            Test {
+                input: "9bb4af1b4f09c071ce3cafa92e4eb73ce8a6f5d82a85733440368dee4eb1cbc7b55ac150773b6fe47dbe036c45582ed67e23f4c74585dab509df1b83610564545642b2b1ec463e18048fc23477c6b2aa035594ecd33791af6af4cbc2a1166aba8d628c57e707f0b0e8707caf91cd44bdb915e0296e0190d56d33d8dde10b5b60377838973c1d943c22ed335e",
+                output_str: "89bf889fbd7a384290d3b1d52709dba686351e53937630b7c7f01bcdda19b1517d317d65e799e686c71a0ab4d65b60b8"
+            },
+            Test {
+                input: "2167f02118cc62043e9091a647cadbed95611a521fe0d64e8518f16c808ab297725598ae296880a773607a798f7c3cfce80d251ebec6885015f9abf7eaabae46798f82cb5926de5c23f44a3f9f9534b3c6f405b5364c2f8a8bdc5ca49c749bed8ce4ba48897062ae8424ca6dde5f55c0e42a95d1e292ca54fb46a84fbc9cd87f2d0c9e7448de3043ae22fdd229",
+                output_str: "5d40e392c2e5b29c80c2d760a93aa1e193472d7ee59e203dd478fe24c5a6264e2873af31abde81827862901ae59571bb"
+            },
+            Test {
+                input: "94b7fa0bc1c44e949b1d7617d31b4720cbe7ca57c6fa4f4094d4761567e389ecc64f6968e4064df70df836a47d0c713336b5028b35930d29eb7a7f9a5af9ad5cf441745baec9bb014ceeff5a41ba5c1ce085feb980bab9cf79f2158e03ef7e63e29c38d7816a84d4f71e0f548b7fc316085ae38a060ff9b8dec36f91ad9ebc0a5b6c338cbb8f6659d342a24368cf",
+                output_str: "7c63a0dc1c39cf4fab2d22f62c1b00757aa4b89ed0d7128da243d9082ad0c78784ac24df34f5ab30375f1d581e7420bd"
+            },
+            Test {
+                input: "ea40e83cb18b3a242c1ecc6ccd0b7853a439dab2c569cfc6dc38a19f5c90acbf76aef9ea3742ff3b54ef7d36eb7ce4ff1c9ab3bc119cff6be93c03e208783335c0ab8137be5b10cdc66ff3f89a1bddc6a1eed74f504cbe7290690bb295a872b9e3fe2cee9e6c67c41db8efd7d863cf10f840fe618e7936da3dca5ca6df933f24f6954ba0801a1294cd8d7e66dfafec",
+                output_str: "ed085d830afd2d8f79627281c2a8163c391fec2c58268f66f74cff9751bb29e0d071ea8fd2fcf943020d0ad758281bfd"
+            },
+            Test {
+                input: "157d5b7e4507f66d9a267476d33831e7bb768d4d04cc3438da12f9010263ea5fcafbde2579db2f6b58f911d593d5f79fb05fe3596e3fa80ff2f761d1b0e57080055c118c53e53cdb63055261d7c9b2b39bd90acc32520cbbdbda2c4fd8856dbcee173132a2679198daf83007a9b5c51511ae49766c792a29520388444ebefe28256fb33d4260439cba73a9479ee00c63",
+                output_str: "29124752ccd4ac724a9c3d53b0b352af2dbd76729f8c5c648b1e9d77819f32e2a7de0e15286478a24df9bb370f855c1c"
+            },
+            Test {
+                input: "836b34b515476f613fe447a4e0c3f3b8f20910ac89a3977055c960d2d5d2b72bd8acc715a9035321b86703a411dde0466d58a59769672aa60ad587b8481de4bba552a1645779789501ec53d540b904821f32b0bd1855b04e4848f9f8cfe9ebd8911be95781a759d7ad9724a7102dbe576776b7c632bc39b9b5e19057e226552a5994c1dbb3b5c7871a11f5537011044c53",
+                output_str: "faeab5687f39ec9894c5ccffb57e82a84bbb7d493cc6afc03d07ac7b4f181e61639b9a4771c99985ed7fa1773e1ca3f4"
+            },
+            Test {
+                input: "cc7784a4912a7ab5ad3620aab29ba87077cd3cb83636adc9f3dc94f51edf521b2161ef108f21a0a298557981c0e53ce6ced45bdf782c1ef200d29bab81dd6460586964edab7cebdbbec75fd7925060f7da2b853b2b089588fa0f8c16ec6498b14c55dcee335cb3a91d698e4d393ab8e8eac0825f8adebeee196df41205c011674e53426caa453f8de1cbb57932b0b741d4c6",
+                output_str: "e4e352b1d2d987a37c831629fe0c6ab9eab2c35e401d1b5f443adc54a96ef3c91d0876ccf46adef819c460369136da87"
+            },
+            Test {
+                input: "7639b461fff270b2455ac1d1afce782944aea5e9087eb4a39eb96bb5c3baaf0e868c8526d3404f9405e79e77bfac5ffb89bf1957b523e17d341d7323c302ea7083872dd5e8705694acdda36d5a1b895aaa16eca6104c82688532c8bfe1790b5dc9f4ec5fe95baed37e1d287be710431f1e5e8ee105bc42ed37d74b1e55984bf1c09fe6a1fa13ef3b96faeaed6a2a1950a12153",
+                output_str: "6c288fe4a74f0ed1b36d12f2db697fbc44017bb57d38c9ebd45f5a8b4feb59148060ae4ba1ffa162e10e6916cea1a794"
+            },
+            Test {
+                input: "eb6513fc61b30cfba58d4d7e80f94d14589090cf1d80b1df2e68088dc6104959ba0d583d585e9578ab0aec0cf36c48435eb52ed9ab4bbce7a5abe679c97ae2dbe35e8cc1d45b06dda3cf418665c57cbee4bbb47fa4caf78f4ee656fec237fe4eebbafa206e1ef2bd0ee4ae71bd0e9b2f54f91daadf1febfd7032381d636b733dcb3bf76fb14e23aff1f68ed3dbcf75c9b99c6f26",
+                output_str: "e1b6dac3f138b5f336f1f75894f825ffc197836c92bf359b55bb2a78239f24f9c4aa1e063c9c2b273b9cfa766fbfbae5"
+            },
+            Test {
+                input: "1594d74bf5dde444265d4c04dad9721ff3e34cbf622daf341fe16b96431f6c4df1f760d34f296eb97d98d560ad5286fec4dce1724f20b54fd7df51d4bf137add656c80546fb1bf516d62ee82baa992910ef4cc18b70f3f8698276fcfb44e0ec546c2c39cfd8ee91034ff9303058b4252462f86c823eb15bf481e6b79cc3a02218595b3658e8b37382bd5048eaed5fd02c37944e73b",
+                output_str: "6e07b59e93b22475633b5ba1aa6891119cff690697ac679e9349e8694c654074d965f0c32ff517b10ee8f6993f6e4646"
+            },
+            Test {
+                input: "4cfa1278903026f66fedd41374558be1b585d03c5c55dac94361df286d4bd39c7cb8037ed3b267b07c346626449d0cc5b0dd2cf221f7e4c3449a4be99985d2d5e67bff2923357ddeab5abcb4619f3a3a57b2cf928a022eb27676c6cf805689004fca4d41ea6c2d0a4789c7605f7bb838dd883b3ad3e6027e775bcf262881428099c7fff95b14c095ea130e0b9938a5e22fc52650f591",
+                output_str: "19eb2e15262a839538846f7252676971207913279b9ae9b6ba3650d8f3a8e558b13c35b31f1ab7429e376255338c4aa2"
+            },
+            Test {
+                input: "d3e65cb92cfa79662f6af493d696a07ccf32aaadcceff06e73e8d9f6f909209e66715d6e978788c49efb9087b170ecf3aa86d2d4d1a065ae0efc8924f365d676b3cb9e2bec918fd96d0b43dee83727c9a93bf56ca2b2e59adba85696546a815067fc7a78039629d4948d157e7b0d826d1bf8e81237bab7321312fdaa4d521744f988db6fdf04549d0fdca393d639c729af716e9c8bba48",
+                output_str: "f4da80b26fb5e6f7e5dfe47128eee095d46d9acefbe76f74efbc8a1ad68e8456634e9376025648ef7a3350299f366e29"
+            },
+            Test {
+                input: "842cc583504539622d7f71e7e31863a2b885c56a0ba62db4c2a3f2fd12e79660dc7205ca29a0dc0a87db4dc62ee47a41db36b9ddb3293b9ac4baae7df5c6e7201e17f717ab56e12cad476be49608ad2d50309e7d48d2d8de4fa58ac3cfeafeee48c0a9eec88498e3efc51f54d300d828dddccb9d0b06dd021a29cf5cb5b2506915beb8a11998b8b886e0f9b7a80e97d91a7d01270f9a7717",
+                output_str: "bdba7838a1e7a601d559f49ec1323b7c5fabe1e109fdcaff3f7865f9af4196abbf60ac123097a7b860fe438684355eb0"
+            },
+            Test {
+                input: "6c4b0a0719573e57248661e98febe326571f9a1ca813d3638531ae28b4860f23c3a3a8ac1c250034a660e2d71e16d3acc4bf9ce215c6f15b1c0fc7e77d3d27157e66da9ceec9258f8f2bf9e02b4ac93793dd6e29e307ede3695a0df63cbdc0fc66fb770813eb149ca2a916911bee4902c47c7802e69e405fe3c04ceb5522792a5503fa829f707272226621f7c488a7698c0d69aa561be9f378",
+                output_str: "96dfe9996bffa5e5d83c39b11f47f12d11210f7d4300b7180d1891eaaa7fe4809f9489b1e2407ff87fb2628ddf1fc020"
+            },
+            Test {
+                input: "51b7dbb7ce2ffeb427a91ccfe5218fd40f9e0b7e24756d4c47cd55606008bdc27d16400933906fd9f30effdd4880022d081155342af3fb6cd53672ab7fb5b3a3bcbe47be1fd3a2278cae8a5fd61c1433f7d350675dd21803746cadca574130f01200024c6340ab0cc2cf74f2234669f34e9009ef2eb94823d62b31407f4ba46f1a1eec41641e84d77727b59e746b8a671bef936f05be820759fa",
+                output_str: "79cf2a3017f82693c0a531a367186d055fce63081edf980c6a0b967b6ecce75d635b98485e9b6b285b08336ff34e61c9"
+            },
+            Test {
+                input: "83599d93f5561e821bd01a472386bc2ff4efbd4aed60d5821e84aae74d8071029810f5e286f8f17651cd27da07b1eb4382f754cd1c95268783ad09220f5502840370d494beb17124220f6afce91ec8a0f55231f9652433e5ce3489b727716cf4aeba7dcda20cd29aa9a859201253f948dd94395aba9e3852bd1d60dda7ae5dc045b283da006e1cbad83cc13292a315db5553305c628dd091146597",
+                output_str: "0ed3ca1620ce3a923a22e9d13bbf7543acee05f66b67e6d6f435bc513f4698949c27528068f892f0871916fe2d0433c3"
+            },
+            Test {
+                input: "2be9bf526c9d5a75d565dd11ef63b979d068659c7f026c08bea4af161d85a462d80e45040e91f4165c074c43ac661380311a8cbed59cc8e4c4518e80cd2c78ab1cabf66bff83eab3a80148550307310950d034a6286c93a1ece8929e6385c5e3bb6ea8a7c0fb6d6332e320e71cc4eb462a2a62e2bfe08f0ccad93e61bedb5dd0b786a728ab666f07e0576d189c92bf9fb20dca49ac2d3956d47385e2",
+                output_str: "69a27bbf080e015592893d3b55d1957d267784569923a466165a6fb129613d8ea6f610f3760e349d46b09277cb854546"
+            },
+            Test {
+                input: "ca76d3a12595a817682617006848675547d3e8f50c2210f9af906c0e7ce50b4460186fe70457a9e879e79fd4d1a688c70a347361c847ba0dd6aa52936eaf8e58a1be2f5c1c704e20146d366aeb3853bed9de9befe9569ac8aaea37a9fb7139a1a1a7d5c748605a8defb297869ebedd71d615a5da23496d11e11abbb126b206fa0a7797ee7de117986012d0362dcef775c2fe145ada6bda1ccb326bf644",
+                output_str: "e9c8830140629669a1dc5c8ee27be669b7122f4dc88224635cde334ad99615f3fdc4869e56263e3c7f4420736f714e26"
+            },
+            Test {
+                input: "f76b85dc67421025d64e93096d1d712b7baf7fb001716f02d33b2160c2c882c310ef13a576b1c2d30ef8f78ef8d2f465007109aad93f74cb9e7d7bef7c9590e8af3b267c89c15db238138c45833c98cc4a471a7802723ef4c744a853cf80a0c2568dd4ed58a2c9644806f42104cee53628e5bdf7b63b0b338e931e31b87c24b146c6d040605567ceef5960df9e022cb469d4c787f4cba3c544a1ac91f95f",
+                output_str: "4df060276105bf002f8e9f3f08d5b51f7c2adfe5aab9a1a683c053e045c89a883028b1093461368262ea85f5239ac7b1"
+            },
+            Test {
+                input: "25b8c9c032ea6bcd733ffc8718fbb2a503a4ea8f71dea1176189f694304f0ff68e862a8197b839957549ef243a5279fc2646bd4c009b6d1edebf24738197abb4c992f6b1dc9ba891f570879accd5a6b18691a93c7d0a8d38f95b639c1daeb48c4c2f15ccf5b9d508f8333c32de78781b41850f261b855c4bebcc125a380c54d501c5d3bd07e6b52102116088e53d76583b0161e2a58d0778f091206aabd5a1",
+                output_str: "816aa6db9b663288e5f932f0feaff0ee7875c3b3e6fbac0cddc458bd646371969cf50d2d0942fcc7403573b01b05b455"
+            },
+            Test {
+                input: "21cfdc2a7ccb7f331b3d2eefff37e48ad9fa9c788c3f3c200e0173d99963e1cbca93623b264e920394ae48bb4c3a5bb96ffbc8f0e53f30e22956adabc2765f57fb761e147ecbf8567533db6e50c8a1f894310a94edf806dd8ca6a0e141c0fa7c9fae6c6ae65f18c93a8529e6e5b553bf55f25be2e80a9882bd37f145fecbeb3d447a3c4e46c21524cc55cdd62f521ab92a8ba72b897996c49bb273198b7b1c9e",
+                output_str: "125b51c253391677c59c0332c6a13d07de55eab80857593f0839a56fa678c5e2f7cb2f934abe5e5887804aab5d8f13e1"
+            },
+            Test {
+                input: "4e452ba42127dcc956ef4f8f35dd68cb225fb73b5bc7e1ec5a898bba2931563e74faff3b67314f241ec49f4a7061e3bd0213ae826bab380f1f14faab8b0efddd5fd1bb49373853a08f30553d5a55ccbbb8153de4704f29ca2bdeef0419468e05dd51557ccc80c0a96190bbcc4d77ecff21c66bdf486459d427f986410f883a80a5bcc32c20f0478bb9a97a126fc5f95451e40f292a4614930d054c851acd019ccf",
+                output_str: "130c4b06a55f11c80c41608adfd7b4ce8795871bcf16900f20d2751e123b41d3b2048fd05267c2f9653ece3630bdd330"
+            },
+            Test {
+                input: "fa85671df7dadf99a6ffee97a3ab9991671f5629195049880497487867a6c446b60087fac9a0f2fcc8e3b24e97e42345b93b5f7d3691829d3f8ccd4bb36411b85fc2328eb0c51cb3151f70860ad3246ce0623a8dc8b3c49f958f8690f8e3860e71eb2b1479a5cea0b3f8befd87acaf5362435eaeccb52f38617bc6c5c2c6e269ead1fbd69e941d4ad2012da2c5b21bcfbf98e4a77ab2af1f3fda3233f046d38f1dc8",
+                output_str: "3ea0fa3fc035ea40cbbe9a3c1c6f7e5a437ba20f26736f2895f81d53bec92a186e74762910c4aa62565373d38b28d5fd"
+            },
+            Test {
+                input: "e90847ae6797fbc0b6b36d6e588c0a743d725788ca50b6d792352ea8294f5ba654a15366b8e1b288d84f5178240827975a763bc45c7b0430e8a559df4488505e009c63da994f1403f407958203cebb6e37d89c94a5eacf6039a327f6c4dbbc7a2a307d976aa39e41af6537243fc218dfa6ab4dd817b6a397df5ca69107a9198799ed248641b63b42cb4c29bfdd7975ac96edfc274ac562d0474c60347a078ce4c25e88",
+                output_str: "7c1f1a46e409046b5a314767e8b7e7b1d9a92931443c5d02a581371b380afa1867e554c3f7df2e4557acfd9f8e230c44"
+            },
+            Test {
+                input: "f6d5c2b6c93954fc627602c00c4ca9a7d3ed12b27173f0b2c9b0e4a5939398a665e67e69d0b12fb7e4ceb253e8083d1ceb724ac07f009f094e42f2d6f2129489e846eaff0700a8d4453ef453a3eddc18f408c77a83275617fabc4ea3a2833aa73406c0e966276079d38e8e38539a70e194cc5513aaa457c699383fd1900b1e72bdfb835d1fd321b37ba80549b078a49ea08152869a918ca57f5b54ed71e4fd3ac5c06729",
+                output_str: "2ad23817002c8f0089d423760f5569eb67cbeed2f0f2aa12f8ede7856ee22aa6eb684f86ae91741a4aa3c80ac97c4a0b"
+            },
+            Test {
+                input: "cf8562b1bed89892d67ddaaf3deeb28246456e972326dbcdb5cf3fb289aca01e68da5d59896e3a6165358b071b304d6ab3d018944be5049d5e0e2bb819acf67a6006111089e6767132d72dd85beddcbb2d64496db0cc92955ab4c6234f1eea24f2d51483f2e209e4589bf9519fac51b4d061e801125e605f8093bb6997bc163d551596fe4ab7cfae8fb9a90f6980480ce0c229fd1675409bd788354daf316240cfe0af93eb",
+                output_str: "d34974759c6a4aa9d1a4ed3de341a2ba022df127be92eb0bbc1900eb5ac7b8afe909b52da5714668c3c4b7db939f2436"
+            },
+            Test {
+                input: "2ace31abb0a2e3267944d2f75e1559985db7354c6e605f18dc8470423fca30b7331d9b33c4a4326783d1caae1b4f07060eff978e4746bf0c7e30cd61040bd5ec2746b29863eb7f103ebda614c4291a805b6a4c8214230564a0557bc7102e0bd3ed23719252f7435d64d210ee2aafc585be903fa41e1968c50fd5d5367926df7a05e3a42cf07e656ff92de73b036cf8b19898c0cb34557c0c12c2d8b84e91181af467bc75a9d1",
+                output_str: "0fb38ae233520d4f57469463e1e68d5518ea4e965755c03ad458dd285afb2df518c3d389bd361cbdce46b654631a18c2"
+            },
+            Test {
+                input: "0d8d09aed19f1013969ce5e7eb92f83a209ae76be31c754844ea9116ceb39a22ebb6003017bbcf26555fa6624185187db8f0cb3564b8b1c06bf685d47f3286eda20b83358f599d2044bbf0583fab8d78f854fe0a596183230c5ef8e54426750eaf2cc4e29d3bdd037e734d863c2bd9789b4c243096138f7672c232314effdfc6513427e2da76916b5248933be312eb5dde4cf70804fb258ac5fb82d58d08177ac6f4756017fff5",
+                output_str: "cb8f1cc9eb72465176b97b6226a87e69d77c65190114cce1f830a3dfefa5a8a278d5cf594b173ac58c06ec74958ff8c6"
+            },
+            Test {
+                input: "c3236b73deb7662bf3f3daa58f137b358ba610560ef7455785a9befdb035a066e90704f929bd9689cef0ce3bda5acf4480bceb8d09d10b098ad8500d9b6071dfc3a14af6c77511d81e3aa8844986c3bea6f469f9e02194c92868cd5f51646256798ff0424954c1434bdfed9facb390b07d342e992936e0f88bfd0e884a0ddb679d0547ccdec6384285a45429d115ac7d235a717242021d1dc35641f5f0a48e8445dba58e6cb2c8ea",
+                output_str: "87776d7022dc18592b578c534e2fcf57946e0f74c47df85612f89c6593fd50a9e445c048d6cda9a1d1d10ea3b3c973d0"
+            },
+            Test {
+                input: "b39feb8283eadc63e8184b51df5ae3fd41aac8a963bb0be1cd08aa5867d8d910c669221e73243360646f6553d1ca05a84e8dc0de05b6419ec349ca994480193d01c92525f3fb3dcefb08afc6d26947bdbbfd85193f53b50609c6140905c53a6686b58e53a319a57b962331ede98149af3de3118a819da4d76706a0424b4e1d2910b0ed26af61d150ebcb46595d4266a0bd7f651ba47d0c7f179ca28545007d92e8419d48fdfbd744ce",
+                output_str: "83f4442147fefc8e5bad3e9ee4c6661a771ae8c87458ab67153decd35daf6756eef28e4ae72e65ebfae08886a6e773e0"
+            },
+            Test {
+                input: "a983d54f503803e8c7999f4edbbe82e9084f422143a932ddddc47a17b0b7564a7f37a99d0786e99476428d29e29d3c197a72bfab1342c12a0fc4787fd7017d7a6174049ea43b5779169ef7472bdbbd941dcb82fc73aac45a8a94c9f2bd3477f61fd3b796f02a1b8264a214c6fea74b7051b226c722099ec7883a462b83b6afdd4009248b8a237f605fe5a08fe7d8b45321421ebba67bd70a0b00ddbf94baab7f359d5d1eea105f28dcfb",
+                output_str: "51358159074d960c0b9d73d5f12afdafb8f5d7905bda62379a6e0d6727d03efd26eea51b434368e2e566cb4747d0ba35"
+            },
+            Test {
+                input: "e4d1c1897a0a866ce564635b74222f9696bf2c7f640dd78d7e2aca66e1b61c642bb03ea7536aae597811e9bf4a7b453ede31f97b46a5f0ef51a071a2b3918df16b152519ae3776f9f1edab4c2a377c3292e96408359d3613844d5eb393000283d5ad3401a318b12fd1474b8612f2bb50fb6a8b9e023a54d7dde28c43d6d8854c8d9d1155935c199811dbfc87e9e0072e90eb88681cc7529714f8fb8a2c9d88567adfb974ee205a9bf7b848",
+                output_str: "3ecea8caf0d8efa42d54ac5ef36e624237d9f5508ed6fcb6434d67f3fb788c538c635798f52b2f073a4a7376fd31c4a3"
+            },
+            Test {
+                input: "b10c59723e3dcadd6d75df87d0a1580e73133a9b7d00cb95ec19f5547027323be75158b11f80b6e142c6a78531886d9047b08e551e75e6261e79785366d7024bd7cd9cf322d9be7d57fb661069f2481c7bb759cd71b4b36ca2bc2df6d3a328faebdb995a9794a8d72155ed551a1f87c80bf6059b43fc764900b18a1c2441f7487743cf84e565f61f8dd2ece6b6ccc9444049197aaaf53e926fbee3bfca8be588ec77f29d211be89de18b15f6",
+                output_str: "a8876fe4652acf72dcc8fd5133e5d4ca4e3766ab987cf66eae5e3770e252d2fd2a890525016623ee69064690828c727b"
+            },
+            Test {
+                input: "db11f609baba7b0ca634926b1dd539c8cbada24967d7add4d9876f77c2d80c0f4dcefbd7121548373582705cca2495bd2a43716fe64ed26d059cfb566b3364bd49ee0717bdd9810dd14d8fad80dbbdc4cafb37cc60fb0fe2a80fb4541b8ca9d59dce457738a9d3d8f641af8c3fd6da162dc16fc01aac527a4a0255b4d231c0be50f44f0db0b713af03d968fe7f0f61ed0824c55c4b5265548febd6aad5c5eedf63efe793489c39b8fd29d104ce",
+                output_str: "6a09735736780f199d75c60903aa24d7f8aa17516690854f7522ef0bbf47d41cbdc8bdb2cb2f3c5596510539677607e9"
+            },
+            Test {
+                input: "bebd4f1a84fc8b15e4452a54bd02d69e304b7f32616aadd90537937106ae4e28de9d8aab02d19bc3e2fde1d651559e296453e4dba94370a14dbbb2d1d4e2022302ee90e208321efcd8528ad89e46dc839ea9df618ea8394a6bff308e7726bae0c19bcd4be52da6258e2ef4e96aa21244429f49ef5cb486d7ff35cac1bacb7e95711944bccb2ab34700d42d1eb38b5d536b947348a458ede3dc6bd6ec547b1b0cae5b257be36a7124e1060c170ffa",
+                output_str: "83fc2b91ab81d4b15363f15e53bf639063bac55502b4421cf9a53bcab9ff47fd77de5ac6934f67a412ea1910fad67768"
+            },
+            Test {
+                input: "5aca56a03a13784bdc3289d9364f79e2a85c12276b49b92db0adaa4f206d5028f213f678c3510e111f9dc4c1c1f8b6acb17a6413aa227607c515c62a733817ba5e762cc6748e7e0d6872c984d723c9bb3b117eb8963185300a80bfa65cde495d70a46c44858605fccbed086c2b45cef963d33294dbe9706b13af22f1b7c4cd5a001cfec251fba18e722c6e1c4b1166918b4f6f48a98b64b3c07fc86a6b17a6d0480ab79d4e6415b520f1c484d675b1",
+                output_str: "77c0480b91f32ef809d8c23ab236581f0bca8b9447a4d36228052b3abb6ab69c61d19d720486a3ff497a4673b84cb951"
+            },
+            Test {
+                input: "a5aad0e4646a32c85cfcac73f02fc5300f1982fabb2f2179e28303e447854094cdfc854310e5c0f60993ceff54d84d6b46323d930adb07c17599b35b505f09e784bca5985e0172257797fb53649e2e9723efd16865c31b5c3d5113b58bb0bfc8920fabdda086d7537e66d709d050bd14d0c960873f156fad5b3d3840cdfcdc9be6af519db262a27f40896ab25cc39f96984d650611c0d5a3080d5b3a1bf186abd42956588b3b58cd948970d298776060",
+                output_str: "781466e257d2fa594e39dc220a260c7478d2158bb70e426f9e9587f5a51a7c29fdc7af23e7ab9c774e33c08ab38cedb7"
+            },
+            Test {
+                input: "06cbbe67e94a978203ead6c057a1a5b098478b4b4cbef5a97e93c8e42f5572713575fc2a884531d7622f8f879387a859a80f10ef02708cd8f7413ab385afc357678b9578c0ebf641ef076a1a30f1f75379e9dcb2a885bdd295905ee80c0168a62a9597d10cf12dd2d8cee46645c7e5a141f6e0e23aa482abe5661c16e69ef1e28371e2e236c359ba4e92c25626a7b7ff13f6ea4ae906e1cfe163e91719b1f750a96cbde5fbc953d9e576cd216afc90323a",
+                output_str: "51bebfb5aafe777f390e2851b7eb9aa3809194fe3ba1689abee7e43d44a5874e0c252793dfd42c1270c63c407aef6780"
+            },
+            Test {
+                input: "f1c528cf7739874707d4d8ad5b98f7c77169de0b57188df233b2dc8a5b31eda5db4291dd9f68e6bad37b8d7f6c9c0044b3bf74bbc3d7d1798e138709b0d75e7c593d3cccdc1b20c7174b4e692add820ace262d45ccfae2077e878796347168060a162ecca8c38c1a88350bd63bb539134f700fd4addd5959e255337daa06bc86358fabcbefdfb5bc889783d843c08aadc6c4f6c36f65f156e851c9a0f917e4a367b5ad93d874812a1de6a7b93cd53ad97232",
+                output_str: "fcdf0032f34ba6c42d679b182d07b10f4dff2189b0a5ef6642fbb71b16f910e3240ed9b502b1c6b395bee74ad0fb4191"
+            },
+            Test {
+                input: "9d9f3a7ecd51b41f6572fd0d0881e30390dfb780991dae7db3b47619134718e6f987810e542619dfaa7b505c76b7350c6432d8bf1cfebdf1069b90a35f0d04cbdf130b0dfc7875f4a4e62cdb8e525aadd7ce842520a482ac18f09442d78305fe85a74e39e760a4837482ed2f437dd13b2ec1042afcf9decdc3e877e50ff4106ad10a525230d11920324a81094da31deab6476aa42f20c84843cfc1c58545ee80352bdd3740dd6a16792ae2d86f11641bb717c2",
+                output_str: "92aadc02bb9795a48b031034ee6ab873df481d232932fb5fd6c3762e50e58da46d1f5e5e874597f15c83127f0a3042b1"
+            },
+            Test {
+                input: "5179888724819fbad3afa927d3577796660e6a81c52d98e9303261d5a4a83232f6f758934d50aa83ff9e20a5926dfebaac49529d006eb923c5ae5048ed544ec471ed7191edf46363383824f915769b3e688094c682b02151e5ee01e510b431c8865aff8b6b6f2f59cb6d129da79e97c6d2b8fa6c6da3f603199d2d1bcab547682a81cd6cf65f6551121391d78bcc23b5bd0e922ec6d8bf97c952e84dd28aef909aba31edb903b28fbfc33b7703cd996215a11238",
+                output_str: "0d0ccdbfeb0a933f211eaa94eb452900324340505ccf8db7ad93e976271f812fb8907805f6313d0b0931f5c9203bdba5"
+            },
+            Test {
+                input: "576ef3520d30b7a4899b8c0d5e359e45c5189add100e43be429a02fb3de5ff4f8fd0e79d9663acca72cd29c94582b19292a557c5b1315297d168fbb54e9e2ecd13809c2b5fce998edc6570545e1499dbe7fb74d47cd7f35823b212b05bf3f5a79caa34224fdd670d335fcb106f5d92c3946f44d3afcbae2e41ac554d8e6759f332b76be89a0324aa12c5482d1ea3ee89ded4936f3e3c080436f539fa137e74c6d3389bdf5a45074c47bc7b20b0948407a66d855e2f",
+                output_str: "fef6b1f27b0cebc4568588e627d28dd569a58a8f9a51a1d2887b40f5547b2c67c71917be998d1987ac78e9077cc790ab"
+            },
+            Test {
+                input: "0df2152fa4f4357c8741529dd77e783925d3d76e95bafa2b542a2c33f3d1d117d159cf473f82310356fee4c90a9e505e70f8f24859656368ba09381fa245eb6c3d763f3093f0c89b972e66b53d59406d9f01aea07f8b3b615cac4ee4d05f542e7d0dab45d67ccccd3a606ccbeb31ea1fa7005ba07176e60dab7d78f6810ef086f42f08e595f0ec217372b98970cc6321576d92ce38f7c397a403bada1548d205c343ac09deca86325373c3b76d9f32028fea8eb32515",
+                output_str: "e9957732e7dab64550f003ee6d0353ae89bdc6d69d05766024cff189e4fc8faa41db72954e8e5ac0b29265c8f785e737"
+            },
+            Test {
+                input: "3e15350d87d6ebb5c8ad99d42515cfe17980933c7a8f6b8bbbf0a63728cefaad2052623c0bd5931839112a48633fb3c2004e0749c87a41b26a8b48945539d1ff41a4b269462fd199bfecd45374756f55a9116e92093ac99451aefb2af9fd32d6d7f5fbc7f7a540d5097c096ebc3b3a721541de073a1cc02f7fb0fb1b9327fb0b1218ca49c9487ab5396622a13ae546c97abdef6b56380dda7012a8384091b6656d0ab272d363cea78163ff765cdd13ab1738b940d16cae",
+                output_str: "98d73b3555f003058f7b5a145d89faec46c17099a354ef3834a20142dbd50a0e8054598ce7941bf5dd4df7ccf218f02f"
+            },
+            Test {
+                input: "c38d6b0b757cb552be40940ece0009ef3b0b59307c1451686f1a22702922800d58bce7a636c1727ee547c01b214779e898fc0e560f8ae7f61bef4d75eaa696b921fd6b735d171535e9edd267c192b99880c87997711002009095d8a7a437e258104a41a505e5ef71e5613ddd2008195f0c574e6ba3fe40099cfa116e5f1a2fa8a6da04badcb4e2d5d0de31fdc4800891c45781a0aac7c907b56d631fca5ce8b2cde620d11d1777ed9fa603541de794ddc5758fcd5fad78c0",
+                output_str: "3795de490f43b9899947c1c305c30e26331ba0e611dce7961172b2e4299932147bc9e241c32e61fa964d4f436eccfd37"
+            },
+            Test {
+                input: "8d2de3f0b37a6385c90739805b170057f091cd0c7a0bc951540f26a5a75b3e694631bb64c7635eed316f51318e9d8de13c70a2aba04a14836855f35e480528b776d0a1e8a23b547c8b8d6a0d09b241d3be9377160cca4e6793d00a515dc2992cb7fc741daca171431da99cce6f7789f129e2ac5cf65b40d703035cd2185bb936c82002daf8cbc27a7a9e554b06196630446a6f0a14ba155ed26d95bd627b7205c072d02b60db0fd7e49ea058c2e0ba202daff0de91e845cf79",
+                output_str: "e9f289e671541fec4599915a0d9935bf5c20a12c203bcde88a46eaf5cab2d437f9fcdef67b98768bb80c9a874b3f46c7"
+            },
+            Test {
+                input: "c464bbdad275c50dcd983b65ad1019b9ff85a1e71c807f3204bb2c921dc31fbcd8c5fc45868ae9ef85b6c9b83bba2a5a822201ed68586ec5ec27fb2857a5d1a2d09d09115f22dcc39fe61f5e1ba0ff6e8b4acb4c6da748be7f3f0839739394ff7fa8e39f7f7e84a33c3866875c01bcb1263c9405d91908e9e0b50e7459fabb63d8c6bbb73d8e3483c099b55bc30ff092ff68b6adedfd477d63570c9f5515847f36e24ba0b705557130cec57ebad1d0b31a378e91894ee26e3a04",
+                output_str: "88c23be040be64d23aee8d7ee962228a6f07831b0e05fbe2f25f07729f00c2c617eb6975f57b3f17dd540e8ebca654a9"
+            },
+            Test {
+                input: "8b8d68bb8a75732fe272815a68a1c9c5aa31b41dedc8493e76525d1d013d33cebd9e21a5bb95db2616976a8c07fcf411f5f6bc6f7e0b57aca78cc2790a6f9b898858ac9c79b165ff24e66677531e39f572be5d81eb3264524181115f32780257bfb9aeec6af12af28e587cac068a1a2953b59ad680f4c245b2e3ec36f59940d37e1d3db38e13edb29b5c0f404f6ff87f80fc8be7a225ff22fbb9c8b6b1d7330c57840d24bc75b06b80d30dad6806544d510af6c4785e823ac3e0b8",
+                output_str: "6c42dee61cd97c50f5340cf4dc4f7e319fb5fac7a26b41dee66d789804bd1fef1ef2911643c9c1e2c0485c979b36d927"
+            },
+            Test {
+                input: "6b018710446f368e7421f1bc0ccf562d9c1843846bc8d98d1c9bf7d9d6fcb48bfc3bf83b36d44c4fa93430af75cd190bde36a7f92f867f58a803900df8018150384d85d82132f123006ac2aeba58e02a037fe6afbd65eca7c44977dd3dc74f48b6e7a1bfd5cc4dcf24e4d52e92bd4455848e4928b0eac8b7476fe3cc03e862aa4dff4470dbfed6de48e410f25096487ecfc32a27277f3f5023b2725ade461b1355889554a8836c9cf53bd767f5737d55184eea1ab3f53edd0976c485",
+                output_str: "720150fd5a1cf94a42f922efcbb723ff948f74ca6d0a3f399ac54da8b3bc07f39e6e2979c16c875866cf2f584ca7f2db"
+            },
+            Test {
+                input: "c9534a24714bd4be37c88a3da1082eda7cabd154c309d7bd670dccd95aa535594463058a29f79031d6ecaa9f675d1211e9359be82669a79c855ea8d89dd38c2c761ddd0ec0ce9e97597432e9a1beae062cdd71edfdfd464119be9e69d18a7a7fd7ce0e2106f0c8b0abf4715e2ca48ef9f454dc203c96656653b727083513f8efb86e49c513bb758b3b052fe21f1c05bb33c37129d6cc81f1aef6adc45b0e8827a830fe545cf57d0955802c117d23ccb55ea28f95c0d8c2f9c5a242b33f",
+                output_str: "fa6f90935843d4f58e77cabe4ba662b4fabc1732725faf952eeed70fa0aad6a98fe67f3b6736a1c8f7c5bed4d9b017e0"
+            },
+            Test {
+                input: "07906c87297b867abf4576e9f3cc7f82f22b154afcbf293b9319f1b0584da6a40c27b32e0b1b7f412c4f1b82480e70a9235b12ec27090a5a33175a2bb28d8adc475cefe33f7803f8ce27967217381f02e67a3b4f84a71f1c5228e0c2ad971373f6f672624fcea8d1a9f85170fad30fa0bbd25035c3b41a6175d467998bd1215f6f3866f53847f9cf68ef3e2fbb54bc994de2302b829c5eea68ec441fcbafd7d16ae4fe9fff98bf00e5bc2ad54dd91ff9fda4dd77b6c754a91955d1fbaad0",
+                output_str: "4e2832fee290d1917c15b31893f6578c1299445b99bc48708e13348a11eb2f27fe217a63f532583793d18cdeccaa78b9"
+            },
+            Test {
+                input: "588e94b9054abc2189df69b8ba34341b77cdd528e7860e5defcaa79b0c9a452ad4b82aa306be84536eb7cedcbe058d7b84a6aef826b028b8a0271b69ac3605a9635ea9f5ea0aa700f3eb7835bc54611b922964300c953efe7491e3677c2cebe0822e956cd16433b02c68c4a23252c3f9e151a416b4963257b783e038f6b4d5c9f110f871652c7a649a7bcedcbccc6f2d0725bb903cc196ba76c76aa9f10a190b1d1168993baa9ffc96a1655216773458bec72b0e39c9f2c121378feab4e76a",
+                output_str: "1fb97d6f42480e9f13c934c4a874877a808f1d73314c544d8570c0749f20fa35f53a0c0bda1f10d1a10a029abbb50bc7"
+            },
+            Test {
+                input: "08959a7e4baae874928813364071194e2939772f20db7c3157078987c557c2a6d5abe68d520eef3dc491692e1e21bcd880adebf63bb4213b50897fa005256ed41b5690f78f52855c8d9168a4b666fce2da2b456d7a7e7c17ab5f2fb1ee90b79e698712e963715983fd07641ae4b4e9dc73203fac1ae11fa1f8c7941fcc82eab247addb56e2638447e9d609e610b60ce086656aaebf1da3c8a231d7d94e2fd0afe46b391ff14a72eaeb3f44ad4df85866def43d4781a0b3578bc996c87970b132",
+                output_str: "86b3c81aa398c8819afc4f282dfbce24f4192b2530c267a78373d253c35c1dcc4f40835529563fd42a33fd2cbd680515"
+            },
+            Test {
+                input: "cb2a234f45e2ecd5863895a451d389a369aab99cfef0d5c9ffca1e6e63f763b5c14fb9b478313c8e8c0efeb3ac9500cf5fd93791b789e67eac12fd038e2547cc8e0fc9db591f33a1e4907c64a922dda23ec9827310b306098554a4a78f050262db5b545b159e1ff1dca6eb734b872343b842c57eafcfda8405eedbb48ef32e99696d135979235c3a05364e371c2d76f1902f1d83146df9495c0a6c57d7bf9ee77e80f9787aee27be1fe126cdc9ef893a4a7dcbbc367e40fe4e1ee90b42ea25af01",
+                output_str: "a6bf548ab19ff60d6a8729fa62fdc9b59237843739afff877233ed374bcf70a017126974c2d1a3222d8d906be850a25d"
+            },
+            Test {
+                input: "d16beadf02ab1d4dc6f88b8c4554c51e866df830b89c06e786a5f8757e8909310af51c840efe8d20b35331f4355d80f73295974653ddd620cdde4730fb6c8d0d2dcb2b45d92d4fbdb567c0a3e86bd1a8a795af26fbf29fc6c65941cddb090ff7cd230ac5268ab4606fccba9eded0a2b5d014ee0c34f0b2881ac036e24e151be89eeb6cd9a7a790afccff234d7cb11b99ebf58cd0c589f20bdac4f9f0e28f75e3e04e5b3debce607a496d848d67fa7b49132c71b878fd5557e082a18eca1fbda94d4b",
+                output_str: "ba7d3b6af5966c8c2723b1318820505d040da810126abc3e65088dc421e46d3e54dd31777c539ae083b7b8a4e2303836"
+            },
+            Test {
+                input: "8f65f6bc59a85705016e2bae7fe57980de3127e5ab275f573d334f73f8603106ec3553016608ef2dd6e69b24be0b7113bf6a760ba6e9ce1c48f9e186012cf96a1d4849d75df5bb8315387fd78e9e153e76f8ba7ec6c8849810f59fb4bb9b004318210b37f1299526866f44059e017e22e96cbe418699d014c6ea01c9f0038b10299884dbec3199bb05adc94e955a1533219c1115fed0e5f21228b071f40dd57c4240d98d37b73e412fe0fa4703120d7c0c67972ed233e5deb300a22605472fa3a3ba86",
+                output_str: "48ca5912c111db667a77be7c77f841e8b37130248377a19cd2fa3cd2eec48b337cfe07c290f2690ad49e79ce3a9f9e53"
+            },
+            Test {
+                input: "84891e52e0d451813210c3fd635b39a03a6b7a7317b221a7abc270dfa946c42669aacbbbdf801e1584f330e28c729847ea14152bd637b3d0f2b38b4bd5bf9c791c58806281103a3eabbaede5e711e539e6a8b2cf297cf351c078b4fa8f7f35cf61bebf8814bf248a01d41e86c5715ea40c63f7375379a7eb1d78f27622fb468ab784aaaba4e534a6dfd1df6fa15511341e725ed2e87f98737ccb7b6a6dfae416477472b046bf1811187d151bfa9f7b2bf9acdb23a3be507cdf14cfdf517d2cb5fb9e4ab6",
+                output_str: "4b3849b0916dd445b1856e1b908c414c752d280de2183dd1f0193e73fd1bc02198599502391e8ca48d65e610d6edcd8e"
+            },
+            Test {
+                input: "fdd7a9433a3b4afabd7a3a5e3457e56debf78e84b7a0b0ca0e8c6d53bd0c2dae31b2700c6128334f43981be3b213b1d7a118d59c7e6b6493a86f866a1635c12859cfb9ad17460a77b4522a5c1883c3d6acc86e6162667ec414e9a104aa892053a2b1d72165a855bacd8faf8034a5dd9b716f47a0818c09bb6baf22aa503c06b4ca261f557761989d2afbd88b6a678ad128af68672107d0f1fc73c5ca740459297b3292b281e93bceb761bde7221c3a55708e5ec84472cddcaa84ecf23723cc0991355c6280",
+                output_str: "02c90820d5fa9a91072991e87bfeec7f18315f8ca1908edbf19886c4ca5bd54ab9ec96a6ab7b815b58538f088867030f"
+            },
+            Test {
+                input: "70a40bfbef92277a1aad72f6b79d0177197c4ebd432668cfec05d099accb651062b5dff156c0b27336687a94b26679cfdd9daf7ad204338dd9c4d14114033a5c225bd11f217b5f4732da167ee3f939262d4043fc9cba92303b7b5e96aea12adda64859df4b86e9ee0b58e39091e6b188b408ac94e1294a8911245ee361e60e601eff58d1d37639f3753bec80ebb4efde25817436076623fc65415fe51d1b0280366d12c554d86743f3c3b6572e400361a60726131441ba493a83fbe9afda90f7af1ae717238d",
+                output_str: "75967501ff781efc3c9d597179c8ccaee4373d9bf6aa6a5bed5118303edc8b7478a47f2ceaf0a6b5b7224e53d5f1cdb3"
+            },
+            Test {
+                input: "74356e449f4bf8644f77b14f4d67cb6bd9c1f5ae357621d5b8147e562b65c66585caf2e491b48529a01a34d226d436959153815380d5689e30b35357cdac6e08d3f2b0e88e200600d62bd9f5eaf488df86a4470ea227006182e44809009868c4c280c43d7d64a5268fa719074960087b3a6abc837882f882c837834535929389a12b2c78187e2ea07ef8b8eef27dc85002c3ae35f1a50bee6a1c48ba7e175f3316670b27983472aa6a61eed0a683a39ee323080620ea44a9f74411ae5ce99030528f9ab49c79f2",
+                output_str: "298387ba8a3eb88ee36b4206e54193bc5857f2a303ce41dff7c3bd53ef7ee3d34ae7e0c714311a7bd8d25502cab414b7"
+            },
+            Test {
+                input: "8c3798e51bc68482d7337d3abb75dc9ffe860714a9ad73551e120059860dde24ab87327222b64cf774415a70f724cdf270de3fe47dda07b61c9ef2a3551f45a5584860248fabde676e1cd75f6355aa3eaeabe3b51dc813d9fb2eaa4f0f1d9f834d7cad9c7c695ae84b329385bc0bef895b9f1edf44a03d4b410cc23a79a6b62e4f346a5e8dd851c2857995ddbf5b2d717aeb847310e1f6a46ac3d26a7f9b44985af656d2b7c9406e8a9e8f47dcb4ef6b83caacf9aefb6118bfcff7e44bef6937ebddc89186839b77",
+                output_str: "27cef65d1aecb7051bad55da0d601bc9d7a16d938a5715374a43109dd41b5c27d26c91cb44e4b47002d9b90aba0584d1"
+            },
+            Test {
+                input: "fa56bf730c4f8395875189c10c4fb251605757a8fecc31f9737e3c2503b02608e6731e85d7a38393c67de516b85304824bfb135e33bf22b3a23b913bf6acd2b7ab85198b8187b2bcd454d5e3318cacb32fd6261c31ae7f6c54ef6a7a2a4c9f3ecb81ce3555d4f0ad466dd4c108a90399d70041997c3b25345a9653f3c9a6711ab1b91d6a9d2216442da2c973cbd685ee7643bfd77327a2f7ae9cb283620a08716dfb462e5c1d65432ca9d56a90e811443cd1ecb8f0de179c9cb48ba4f6fec360c66f252f6e64edc96b",
+                output_str: "4ac9bdfd9f717d01598908ba457627d3af7c8123f7110dd7fdb40e91ee6cac201a8b728a384e663890847dfd4de7fa76"
+            },
+            Test {
+                input: "b6134f9c3e91dd8000740d009dd806240811d51ab1546a974bcb18d344642baa5cd5903af84d58ec5ba17301d5ec0f10ccd0509cbb3fd3fff9172d193af0f782252fd1338c7244d40e0e42362275b22d01c4c3389f19dd69bdf958ebe28e31a4ffe2b5f18a87831cfb7095f58a87c9fa21db72ba269379b2dc2384b3da953c7925761fed324620acea435e52b424a7723f6a2357374157a34cd8252351c25a1b232826cefe1bd3e70ffc15a31e7c0598219d7f00436294d11891b82497bc78aa5363892a2495df8c1eef",
+                output_str: "f03fa03e4cf9c23443d7dbdbb66d9abbafefb6500143ff0bfb5d7d6ca2bf1d7cd043a7ba7efb48f15ebc68d1f94598e7"
+            },
+            Test {
+                input: "c941cdb9c28ab0a791f2e5c8e8bb52850626aa89205bec3a7e22682313d198b1fa33fc7295381354858758ae6c8ec6fac3245c6e454d16fa2f51c4166fab51df272858f2d603770c40987f64442d487af49cd5c3991ce858ea2a60dab6a65a34414965933973ac2457089e359160b7cdedc42f29e10a91921785f6b7224ee0b349393cdcff6151b50b377d609559923d0984cda6000829b916ab6896693ef6a2199b3c22f7dc5500a15b8258420e314c222bc000bc4e5413e6dd82c993f8330f5c6d1be4bc79f08a1a0a46",
+                output_str: "9c779d981f9b7e491ff868be22b37fa9df72de55672a0226a821b29c045df4ff788fa7271d557ef6025eea255809f241"
+            },
+            Test {
+                input: "4499efffac4bcea52747efd1e4f20b73e48758be915c88a1ffe5299b0b005837a46b2f20a9cb3c6e64a9e3c564a27c0f1c6ad1960373036ec5bfe1a8fc6a435c2185ed0f114c50e8b3e4c7ed96b06a036819c9463e864a58d6286f785e32a804443a56af0b4df6abc57ed5c2b185ddee8489ea080deeee66aa33c2e6dab36251c402682b6824821f998c32163164298e1fafd31babbcffb594c91888c6219079d907fdb438ed89529d6d96212fd55abe20399dbefd342248507436931cdead496eb6e4a80358acc78647d043",
+                output_str: "2c0bc54a67b00ad703fc595751074c4e447efde00caaf8c8fcadf5768c330b6c7f1918f044f5c5c55810d078534a7bb3"
+            },
+            Test {
+                input: "eecbb8fdfa4da62170fd06727f697d81f83f601ff61e478105d3cb7502f2c89bf3e8f56edd469d049807a38882a7eefbc85fc9a950952e9fa84b8afebd3ce782d4da598002827b1eb98882ea1f0a8f7aa9ce013a6e9bc462fb66c8d4a18da21401e1b93356eb12f3725b6db1684f2300a98b9a119e5d27ff704affb618e12708e77e6e5f34139a5a41131fd1d6336c272a8fc37080f041c71341bee6ab550cb4a20a6ddb6a8e0299f2b14bc730c54b8b1c1c487b494bdccfd3a53535ab2f231590bf2c4062fd2ad58f906a2d0d",
+                output_str: "2db19ca557723cd3c17e7d8140ca301a5a2cb77e3f1f595f5b850a78943c7f36fc37056dcf2badb90dda77bfa969c0aa"
+            },
+            Test {
+                input: "e64f3e4ace5c8418d65fec2bc5d2a303dd458034736e3b0df719098be7a206deaf52d6ba82316caf330ef852375188cde2b39cc94aa449578a7e2a8e3f5a9d68e816b8d16889fbc0ebf0939d04f63033ae9ae2bdab73b88c26d6bd25ee460ee1ef58fb0afa92cc539f8c76d3d097e7a6a63ebb9b5887edf3cf076028c5bbd5b9db3211371ad3fe121d4e9bf44229f4e1ecf5a0f9f0eba4d5ceb72878ab22c3f0eb5a625323ac66f7061f4a81fac834471e0c59553f108475fe290d43e6a055ae3ee46fb67422f814a68c4be3e8c9",
+                output_str: "71e5dd0755cf8b82bc79aed6fb61c9e4ff8361c9afc5ad980808a8bc480e09d59b234074472851080714e0275ce72dc5"
+            },
+            Test {
+                input: "d2cb2d733033f9e91395312808383cc4f0ca974e87ec68400d52e96b3fa6984ac58d9ad0938dde5a973008d818c49607d9de2284e7618f1b8aed8372fbd52ed54557af4220fac09dfa8443011699b97d743f8f2b1aef3537ebb45dcc9e13dfb438428ee190a4efdb3caeb7f3933117bf63abdc7e57beb4171c7e1ad260ab0587806c4d137b6316b50abc9cce0dff3acada47bbb86be777e617bbe578ff4519844db360e0a96c6701290e76bb95d26f0f804c8a4f2717eac4e7de9f2cff3bbc55a17e776c0d02856032a6cd10ad2838",
+                output_str: "51f951b8f1013ba9bced90478e248cd89d4debc6a19ceb6ef81ba1a5d8d3339d426d50a94c7ce3d143c45deccef94965"
+            },
+            Test {
+                input: "f2998955613dd414cc111df5ce30a995bb792e260b0e37a5b1d942fe90171a4ac2f66d4928d7ad377f4d0554cbf4c523d21f6e5f379d6f4b028cdcb9b1758d3b39663242ff3cb6ede6a36a6f05db3bc41e0d861b384b6dec58bb096d0a422fd542df175e1be1571fb52ae66f2d86a2f6824a8cfaacbac4a7492ad0433eeb15454af8f312b3b2a577750e3efbd370e8a8cac1582581971fba3ba4bd0d76e718dacf8433d33a59d287f8cc92234e7a271041b526e389efb0e40b6a18b3aaf658e82ed1c78631fd23b4c3eb27c3faec8685",
+                output_str: "210ebc1556e31a27eaf60a5fe3e181135c5ea117e3ff21af2d04beab9a243ffff632e3d7778f9a6d0304c1acf3659a3c"
+            },
+            Test {
+                input: "447797e2899b72a356ba55bf4df3acca6cdb1041eb477bd1834a9f9acbc340a294d729f2f97df3a610be0ff15edb9c6d5db41644b9874360140fc64f52aa03f0286c8a640670067a84e017926a70438db1bb361defee7317021425f8821def26d1efd77fc853b818545d055adc9284796e583c76e6fe74c9ac2587aa46aa8f8804f2feb5836cc4b3ababab8429a5783e17d5999f32242eb59ef30cd7adabc16d72dbdb097623047c98989f88d14eaf02a7212be16ec2d07981aaa99949ddf89ecd90333a77bc4e1988a82abf7c7caf3291",
+                output_str: "f5f659f6999bad8cdc77c42901a8d64c1fa827f7848985136140bf5d4b3bbb3d964d2d8156f9fd02b6d382bc8410a88e"
+            },
+            Test {
+                input: "9f2c18ade9b380c784e170fb763e9aa205f64303067eb1bcea93df5dac4bf5a2e00b78195f808df24fc76e26cb7be31dc35f0844cded1567bba29858cffc97fb29010331b01d6a3fb3159cc1b973d255da9843e34a0a4061cabdb9ed37f241bfabb3c20d32743f4026b59a4ccc385a2301f83c0b0a190b0f2d01acb8f0d41111e10f2f4e149379275599a52dc089b35fdd5234b0cfb7b6d8aebd563ca1fa653c5c021dfd6f5920e6f18bfafdbecbf0ab00281333ed50b9a999549c1c8f8c63d7626c48322e9791d5ff72294049bde91e73f8",
+                output_str: "b151bf98c52f63f294a4b1e990c86cb73c4bdd476b25c138ca66b2ba08447540b0a787dfddaa3d38af44ca8ebbed74d8"
+            },
+            Test {
+                input: "ae159f3fa33619002ae6bcce8cbbdd7d28e5ed9d61534595c4c9f43c402a9bb31f3b301cbfd4a43ce4c24cd5c9849cc6259eca90e2a79e01ffbac07ba0e147fa42676a1d668570e0396387b5bcd599e8e66aaed1b8a191c5a47547f61373021fa6deadcb55363d233c24440f2c73dbb519f7c9fa5a8962efd5f6252c0407f190dfefad707f3c7007d69ff36b8489a5b6b7c557e79dd4f50c06511f599f56c896b35c917b63ba35c6ff8092baf7d1658e77fc95d8a6a43eeb4c01f33f03877f92774be89c1114dd531c011e53a34dc248a2f0e6",
+                output_str: "47d74fdd9a19a5389313610643fa859ff0bd7b583b099fddb9c980dcc000afeb639dd99071ea31976da35b7bc949bd4e"
+            },
+            Test {
+                input: "3b8e97c5ffc2d6a40fa7de7fcefc90f3b12c940e7ab415321e29ee692dfac799b009c99dcddb708fce5a178c5c35ee2b8617143edc4c40b4d313661f49abdd93cea79d117518805496fe6acf292c4c2a1f76b403a97d7c399daf85b46ad84e16246c67d6836757bde336c290d5d401e6c1386ab32797af6bb251e9b2d8fe754c47482b72e0b394eab76916126fd68ea7d65eb93d59f5b4c5ac40f7c3b37e7f3694f29424c24af8c8f0ef59cd9dbf1d28e0e10f799a6f78cad1d45b9db3d7dee4a7059abe99182714983b9c9d44d7f5643596d4f3",
+                output_str: "9b809198dcce24175e33098331d3a402a821ae9326e72775aae34d1a9bb53d2b57863905cfd60543bbc42b454007c315"
+            },
+            Test {
+                input: "3434ec31b10fafdbfeec0dd6bd94e80f7ba9dca19ef075f7eb017512af66d6a4bcf7d16ba0819a1892a6372f9b35bcc7ca8155ee19e8428bc22d214856ed5fa9374c3c09bde169602cc219679f65a1566fc7316f4cc3b631a18fb4449fa6afa16a3db2bc4212eff539c67cf184680826535589c7111d73bffce431b4c40492e763d9279560aaa38eb2dc14a212d723f994a1fe656ff4dd14551ce4e7c621b2aa5604a10001b2878a897a28a08095c325e10a26d2fb1a75bfd64c250309bb55a44f23bbac0d5516a1c687d3b41ef2fbbf9cc56d4739",
+                output_str: "93c9834501fc728508a15eb9205e678983f3bdb0ba447ee739ae5082db37f2f2d485088130e0b1cbf0039d18bdf429f7"
+            },
+            Test {
+                input: "7c7953d81c8d208fd1c97681d48f49dd003456de60475b84070ef4847c333b74575b1fc8d2a186964485a3b8634feaa3595aaa1a2f4595a7d6b6153563dee31bbac443c8a33eed6d5d956a980a68366c2527b550ee950250dfb691eacbd5d56ae14b970668be174c89df2fea43ae52f13142639c884fd62a3683c0c3792f0f24ab1318bcb27e21f4737fab62c77ea38bc8fd1cf41f7dab64c13febe7152bf5bb7ab5a78f5346d43cc741cb6f72b7b8980f268b68bf62abdfb1577a52438fe14b591498cc95f071228460c7c5d5ceb4a7bde588e7f21c",
+                output_str: "c0ad8c3e7ea595104d4bc0a08dcbc85042ed50dd8d9b01ab47c9f066f91ad3bffede4107f1eb1f5b61ca7d4091d68327"
+            },
+            Test {
+                input: "7a6a4f4fdc59a1d223381ae5af498d74b7252ecf59e389e49130c7eaee626e7bd9897effd92017f4ccde66b0440462cdedfd352d8153e6a4c8d7a0812f701cc737b5178c2556f07111200eb627dbc299caa792dfa58f35935299fa3a3519e9b03166dffa159103ffa35e8577f7c0a86c6b46fe13db8e2cdd9dcfba85bdddcce0a7a8e155f81f712d8e9fe646153d3d22c811bd39f830433b2213dd46301941b59293fd0a33e2b63adbd95239bc01315c46fdb678875b3c81e053a40f581cfbec24a1404b1671a1b88a6d06120229518fb13a74ca0ac5ae",
+                output_str: "aa8daa02abcbc5a4b3003bff5cbc2c84594c5a0f84bd449a1a56be59566e13ec6803010d422a4c244b99812f4537c93d"
+            },
+            Test {
+                input: "d9faa14cebe9b7de551b6c0765409a33938562013b5e8e0e1e0a6418df7399d0a6a771fb81c3ca9bd3bb8e2951b0bc792525a294ebd1083688806fe5e7f1e17fd4e3a41d00c89e8fcf4a363caedb1acb558e3d562f1302b3d83bb886ed27b76033798131dab05b4217381eaaa7ba15ec820bb5c13b516dd640eaec5a27d05fdfca0f35b3a5312146806b4c0275bcd0aaa3b2017f346975db566f9b4d137f4ee10644c2a2da66deeca5342e236495c3c6280528bfd32e90af4cd9bb908f34012b52b4bc56d48cc8a6b59bab014988eabd12e1a0a1c2e170e7",
+                output_str: "caeb4f829a925679416f7cb177ed4c99721b851ab59d52979bfec6d2aaa1e602f4310b15624f9d7bf2d351db73bfb5ea"
+            },
+            Test {
+                input: "2d8427433d0c61f2d96cfe80cf1e932265a191365c3b61aaa3d6dcc039f6ba2ad52a6a8cc30fc10f705e6b7705105977fa496c1c708a277a124304f1fc40911e7441d1b5e77b951aad7b01fd5db1b377d165b05bbf898042e39660caf8b279fe5229d1a8db86c0999ed65e53d01ccbc4b43173ccf992b3a14586f6ba42f5fe30afa8ae40c5df29966f9346da5f8b35f16a1de3ab6de0f477d8d8660918060e88b9b9e9ca6a4207033b87a812dbf5544d39e4882010f82b6ce005f8e8ff6fe3c3806bc2b73c2b83afb704345629304f9f86358712e9fae3ca3e",
+                output_str: "fc1fc7f19f6c9d0ad1462b24c121c89b01b4e083edad02a8dbdeb990d98cafe0afe01e2eba646872cd816b5203ee8a87"
+            },
+            Test {
+                input: "5e19d97887fcaac0387e22c6f803c34a3dacd2604172433f7a8a7a526ca4a2a1271ecfc5d5d7be5ac0d85d921095350dfc65997d443c21c8094e0a3fefd2961bcb94aed03291ae310ccda75d8ace4bc7d89e7d3e5d1650bda5d668b8b50bfc8e608e184f4d3a9a2badc4ff5f07e0c0bc8a9f2e0b2a26fd6d8c550008faaab75fd71af2a424bec9a7cd9d83fad4c8e9319115656a8717d3b523a68ff8004258b9990ed362308461804ba3e3a7e92d8f2ffae5c2fba55ba5a3c27c0a2f71bd711d2fe1799c2adb31b200035481e9ee5c4adf2ab9c0fa50b23975cf",
+                output_str: "84803e50dec901ff930c8a76ebc1f98ec72874deef0d249020b1dbeb4ea7d8c7da4761ede077158460e054a7f71d1994"
+            },
+            Test {
+                input: "c8e976ab4638909387ce3b8d4e510c3230e5690e02c45093b1d297910abc481e56eea0f296f98379dfc9080af69e73b2399d1c143bee80ae1328162ce1ba7f6a8374679b20aacd380eb4e61382c99998704d62701afa914f9a2705cdb065885f50d086c3eb5753700c387118bb142f3e6da1e988dfb31ac75d7368931e45d1391a274b22f83ceb072f9bcabc0b216685bfd789f5023971024b1878a205442522f9ea7d8797a4102a3df41703768251fd5e017c85d1200a464118aa35654e7ca39f3c375b8ef8cbe7534dbc64bc20befb417cf60ec92f63d9ee7397",
+                output_str: "05586bcb8077e19f3f43015216d623b1439c49ecdd3c53255553e9133fd1a9008891520d2eebe5684c546028ca2cddfe"
+            },
+            Test {
+                input: "7145fa124b7429a1fc2231237a949ba7201bcc1822d3272de005b682398196c25f7e5cc2f289fbf44415f699cb7fe6757791b1443410234ae061edf623359e2b4e32c19bf88450432dd01caa5eb16a1dc378f391ca5e3c4e5f356728bddd4975db7c890da8bbc84cc73ff244394d0d48954978765e4a00b593f70f2ca082673a261ed88dbcef1127728d8cd89bc2c597e9102ced6010f65fa75a14ebe467fa57ce3bd4948b6867d74a9df5c0ec6f530cbf2ee61ce6f06bc8f2864dff5583776b31df8c7ffcb61428a56bf7bd37188b4a5123bbf338393af46eda85e6",
+                output_str: "a200d8ef3d120b917561edc8420bde022b3ace792925c8fabf25ad9b0fa676d2260abd8098f383c0f93043d5d3f56c47"
+            },
+            Test {
+                input: "7fdfadcc9d29bad23ae038c6c65cda1aef757221b8872ed3d75ff8df7da0627d266e224e812c39f7983e4558bfd0a1f2bef3feb56ba09120ef762917b9c093867948547aee98600d10d87b20106878a8d22c64378bf634f7f75900c03986b077b0bf8b740a82447b61b99fee5376c5eb6680ec9e3088f0bdd0c56883413d60c1357d3c811950e5890e7600103c916341b80c743c6a852b7b4fb60c3ba21f3bc15b8382437a68454779cf3cd7f9f90ccc8ef28d0b706535b1e4108eb5627bb45d719cb046839aee311ca1abdc8319e050d67972cb35a6b1601b25dbf487",
+                output_str: "a8905d1e9f4fc96f2d769d31c9a120de43a0b20115c8d17bf0313206eb9cd87ae41df2d444c9d75f9366998263d61c07"
+            },
+            Test {
+                input: "988638219fd3095421f826f56e4f09e356296b628c3ce6930c9f2e758fd1a80c8273f2f61e4daae65c4f110d3e7ca0965ac7d24e34c0dc4ba2d6ff0bf5bbe93b3585f354d7543cb542a1aa54674d375077f2d360a8f4d42f3db131c3b7ab7306267ba107659864a90c8c909460a73621d1f5d9d3fd95beb19b23db1cb6c0d0fba91d36891529b8bd8263caa1bab56a4affaed44962df096d8d5b1eb845ef31188b3e10f1af811a13f156beb7a288aae593ebd1471b624aa1a7c6adf01e2200b3d72d88a3aed3100c88231e41efc376906f0b580dc895f080fda5741db1cb",
+                output_str: "88249af84a7f1e49d144869a3d4fe8aa6e1a4874ee467bc99e9c33e2105af2d097417d6b78537925392db2c5cb1e0b92"
+            },
+            Test {
+                input: "5aab62756d307a669d146aba988d9074c5a159b3de85151a819b117ca1ff6597f6156e80fdd28c9c3176835164d37da7da11d94e09add770b68a6e081cd22ca0c004bfe7cd283bf43a588da91f509b27a6584c474a4a2f3ee0f1f56447379240a5ab1fb77fdca49b305f07ba86b62756fb9efb4fc225c86845f026ea542076b91a0bc2cdd136e122c659be259d98e5841df4c2f60330d4d8cdee7bf1a0a244524eecc68ff2aef5bf0069c9e87a11c6e519de1a4062a10c83837388f7ef58598a3846f49d499682b683c4a062b421594fafbc1383c943ba83bdef515efcf10d",
+                output_str: "c46122d00b61e79df025a4d525b8a602c7ac004304a993872e3a8aa37fc0e8eaae5fad9a220c5c6afbd5a4783680013a"
+            },
+            Test {
+                input: "47b8216aa0fbb5d67966f2e82c17c07aa2d6327e96fcd83e3de7333689f3ee79994a1bf45082c4d725ed8d41205cb5bcdf5c341f77facb1da46a5b9b2cbc49eadf786bcd881f371a95fa17df73f606519aea0ff79d5a11427b98ee7f13a5c00637e2854134691059839121fea9abe2cd1bcbbbf27c74caf3678e05bfb1c949897ea01f56ffa4dafbe8644611685c617a3206c7a7036e4ac816799f693dafe7f19f303ce4eba09d21e03610201bfc665b72400a547a1e00fa9b7ad8d84f84b34aef118515e74def11b9188bd1e1f97d9a12c30132ec2806339bdadacda2fd8b78",
+                output_str: "aba0ee3c16d3dc753f6e466c33a998a73282c0dbeaf51324979a58437636886e5521b567c9a62d405ee558ffebae91bc"
+            },
+            Test {
+                input: "8cff1f67fe53c098896d9136389bd8881816ccab34862bb67a656e3d98896f3ce6ffd4da73975809fcdf9666760d6e561c55238b205d8049c1cedeef374d1735daa533147bfa960b2cce4a4f254176bb4d1bd1e89654432b8dbe1a135c42115b394b024856a2a83dc85d6782be4b444239567ccec4b184d4548eae3ff6a192f343292ba2e32a0f267f31cc26719eb85245d415fb897ac2da433ee91a99424c9d7f1766a44171d1651001c38fc79294accc68ceb5665d36218454d3ba169ae058a831338c17743603f81ee173bfc0927464f9bd728dee94c6aeab7aae6ee3a627e8",
+                output_str: "28b37125f233ba8d527e5284a16e6efe9ae84d3ebc6ee4c88aee0ab165c111a32ff2cdcc4213ac3267b0546dc0d74c84"
+            },
+            Test {
+                input: "eacd07971cff9b9939903f8c1d8cbb5d4db1b548a85d04e037514a583604e787f32992bf2111b97ac5e8a938233552731321522ab5e8583561260b7d13ebeef785b23a41fd8576a6da764a8ed6d822d4957a545d5244756c18aa80e1aad4d1f9c20d259dee1711e2cc8fd013169fb7cc4ce38b362f8e0936ae9198b7e838dcea4f7a5b9429bb3f6bbcf2dc92565e3676c1c5e6eb3dd2a0f86aa23edd3d0891f197447692794b3dfa269611ad97f72b795602b4fdb198f3fd3eb41b415064256e345e8d8c51c555dc8a21904a9b0f1ad0effab7786aac2da3b196507e9f33ca356427",
+                output_str: "258988e54d66e0c53b263ba68d9e3aa47d278df87c51219cce6f2547281ea6581540e28c1d7e069254791f0d385ea694"
+            },
+            Test {
+                input: "23ac4e9a42c6ef45c3336ce6dfc2ff7de8884cd23dc912fef0f7756c09d335c189f3ad3a23697abda851a81881a0c8ccafc980ab2c702564c2be15fe4c4b9f10dfb2248d0d0cb2e2887fd4598a1d4acda897944a2ffc580ff92719c95cf2aa42dc584674cb5a9bc5765b9d6ddf5789791d15f8dd925aa12bffafbce60827b490bb7df3dda6f2a143c8bf96abc903d83d59a791e2d62814a89b8080a28060568cf24a80ae61179fe84e0ffad00388178cb6a617d37efd54cc01970a4a41d1a8d3ddce46edbba4ab7c90ad565398d376f431189ce8c1c33e132feae6a8cd17a61c630012",
+                output_str: "f6a9399b482a3a5ea6fe79a2db7bae7e588c9b7da03dd85c120112fdbc234350529a1f37abbebeb770299e141eea7ba3"
+            },
+            Test {
+                input: "0172df732282c9d488669c358e3492260cbe91c95cfbc1e3fea6c4b0ec129b45f242ace09f152fc6234e1bee8aab8cd56e8b486e1dcba9c05407c2f95da8d8f1c0af78ee2ed82a3a79ec0cb0709396ee62aadb84f8a4ee8a7ccca3c1ee84e302a09ea802204afecf04097e67d0f8e8a9d2651126c0a598a37081e42d168b0ae8a71951c524259e4e2054e535b779679bdade566fe55700858618e626b4a0faf895bcce9011504a49e05fd56127eae3d1f8917afb548ecadabda1020111fec9314c413498a360b08640549a22cb23c731ace743252a8227a0d2689d4c6001606678dfb921",
+                output_str: "c0f957e52e40f9b8ea945d40779286f7257ad463a934b049df40c31d3547aef41aea2dd981fd2579327229b54ee04e66"
+            },
+            Test {
+                input: "3875b9240cf3e0a8b59c658540f26a701cf188496e2c2174788b126fd29402d6a75453ba0635284d08835f40051a2a9683dc92afb9383719191231170379ba6f4adc816fecbb0f9c446b785bf520796841e58878b73c58d3ebb097ce4761fdeabe15de2f319dfbaf1742cdeb389559c788131a6793e193856661376c81ce9568da19aa6925b47ffd77a43c7a0e758c37d69254909ff0fbd415ef8eb937bcd49f91468b49974c07dc819abd67395db0e05874ff83dddab895344abd0e7111b2df9e58d76d85ad98106b36295826be04d435615595605e4b4bb824b33c4afeb5e7bb0d19f909",
+                output_str: "779eecf39311318051bf73c441fb799708912049e28df3fadde449e4cd820cc4ca1bd0f8513927d9a64f5d34faaba039"
+            },
+            Test {
+                input: "747cc1a59fefba94a9c75ba866c30dc5c1cb0c0f8e9361d98484956dd5d1a40f6184afbe3dac9f76028d1caeccfbf69199c6ce2b4c092a3f4d2a56fe5a33a00757f4d7dee5dfb0524311a97ae0668a47971b95766e2f6dd48c3f57841f91f04a00ad5ea70f2d479a2620dc5cd78eaab3a3b011719b7e78d19ddf70d9423798af77517ebc55392fcd01fc600d8d466b9e7a7a85bf33f9cc5419e9bd874ddfd60981150ddaf8d7febaa4374f0872a5628d318000311e2f5655365ad4d407c20e5c04df17a222e7deec79c5ab1116d8572f91cd06e1ccc7ced53736fc867fd49ecebe6bf8082e8a",
+                output_str: "3d6495eb3da4e81d3470a050f416e2c8abf657a26d4fd64af35735b5782b611fb798a72fe7a61ce79d0496f69654cc80"
+            },
+            Test {
+                input: "57af971fccaec97435dc2ec9ef0429bcedc6b647729ea168858a6e49ac1071e706f4a5a645ca14e8c7746d65511620682c906c8b86ec901f3dded4167b3f00b06cbfac6aee3728051b3e5ff10b4f9ed8bd0b8da94303c833755b3ca3aeddf0b54bc8d6632138b5d25bab03d17b3458a9d782108006f5bb7de75b5c0ba854b423d8bb801e701e99dc4feaad59bc1c7112453b04d33ea3635639fb802c73c2b71d58a56bbd671b18fe34ed2e3dca38827d63fdb1d4fb3285405004b2b3e26081a8ff08cd6d2b08f8e7b7e90a2ab1ed7a41b1d0128522c2f8bff56a7fe67969422ce839a9d4608f03",
+                output_str: "f8188eafd0e2f9c7f44e70b38db1fe3e12b1469739ca6a13ed5a8661673a318296ffaf8d37f6fcec22a2d00eee2abeba"
+            },
+            Test {
+                input: "04e16dedc1227902baaf332d3d08923601bdd64f573faa1bb7201918cfe16b1e10151dae875da0c0d63c59c3dd050c4c6a874011b018421afc4623ab0381831b2da2a8ba42c96e4f70864ac44e106f94311051e74c77c1291bf5db9539e69567bf6a11cf6932bbbad33f8946bf5814c066d851633d1a513510039b349939bfd42b858c21827c8ff05f1d09b1b0765dc78a135b5ca4dfba0801bcaddfa175623c8b647eacfb4444b85a44f73890607d06d507a4f8393658788669f6ef4deb58d08c50ca0756d5e2f49d1a7ad73e0f0b3d3b5f090acf622b1878c59133e4a848e05153592ea81c6fbf",
+                output_str: "7d83c3f2265c90fef4bc6bd0d17a218f0e196489cb2d8455bbee80ab989ffea46de753346edbd5c88448fedb0d4aad4d"
+            },
+            Test {
+                input: "7c815c384eee0f288ece27cced52a01603127b079c007378bc5d1e6c5e9e6d1c735723acbbd5801ac49854b2b569d4472d33f40bbb8882956245c366dc3582d71696a97a4e19557e41e54dee482a14229005f93afd2c4a7d8614d10a97a9dfa07f7cd946fa45263063ddd29db8f9e34db60daa32684f0072ea2a9426ecebfa5239fb67f29c18cbaa2af6ed4bf4283936823ac1790164fec5457a9cba7c767ca59392d94cab7448f50eb34e9a93a80027471ce59736f099c886dea1ab4cba4d89f5fc7ae2f21ccd27f611eca4626b2d08dc22382e92c1efb2f6afdc8fdc3d2172604f5035c46b8197d3",
+                output_str: "fcc5fcfef5ba874a317b73c9b1b4cf6877373d41f0b8080a5d4f021e0d67f3b9f8ccaacfd4244fc10ba58b3a470db48b"
+            },
+            Test {
+                input: "e29d505158dbdd937d9e3d2145658ee6f5992a2fc790f4f608d9cdb44a091d5b94b88e81fac4fdf5c49442f13b911c55886469629551189eaff62488f1a479b7db11a1560e198ddccccf50159093425ff7f1cb8d1d1246d0978764087d6bac257026b090efae8cec5f22b6f21c59ace1ac7386f5b8837ca6a12b6fbf5534dd0560ef05ca78104d3b943ddb220feaec89aa5e692a00f822a2ab9a2fe60350d75e7be16ff2526dc643872502d01f42f188abed0a6e9a6f5fd0d1ce7d5755c9ffa66b0af0b20bd806f08e06156690d81ac811778ca3dac2c249b96002017fce93e507e3b953acf99964b847",
+                output_str: "9b336b4c2b530f65c01af3f0a46cf1b626d5dbf1b2e50f790b9f34cca367315fdfbf7d9619cda4da22e39f9315303816"
+            },
+            Test {
+                input: "d85588696f576e65eca0155f395f0cfacd83f36a99111ed5768df2d116d2121e32357ba4f54ede927f189f297d3a97fad4e9a0f5b41d8d89dd7fe20156799c2b7b6bf9c957ba0d6763f5c3bc5129747bbb53652b49290cff1c87e2cdf2c4b95d8aaee09bc8fbfa6883e62d237885810491bfc101f1d8c636e3d0ede838ad05c207a3df4fad76452979eb99f29afaecedd1c63b8d36cf378454a1bb67a741c77ac6b6b3f95f4f02b64dabc15438613ea49750df42ee90101f115aa9abb9ff64324dde9dabbb01054e1bd6b4bcdc7930a44c2300d87ca78c06924d0323ad7887e46c90e8c4d100acd9eed21e",
+                output_str: "cac442227f10c4935d42c2914043167890c3ee1f4556d38d20767e8402aec4d70111f2034276e90f28102de634e26afd"
+            },
+            Test {
+                input: "3a12f8508b40c32c74492b66323375dcfe49184c78f73179f3314b79e63376b8ac683f5a51f1534bd729b02b04d002f55cbd8e8fc9b5ec1ea6bbe6a0d0e7431518e6ba45d124035f9d3dce0a8bb7bf1430a9f657e0b4ea9f20eb20c786a58181a1e20a96f1628f8728a13bdf7a4b4b32fc8aa7054cc4881ae7fa19afa65c6c3ee1b3ade3192af42054a8a911b8ec1826865d46d93f1e7c5e2b7813c92a506e53886f3d4701bb93d2a681ad109c845904bb861af8af0646b6e399b38b614051d34f6842563a0f37ec00cb3d865fc5d746c4987de2a65071100883a2a9c7a2bfe1e2dd603d9ea24dc7c5fd06be",
+                output_str: "05e3fb83ee8d609874d5935283702f29e5e896bb090c48033489295989c45dd2c06f5bd558b6bc786ab1251f75664b06"
+            },
+            Test {
+                input: "1861edce46fa5ad17e1ff1deae084dec580f97d0a67885dfe834b9dfac1ae076742ce9e267512ca51f6df5a455af0c5fd6abf94acea103a3370c354485a7846fb84f3ac7c2904b5b2fbf227002ce512133bb7e1c4e50057bfd1e44db33c7cdb969a99e284b184f50a14b068a1fc5009d9b298dbe92239572a7627aac02abe8f3e3b473417f36d4d2505d16b7577f4526c9d94a270a2dfe450d06da8f6fa956879a0a55cfe99e742ea555ea477ba3e9b44ccd508c375423611af92e55345dc215779b2d5119eba49c71d49b9fe3f1569fa24e5ca3e332d042422a8b8158d3ec66a80012976f31ffdf305f0c9c5e",
+                output_str: "6e463c7fb5cf436b1444921afe76d2fa4e7a23edfc9d496af1dc7e78a0173d797eff80f2bb32cfd34daf5633c4e6bcd6"
+            },
+            Test {
+                input: "08d0ffde3a6e4ef65608ea672e4830c12943d7187ccff08f4941cfc13e545f3b9c7ad5eebbe2b01642b486caf855c2c73f58c1e4e3391da8e2d63d96e15fd84953ae5c231911b00ad6050cd7aafdaac9b0f663ae6aab45519d0f5391a541707d479034e73a6ad805ae3598096af078f1393301493d663dd71f83869ca27ba508b7e91e81e128c1716dc3acfe3084b2201e04cf8006617eecf1b640474a5d45cfde9f4d3ef92d6d055b909892194d8a8218db6d8203a84261d200d71473d7488f3427416b6896c137d455f231071cacbc86e0415ab88aec841d96b7b8af41e05bb461a40645bf176601f1e760de5f",
+                output_str: "90457e3d33fce103420056a1c712441e04856b17cf37a4e133841e6d9a944b5ebef98cb1c1ccd575632cd3b5c177669e"
+            },
+            Test {
+                input: "d782abb72a5be3392757be02d3e45be6e2099d6f000d042c8a543f50ed6ebc055a7f133b0dd8e9bc348536edcaae2e12ec18e8837df7a1b3c87ec46d50c241dee820fd586197552dc20beea50f445a07a38f1768a39e2b2ff05dddedf751f1def612d2e4d810daa3a0cc904516f9a43af660315385178a529e51f8aae141808c8bc5d7b60cac26bb984ac1890d0436ef780426c547e94a7b08f01acbfc4a3825eae04f520a9016f2fb8bf5165ed12736fc71e36a49a73614739eaa3ec834069b1b40f1350c2b3ab885c02c640b9f7686ed5f99527e41cfcd796fe4c256c9173186c226169ff257954ebda81c0e5f99",
+                output_str: "e5fc73c70028d1b82a9aa976d34f5fc72916839027038e79df2e29149e861f09a41a8203ce922203f710964b4f5bec2e"
+            },
+            Test {
+                input: "5fce8109a358570e40983e1184e541833bb9091e280f258cfb144387b05d190e431cb19baa67273ba0c58abe91308e1844dcd0b3678baa42f335f2fa05267a0240b3c718a5942b3b3e3bfa98a55c25a1466e8d7a603722cb2bbf03afa54cd769a99f310735ee5a05dae2c22d397bd95635f58c48a67f90e1b73aafcd3f82117f0166657838691005b18da6f341d6e90fc1cdb352b30fae45d348294e501b63252de14740f2b85ae5299ddec3172de8b6d0ba219a20a23bb5e10ff434d39db3f583305e9f5c039d98569e377b75a70ab837d1df269b8a4b566f40bb91b577455fd3c356c914fa06b9a7ce24c7317a172d",
+                output_str: "b0a1bba912daa6d80edc6519b501b629456394d7bda24d46afc9fc1d93a0b5962fa4f95214273290d32b3eaeff6f9dfe"
+            },
+            Test {
+                input: "6172f1971a6e1e4e6170afbad95d5fec99bf69b24b674bc17dd78011615e502de6f56b86b1a71d3f4348087218ac7b7d09302993be272e4a591968aef18a1262d665610d1070ee91cc8da36e1f841a69a7a682c580e836941d21d909a3afc1f0b963e1ca5ab193e124a1a53df1c587470e5881fb54dae1b0d840f0c8f9d1b04c645ba1041c7d8dbf22030a623aa15638b3d99a2c400ff76f3252079af88d2b37f35ee66c1ad7801a28d3d388ac450b97d5f0f79e4541755356b3b1a5696b023f39ab7ab5f28df4202936bc97393b93bc915cb159ea1bd7a0a414cb4b7a1ac3af68f50d79f0c9c7314e750f7d02faa58bfa",
+                output_str: "fce4637898ba0cbd9d7b636febddc02a435901cbbef8bf76d3e866d97d55354b71fc12e67a09e793d749316d714fe08c"
+            },
+            Test {
+                input: "5668ecd99dfbe215c4118398ac9c9eaf1a1433fab4ccdd3968064752b625ea944731f75d48a27d047d67547f14dd0ffaa55fa5e29f7af0d161d85eafc4f2029b717c918eab9d304543290bdba7158b68020c0ba4e079bc95b5bc0fc044a992b94b4ccd3bd66d0eabb5dbbab904d62e00752c4e3b0091d773bcf4c14b4377da3efff824b1cb2fa01b32d1e46c909e626ed2dae920f4c7dbeb635bc754facbd8d49beba3f23c1c41ccbfcd0ee0c114e69737f5597c0bf1d859f0c767e18002ae8e39c26261ffde2920d3d0baf0e906138696cfe5b7e32b600f45df3aaa39932f3a7df95b60fa8712a2271fcaf3911ce7b511b1",
+                output_str: "2b5471fae3805852f4cf39541f8a0a3774818f79fe50476e225d89b62e43be3255e96d19cbc334aef04192840f075c7d"
+            },
+            Test {
+                input: "03d625488354df30e3f875a68edfcf340e8366a8e1ab67f9d5c5486a96829dfac0578289082b2a62117e1cf418b43b90e0adc881fc6ae8105c888e9ecd21aea1c9ae1a4038dfd17378fed71d02ae492087d7cdcd98f746855227967cb1ab4714261ee3bead3f4db118329d3ebef4bc48a875c19ba763966da0ebea800e01b2f50b00e9dd4caca6dcb314d00184ef71ea2391d760c950710db4a70f9212ffc54861f9dc752ce18867b8ad0c48df8466ef7231e7ac567f0eb55099e622ebb86cb237520190a61c66ad34f1f4e289cb3282ae3eaac6152ed24d2c92bae5a7658252a53c49b7b02dfe54fdb2e90074b6cf310ac661",
+                output_str: "d4d3b49878aec72e2e7fafb687da7efe242cb60adf5c65c577c444cfc95a2a2ec670000c8a78898a07400e3502d73f27"
+            },
+            Test {
+                input: "2edc282ffb90b97118dd03aaa03b145f363905e3cbd2d50ecd692b37bf000185c651d3e9726c690d3773ec1e48510e42b17742b0b0377e7de6b8f55e00a8a4db4740cee6db0830529dd19617501dc1e9359aa3bcf147e0a76b3ab70c4984c13e339e6806bb35e683af8527093670859f3d8a0fc7d493bcba6bb12b5f65e71e705ca5d6c948d66ed3d730b26db395b3447737c26fad089aa0ad0e306cb28bf0acf106f89af3745f0ec72d534968cca543cd2ca50c94b1456743254e358c1317c07a07bf2b0eca438a709367fafc89a57239028fc5fecfd53b8ef958ef10ee0608b7f5cb9923ad97058ec067700cc746c127a61ee3",
+                output_str: "fe1c2143f2957819df9c9dd05d004be0e557eed8c5a2b7ce457d5856132b1c43eecec36ad704a930a85485a34c3860fe"
+            },
+            Test {
+                input: "90b28a6aa1fe533915bcb8e81ed6cacdc10962b7ff82474f845eeb86977600cf70b07ba8e3796141ee340e3fce842a38a50afbe90301a3bdcc591f2e7d9de53e495525560b908c892439990a2ca2679c5539ffdf636777ad9c1cdef809cda9e8dcdb451abb9e9c17efa4379abd24b182bd981cafc792640a183b61694301d04c5b3eaad694a6bd4cc06ef5da8fa23b4fa2a64559c5a68397930079d250c51bcf00e2b16a6c49171433b0aadfd80231276560b80458dd77089b7a1bbcc9e7e4b9f881eacd6c92c4318348a13f4914eb27115a1cfc5d16d7fd94954c3532efaca2cab025103b2d02c6fd71da3a77f417d7932685888a",
+                output_str: "4d1f626688e6899b5fccd47faab45e96c61e169869cabef40283b2418dfb2888fb80cc9f2c526497c50c5244784f195c"
+            },
+            Test {
+                input: "2969447d175490f2aa9bb055014dbef2e6854c95f8d60950bfe8c0be8de254c26b2d31b9e4de9c68c9adf49e4ee9b1c2850967f29f5d08738483b417bb96b2a56f0c8aca632b552059c59aac3f61f7b45c966b75f1d9931ff4e596406378cee91aaa726a3a84c33f37e9cdbe626b5745a0b06064a8a8d56e53aaf102d23dd9df0a3fdf7a638509a6761a33fa42fa8ddbd8e16159c93008b53765019c3f0e9f10b144ce2ac57f5d7297f9c9949e4ff68b70d339f87501ce8550b772f32c6da8ad2ce2100a895d8b08fa1eead7c376b407709703c510b50f87e73e43f8e7348f87c3832a547ef2bbe5799abedcf5e1f372ea809233f006",
+                output_str: "a063d778b0a2a11d3a9cba425ee5938fcaa6e2bf1f30a665fa811601444d5749afa18766db5f0426c5b8392238b7862e"
+            },
+            Test {
+                input: "721645633a44a2c78b19024eaecf58575ab23c27190833c26875dc0f0d50b46aea9c343d82ea7d5b3e50ec700545c615daeaea64726a0f05607576dcd396d812b03fb6551c641087856d050b10e6a4d5577b82a98afb89cee8594c9dc19e79feff0382fcfd127f1b803a4b9946f4ac9a4378e1e6e041b1389a53e3450cd32d9d2941b0cbabdb50da8ea2513145164c3ab6bcbd251c448d2d4b087ac57a59c2285d564f16da4ed5e607ed979592146ffb0ef3f3db308fb342df5eb5924a48256fc763141a278814c82d6d6348577545870ae3a83c7230ac02a1540fe1798f7ef09e335a865a2ae0949b21e4f748fb8a51f44750e213a8fb",
+                output_str: "470ee6d35157846890a01b3809eb923cc45dfff2fca2826f458325466c983b1c64bea38bcaeca921c90dd00432eccf89"
+            },
+            Test {
+                input: "6b860d39725a14b498bb714574b4d37ca787404768f64c648b1751b353ac92bac2c3a28ea909fdf0423336401a02e63ec24325300d823b6864bb701f9d7c7a1f8ec9d0ae3584aa6dd62ea1997cd831b4babd9a4da50932d4efda745c61e4130890e156aee6113716daf95764222a91187db2effea49d5d0596102d619bd26a616bbfda8335505fbb0d90b4c180d1a2335b91538e1668f9f9642790b4e55f9cab0fe2bdd2935d001ee6419abab5457880d0dbff20ed8758f4c20fe759efb33141cf0e892587fe8187e5fbc57786b7e8b089612c936dfc03d27efbbe7c8673f1606bd51d5ff386f4a7ab68edf59f385eb1291f117bfe717399",
+                output_str: "a8f0a3c89cf7e56acc18ace1638bcf133094fd9f75f05677c3cd0ed3614a593cbceb09c78c86e350fd07ff4429a6a165"
+            },
+            Test {
+                input: "6a01830af3889a25183244decb508bd01253d5b508ab490d3124afbf42626b2e70894e9b562b288d0a2450cfacf14a0ddae5c04716e5a0082c33981f6037d23d5e045ee1ef2283fb8b6378a914c5d9441627a722c282ff452e25a7ea608d69cee4393a0725d17963d0342684f255496d8a18c2961145315130549311fc07f0312fb78e6077334f87eaa873bee8aa95698996eb21375eb2b4ef53c14401207deb4568398e5dd9a7cf97e8c9663e23334b46912f8344c19efcf8c2ba6f04325f1a27e062b62a58d0766fc6db4d2c6a1928604b0175d872d16b7908ebc041761187cc785526c2a3873feac3a642bb39f5351550af9770c328af7b",
+                output_str: "c8a9a24464f21b133ebe20ba421a81ee34dceacd5f04dcfb66d219f7f4145633692c572b63007834a406ecfb938a14f6"
+            },
+            Test {
+                input: "b3c5e74b69933c2533106c563b4ca20238f2b6e675e8681e34a389894785bdade59652d4a73d80a5c85bd454fd1e9ffdad1c3815f5038e9ef432aac5c3c4fe840cc370cf86580a6011778bbedaf511a51b56d1a2eb68394aa299e26da9ada6a2f39b9faff7fba457689b9c1a577b2a1e505fdf75c7a0a64b1df81b3a356001bf0df4e02a1fc59f651c9d585ec6224bb279c6beba2966e8882d68376081b987468e7aed1ef90ebd090ae825795cdca1b4f09a979c8dfc21a48d8a53cdbb26c4db547fc06efe2f9850edd2685a4661cb4911f165d4b63ef25b87d0a96d3dff6ab0758999aad214d07bd4f133a6734fde445fe474711b69a98f7e2b",
+                output_str: "91bada31b57a4bf3d2eb19a34ff921db10bd6406191486d25d5ca4de5e00b5e2815dae741064e5b877ac57511b949f91"
+            },
+            Test {
+                input: "83af34279ccb5430febec07a81950d30f4b66f484826afee7456f0071a51e1bbc55570b5cc7ec6f9309c17bf5befdd7c6ba6e968cf218a2b34bd5cf927ab846e38a40bbd81759e9e33381016a755f699df35d660007b5eadf292feefb735207ebf70b5bd17834f7bfa0e16cb219ad4af524ab1ea37334aa66435e5d397fc0a065c411ebbce32c240b90476d307ce802ec82c1c49bc1bec48c0675ec2a6c6f3ed3e5b741d13437095707c565e10d8a20b8c20468ff9514fcf31b4249cd82dcee58c0a2af538b291a87e3390d737191a07484a5d3f3fb8c8f15ce056e5e5f8febe5e1fb59d6740980aa06ca8a0c20f5712b4cde5d032e92ab89f0ae1",
+                output_str: "f310e80951c7bb6395ca168aae7ec42deff6c4cd3f5be9c8b49b85b405f731911ae8267ffebd543dbdf409ec20a858d2"
+            },
+            Test {
+                input: "a7ed84749ccc56bb1dfba57119d279d412b8a986886d810f067af349e8749e9ea746a60b03742636c464fc1ee233acc52c1983914692b64309edfdf29f1ab912ec3e8da074d3f1d231511f5756f0b6eead3e89a6a88fe330a10face267bffbfc3e3090c7fd9a850561f363ad75ea881e7244f80ff55802d5ef7a1a4e7b89fcfa80f16df54d1b056ee637e6964b9e0ffd15b6196bdd7db270c56b47251485348e49813b4eb9ed122a01b3ea45ad5e1a929df61d5c0f3e77e1fdc356b63883a60e9cbb9fc3e00c2f32dbd469659883f690c6772e335f617bc33f161d6f6984252ee12e62b6000ac5231e0c9bc65be223d8dfd94c5004a101af9fd6c0fb",
+                output_str: "cfd05e080994fc6d7aef2d8c6e44d8a5e90f5a231676e0fae0d2b8ce162ca9d06712580c99997a7709a06180dd42fb91"
+            },
+            Test {
+                input: "a6fe30dcfcda1a329e82ab50e32b5f50eb25c873c5d2305860a835aecee6264aa36a47429922c4b8b3afd00da16035830edb897831c4e7b00f2c23fc0b15fdc30d85fb70c30c431c638e1a25b51caf1d7e8b050b7f89bfb30f59f0f20fecff3d639abc4255b3868fc45dd81e47eb12ab40f2aac735df5d1dc1ad997cefc4d836b854cee9ac02900036f3867fe0d84afff37bde3308c2206c62c4743375094108877c73b87b2546fe05ea137bedfc06a2796274099a0d554da8f7d7223a48cbf31b7decaa1ebc8b145763e3673168c1b1b715c1cd99ecd3ddb238b06049885ecad9347c2436dff32c771f34a38587a44a82c5d3d137a03caa27e66c8ff6",
+                output_str: "8fa26dd5a54bf94a037a165ec5ce3ed86147a08dcfe3b48818b0c0beeefa33b145323b598f761de2b639d05127f1cf3e"
+            },
+            Test {
+                input: "83167ff53704c3aa19e9fb3303539759c46dd4091a52ddae9ad86408b69335989e61414bc20ab4d01220e35241eff5c9522b079fba597674c8d716fe441e566110b6211531ceccf8fd06bc8e511d00785e57788ed9a1c5c73524f01830d2e1148c92d0edc97113e3b7b5cd3049627abdb8b39dd4d6890e0ee91993f92b03354a88f52251c546e64434d9c3d74544f23fb93e5a2d2f1fb15545b4e1367c97335b0291944c8b730ad3d4789273fa44fb98d78a36c3c3764abeeac7c569c1e43a352e5b770c3504f87090dee075a1c4c85c0c39cf421bdcc615f9eff6cb4fe6468004aece5f30e1ecc6db22ad9939bb2b0ccc96521dfbf4ae008b5b46bc006e",
+                output_str: "283fd61d1e50572ef403bf9c554d76d694a54f902c49795d1cf506f0ee263e7ba994f72bdc4732531fa7194257f2dfda"
+            },
+            Test {
+                input: "3a3a819c48efde2ad914fbf00e18ab6bc4f14513ab27d0c178a188b61431e7f5623cb66b23346775d386b50e982c493adbbfc54b9a3cd383382336a1a0b2150a15358f336d03ae18f666c7573d55c4fd181c29e6ccfde63ea35f0adf5885cfc0a3d84a2b2e4dd24496db789e663170cef74798aa1bbcd4574ea0bba40489d764b2f83aadc66b148b4a0cd95246c127d5871c4f11418690a5ddf01246a0c80a43c70088b6183639dcfda4125bd113a8f49ee23ed306faac576c3fb0c1e256671d817fc2534a52f5b439f72e424de376f4c565cca82307dd9ef76da5b7c4eb7e085172e328807c02d011ffbf33785378d79dc266f6a5be6bb0e4a92eceebaeb1",
+                output_str: "128dc611762be9b135b3739484cfaadca7481d68514f3dfd6f5d78bb1863ae68130835cdc7061a7ed964b32f1db75ee1"
+            }
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Sha3_384));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_sha3_512() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26",
+            },
+            Test {
+                input: "cc",
+                output_str: "3939fcc8b57b63612542da31a834e5dcc36e2ee0f652ac72e02624fa2e5adeecc7dd6bb3580224b4d6138706fc6e80597b528051230b00621cc2b22999eaa205"
+            },
+            Test {
+                input: "41fb",
+                output_str: "aa092865a40694d91754dbc767b5202c546e226877147a95cb8b4c8f8709fe8cd6905256b089da37896ea5ca19d2cd9ab94c7192fc39f7cd4d598975a3013c69"
+            },
+            Test {
+                input: "1f877c",
+                output_str: "cb20dcf54955f8091111688beccef48c1a2f0d0608c3a575163751f002db30f40f2f671834b22d208591cfaf1f5ecfe43c49863a53b3225bdfd7c6591ba7658b"
+            },
+            Test {
+                input: "c1ecfdfc",
+                output_str: "d4b4bdfef56b821d36f4f70ab0d231b8d0c9134638fd54c46309d14fada92a2840186eed5415ad7cf3969bdfbf2daf8cca76abfe549be6578c6f4143617a4f1a"
+            },
+            Test {
+                input: "21f134ac57",
+                output_str: "584219a84e8796076bf1178b14b9d1e2f96a4b4ef11f10cc516fbe1a29639d6ba74fb92815f9e3c5192ed4dca20aea5b109d52237c9956401fd44b221f82ab37"
+            },
+            Test {
+                input: "c6f50bb74e29",
+                output_str: "4345b92a2ab7eadb6a24ee1d175ac258ccf2f694ac09ec9d47399e4d96f61f30b322c5438c51bacd0d597d00471a41ed8e9c9f146bbc807e6bc385f850fbabfe"
+            },
+            Test {
+                input: "119713cc83eeef",
+                output_str: "50081c93bf73ecc54a5ffe43fc14f8baeedbe7da0302ac984c9e668389886bd064bab26ddcb616eb4e0e726042b19f3fd50bdd0d2c5b34892e00e6f399de254f"
+            },
+            Test {
+                input: "4a4f202484512526",
+                output_str: "150d787d6eb49670c2a4ccd17e6cce7a04c1fe30fce03d1ef2501752d92ae04cb345fd42e51038c83b2b4f8fd438d1b4b55cc588c6b913132f1a658fb122cb52"
+            },
+            Test {
+                input: "1f66ab4185ed9b6375",
+                output_str: "a13c951c6c51f236a0197a29a8994b1c7294e17ba518ed1029d6f54ad739d8765920281bbb854d16fbb60e0385afd6e6e433e63aaa77e73b8bee7fde569d6875"
+            },
+            Test {
+                input: "eed7422227613b6f53c9",
+                output_str: "5a566fb181be53a4109275537d80e5fd0f314d68884529ca66b8b0e9f240a673b64b28fffe4c1ec4a5cef0f430229c5757ebd172b4b0b68a81d8c58a9e96e164"
+            },
+            Test {
+                input: "eaeed5cdffd89dece455f1",
+                output_str: "7c77e30ece98ef88964458683c5e0287b5896e166ccca71d2bfd8d8bbc6d6fe589a0225eb1d6aa7b220f1410c9a9ec0672ccddaa1732c3e2877fb5d232c2a428"
+            },
+            Test {
+                input: "5be43c90f22902e4fe8ed2d3",
+                output_str: "f5df5952924e933330bd5bd7627a62c3672f24a4991dadaf78816e023769c91d1910537f9c19fcde60fa6de927982dd5f5970f74e30f2b040f67348a3394c48c"
+            },
+            Test {
+                input: "a746273228122f381c3b46e4f1",
+                output_str: "80a1317ec534ed48d8a813e0bca0cee04f705a2f86352306a932edc548b9a8f1cf79f95027f43bdada8213449c54f68f4dd800b15c4abad87ad7a3b371a7c918"
+            },
+            Test {
+                input: "3c5871cd619c69a63b540eb5a625",
+                output_str: "54c274c3ddf26d824f5fdfcb349a600890057eb2e2022245cbb8bdc0d2240cfa8348f02191fabc0e10f9287185211c9f569132ee6dde4c396668b4bb50aefc3f"
+            },
+            Test {
+                input: "fa22874bcc068879e8ef11a69f0722",
+                output_str: "00767236a7352551b283a8ecf4c79274f8c4cea553ab43fc71cf22fb2f6865ad02c88bf0092f213057340c85a5318f62f4991c00c63cb0558cbcf13d6d84e73d"
+            },
+            Test {
+                input: "52a608ab21ccdd8a4457a57ede782176",
+                output_str: "001618372e75147af90c0cf16c3bbdaa069ddbc62483b392d028ded49f75084a5dfcc53aecd9f57ddbb73daa041fd71089d8fb5edf6cfaf6f1e4e25ad3de266c"
+            },
+            Test {
+                input: "82e192e4043ddcd12ecf52969d0f807eed",
+                output_str: "9644e3c90b67e22124e96dfedce53d33c460f132868f0975d18b22cfd59f637dd85aa405e39808a45570a498c0b8f2cba59f8e1437eaef89f20b88298adfa2de"
+            },
+            Test {
+                input: "75683dcb556140c522543bb6e9098b21a21e",
+                output_str: "4739994390728f4a938df7b3201cd63771858453f0ff1dde9a2b9c38a27a0f6c868460d00ee03ddcb0f063f5f8bb7cb0959b7a222259da0f2c57fa400b50985b"
+            },
+            Test {
+                input: "06e4efe45035e61faaf4287b4d8d1f12ca97e5",
+                output_str: "af69a46527c17117e6dff32cba289eddd1eecda13e5313e46678eb8006e7639854c3970dfeb4d907db1151c1c5ee25ca6f195b09ca5a5cc97a4d64ac4c75578e"
+            },
+            Test {
+                input: "e26193989d06568fe688e75540aea06747d9f851",
+                output_str: "191cef1c6aa009b1aba674be2b3f0da418fdf9e6a7ecf2be42ac14f7d6e07331425133a83b4e0161cc7debf9dcd7fe3787dcb6622a38475189edfe1de6b053d6"
+            },
+            Test {
+                input: "d8dc8fdefbdce9d44e4cbafe78447bae3b5436102a",
+                output_str: "a60d7587424b7242d93bcce515f1c75ae2be7710f72ed3f4e5ea8bc2ba8d64099fe42b88a295e12fdafab441d772c4a9a7d794b27788edea271571a04305f253"
+            },
+            Test {
+                input: "57085fd7e14216ab102d8317b0cb338a786d5fc32d8f",
+                output_str: "09fcad97ea3cb6b7fc61580de0968d238006b7e71f0bd58aba2aa9d4adb855d7606e7632138ccc0aa065ca0b92422262e029da17d73cd3011ff285706c7fc1ae"
+            },
+            Test {
+                input: "a05404df5dbb57697e2c16fa29defac8ab3560d6126fa0",
+                output_str: "f61faab080cf9a5f75407b081a03def4f49a601a2bb832e8c6401be0c98b3ceb3f75c922a91bd5060b3217f737404ef4612b9a009b69ca648b1e37b2ed49229d"
+            },
+            Test {
+                input: "aecbb02759f7433d6fcb06963c74061cd83b5b3ffa6f13c6",
+                output_str: "51de0a622fc6fc702c7c2db5ccb05ca0ddf792986e44b4d336a7a5daf19a20a371d9bf7dde822ecdd0a4ce28e4a0b46fe51a2aabefa7865807ef3d3b1887f14d"
+            },
+            Test {
+                input: "aafdc9243d3d4a096558a360cc27c8d862f0be73db5e88aa55",
+                output_str: "6286c3db87d3b45cfd4de85a7add18e07ae22f1f0f4675e1d4e1fc77633734d7962818a9f3b96b37fe774fc26dea787485317b9622275f63a7dd6d62d650d307"
+            },
+            Test {
+                input: "7bc84867f6f9e9fdc3e1046cae3a52c77ed485860ee260e30b15",
+                output_str: "8146c43a0ffe481872142f56a9cea44332edc76b4e99c2bdc39d7f80b2a6b554c7598f09855bf7abc5e6c048be76f5f369ebb2884e6e37f186e8719df3d523e4"
+            },
+            Test {
+                input: "fac523575a99ec48279a7a459e98ff901918a475034327efb55843",
+                output_str: "4b86fbf9dfb6767eb660af9c30983ed65b6fd051247ab54767dfb49530eb3c01014eb26df63e536cf55e0bce2f62654fb2fce3839b4bfd301570b1ab794df67d"
+            },
+            Test {
+                input: "0f8b2d8fcfd9d68cffc17ccfb117709b53d26462a3f346fb7c79b85e",
+                output_str: "21132fc11f6040ad493d627027c752ce29816589de7be78562914b63d1a9219803ddbd9673aa749f37ff4d6e1b5ae2a12633ba8b0c9994e031ebf6c42e58a793"
+            },
+            Test {
+                input: "a963c3e895ff5a0be4824400518d81412f875fa50521e26e85eac90c04",
+                output_str: "8a5374d92ff9a58e0451e609aa5c0c5c172bb2068c80562d0324f9cb6a037436910c6593f950c44374b4e5bf6f6d3a436ece6daaeb56d147d8cd839cca35eac3"
+            },
+            Test {
+                input: "03a18688b10cc0edf83adf0a84808a9718383c4070c6c4f295098699ac2c",
+                output_str: "71025d089a39d27327c46c27bd4e7565ddbf9c286f185a08178601c3bab4667f368a3a8bddacf25b2b0aa5c9e0cd6c87dc32c854027a8954b5c6afd3a85097ac"
+            },
+            Test {
+                input: "84fb51b517df6c5accb5d022f8f28da09b10232d42320ffc32dbecc3835b29",
+                output_str: "dc29eb7130812a652af3ff9b77629684634502ea6667e7e9f80090ec2a9d690c8c9a78645fb04d9cd269e706ee2c96e74207fbbda559dc285c9bc52f15a256ca"
+            },
+            Test {
+                input: "9f2fcc7c90de090d6b87cd7e9718c1ea6cb21118fc2d5de9f97e5db6ac1e9c10",
+                output_str: "b087c90421aebf87911647de9d465cbda166b672ec47ccd4054a7135a1ef885e7903b52c3f2c3fe722b1c169297a91b82428956a02c631a2240f12162c7bc726"
+            },
+            Test {
+                input: "de8f1b3faa4b7040ed4563c3b8e598253178e87e4d0df75e4ff2f2dedd5a0be046",
+                output_str: "d2a95c6fc0f39c8f7a86c4dd6261a79c940fcb313bcfba9bf71527f5bc70ef827cd97dfa18280e5ddee5ccbc1d63ce88ce2bcdd82dab610f79867a7c20b11e4f"
+            },
+            Test {
+                input: "62f154ec394d0bc757d045c798c8b87a00e0655d0481a7d2d9fb58d93aedc676b5a0",
+                output_str: "af8c0fbd72b3f807db95c9231bc4e93153dc6608b22f4707316aab3d69af0e63291b569f118b5c9e693c5bac4630c4a923a4743581246ad3446dda4f9076fddb"
+            },
+            Test {
+                input: "b2dcfe9ff19e2b23ce7da2a4207d3e5ec7c6112a8a22aec9675a886378e14e5bfbad4e",
+                output_str: "bfc7d968d45342069807c5f1b96425cfffe99ed136d47665e902e026c118701bb7c3e7fd691785115cfdb2ef235a66bcc1384a1d088b8cca90d9d560913549de"
+            },
+            Test {
+                input: "47f5697ac8c31409c0868827347a613a3562041c633cf1f1f86865a576e02835ed2c2492",
+                output_str: "9a348540ab669cdd8914426fbbad192ba0db16583e8d4e867b66cc78c6496e4d83ddbf7b972b0668df7903b0fe9ab82b65153f947cf2af2591121c9d1a78e515"
+            },
+            Test {
+                input: "512a6d292e67ecb2fe486bfe92660953a75484ff4c4f2eca2b0af0edcdd4339c6b2ee4e542",
+                output_str: "ffdb649d1aa7ff269b9bb0ae6192f7bcbc06612528df0e68521d5c891e9bba129271a07dc56393bb21218f5e2fb92cfff833432066aa6380f3557a0748e65b33"
+            },
+            Test {
+                input: "973cf2b4dcf0bfa872b41194cb05bb4e16760a1840d8343301802576197ec19e2a1493d8f4fb",
+                output_str: "9665808d39b4becfdd9aa8020a0a72cfd4f823a15d670d51278a4ae95507e16020aeded6e6c0e2dab0bad890a9e7552403d2aa8d1ebc0b8eaec9a3a8dbb2a9ef"
+            },
+            Test {
+                input: "80beebcd2e3f8a9451d4499961c9731ae667cdc24ea020ce3b9aa4bbc0a7f79e30a934467da4b0",
+                output_str: "7aba6b9f8f18d9d72b883eb988a5f4ffcc0217a3da316aff11b38976e90b0736cb000f522dbf2ddcbb61ba4bf44c356ec5b46fc86a5133f971a94fe2a9983260"
+            },
+            Test {
+                input: "7abaa12ec2a7347674e444140ae0fb659d08e1c66decd8d6eae925fa451d65f3c0308e29446b8ed3",
+                output_str: "589c46625a6ac9a2c9c9a884f427c3c032887ae53a69932b72e1e3796bb9568929d163395a3aa8b2ab23c564937cd729206d9b62cc60353b68a69a739616eb35"
+            },
+            Test {
+                input: "c88dee9927679b8af422abcbacf283b904ff31e1cac58c7819809f65d5807d46723b20f67ba610c2b7",
+                output_str: "f7cd8737a1ab36b37612e57d1e5a3d4a269d18cf2cb7644a12540e3b184631794ec1a1da118a109aef514db3590fe27be0752ec0826acaf458fb0a754bdc51f1"
+            },
+            Test {
+                input: "01e43fe350fcec450ec9b102053e6b5d56e09896e0ddd9074fe138e6038210270c834ce6eadc2bb86bf6",
+                output_str: "b21bdede484ca18f672058667cb2f2dc922c44351e95c2cda75af7e45577bf50e3f203139f6262279adfc3221b94a072641f8bdb55dcc02f21d0879eb5e7466a"
+            },
+            Test {
+                input: "337023370a48b62ee43546f17c4ef2bf8d7ecd1d49f90bab604b839c2e6e5bd21540d29ba27ab8e309a4b7",
+                output_str: "db56265b9346968a390e9841d5b7878a158baed946068e808e456735a67e49220fab66239d5d506dd75a58f2c56e25c9c105a3827c1434c67255cfc9101a5d09"
+            },
+            Test {
+                input: "6892540f964c8c74bd2db02c0ad884510cb38afd4438af31fc912756f3efec6b32b58ebc38fc2a6b913596a8",
+                output_str: "4c825fd9a795ccd20a0892da1572b9b1f70ba05ff2d2da3a4726a74f9ab5323ccbc4290459c1bb46f0a1e1ffc357ff4766f4f4879daa91d31eca986aa30c7b00"
+            },
+            Test {
+                input: "f5961dfd2b1ffffda4ffbf30560c165bfedab8ce0be525845deb8dc61004b7db38467205f5dcfb34a2acfe96c0",
+                output_str: "8445a05766a30ddd0080589f8e8cbf7ec59fb7a3ce73c0209791b19cf712cf1635d63c8356822272309c6b9f01637088878dbffbedb26d2a566185225c4da56b"
+            },
+            Test {
+                input: "ca061a2eb6ceed8881ce2057172d869d73a1951e63d57261384b80ceb5451e77b06cf0f5a0ea15ca907ee1c27eba",
+                output_str: "2dc25165cf317ed7de2b4f2fd0995d7785978ca8581ea8033e912f2e44ee613debfc5535c48d63838f325d1416b9180c20bde82614504b7161f9860530eca70c"
+            },
+            Test {
+                input: "1743a77251d69242750c4f1140532cd3c33f9b5ccdf7514e8584d4a5f9fbd730bcf84d0d4726364b9bf95ab251d9bb",
+                output_str: "cb6110a02d7ca636463f6e3502ccf0173b000482c7e002ad9277c1d10317bddebc3da7f91d0173e3e2f9552bdfdea4dd1afbf7508b096aab1804921e95754e78"
+            },
+            Test {
+                input: "d8faba1f5194c4db5f176fabfff856924ef627a37cd08cf55608bba8f1e324d7c7f157298eabc4dce7d89ce5162499f9",
+                output_str: "7ef3a2894c6ecbc4201b15348f90671515accba3c8166621f864a9184bf08c3f5a895f6b599d3cb41f20a8a1df25ae84f1a6d7c8de74fb7cef48f7e96fde8d43"
+            },
+            Test {
+                input: "be9684be70340860373c9c482ba517e899fc81baaa12e5c6d7727975d1d41ba8bef788cdb5cf4606c9c1c7f61aed59f97d",
+                output_str: "39c7ae0f80129d9d2980a6246e2b6f10a39efafd694ded12a6089509d95ece506dc38c0a9de487d9d401db1f15193404911069533bcae4c48c53f27bee3ce0ac"
+            },
+            Test {
+                input: "7e15d2b9ea74ca60f66c8dfab377d9198b7b16deb6a1ba0ea3c7ee2042f89d3786e779cf053c77785aa9e692f821f14a7f51",
+                output_str: "9b8a7d2f8519ad6dc3d2bc5b696b354c5a8b4796402ce1242c52638eea6893a1269820a642bc9efe56cd7e26dc46e97a7fc58faf3f1a7a25f86ecdc1f2f17e64"
+            },
+            Test {
+                input: "9a219be43713bd578015e9fda66c0f2d83cac563b776ab9f38f3e4f7ef229cb443304fba401efb2bdbd7ece939102298651c86",
+                output_str: "b5ceef23f56be807b616c7fda4867a1d12d0a16845459fc704ce631ad3279ab222dca7addae595d289cba8996d46655fa9b6be58700302e655c51c825f31bb2e"
+            },
+            Test {
+                input: "c8f2b693bd0d75ef99caebdc22adf4088a95a3542f637203e283bbc3268780e787d68d28cc3897452f6a22aa8573ccebf245972a",
+                output_str: "143d024fa75c8d46273589b8f78432d49ef14178e4aaa27dc366c9cb787f24b73f4197a722f13031181a6fa6e4f66127893da7b23a579bb93fe7d737a4194093"
+            },
+            Test {
+                input: "ec0f99711016c6a2a07ad80d16427506ce6f441059fd269442baaa28c6ca037b22eeac49d5d894c0bf66219f2c08e9d0e8ab21de52",
+                output_str: "0f48d008dd3aa630e8261658a55b565b6773992426b08592b4c1d77a58b067f05e25974e501628a2db632f2dddd73673119ada5674d0ce92c7aa908b9e9c435e"
+            },
+            Test {
+                input: "0dc45181337ca32a8222fe7a3bf42fc9f89744259cff653504d6051fe84b1a7ffd20cb47d4696ce212a686bb9be9a8ab1c697b6d6a33",
+                output_str: "297498639fc7aa4152654e468e08f29affd7061d44e3f532be4bac169c877a2ea7b4d70d6bc0f678be08aa064258ef57111310d13b889712d06530b690841dbe"
+            },
+            Test {
+                input: "de286ba4206e8b005714f80fb1cdfaebde91d29f84603e4a3ebc04686f99a46c9e880b96c574825582e8812a26e5a857ffc6579f63742f",
+                output_str: "1b6da16151fcd18383372683480119a304796b2a5e54f7edc6c7bc86817359e73f6fc5587c77bfc71b56ec67905fa7f15193f9f13cfa190bc7b05503a5782c8a"
+            },
+            Test {
+                input: "eebcc18057252cbf3f9c070f1a73213356d5d4bc19ac2a411ec8cdeee7a571e2e20eaf61fd0c33a0ffeb297ddb77a97f0a415347db66bcaf",
+                output_str: "b2f40935e7c9018814c4e2721d9b5aeeed3370690378e472bd29f227442ca4942b06189c346fda498123ece59018e42c8b7ee38191f97789b4aa93223a8d80ef"
+            },
+            Test {
+                input: "416b5cdc9fe951bd361bd7abfc120a5054758eba88fdd68fd84e39d3b09ac25497d36b43cbe7b85a6a3cebda8db4e5549c3ee51bb6fcb6ac1e",
+                output_str: "c8d242fb5ff1c6cd11a040aeaf35cc09e355a975e04ded1d8341878bed5dff8bbbd1b69f4d122ce53309ac08753b95d2a57721dfd12e70a8ef12e11e16de0fd9"
+            },
+            Test {
+                input: "5c5faf66f32e0f8311c32e8da8284a4ed60891a5a7e50fb2956b3cbaa79fc66ca376460e100415401fc2b8518c64502f187ea14bfc9503759705",
+                output_str: "d1d5d5dd7d196b87be4a38f2d9b4a69df9dfe0a6e8ce71b08cf22c7f670ecf273eaf395d12fc63e1741def113cc7104970194a7c7c807e5319d7bb702f20b568"
+            },
+            Test {
+                input: "7167e1e02be1a7ca69d788666f823ae4eef39271f3c26a5cf7cee05bca83161066dc2e217b330df821103799df6d74810eed363adc4ab99f36046a",
+                output_str: "d812470b2d135b6e1bc0c85dc0652bf9f6c2f9ee707a2e667181cc9f689bc7df9cc999b08716868afac78244b151b725a027d9250ab7a073a469e7f09bdb0b55"
+            },
+            Test {
+                input: "2fda311dbba27321c5329510fae6948f03210b76d43e7448d1689a063877b6d14c4f6d0eaa96c150051371f7dd8a4119f7da5c483cc3e6723c01fb7d",
+                output_str: "203ef6bb5132a9d44eae93c7202b1469c2c2b93706d0a31b29223c411a39550f60f39b9556fd040bfb5f9f7099313b8874c8ed677cfc5f93d9a2941a9b0139de"
+            },
+            Test {
+                input: "95d1474a5aab5d2422aca6e481187833a6212bd2d0f91451a67dd786dfc91dfed51b35f47e1deb8a8ab4b9cb67b70179cc26f553ae7b569969ce151b8d",
+                output_str: "23bead09707a77b295fd22fe001282338c2d368302a05fb114ba2a012c4defcf06f3887d6db7a0a1de04bc399bde92d6be71904a9aa7b92bedfa0203f1d8b06f"
+            },
+            Test {
+                input: "c71bd7941f41df044a2927a8ff55b4b467c33d089f0988aa253d294addbdb32530c0d4208b10d9959823f0c0f0734684006df79f7099870f6bf53211a88d",
+                output_str: "93a8db85774b321090801df4dc3cc75e94af63ff6dcf50bd210e5b65fb35e1beaeded55602eb32380726029834982d77b434e94179d0a3ee1059345910ee1dcc"
+            },
+            Test {
+                input: "f57c64006d9ea761892e145c99df1b24640883da79d9ed5262859dcda8c3c32e05b03d984f1ab4a230242ab6b78d368dc5aaa1e6d3498d53371e84b0c1d4ba",
+                output_str: "3b7d98ff3152b2024aad4fa0b40dc642e842d453305ecef278574e386172f3c164e4efb9c2951a23fc73d83c16b4900fb92aeb8efe06b58f918bc4a481e4c238"
+            },
+            Test {
+                input: "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7",
+                output_str: "eb5067bf762a291cf258ad69a816a0b089e0bd44f8e5b74cf60bce64734e59853ccb8d091cd2e33f90aa063fb7942cf5965d459200144c1a0801abd69a9a094a"
+            },
+            Test {
+                input: "16e8b3d8f988e9bb04de9c96f2627811c973ce4a5296b4772ca3eefeb80a652bdf21f50df79f32db23f9f73d393b2d57d9a0297f7a2f2e79cfda39fa393df1ac00",
+                output_str: "b0e23d600ba4215f79d50047bbfed50df7d6e769514d796afd166deeca88bd1cbe0afc72a41e0317a223225b4f5882f723afcba3af7c457eb525946da6c53bb0"
+            },
+            Test {
+                input: "fc424eeb27c18a11c01f39c555d8b78a805b88dba1dc2a42ed5e2c0ec737ff68b2456d80eb85e11714fa3f8eabfb906d3c17964cb4f5e76b29c1765db03d91be37fc",
+                output_str: "83021062117da99327e521d7c91331208bf3f0a972a6c755eca46760c0984871fe03724a51fb5441c3cdd3d24fa1b8127510d6a42cfe18b08e8096ed702ef33c"
+            },
+            Test {
+                input: "abe3472b54e72734bdba7d9158736464251c4f21b33fbbc92d7fac9a35c4e3322ff01d2380cbaa4ef8fb07d21a2128b7b9f5b6d9f34e13f39c7ffc2e72e47888599ba5",
+                output_str: "bca9f06b6b9ab8f76c4f3dbe677d5b4b3103423644484c77cdd8c5dd6c1a0bf717c76e83da9b2b4edfe4cc133c1fc86396e8c3a9e42fdd20519fcaa19969189f"
+            },
+            Test {
+                input: "36f9f0a65f2ca498d739b944d6eff3da5ebba57e7d9c41598a2b0e4380f3cf4b479ec2348d015ffe6256273511154afcf3b4b4bf09d6c4744fdd0f62d75079d440706b05",
+                output_str: "dcdf7617f79da8475b3a4db1306c9caf87f1ae85ec97721892d8e20d0e54ec82ee7a0f2d17f21a61aecd89a6c4cf5019d7b8077447efe03def5208010a8a1e84"
+            },
+            Test {
+                input: "abc87763cae1ca98bd8c5b82caba54ac83286f87e9610128ae4de68ac95df5e329c360717bd349f26b872528492ca7c94c2c1e1ef56b74dbb65c2ac351981fdb31d06c77a4",
+                output_str: "9b8c7142180f0ed85359b6d186ae05b77b2db7c3e1f066392e733b7eeffd7c11f7a6c0c570273a1f3fea1a0929d017c7a4fa00175b5aba76861bca7ee806458b"
+            },
+            Test {
+                input: "94f7ca8e1a54234c6d53cc734bb3d3150c8ba8c5f880eab8d25fed13793a9701ebe320509286fd8e422e931d99c98da4df7e70ae447bab8cffd92382d8a77760a259fc4fbd72",
+                output_str: "3ab73a0a75b997c0ee8329c33e6ef1389e9821711867f775af29517edffbe410d037143c6431fded3d8ce728086c3512e94f038b9243b50cb820dc2445535d91"
+            },
+            Test {
+                input: "13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d",
+                output_str: "def4ab6cda8839729a03e000846604b17f03c5d5d7ec23c483670a13e11573c1e9347a63ec69a5abb21305f9382ecdaaabc6850f92840e86f88f4dabfcd93cc0"
+            },
+            Test {
+                input: "1eed9cba179a009ec2ec5508773dd305477ca117e6d569e66b5f64c6bc64801ce25a8424ce4a26d575b8a6fb10ead3fd1992edddeec2ebe7150dc98f63adc3237ef57b91397aa8a7",
+                output_str: "a3e168b0d6c143ee9e17eae92930b97e6600356b73aebb5d68005dd1d07494451a37052f7b39ff030c1ae1d7efc4e0c3667eb7a76c627ec14354c4f6a796e2c6"
+            },
+            Test {
+                input: "ba5b67b5ec3a3ffae2c19dd8176a2ef75c0cd903725d45c9cb7009a900c0b0ca7a2967a95ae68269a6dbf8466c7b6844a1d608ac661f7eff00538e323db5f2c644b78b2d48de1a08aa",
+                output_str: "635741b37f66cd5ce4dbd1f78accd907f96146e770b239046afb9181910b612d0e65841ff866806eed83c3ae7012fc55e42c3ffc9c6e3d03ce2870442f293ab4"
+            },
+            Test {
+                input: "0efa26ac5673167dcacab860932ed612f65ff49b80fa9ae65465e5542cb62075df1c5ae54fba4db807be25b070033efa223bdd5b1d3c94c6e1909c02b620d4b1b3a6c9fed24d70749604",
+                output_str: "d6299a21cb1b31f0a6eb67d82d4e738249013b75c9bcb4a4fe419036a6043a7103e9ca9b7d25759177c4b64001377093cf39f35c9b1625c6819369fa375fa49d"
+            },
+            Test {
+                input: "bbfd933d1fd7bf594ac7f435277dc17d8d5a5b8e4d13d96d2f64e771abbd51a5a8aea741beccbddb177bcea05243ebd003cfdeae877cca4da94605b67691919d8b033f77d384ca01593c1b",
+                output_str: "07f0a184734ba4bb721f36d7b1b383f6bf99cd5f75941ecf1ff2b325f03af970d1db1f035975702093f59a7610bf054d12017ecd6109177cf061ab1496f87860"
+            },
+            Test {
+                input: "90078999fd3c35b8afbf4066cbde335891365f0fc75c1286cdd88fa51fab94f9b8def7c9ac582a5dbcd95817afb7d1b48f63704e19c2baa4df347f48d4a6d603013c23f1e9611d595ebac37c",
+                output_str: "89070b8b1e322ccf9d6307edc11fc34e13874c4977da9f6035d06faf647d7f7d54b8250b541744298aacd4c54d9b41b4085dd35c491a461d504bdb42fc12f03c"
+            },
+            Test {
+                input: "64105eca863515c20e7cfbaa0a0b8809046164f374d691cdbd6508aaabc1819f9ac84b52bafc1b0fe7cddbc554b608c01c8904c669d8db316a0953a4c68ece324ec5a49ffdb59a1bd6a292aa0e",
+                output_str: "6c3fbe32556445dad430cf15fe1243b6ab44349eec2be1132b0680e5edf0b08b55f1abe473439c5e0750132996195fd120c267b9100c47777b339132ec34cc80"
+            },
+            Test {
+                input: "d4654be288b9f3b711c2d02015978a8cc57471d5680a092aa534f7372c71ceaab725a383c4fcf4d8deaa57fca3ce056f312961eccf9b86f14981ba5bed6ab5b4498e1f6c82c6cae6fc14845b3c8a",
+                output_str: "6ae3e656cf94db10ae3c185362a6625cec53e0ba4dc7d1608a3f2fca3c4f31f89fe1b06fe9ca345e3f5e967a3ebcf6a1a16e24521d5c4690d9b642483ac7a896"
+            },
+            Test {
+                input: "12d9394888305ac96e65f2bf0e1b18c29c90fe9d714dd59f651f52b88b3008c588435548066ea2fc4c101118c91f32556224a540de6efddbca296ef1fb00341f5b01fecfc146bdb251b3bdad556cd2",
+                output_str: "ada8e78ce3e6d447ba2b7dcf98718fe7d43b38d68117e5779a41edd8fa72198e3b3c1c0215925bc9d007fd2c355edd668a0c27ef0ff89f76cf85363d4c9ee001"
+            },
+            Test {
+                input: "871a0d7a5f36c3da1dfce57acd8ab8487c274fad336bc137ebd6ff4658b547c1dcfab65f037aa58f35ef16aff4abe77ba61f65826f7be681b5b6d5a1ea8085e2ae9cd5cf0991878a311b549a6d6af230",
+                output_str: "3569d9a08dfb0001be713940c464c119f5a4c1b9ff97d8297d04c7b2dce2d684aee16443c32e5bb2355ac8a336249d1baaeab4fbd04ab982d6b178dd0a5b5bc8"
+            },
+            Test {
+                input: "e90b4ffef4d457bc7711ff4aa72231ca25af6b2e206f8bf859d8758b89a7cd36105db2538d06da83bad5f663ba11a5f6f61f236fd5f8d53c5e89f183a3cec615b50c7c681e773d109ff7491b5cc22296c5",
+                output_str: "1343e3cd162d7986431babe66383b84029665691e36caf97cdaca17ee9e97d74201d2a828d72e9fbbd5e07831d90f09eaf3c863bd102cdb1edebc8ad58a53ece"
+            },
+            Test {
+                input: "e728de62d75856500c4c77a428612cd804f30c3f10d36fb219c5ca0aa30726ab190e5f3f279e0733d77e7267c17be27d21650a9a4d1e32f649627638dbada9702c7ca303269ed14014b2f3cf8b894eac8554",
+                output_str: "bba01dbea9660f9c2ad74460b67a82440701eb995143ffcf7434b5d2de4e35c82cc757df776d46199dd8e7355aeb1f42a88f6f0bb50fd239c73898156e4ddbbc"
+            },
+            Test {
+                input: "6348f229e7b1df3b770c77544e5166e081850fa1c6c88169db74c76e42eb983facb276ad6a0d1fa7b50d3e3b6fcd799ec97470920a7abed47d288ff883e24ca21c7f8016b93bb9b9e078bdb9703d2b781b616e",
+                output_str: "3268bc24e29392dda1677b7a3ce3111994482d17bad1c150ac885f1d29c308657c69fd4f7ce5967d04fccb920dacb00d0ce09536ee92a6664cb20e692d91d8ce"
+            },
+            Test {
+                input: "4b127fde5de733a1680c2790363627e63ac8a3f1b4707d982caea258655d9bf18f89afe54127482ba01e08845594b671306a025c9a5c5b6f93b0a39522dc877437be5c2436cbf300ce7ab6747934fcfc30aeaaf6",
+                output_str: "ec13e390fa65fdc11054e32c9f5bf5e6e97fbc34c28089346ff22d9762bebf6a14fa7f9c2e6643d1ed7ec6925d0fa2098f8149058e99d02ad5cb61b4ccba6467"
+            },
+            Test {
+                input: "08461f006cff4cc64b752c957287e5a0faabc05c9bff89d23fd902d324c79903b48fcb8f8f4b01f3e4ddb483593d25f000386698f5ade7faade9615fdc50d32785ea51d49894e45baa3dc707e224688c6408b68b11",
+                output_str: "6fd5a334d4b7f9c72a8db1292cc8f19bf2a00f5c226c1636248024723cb876070a9657f48ab3b1d4229202b7bbc64053a48c3ff6b93ab11a2af3237721c9cc09"
+            },
+            Test {
+                input: "68c8f8849b120e6e0c9969a5866af591a829b92f33cd9a4a3196957a148c49138e1e2f5c7619a6d5edebe995acd81ec8bb9c7b9cfca678d081ea9e25a75d39db04e18d475920ce828b94e72241f24db72546b352a0e4",
+                output_str: "016c80cbabed07c50f2c1b677c43e52de8d11751e54e596e0c04b3837a7e34a9ff5d2e98e7c58182879c15847d18dce88ea900337bc448112e98ce1118820c58"
+            },
+            Test {
+                input: "b8d56472954e31fb54e28fca743f84d8dc34891cb564c64b08f7b71636debd64ca1edbdba7fc5c3e40049ce982bba8c7e0703034e331384695e9de76b5104f2fbc4535ecbeebc33bc27f29f18f6f27e8023b0fbb6f563c",
+                output_str: "a4e85ff86482c10c6aaabc79a573cbf89a0a927110d755f22b529bd7cf3f6cc6cb9861e509657242a78b0c0af78ff97abcc1a8388270d6c8d302d45c9ba58404"
+            },
+            Test {
+                input: "0d58ac665fa84342e60cefee31b1a4eacdb092f122dfc68309077aed1f3e528f578859ee9e4cefb4a728e946324927b675cd4f4ac84f64db3dacfe850c1dd18744c74ceccd9fe4dc214085108f404eab6d8f452b5442a47d",
+                output_str: "b97afb77d39f8904ae8a5129a7ddc8ec9290ac40356e1b53dd057fa7584ba31afaf9ef5b657097fc115eaa33e7ede36dd00832d677ebd07c34b071e73580dd3a"
+            },
+            Test {
+                input: "1755e2d2e5d1c1b0156456b539753ff416651d44698e87002dcf61dcfa2b4e72f264d9ad591df1fdee7b41b2eb00283c5aebb3411323b672eaa145c5125185104f20f335804b02325b6dea65603f349f4d5d8b782dd3469ccd",
+                output_str: "ab2fc59a43a2666c9206b9317479285e660b670c6f111f999556e8151e0eb8d12bc82c9a7e7b3f8d6f382a8d96775ea417f754ff552e1bac271fbd08240f1b86"
+            },
+            Test {
+                input: "b180de1a611111ee7584ba2c4b020598cd574ac77e404e853d15a101c6f5a2e5c801d7d85dc95286a1804c870bb9f00fd4dcb03aa8328275158819dcad7253f3e3d237aeaa7979268a5db1c6ce08a9ec7c2579783c8afc1f91a7",
+                output_str: "0a673af84e2d2317b80a873bfe38b252872708b38af9b956e3554ac2dce2f77c815593d99930e7aa666c57b59730712e5c4a9b57849eddd712a378040eb824d8"
+            },
+            Test {
+                input: "cf3583cbdfd4cbc17063b1e7d90b02f0e6e2ee05f99d77e24e560392535e47e05077157f96813544a17046914f9efb64762a23cf7a49fe52a0a4c01c630cfe8727b81fb99a89ff7cc11dca5173057e0417b8fe7a9efba6d95c555f",
+                output_str: "1d34645463ebbd932c730e593d9c108aa86807db6785f05c4ce80f3e8302f87efbccb1ab884e25f1dcd5485d385502995e7abe2ef11bd3469e036d7eb93b4f39"
+            },
+            Test {
+                input: "072fc02340ef99115bad72f92c01e4c093b9599f6cfc45cb380ee686cb5eb019e806ab9bd55e634ab10aa62a9510cc0672cd3eddb589c7df2b67fcd3329f61b1a4441eca87a33c8f55da4fbbad5cf2b2527b8e983bb31a2fadec7523",
+                output_str: "3f57fa915a782e3cc69815ba219f42aa2c222cd7f309f10af843384b3d3939aa0b92dd9571686c7961e06bfee818127fc5b5f32c67f4aa2af10d4fa38f65e90d"
+            },
+            Test {
+                input: "76eecf956a52649f877528146de33df249cd800e21830f65e90f0f25ca9d6540fde40603230eca6760f1139c7f268deba2060631eea92b1fff05f93fd5572fbe29579ecd48bc3a8d6c2eb4a6b26e38d6c5fbf2c08044aeea470a8f2f26",
+                output_str: "151382ca35fb20b895a9dc074d687f2f335eaf57456d357a685ef752da59174d3f239aa9e04f142138d9413b21904665ef4df2f63e663b490383660481f78362"
+            },
+            Test {
+                input: "7adc0b6693e61c269f278e6944a5a2d8300981e40022f839ac644387bfac9086650085c2cdc585fea47b9d2e52d65a2b29a7dc370401ef5d60dd0d21f9e2b90fae919319b14b8c5565b0423cefb827d5f1203302a9d01523498a4db10374",
+                output_str: "23aa4b74c54e8f450054b6abdbc6f6c3e44366afcec099b155775de040bf3b9cdd0b875f9d490faa694f18ccbffec6cab7de57a59ec6327240ac59d62d50b21c"
+            },
+            Test {
+                input: "e1fffa9826cce8b86bccefb8794e48c46cdf372013f782eced1e378269b7be2b7bf51374092261ae120e822be685f2e7a83664bcfbe38fe8633f24e633ffe1988e1bc5acf59a587079a57a910bda60060e85b5f5b6f776f0529639d9cce4bd",
+                output_str: "3605cec16a7aa8b2525479fcc1295411b6a952dce233c9acc856d6d17c9812c920178500cd0028b5998d07046c6a5cf398ee1ec97df9182c33fca86647861878"
+            },
+            Test {
+                input: "69f9abba65592ee01db4dce52dbab90b08fc04193602792ee4daa263033d59081587b09bbe49d0b49c9825d22840b2ff5d9c5155f975f8f2c2e7a90c75d2e4a8040fe39f63bbafb403d9e28cc3b86e04e394a9c9e8065bd3c85fa9f0c7891600",
+                output_str: "c5a526d75816d41b53bf164b0467e0b80a9984d1830edb9d49f7ec3ecfefb01a2c824a0f645753aa463d567cb2782afcb2b2c2102ea664c56998f79062636fc1"
+            },
+            Test {
+                input: "38a10a352ca5aedfa8e19c64787d8e9c3a75dbf3b8674bfab29b5dbfc15a63d10fae66cd1a6e6d2452d557967eaad89a4c98449787b0b3164ca5b717a93f24eb0b506ceb70cbbcb8d72b2a72993f909aad92f044e0b5a2c9ac9cb16a0ca2f81f49",
+                output_str: "b239941a31100ab1b24af2d1fef149dba300105a31b72a8f217e306a0602d722ccd593a23e6539d3e4195a7e12ca19ae2bae8b8399f7a9d50db30216e973f2bf"
+            },
+            Test {
+                input: "6d8c6e449bc13634f115749c248c17cd148b72157a2c37bf8969ea83b4d6ba8c0ee2711c28ee11495f43049596520ce436004b026b6c1f7292b9c436b055cbb72d530d860d1276a1502a5140e3c3f54a93663e4d20edec32d284e25564f624955b52",
+                output_str: "d6ab0d0b416d1bbc85479f9850585761b91775a60307afacf70943feb58657740fe35dc760ab9cfa672c6b5552aa67bfa1f0d6a6f943b3912c229b8e0155c002"
+            },
+            Test {
+                input: "6efcbcaf451c129dbe00b9cef0c3749d3ee9d41c7bd500ade40cdc65dedbbbadb885a5b14b32a0c0d087825201e303288a733842fa7e599c0c514e078f05c821c7a4498b01c40032e9f1872a1c925fa17ce253e8935e4c3c71282242cb716b2089ccc1",
+                output_str: "bc0a28450368c288013e2eb1196e58933ce05869cb55fa2bda61d9d92f83b903e59dde0b927ca6dbc46f5af2eb7e8831e8668888bfea46d78f4d274818d56328"
+            },
+            Test {
+                input: "433c5303131624c0021d868a30825475e8d0bd3052a022180398f4ca4423b98214b6beaac21c8807a2c33f8c93bd42b092cc1b06cedf3224d5ed1ec29784444f22e08a55aa58542b524b02cd3d5d5f6907afe71c5d7462224a3f9d9e53e7e0846dcbb4ce",
+                output_str: "7820a20056df741e19ff4d150663488cf86f936353e99e25b93220f5230bfbc13363b458d6db92f9d211d705362b01782ec118acfe53bae4c6ac2c7e5d0111fb"
+            },
+            Test {
+                input: "a873e0c67ca639026b6683008f7aa6324d4979550e9bce064ca1e1fb97a30b147a24f3f666c0a72d71348ede701cf2d17e2253c34d1ec3b647dbcef2f879f4eb881c4830b791378c901eb725ea5c172316c6d606e0af7df4df7f76e490cd30b2badf45685f",
+                output_str: "0984a43286a3cb22fb59f7880e114e23e3ad3b0d43025f3987d0aa6fa8e53e6066f80f4769241dcd062431c7f6712c57c6e3275ed3f2bc591db6dc20e5be0953"
+            },
+            Test {
+                input: "006917b64f9dcdf1d2d87c8a6173b64f6587168e80faa80f82d84f60301e561e312d9fbce62f39a6fb476e01e925f26bcc91de621449be6504c504830aae394096c8fc7694651051365d4ee9070101ec9b68086f2ea8f8ab7b811ea8ad934d5c9b62c60a4771",
+                output_str: "a6300497f650859cd744679885cd5437a64cc3961574dcce65e1611616a9f97190f39130ba532094bd62464d0b8b52297a2c9c279b2c9860c072cd44449a9cdf"
+            },
+            Test {
+                input: "f13c972c52cb3cc4a4df28c97f2df11ce089b815466be88863243eb318c2adb1a417cb1041308598541720197b9b1cb5ba2318bd5574d1df2174af14884149ba9b2f446d609df240ce335599957b8ec80876d9a085ae084907bc5961b20bf5f6ca58d5dab38adb",
+                output_str: "e2052884d112238807c02c135247f76e0e394bd6583ba83ed2731cf68f057276272b891a761cdec6d8ad2e3f33e86ae9d9a234682bce7a53816235692d2cf821"
+            },
+            Test {
+                input: "e35780eb9799ad4c77535d4ddb683cf33ef367715327cf4c4a58ed9cbdcdd486f669f80189d549a9364fa82a51a52654ec721bb3aab95dceb4a86a6afa93826db923517e928f33e3fba850d45660ef83b9876accafa2a9987a254b137c6e140a21691e1069413848",
+                output_str: "ff6a7d0efea45e5f0abcb173fce2be76b52d0f3fc363afe31d219472742d73e56cee2ab91a94d41335c4fa25cbdd6ebd1a087637caa25099d5a9d60693cf62b9"
+            },
+            Test {
+                input: "64ec021c9585e01ffe6d31bb50d44c79b6993d72678163db474947a053674619d158016adb243f5c8d50aa92f50ab36e579ff2dabb780a2b529370daa299207cfbcdd3a9a25006d19c4f1fe33e4b1eaec315d8c6ee1e730623fd1941875b924eb57d6d0c2edc4e78d6",
+                output_str: "4183f96759e7c0628f2fc81979274f42111a43bd5dbb3685bb21704ce6b0ed3d164decf28a3a991b303e1d7b86e2b175ba89945a8524f9c9318f12b160a1e4d1"
+            },
+            Test {
+                input: "5954bab512cf327d66b5d9f296180080402624ad7628506b555eea8382562324cf452fba4a2130de3e165d11831a270d9cb97ce8c2d32a96f50d71600bb4ca268cf98e90d6496b0a6619a5a8c63db6d8a0634dfc6c7ec8ea9c006b6c456f1b20cd19e781af20454ac880",
+                output_str: "940c6f0bacf11e4b045f432003f889278709f9c3d8e420c9a17155f57e776d72b4306bba4adf721708f6ef457444ab12238372e207ab41d5ef5a68529ed0b26c"
+            },
+            Test {
+                input: "03d9f92b2c565709a568724a0aff90f8f347f43b02338f94a03ed32e6f33666ff5802da4c81bdce0d0e86c04afd4edc2fc8b4141c2975b6f07639b1994c973d9a9afce3d9d365862003498513bfa166d2629e314d97441667b007414e739d7febf0fe3c32c17aa188a8683",
+                output_str: "172f0c680310375156911c07b1819f0b9d124514ec2c3750cb2e39926a28a4636ab7ecdcdd9d6a960d16c864dd585645d87f145c5b315381f356656d617fe97d"
+            },
+            Test {
+                input: "f31e8b4f9e0621d531d22a380be5d9abd56faec53cbd39b1fab230ea67184440e5b1d15457bd25f56204fa917fa48e669016cb48c1ffc1e1e45274b3b47379e00a43843cf8601a5551411ec12503e5aac43d8676a1b2297ec7a0800dbfee04292e937f21c005f17411473041",
+                output_str: "410dbaa5e3453f2dafce135dc014f28fbf693c84eb7d4becb80a3db32e16e89062b3ff59c1dfdfab32d84d20284632a2ac7f8f88d4b7023f879463ba18ff6553"
+            },
+            Test {
+                input: "758ea3fea738973db0b8be7e599bbef4519373d6e6dcd7195ea885fc991d896762992759c2a09002912fb08e0cb5b76f49162aeb8cf87b172cf3ad190253df612f77b1f0c532e3b5fc99c2d31f8f65011695a087a35ee4eee5e334c369d8ee5d29f695815d866da99df3f79403",
+                output_str: "f93a099159c39617b75b188d527fc4db287cbb4fdddba5ad4dcb4cffc4dc59762bbc41a58d3a788eae152aea024bc4cc4f29fc7b8ab68065a68650a04b51818a"
+            },
+            Test {
+                input: "47c6e0c2b74948465921868804f0f7bd50dd323583dc784f998a93cd1ca4c6ef84d41dc81c2c40f34b5bee6a93867b3bdba0052c5f59e6f3657918c382e771d33109122cc8bb0e1e53c4e3d13b43ce44970f5e0c079d2ad7d7a3549cd75760c21bb15b447589e86e8d76b1e9ced2",
+                output_str: "05e69984ee99aa2bc851083aa44ee56feef86c45888867cdcdd0c7a8049080ae7858b93c19953a881be5c036bd8fe83628c2e3aa9939a288b4ac4bc2876c2fbc"
+            },
+            Test {
+                input: "f690a132ab46b28edfa6479283d6444e371c6459108afd9c35dbd235e0b6b6ff4c4ea58e7554bd002460433b2164ca51e868f7947d7d7a0d792e4abf0be5f450853cc40d85485b2b8857ea31b5ea6e4ccfa2f3a7ef3380066d7d8979fdac618aad3d7e886dea4f005ae4ad05e5065f",
+                output_str: "be22f3e253c2563c3353e693d2d5a65dc6bac2cbcda8e43e8584f9d851e602d4374936403fd688f0135e363de8099f249dd21c61695c109c27ed5f4f4c1808bf"
+            },
+            Test {
+                input: "58d6a99bc6458824b256916770a8417040721cccfd4b79eacd8b65a3767ce5ba7e74104c985ac56b8cc9aebd16febd4cda5adb130b0ff2329cc8d611eb14dac268a2f9e633c99de33997fea41c52a7c5e1317d5b5daed35eba7d5a60e45d1fa7eaabc35f5c2b0a0f2379231953322c4e",
+                output_str: "1d1836c4e2c3eb27a74a9cd600c064391bd9edd45464a5795182c8794748ba51a345c6fae2b91f5758401e4f427d50b6882b1df0977976c2c9432c1a9b3ae03f"
+            },
+            Test {
+                input: "befab574396d7f8b6705e2d5b58b2c1c820bb24e3f4bae3e8fbcd36dbf734ee14e5d6ab972aedd3540235466e825850ee4c512ea9795abfd33f330d9fd7f79e62bbb63a6ea85de15beaeea6f8d204a28956059e2632d11861dfb0e65bc07ac8a159388d5c3277e227286f65ff5e5b5aec1",
+                output_str: "cb0d33c173c765bba3714d56a4cf48fd6320ab8c5317e7ab1a46472afb756232cd27f51473dcf9bd7dac1aa7f669353fd8f3d27d17d3fe3eb3386876eca38a85"
+            },
+            Test {
+                input: "8e58144fa9179d686478622ce450c748260c95d1ba43b8f9b59abeca8d93488da73463ef40198b4d16fb0b0707201347e0506ff19d01bea0f42b8af9e71a1f1bd168781069d4d338fdef00bf419fbb003031df671f4a37979564f69282de9c65407847dd0da505ab1641c02dea4f0d834986",
+                output_str: "b579ad0c750b91e0671bb7f0482a519835d155ae1a4db92112e66fbd158835e0c29e2f122a8c54c530f92633f6ec7b222ca3ced45b4b5a24426d99c59c1b6609"
+            },
+            Test {
+                input: "b55c10eae0ec684c16d13463f29291bf26c82e2fa0422a99c71db4af14dd9c7f33eda52fd73d017cc0f2dbe734d831f0d820d06d5f89dacc485739144f8cfd4799223b1aff9031a105cb6a029ba71e6e5867d85a554991c38df3c9ef8c1e1e9a7630be61caabca69280c399c1fb7a12d12aefc",
+                output_str: "689c878d8a44c79eaf0579dc96c0e7fe7d33491f59a6058bee60e14b8006bdf6a6070b2b6d3bb6d7c31ccae09ec403df49dd12ba72c8532a8e476b4b415d8369"
+            },
+            Test {
+                input: "2eeea693f585f4ed6f6f8865bbae47a6908aecd7c429e4bec4f0de1d0ca0183fa201a0cb14a529b7d7ac0e6ff6607a3243ee9fb11bcf3e2304fe75ffcddd6c5c2e2a4cd45f63c962d010645058d36571404a6d2b4f44755434d76998e83409c3205aa1615db44057db991231d2cb42624574f545",
+                output_str: "4e4dc49e414c794a4b6d8d2093feab46d91321cfd089b1fd8cb5154f3e342645f6233a9216db04f080e5af8b156e782ad16e0b15d814173e78fcf5e7cf8ea51f"
+            },
+            Test {
+                input: "dab11dc0b047db0420a585f56c42d93175562852428499f66a0db811fcdddab2f7cdffed1543e5fb72110b64686bc7b6887a538ad44c050f1e42631bc4ec8a9f2a047163d822a38989ee4aab01b4c1f161b062d873b1cfa388fd301514f62224157b9bef423c7783b7aac8d30d65cd1bba8d689c2d",
+                output_str: "2c8f456f9091517cafa9df1d09ee621edfeb2c00dab944355d592dfda128f837228578e3965d3767959d3cdde4e7b67e02241f28c5417e33ea74e39032f938ea"
+            },
+            Test {
+                input: "42e99a2f80aee0e001279a2434f731e01d34a44b1a8101726921c0590c30f3120eb83059f325e894a5ac959dca71ce2214799916424e859d27d789437b9d27240bf8c35adbafcecc322b48aa205b293962d858652abacbd588bcf6cbc388d0993bd622f96ed54614c25b6a9aa527589eaaffcf17ddf7",
+                output_str: "3ae18402ad4123af1ad868450591c46f66431d422a29d932df94af9ab3e256f806575b3eb0d24edc7531725e0336847b2e571ae667b619a9d79a3e168948af5d"
+            },
+            Test {
+                input: "3c9b46450c0f2cae8e3823f8bdb4277f31b744ce2eb17054bddc6dff36af7f49fb8a2320cc3bdf8e0a2ea29ad3a55de1165d219adeddb5175253e2d1489e9b6fdd02e2c3d3a4b54d60e3a47334c37913c5695378a669e9b72dec32af5434f93f46176ebf044c4784467c700470d0c0b40c8a088c815816",
+                output_str: "6f3e1294b67d875165fd09dd493dd55924e9e28e53afa2da80916d7d54e19c1705121d617e53f56eba4767d6435e986feeaeb965ec4956fd3c02de1288fbc661"
+            },
+            Test {
+                input: "d1e654b77cb155f5c77971a64df9e5d34c26a3cad6c7f6b300d39deb1910094691adaa095be4ba5d86690a976428635d5526f3e946f7dc3bd4dbc78999e653441187a81f9adcd5a3c5f254bc8256b0158f54673dcc1232f6e918ebfc6c51ce67eaeb042d9f57eec4bfe910e169af78b3de48d137df4f2840",
+                output_str: "aa3398bc7daeb4f22ca6d1937b0c6097a49adb6dbc03fc0f5226a644f217296bf55747269b861fc7b22bc5956ce3d8da28e9f25d8c9599bc653cd0ee0c852473"
+            },
+            Test {
+                input: "626f68c18a69a6590159a9c46be03d5965698f2dac3de779b878b3d9c421e0f21b955a16c715c1ec1e22ce3eb645b8b4f263f60660ea3028981eebd6c8c3a367285b691c8ee56944a7cd1217997e1d9c21620b536bdbd5de8925ff71dec6fbc06624ab6b21e329813de90d1e572dfb89a18120c3f606355d25",
+                output_str: "8bcbbe36dbe305fbb558ea46721d25de7aab7898e583e8bdf26701224387c524c683475c242c7de090608a4f17663d217276f94f4188b942a03039b5e38d6ae3"
+            },
+            Test {
+                input: "651a6fb3c4b80c7c68c6011675e6094eb56abf5fc3057324ebc6477825061f9f27e7a94633abd1fa598a746e4a577caf524c52ec1788471f92b8c37f23795ca19d559d446cab16cbcdce90b79fa1026cee77bf4ab1b503c5b94c2256ad75b3eac6fd5dcb96aca4b03a834bfb4e9af988cecbf2ae597cb9097940",
+                output_str: "4782dfcab650e7a8dae9a010cb002dd0373bfbd31247fa9860876d7fffd2d57c355f2054cb2efeb45c5871f284f46b025798344a3719efab34d15152dd0bbc6c"
+            },
+            Test {
+                input: "8aaf072fce8a2d96bc10b3c91c809ee93072fb205ca7f10abd82ecd82cf040b1bc49ea13d1857815c0e99781de3adbb5443ce1c897e55188ceaf221aa9681638de05ae1b322938f46bce51543b57ecdb4c266272259d1798de13be90e10efec2d07484d9b21a3870e2aa9e06c21aa2d0c9cf420080a80a91dee16f",
+                output_str: "a4d538e449e2b3ebf9aafc88d29e514ba0d2c8de2706f3f6fa5a2c4f95f5db5bab59c1a69c16e4859a19730abb2e6bf06152445eda80e3be5ce652023ea57e5e"
+            },
+            Test {
+                input: "53f918fd00b1701bd504f8cdea803acca21ac18c564ab90c2a17da592c7d69688f6580575395551e8cd33e0fef08ca6ed4588d4d140b3e44c032355df1c531564d7f4835753344345a6781e11cd5e095b73df5f82c8ae3ad00877936896671e947cc52e2b29dcd463d90a0c9929128da222b5a211450bbc0e02448e2",
+                output_str: "8732d243f1b3349f900df430659b9ab9ed99f626ad35cb2084b57d60e5a5b47213ad213859cd40964c5a267c236d0e38167525f778e67e37d4f623a8884128ed"
+            },
+            Test {
+                input: "a64599b8a61b5ccec9e67aed69447459c8da3d1ec6c7c7c82a7428b9b584fa67e90f68e2c00fbbed4613666e5168da4a16f395f7a3c3832b3b134bfc9cbaa95d2a0fe252f44ac6681eb6d40ab91c1d0282fed6701c57463d3c5f2bb8c6a7301fb4576aa3b5f15510db8956ff77478c26a7c09bea7b398cfc83503f538e",
+                output_str: "97dc2606e14f7bfff1fca497965e36caa3a81cfd6459d0254529f64da40ffe7442c08a151d6cee3b46bf3414e80110a0f71eee44d7940027dee90e919e498d65"
+            },
+            Test {
+                input: "0e3ab0e054739b00cdb6a87bd12cae024b54cb5e550e6c425360c2e87e59401f5ec24ef0314855f0f56c47695d56a7fb1417693af2a1ed5291f2fee95f75eed54a1b1c2e81226fbff6f63ade584911c71967a8eb70933bc3f5d15bc91b5c2644d9516d3c3a8c154ee48e118bd1442c043c7a0dba5ac5b1d5360aae5b9065",
+                output_str: "de5978eace4e51f7d289f2befbecb3aac8e9cad48fa0f7310c673d52bbcaeebde49cb5a76d334d6dfdd51ac1ab24e9e1cdc915069dbddb3d2e30b0b0c26b3ee1"
+            },
+            Test {
+                input: "a62fc595b4096e6336e53fcdfc8d1cc175d71dac9d750a6133d23199eaac288207944cea6b16d27631915b4619f743da2e30a0c00bbdb1bbb35ab852ef3b9aec6b0a8dcc6e9e1abaa3ad62ac0a6c5de765de2c3711b769e3fde44a74016fff82ac46fa8f1797d3b2a726b696e3dea5530439acee3a45c2a51bc32dd055650b",
+                output_str: "33abca29a8a7094cfb10be4a80e81f8001ebb933c0d4b98a695b22ab553f94f07646abce6adf491817d17b78c40747d56faf88a613138ca0e596636c672397b4"
+            },
+            Test {
+                input: "2b6db7ced8665ebe9deb080295218426bdaa7c6da9add2088932cdffbaa1c14129bccdd70f369efb149285858d2b1d155d14de2fdb680a8b027284055182a0cae275234cc9c92863c1b4ab66f304cf0621cd54565f5bff461d3b461bd40df28198e3732501b4860eadd503d26d6e69338f4e0456e9e9baf3d827ae685fb1d817",
+                output_str: "4fab45806b4628068458b5d0a2d4bf101b8bfc9276ef86ad5d883765c43f72ce8a5f7b4c5b535a915130bb185e699ab62228014e54df790c0e93aadbe7e39e19"
+            },
+            Test {
+                input: "10db509b2cdcaba6c062ae33be48116a29eb18e390e1bbada5ca0a2718afbcd23431440106594893043cc7f2625281bf7de2655880966a23705f0c5155c2f5cca9f2c2142e96d0a2e763b70686cd421b5db812daced0c6d65035fde558e94f26b3e6dde5bd13980cc80292b723013bd033284584bff27657871b0cf07a849f4ae2",
+                output_str: "5f0bfb4146910cf0c320364b6ad8a02b0966229ab2676d9670f0dd241e8104db02797eefea0b9cabbe90a44757b033755925b2fccf3a00054f9ae8fbcef752a8"
+            },
+            Test {
+                input: "9334de60c997bda6086101a6314f64e4458f5ff9450c509df006e8c547983c651ca97879175aaba0c539e82d05c1e02c480975cbb30118121061b1ebac4f8d9a3781e2db6b18042e01ecf9017a64a0e57447ec7fcbe6a7f82585f7403ee2223d52d37b4bf426428613d6b4257980972a0acab508a7620c1cb28eb4e9d30fc41361ec",
+                output_str: "d38ef3b12eaa0bf62a75b6b63cff3c9ef171de1b75f5d02629365bcfe65ba7ddd30fcef7febb82f19f9bedcc1cc4c679b4292ea62c2a90a7562da9a1318fe278"
+            },
+            Test {
+                input: "e88ab086891693aa535ceb20e64c7ab97c7dd3548f3786339897a5f0c39031549ca870166e477743ccfbe016b4428d89738e426f5ffe81626137f17aecff61b72dbee2dc20961880cfe281dfab5ee38b1921881450e16032de5e4d55ad8d4fca609721b0692bac79be5a06e177fe8c80c0c83519fb3347de9f43d5561cb8107b9b5edc",
+                output_str: "60c95c274f99b8643a186344bc01d1279010be55d1be76f4e6f919f6b54d335ee0e1ca92133f3d7a2520cd82c4000e15efed8d8a66f31b16b0977c63de1beb05"
+            },
+            Test {
+                input: "fd19e01a83eb6ec810b94582cb8fbfa2fcb992b53684fb748d2264f020d3b960cb1d6b8c348c2b54a9fcea72330c2aaa9a24ecdb00c436abc702361a82bb8828b85369b8c72ece0082fe06557163899c2a0efa466c33c04343a839417057399a63a3929be1ee4805d6ce3e5d0d0967fe9004696a5663f4cac9179006a2ceb75542d75d68",
+                output_str: "9385d0ed9e73498e24b8c6e746a1c6be8011ee30fcac9ba17224ee2012378522c78f8737a224621fba19c42040c5c7f38ac07b40e0e75ebc59d17975ee85d655"
+            },
+            Test {
+                input: "59ae20b6f7e0b3c7a989afb28324a40fca25d8651cf1f46ae383ef6d8441587aa1c04c3e3bf88e8131ce6145cfb8973d961e8432b202fa5af3e09d625faad825bc19da9b5c6c20d02abda2fcc58b5bd3fe507bf201263f30543819510c12bc23e2ddb4f711d087a86edb1b355313363a2de996b891025e147036087401ccf3ca7815bf3c49",
+                output_str: "7487164d408874afdf07ebdade8c62e756147beab3238b8738aeed927f54fe6d33af3917d4e181b50cbc88a379c73585f9fba4c1b67b4be449004ea0f66d11ad"
+            },
+            Test {
+                input: "77ee804b9f3295ab2362798b72b0a1b2d3291dceb8139896355830f34b3b328561531f8079b79a6e9980705150866402fdc176c05897e359a6cb1a7ab067383eb497182a7e5aef7038e4c96d133b2782917417e391535b5e1b51f47d8ed7e4d4025fe98dc87b9c1622614bff3d1029e68e372de719803857ca52067cddaad958951cb2068cc6",
+                output_str: "0f41ab2d10c51e28638dad178655f160b2f753db44eed6ce4104693cc4a938d887617774afecb33b890ee7fc577656ce168eea42c604d152b952c9b772c9b530"
+            },
+            Test {
+                input: "b771d5cef5d1a41a93d15643d7181d2a2ef0a8e84d91812f20ed21f147bef732bf3a60ef4067c3734b85bc8cd471780f10dc9e8291b58339a677b960218f71e793f2797aea349406512829065d37bb55ea796fa4f56fd8896b49b2cd19b43215ad967c712b24e5032d065232e02c127409d2ed4146b9d75d763d52db98d949d3b0fed6a8052fbb",
+                output_str: "7575a1fb4fc9a8f9c0466bd5fca496d1cb78696773a212a5f62d02d14e3259d192a87eba4407dd83893527331407b6dadaad920dbc46489b677493ce5f20b595"
+            },
+            Test {
+                input: "b32d95b0b9aad2a8816de6d06d1f86008505bd8c14124f6e9a163b5a2ade55f835d0ec3880ef50700d3b25e42cc0af050ccd1be5e555b23087e04d7bf9813622780c7313a1954f8740b6ee2d3f71f768dd417f520482bd3a08d4f222b4ee9dbd015447b33507dd50f3ab4247c5de9a8abd62a8decea01e3b87c8b927f5b08beb37674c6f8e380c04",
+                output_str: "2e293765022d48996ce8eff0be54e87efb94a14c72de5acd10d0eb5ece029cadfa3ba17a40b2ffa2163991b17786e51caba79e5e0ffd34cf085e2a098be8bacb"
+            },
+            Test {
+                input: "04410e31082a47584b406f051398a6abe74e4da59bb6f85e6b49e8a1f7f2ca00dfba5462c2cd2bfde8b64fb21d70c083f11318b56a52d03b81cac5eec29eb31bd0078b6156786da3d6d8c33098c5c47bb67ac64db14165af65b44544d806dde5f487d5373c7f9792c299e9686b7e5821e7c8e2458315b996b5677d926dac57b3f22da873c601016a0d",
+                output_str: "be8e14b6757ffe53c9b75f6dde9a7b6c40474041de83d4a60645a826d7af1abe1eefcb7b74b62ca6a514e5f2697d585bfecece12931bbe1d4ed7ebf7b0be660e"
+            },
+            Test {
+                input: "8b81e9badde026f14d95c019977024c9e13db7a5cd21f9e9fc491d716164bbacdc7060d882615d411438aea056c340cdf977788f6e17d118de55026855f93270472d1fd18b9e7e812bae107e0dfde7063301b71f6cfe4e225cab3b232905a56e994f08ee2891ba922d49c3dafeb75f7c69750cb67d822c96176c46bd8a29f1701373fb09a1a6e3c7158f",
+                output_str: "6c7e64ee0d826073d4f44bcf1586a83bacf3e2e138dfdb65b8b8b35fd7dae300ea6e32c6245cca27c674feb2196755945ab7c5dce99eab9158a75518ac27c431"
+            },
+            Test {
+                input: "fa6eed24da6666a22208146b19a532c2ec9ba94f09f1def1e7fc13c399a48e41acc2a589d099276296348f396253b57cb0e40291bd282773656b6e0d8bea1cda084a3738816a840485fcf3fb307f777fa5feac48695c2af4769720258c77943fb4556c362d9cba8bf103aeb9034baa8ea8bfb9c4f8e6742ce0d52c49ea8e974f339612e830e9e7a9c29065",
+                output_str: "5842d4da2c309d9b2aa7cfae702262f770a8e646620d65c17271416e9d7981ff93d228cd60dc1cc16921020d841e439e87f085e503d466c904abf8cdd5eccaa9"
+            },
+            Test {
+                input: "9bb4af1b4f09c071ce3cafa92e4eb73ce8a6f5d82a85733440368dee4eb1cbc7b55ac150773b6fe47dbe036c45582ed67e23f4c74585dab509df1b83610564545642b2b1ec463e18048fc23477c6b2aa035594ecd33791af6af4cbc2a1166aba8d628c57e707f0b0e8707caf91cd44bdb915e0296e0190d56d33d8dde10b5b60377838973c1d943c22ed335e",
+                output_str: "f8b24527b5c84ca9a702db2f535f78ed0323c2932a255db24f872551ca7f5c0482b3690c62eec8ad69308db2d72308c4d615cde3835b39b4f6ff115466f32763"
+            },
+            Test {
+                input: "2167f02118cc62043e9091a647cadbed95611a521fe0d64e8518f16c808ab297725598ae296880a773607a798f7c3cfce80d251ebec6885015f9abf7eaabae46798f82cb5926de5c23f44a3f9f9534b3c6f405b5364c2f8a8bdc5ca49c749bed8ce4ba48897062ae8424ca6dde5f55c0e42a95d1e292ca54fb46a84fbc9cd87f2d0c9e7448de3043ae22fdd229",
+                output_str: "08c6e3938de48171a99646bd090b7d53ff422ae63f99850032bd131ac7bdfba8f83466ad31fad3169d8a320fd9548bdff2c40ba20e0d031a8054019c40ed2662"
+            },
+            Test {
+                input: "94b7fa0bc1c44e949b1d7617d31b4720cbe7ca57c6fa4f4094d4761567e389ecc64f6968e4064df70df836a47d0c713336b5028b35930d29eb7a7f9a5af9ad5cf441745baec9bb014ceeff5a41ba5c1ce085feb980bab9cf79f2158e03ef7e63e29c38d7816a84d4f71e0f548b7fc316085ae38a060ff9b8dec36f91ad9ebc0a5b6c338cbb8f6659d342a24368cf",
+                output_str: "6978ad4bc4f0fc44c35c6691ca46627d840baa572de9b0216673c988197191cdf812cf21920e052cc9ce1d507d1ba7db6f151d01620ada702dc637bf90809c19"
+            },
+            Test {
+                input: "ea40e83cb18b3a242c1ecc6ccd0b7853a439dab2c569cfc6dc38a19f5c90acbf76aef9ea3742ff3b54ef7d36eb7ce4ff1c9ab3bc119cff6be93c03e208783335c0ab8137be5b10cdc66ff3f89a1bddc6a1eed74f504cbe7290690bb295a872b9e3fe2cee9e6c67c41db8efd7d863cf10f840fe618e7936da3dca5ca6df933f24f6954ba0801a1294cd8d7e66dfafec",
+                output_str: "3a8e938c45f3f177991296b24565d9a6605516615d96a062c8be53a0d6c5a6487be35d2a8f3cf6620d0c2dba2c560d68295f284be7f82f3b92919033c9ce5d80"
+            },
+            Test {
+                input: "157d5b7e4507f66d9a267476d33831e7bb768d4d04cc3438da12f9010263ea5fcafbde2579db2f6b58f911d593d5f79fb05fe3596e3fa80ff2f761d1b0e57080055c118c53e53cdb63055261d7c9b2b39bd90acc32520cbbdbda2c4fd8856dbcee173132a2679198daf83007a9b5c51511ae49766c792a29520388444ebefe28256fb33d4260439cba73a9479ee00c63",
+                output_str: "fe45289874879720ce2a844ae34bb73522775dcb6019dcd22b8885994672a0889c69e8115c641dc8b83e39f7311815a164dc46e0ba2fca344d86d4bc2ef2532c"
+            },
+            Test {
+                input: "836b34b515476f613fe447a4e0c3f3b8f20910ac89a3977055c960d2d5d2b72bd8acc715a9035321b86703a411dde0466d58a59769672aa60ad587b8481de4bba552a1645779789501ec53d540b904821f32b0bd1855b04e4848f9f8cfe9ebd8911be95781a759d7ad9724a7102dbe576776b7c632bc39b9b5e19057e226552a5994c1dbb3b5c7871a11f5537011044c53",
+                output_str: "aff61c6e11b98e55ac213b1a0bc7de0405221ac5efb1229842e4614f4a029c9bd14a0ed7fd99af3681429f3f309fdb53166aa9a3cd9f1f1223d04b4a9015e94a"
+            },
+            Test {
+                input: "cc7784a4912a7ab5ad3620aab29ba87077cd3cb83636adc9f3dc94f51edf521b2161ef108f21a0a298557981c0e53ce6ced45bdf782c1ef200d29bab81dd6460586964edab7cebdbbec75fd7925060f7da2b853b2b089588fa0f8c16ec6498b14c55dcee335cb3a91d698e4d393ab8e8eac0825f8adebeee196df41205c011674e53426caa453f8de1cbb57932b0b741d4c6",
+                output_str: "26410e1a0d1e3659438dddb2953eb3aa082ceb02a327fa0098574d89f9236f5dff9c17def37f6ce4b5dc1ee5f23f578fe191ee8b51f1b8034bcbbbb7b6a500a5"
+            },
+            Test {
+                input: "7639b461fff270b2455ac1d1afce782944aea5e9087eb4a39eb96bb5c3baaf0e868c8526d3404f9405e79e77bfac5ffb89bf1957b523e17d341d7323c302ea7083872dd5e8705694acdda36d5a1b895aaa16eca6104c82688532c8bfe1790b5dc9f4ec5fe95baed37e1d287be710431f1e5e8ee105bc42ed37d74b1e55984bf1c09fe6a1fa13ef3b96faeaed6a2a1950a12153",
+                output_str: "5015da2a2e1661d3a52a65d19f02933029839f72717a77b5045198665093f944cff85e094d418396a51c574157eed9fb6bdd4eca53278fab62af699b53c82f58"
+            },
+            Test {
+                input: "eb6513fc61b30cfba58d4d7e80f94d14589090cf1d80b1df2e68088dc6104959ba0d583d585e9578ab0aec0cf36c48435eb52ed9ab4bbce7a5abe679c97ae2dbe35e8cc1d45b06dda3cf418665c57cbee4bbb47fa4caf78f4ee656fec237fe4eebbafa206e1ef2bd0ee4ae71bd0e9b2f54f91daadf1febfd7032381d636b733dcb3bf76fb14e23aff1f68ed3dbcf75c9b99c6f26",
+                output_str: "b27828cfebcf4d896eabf1f84d079827b7dcc7f308a20476474de518829a89aac3dc50272cfa976b0b5819c45c9eefc51b87a27d11c9e5f9579121125a887542"
+            },
+            Test {
+                input: "1594d74bf5dde444265d4c04dad9721ff3e34cbf622daf341fe16b96431f6c4df1f760d34f296eb97d98d560ad5286fec4dce1724f20b54fd7df51d4bf137add656c80546fb1bf516d62ee82baa992910ef4cc18b70f3f8698276fcfb44e0ec546c2c39cfd8ee91034ff9303058b4252462f86c823eb15bf481e6b79cc3a02218595b3658e8b37382bd5048eaed5fd02c37944e73b",
+                output_str: "42fc06dcf99b4e804bb349101b46d6a6a7366e47555406ea554248baef52e17afa40829f5709d07ff407881df106f156ca735622b0f051d8c372f6e811cdae25"
+            },
+            Test {
+                input: "4cfa1278903026f66fedd41374558be1b585d03c5c55dac94361df286d4bd39c7cb8037ed3b267b07c346626449d0cc5b0dd2cf221f7e4c3449a4be99985d2d5e67bff2923357ddeab5abcb4619f3a3a57b2cf928a022eb27676c6cf805689004fca4d41ea6c2d0a4789c7605f7bb838dd883b3ad3e6027e775bcf262881428099c7fff95b14c095ea130e0b9938a5e22fc52650f591",
+                output_str: "0ca89c9b7273de384ff33f1bacbb8505628c4d3e30350b335361563ad416ada523122d37acbec57721f7bc5d9b049e1f4fe3c4cfe047e33a0e448ef5d5536cf0"
+            },
+            Test {
+                input: "d3e65cb92cfa79662f6af493d696a07ccf32aaadcceff06e73e8d9f6f909209e66715d6e978788c49efb9087b170ecf3aa86d2d4d1a065ae0efc8924f365d676b3cb9e2bec918fd96d0b43dee83727c9a93bf56ca2b2e59adba85696546a815067fc7a78039629d4948d157e7b0d826d1bf8e81237bab7321312fdaa4d521744f988db6fdf04549d0fdca393d639c729af716e9c8bba48",
+                output_str: "78c59a8cdf4d1d07a66bb2faa7ffa2112d5c0fcabf7e3589e97623bdb922af9af24918c2ccfce2b880bf64145c70dc9a4fde78fdf0918dd2ce5fea9cf99acd41"
+            },
+            Test {
+                input: "842cc583504539622d7f71e7e31863a2b885c56a0ba62db4c2a3f2fd12e79660dc7205ca29a0dc0a87db4dc62ee47a41db36b9ddb3293b9ac4baae7df5c6e7201e17f717ab56e12cad476be49608ad2d50309e7d48d2d8de4fa58ac3cfeafeee48c0a9eec88498e3efc51f54d300d828dddccb9d0b06dd021a29cf5cb5b2506915beb8a11998b8b886e0f9b7a80e97d91a7d01270f9a7717",
+                output_str: "cf4d52d20272de014d367310775287ee5e5cb34cf9af78e65d1d1fe7fb1f13b62dd9b83c382baa6ab4f6949478c8598fef78e8d535311fc19808cb75e22daded"
+            },
+            Test {
+                input: "6c4b0a0719573e57248661e98febe326571f9a1ca813d3638531ae28b4860f23c3a3a8ac1c250034a660e2d71e16d3acc4bf9ce215c6f15b1c0fc7e77d3d27157e66da9ceec9258f8f2bf9e02b4ac93793dd6e29e307ede3695a0df63cbdc0fc66fb770813eb149ca2a916911bee4902c47c7802e69e405fe3c04ceb5522792a5503fa829f707272226621f7c488a7698c0d69aa561be9f378",
+                output_str: "33d632e403c9f9a9349b28aa4821a12b1db557d8928003d30c57d701cff1c49bac9472cecff450e4d91d36c6cd78221790eff6f0fbf498034014cbbace5dcf09"
+            },
+            Test {
+                input: "51b7dbb7ce2ffeb427a91ccfe5218fd40f9e0b7e24756d4c47cd55606008bdc27d16400933906fd9f30effdd4880022d081155342af3fb6cd53672ab7fb5b3a3bcbe47be1fd3a2278cae8a5fd61c1433f7d350675dd21803746cadca574130f01200024c6340ab0cc2cf74f2234669f34e9009ef2eb94823d62b31407f4ba46f1a1eec41641e84d77727b59e746b8a671bef936f05be820759fa",
+                output_str: "954c709abcb0bb881592d93f5c2463ce8c060ad1df3053302ea7b19f2b47bcf0fe359a832f9a865a8d3dbd3be598dfd6d0fc1c574eca0aec78d8e3288399be05"
+            },
+            Test {
+                input: "83599d93f5561e821bd01a472386bc2ff4efbd4aed60d5821e84aae74d8071029810f5e286f8f17651cd27da07b1eb4382f754cd1c95268783ad09220f5502840370d494beb17124220f6afce91ec8a0f55231f9652433e5ce3489b727716cf4aeba7dcda20cd29aa9a859201253f948dd94395aba9e3852bd1d60dda7ae5dc045b283da006e1cbad83cc13292a315db5553305c628dd091146597",
+                output_str: "a337062f5e5c9c35341a51224f2a59e6cf919a63bf59a6cfce261194bbd660f28c2948d03cdce5c7c151ec05b42aadd83051a16a62f0c7df39aaa4efc82ce4d3"
+            },
+            Test {
+                input: "2be9bf526c9d5a75d565dd11ef63b979d068659c7f026c08bea4af161d85a462d80e45040e91f4165c074c43ac661380311a8cbed59cc8e4c4518e80cd2c78ab1cabf66bff83eab3a80148550307310950d034a6286c93a1ece8929e6385c5e3bb6ea8a7c0fb6d6332e320e71cc4eb462a2a62e2bfe08f0ccad93e61bedb5dd0b786a728ab666f07e0576d189c92bf9fb20dca49ac2d3956d47385e2",
+                output_str: "43e9d0ea8e526e83234d7b63d8244c7e7b12ae2acc8082f986367268f10156574300172873845b207a7252624246e7d32ce0f7282e00c4552f6180f34e590e2e"
+            },
+            Test {
+                input: "ca76d3a12595a817682617006848675547d3e8f50c2210f9af906c0e7ce50b4460186fe70457a9e879e79fd4d1a688c70a347361c847ba0dd6aa52936eaf8e58a1be2f5c1c704e20146d366aeb3853bed9de9befe9569ac8aaea37a9fb7139a1a1a7d5c748605a8defb297869ebedd71d615a5da23496d11e11abbb126b206fa0a7797ee7de117986012d0362dcef775c2fe145ada6bda1ccb326bf644",
+                output_str: "f7da8d1e49d0d964400ee40f9c88e07025a8b0b00cadc624a63e2ea85b1598e22c8802be0c1ff368519549a752e02546093d3b984e24600ba2ab7c792b9e074a"
+            },
+            Test {
+                input: "f76b85dc67421025d64e93096d1d712b7baf7fb001716f02d33b2160c2c882c310ef13a576b1c2d30ef8f78ef8d2f465007109aad93f74cb9e7d7bef7c9590e8af3b267c89c15db238138c45833c98cc4a471a7802723ef4c744a853cf80a0c2568dd4ed58a2c9644806f42104cee53628e5bdf7b63b0b338e931e31b87c24b146c6d040605567ceef5960df9e022cb469d4c787f4cba3c544a1ac91f95f",
+                output_str: "d9a42761f980c78c36cf54c4207b0a62954e15a907a7cea149b37a4e0a6376202ff8f12e16ebad3aecc7ff3a9d6ad093b068dfe272e3b9646b1aedc04961dc81"
+            },
+            Test {
+                input: "25b8c9c032ea6bcd733ffc8718fbb2a503a4ea8f71dea1176189f694304f0ff68e862a8197b839957549ef243a5279fc2646bd4c009b6d1edebf24738197abb4c992f6b1dc9ba891f570879accd5a6b18691a93c7d0a8d38f95b639c1daeb48c4c2f15ccf5b9d508f8333c32de78781b41850f261b855c4bebcc125a380c54d501c5d3bd07e6b52102116088e53d76583b0161e2a58d0778f091206aabd5a1",
+                output_str: "bb65d8943413cef89fdb05b35a55ec7503e4546a50fc3ecc825dabc1a1dae6c771bb197f323625877e0bccaa41253c99b6692976b99fc687b0b6b3e9aab478c4"
+            },
+            Test {
+                input: "21cfdc2a7ccb7f331b3d2eefff37e48ad9fa9c788c3f3c200e0173d99963e1cbca93623b264e920394ae48bb4c3a5bb96ffbc8f0e53f30e22956adabc2765f57fb761e147ecbf8567533db6e50c8a1f894310a94edf806dd8ca6a0e141c0fa7c9fae6c6ae65f18c93a8529e6e5b553bf55f25be2e80a9882bd37f145fecbeb3d447a3c4e46c21524cc55cdd62f521ab92a8ba72b897996c49bb273198b7b1c9e",
+                output_str: "540df22180b69b9a83306619b2ca8cd8e07a34bbeb2219ac7cf88b468a947c4448489b303bd65506c9e1ce59348a9d863aab5154848e95b5389783f6f5fb6ad8"
+            },
+            Test {
+                input: "4e452ba42127dcc956ef4f8f35dd68cb225fb73b5bc7e1ec5a898bba2931563e74faff3b67314f241ec49f4a7061e3bd0213ae826bab380f1f14faab8b0efddd5fd1bb49373853a08f30553d5a55ccbbb8153de4704f29ca2bdeef0419468e05dd51557ccc80c0a96190bbcc4d77ecff21c66bdf486459d427f986410f883a80a5bcc32c20f0478bb9a97a126fc5f95451e40f292a4614930d054c851acd019ccf",
+                output_str: "062e4a11a79fdb9cbc3a0e4c5f9875caaa568bc713066e02d2a9ca4d27886ce23f70083a2bf4d0e7c55b120fe6d197203dc1c2fd3469112a08836727859e1f83"
+            },
+            Test {
+                input: "fa85671df7dadf99a6ffee97a3ab9991671f5629195049880497487867a6c446b60087fac9a0f2fcc8e3b24e97e42345b93b5f7d3691829d3f8ccd4bb36411b85fc2328eb0c51cb3151f70860ad3246ce0623a8dc8b3c49f958f8690f8e3860e71eb2b1479a5cea0b3f8befd87acaf5362435eaeccb52f38617bc6c5c2c6e269ead1fbd69e941d4ad2012da2c5b21bcfbf98e4a77ab2af1f3fda3233f046d38f1dc8",
+                output_str: "9e1c6ee0c47b2d2cb77f602cab53ac4c69c69778297894554196cb58060332c9fd8923f45c4b8ec26e16a5d04e6307fb99850a4540ea83e3f2626f3343e97225"
+            },
+            Test {
+                input: "e90847ae6797fbc0b6b36d6e588c0a743d725788ca50b6d792352ea8294f5ba654a15366b8e1b288d84f5178240827975a763bc45c7b0430e8a559df4488505e009c63da994f1403f407958203cebb6e37d89c94a5eacf6039a327f6c4dbbc7a2a307d976aa39e41af6537243fc218dfa6ab4dd817b6a397df5ca69107a9198799ed248641b63b42cb4c29bfdd7975ac96edfc274ac562d0474c60347a078ce4c25e88",
+                output_str: "f18f0b072a6bf608a6c7420e891be3795a6d19ba3e1276c826f1ae775cf125e428ae1a397cfd074be0cd24f7100f51800f14471ccf4f485a6571e2b32e02611f"
+            },
+            Test {
+                input: "f6d5c2b6c93954fc627602c00c4ca9a7d3ed12b27173f0b2c9b0e4a5939398a665e67e69d0b12fb7e4ceb253e8083d1ceb724ac07f009f094e42f2d6f2129489e846eaff0700a8d4453ef453a3eddc18f408c77a83275617fabc4ea3a2833aa73406c0e966276079d38e8e38539a70e194cc5513aaa457c699383fd1900b1e72bdfb835d1fd321b37ba80549b078a49ea08152869a918ca57f5b54ed71e4fd3ac5c06729",
+                output_str: "2859a3165f38cb59de4275658bbae9a0ad647d972cf98fa0eec4c07ee75d576dbf9f5dd19a881db4e4f7db31ec0d77165911329cbe8a46d14d3ea7fdcb8a5c80"
+            },
+            Test {
+                input: "cf8562b1bed89892d67ddaaf3deeb28246456e972326dbcdb5cf3fb289aca01e68da5d59896e3a6165358b071b304d6ab3d018944be5049d5e0e2bb819acf67a6006111089e6767132d72dd85beddcbb2d64496db0cc92955ab4c6234f1eea24f2d51483f2e209e4589bf9519fac51b4d061e801125e605f8093bb6997bc163d551596fe4ab7cfae8fb9a90f6980480ce0c229fd1675409bd788354daf316240cfe0af93eb",
+                output_str: "9281bd03fe95545e5321a91a0ad8fa75a005b928c83450df657419870c4e980e32484fcf1f598702ed20404fece48a2ee9dbcf22120654ae402951605bed197e"
+            },
+            Test {
+                input: "2ace31abb0a2e3267944d2f75e1559985db7354c6e605f18dc8470423fca30b7331d9b33c4a4326783d1caae1b4f07060eff978e4746bf0c7e30cd61040bd5ec2746b29863eb7f103ebda614c4291a805b6a4c8214230564a0557bc7102e0bd3ed23719252f7435d64d210ee2aafc585be903fa41e1968c50fd5d5367926df7a05e3a42cf07e656ff92de73b036cf8b19898c0cb34557c0c12c2d8b84e91181af467bc75a9d1",
+                output_str: "6ca7023e20735624e83995a9e8aeba66b9bc8d0a30df67108eff8aedeb3b3ca484457bd0277c2552cbc7d63dc87eb556f2199c54ea73bae647764de18489b1f1"
+            },
+            Test {
+                input: "0d8d09aed19f1013969ce5e7eb92f83a209ae76be31c754844ea9116ceb39a22ebb6003017bbcf26555fa6624185187db8f0cb3564b8b1c06bf685d47f3286eda20b83358f599d2044bbf0583fab8d78f854fe0a596183230c5ef8e54426750eaf2cc4e29d3bdd037e734d863c2bd9789b4c243096138f7672c232314effdfc6513427e2da76916b5248933be312eb5dde4cf70804fb258ac5fb82d58d08177ac6f4756017fff5",
+                output_str: "a965e699c1ffaee369b3651c3a318582ae329ae51e6ccfb5275f58f748cedb8f6b8434fac4a1135ad9b555aa8cc1ff99a2220cbe83bfc1c374ffc927bb00abd3"
+            },
+            Test {
+                input: "c3236b73deb7662bf3f3daa58f137b358ba610560ef7455785a9befdb035a066e90704f929bd9689cef0ce3bda5acf4480bceb8d09d10b098ad8500d9b6071dfc3a14af6c77511d81e3aa8844986c3bea6f469f9e02194c92868cd5f51646256798ff0424954c1434bdfed9facb390b07d342e992936e0f88bfd0e884a0ddb679d0547ccdec6384285a45429d115ac7d235a717242021d1dc35641f5f0a48e8445dba58e6cb2c8ea",
+                output_str: "4b44ec2d1848d0ec43ab0793390d24535f3328ad23c5f8fc43f5579bd16d84bba08b233b0b5e24e22bf6ca2defeaca16bb98f8cdeaf26eecf2fc94afe4604cf4"
+            },
+            Test {
+                input: "b39feb8283eadc63e8184b51df5ae3fd41aac8a963bb0be1cd08aa5867d8d910c669221e73243360646f6553d1ca05a84e8dc0de05b6419ec349ca994480193d01c92525f3fb3dcefb08afc6d26947bdbbfd85193f53b50609c6140905c53a6686b58e53a319a57b962331ede98149af3de3118a819da4d76706a0424b4e1d2910b0ed26af61d150ebcb46595d4266a0bd7f651ba47d0c7f179ca28545007d92e8419d48fdfbd744ce",
+                output_str: "73169f0be264565e45fb8f4665753e55f240846eb0d481cef0274e4a3d859521767d9f675c0628ddce155267ba686f2142805713f20c4c25e0b24398c65e3480"
+            },
+            Test {
+                input: "a983d54f503803e8c7999f4edbbe82e9084f422143a932ddddc47a17b0b7564a7f37a99d0786e99476428d29e29d3c197a72bfab1342c12a0fc4787fd7017d7a6174049ea43b5779169ef7472bdbbd941dcb82fc73aac45a8a94c9f2bd3477f61fd3b796f02a1b8264a214c6fea74b7051b226c722099ec7883a462b83b6afdd4009248b8a237f605fe5a08fe7d8b45321421ebba67bd70a0b00ddbf94baab7f359d5d1eea105f28dcfb",
+                output_str: "9e1c196cb73d1efa288d63902c64ce1a340bcdb8197f4afecb1118dadd0d076b5fb7f6f809666cc58d2a8c1a68c65d0e91554c41d083f56d7b3dd37df1b6c494"
+            },
+            Test {
+                input: "e4d1c1897a0a866ce564635b74222f9696bf2c7f640dd78d7e2aca66e1b61c642bb03ea7536aae597811e9bf4a7b453ede31f97b46a5f0ef51a071a2b3918df16b152519ae3776f9f1edab4c2a377c3292e96408359d3613844d5eb393000283d5ad3401a318b12fd1474b8612f2bb50fb6a8b9e023a54d7dde28c43d6d8854c8d9d1155935c199811dbfc87e9e0072e90eb88681cc7529714f8fb8a2c9d88567adfb974ee205a9bf7b848",
+                output_str: "0c429cc164253c09538668135c9436fdbc79da8e1fbe92e7bbc6eb30627591e7347ccb43f7aec2d37ff3dabcfc9fa0c80629937c0c177c1c7ed0fc76a15df075"
+            },
+            Test {
+                input: "b10c59723e3dcadd6d75df87d0a1580e73133a9b7d00cb95ec19f5547027323be75158b11f80b6e142c6a78531886d9047b08e551e75e6261e79785366d7024bd7cd9cf322d9be7d57fb661069f2481c7bb759cd71b4b36ca2bc2df6d3a328faebdb995a9794a8d72155ed551a1f87c80bf6059b43fc764900b18a1c2441f7487743cf84e565f61f8dd2ece6b6ccc9444049197aaaf53e926fbee3bfca8be588ec77f29d211be89de18b15f6",
+                output_str: "700112fa90a1a2fd039a41b6485401634e757840e422aeb4a236634958192ffb2f2ddfa2253fc1ecb211c7e036098b714e62f7bf2b6975b1e95faa9b8d02a73a"
+            },
+            Test {
+                input: "db11f609baba7b0ca634926b1dd539c8cbada24967d7add4d9876f77c2d80c0f4dcefbd7121548373582705cca2495bd2a43716fe64ed26d059cfb566b3364bd49ee0717bdd9810dd14d8fad80dbbdc4cafb37cc60fb0fe2a80fb4541b8ca9d59dce457738a9d3d8f641af8c3fd6da162dc16fc01aac527a4a0255b4d231c0be50f44f0db0b713af03d968fe7f0f61ed0824c55c4b5265548febd6aad5c5eedf63efe793489c39b8fd29d104ce",
+                output_str: "901c6d85509f01a47ea2e2792a5db728ea39e5703eedeae41365edf10a866b922b1093e52e687e312db129da1f053ef6848cb0b314c9a3a999eb3e75e14c9cc2"
+            },
+            Test {
+                input: "bebd4f1a84fc8b15e4452a54bd02d69e304b7f32616aadd90537937106ae4e28de9d8aab02d19bc3e2fde1d651559e296453e4dba94370a14dbbb2d1d4e2022302ee90e208321efcd8528ad89e46dc839ea9df618ea8394a6bff308e7726bae0c19bcd4be52da6258e2ef4e96aa21244429f49ef5cb486d7ff35cac1bacb7e95711944bccb2ab34700d42d1eb38b5d536b947348a458ede3dc6bd6ec547b1b0cae5b257be36a7124e1060c170ffa",
+                output_str: "4cc9a61ffe08984417712b80f962365af36ed66a8aab2a788d22a5c6b23962d23584638e712e9183c0a271383db0877f722d399116f9bef79a56ab096ef21749"
+            },
+            Test {
+                input: "5aca56a03a13784bdc3289d9364f79e2a85c12276b49b92db0adaa4f206d5028f213f678c3510e111f9dc4c1c1f8b6acb17a6413aa227607c515c62a733817ba5e762cc6748e7e0d6872c984d723c9bb3b117eb8963185300a80bfa65cde495d70a46c44858605fccbed086c2b45cef963d33294dbe9706b13af22f1b7c4cd5a001cfec251fba18e722c6e1c4b1166918b4f6f48a98b64b3c07fc86a6b17a6d0480ab79d4e6415b520f1c484d675b1",
+                output_str: "b36ea56bb6bf80d91d5a605f8409ae6b7d879ec40815b35c664cc6b01bf6c718ad464f15c34dd1315a79a5456b6c3f8ed89e60390bc71ef747e12cdc77706245"
+            },
+            Test {
+                input: "a5aad0e4646a32c85cfcac73f02fc5300f1982fabb2f2179e28303e447854094cdfc854310e5c0f60993ceff54d84d6b46323d930adb07c17599b35b505f09e784bca5985e0172257797fb53649e2e9723efd16865c31b5c3d5113b58bb0bfc8920fabdda086d7537e66d709d050bd14d0c960873f156fad5b3d3840cdfcdc9be6af519db262a27f40896ab25cc39f96984d650611c0d5a3080d5b3a1bf186abd42956588b3b58cd948970d298776060",
+                output_str: "8ecb8f622dab7087e9a95cd0341192fea6b1c956df9ad3ded823948b7849c4f3150c9559520953ebde98ed76f6e43bfe4fb25fda712525c6d3daa80323be8e4a"
+            },
+            Test {
+                input: "06cbbe67e94a978203ead6c057a1a5b098478b4b4cbef5a97e93c8e42f5572713575fc2a884531d7622f8f879387a859a80f10ef02708cd8f7413ab385afc357678b9578c0ebf641ef076a1a30f1f75379e9dcb2a885bdd295905ee80c0168a62a9597d10cf12dd2d8cee46645c7e5a141f6e0e23aa482abe5661c16e69ef1e28371e2e236c359ba4e92c25626a7b7ff13f6ea4ae906e1cfe163e91719b1f750a96cbde5fbc953d9e576cd216afc90323a",
+                output_str: "519215da34acfcd62dd617ecd5978365417d57c2671a7b48655b89f448b23b128d3ad04910a1bbbdc00e954a1e49765176a8aca4c37d56abf0e0b72e331a8d7c"
+            },
+            Test {
+                input: "f1c528cf7739874707d4d8ad5b98f7c77169de0b57188df233b2dc8a5b31eda5db4291dd9f68e6bad37b8d7f6c9c0044b3bf74bbc3d7d1798e138709b0d75e7c593d3cccdc1b20c7174b4e692add820ace262d45ccfae2077e878796347168060a162ecca8c38c1a88350bd63bb539134f700fd4addd5959e255337daa06bc86358fabcbefdfb5bc889783d843c08aadc6c4f6c36f65f156e851c9a0f917e4a367b5ad93d874812a1de6a7b93cd53ad97232",
+                output_str: "0d1c1ad4e1cfefee854c4a739a0342e39d700dbaf4891978d7c839e87c680717d63ab4aa1ed7eb657ced9f8d2cf47204262e609610842fc5b219acff7eb188c4"
+            },
+            Test {
+                input: "9d9f3a7ecd51b41f6572fd0d0881e30390dfb780991dae7db3b47619134718e6f987810e542619dfaa7b505c76b7350c6432d8bf1cfebdf1069b90a35f0d04cbdf130b0dfc7875f4a4e62cdb8e525aadd7ce842520a482ac18f09442d78305fe85a74e39e760a4837482ed2f437dd13b2ec1042afcf9decdc3e877e50ff4106ad10a525230d11920324a81094da31deab6476aa42f20c84843cfc1c58545ee80352bdd3740dd6a16792ae2d86f11641bb717c2",
+                output_str: "0a5d9ef40ba2b98edbd7918cc6779483a1a00bd94cc1e1495495caf6cd47c6239571c3828f4565a0d53786781d712c10ef7333227f651974628887d442a5ef9d"
+            },
+            Test {
+                input: "5179888724819fbad3afa927d3577796660e6a81c52d98e9303261d5a4a83232f6f758934d50aa83ff9e20a5926dfebaac49529d006eb923c5ae5048ed544ec471ed7191edf46363383824f915769b3e688094c682b02151e5ee01e510b431c8865aff8b6b6f2f59cb6d129da79e97c6d2b8fa6c6da3f603199d2d1bcab547682a81cd6cf65f6551121391d78bcc23b5bd0e922ec6d8bf97c952e84dd28aef909aba31edb903b28fbfc33b7703cd996215a11238",
+                output_str: "ea83de9ae057701f6ec68ff67e92e0334c18ebb79af1953c2514408d58e69f105441642a1d5b7d6010f7cb15d131dd531855ca337a7b0b794fa6d6923f017afa"
+            },
+            Test {
+                input: "576ef3520d30b7a4899b8c0d5e359e45c5189add100e43be429a02fb3de5ff4f8fd0e79d9663acca72cd29c94582b19292a557c5b1315297d168fbb54e9e2ecd13809c2b5fce998edc6570545e1499dbe7fb74d47cd7f35823b212b05bf3f5a79caa34224fdd670d335fcb106f5d92c3946f44d3afcbae2e41ac554d8e6759f332b76be89a0324aa12c5482d1ea3ee89ded4936f3e3c080436f539fa137e74c6d3389bdf5a45074c47bc7b20b0948407a66d855e2f",
+                output_str: "6651c25d33d10b72535f1db26a1dfe2eb99cdd505448018589b5b88b7cab63eb439c31a474c6f1191df14efc7d0665cc7b82a7dc54a7c6b0c2fd1f75c30d6872"
+            },
+            Test {
+                input: "0df2152fa4f4357c8741529dd77e783925d3d76e95bafa2b542a2c33f3d1d117d159cf473f82310356fee4c90a9e505e70f8f24859656368ba09381fa245eb6c3d763f3093f0c89b972e66b53d59406d9f01aea07f8b3b615cac4ee4d05f542e7d0dab45d67ccccd3a606ccbeb31ea1fa7005ba07176e60dab7d78f6810ef086f42f08e595f0ec217372b98970cc6321576d92ce38f7c397a403bada1548d205c343ac09deca86325373c3b76d9f32028fea8eb32515",
+                output_str: "a754652247f7285ce2dd8a10035c69961e4f9c025e1fd087cbd3126e049a9e832c3f3a491fcde338b8c01946cdd7dec32a8fd7ed1cb3045bcaf3398905b1bb42"
+            },
+            Test {
+                input: "3e15350d87d6ebb5c8ad99d42515cfe17980933c7a8f6b8bbbf0a63728cefaad2052623c0bd5931839112a48633fb3c2004e0749c87a41b26a8b48945539d1ff41a4b269462fd199bfecd45374756f55a9116e92093ac99451aefb2af9fd32d6d7f5fbc7f7a540d5097c096ebc3b3a721541de073a1cc02f7fb0fb1b9327fb0b1218ca49c9487ab5396622a13ae546c97abdef6b56380dda7012a8384091b6656d0ab272d363cea78163ff765cdd13ab1738b940d16cae",
+                output_str: "fc1127f6650f32638453ab773f5ce60f9f6165bc9928eff18c7a3281540c7a615d2d62a92e557d4a1ec1229e84819d2dbf06ced4de0ff90040ecb961d678e181"
+            },
+            Test {
+                input: "c38d6b0b757cb552be40940ece0009ef3b0b59307c1451686f1a22702922800d58bce7a636c1727ee547c01b214779e898fc0e560f8ae7f61bef4d75eaa696b921fd6b735d171535e9edd267c192b99880c87997711002009095d8a7a437e258104a41a505e5ef71e5613ddd2008195f0c574e6ba3fe40099cfa116e5f1a2fa8a6da04badcb4e2d5d0de31fdc4800891c45781a0aac7c907b56d631fca5ce8b2cde620d11d1777ed9fa603541de794ddc5758fcd5fad78c0",
+                output_str: "43c21bccac7acee8ed437b874ed7cdf20ea2e9dc98ab82124610dc4f8416248b51309045cdfbce92efa9e56c5b36d6e5d27580319ce69c22e5d6c87e551eed4a"
+            },
+            Test {
+                input: "8d2de3f0b37a6385c90739805b170057f091cd0c7a0bc951540f26a5a75b3e694631bb64c7635eed316f51318e9d8de13c70a2aba04a14836855f35e480528b776d0a1e8a23b547c8b8d6a0d09b241d3be9377160cca4e6793d00a515dc2992cb7fc741daca171431da99cce6f7789f129e2ac5cf65b40d703035cd2185bb936c82002daf8cbc27a7a9e554b06196630446a6f0a14ba155ed26d95bd627b7205c072d02b60db0fd7e49ea058c2e0ba202daff0de91e845cf79",
+                output_str: "893934b8c630a9bf713c64ffd1128eac75d1cefdef6642fb27f20cb56694c2fa8ba6efcf3e0e56c7789cfaac6b2f7b247dea8367ffd269e74b9cdfb0537031ea"
+            },
+            Test {
+                input: "c464bbdad275c50dcd983b65ad1019b9ff85a1e71c807f3204bb2c921dc31fbcd8c5fc45868ae9ef85b6c9b83bba2a5a822201ed68586ec5ec27fb2857a5d1a2d09d09115f22dcc39fe61f5e1ba0ff6e8b4acb4c6da748be7f3f0839739394ff7fa8e39f7f7e84a33c3866875c01bcb1263c9405d91908e9e0b50e7459fabb63d8c6bbb73d8e3483c099b55bc30ff092ff68b6adedfd477d63570c9f5515847f36e24ba0b705557130cec57ebad1d0b31a378e91894ee26e3a04",
+                output_str: "b4cb58d8497978916dc362d37ade12c7a0d8fe3b08b370659b27218291e04ef343095a91887b040984cb80b0c8611fd12c18ead37b95320d59eddb32113e42a4"
+            },
+            Test {
+                input: "8b8d68bb8a75732fe272815a68a1c9c5aa31b41dedc8493e76525d1d013d33cebd9e21a5bb95db2616976a8c07fcf411f5f6bc6f7e0b57aca78cc2790a6f9b898858ac9c79b165ff24e66677531e39f572be5d81eb3264524181115f32780257bfb9aeec6af12af28e587cac068a1a2953b59ad680f4c245b2e3ec36f59940d37e1d3db38e13edb29b5c0f404f6ff87f80fc8be7a225ff22fbb9c8b6b1d7330c57840d24bc75b06b80d30dad6806544d510af6c4785e823ac3e0b8",
+                output_str: "35c3f8f0dc28608ec942cb6287482219b42b2ebcbad92b4c34e77e21b7d93b0e85ebf483db2d4a979c48e58f746ac3dcf563ca7e1b2940371d8d83bf0795ec45"
+            },
+            Test {
+                input: "6b018710446f368e7421f1bc0ccf562d9c1843846bc8d98d1c9bf7d9d6fcb48bfc3bf83b36d44c4fa93430af75cd190bde36a7f92f867f58a803900df8018150384d85d82132f123006ac2aeba58e02a037fe6afbd65eca7c44977dd3dc74f48b6e7a1bfd5cc4dcf24e4d52e92bd4455848e4928b0eac8b7476fe3cc03e862aa4dff4470dbfed6de48e410f25096487ecfc32a27277f3f5023b2725ade461b1355889554a8836c9cf53bd767f5737d55184eea1ab3f53edd0976c485",
+                output_str: "b90e0cc6bc53182c4f2d17aa51391c8250c3032a12daf2fcc641b49aa81ed9449403567b75d4121376dd8cc2d2bdbafa456308ad7c0c13ba85619d75350727e3"
+            },
+            Test {
+                input: "c9534a24714bd4be37c88a3da1082eda7cabd154c309d7bd670dccd95aa535594463058a29f79031d6ecaa9f675d1211e9359be82669a79c855ea8d89dd38c2c761ddd0ec0ce9e97597432e9a1beae062cdd71edfdfd464119be9e69d18a7a7fd7ce0e2106f0c8b0abf4715e2ca48ef9f454dc203c96656653b727083513f8efb86e49c513bb758b3b052fe21f1c05bb33c37129d6cc81f1aef6adc45b0e8827a830fe545cf57d0955802c117d23ccb55ea28f95c0d8c2f9c5a242b33f",
+                output_str: "99497355ae1791799d11536c73605cdd1496c74e3e930b6272a103c3aa8c984d2d74b01ae72c94f2a4d3a069eac6e00984d21eae3dd7b32ad082b396601093ba"
+            },
+            Test {
+                input: "07906c87297b867abf4576e9f3cc7f82f22b154afcbf293b9319f1b0584da6a40c27b32e0b1b7f412c4f1b82480e70a9235b12ec27090a5a33175a2bb28d8adc475cefe33f7803f8ce27967217381f02e67a3b4f84a71f1c5228e0c2ad971373f6f672624fcea8d1a9f85170fad30fa0bbd25035c3b41a6175d467998bd1215f6f3866f53847f9cf68ef3e2fbb54bc994de2302b829c5eea68ec441fcbafd7d16ae4fe9fff98bf00e5bc2ad54dd91ff9fda4dd77b6c754a91955d1fbaad0",
+                output_str: "c98265396f3278fc532125ded097a6851fc5bf37ca32ec26f43e64874241309f568a217119ba984c54099f8899ac94b7900a4dd9d3877e18371f5dafd1921f08"
+            },
+            Test {
+                input: "588e94b9054abc2189df69b8ba34341b77cdd528e7860e5defcaa79b0c9a452ad4b82aa306be84536eb7cedcbe058d7b84a6aef826b028b8a0271b69ac3605a9635ea9f5ea0aa700f3eb7835bc54611b922964300c953efe7491e3677c2cebe0822e956cd16433b02c68c4a23252c3f9e151a416b4963257b783e038f6b4d5c9f110f871652c7a649a7bcedcbccc6f2d0725bb903cc196ba76c76aa9f10a190b1d1168993baa9ffc96a1655216773458bec72b0e39c9f2c121378feab4e76a",
+                output_str: "fc03be193a5ed0e6b3502661c2d9e4e2a503cf3fdb231526a90c3c4c26089c787ee6cbf50d90af61c17c5df0b29c373b426740cd0d6fc370de64eb2164bbaeb2"
+            },
+            Test {
+                input: "08959a7e4baae874928813364071194e2939772f20db7c3157078987c557c2a6d5abe68d520eef3dc491692e1e21bcd880adebf63bb4213b50897fa005256ed41b5690f78f52855c8d9168a4b666fce2da2b456d7a7e7c17ab5f2fb1ee90b79e698712e963715983fd07641ae4b4e9dc73203fac1ae11fa1f8c7941fcc82eab247addb56e2638447e9d609e610b60ce086656aaebf1da3c8a231d7d94e2fd0afe46b391ff14a72eaeb3f44ad4df85866def43d4781a0b3578bc996c87970b132",
+                output_str: "fb9c3a9183b6d251bf61faf1843455cb9c1be35eabdc131d5bf38e98337934968291e9d6dc104374bc234ff22cc23cd6f338e7a3b019cdc9df6e3750b6b01fde"
+            },
+            Test {
+                input: "cb2a234f45e2ecd5863895a451d389a369aab99cfef0d5c9ffca1e6e63f763b5c14fb9b478313c8e8c0efeb3ac9500cf5fd93791b789e67eac12fd038e2547cc8e0fc9db591f33a1e4907c64a922dda23ec9827310b306098554a4a78f050262db5b545b159e1ff1dca6eb734b872343b842c57eafcfda8405eedbb48ef32e99696d135979235c3a05364e371c2d76f1902f1d83146df9495c0a6c57d7bf9ee77e80f9787aee27be1fe126cdc9ef893a4a7dcbbc367e40fe4e1ee90b42ea25af01",
+                output_str: "f7965b71198636f162d5a4e08d73e8c8a9ac1addbdfd7c180c489cca7360b3fee3a4286154460bf867923b348bfe32e79d9139a0cb52c46fa20785faeae0a8bc"
+            },
+            Test {
+                input: "d16beadf02ab1d4dc6f88b8c4554c51e866df830b89c06e786a5f8757e8909310af51c840efe8d20b35331f4355d80f73295974653ddd620cdde4730fb6c8d0d2dcb2b45d92d4fbdb567c0a3e86bd1a8a795af26fbf29fc6c65941cddb090ff7cd230ac5268ab4606fccba9eded0a2b5d014ee0c34f0b2881ac036e24e151be89eeb6cd9a7a790afccff234d7cb11b99ebf58cd0c589f20bdac4f9f0e28f75e3e04e5b3debce607a496d848d67fa7b49132c71b878fd5557e082a18eca1fbda94d4b",
+                output_str: "5337477487a0af43eb7b995293ca2bef6eab2432b1333dcaead7064406e22861fcea623fd8b85b30465787352a36c943610f1458fd22e3f55ddd195a6acaa374"
+            },
+            Test {
+                input: "8f65f6bc59a85705016e2bae7fe57980de3127e5ab275f573d334f73f8603106ec3553016608ef2dd6e69b24be0b7113bf6a760ba6e9ce1c48f9e186012cf96a1d4849d75df5bb8315387fd78e9e153e76f8ba7ec6c8849810f59fb4bb9b004318210b37f1299526866f44059e017e22e96cbe418699d014c6ea01c9f0038b10299884dbec3199bb05adc94e955a1533219c1115fed0e5f21228b071f40dd57c4240d98d37b73e412fe0fa4703120d7c0c67972ed233e5deb300a22605472fa3a3ba86",
+                output_str: "28ab5c6298a602ae51eeec4080245f7ca10f9a8c304f22b5aa88d0e49226c01c2fd3cc5d8e99309767816e4f6d52719876065495ddb61dd113cfff06b11d8604"
+            },
+            Test {
+                input: "84891e52e0d451813210c3fd635b39a03a6b7a7317b221a7abc270dfa946c42669aacbbbdf801e1584f330e28c729847ea14152bd637b3d0f2b38b4bd5bf9c791c58806281103a3eabbaede5e711e539e6a8b2cf297cf351c078b4fa8f7f35cf61bebf8814bf248a01d41e86c5715ea40c63f7375379a7eb1d78f27622fb468ab784aaaba4e534a6dfd1df6fa15511341e725ed2e87f98737ccb7b6a6dfae416477472b046bf1811187d151bfa9f7b2bf9acdb23a3be507cdf14cfdf517d2cb5fb9e4ab6",
+                output_str: "2aeeac015d93245f6bf727cd182894097b902cd407d7e0dd06da1a63f4451c657ff39f925e7c8a894ae593d11ebc2d5d1de3d9a18018806719277d993f7fabed"
+            },
+            Test {
+                input: "fdd7a9433a3b4afabd7a3a5e3457e56debf78e84b7a0b0ca0e8c6d53bd0c2dae31b2700c6128334f43981be3b213b1d7a118d59c7e6b6493a86f866a1635c12859cfb9ad17460a77b4522a5c1883c3d6acc86e6162667ec414e9a104aa892053a2b1d72165a855bacd8faf8034a5dd9b716f47a0818c09bb6baf22aa503c06b4ca261f557761989d2afbd88b6a678ad128af68672107d0f1fc73c5ca740459297b3292b281e93bceb761bde7221c3a55708e5ec84472cddcaa84ecf23723cc0991355c6280",
+                output_str: "d0a119617b7e30c2a85ecbb3bbf325ddd589431c8c2e2f9fc6e324a6ed8baf11870a80556cc0688fee4db70f22b9424b4f37a0f1e7ea314684da31bf473b3f34"
+            },
+            Test {
+                input: "70a40bfbef92277a1aad72f6b79d0177197c4ebd432668cfec05d099accb651062b5dff156c0b27336687a94b26679cfdd9daf7ad204338dd9c4d14114033a5c225bd11f217b5f4732da167ee3f939262d4043fc9cba92303b7b5e96aea12adda64859df4b86e9ee0b58e39091e6b188b408ac94e1294a8911245ee361e60e601eff58d1d37639f3753bec80ebb4efde25817436076623fc65415fe51d1b0280366d12c554d86743f3c3b6572e400361a60726131441ba493a83fbe9afda90f7af1ae717238d",
+                output_str: "1c88789885dccc9ae81029acf0b6c9d083cdb9774c345f1c755e54c45e9af63a70dc2abaefeb1ad416f1bd3d9b69d4c4404d22c85e636a4703769c0112b550b8"
+            },
+            Test {
+                input: "74356e449f4bf8644f77b14f4d67cb6bd9c1f5ae357621d5b8147e562b65c66585caf2e491b48529a01a34d226d436959153815380d5689e30b35357cdac6e08d3f2b0e88e200600d62bd9f5eaf488df86a4470ea227006182e44809009868c4c280c43d7d64a5268fa719074960087b3a6abc837882f882c837834535929389a12b2c78187e2ea07ef8b8eef27dc85002c3ae35f1a50bee6a1c48ba7e175f3316670b27983472aa6a61eed0a683a39ee323080620ea44a9f74411ae5ce99030528f9ab49c79f2",
+                output_str: "f52d7dd7ff248a1bca7b714f14a79df5766fd67c0031a471cc509f3516d7c348c33f7d4b1ca331b9323896b7074e10a891cea851f9ac20245812b8cfaa556352"
+            },
+            Test {
+                input: "8c3798e51bc68482d7337d3abb75dc9ffe860714a9ad73551e120059860dde24ab87327222b64cf774415a70f724cdf270de3fe47dda07b61c9ef2a3551f45a5584860248fabde676e1cd75f6355aa3eaeabe3b51dc813d9fb2eaa4f0f1d9f834d7cad9c7c695ae84b329385bc0bef895b9f1edf44a03d4b410cc23a79a6b62e4f346a5e8dd851c2857995ddbf5b2d717aeb847310e1f6a46ac3d26a7f9b44985af656d2b7c9406e8a9e8f47dcb4ef6b83caacf9aefb6118bfcff7e44bef6937ebddc89186839b77",
+                output_str: "a8aee42a77c9b6387dc97319581959d9bd878d061487fd069aca04d6f84d347e23587a6c7c56329b2df88c56c7100ed51ace5b5f778d65478f059cafd6c098fd"
+            },
+            Test {
+                input: "fa56bf730c4f8395875189c10c4fb251605757a8fecc31f9737e3c2503b02608e6731e85d7a38393c67de516b85304824bfb135e33bf22b3a23b913bf6acd2b7ab85198b8187b2bcd454d5e3318cacb32fd6261c31ae7f6c54ef6a7a2a4c9f3ecb81ce3555d4f0ad466dd4c108a90399d70041997c3b25345a9653f3c9a6711ab1b91d6a9d2216442da2c973cbd685ee7643bfd77327a2f7ae9cb283620a08716dfb462e5c1d65432ca9d56a90e811443cd1ecb8f0de179c9cb48ba4f6fec360c66f252f6e64edc96b",
+                output_str: "4b961c4bb6035e7bdda2e1a3b6f9cd52d1789866044c4a925693bea88f65d046238bbeb4e7d3b060e47288041407392b291ae610ba70d6b4d64e74e7a7d0256f"
+            },
+            Test {
+                input: "b6134f9c3e91dd8000740d009dd806240811d51ab1546a974bcb18d344642baa5cd5903af84d58ec5ba17301d5ec0f10ccd0509cbb3fd3fff9172d193af0f782252fd1338c7244d40e0e42362275b22d01c4c3389f19dd69bdf958ebe28e31a4ffe2b5f18a87831cfb7095f58a87c9fa21db72ba269379b2dc2384b3da953c7925761fed324620acea435e52b424a7723f6a2357374157a34cd8252351c25a1b232826cefe1bd3e70ffc15a31e7c0598219d7f00436294d11891b82497bc78aa5363892a2495df8c1eef",
+                output_str: "c0515b65b640b3ffd0a1582a54f4c8fb35c109b7fb472666e043d3c00ae3e0e0fa156c4cefb46b5b7b4c0e480623e1a26018bdaedc3e27d9c0d44c3e1d862015"
+            },
+            Test {
+                input: "c941cdb9c28ab0a791f2e5c8e8bb52850626aa89205bec3a7e22682313d198b1fa33fc7295381354858758ae6c8ec6fac3245c6e454d16fa2f51c4166fab51df272858f2d603770c40987f64442d487af49cd5c3991ce858ea2a60dab6a65a34414965933973ac2457089e359160b7cdedc42f29e10a91921785f6b7224ee0b349393cdcff6151b50b377d609559923d0984cda6000829b916ab6896693ef6a2199b3c22f7dc5500a15b8258420e314c222bc000bc4e5413e6dd82c993f8330f5c6d1be4bc79f08a1a0a46",
+                output_str: "45c584564d9e0b8239cc1284939ba407a8e5e981691eab6a04d9354c9c855e400b3037151122ced237636e61a7ff2905e0213a6d07306c459e2189e3e6a9e0b8"
+            },
+            Test {
+                input: "4499efffac4bcea52747efd1e4f20b73e48758be915c88a1ffe5299b0b005837a46b2f20a9cb3c6e64a9e3c564a27c0f1c6ad1960373036ec5bfe1a8fc6a435c2185ed0f114c50e8b3e4c7ed96b06a036819c9463e864a58d6286f785e32a804443a56af0b4df6abc57ed5c2b185ddee8489ea080deeee66aa33c2e6dab36251c402682b6824821f998c32163164298e1fafd31babbcffb594c91888c6219079d907fdb438ed89529d6d96212fd55abe20399dbefd342248507436931cdead496eb6e4a80358acc78647d043",
+                output_str: "136723350857e03756f02e60451a28e711611927b8136dcff3e567dc618ff36b3100737c9781b9c84a576745c1e6be030dac8803a71464af39db94d00253af3e"
+            },
+            Test {
+                input: "eecbb8fdfa4da62170fd06727f697d81f83f601ff61e478105d3cb7502f2c89bf3e8f56edd469d049807a38882a7eefbc85fc9a950952e9fa84b8afebd3ce782d4da598002827b1eb98882ea1f0a8f7aa9ce013a6e9bc462fb66c8d4a18da21401e1b93356eb12f3725b6db1684f2300a98b9a119e5d27ff704affb618e12708e77e6e5f34139a5a41131fd1d6336c272a8fc37080f041c71341bee6ab550cb4a20a6ddb6a8e0299f2b14bc730c54b8b1c1c487b494bdccfd3a53535ab2f231590bf2c4062fd2ad58f906a2d0d",
+                output_str: "c0f7713aa021a04525f751722a9ae5c4c7934d0a286f1fb05823d86a96251c04decd960d8d4d66e2c565e6207a49612e1efde386536854b6ab9a4807b0a145be"
+            },
+            Test {
+                input: "e64f3e4ace5c8418d65fec2bc5d2a303dd458034736e3b0df719098be7a206deaf52d6ba82316caf330ef852375188cde2b39cc94aa449578a7e2a8e3f5a9d68e816b8d16889fbc0ebf0939d04f63033ae9ae2bdab73b88c26d6bd25ee460ee1ef58fb0afa92cc539f8c76d3d097e7a6a63ebb9b5887edf3cf076028c5bbd5b9db3211371ad3fe121d4e9bf44229f4e1ecf5a0f9f0eba4d5ceb72878ab22c3f0eb5a625323ac66f7061f4a81fac834471e0c59553f108475fe290d43e6a055ae3ee46fb67422f814a68c4be3e8c9",
+                output_str: "fe1cb67d77fb463f77747fed292a989a341044a8b65fa1df1441aa41a5c795916626e0e479fd0ba7f9b1dc15fed245b99598d35359834e8fd25cf19685219be2"
+            },
+            Test {
+                input: "d2cb2d733033f9e91395312808383cc4f0ca974e87ec68400d52e96b3fa6984ac58d9ad0938dde5a973008d818c49607d9de2284e7618f1b8aed8372fbd52ed54557af4220fac09dfa8443011699b97d743f8f2b1aef3537ebb45dcc9e13dfb438428ee190a4efdb3caeb7f3933117bf63abdc7e57beb4171c7e1ad260ab0587806c4d137b6316b50abc9cce0dff3acada47bbb86be777e617bbe578ff4519844db360e0a96c6701290e76bb95d26f0f804c8a4f2717eac4e7de9f2cff3bbc55a17e776c0d02856032a6cd10ad2838",
+                output_str: "4043cdd3f0ea793e49a8ec382f8071f6020b529cf8c82e969429117b362129b7689d3f1ea7ff77ee50263cecdac5a43aa2aee97cf3e665ccf535f6de65ad0100"
+            },
+            Test {
+                input: "f2998955613dd414cc111df5ce30a995bb792e260b0e37a5b1d942fe90171a4ac2f66d4928d7ad377f4d0554cbf4c523d21f6e5f379d6f4b028cdcb9b1758d3b39663242ff3cb6ede6a36a6f05db3bc41e0d861b384b6dec58bb096d0a422fd542df175e1be1571fb52ae66f2d86a2f6824a8cfaacbac4a7492ad0433eeb15454af8f312b3b2a577750e3efbd370e8a8cac1582581971fba3ba4bd0d76e718dacf8433d33a59d287f8cc92234e7a271041b526e389efb0e40b6a18b3aaf658e82ed1c78631fd23b4c3eb27c3faec8685",
+                output_str: "7392bd445f58cd5d7d3ca98579cbaa9a9437d0c95e7932b4004117f207f8aa39156bc42537b0c790150d443c2d68c2c43e362df9d019601797162e63076936c3"
+            },
+            Test {
+                input: "447797e2899b72a356ba55bf4df3acca6cdb1041eb477bd1834a9f9acbc340a294d729f2f97df3a610be0ff15edb9c6d5db41644b9874360140fc64f52aa03f0286c8a640670067a84e017926a70438db1bb361defee7317021425f8821def26d1efd77fc853b818545d055adc9284796e583c76e6fe74c9ac2587aa46aa8f8804f2feb5836cc4b3ababab8429a5783e17d5999f32242eb59ef30cd7adabc16d72dbdb097623047c98989f88d14eaf02a7212be16ec2d07981aaa99949ddf89ecd90333a77bc4e1988a82abf7c7caf3291",
+                output_str: "9ff0f0d70ca076ca44c353a3c678c2095c89f619bb53ec9cb4888e2f14e50fbc146a7b521356369f1b9d5665836e45d5400f9856cc6da3b3afe6f3b0471fc9c6"
+            },
+            Test {
+                input: "9f2c18ade9b380c784e170fb763e9aa205f64303067eb1bcea93df5dac4bf5a2e00b78195f808df24fc76e26cb7be31dc35f0844cded1567bba29858cffc97fb29010331b01d6a3fb3159cc1b973d255da9843e34a0a4061cabdb9ed37f241bfabb3c20d32743f4026b59a4ccc385a2301f83c0b0a190b0f2d01acb8f0d41111e10f2f4e149379275599a52dc089b35fdd5234b0cfb7b6d8aebd563ca1fa653c5c021dfd6f5920e6f18bfafdbecbf0ab00281333ed50b9a999549c1c8f8c63d7626c48322e9791d5ff72294049bde91e73f8",
+                output_str: "a981faa9d3cac492b2fa078d1158f81248df8db36acbd5bad3a6c633bbe500eb481d2937beee9a76c84edcdfa0f997edce708f07851422a7597e2463fc1912cd"
+            },
+            Test {
+                input: "ae159f3fa33619002ae6bcce8cbbdd7d28e5ed9d61534595c4c9f43c402a9bb31f3b301cbfd4a43ce4c24cd5c9849cc6259eca90e2a79e01ffbac07ba0e147fa42676a1d668570e0396387b5bcd599e8e66aaed1b8a191c5a47547f61373021fa6deadcb55363d233c24440f2c73dbb519f7c9fa5a8962efd5f6252c0407f190dfefad707f3c7007d69ff36b8489a5b6b7c557e79dd4f50c06511f599f56c896b35c917b63ba35c6ff8092baf7d1658e77fc95d8a6a43eeb4c01f33f03877f92774be89c1114dd531c011e53a34dc248a2f0e6",
+                output_str: "89025c13bc6b61a1bfadb1d37d676e49e6754e9dfc00d52c5ef13ba57c845d14ac75d5ae6f06714028103c3424717f4c2fbf6d88d055690987620ac5b440576a"
+            },
+            Test {
+                input: "3b8e97c5ffc2d6a40fa7de7fcefc90f3b12c940e7ab415321e29ee692dfac799b009c99dcddb708fce5a178c5c35ee2b8617143edc4c40b4d313661f49abdd93cea79d117518805496fe6acf292c4c2a1f76b403a97d7c399daf85b46ad84e16246c67d6836757bde336c290d5d401e6c1386ab32797af6bb251e9b2d8fe754c47482b72e0b394eab76916126fd68ea7d65eb93d59f5b4c5ac40f7c3b37e7f3694f29424c24af8c8f0ef59cd9dbf1d28e0e10f799a6f78cad1d45b9db3d7dee4a7059abe99182714983b9c9d44d7f5643596d4f3",
+                output_str: "1545d8334836f7436f77f21532f5d3058e351db8357efc1e089583a0c40ad3a6af5f2fee793d3fe1b4721f6817a373499b20912a35c4609fa9d84bd274e978fc"
+            },
+            Test {
+                input: "3434ec31b10fafdbfeec0dd6bd94e80f7ba9dca19ef075f7eb017512af66d6a4bcf7d16ba0819a1892a6372f9b35bcc7ca8155ee19e8428bc22d214856ed5fa9374c3c09bde169602cc219679f65a1566fc7316f4cc3b631a18fb4449fa6afa16a3db2bc4212eff539c67cf184680826535589c7111d73bffce431b4c40492e763d9279560aaa38eb2dc14a212d723f994a1fe656ff4dd14551ce4e7c621b2aa5604a10001b2878a897a28a08095c325e10a26d2fb1a75bfd64c250309bb55a44f23bbac0d5516a1c687d3b41ef2fbbf9cc56d4739",
+                output_str: "afaf201ba353316c1a7b810f120cff941bb658b0763eef59433403d8313b8f00bf18177898ae71907d3b524e68bb028ea1442866856111b12089bcbed177fd46"
+            },
+            Test {
+                input: "7c7953d81c8d208fd1c97681d48f49dd003456de60475b84070ef4847c333b74575b1fc8d2a186964485a3b8634feaa3595aaa1a2f4595a7d6b6153563dee31bbac443c8a33eed6d5d956a980a68366c2527b550ee950250dfb691eacbd5d56ae14b970668be174c89df2fea43ae52f13142639c884fd62a3683c0c3792f0f24ab1318bcb27e21f4737fab62c77ea38bc8fd1cf41f7dab64c13febe7152bf5bb7ab5a78f5346d43cc741cb6f72b7b8980f268b68bf62abdfb1577a52438fe14b591498cc95f071228460c7c5d5ceb4a7bde588e7f21c",
+                output_str: "3fb4f21a231973d2247f206d47b19ee1551647fd4d4f21fbcd6f653577c1ac69eae4db432c0234acbe17b2ced0238a56acc34d7bb82fbc190903035b7c538857"
+            },
+            Test {
+                input: "7a6a4f4fdc59a1d223381ae5af498d74b7252ecf59e389e49130c7eaee626e7bd9897effd92017f4ccde66b0440462cdedfd352d8153e6a4c8d7a0812f701cc737b5178c2556f07111200eb627dbc299caa792dfa58f35935299fa3a3519e9b03166dffa159103ffa35e8577f7c0a86c6b46fe13db8e2cdd9dcfba85bdddcce0a7a8e155f81f712d8e9fe646153d3d22c811bd39f830433b2213dd46301941b59293fd0a33e2b63adbd95239bc01315c46fdb678875b3c81e053a40f581cfbec24a1404b1671a1b88a6d06120229518fb13a74ca0ac5ae",
+                output_str: "0b1c53e68667314b5f3f0f30e25c622b1a86d10701d4a0473fd40f22c50acb47d63eafa582a2fbe5453a3f73bfbca923680f4c2c7f99c98388c07ddd7aff2c6e"
+            },
+            Test {
+                input: "d9faa14cebe9b7de551b6c0765409a33938562013b5e8e0e1e0a6418df7399d0a6a771fb81c3ca9bd3bb8e2951b0bc792525a294ebd1083688806fe5e7f1e17fd4e3a41d00c89e8fcf4a363caedb1acb558e3d562f1302b3d83bb886ed27b76033798131dab05b4217381eaaa7ba15ec820bb5c13b516dd640eaec5a27d05fdfca0f35b3a5312146806b4c0275bcd0aaa3b2017f346975db566f9b4d137f4ee10644c2a2da66deeca5342e236495c3c6280528bfd32e90af4cd9bb908f34012b52b4bc56d48cc8a6b59bab014988eabd12e1a0a1c2e170e7",
+                output_str: "d836d0ce3a28ad71c3a876796bf65aab838d84e4802ed49ac04484ae06aa08ed31deb5c38c1022f0aceed49cb58e38d3aab09efeced9349fdc33379251259826"
+            },
+            Test {
+                input: "2d8427433d0c61f2d96cfe80cf1e932265a191365c3b61aaa3d6dcc039f6ba2ad52a6a8cc30fc10f705e6b7705105977fa496c1c708a277a124304f1fc40911e7441d1b5e77b951aad7b01fd5db1b377d165b05bbf898042e39660caf8b279fe5229d1a8db86c0999ed65e53d01ccbc4b43173ccf992b3a14586f6ba42f5fe30afa8ae40c5df29966f9346da5f8b35f16a1de3ab6de0f477d8d8660918060e88b9b9e9ca6a4207033b87a812dbf5544d39e4882010f82b6ce005f8e8ff6fe3c3806bc2b73c2b83afb704345629304f9f86358712e9fae3ca3e",
+                output_str: "61b8a7520dab4d395044b1a9ccc4f5263edae0325767e3d2a0ef225933a81f7e3796280870dbdab8457d585c4106315b537653dc3d77e915100f421db39f43b3"
+            },
+            Test {
+                input: "5e19d97887fcaac0387e22c6f803c34a3dacd2604172433f7a8a7a526ca4a2a1271ecfc5d5d7be5ac0d85d921095350dfc65997d443c21c8094e0a3fefd2961bcb94aed03291ae310ccda75d8ace4bc7d89e7d3e5d1650bda5d668b8b50bfc8e608e184f4d3a9a2badc4ff5f07e0c0bc8a9f2e0b2a26fd6d8c550008faaab75fd71af2a424bec9a7cd9d83fad4c8e9319115656a8717d3b523a68ff8004258b9990ed362308461804ba3e3a7e92d8f2ffae5c2fba55ba5a3c27c0a2f71bd711d2fe1799c2adb31b200035481e9ee5c4adf2ab9c0fa50b23975cf",
+                output_str: "b847b292818e800baa415c2521a8158a6ab749934db693d0d2e4613cdae60bd56075cf2c29f587dc3530164190bc2c02d97ca32347fa2aa431e511bb7d1c87e8"
+            },
+            Test {
+                input: "c8e976ab4638909387ce3b8d4e510c3230e5690e02c45093b1d297910abc481e56eea0f296f98379dfc9080af69e73b2399d1c143bee80ae1328162ce1ba7f6a8374679b20aacd380eb4e61382c99998704d62701afa914f9a2705cdb065885f50d086c3eb5753700c387118bb142f3e6da1e988dfb31ac75d7368931e45d1391a274b22f83ceb072f9bcabc0b216685bfd789f5023971024b1878a205442522f9ea7d8797a4102a3df41703768251fd5e017c85d1200a464118aa35654e7ca39f3c375b8ef8cbe7534dbc64bc20befb417cf60ec92f63d9ee7397",
+                output_str: "95ed6d8567774e66404fc32b7a01e1c625fc8322ab9be0cd7c936731638b04c09748973d95665a35b218d1531411f3aa5e5c47e65d857a43783e2bd3c9d29005"
+            },
+            Test {
+                input: "7145fa124b7429a1fc2231237a949ba7201bcc1822d3272de005b682398196c25f7e5cc2f289fbf44415f699cb7fe6757791b1443410234ae061edf623359e2b4e32c19bf88450432dd01caa5eb16a1dc378f391ca5e3c4e5f356728bddd4975db7c890da8bbc84cc73ff244394d0d48954978765e4a00b593f70f2ca082673a261ed88dbcef1127728d8cd89bc2c597e9102ced6010f65fa75a14ebe467fa57ce3bd4948b6867d74a9df5c0ec6f530cbf2ee61ce6f06bc8f2864dff5583776b31df8c7ffcb61428a56bf7bd37188b4a5123bbf338393af46eda85e6",
+                output_str: "98350793fc1540ae72757c2d1ba0fa34df1923c987f365752788e3c65931746c36d13fd293db8ea1b6374872ccf74e9b0cff67c6debb4263390cd96e2bdd864f"
+            },
+            Test {
+                input: "7fdfadcc9d29bad23ae038c6c65cda1aef757221b8872ed3d75ff8df7da0627d266e224e812c39f7983e4558bfd0a1f2bef3feb56ba09120ef762917b9c093867948547aee98600d10d87b20106878a8d22c64378bf634f7f75900c03986b077b0bf8b740a82447b61b99fee5376c5eb6680ec9e3088f0bdd0c56883413d60c1357d3c811950e5890e7600103c916341b80c743c6a852b7b4fb60c3ba21f3bc15b8382437a68454779cf3cd7f9f90ccc8ef28d0b706535b1e4108eb5627bb45d719cb046839aee311ca1abdc8319e050d67972cb35a6b1601b25dbf487",
+                output_str: "c2493d60e1efa6b472933ede64d1f49eff773635f66c6454e57e47935a0f4c5b94548da5c369bdac7146e54f017c3fd674ce32f8d95151c7cbc3e3bba3ebe0d3"
+            },
+            Test {
+                input: "988638219fd3095421f826f56e4f09e356296b628c3ce6930c9f2e758fd1a80c8273f2f61e4daae65c4f110d3e7ca0965ac7d24e34c0dc4ba2d6ff0bf5bbe93b3585f354d7543cb542a1aa54674d375077f2d360a8f4d42f3db131c3b7ab7306267ba107659864a90c8c909460a73621d1f5d9d3fd95beb19b23db1cb6c0d0fba91d36891529b8bd8263caa1bab56a4affaed44962df096d8d5b1eb845ef31188b3e10f1af811a13f156beb7a288aae593ebd1471b624aa1a7c6adf01e2200b3d72d88a3aed3100c88231e41efc376906f0b580dc895f080fda5741db1cb",
+                output_str: "70d7ba6585cd2ef91bb261025f9dcc80f8359c9dc30c7c2961f0d1f6057b9c44e3aa67a4bc00f137886e3cf1316d75f8ebf651c79df9a99cabd0383008372016"
+            },
+            Test {
+                input: "5aab62756d307a669d146aba988d9074c5a159b3de85151a819b117ca1ff6597f6156e80fdd28c9c3176835164d37da7da11d94e09add770b68a6e081cd22ca0c004bfe7cd283bf43a588da91f509b27a6584c474a4a2f3ee0f1f56447379240a5ab1fb77fdca49b305f07ba86b62756fb9efb4fc225c86845f026ea542076b91a0bc2cdd136e122c659be259d98e5841df4c2f60330d4d8cdee7bf1a0a244524eecc68ff2aef5bf0069c9e87a11c6e519de1a4062a10c83837388f7ef58598a3846f49d499682b683c4a062b421594fafbc1383c943ba83bdef515efcf10d",
+                output_str: "b50d0da9b3db1545cc1d2f35465c74d07543b3564249f12c546a08797eea73326ce624203a3d25c92ce636bcce86da9cb9f39bc755ec0f39c090a0e8a72da70b"
+            },
+            Test {
+                input: "47b8216aa0fbb5d67966f2e82c17c07aa2d6327e96fcd83e3de7333689f3ee79994a1bf45082c4d725ed8d41205cb5bcdf5c341f77facb1da46a5b9b2cbc49eadf786bcd881f371a95fa17df73f606519aea0ff79d5a11427b98ee7f13a5c00637e2854134691059839121fea9abe2cd1bcbbbf27c74caf3678e05bfb1c949897ea01f56ffa4dafbe8644611685c617a3206c7a7036e4ac816799f693dafe7f19f303ce4eba09d21e03610201bfc665b72400a547a1e00fa9b7ad8d84f84b34aef118515e74def11b9188bd1e1f97d9a12c30132ec2806339bdadacda2fd8b78",
+                output_str: "83752a88c915d4193296725decc50c9c05d25d6bbd9af2e0ef06286ecfee961de959bedbb130704d432c2bc89930208f450e0a022661724043d268cb24e7fc47"
+            },
+            Test {
+                input: "8cff1f67fe53c098896d9136389bd8881816ccab34862bb67a656e3d98896f3ce6ffd4da73975809fcdf9666760d6e561c55238b205d8049c1cedeef374d1735daa533147bfa960b2cce4a4f254176bb4d1bd1e89654432b8dbe1a135c42115b394b024856a2a83dc85d6782be4b444239567ccec4b184d4548eae3ff6a192f343292ba2e32a0f267f31cc26719eb85245d415fb897ac2da433ee91a99424c9d7f1766a44171d1651001c38fc79294accc68ceb5665d36218454d3ba169ae058a831338c17743603f81ee173bfc0927464f9bd728dee94c6aeab7aae6ee3a627e8",
+                output_str: "7288424ba855a76c7480b606f8f32e94396799bab8bb3fc8fd21d180966c64971071e2645622524ec7d1645eea7b7c1fa21f7f5b6b90f3e5beb99222f05ea905"
+            },
+            Test {
+                input: "eacd07971cff9b9939903f8c1d8cbb5d4db1b548a85d04e037514a583604e787f32992bf2111b97ac5e8a938233552731321522ab5e8583561260b7d13ebeef785b23a41fd8576a6da764a8ed6d822d4957a545d5244756c18aa80e1aad4d1f9c20d259dee1711e2cc8fd013169fb7cc4ce38b362f8e0936ae9198b7e838dcea4f7a5b9429bb3f6bbcf2dc92565e3676c1c5e6eb3dd2a0f86aa23edd3d0891f197447692794b3dfa269611ad97f72b795602b4fdb198f3fd3eb41b415064256e345e8d8c51c555dc8a21904a9b0f1ad0effab7786aac2da3b196507e9f33ca356427",
+                output_str: "e9399376d89c4dd4464e45825f4302cdccd4c41db4e8951be17bcc6451858332398b7e4e7f5eee6830c715451e4aacdb179dd5247ba6d5728cbd4060aeb77cb9"
+            },
+            Test {
+                input: "23ac4e9a42c6ef45c3336ce6dfc2ff7de8884cd23dc912fef0f7756c09d335c189f3ad3a23697abda851a81881a0c8ccafc980ab2c702564c2be15fe4c4b9f10dfb2248d0d0cb2e2887fd4598a1d4acda897944a2ffc580ff92719c95cf2aa42dc584674cb5a9bc5765b9d6ddf5789791d15f8dd925aa12bffafbce60827b490bb7df3dda6f2a143c8bf96abc903d83d59a791e2d62814a89b8080a28060568cf24a80ae61179fe84e0ffad00388178cb6a617d37efd54cc01970a4a41d1a8d3ddce46edbba4ab7c90ad565398d376f431189ce8c1c33e132feae6a8cd17a61c630012",
+                output_str: "ccea447efe6f8b06ac42076280377635f5fd0767f4af8b245fe63b79fe4974e9156744e60e98d12018214c39f8a826d506d0d5948645e9f883c208d37d927a41"
+            },
+            Test {
+                input: "0172df732282c9d488669c358e3492260cbe91c95cfbc1e3fea6c4b0ec129b45f242ace09f152fc6234e1bee8aab8cd56e8b486e1dcba9c05407c2f95da8d8f1c0af78ee2ed82a3a79ec0cb0709396ee62aadb84f8a4ee8a7ccca3c1ee84e302a09ea802204afecf04097e67d0f8e8a9d2651126c0a598a37081e42d168b0ae8a71951c524259e4e2054e535b779679bdade566fe55700858618e626b4a0faf895bcce9011504a49e05fd56127eae3d1f8917afb548ecadabda1020111fec9314c413498a360b08640549a22cb23c731ace743252a8227a0d2689d4c6001606678dfb921",
+                output_str: "7e03fce3b67ebb28308823f56aa93dbb4d9efdbd93300d97b1f99efcb82c3684c5a5a5aa64e7a34c69b89399cab05f22e8e88607b863336e4cbf8cf6e74b98c1"
+            },
+            Test {
+                input: "3875b9240cf3e0a8b59c658540f26a701cf188496e2c2174788b126fd29402d6a75453ba0635284d08835f40051a2a9683dc92afb9383719191231170379ba6f4adc816fecbb0f9c446b785bf520796841e58878b73c58d3ebb097ce4761fdeabe15de2f319dfbaf1742cdeb389559c788131a6793e193856661376c81ce9568da19aa6925b47ffd77a43c7a0e758c37d69254909ff0fbd415ef8eb937bcd49f91468b49974c07dc819abd67395db0e05874ff83dddab895344abd0e7111b2df9e58d76d85ad98106b36295826be04d435615595605e4b4bb824b33c4afeb5e7bb0d19f909",
+                output_str: "6a457ae74f89c42bbd2bd2ebfffbd71f036ff7b76c4afddffbd52f32e588a9543ced09da9a3e130ac1a19ef1acb2fa68ac41917ed6bad37a60982b16b5eb4ff3"
+            },
+            Test {
+                input: "747cc1a59fefba94a9c75ba866c30dc5c1cb0c0f8e9361d98484956dd5d1a40f6184afbe3dac9f76028d1caeccfbf69199c6ce2b4c092a3f4d2a56fe5a33a00757f4d7dee5dfb0524311a97ae0668a47971b95766e2f6dd48c3f57841f91f04a00ad5ea70f2d479a2620dc5cd78eaab3a3b011719b7e78d19ddf70d9423798af77517ebc55392fcd01fc600d8d466b9e7a7a85bf33f9cc5419e9bd874ddfd60981150ddaf8d7febaa4374f0872a5628d318000311e2f5655365ad4d407c20e5c04df17a222e7deec79c5ab1116d8572f91cd06e1ccc7ced53736fc867fd49ecebe6bf8082e8a",
+                output_str: "91b8cd795d1a6828601e00db0c91ff9a6f837444f53fcf89e990b88f5f3e34eb490e72a1795fab84f78da3f7afc89896c7cde5865d1bcd74d5639e4903c683fe"
+            },
+            Test {
+                input: "57af971fccaec97435dc2ec9ef0429bcedc6b647729ea168858a6e49ac1071e706f4a5a645ca14e8c7746d65511620682c906c8b86ec901f3dded4167b3f00b06cbfac6aee3728051b3e5ff10b4f9ed8bd0b8da94303c833755b3ca3aeddf0b54bc8d6632138b5d25bab03d17b3458a9d782108006f5bb7de75b5c0ba854b423d8bb801e701e99dc4feaad59bc1c7112453b04d33ea3635639fb802c73c2b71d58a56bbd671b18fe34ed2e3dca38827d63fdb1d4fb3285405004b2b3e26081a8ff08cd6d2b08f8e7b7e90a2ab1ed7a41b1d0128522c2f8bff56a7fe67969422ce839a9d4608f03",
+                output_str: "7635d79c1b32e4934eb0090c6d46c0b240f626c77d84f8eabf571ba8fde924f4a1cf456704b101f667f912dedbbcbeff2180a419a68c7b790ba606e6602d5115"
+            },
+            Test {
+                input: "04e16dedc1227902baaf332d3d08923601bdd64f573faa1bb7201918cfe16b1e10151dae875da0c0d63c59c3dd050c4c6a874011b018421afc4623ab0381831b2da2a8ba42c96e4f70864ac44e106f94311051e74c77c1291bf5db9539e69567bf6a11cf6932bbbad33f8946bf5814c066d851633d1a513510039b349939bfd42b858c21827c8ff05f1d09b1b0765dc78a135b5ca4dfba0801bcaddfa175623c8b647eacfb4444b85a44f73890607d06d507a4f8393658788669f6ef4deb58d08c50ca0756d5e2f49d1a7ad73e0f0b3d3b5f090acf622b1878c59133e4a848e05153592ea81c6fbf",
+                output_str: "ddd0c521ed60c55f65bae241a9072d7f6f6cca7f64624ec92c037bf8bc16f0602e75ee46879af41f3eff5ce235905f3856a031c3cc90a4851f4cd8463aae6de8"
+            },
+            Test {
+                input: "7c815c384eee0f288ece27cced52a01603127b079c007378bc5d1e6c5e9e6d1c735723acbbd5801ac49854b2b569d4472d33f40bbb8882956245c366dc3582d71696a97a4e19557e41e54dee482a14229005f93afd2c4a7d8614d10a97a9dfa07f7cd946fa45263063ddd29db8f9e34db60daa32684f0072ea2a9426ecebfa5239fb67f29c18cbaa2af6ed4bf4283936823ac1790164fec5457a9cba7c767ca59392d94cab7448f50eb34e9a93a80027471ce59736f099c886dea1ab4cba4d89f5fc7ae2f21ccd27f611eca4626b2d08dc22382e92c1efb2f6afdc8fdc3d2172604f5035c46b8197d3",
+                output_str: "c84c03564d024f90560001ca4cef867af77999943e313ca17328756c43d2fe31cf98812d3a7aab1535c28ed29d692db4824e8d6dce06c9994dbcbe0f82633fbe"
+            },
+            Test {
+                input: "e29d505158dbdd937d9e3d2145658ee6f5992a2fc790f4f608d9cdb44a091d5b94b88e81fac4fdf5c49442f13b911c55886469629551189eaff62488f1a479b7db11a1560e198ddccccf50159093425ff7f1cb8d1d1246d0978764087d6bac257026b090efae8cec5f22b6f21c59ace1ac7386f5b8837ca6a12b6fbf5534dd0560ef05ca78104d3b943ddb220feaec89aa5e692a00f822a2ab9a2fe60350d75e7be16ff2526dc643872502d01f42f188abed0a6e9a6f5fd0d1ce7d5755c9ffa66b0af0b20bd806f08e06156690d81ac811778ca3dac2c249b96002017fce93e507e3b953acf99964b847",
+                output_str: "b4563191675191ed4d6107e52fa15adc9d70642358d8c3e34df10274e25d373fd8d19e92472b823e28bbdd1d541a95fddd0d43c79fcb3ba18a7ec038d3ef69a6"
+            },
+            Test {
+                input: "d85588696f576e65eca0155f395f0cfacd83f36a99111ed5768df2d116d2121e32357ba4f54ede927f189f297d3a97fad4e9a0f5b41d8d89dd7fe20156799c2b7b6bf9c957ba0d6763f5c3bc5129747bbb53652b49290cff1c87e2cdf2c4b95d8aaee09bc8fbfa6883e62d237885810491bfc101f1d8c636e3d0ede838ad05c207a3df4fad76452979eb99f29afaecedd1c63b8d36cf378454a1bb67a741c77ac6b6b3f95f4f02b64dabc15438613ea49750df42ee90101f115aa9abb9ff64324dde9dabbb01054e1bd6b4bcdc7930a44c2300d87ca78c06924d0323ad7887e46c90e8c4d100acd9eed21e",
+                output_str: "a30bd80cb3acb3bfa7e037a3d0d2500974d71957f68135133020c32eb4d688f132d0fb045be027f124b3d935cb889e3cbc4a4a420026bb2ac2a4b1b15c57bb64"
+            },
+            Test {
+                input: "3a12f8508b40c32c74492b66323375dcfe49184c78f73179f3314b79e63376b8ac683f5a51f1534bd729b02b04d002f55cbd8e8fc9b5ec1ea6bbe6a0d0e7431518e6ba45d124035f9d3dce0a8bb7bf1430a9f657e0b4ea9f20eb20c786a58181a1e20a96f1628f8728a13bdf7a4b4b32fc8aa7054cc4881ae7fa19afa65c6c3ee1b3ade3192af42054a8a911b8ec1826865d46d93f1e7c5e2b7813c92a506e53886f3d4701bb93d2a681ad109c845904bb861af8af0646b6e399b38b614051d34f6842563a0f37ec00cb3d865fc5d746c4987de2a65071100883a2a9c7a2bfe1e2dd603d9ea24dc7c5fd06be",
+                output_str: "4a5809e457f54d9c7e8209f6c482d52a4efe6d8a20c4c6fba83687294929232d25cd7bf511d8e6fbf272e983f07d044f8723098d7a381f04e957b0787087ef02"
+            },
+            Test {
+                input: "1861edce46fa5ad17e1ff1deae084dec580f97d0a67885dfe834b9dfac1ae076742ce9e267512ca51f6df5a455af0c5fd6abf94acea103a3370c354485a7846fb84f3ac7c2904b5b2fbf227002ce512133bb7e1c4e50057bfd1e44db33c7cdb969a99e284b184f50a14b068a1fc5009d9b298dbe92239572a7627aac02abe8f3e3b473417f36d4d2505d16b7577f4526c9d94a270a2dfe450d06da8f6fa956879a0a55cfe99e742ea555ea477ba3e9b44ccd508c375423611af92e55345dc215779b2d5119eba49c71d49b9fe3f1569fa24e5ca3e332d042422a8b8158d3ec66a80012976f31ffdf305f0c9c5e",
+                output_str: "a79016c34bee41ab5cb10278478a5b55d07c2e0831835dde6f8ff8dafac37a5f88fba07cceffe35849dbd123b06df2335b002645d078fe1b08843c257a1bbe56"
+            },
+            Test {
+                input: "08d0ffde3a6e4ef65608ea672e4830c12943d7187ccff08f4941cfc13e545f3b9c7ad5eebbe2b01642b486caf855c2c73f58c1e4e3391da8e2d63d96e15fd84953ae5c231911b00ad6050cd7aafdaac9b0f663ae6aab45519d0f5391a541707d479034e73a6ad805ae3598096af078f1393301493d663dd71f83869ca27ba508b7e91e81e128c1716dc3acfe3084b2201e04cf8006617eecf1b640474a5d45cfde9f4d3ef92d6d055b909892194d8a8218db6d8203a84261d200d71473d7488f3427416b6896c137d455f231071cacbc86e0415ab88aec841d96b7b8af41e05bb461a40645bf176601f1e760de5f",
+                output_str: "603f7b09565634d4410b574a4dc9ea467437964517e5efa51a362a30e8c632c55162a3351bb5532e40948aa9a1e3a8786c0422aec3ec338c7f4b57679200452b"
+            },
+            Test {
+                input: "d782abb72a5be3392757be02d3e45be6e2099d6f000d042c8a543f50ed6ebc055a7f133b0dd8e9bc348536edcaae2e12ec18e8837df7a1b3c87ec46d50c241dee820fd586197552dc20beea50f445a07a38f1768a39e2b2ff05dddedf751f1def612d2e4d810daa3a0cc904516f9a43af660315385178a529e51f8aae141808c8bc5d7b60cac26bb984ac1890d0436ef780426c547e94a7b08f01acbfc4a3825eae04f520a9016f2fb8bf5165ed12736fc71e36a49a73614739eaa3ec834069b1b40f1350c2b3ab885c02c640b9f7686ed5f99527e41cfcd796fe4c256c9173186c226169ff257954ebda81c0e5f99",
+                output_str: "1018692d530c55baa580ae1e7384351100d4637cd33869c71e6076a3d4e310d964b81d593e89718845ac7a89e8ad5073506427c6c8f7fadfa0c5dc3cfaa5d924"
+            },
+            Test {
+                input: "5fce8109a358570e40983e1184e541833bb9091e280f258cfb144387b05d190e431cb19baa67273ba0c58abe91308e1844dcd0b3678baa42f335f2fa05267a0240b3c718a5942b3b3e3bfa98a55c25a1466e8d7a603722cb2bbf03afa54cd769a99f310735ee5a05dae2c22d397bd95635f58c48a67f90e1b73aafcd3f82117f0166657838691005b18da6f341d6e90fc1cdb352b30fae45d348294e501b63252de14740f2b85ae5299ddec3172de8b6d0ba219a20a23bb5e10ff434d39db3f583305e9f5c039d98569e377b75a70ab837d1df269b8a4b566f40bb91b577455fd3c356c914fa06b9a7ce24c7317a172d",
+                output_str: "e3c0eaffc3567bd72cc02150a75f32dde53de2652c5313eb3e97018adddf629da01d97d0a9e2519451a7292f5de00ee4456fe6e4f14f96d5de7e6f174edb28c4"
+            },
+            Test {
+                input: "6172f1971a6e1e4e6170afbad95d5fec99bf69b24b674bc17dd78011615e502de6f56b86b1a71d3f4348087218ac7b7d09302993be272e4a591968aef18a1262d665610d1070ee91cc8da36e1f841a69a7a682c580e836941d21d909a3afc1f0b963e1ca5ab193e124a1a53df1c587470e5881fb54dae1b0d840f0c8f9d1b04c645ba1041c7d8dbf22030a623aa15638b3d99a2c400ff76f3252079af88d2b37f35ee66c1ad7801a28d3d388ac450b97d5f0f79e4541755356b3b1a5696b023f39ab7ab5f28df4202936bc97393b93bc915cb159ea1bd7a0a414cb4b7a1ac3af68f50d79f0c9c7314e750f7d02faa58bfa",
+                output_str: "192ae7a0f7a816fd3d4020bddcf2aaf52a64e6384dca527f33af4ee69099dca97b890a99cfab9d904a35f2707856696c30c6432df70a6cef704bb268055a6d07"
+            },
+            Test {
+                input: "5668ecd99dfbe215c4118398ac9c9eaf1a1433fab4ccdd3968064752b625ea944731f75d48a27d047d67547f14dd0ffaa55fa5e29f7af0d161d85eafc4f2029b717c918eab9d304543290bdba7158b68020c0ba4e079bc95b5bc0fc044a992b94b4ccd3bd66d0eabb5dbbab904d62e00752c4e3b0091d773bcf4c14b4377da3efff824b1cb2fa01b32d1e46c909e626ed2dae920f4c7dbeb635bc754facbd8d49beba3f23c1c41ccbfcd0ee0c114e69737f5597c0bf1d859f0c767e18002ae8e39c26261ffde2920d3d0baf0e906138696cfe5b7e32b600f45df3aaa39932f3a7df95b60fa8712a2271fcaf3911ce7b511b1",
+                output_str: "6bcd7e7c359fdd93a56d79f97fc2d534619f14fe443ac8c9e042c5105fbaf2777718de07424a62333ffd43a501a8544449a7cac3c8d821e380b0cb8172b9493b"
+            },
+            Test {
+                input: "03d625488354df30e3f875a68edfcf340e8366a8e1ab67f9d5c5486a96829dfac0578289082b2a62117e1cf418b43b90e0adc881fc6ae8105c888e9ecd21aea1c9ae1a4038dfd17378fed71d02ae492087d7cdcd98f746855227967cb1ab4714261ee3bead3f4db118329d3ebef4bc48a875c19ba763966da0ebea800e01b2f50b00e9dd4caca6dcb314d00184ef71ea2391d760c950710db4a70f9212ffc54861f9dc752ce18867b8ad0c48df8466ef7231e7ac567f0eb55099e622ebb86cb237520190a61c66ad34f1f4e289cb3282ae3eaac6152ed24d2c92bae5a7658252a53c49b7b02dfe54fdb2e90074b6cf310ac661",
+                output_str: "1fcd1e38ab03c750366cf86dd72ec3bf22f5bbf7fea0149d31b6a67b68b537b59ba37917fd88ced9aa8d2941a65f552b7928b3785c66d640f3b74af039ed18ce"
+            },
+            Test {
+                input: "2edc282ffb90b97118dd03aaa03b145f363905e3cbd2d50ecd692b37bf000185c651d3e9726c690d3773ec1e48510e42b17742b0b0377e7de6b8f55e00a8a4db4740cee6db0830529dd19617501dc1e9359aa3bcf147e0a76b3ab70c4984c13e339e6806bb35e683af8527093670859f3d8a0fc7d493bcba6bb12b5f65e71e705ca5d6c948d66ed3d730b26db395b3447737c26fad089aa0ad0e306cb28bf0acf106f89af3745f0ec72d534968cca543cd2ca50c94b1456743254e358c1317c07a07bf2b0eca438a709367fafc89a57239028fc5fecfd53b8ef958ef10ee0608b7f5cb9923ad97058ec067700cc746c127a61ee3",
+                output_str: "f39ef0626d3fbd9cd435a93e7eee41e4a2ff5362f56c988b20870a3befa50470dc5fabe39895c0761289fafd9147abab02561f300d0ceb9a732e14ca887caf18"
+            },
+            Test {
+                input: "90b28a6aa1fe533915bcb8e81ed6cacdc10962b7ff82474f845eeb86977600cf70b07ba8e3796141ee340e3fce842a38a50afbe90301a3bdcc591f2e7d9de53e495525560b908c892439990a2ca2679c5539ffdf636777ad9c1cdef809cda9e8dcdb451abb9e9c17efa4379abd24b182bd981cafc792640a183b61694301d04c5b3eaad694a6bd4cc06ef5da8fa23b4fa2a64559c5a68397930079d250c51bcf00e2b16a6c49171433b0aadfd80231276560b80458dd77089b7a1bbcc9e7e4b9f881eacd6c92c4318348a13f4914eb27115a1cfc5d16d7fd94954c3532efaca2cab025103b2d02c6fd71da3a77f417d7932685888a",
+                output_str: "81e8b59ddcd24811b405f7529da125f0dc19ae21e8795ce9e6692dab645b7959446adcaa3061dc4642a51d8a562efb03a7680af0f52c01406d5c213eaac6be55"
+            },
+            Test {
+                input: "2969447d175490f2aa9bb055014dbef2e6854c95f8d60950bfe8c0be8de254c26b2d31b9e4de9c68c9adf49e4ee9b1c2850967f29f5d08738483b417bb96b2a56f0c8aca632b552059c59aac3f61f7b45c966b75f1d9931ff4e596406378cee91aaa726a3a84c33f37e9cdbe626b5745a0b06064a8a8d56e53aaf102d23dd9df0a3fdf7a638509a6761a33fa42fa8ddbd8e16159c93008b53765019c3f0e9f10b144ce2ac57f5d7297f9c9949e4ff68b70d339f87501ce8550b772f32c6da8ad2ce2100a895d8b08fa1eead7c376b407709703c510b50f87e73e43f8e7348f87c3832a547ef2bbe5799abedcf5e1f372ea809233f006",
+                output_str: "63424b09069fbd2d0fac00805aad07fd56e30bb8116b5476ae90bf6acec84c3b45368a9ebb7fcea8d65965f52514a2a59a06e6e06b07dc6aee7f756bfc188e25"
+            },
+            Test {
+                input: "721645633a44a2c78b19024eaecf58575ab23c27190833c26875dc0f0d50b46aea9c343d82ea7d5b3e50ec700545c615daeaea64726a0f05607576dcd396d812b03fb6551c641087856d050b10e6a4d5577b82a98afb89cee8594c9dc19e79feff0382fcfd127f1b803a4b9946f4ac9a4378e1e6e041b1389a53e3450cd32d9d2941b0cbabdb50da8ea2513145164c3ab6bcbd251c448d2d4b087ac57a59c2285d564f16da4ed5e607ed979592146ffb0ef3f3db308fb342df5eb5924a48256fc763141a278814c82d6d6348577545870ae3a83c7230ac02a1540fe1798f7ef09e335a865a2ae0949b21e4f748fb8a51f44750e213a8fb",
+                output_str: "1e709fb3501fa818f57e70c365db45ccf2eb8a8fa66de9b5f211d6f0cc9722ade963c965ad5f6937ba62edc2d8983843e0f3679d9c97b30cd54f2409dda5f474"
+            },
+            Test {
+                input: "6b860d39725a14b498bb714574b4d37ca787404768f64c648b1751b353ac92bac2c3a28ea909fdf0423336401a02e63ec24325300d823b6864bb701f9d7c7a1f8ec9d0ae3584aa6dd62ea1997cd831b4babd9a4da50932d4efda745c61e4130890e156aee6113716daf95764222a91187db2effea49d5d0596102d619bd26a616bbfda8335505fbb0d90b4c180d1a2335b91538e1668f9f9642790b4e55f9cab0fe2bdd2935d001ee6419abab5457880d0dbff20ed8758f4c20fe759efb33141cf0e892587fe8187e5fbc57786b7e8b089612c936dfc03d27efbbe7c8673f1606bd51d5ff386f4a7ab68edf59f385eb1291f117bfe717399",
+                output_str: "5b9f0c544627faadea82825a569da33a75c5da6cc169926de0556a737e4daa07abf1dc3db0704f5d67fcbc4cb62aac442ecec867a2c16846f1d53d205cb872ac"
+            },
+            Test {
+                input: "6a01830af3889a25183244decb508bd01253d5b508ab490d3124afbf42626b2e70894e9b562b288d0a2450cfacf14a0ddae5c04716e5a0082c33981f6037d23d5e045ee1ef2283fb8b6378a914c5d9441627a722c282ff452e25a7ea608d69cee4393a0725d17963d0342684f255496d8a18c2961145315130549311fc07f0312fb78e6077334f87eaa873bee8aa95698996eb21375eb2b4ef53c14401207deb4568398e5dd9a7cf97e8c9663e23334b46912f8344c19efcf8c2ba6f04325f1a27e062b62a58d0766fc6db4d2c6a1928604b0175d872d16b7908ebc041761187cc785526c2a3873feac3a642bb39f5351550af9770c328af7b",
+                output_str: "930ab42a9f5f5bc5f2222c748f2478a00f40c3b6d6487d6d7ed0d71100f40fcbb2c66566ea26ad0a417629f5a61dca411ccd21f7367d308f3b1b24901824fa9b"
+            },
+            Test {
+                input: "b3c5e74b69933c2533106c563b4ca20238f2b6e675e8681e34a389894785bdade59652d4a73d80a5c85bd454fd1e9ffdad1c3815f5038e9ef432aac5c3c4fe840cc370cf86580a6011778bbedaf511a51b56d1a2eb68394aa299e26da9ada6a2f39b9faff7fba457689b9c1a577b2a1e505fdf75c7a0a64b1df81b3a356001bf0df4e02a1fc59f651c9d585ec6224bb279c6beba2966e8882d68376081b987468e7aed1ef90ebd090ae825795cdca1b4f09a979c8dfc21a48d8a53cdbb26c4db547fc06efe2f9850edd2685a4661cb4911f165d4b63ef25b87d0a96d3dff6ab0758999aad214d07bd4f133a6734fde445fe474711b69a98f7e2b",
+                output_str: "08203943c58210d3f82758272befbb9234fe913409a07944645959b1a6af2f4363abd7451232623daa8e65c87f34939c140608950fbdbbe83d66407944f5423a"
+            },
+            Test {
+                input: "83af34279ccb5430febec07a81950d30f4b66f484826afee7456f0071a51e1bbc55570b5cc7ec6f9309c17bf5befdd7c6ba6e968cf218a2b34bd5cf927ab846e38a40bbd81759e9e33381016a755f699df35d660007b5eadf292feefb735207ebf70b5bd17834f7bfa0e16cb219ad4af524ab1ea37334aa66435e5d397fc0a065c411ebbce32c240b90476d307ce802ec82c1c49bc1bec48c0675ec2a6c6f3ed3e5b741d13437095707c565e10d8a20b8c20468ff9514fcf31b4249cd82dcee58c0a2af538b291a87e3390d737191a07484a5d3f3fb8c8f15ce056e5e5f8febe5e1fb59d6740980aa06ca8a0c20f5712b4cde5d032e92ab89f0ae1",
+                output_str: "a24dd6a50333f289c175cd4ec185da9906e38c287a339dc4defafd71b2ea32a6f6aefe758e25fc8f043e806f1b2ee019e13b85536cd3efaa2a9b5994fcae4788"
+            },
+            Test {
+                input: "a7ed84749ccc56bb1dfba57119d279d412b8a986886d810f067af349e8749e9ea746a60b03742636c464fc1ee233acc52c1983914692b64309edfdf29f1ab912ec3e8da074d3f1d231511f5756f0b6eead3e89a6a88fe330a10face267bffbfc3e3090c7fd9a850561f363ad75ea881e7244f80ff55802d5ef7a1a4e7b89fcfa80f16df54d1b056ee637e6964b9e0ffd15b6196bdd7db270c56b47251485348e49813b4eb9ed122a01b3ea45ad5e1a929df61d5c0f3e77e1fdc356b63883a60e9cbb9fc3e00c2f32dbd469659883f690c6772e335f617bc33f161d6f6984252ee12e62b6000ac5231e0c9bc65be223d8dfd94c5004a101af9fd6c0fb",
+                output_str: "cd1ed5fff6fa3d453872510b6b2712ec9c6eba9543734d88511ed475905e123ed6ef6624f220445fe89c257a9f9c5166a2772ef768b50e9290fb1d4761eca6c8"
+            },
+            Test {
+                input: "a6fe30dcfcda1a329e82ab50e32b5f50eb25c873c5d2305860a835aecee6264aa36a47429922c4b8b3afd00da16035830edb897831c4e7b00f2c23fc0b15fdc30d85fb70c30c431c638e1a25b51caf1d7e8b050b7f89bfb30f59f0f20fecff3d639abc4255b3868fc45dd81e47eb12ab40f2aac735df5d1dc1ad997cefc4d836b854cee9ac02900036f3867fe0d84afff37bde3308c2206c62c4743375094108877c73b87b2546fe05ea137bedfc06a2796274099a0d554da8f7d7223a48cbf31b7decaa1ebc8b145763e3673168c1b1b715c1cd99ecd3ddb238b06049885ecad9347c2436dff32c771f34a38587a44a82c5d3d137a03caa27e66c8ff6",
+                output_str: "cfaa0eb1c9f02c0469eefb31a1a53ca1a4765f78ec171cf15da7d5c512817b8bf7d7cd7b1416b3de2bba05edfb0b493495ac2107a4b686d5dd8d6ad41b4aa3d7"
+            },
+            Test {
+                input: "83167ff53704c3aa19e9fb3303539759c46dd4091a52ddae9ad86408b69335989e61414bc20ab4d01220e35241eff5c9522b079fba597674c8d716fe441e566110b6211531ceccf8fd06bc8e511d00785e57788ed9a1c5c73524f01830d2e1148c92d0edc97113e3b7b5cd3049627abdb8b39dd4d6890e0ee91993f92b03354a88f52251c546e64434d9c3d74544f23fb93e5a2d2f1fb15545b4e1367c97335b0291944c8b730ad3d4789273fa44fb98d78a36c3c3764abeeac7c569c1e43a352e5b770c3504f87090dee075a1c4c85c0c39cf421bdcc615f9eff6cb4fe6468004aece5f30e1ecc6db22ad9939bb2b0ccc96521dfbf4ae008b5b46bc006e",
+                output_str: "2be71ee9ace2dbcfd43d6d020c07244554dac8a2cf1571d0fa1d004933739e8978323056797e04c333f5bf187e64f1d881e502672567f204de0e73ce26e7190d"
+            },
+            Test {
+                input: "3a3a819c48efde2ad914fbf00e18ab6bc4f14513ab27d0c178a188b61431e7f5623cb66b23346775d386b50e982c493adbbfc54b9a3cd383382336a1a0b2150a15358f336d03ae18f666c7573d55c4fd181c29e6ccfde63ea35f0adf5885cfc0a3d84a2b2e4dd24496db789e663170cef74798aa1bbcd4574ea0bba40489d764b2f83aadc66b148b4a0cd95246c127d5871c4f11418690a5ddf01246a0c80a43c70088b6183639dcfda4125bd113a8f49ee23ed306faac576c3fb0c1e256671d817fc2534a52f5b439f72e424de376f4c565cca82307dd9ef76da5b7c4eb7e085172e328807c02d011ffbf33785378d79dc266f6a5be6bb0e4a92eceebaeb1",
+                output_str: "6e8b8bd195bdd560689af2348bdc74ab7cd05ed8b9a57711e9be71e9726fda4591fee12205edacaf82ffbbaf16dff9e702a708862080166c2ff6ba379bc7ffc2"
+            }
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Sha3_512));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_sha3_shake128() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef263cb1eea988004b93103cfb0aeefd2a686e01fa4a58e8a3639ca8a1e3f9ae57e235b8cc873c23dc62b8d260169afa2f75ab916a58d974918835d25e6a435085b2badfd6dfaac359a5efbb7bcc4b59d538df9a04302e10c8bc1cbf1a0b3a5120ea17cda7cfad765f5623474d368ccca8af0007cd9f5e4c849f167a580b14aabdefaee7eef47cb0fca9767be1fda69419dfb927e9df07348b196691abaeb580b32def58538b8d23f87732ea63b02b4fa0f4873360e2841928cd60dd4cee8cc0d4c922a96188d032675c8ac850933c7aff1533b94c834adbb69c6115bad4692d8619f90b0cdf8a7b9c264029ac185b70b83f2801f2f4b3f70c593ea3aeeb613a7f1b1de33fd75081f592305f2e4526edc09631b10958f464d889f31ba010250fda7f1368ec2967fc84ef2ae9aff268e0b1700affc6820b523a3d917135f2dff2ee06bfe72b3124721d4a26c04e53a75e30e73a7a9c4a95d91c55d495e9f51dd0b5e9d83c6d5e8ce803aa62b8d654db53d09b8dcff273cdfeb573fad8bcd45578bec2e770d01efde86e721a3f7c6cce275dabe6e2143f1af18da7efddc4c7b70b5e345db93cc936bea323491ccb38a388f546a9ff00dd4e1300b9b2153d2041d205b443e41b45a653f2a5c4492c1add544512dda2529833462b71a41a45be97290b6f"
+            },
+            Test {
+                input: "cc",
+                output_str: "4dd4b0004a7d9e613a0f488b4846f804015f0f8ccdba5f7c16810bbc5a1c6fb254efc81969c5eb49e682babae02238a31fd2708e418d7b754e21e4b75b65e7d39b5b42d739066e7c63595daf26c3a6a2f7001ee636c7cb2a6c69b1ec7314a21ff24833eab61258327517b684928c7444380a6eacd60a6e9400da37a61050e4cd1fbdd05dde0901ea2f3f67567f7c9bf7aa53590f29c94cb4226e77c68e1600e4765bea40b3644b4d1e93eda6fb0380377c12d5bb9df4728099e88b55d820c7f827034d809e756831a334c078fc28acb76b5adb3bff6dd659caa49cc34f726880f293bd3fc132027ae7602242064efec4d9d656e069d4dfae0b40c1d6b6cdb21d89d00e168b0b74d72ebb3b672b57af3e99c85da2f41ce70672cd0e0521678fc56eab6314a0b3af8b724376c01433d84943a73af703d293634bc24322992756ee261fff0d71bffb8aebf1026a6a345f2eaed505bc7e02498a3225fc91499dd5f5e30e386557c5fe0a88bc2337c80d7ea42b60622960230577ce800cb63594f619b7de31e026429b7648c5835afc00559fa4c7695d6dd9f7b2537a265e9af7a2c986f8b60e7dc6eb3c4d805a6eefb6fbb5bfde21ed7e41cfdbeb02b0bab76f9998ba1e52815a246b084efae7960affc2ba5c647e7cc05ef8120568432dfde1d7246473304808985600a1afc20b99185af25e89dc2ec6f4880dc79bad50dffcc9ea"
+            },
+            Test {
+                input: "41fb",
+                output_str: "09c9652bb968996a35e4814e27587131f53fd01ab9fe83758aceb8134fceca24c84f592cee43a4476e8853fcab7dafef7b60ecfebfd70dfcf587b3af358a286fe3713bf4735a84975bb65e3586c81ea716bfb999626dc973a495a6e0024061387d628e9e59dfd2b39c68c8cead665ab43f6d2625a10630761dfb60276ea97b280442462246c6d74a1960a8419a76a37b68449a9e427d6a7ec1fbdf4760847ad6f6f5a08cefb767caeb6c2382f4f3d0e49de4428cd4240635c9136911a82ff0b9c74569a1b7c8af72ab1ea5f2f6f6a45e3bb08229addfa916b18a74f7939c5130152ac8343a10694154fdc6e1570ec7ecabbb01eddc92ef0bb1b3db914c74cce399acc9b766fd7494b2ef27ac57b80d52535942d55e2dbfaa61cdf3f48759aa612ded11421855ad15ffab91462a56f873bbaf4fe88457a47b6c0594818d0a9189895239c1429ed8754eee5498f4d0fb6c9d0df0eb5316289e72c6aaeb8c61317b409156d4221ce6cfc7c5f39272d87c2d884f88f1b8b3c05ca9e235ed92c7dd7806cdada7166cc1b9107da5e6536d4ff111bf9199d6b72ac17d874323d68d76aec4650f1a4b067c50215362201a7f71116bf6633af08d712804b83f08a5dc7ccd4315963106d50453d44eff59c9c652f4a924be93c0b958ea286b0a4b597899a28c9bd5419c042668aa7b0cfcac4cdf9260f2824abf3ee79fef53ebe3c36df831"
+            },
+            Test {
+                input: "1f877c",
+                output_str: "e2d3144669ab578347fcca0b572783a269a8cf9adda4d87782053d80d5f0fdd27835cf883036e536ce76fef689a5e7bd646a7fb7d74f090193b2390e614759b7eb7de915a38328745890b1ef1e7aed78168e996d7ac774d47f8f118b3e00a7bd151131ba3705ae81b57fb7cbffe114e2f4c3ca152b8874fb906e862840624e02bbf9502e46d8888433a38e82e04caacb60019222d433e8f2e758bd41aab395bf83611fd0c3f7fd5173306182449b9a22c4013f2263b41eac4d0eda16854961fbaa6ad04a89e72a602ac59659ec2a60c1d020bacc74a711d4254a2ecc5f8f0627b4f72ae130c50590f8b91c52957b795d12da09bdd40d41e3cd48e30e37fe5fd0b86eb38ab4661085ef515e70231a5f11f9dbf7433763b17d84f36bf42fb6d57789c6da2be8d205ead87bdcc3fa6ac85fcc3e70571ebb2ee4bbbfc04e71b3a88e000464608475c94c7d7ec1bbfcec980b166096e9bdde9192c53e350d3b92f3ab0fcef4e49e05bbbc18b11eca942c8a0776ed4f293b7fc9b8e7c0303a29a41de64bfebd2967875290d471640a914b0775cdff140b2b66cb099a05f5357c9d5e7f9f1d78b828ccd23fc7cd58329613de4be9869b4f2db18f5792795c34c43d23e2cc5525b4a363a9619ad57e42c36ec459ffae56b61717ef36afc9fbe5a72a7d23d435b2ef38a2b0e22ab5dfc8bb8747b6ebf17a63f6368795c6a16dee05362422"
+            },
+            Test {
+                input: "c1ecfdfc",
+                output_str: "b5eb987e7cbfc7c9d140afd20b500e30f2f71188bce885951f22fbc35de40e7411311bc8479f895a069600483751295f5c3855474d65436b347608583125a6bd41ca30dc99cb342b72a96f8a2213e98a16bbb9e38a141b4fba68c1a723d1d578a91b4a1bafd03b25bd3cfb6d4e1e044637889c6d7af0209dbb5e10837d5c5991d2766012e7e86a82838b455b96d882b7e25c9072a66da22b0acb992fd3ccf5fbc28625b896bdf8d4b7358901d12698fd823fe09afb4f238631ee1277752f2900e38c7fc163381a01601dbde8cd30a9a8ee8353def6c610b50962d0ec1f4f3eec2afd7fcd5296e299c23005960c1aabf3408ede96de18e10fde99774b5bd33092639d8be9d872130c96311eb6dca82cc28a62c01e3f9c454251d87fa890284c06187f904cf23ccc62690628c590bc8b84eee68371d3412dcb5648a634f2359951cd011028e61c28a33ec4e31550c1c0e4123d1091e22d56bd587e73b7dd43c1b431d9547398c5e7eb6c682ea2fd758c86c1222c0d6ab236b8106dac19338e86cb8f6ec0fb607d70c938cac172c80079b018bb62939546505b8b6e146a3ad7a35f20d7f9a353f1e6535c23ae93ce8f78c045402e707a664f5918e6836d343240e6112efa29dfc4d18778c91e2b8530e4ff6e4947623d31dafac9b0d194e36c44e10b1a846935684f89adb44782e8fff2e3e62b65d18140f10d36cd817f835eb0c0"
+            },
+            Test {
+                input: "21f134ac57",
+                output_str: "7bfbb40da3704a558291b39e1e56ed9f6f56ae783270ab02a202060c9173fbb0b45575b32348a6ed2c927a39a30da0a2bbc1807497ad50f27a107754af62762c0b9e8e62438101deca378899c521cb76c75d299ede19ba70e2ab91da9e39ebdc917355b6fe28ee254c0cd48f3a28fb51766fd58154c98a5c650a4e4841d14e2c8f5baebf5aaf2a2120279d2d33214a51ca30c4e05209bbd60106cc343ec867effc826cb32a2e736c4aa561ffaecb46ffb74d1b3fd36242244312067c7cea2ebbcf988e17742c3c80e8dee6d509997866a308c101214f860512d38e3b6c307c1ce779fd42fdcb9d909a2d6f9dd5a3687708905390479950d55e8890d10d7057863cf006034a6d01d77fb33c0e28b093fe3337be8416202dc866796739271c9e326199092fa27556c9f40d7e9bac869b6d7e8018409ea92af2464c58245e89556da3e80b6b4200b9e53fc80c93149e3dc4921a5fbe7df67f1d0b753cba41b75ee5cba78a89a2a85a46bbfaa625a40ee62616e68b07c06339717c81b4343760e97e2676c347d9625ece383fbb8448e7837dc704e2956b18cc506e3ba1416c936bfd66e9aed3a2c7b0a8dedadb04ab711d147f1c1c83322ec1e6f1468ad770663c7938d4032758462513652498cf124b6357b4f7c7e4db0d0c0c1b7247875cb6685e0567a8ab8cfbe9383daeaa27d224ca9c69c07afa929ffc09a03e165d72153ad2"
+            },
+            Test {
+                input: "c6f50bb74e29",
+                output_str: "8d876c67a5cc15a544eb81e93b6fc15713fd1c55d778204eb6af7086af3fe97d12b4dd22c7aad54eb9c9e391b90a7c55abacc3c81dd1788895f17033d561060e2b9cffd47974f196c6907907dfdc65cdf33baafa7049635a70353d92a56a59ecf0cd291ab9b509d296356e8b0c91983d158db1568681de035e56b86eae32ad3e0193cb816bd2d111c266632ddf907bb276e14880571506e2c328a3eeaa9744210ebfead123e241a8c49c92ada79b718d970f0e8525a60ffe9074e73491e6f0eed1e047eb95cb52c47f6a1bab77017d020f016b64798e5d7fc360d5fa213d44e5b75c918c9ecbb134ce1dbe13c419da62326a550ad4a22e171ce75a369bb820cd75fde01993ca131f302be7941f7950a9969d78148fe7c45bbd22fe83ad0354194859f2f0dda1c92f2c8edfd3f7a9d8f618d0d02222442df41d858cbb7a46e5b12a0923dcb53587957ee07ed3e1c4a46eb1141cee394972726dd003239ecfe8fddc4e58c50359af3f89fe58f5cd5aebc0dc6b9d600f3ed08506256f18695ddc1e3b459ad75090f0764fa89e5ccec98ee0b387b5fb778620bda72cb3e2ae50de8b0d6b43f26e13a16fdf08bea752b457bf486ce427fd17bd4c5890a89af2c85b292c51cec75490c1c6de9d60dc49d3a77eeb7e19002150794234194115bc685e9981f88b0e1d9c6585f2c5f9dc805ff6c7636c1e06d9f5c018f74a2ce92eff6b26"
+            },
+            Test {
+                input: "119713cc83eeef",
+                output_str: "e2a9537bac3c4dfc9008c1a7aba653883d7a1df35685dbf49abe5a7e93bf044bc3312a5e4d9743d72bd28acc16f64ac5090a71761d936fb9da7c782af9bc1f636d0e17cb41c7e0e9dfbdb2017ecaba6dbecdce2aecce3ed4f59324e74d58d434096356e567b35ac85f7ca9ab80b1c987ce70f998abe6536fe485a866a22cdcc37db08cc742b4612121cf34c2d404b37e8ea8d90ca9cfd0c8c6ecb6b44bf73f4d048a0fd85591d8726be6246df406472ca05d18dffebeab7ed991be6cd2940ec9b26f9c9219dfffcd721f5dd93cf5342a89a6c69168871b14934d4f1794e14b92ea991a78292423f5cd0a5d3454e55dee27077d6af78d87bb3fb9e139331abf326fde2fe1d3b1533aa038bf59bdc2d6333f968611a4f9ba66efe92ae8c099ecfc1a36be726816fafcc0b016c58b1e42d2cc7065e71abbd7cec1ed547aebf46f5dd72bd472cd764ccb3c4afaca540bdc27f52f63151e9fd90ad5bba7f84c9ec7e996692b842fb1a54d2860a301a9df6f357c2e05c14154f5fb77a86e4da9e9a039cddeb10d6e5de2e0a585b2701d48e8298bf71f5f72351f8eb3fba5426286a82abb75ea46bfc0f65a2e49567cfc970c36d63b2cc73ad7f9791179b1a0c4d84651dce57b966410ca23cfcb9bf5bd70d56f5bf1a7c939de74924edbfcc614113c83803b123f3eefce2c809a7a9fb01c709bc09b5f7632d6b59e31a6469d90185477"
+            },
+            Test {
+                input: "4a4f202484512526",
+                output_str: "977735a853d872ff7c17c4a825afd9df886ac43387df245c37a608ac7f4e0ed015811167222000aee1968960174ee5a39369a23c5dffb4991ad247b8801de71bea97069ea77202999f8e8cf3829816ee598b00c4049265dfbb2b138b13ec3194b988242bc099248baf9997aed80e95b5f859d42b12dbd578fdeae47ccc2f8d3e90bf6e8d98afbe2f4813f68b6fbc4c18c9b8a557a0d87d744a4238d89260941030945538b2df07e05fd45b50bd790a0510ed4430adb3b7768df8c4914e0914fb00da09331f11371052d301031853c7f3c32528c0622a77c48463cd1cd96ecf7490f70f16e941cbfade71dd8477ecff1177b7193e456ecc42befbe070667d6f39abee5cba354b33a83602c1c17280d2dbd0ce597ecf1fec3b27810df38c2805d8b85d60994edd2c83f5898cc6623241f16c4c92444fb6a0714d8bf189aa5aec9d5bf1448805764ea0ccc8b6e399961dfa7cb9d8de8d800080eeb5d010bcacac6728e8de482c37270459dcbc80f496267377d97817149372a053b2d53209c2dd61216cc3aad29c7238d6b142d71a92ceee4710476c2a48fadb683b9423727ce772fce2bdbcf781c119fb43526b8eaaf1d10f21e586952227e29bae61fa2c7edc6260f76ab543244e538180cd90c207330ef29cea987f7acdfa028a78d3e93f11ea159b21bf3f50faeb7961874e816162d42735c9d3567afa45d1d8b66cefb58678"
+            },
+            Test {
+                input: "1f66ab4185ed9b6375",
+                output_str: "1d96e0454be037d890fbeb776ce5c922bdfb827af1d1abee1bc8b3ae95453532d40c0b3f9c93e400ff70f6fbd4dd0470df1f06e04ab4a596b6f92bbcaad3650d60b940096260226913435c9bbf5f29de8bcc9721748e3f1deb7fae88741084507e1ba72a267c2c2276d8bd8ed284578b46ae81230f383214137cd7c190524818576f77b0a53c3421e0476d91e11bae79acc4995a24fd1398f6f67e22033bc381abe6de4e0563238fdc39a1b305fa9403ee35800432999eb3421c8cc17f77f2a544957afc2ce9496d2b739511b3cc52db118ee874e43e95fa69d7ef024931377af86a9448f3899dd0a87edcfecfc1bcf7c17d470c71cc488744f2b627626112aee465adde9c6719ac0f6e928c77b0ba0ae8a5ce20005c46768021438b611826675e0b94fdc7484a3854936216e2239650c794ef001ef8f9f4cb440664472445875d06c519e14c957d6fcfb73fb72b46cfac4548ba94b95979fe5feac07035e0fdd21af7e3b69228afb2d97f2a333a5d40a84399c6d4f5a7ebef9acd08d66c2781eb9085a42e38c434230816b90dd838a2f10e727ee5f58d7469b47fd5324ef53a88208c44943009ae7a2803d55760a6ad4bc6e961c8bcc7f7f5bd07da63709d85832e26772e01886b2d5b73ca488b8402c6a15d2aec605d154f9a41efa93601d26374d3fe8a5337e98bb7a1b5f0071d3c8bcb69cbd0b3683e7a494808c9bc4490"
+            },
+            Test {
+                input: "eed7422227613b6f53c9",
+                output_str: "0c5db5eb4c5c83fdcefe9ef623596f96d2078c6dcc5d9b5e4f1eb5abbea23ed4478895d9d9c8fde4733933986c6cb4d03aac65dc7bd628169785cfc5d9d4d33ecc7c6ac98312f020b117c831b2ace85e1adbe0a5349bbe9fecbc6e998c6da1e2f333c105362506766d105f707d905cb616d8bd4b23ed5072e3f4d42412e3ed6c894cd37d8f9a46be6ef9a53d60254f4e9627625a3671b234664740c24bda608a44edda0cc652b843df722ad38b9fd7f122c89d8df0a68e03fbc0320bba016a0f3c36fba6278f9c2af9bcfc9f312ce55f011255332505fcbaf0adc512864d633cc0fb4d81bae980e9522aebb2a07199b238592e4379537e045ccde8b0fc44b2781421dc657938851324f5fb6e1b7d9548a50cb6c02a71b16dace90b84ef033594b2f0a688f6f9719a1008c1451353f8895ae1b7b16b27ac94b67f390d9586b7ee31af7b6e7d110813a6a4e01d4c94f17a1edb0633a1c4f69de184bf4315dc98bd453fc22ea11f8ea5f5548c5dc09d3f186b40c4783aaa4bde1a8f2aeed007a0be440be16649111921f779c7e284b8326785d87c3df06a05b3373e88526d9e8afdafd8e673d1876711ff2f68abadb7cad4545f0dff64bba98c86d7422c4dfcfa8f2bf7d72ff0617bd076b4de0b457f5fa2b881fca5722864ebca11602923bd0d6b21a9d7101ed1f34ad480f8f73e2adf821b2b259d6dc535aa94d3cad7158df14e"
+            },
+            Test {
+                input: "eaeed5cdffd89dece455f1",
+                output_str: "055c0a829125f20a0dbaa6106de95579be4188363c7d7e3f3efc40aff360298897968b250b8410829cddce5edc80b764a5aff16fff1c3d29614c6bc4c80d095f0c73443e8fe596c86c83ac1d9ba69847f6e64ca643ef3d7010c5f9944a660b14559ff27d4a5aa9862cffb67b47810d04c736bf842450a7e5239c5d2c61087888eb892b9ba495ef7031ffe2a56bc4e8fe4ca92d908666091d40f8dbadb0186db30af31a4bcd3faf962b56271a4c5c4a02c75f11d13f3dedb0f57ee554b9aa47b19109d3cc2ac58d9c55653b42bf5cc3c8143481146bb54b6284077e94a6b2daadccdb3e85fdebd9003c12fc62dfd07dcd9ce747893dc611eb71580f2affc624958e1c78c1554706a1582359f6962ed70fcf82fccddf9fbfaf0023fa1fe771d358a5d69e6f8917ec3425543557aba96d40303c5034fc7a873ca12d485998a856db5724009b884590c284b685de5677c76944d07db1ff855743587374d9f0ab70136afee1d1edf962d1ae9d9db036f28499ade8386e78d2d54f8f54a85ef0d771750a5d51511439ecfab2a486fa1cf77e8973e977bec186ed45f6c49845e9e19502ccb3cfbc4f2576d9d30a003f8c00dc209ee68f147cf17beb5e5e410388a0cec4643a3ba24b6532cd73db049b74e4ec5db415586095378297a60c2efb70674c473488385b47ea9e9d39952ae9a515e139b20d76a30e65f09b7d701b3172899643"
+            },
+            Test {
+                input: "5be43c90f22902e4fe8ed2d3",
+                output_str: "9f8f1774fbea8ec70d0661f8dcca2953ebd20fd73bfd74e6bf037b4fbfef17177f1a02e919fc2b40bedcf640be5f191d6572bc57c0f5ea29cdd413e8a97bc24bd490b221fa452594f78136c68b21984daea6b61899c386963ea6f078a9a903f05506d0c5592e341a798dc46c0198c039fa2913b7f7560ca6a703a6a86b18cd67adb53a13295ade0ba89522cf98263094b362c0635890cf4fd14d0ce5deae75049c5af37edba5c0803b26ebe951996018d66390fbd37ff9f24fc5a7435513d3173e26e1850ef3ae729eff8c38aa18a41b97e11a7ac452445d7ec617b8e0894153b067eb380d83209d05bc1b18b41272ecbef29472ec90686256f0cbbf9f5089a78d853b50772e494bf27fc0dbd3492fb16b8aad6d7ae027d41aeb633cfa3ca931cdacd968c1f24684267abf45534f89a362c1195f8cb31f1026d3d554af70deca0c5fd3973f55f20218056fe70b74a3311ac394efe4fc0130b5bb092b33ba3b91e2288815bac931c5625297c2f3180dae4b824409b435842aa12f7f01a185f699fdb2c6a9d42cb475b0493eb6759fd5809781560626fef4a4522ee06a2d3fee7ca2203eb84b717a1a825a2965d2c1c1cc0402658ec5d2448961f521ac318fa4a672f0f8051ae59c05394f84d25a1f9e27b21550a71ec285c8b2f86bbd8fc0da09614bbb635f905aae3d401e7969ddc9fe0837959a6749aa76fcd3a70920766662"
+            },
+            Test {
+                input: "a746273228122f381c3b46e4f1",
+                output_str: "e73d11ef660c0f9b35ce16c12c58051953c229ac29229fd38e00abea6fc7917427d30952dc52ff435a928f34bf14ea4edf960c78a5008f4678727bdb4c591d47c0d3a1abc314cc475e47cf68b243a0f193b5a0fe06613c2715829e672eae605905e6f52624f971731aed8d1cc022cf166c7391e249626ffc578f2cc48f89784d7f38dd14012151834ddfdaa245922a27fdda1465a8056c511a72a784095496fa0258007394c193ed705588607df19a6452f4e5c890fe648339a597418ba2e7e706c36d3dc493a3a6842f39409ce186222afb81eb044081c6145ccf8b0e852dc602a2b7031355911a7c1b16ed74e8bd6c4ec8ac56511768c008ba25343fe5cc7ac262c4662ac803ec1082a52a0530f0c8431f68ef9f7c4c7dfc9c05228e3638b7a26dcd9fd28331f7b04bef3956d6c49fc946dc97e935a76b3b2b4decda6113a9dcab916538520b28defb05db55f2d168fd6faf678c6ed335a33c5da6b575fccfb64ff2efbc5bcf2500f006e2f3dfb4c60a2babec8240143c779a3d9753f107bcf9981206922757e04fc93083ed10a77d5c603efff8592ac3902e2d07b72a5c75c71b631dfdbf3997744fd63250d2ebbec2dd3bb10e05fbb3a993831d62a6c03f403e30ea3b80f2c8a3b80473c2d2f2c51b8b5563e46a0a57a02c4e73da0491312865e15c4251d3db6516a51dcfefb1167cef7021e570fdcbf862bb5b81b461e2"
+            },
+            Test {
+                input: "3c5871cd619c69a63b540eb5a625",
+                output_str: "b28d5ef1e7cb85b4406fd3349ec1d5f3727a9fc9c7132ef6593779b0d3677512d5f10a6022df96aeffb4252159cce5562008e3e6bf02dc91a1da479b5b091c88b65c80f4e8d83279dfeccae72da723842edcb2ba02c4e3e9325804a04366e7fadcee8bb2d678e31928d59f2f0a546c742d8120694f5f02810d5bcdc320855164f60226865bdcec1437f262d6d222d1cba8577910847b75d5c4549bdddca32c3768f1b789cef62f56993cb72338274e5740062be3ec7afff53215e894600b35ddeeb1aa1e9962b22329fc41a5696580dcce450de6c11f92332a3fd959ca5b367b9ec156fad0318191314e98c1e2f82fcebafcb6523693a0c633b82251aa5ab4801b1afb004fb28de7b790e65f50e0cc85181fd914c76d915c1e220a53070d73bdc1c1bf2d0d9a3ea45697c3538afab5f577e09483195ec8b7737236491143d7ab0f81228031cdca4ebb2442ad5af92caaec92cc1f72e32e573d57bb48eb58453b0e0d680b7a3d46b4a5716b7756f8f73bc876de181c443c082022c7a3322059f83aa16fcdff5e078af2f85562f0d60632f4a76b29f27bd91301b276cc414af7c7b0a20fe0d0540dbc2b7a4f6918b37bac345411247f2f7ed5aedd12e72ade756da4962c2e19b998ae1a29e0daf6379a45adfef26aecc80d9ed1714582f7d40de0c3bfadf4a35da62ed4357b88c45227810d63f33be90529f426b6af513c1b43ba"
+            },
+            Test {
+                input: "fa22874bcc068879e8ef11a69f0722",
+                output_str: "d7da38e9032ffcadf7cb93c9969171a0493525f8eee3073dcc9afc83c704843a8173ef5374c4d564bdf246d41af6edd0872e5ee43f5d2c5c85134166f9b2ab9203cfca96a405f934f3b834299c954a3d30a2cc6737935db8c094636d659d8a3192ac8925809567719faf13ad40ccbe7fb1099bf4fcf415817b32ce923b1ad764b88e6fa24a9f0876c84d8b6fbb0346a87248a99e15c528d8efb167f6f1f00099d67f5b879fe8b7943726f648158c0356985cc48d92424a44b906b14eb8217b5c75d88e50311007c1ce7badbd9a48eccd4f8936b81d0c2a76918a06e3d2b2936c5a157d9375058162259d7d0ad25dba2490ae1babf69176b394fe2f00dc000eda5a0da049153c077d51a89100dd5b8ef4ec3868f5c9d8e4c1875f292c4fd22c51ecffe30aa40eb4ff50fa00a61f6116a337bed4d13b52e12f06bb4f8a88060b77b9f1300b5d895f7314ae728421ca951fe8da4be55723ae5533e59e06e0bc8d828603cedddfdfb9d82506141e1d90ffcd65403a94586c9259a6cb18550bd22b241112dd9d866f12adf2b009740ad71630c35b16e062460c708831df28918a5dae14bab1ca781effafbd267081a7fcdb418417717756f34bd98a799b02ff2e275193b0c1b721c2696ad732ac77af212da45b22f27d54d1559a1cd7b39a49a6286d305dd4a257452e930d5f2c3cf16c6674adf81be1d8231db6c1b8a9ccafa6e98b"
+            },
+            Test {
+                input: "52a608ab21ccdd8a4457a57ede782176",
+                output_str: "3a0faca70c9d2b81d1064d429ea3b05ad27366f64985379ddd75bc73d6a8381045c2ae2e9c723462ee09efbb1c2a8ed7a0729d0d9b20f03bbcf55a86859ecbe80c8cab60bab4c5d063dea224e825e38642124ea705327e075b61d08e0b49dc184c5194292bb4a797cd24d924cc64816bf911fbf4985130a59d68ff0673cc8c4a390ad593bebf16419ff464ecb3fc78c160b6db9f755a5faa7a9365b58ce7f90465af960c48b771699e0eb227f5370387e6248e17ee192007128ee7ad3d94bb9a2193bbd4618afb3a399cb2016ecd5f9e41af10701ff1915a6e091f44f193b0f729cc4af5fecf683b1c7dd2644d7458c45ffd635eeb85c79e241c1f4869cda9e77e80f7b878c24e9af77d22d8c7c0c406c8aaf50f57bab68fc6c3a20274b6bc353e6d60da40e8369139b4508dae96dba12dca9d80a19041a3798b252fd24bf2be64035cda6d95d6e570ea868eb8808193b3792897a2147396a47d27c81d40ff4bf9212ab239d7a789d8cdd545a98b447f6abbff4bf6fe631cf2483881e933c1e62a21bec503a6ea60f3b179f9ca6852daaba4ced7ade5e35e960463fa4c3a32f4c580f03cd2e45f10e32507fb2880827f56bfc5030a4ca94635edb134580715a23c87d755fd91b1566d1a471f310edb2c12aa11f2d280683f43155d67e2ec04ec2cb2cee53a4d00f77aa73dcd6cad61d1ab7c30a627cc75f83d48bdf9a76ab456"
+            },
+            Test {
+                input: "82e192e4043ddcd12ecf52969d0f807eed",
+                output_str: "3d62e50de92bf40637d481cedbd22f2dbabaeec0e94d1f99f3ef2e68b1f55d97ada13d2372104d63946e3eb7c50d7e58f5aa0d5730e4366bbcb6cd332aef45da6c4e5efffda948e4e7e6fb9c49b46ac954cbd53a925c8ebf73bc4fd53ecf34f0d67026136e8cff3c8b8661c9d5d19420509b47a19d4c848c83b791d1f843f8df7f69f736a414bb9075b4bb6070fa094a0095f101fe569e45e4e7fdd2b3622b5b912c21be28208ce90c7c342e6de485d7344dcf3e89d9c71f320001c52054ead0ec37b4cb356ccf80088dfd2eb63823210ca3767abb13623c9baea9be5ecb8dbb8d3dc97c88f6ba9c4a9c443a00e9a476fdad93ada9f64d12803dc7fe1c7126d23430cf680f94f0b218a06d5fb4f7698dcb5c896070a03d5daead54e3624ea55e966ea64d0714aaf9e17fef5da0998f6a301b20e988579fd98831649b5f71b67ce86f65003ef5f160b18ca218d446c6a18f341282cc89e585894a2cdb24e107bcebe66d3265895a622e51b617a57020b29e236df78271b1b87c5ffeeefbdf3f36eb3152687209929c800b9cb4a29cfe7aff4302c990e60cf61acdbabc3cd7f98bfaa55bd61c7d97b3b0a935e254d1d46801fb6a02567de9f75343b612f95dc555340bee70e61ba8b3e1d7478d77d52c5f395301178d42fc3dddd1322cd31ecb8e236f1748260f45af38a57aa8dd1796bdbc99ac14d1801be95a08c1c6c61b70ae"
+            },
+            Test {
+                input: "75683dcb556140c522543bb6e9098b21a21e",
+                output_str: "d062c8f1218f1dc5f3ca5c2ff3f33847f3f74c6a40a3c2c6c15e316b6c9fb36a7c1da9c25833d25c8dc7fcf4f852e3955b4c9246f4ccc3fb9bec64990e5d84730d56e5e4839ea23b258be3660014c49645a268eb03bfd932d879b2260bf4c6cc4ee97c8bdc9c02e609372d1fc24029193475992a27c52c20f1f821f285bfd1f4c6ed944ee89a96860364e44971e0b6aaecd446d868c9f7175c7c23e980adafa860e690eba14b71f7eef16da6017ba3fafce89628f64662af12bea0dc93222fefa733434a4778f0f2f5c0da2439c5c577345b59771a4991a56ebcac98961e7ef8ae3f1f8062c1268de1e6ca5291d4d7f1c1c4652a49aea180a5685f9e6c8ba01f8e3be7c1e5d40a9a0cb8661fc77f624f373c90da1876218a78be6507c2e999a25fe87e5f334ed83689936ad06a7f031590ad13105dcdfde7554d42f85bba80a03d3c1459a25f07e93b77293b48e8d831ec371e268e361454ca01539357d4c10255e3db0576ca7f9e6f4ae766822274a6669ab218474f9d0cb5b96fd0a55d4f454c6ee31e3a040568cf77f97d5b8c4fa783aa5625bd8ea951deb4bef186f37663ae83b2cd27276a390d730efbdbb798049b151e4962b5b17c4739f9127b87cd5acb00c4cf04295acbbf53324c3c539bded5e64fb4a3bc08076f52eb0a4bab60138e50dcfbe48765047ff4468404820088485974f4c4fd8546538698ea3904795d"
+            },
+            Test {
+                input: "06e4efe45035e61faaf4287b4d8d1f12ca97e5",
+                output_str: "abc182a9d28b3e043f887c072acea1e0e6c26a90bf6fe9e1bf925d20100c3f8e46dd5634ce077f6768450626105210bbd36789feb64e9e0a0eb5007eae54d2431156a6baa49d85b31a716b69336dbcad7bd43f0c9afd4d62bbe69d5ea276f01b1b39c637ba13f9d5cfd637fefa3d80706896f47a58d602166645aa5cafbf5c280eaf765a47f4981a9673edb27089f31314a6367bfb333e4a937ccc3e704218696f998a3269518965bea095a934c171f78979d6ced938f8fb3d6cc8f61edeabfdea038dbf7159917e3f941c2d17e351390ab77678477b11d2dfe2351180e305025403fb826255def38aaf0ed06bc2af707337dcdc1e5a08fe03e9cd043d5a152ef37fd4893266abc1875dd28e2c7160700899d5f39df5deac2e91131360922f2abb6bfc49a8fc0b638cd13b6037f99bd0d72a56346804e146e8b2889ad843813dacb56fd8d9909a989c82064e4838d4f01c19a8e8d1b189eb060f642ca5cef14a2f361c1f34d968fdcf37d7837e3aa9b866935095966109c763c8dd1cc70df91fbe7b5ac7fc6433f5db4b780bc9be4ef862b596e08ad32c201a07f04e267ee2705245c48918b71c84d78ba48af70a4776523d37a8b90d53ad45465daba2b48ce0c09978fab5f4a0cfa6174d55612b7102cedb7a591eb6a778bd41cf3c289d06e86b4d329f71dc6c3be75d7e661e7e9b5f4cd92225fb5991f73237e2520b9aa604"
+            },
+            Test {
+                input: "e26193989d06568fe688e75540aea06747d9f851",
+                output_str: "bfcbfb531c1689126c2323f9294c1bea280013a2315a596ada34f022bb6d3d8a699ba8e2c54ae3bb7b32c422c727b41678f781d652dcbf1a40b8627b56e004aa5f1753b1152920121b1a2d8cd5e9ca02929be7f2eb433baae2fa41830f146c72a12aaa97e8f8b863749b3026e99e0bb7e0a937f003604b470c913546e73413a86ee2e9892fca2a7839b20309afc1fc9a0ef14478ce0ccb5ccbe37469b7dac3a7b74b253ccf2ed085f9a0bef3759a4002e2e67f81d953e9bd53a4d39a267cc0d262e5d80f50f8b87d816c91a2c64d798784a5677744ee02b5da2cf07d79282bf8c791433e0b3e296c38ad9e0162baedc89f1b368537103ef797ae54e68aabd23de81b760689839341155930796ad7a49702113f737d0812e20b850c38c3767421177b39fb60f3fcd0b81a50a8624e57b676203be7c8bdc66be9abb5a1ab175705dbf65bdf5d119f331205aa74e6e04c766e408d0b2651511cdc513c75c6e326220dd3da4a12c82317455d450f44f5f1e55bb7a91bac1c34c1e405baf53fc8bcbff7ea119ca53f6ddfcb5e4f2892b837846ceafd8abf5bbacf09a3127685b8b40a2452e52ea6c006f22ec7fd9df925b939570096e5e0ae74d67e46e5402dc94d4a47e460d718c98a4426f3e68deae1a4e509707a20b136fccf3c26c8956c14312bd855f0b3fc6a97cf1c7e9ade4a4907a7ccfe6eb5830d17451378acfee3884e8a"
+            },
+            Test {
+                input: "d8dc8fdefbdce9d44e4cbafe78447bae3b5436102a",
+                output_str: "e3a05f6157ba90878e8c394e09753a69d271c77b233799e0d68a32209f0cdfcd5e3f41dc9109f836a4c45043e7eabf41946fd05922723b0e6526e5b99b10e89b3c4ca6ce5a2c6c431fb14e6cbc7986c4ca691037b1f306f8ecaa146d3e0b5736a53a2be74e1704e65864c3acf042459bbfbb440ec73ec884d89aee7525cecba651429f2cd092e4b3bf24aa144873eb870749564a52ae62fc86674b0d9fcee67de8910dfd812ca75a47f8fd0b2393e616fe8250899c36c27dbc30716c9f5fa181ac6a6065b73e3ddb94447e22eb858e8d1e12c24b80d99d4e6291a0d588508319c5b54e616270fcc504d5925b0ecb12f211c3b63286383498fa1a7b4b1bd399934dc6df4b7a6be0f42934052aae7624ea4b6837e07eba9ef2d066a911cf71776a2eea41e04122e5afa6f91865dac64686212a93cce21305d925606faafabf7c6d27a8a91c5bd24730e2ef0f11a9467f7661736123e7b8ec29b4acabf9aed239ebf3c79f4c37f54db912916eba3a91ad6362dc616d7339ab457629bdd0fb97b8ab605b9fefb65e2e70fee3f2a29a3d6d487682bee87d5c615870cb615adf197aec1e5ee35c242149db2d5dcdd598db5981a5ec57d31c9644cfbddc03fd2f5f8881d2244a094ff4140d252e2505089337b925d84e3ef632c96888e0fe5c23b1d67a64ff3269a430db1927cece798ed159daaa3b69819fed596eaba5b6bf4fe3e688"
+            },
+            Test {
+                input: "57085fd7e14216ab102d8317b0cb338a786d5fc32d8f",
+                output_str: "2d81f6711464ad6b3de6f985e02d52c30ddb350bcad92fc15df3a67290e4d74e2eac52ebf9479dc223770d6481b1a640784b6e4a31ea840692e625bb2d400a5c0c7966e5c4ae2a4cd0a3204d7db266745d64122f83141fddc676b57713e45ca04139d49bf42edcdf443b5600668c1534953aa95fcf4bf9a8ee8b52680c9463e5cb5aaf09f18eeb2885a061daee4c3ee5dd6e824bdef31a93e092236f91b8e2ade094e718f8e203e43ef00a843a2548457d0ef2315ff91e5221011b874cd798254fb4a2e4c65405644e0deac6529ef59ee52f2496d9b19485e8128a76548c212d667637213b637919186afaf827a1a0cb5f584f475723d7d2eef4162e05f9acd221c3416e7e88d22d4c471a05eb0dc70822e912942261e9369c0d35a672acc5a48c86d6835ed99bc201a02ce40e86e0c096b2c34e5bca207e5c5c90cf86bb3ccd7fb89613e53ec90245f9d8315d1102462ce10aaee4608101aedb37857db22accd5b024ed323151d75223e6cb0ef402f12ee2905869396ef6ad09f6fcfc57310bbe46ca7817021df43fbdccd9d62158afa8f20300f8fa17b202733438c1f6b0f1d1fb1fc8ad8414e864debbebb5f96367135224581b9b8e54e64937f708a2cf07573a42c45444c37ddb1287d4d27cd3a9dbe476eab7c39a37722bc4a1345a34c168dc93d48bf719e79f25ff112fd687b86c20c98533ca4b0fbc1f3d4a6ca469e4"
+            },
+            Test {
+                input: "a05404df5dbb57697e2c16fa29defac8ab3560d6126fa0",
+                output_str: "cfdda60353118cb298a271246886e4c7f976465c1b65fb51e87f7e5a9be050b38ba3eb23f52116f0a13ad802e12af81a0626a51c17e9edef5cfd1937bd774b4e63b19bf1bc61a4ed23a2acf45869e4efe9cfcc8c89af6861e4122515e2b5ea8dbf024f36efedb7e6d6dda829a5e45e21466f4bfc55596748a9fe0a61b3b9b9ab2906008dc3b8bfb71761eeacce68fed2f0f0b380661831e4754175ae79e9c093db7f2219c39cc36ec72ea39c65128d835127c3808de4f3113e9ce42bf1f86250919c8907e21b0905d960480d9786ed5be6fea4ca1017708e1a153846ae80f8c81df6118de9c25de8b72473e5a2f40980417259ca2d3fac3afcc42e1d5ddef03673cc2d9a7e6170357085a135b31b6e8334d331e222055fe01ac3dda56472572cfcd908797bbd7b8da672e2f9a10497e423ac9e84c17c81f81a944952c7511fc34c5626471b85d80cbc618a68dcc343575219999f28d01f732e76dcd6b056f60d0a9ceb822c1bb772f55bc85fd122a0972b0c0fe8b88d731887656036a4a4278d0f46b27b93530d3dda7a689dbbb73d9de39a6f96082c8d9b9aec1fcef64c7434c38b132a66b3e2dd51367eb83fec5e6af8b18a151058d092ed381ab4a86cb542f54ebf5b0824df726b91de3bd088cf8d1e55eb1f2c834ab5ab9e25bdd0a4445c692d568b6458bc29cedb6cb5c5e7c29f16e1b95f22c2752fe1175ffd41f112ee"
+            },
+            Test {
+                input: "aecbb02759f7433d6fcb06963c74061cd83b5b3ffa6f13c6",
+                output_str: "8fdb0bfc41e23944858401d837455d17966db41f4b9d2bab52e208b2e32b22e1fbf3cd83f13b6b99f14bcde767b286f7d16331fd56db42a4acd9c370bafa8c99f91a5ceb24d52b52cc657686163057471f2d8c982af779b05ba1e49114bd55bd59e1dfdc69f49ea96f771fb4f6b67d1606e6d652368a31cc3f7418427a8df6fff8e0b5e43efb6d9795d766017284879aa199b6726c84623ed69288633a34d3742d20f1249e1c70370bb19320627598d208a7531ea233e772cf7f3994c06ffda7e63b85bef873cb89a83499174b461b36a375fae6d5779e23eed9d6624de2ef309721c428d8a64a2fa7abde1bb56f66f04225e30501aad9b9d9078ccefc8f721252a232b82d984dc5d1a03e9f94630b4023ccc4ba6a47ffbbcabedd754bb403c25ebd27d445743e17def49eb16a75b25921e49373a4a669a3b3c6bf5acf72faad2d9e0aec3723fc07e541b72ea98dc3e7903cc89df00f6b20f147302d6af18fc94fba446d37f5ea3a49a9b2942dc4926e06f6d385409753e3ed1c9e1672b783e491635b2701fceb0f133c1cdf9364b7bd55cf1ca89de5acd13fd7b94b3ee849e789454ec39474636522fe41ea3504ce134610d675d5cf299f3e94686f1ad9be58af227928b9033823ca7195e6856f72008b31f4ad7095f98b4a5256d2a676817e02e7839b2b875b59ad020b97bcaefd515b061f49526821043b3b1a1f29b61f5b"
+            },
+            Test {
+                input: "aafdc9243d3d4a096558a360cc27c8d862f0be73db5e88aa55",
+                output_str: "64c80b3cdeba491185a9ed7e0b5efc031e36d4f22f9b99a30237c5459c7da37b16296a7d2e221b314b47f524a01d94845f7b1f38d7d52da83860e576e8910365a217ebba342c7e26a350ffcda54fad792756eb1d87096f0625d6b237e77060e350b9cb9179db967bfd8c63e15aaa24336b8314b692f027c99edbb757e572b0da00b45d90200bd778b396d18375d77e0cf32e7eac5003794a010b3a1dcc5968f59a0cedd4b2ebf4f0f151e5d8f88c297506295080c91ca11da2cf32447245e0667d1d4fb619c514014adfb7733d972198ba4846d57ee8d9ff73d543cb32cb6822996d04b08af13df3a696df38c29b677ba6fa481a5a22d2611b8d721ef11c4361a3205f75c90b7b439b47893cd5c38462646355800ee91dd9366d8ca3c2ef754b8ddb4fa83397faaee9bb24ee4fda89532cd7e1f05cc4d52754ecb59dc6bca363d9e804b32c47664be92a23023bdebabc70dc45f15a708d5a0ca7e6f461c825d58784748284722df182296103d27a2868c06defce8f0669a173a9ea7c9d7ba1ad721a48a7076ca7e005d0be0c6f5df889747a581b54674ddd18a3002662a8d1f1373ccf9c0760b008a805e737660ce28be2db4fdfca40bfde0357615b8b09b264b9a9c3edfb70f967bb520b09a76654eca9fdf6af19b298dc3348e7a5771f3c3e2abee576819a1c59881e6b8fb1db1b114d746e90ce6f9f6c09acb5c46b03653e"
+            },
+            Test {
+                input: "7bc84867f6f9e9fdc3e1046cae3a52c77ed485860ee260e30b15",
+                output_str: "50102cb39ffbd98f3499ff53914870cbe4440ca8b6d61b79b7e6481b943d8e532947d06a5e04a6ec8e595958245088fa807600b1300ed4de47a2e800d812bada538e351dac64dd3043e7f655b411241c9031ed2765264e372c6f59435988963ef83098452029761d43e4d329cbbd04825719adab1920dbed999c1c82bc9a362ab6c0de15a65ea6e7eaf9b75fa15543910e7cfc214f25cafbc771d9e641fa65a6f52fa97ce428910972efce8c23ffb56aa5ecca3efe08e12125e3c88c652c89765ab1b72c9d16ae3cf4c8a413aca5675c18439f3909bc8da92ed71c7219a89dcdbb3e07a3a8d4145b2d65e9525d3e583c70589d79519793f463de6799d682e24e83e91a96e866bbf0bd72c041dfd44ff345fa83c24c13ae0689de442dd01c85179e69fd9e07fe2e2af1f5d1b5365fe16c3d9da5f1d83a6bd71923252371d230d20de8a76a810ef29469a370cc552bc0fe8329cdf85905134ba4f7c4f77fc83bef84f7560adcbbf8d384267ae24efcbd78b8dedc130ba739c5ce96d8cd05299c50037b94f9b48012bf346e079c4599c2dfbbb1f3980a1800bd593acdf5c7e355d3cc44ca412a3565fbd8b2a9e8a9e44667979c9b261aad8ec2b201259a2d7e4d5da6d5de05ae61760ee8dea70ce5f380bf3f1620b3c67d8ec5dcd47eb14c078eff113a952b7c77b8e832dfcbb5e7492f090d8d4a9893d222ab77bee17501b8cbbe"
+            },
+            Test {
+                input: "fac523575a99ec48279a7a459e98ff901918a475034327efb55843",
+                output_str: "ea2a6c14acaa13b8ce15f4363206525a44ae834d82b000efe0438a4321ec1eb6de31390bb495ea7f067d4a3fd9be173981076bbe4928f2e9173f4a3158dc4de9f940bd4c8e76c2f886c5d4c07a28e6ca1b35a4c31c153323508db12d63908ed758195cba55b1b8c9687d219e4b053849d5134d3bdd8d8b0adb2c02793677853d6fb496813d72dd415f9ee59b6c30aebe1be2cc5fc3d9b4d4456ac65be1970e5853f87c57bec289e995faa9fff16aab0eca5eee8319897d24e6d68f29b9a8937a0d98717ad61370e25c0f0b68974d41abf5dbc3c05a26c4b5bd4c60f5d2f2f0126675b785cc2a0d0bd1b2efc2bfd14790aeb55db281535950891bb90a6a02279852bc07d6f03f7c42b4e2b4da0008e6ccc0a8fdde198159f6a2bcd516ea80d48f8ee63580abf97980530ab589fc2158705eb0b5015d6b92d41d4d985661bed07cd1e43595c1a9c902f08976f22e01825cd2c9970a2d09fa0ac68c3428fe2b4957e528deab2d1324db176761ed9a3cefd129edaa882c848e994b45d7df77a489569b1720c183902a5a7e8116223dc3cd0fe84826a28d2266834d0b09aff134611203d8704feb7f1be1736ec9868f4f638598bd530f6d0daa795ea85c2954dc188a27a14aacbe2ea7cddf85b3dc9f2df61175530127af3594ea39186f9a18348f9d60dd2b32db207e5398f59dba345511d9798613d66318c7f3504a431a0cb8e9d9"
+            },
+            Test {
+                input: "0f8b2d8fcfd9d68cffc17ccfb117709b53d26462a3f346fb7c79b85e",
+                output_str: "3325661a828829064e99adef00e99e8b9b08a53a4c6b008fae8db1a833cf26d83f3f8c613defa9885593996adae75995dd196893de7a89718296f12611b3315e22218b8e26e8124ba7604b4cfe5f427dafa90e78d0b5e14351d52f9b8eee659b54e07f1a8aa08281b2d8672cd405359a681c74e84b1f6f6553ed9b5184d10eb608b37807e5a824c3f0e1126824acf192c9767919f1070e77e2f81a1b5e5ddafdce09de562caa1470bc1023e0edb8901eb9ccfb813366ef60decf20d0beb552e7883ea4063383b123d94c35f5d00d57827d60dfb3550485b75d2235400a696684289962c2f71227c847548961b4f3631c656acca90f9ab21547a99197c32fbdd410fb7def62d1b293bb0fa36921bee609a6d7c2c9d6abb287eb2920003c1e965bdde75a90a41518855039e3edfef1a3dddaa192fc6198aba7c0631949f140291fcdfb8d387ad4c19f71b6ec4a6c3f5b22a0f8bbc0f852e03953057ceac0183569815625f566f050ac6b14bd87d3056a8fa5d99e621632aaabe723189b0e87dcd3cc3d29a4e3acf2ea915a8a7e0ed73af0bb905a4e8b0599d20d699d2c971bbe338c964bb735f72540d8dfdc069f950aa13c814f46866a32c3efd0ec5d28482298bee0cfed7b8725e64c75ed0a35d8db157278d169849b56aff015603e1006c168276d96aaa91ebcfc6c6890d5382cdf1c6c5a1bb6a3c090f37aca605e9e7459ee"
+            },
+            Test {
+                input: "a963c3e895ff5a0be4824400518d81412f875fa50521e26e85eac90c04",
+                output_str: "1acb385112f369e6d00420faf1291b1baeb428c09017b647d7343dd2ff50870cbd47601efe679ac0724dc63cbf543c87df5060cb0f11c786e97844a02bdab528d3fa5890dbcadd9eddf2de00a639b0ffb8fb2cde673f66c54bd554e737b5f370f53823b135b3257af3394408a853666bb00139f147c6ec198a5829e8a5f85279b306a428dc2579e66e1e18eb3c4971644dbedf4f99bddc9e4096d0bc915ad1f72d522395c6306d047c399bb1c4877bd8278fd29926c3b74aac5414e9e0936e01daee1061c5cd243c380ad802459972d3c2df479719a554cd9318a8faa3016aa6ee057a4e57cccb698a4b0ec411f31d11f0642053880662eb3e098f88f74c65225669a4cc8f3a04e23f6e5e40f9a3c7fc2b4993782d58b27f80040dd94475a85a14bc792c6b86525d359cab32744e2bdb4890a392ee847c065364bfa18c85d7e328e5acd9f04e6a6542c8b734a3e3795898d7e48ffa8686cc12497883092395239a55e56ac18c4d63a9281fb8aeca2c099bdccc65cd239cbe597cf5d577585fdde3f4b573a666c2d1e3c611df94c9c519dce3110c33ea697fc1955127c91bdd420de5eb667933a49e15959eb3049c7d265cb638bdfe3d6425e20dce650892e0fc346922a4277c1cb1ade59886f8006f0d0074937e852a0542b5a111cc4acd65f3b2580670dfd41c0c9ee3ca5fccdd7743d131eefba0543646b31a9eaac4cd30de"
+            },
+            Test {
+                input: "03a18688b10cc0edf83adf0a84808a9718383c4070c6c4f295098699ac2c",
+                output_str: "3c7002a2eced36b19a3d71464f86a526d0f2a92ca76fe392810616e75a25c223f06bb1ec3bb5ba0d00a51958789de67724e1d57c4806f6752e610327b4c84e9c5e815f8765e6b452376cb1ea5e3151c21e789fcba16ed05306c53f2f089b21f2b5590cd4b48647caad444450a1a60e1cd0bd87465c2a3c2d25b15146767b6dcea1a8aeb8b717410eebab139b041fbba1f654a7136b7071573316b3a7e5bcf8929cc1465ffde55df7449c7068eb1d74c0b12418b50046fa2197a47f4cd15e7d3702e260c188cfdfbd55cf4332be6cbb157fa8e62d003d902433719b516c59d31f8f935ced0f010ee66e8e48448fb9bf3a855bed9cc604df713a689009223f858de44137cfdaf2b194131b84559a98afd4f86ab13d7a1df01e414a10768f6d48e426ea64a0602bdaca1ca56c903940a35f28842922c114f25f7000d720edd40aae30f300abce4fa5a3b6088b27377d7767762b220da383308d00a43e3b9eaa1899c3d4e261eb132c41029ac024d781001b56a1127226c3517a015782097d754233d83d3237a04754f3f22547c4321fc175f9e83e679b0ec7564d942d77f64ea480780242cca0ba64a8c41c7e94e575cd9e60c229e4765c8bc993048a81eb4d9a7f1f1fe449abcc1cc5b5cf500d922a3dd26d6abc62085249af7a60271177b19f2d150495ff3b4e8aa0414c58fc1a1979eb9938fcfc6ab3af97b9a7c8c94d12c821"
+            },
+            Test {
+                input: "84fb51b517df6c5accb5d022f8f28da09b10232d42320ffc32dbecc3835b29",
+                output_str: "e22ac7fe9db19147b2dbd586d6c5837a5dd3df2346ea61dac753b0371274dc110612ae3db350eafeeb89bb1179eb9d84a0590b243d0dd9baa00796030d2782f0163e85328a0aa06974a7321e66649281db8c506400310ab3e21243f4c2cc5cd8b36ac7c35c235305e6b1585b33784897d82a2d31f664d963ada323a9c922a61d9aa5bef0b90c6b7183f1fd0ed4128b2fe0e12eb6b461176c52aebfd608c00c7d79799071ab30da33ca9aa26932aeee0d585905bbc853e80aa746706faf7be50c90c1fbc18e290505277e9bb9bfa9c767e952a68c4f93a044f62e066e61a0ad301bbfb921c818690bf6d116c6cbe7df174a7e57e22294303820494757b3254ac40404a7f4a6d1f9624e5cf3a770392b2df9fd1ffef01ac9afdc74442c0eb6f11e1eabc59270b4da6f2d6356e79607d6462c08a6f29154bcadf4ffd6e20ecb700e188e523b3930e35c8990afad2141ff71912adb07dc00d5bb78d7fc5590467815ba9f46ce4f5cad34910a574687d8f7fac2f60b34d4c3ba6d25d3e5118b851bcb73c1b1004a623f8ddc8a0d07ad21b45f543ca8e705b3864d1c4fe024a19ed5fb0542dba0c39fe0a82d83266d9c124e61ddb107d8e0ab57c970cfe5879daaa7170022408f7a9a228196c5c7ac614cb98cc276d1f5ecd79347a41d97360a19e65681a5b75e78c7f79addcd401da6de7ded3b1dff1f746806ae03f496ca701c8448"
+            },
+            Test {
+                input: "9f2fcc7c90de090d6b87cd7e9718c1ea6cb21118fc2d5de9f97e5db6ac1e9c10",
+                output_str: "fcdead82f39cdfcef99c1babb674a9a8e24ac594646c31d020a4cd2bc2554afd78c4e413f7804fa1708b9f4000fd860e3070f2e1ba9eee3805352aad655b4b0a728f2d5fcc43243825bc0dce33ca716626dc76e920d72575e26ddd7110d0f991a91200b513aee23ac9bc7043a152ace0cd0b49181d2bb6bd36e93c0b627aca9c6ab6c85ed70ce762429c8f262708103284c0a792138f10e8568efb2399b38a31055c1188ba59344e6a2b73d5c04aa524056649844d1dadcd07d35df5d851ebaffca5703b80153ea627b1badfb2885f70f786d34f5650fe73e3690a8a96610059253dd3abb5fa7c54cf6e77695d24a6594077ee4d3673f9fc56c62fc7f710cf872014c0a7de8b1ca6ae8cefaadeaf5f4d055ff765ad418713f2dd08eafb5e16eed9fe344ee8d4388fdc22351f63834017b539e3ff143f394b5b74d06f65e96a7a3d028fd14f6c7001eb7ad2dcfcf4b2447aa173a2ae8edb581b5bbd89e8a468fe0a38507530b9795da3bcec6ddebce9eb3132ef18c9c2a8b936a431c8b121fa996ff9ba5ce522986b678a5ec99a103a91cf33196e08c82dc65e68aed238a9316a73e71cf5a67ce440b93bdb845b3a60539eccdce41bc723ec9a14ee4e082f60c0be3d5e50dfc8be1e86a97ecee9d88e2bb2a3aff47fbd6d6675d81efe0708926b81ab314a524fc745090162d2ac723c4326e0f9e16fbdba2b1e9914bbeedff96b"
+            },
+            Test {
+                input: "de8f1b3faa4b7040ed4563c3b8e598253178e87e4d0df75e4ff2f2dedd5a0be046",
+                output_str: "f9a4d63d82c6efa5b1ff90b26510ecf06c53bb1c3b7427b64c41de1fa03bc0728085c972e94a7fbfe5f3150a7b9fd8477c6cc1c250dc6fe017b0d0668adca12e3c1c9bdc78247529dd1f69198bb0a371072f0225420afddfd64ac1f7a8f06fefde803579491d8bf61d6ca84e985b1ebc7f0b48822b8bda9cf9aaf75b7c33c5d360547a34c68114e8a894d658e4f27e3c137e1b2a203293c015975aeb49ab315d142024767836efe41ddcf42458c5b5238ade07302a0edc28a5e4f686d1f98372a179dcdd2eff78914aefa492c05aff03a5ca3e188f611ac24922cc28ac8010572f406c0ed1bba849664952ae23842454f60d7f4091d0a4bc2ca6c7b3e1c7dc72659df6a709587bdb30ffc3bfe6391ffe3d94084d93f2186024b9aa7eb52d5cbe760e5e3a49496a2239c9c71fd2c18c199441f7509108b8e32bce086a110507038069f99477dd9f75efdad8ed861c38c61e2888f7ba3e1ac237a2703bcd64f19befe921259f88d225b9b5461f070297a28908a35d78bd66165c8ca532ec58c64da1988e39d1237588661933320c80b30c183126a10222d6c2deba60a55eb6574af1050ab4a6253817ef90a1da8b42633b97f792950364d1e7c490a5a2bbb8c3412289329d2b0a644f8a447c5ce8a420c402429b94f4fe11bcc71fa2314d4692db47ec2eb58c32513b07b7cf7db276d1ab7190232e7025f805ca2ff9f27afec20e"
+            },
+            Test {
+                input: "62f154ec394d0bc757d045c798c8b87a00e0655d0481a7d2d9fb58d93aedc676b5a0",
+                output_str: "cb65eddd9ed9fbb19e03ddbee2d0eb5f0c2610f0ae9f89c50a463a303c3cebd64345f39f1ce7e04bd5aff16b15d5ded79e717ce07ecaee9b7bf1841b17a1266b5f92f2a92d6bf964e53c3727c50fd9418c1cdbd06f0f0510fef3abed7b4cc31534e885edd00fb1316617d6433b249956e1565be72e5483edc6e5e90b470cb2e089150d3b3b70fff3227131e0dfa12a2248c064dfc83702fc462fb2165cafdbef309edf1bb785addbe17c6e6de702ba4be1229a7ab7be122306e306e92d0de7020fc1cb568f5eab5f0a2140b010587debdd8404dda2c4d6e728a4f1a55182e018789cfe03600301641d5de2dc58fecada9a9e1425dabf1f00ea013c05ef3d64113ff351f10916438c6b92b6b6bc5fd3d6cab43669a1c60ecd39829c327899885edba19b8a9b4992805916c460e5b5f72f53242d206d2b3da3a976784fc40b6a4f0fcde7422453565398a040f9e5545c482efbf9d3110100dfb04dbfb24a94fcf3fa05406ee9b7e677ba0d3a52032aebc2cba54dddd8cc0900c90f48cb9ae107de01c3218f0ef5bd9db9d7df8e926e60a384dca5299610413316bccaf2821b926174efbb791d465f887ce3020b908b07e545a386283e17f980639e81e71b0203a3d22ef233b4b2e593fadb04503f0cfc5ead74075767228458b1ef4c5da77d126d6db7eaad6a2bf5fe9c18e562afe5671dccb60f8ddef168375be45ef2a391556f"
+            },
+            Test {
+                input: "b2dcfe9ff19e2b23ce7da2a4207d3e5ec7c6112a8a22aec9675a886378e14e5bfbad4e",
+                output_str: "7a3e2cf760d677ab42125bc78324a8e42866e2c148087f92ff27e149dcb2ecc3f3209d3000583d96c60accbb637714c4175b0db1f982a99a7d121774afa37adac741ad9cf72bfe7175f591e18256a95a0cbeea06b5cace02c7903b1448ded23f3a7ad61f9c5ce0f61235520706667e94062cba04f735cff813a5b7501975bb7de70747e619efad4d548cba8fa818a0f4b59f8974429075dc492e014436ccee77ff6947fe3702659a14baf89fdee45dedcfe4cfb1d45d59ee5d79dde87c187ad1e04f06217c41c35f1185e63b625e30e67c5377a11909612dac6539f72a6bf46efa1674d41f00fc2df3a603a480517894b88556971b793fe3d14e7699762641913ace9460a4791487937fc6c94b6a0a091c465a3ef24ec55acc8be486255848dc7bace4a3f860c7df0307b70fb33d8164fe3fea9acd2bf3484baceefbb4d24d77bde756cf7614bc2f4d037e16943e08437695dae204ca08972be843f59d608325c7d6d64b136148887b49fc71ade52b11e80576facba740d88993dc77df9b7adec54a6daf3149b21b9d0d910f2eef2c39ab3304f2e5656df646e551bad1e4b2baa3c7ba7857ca2387f516a0de8600f14b653055db1221a57ceae2e4ae4d3102b60bee67a5456e0e2c0e5a0a2ec249a3ad11b533005946bc6038a98d129fc696f48f05f0914913d45bd7626046addb5ae3bb4c4e1bef5332767b49d8b576953832"
+            },
+            Test {
+                input: "47f5697ac8c31409c0868827347a613a3562041c633cf1f1f86865a576e02835ed2c2492",
+                output_str: "0622ecabcdd9a8c2bc20fe0b9b39ce1a6a835b5181327794db2e1b40070fd9d89a498d242aaaa8fb5063d5e2af45a1cd04cb28b96edf844aa37c7cf6efe39363aae56e1e6c1e537cf8e58c20d5af57aa0687978e8ea46936defd6a6f3486abb9e1f04b6128710f75314df64706190f4aacca8fa9f4e1008385e641f40fabd228b9dd421e30184995720d49112fc429165aab6dadb0cfb6f986e11866d138dda8a5b4656b062d73cfcbc8b8873509fea2820e150672ae7c01eacf5d9575ec6b1dcff1f55e6c2dca4ece5fb4a6f1ec7bd089c24149f1136af9018920977519f390fb7929fe84228d5ecbf8fcd5291791cf7fb6ca7208350cfd5d7a761cb8b6524de5a85467dee4202232218ce6b39e5505ef02452b4fc0a87c32c9b9c9b8bf5fbd5755313f551891c5d11e26fd57b65a42def3beb07c88d117cd168335a7749b97b1fdb04c7ed3d2aa1a2db4e70226f3d8b87acc19a1f34f60bfc1cd0ea1864c5a991ca21c72c163d0b6ba5833d8efc7aaade5bc6d335e62852addab38831aa04dc4247dc7e1ca5e0b2da9ecc5358a889ead2f2cdfb538d900face60aa53228145644fc4aa2be363655ed6ccc47d23ccaa0eea0048887e2c670ab4ac85bc71d1caf7a1c02eb3c784fb189ae756ee9133115232a92105b033148c1c9806821beb545035a1359cb4290b736d3d14c5f990ad2e4fb02a1780e34db86fee3bd2a3a9fd"
+            },
+            Test {
+                input: "512a6d292e67ecb2fe486bfe92660953a75484ff4c4f2eca2b0af0edcdd4339c6b2ee4e542",
+                output_str: "0d126808ed2ac9458f8002cf172966c8daf02045518edbcf87fd315f31ea781c73579dd9be6a3000f7d6e5c400970d4b6731f90d75ca01e55ede430d8a459a98c71d9ce16bcfc334bfa1ce8e18a70a50e3b795b810fe3273b9eb7de8d9b7175f97c32fb057678d819b1134ac30797f6ff7b622ce48616436ff7c38453029dd7b35e648c14ac725eb49067de2f0dfced2cb89ac6988ca178e72d0d19ecc481748be17e8baaabdbadbb84d0b2f2a49c4e60c00018ecb61d2cd25d8841157d9b6ed74c70c7791f6f88ce61b5fe0f28ddd2b4eae5e2a71dff495907fd883ccd522ea1dd55291a5b274b4333eb62650d55b0ce61ec1761cb2d5ea39c712365309537918ebac6eb8a0be3d19cdd0f32fca2c32fda5deb68ea99ff5f7b66ec4fdbc2f8a829a4b3512a52044a7f7c567532376d971ae504601841c8091695533266d14a14ac46a7370372195cbb4bc212ef72a18f7962eee6738ef1a669b663b336cb324ed808c3affe2f39514becd5d654715c85f3e5cdbd9029c1f589cd0d563aa98c6fa99769815922ca7a30f13f55843dd952f5724ccdbb58a269da7d066a548540c23f4a740d82f90246d193c22a0cd0601c2030e08e5f0a9ab7b468de0530f50b156c38dbf08217b63b726b85227a5fad8bf9165e76b02cb00cf7ddfb03d9d38c882e81e657fe5596b66e777e672ff416a3155d4e2ebeeac5b49a8ae3851ab13ba"
+            },
+            Test {
+                input: "973cf2b4dcf0bfa872b41194cb05bb4e16760a1840d8343301802576197ec19e2a1493d8f4fb",
+                output_str: "863dd45342e1af41f682c138ee8daf96308b1973b3740cebe9c2999d4190b05c7630edc87f9942f31a089712bf2b705f1f3d835e25e51e8bc6d5ffd017a5fc2f30ecfa82c6b9033aa336acaec58fa5e0d4f4b40be4f60b0ab303ad007336b5d08989e635e92c7c0f22cbeb049bb4761e786fde0e7aa378f6c492b3357916de530e7fdfab45d2116b3137b0ba6bbc5a04313757b26cb3467031d82a98025e628f0a3bcdb234d4e7faaebd7f7f4e94a2c4ddbd947a3ad2e66f7d45e66c89aa037b956af67d7a2dd696d231d31159b5e217ef4a911a24b4c012ad67152c9a1fbf85bffdef6523629baf766e22f009b6371a4c9473a42ac84e2be89d2698e668373a01a2e8edf60f9c7d83ba415ebf8588c0812a4409a5ee205d794ec5e3b5a3688d8520c98d516c877f5448b6cdfc1a1df445008cee775160096237efc27fd32e1629835b6663601647aade495a117c025e03c80d8dc2f31bbb7cdd4d2c50c7987e8003ac04226e5e051e8d2930f93c143f2804dddb343591ce11fe55bed40a5deb0728eb575694d4f62b7e7901e3a005a306961051a0219fa49e263e85e87b2880ce9c9cad37f5dcf001df265fb448093cf08ee592c66d2bdd37907d6492b05ef24e96b08da4e55a289e6a2ccf65624257a754c133b54db543ffce3d11093576357c75d09e0e5d18d95d2fd5206a1f5750030fa789b83a81b6e81d98b1d360c179"
+            },
+            Test {
+                input: "80beebcd2e3f8a9451d4499961c9731ae667cdc24ea020ce3b9aa4bbc0a7f79e30a934467da4b0",
+                output_str: "015bb0de6a28737d365353e9f0052edb5272a67f83863341a7b798ca9197a051039987e22e6ff95f31ef2be455956f7c5704fa4108f600db247802712ed268f35b27ab89ad0116245783dc7be9b511ee4a0388a7ef9a234e1161f69910d3c0c76738db4be4480ea0e8bbabb081428410c34cb54968f7dbb8cde3336317b6d813a9a859e4ae69bfcd855d261ec89a54c510c4dd2f68cd5d607b299204654f01de5a8158f2e2bbfcb20857f029a579cb769b3f232a17f546a653d04feffbedf3c6875db3b1905e73a4c7bb383a6b825c240f047a2b6f6b944b3c51362dd2dca46d23cb502a7267acde99a8e76e63086461eec706612452e240f97873ca213f9fe6a72e66d91bd3f60d04f7da7cb059258875f0d458120f0800bdfcebdffe2abe784189406c9bb63f3e807be88c72ceea54a55244b481875dc2c736d899d9a928cf02c2b5176d8ac5b64bba7d949c974e613f41b5ce1b687b91dbeeceb66aeba8ce8799b3484d9255d54559adb01d960710d198fa8c5a18eff47e3399a8e2c386d846bda56e5d9e7c9478dd563c50d840dc664d105ea92b62c6656e2ccd31955ee7c438256b2275036deb2380c08d26d26c1e638f7eae12f5e8539f74516f1340da7b16a4ebf8adc93f690ff39b39c612d42f8d4cbd764b2f7cecd12250527810c490b0ff8a3991e3924eaec03f67ba99759232d00cd58130bb3be9235e14772462"
+            },
+            Test {
+                input: "7abaa12ec2a7347674e444140ae0fb659d08e1c66decd8d6eae925fa451d65f3c0308e29446b8ed3",
+                output_str: "9ce519a1f37b2c70c6f641c076f787e8ab26186efabeb6ce18eb8e75b0a8eede06fd78d326ebb3b049ae484d6af7b1daead737653717796a34de1dbcf900fc59b299756398edce063c5654205c5fd268aa71a639c35e35d4deebfb8dca17686b58a639f0da50e1a7938b47a466d03de7041b5192fdaf036547b7f22d5a23f8b6ac48e7c67b7372af0e358cf73d2fa922ab3ce823a68b95bc3a543ba236e413a3cc2b3181df4d3649474213a0f8148836230bab4ad722b2a3fc446c395977cb3875c06c0031e807c24be7ea9b025248f1a99c494472cf417a803c69b3ff8880c0d364512166f7e34f9837b5c66931017a4da3e63998d0f402d5a75212c8042712ae4af4b4900efe6c9e1ec5aca07fc230e6e7834a5a865f2da71eec9054427945a913c5345506ee32e6aefe4ea3e488ba07455d98c94b5078e75e2304f2e85dd9dd4be18f023d1ac6abe5924c8e7b8219e3248f14eb4b78b6c16fe2c3aa40b97566ad3bb89154926baf8820d7e8e4557f8138edab423cc0c800dbaec892482b6155422d2ae3c1e90dfc96ab800fd35df97092ab0a83a40c7b925514cca3833bc1ff6b7e25469d6744a117699c481e4edde082211e9d94a73a0c29fecdb271e75ad038eed0c7d5b856c1768c4b9749b25811f16b1c408c1f2e3f2bfdcfc8e5a329b675418abc4809dcdf2a3c4f867ab9e0c0ae28924fce90802715fd5424e783c4"
+            },
+            Test {
+                input: "c88dee9927679b8af422abcbacf283b904ff31e1cac58c7819809f65d5807d46723b20f67ba610c2b7",
+                output_str: "648167774b09a9fbfbfd351051d18f9112d63b066beaf5070d3780189658febea0a4581dafc6948ec1fa96f0364ef3d1f2323efe5294bd76c28632fddeda51079e9bca5c1efe95f76bcd4593836b9c64d82dd6ed02ad07622bf2b1f7f0b0738e0e3929f49edac321268c78d47d853390fdd8f1bb29c6df469360e75e96493dd4fe5bb2d0816938d5642b87f0344fe4186ddfcca06643a691bd9272f407d6df7a1633550f076042277c325152c8673f3fd6c980d6bde4eab43018e322dd3647da183910cf4bcd3464cdfe0d0283e79201553bf03b028fe6f4862953f865c6108bce672c4db5503c1d969f87bdc310f7b78d9df08ade46f54ef718083f90e60599e41cce34110befbe315e8a0bb91d428df35af59cd4f0c8059b6ed68339307280b05c3aa490b7900c13c3e12f1a4a3983db5f0a620179af9ef900535e32146c8801c750080e363a6a67e4a9037fc4301fb28b006822598b38dc38dee16af9a1127518684bfd4a0920c7267ad52a447cbd6178a0329d4da146657549cdced7ecf9c2053541943afcd508f677549f364d7f793a7b7bb8ff12b7594ff768faf6dd77b3cefe97715fe70d8ce8468aeb8266cb09f21285a001ae13d0fc8f29cf8380685034a886ddfe8d3ad57329e6fb92d2a079e5af01f77aefd78a29d294a6a8e37e20159408bba4f10f6fba5d54d4c4d93b1acd65d84088aba61ec29e122efdcb6e"
+            },
+            Test {
+                input: "01e43fe350fcec450ec9b102053e6b5d56e09896e0ddd9074fe138e6038210270c834ce6eadc2bb86bf6",
+                output_str: "be4ddbad9be9abc823f65a647910aa06265b547b0234c1af6a12987000f710016295ea57cc5f30656c56a66f28e85c24567adf2224011191a045c23d4491e444114392b74bfbc60858e719a67bfdebc135725de961ef7a81ab90ce4192107a5ca84aabbfd919bcdb8270e8079e29eda4c22e130a1f046e5a87a4f2cdfbb4dafae337c1fdb5bdd9deb321704c585d632cbb7a0438427a86ccf7575856b535b2e92a3872f2b5d3c945c16f3547b4779e5798bc82883e850585a7fae200a47b68ffbae54b17238d7cb3fa2c9374942523584d85f1485969bf61af5e117275fad27577daad38ea3702b5dade3d27b4a2e2a66f88ccda568d5d4a11e1dda5d8ba7ed9cbdec91487c19e1f9a57d59afe374741d8fc9df32b3bb60f8fabea1eaa95289b43d1fe712a50b73bf68cad16aa25a1dd95d80a0f174061a01d9f18509589188d186bdb991ac9a41423baf9154210ed6cb098d6844699f07a388eee76e8dba801276f6d2aa7965065f3c923ab64620da1e17a444790f9b7b326a3579b9a5ea5fec313d294f97fc846d721945b6adde91b66454ff2f2a81cfa19f6b45c51d07be8216fe7c1e052a24904b2ec2e9929314cd9da48450beb8ffed8c499816c078aeb2a1b52f07b5917dec0a7beec2b83f778bfb15ce413c9a4307ccb7c83c879824d0cfccc4b3aecc519326ffab353e37c59bb99ffbeb44a95beb1dad25843becc51"
+            },
+            Test {
+                input: "337023370a48b62ee43546f17c4ef2bf8d7ecd1d49f90bab604b839c2e6e5bd21540d29ba27ab8e309a4b7",
+                output_str: "2378c76e867947e94c0383861e60e659401b1177bdc1133fbdfba3552b458dcf1ba41c825ed8f41f7f8c8986b0a47b25bfd5f0294fdc707c8389560be932c582e2b5c63cd85754e9d96a9725c12ad234b887fd5e96ccd52507bc564f59e2e0a8fe89a444aa3542c2b302d1b9f8f3d41f1c960e1867a4fe64d5f6216e64199f3d66fe4bd22abe7b23ef97328f5fdb5cd502a118000e0606d31560c2cbd4cb7ebf90a0aa1826cb32ac85156b678198d225f4d58d3076fff881d9e6815dae811e7a04191602e4287f72c95a497c2dc47c925b7b1b78bef334b153566a8b46ac8f6cc0765300e970b12adf8e0dfacca6a59092891d73ed55dd624a2464509fb5610be2ae0696097d5645cbc9e992b7f1f39005eea0ae0a8b55ada1f28ec2a544266462e6a3ba97a000ea722701690007ea7fd41fb3f83bf85d5e19ab140f2ffe6dd70f199b7995997eec43b98abca0e7902442d0f14e7e4b288a83f8e4f5287f78f57a2df951d62bdb9b9cfdf3d28f0374bbd3b4ab955244ae444e23988721e5b3c4f536a80fbb7114de769d587600c92539d92c3b2621c679064693bd9893bed3c353af5347707b6586912d6ced5903abb41dbcd5b4bb67ef2a315f8bfd23073d76715e869f474df6f5c98e3c1e65117b1844b03835187a6b2ae054eae51797de704c7d4c88a258efb12d1fd618d9e95c4ae37ea0f54effe216c71a0f0514bd569b"
+            },
+            Test {
+                input: "6892540f964c8c74bd2db02c0ad884510cb38afd4438af31fc912756f3efec6b32b58ebc38fc2a6b913596a8",
+                output_str: "66c5253cb16c479b2d7b63e7db76ca275f14319dacc1d00c08a7e170d97366638949fe0fe252448d9749ec105105e8bb483224076fa9204f9a4585f150eaadd931b5d895edd8f2ae37e30fd991174064f7cd93b03434c22a8e5cd27cfe19b5d8f4bd405a9d182e4d7f9a2b009c68ef4798a469662e40467ad626fdd0553b0ee86320b3db087c096b54fd9f367199aae4490f796bfe72df10756bb10e336dba6305b686a291d1097fd9dcb1a629f38d2ed30b87a8f5c1ea1a2ae384bd5f316bf112f6bed8ddc50b4e17509c3d194750d02ae76fc1105753b07130861e866e89b2df9c498c87ba2b9161753303e0db34fa6a523a6bbcb262d3c644d1ec88f9fe1710a65290db69ff847d850107e028ee6cf444e5aa986c98d3d5585d66b4fafa1331ff4a6f54eacd712f39fcb234f4d4cb8c992d079471a269cd3d3f733f0806a78bfc30f8fb3aa97f2f2ad36e8ab019d7e833855299ebc91ca512fb226d797226486153133858649c31ce43308e6e0499ede16af5fcc5cc9593a71beed6206063d471a79f65e640b8c20a131fb15439b9f35d6053dba46b2f2682281e9572720bd3945cac603e61e82bce2144a19dc1f254179e011d096bd9fb2caf77bda529bf7f654118d5db1cd2f973f55ec7b11ab616e731955752fd8347718cfdb2cf6eb6551c449ca601299166dd7e10eba447df8c29e96436b6834f162d7987d9f55b12"
+            },
+            Test {
+                input: "f5961dfd2b1ffffda4ffbf30560c165bfedab8ce0be525845deb8dc61004b7db38467205f5dcfb34a2acfe96c0",
+                output_str: "0128b09a01815373846eb62037245b4bf522303fff74a76b0ac17482ad79e0bb2686871b1916df154a7506985f2a3a6d86074c988c2fa255ddc266cb8effde2d0275bd3360c1e920595e185eda95b54a0b02d6bad88f63509c5b816cd375c0281d1fe29f11318bd35e4afe0cdf51b9c7ccea285787fa74a72878dd3878565606f4889d3454913b0dcb7abc4b2f08fa3f2aaeb6856a25185a00b1be8a8bc7a9a34670793923647ae426bb98c75e45896d4db8a990d2712401694e202ef2e3f33df1120ea9e821a874e67f37648a898ccd759a1db6fa6fd5c14756538f725c468bd3c0b6973a7592c8cf0091d347174e8d954e5795d360c4de1d0785fe45b71da884659c98bac3005e5bd88817450359b51510ad95f16f08ecc64cb9842f0f8ea005315f6cb17c1cf6e01ba64f6847ebd4472db1affcbc0e7b7f5ee8dc5dd18b148bc542cf0987e294aff2edb3ee60c8aa4b8bfbd42433243d55b4b9e00ccded77251f789aad74681880ac765b21e01d499553acefa48456a7e70a9a39163c2e089f26c94733dd63eac1d2bca7082145402fd762665c3f72760dcff13ca4e80f504148144054b714573381c7770c33e07d3a787acc072f3c35b9573fcdc352cd87be8653618d159f78baf16ecf6f8e316a97acdf4bce2c65ca1bc98f257914fce9be62e899ca3ba40a98a57afc3d63b0b0b92b69fd0df0451d7f34297523a99d58"
+            },
+            Test {
+                input: "ca061a2eb6ceed8881ce2057172d869d73a1951e63d57261384b80ceb5451e77b06cf0f5a0ea15ca907ee1c27eba",
+                output_str: "fb206d80aa1d2af8ce64890d3fa84600f80423aa98447792f732fce4716e559f7fd4338bafa60937781b68736603b7a86f1688a2ec60880f6a90781dc8ba3d9b329d662de842961ac84d8fc876449dd8c393441767206188d561af59befe6b91e365413a5f357622a670e22e730183358f9689e70f1b0d09ca9924903379394f516003e37b800602edb84912492288a2e09b46bacfa3f4677d2b24605a584b3ce3174fcd1ae4debdc99c9a75ea7f4e770e2ef184f801e4d111ee5b11950b29376ff19b30a50c4df93a82ec891a321f9a6ea1e0f96eda2fa0c2fc176d5151a6dae7c9536ab17ba47ae31ad69b2af9248e5236aa58d7b864202512e5356da226d5750ce12c062733bd73b7163812efd452ffc4cdd8e5611996e23cc0a5824c5ae4abb59a5dae40563965483b66437b1e75369ff6ab31abfb34581ccd00ca76cf72af7eca65824a46a48fb88c8aca06cbc5d3785db3ab78bb1174354c7affa85086444d3ec92538cab178023e46c7e5e5ea2fee1a970f41d374a73fa6d477d224f095a829ae8e0835d197dc66d1dedab9427dc085a6a95c4f065cf656ad1146ed0c45ee7bcf9f6185358702685e9539c921501e3338c2a6df7b5f25bb248e567f2173164cdcbd8daf0130879ca8362cc6ca28f531d81d607258b66d589eaa9cd5a22fd7490b9a01cb6c0958c2820ff832eb94f0e0ca959b93dcae56a4fb52981f09"
+            },
+            Test {
+                input: "1743a77251d69242750c4f1140532cd3c33f9b5ccdf7514e8584d4a5f9fbd730bcf84d0d4726364b9bf95ab251d9bb",
+                output_str: "eb74359ae344b26e3533947e26cefbe809935ce7ce0d597d1c4125542ffbf1783052e0f90a402d7888cca5f96ce9d874c600b2e026ba4e79ed427f3da96448beef4701c27ca31860790156e93b12a9f42929a8f8d9771ca3bb59ace00c4732983997dcac1046e574eb9e5c912ad4e3813001c86c91b6385e92dfe92ff5cf90652680392a33f6a1937a77df9b9ef2556643308029dc5b5fe23ac9b567e6c81d0e909a279e58215d22132ed83dcf743065c0cb16eb7b991f842125254bac71d80b64f205d799f698f0fdf7ea19c9234357c5838a0bf6add176416db3324cb07b543156c38c2ffb0df104fe3884a6b8f03b0e751b3824fd097fbd3557c5b9c962e9fb29175d1f20799ff6ad9843e1a5b64b2e69fe39f77c2d1a3fd3adb8672d1771fd6769c54775df97b0964e14b2b326362d9792c0c4cdc37aff30dc3d007ac62141d370f0984f4b3d16b87fef8028792ca92ce6620952d766474566c1e96df672f3c335bf2949228006be2b1912c0ddfe66ba6648eb6ea8624b5dbbdec70bd0a745434dc5404c7ac7dcc94197f8c48fa381a5e8e7ffd1c35442c04ee2378d2761b3647a7637423300cc09910b9a4ef90d4992a8ff8faa3b6138ad01e7c3c89660e963bb2422649589df53d5181479cd55a55b1b2807ed120fa9777acff785225129ab1802ec247c48db4bbc284768bdc155d77b072d686462d831491c80752e13"
+            },
+            Test {
+                input: "d8faba1f5194c4db5f176fabfff856924ef627a37cd08cf55608bba8f1e324d7c7f157298eabc4dce7d89ce5162499f9",
+                output_str: "691033ab5c34d52acbb6eae6a669cfb53c39a8020a6ebe9600aca2d9a2acfc898a0dac7796d46e6f304550a8894a9e1c516a1a127287d4ef74e9a403d326dabe1fc548d1aa1323c2ac40938708d7872960e11248235d2aa39cf3ed88a18f8a2fc2794174dbd4c1fb8c686b37641c7cddc565683f0d173952d2c1dc26ed5f5b806c127114910892b1ba0b0eb07c20aef016ac83a78c152b4c4ec41ccd8974d93e686f52ca8656da6d85bebde10c4447005278630595379f57c529c4ee94b8e4100ab930206d9ccee8811fac2f1b5425b6f0740fbaf2f8470a9985b77865750326cd60f855f4427f6ebbaa27cdf0a0444ff278bc22a55bca5f90a58b27d792ee6e8998e94819b673b725079c95f0eae473f62c09d9bb1060ee9f6263950150461a13d758b8da498284f8f355259b2b332ae9117d2a35e0e09bc8ca406c14e8799ccbf0592bfbfb40c1da7b5a88609d71093b46a91fbe94c78a6c9ce9c81a2e189bd832dd746ce19ca3ac9f56572fa691cb506cae417f405088bbc6425118bdbc0c99f97702029c177d8ec398dfc19a98ae3a3f86ae1a8122adc5952b1891269c46821c1561b21e4b47f36904ff7c6814c0a08b6045400be72ec1e647887e27af46ea49c9ec4ff621e544390bf60429cdf1307c93a3a1c8fae2efb6062b9314a06faae8f84481a369b64234ecea944ec6fb3cfa31258017ddb373c55a64c0f9e74f"
+            },
+            Test {
+                input: "be9684be70340860373c9c482ba517e899fc81baaa12e5c6d7727975d1d41ba8bef788cdb5cf4606c9c1c7f61aed59f97d",
+                output_str: "68e791106da01933ec70eb650ac2f03eef1685213522f2e88ea7f8dfaf92aabe75ea0d169d9bc11d13e294338a57295279b28b41d8a4b738cffd629fd4d7d5d8ac7b4304e384db31b0328391c19ca9d381e66d41816e647acb66f312a418795c0d65fdaa6e25aa24811022c2be529c83be47274e8c01d4a2710d6ab8bdf095566f1b3dbda7d4f1bb5bbd3eafd4486afe67b682066b8cecd447b9c2e9e9416f2ce5ca8ca1282b4ae9bbd7c842f776bff7372591cb3eed785c82a27076470eca15a33d5b38ae02fccce396326f1bbe28995c0f8dde42c09182995f143a0f2d4427e8f2497f0b257ccbba286c2fb7885b642494f933b584b0ca83b545ff1521f67ec8e5ae4d93fc82544fc20778ce197f3a2f64ef3d9ca583a0d821a5151f462cd70c83724f9976457ee49d3caedf9b6cf0ab72fe7dc0c9f41f9c5ecd12d5f2d8bd6edb2cbe11f0462d36cf248a9552b0265e386dd44b9853f0ac63fece4f860107903f8db2e1f6f4017f05338fee8467c0c40720663b54f556464f4e87f20192299efc178bc73fbbf350782520900644265863223bb42a5ed2e416b9d31f3021ebdba693cd56c4b17eae16d1a10a381713ae39d5ad6a220cda8a91adfcfac51c65d03910df4aab7f7bc1ca49ca6ad08edfcc976de0229ae9d379e067aa9b3fc3a6cd0dbd7d1fc63c4ac2116f9bd3cd70b94a53b71987c17f65d5e77ad5674cc16f"
+            },
+            Test {
+                input: "7e15d2b9ea74ca60f66c8dfab377d9198b7b16deb6a1ba0ea3c7ee2042f89d3786e779cf053c77785aa9e692f821f14a7f51",
+                output_str: "3ad90f57fcffbb40076cb98869510be446f8161ae4f37f57939f8084cdcdb4e64dc7f380fef8b68cf274780a6a5ff31b1d573942e717470742e891b084e24f9441d27f7fae86a8278e84601b9d4830ad9faec738fbbf86aa299653c2eca3b233ea2d1350de9feafa76fb8986010a26eddfcf33fe976071b3c719ea15a2298d060f5af88e3f06ffb4c70ab13886686b8643843c65bd882c924e760b9d78d705b78b2ed14980e9e89d6e99e8945b3a92b9ac282642651d94600d8e5e583a59bae4cf6c4a38353b90894a7aff2881bbe06464fecd3a54b2726a55fec0fe5bb75f403defab989f75dc04123f5563999d1503413412e16d671969ad0d97a6808b1957a7481d32bccbdeec7809a90343ee59c84cd6ad134529cec5e42a31843bcca3449dd3a2e075998788811a601a3661e241a88406071b90c88799f370dc83b440c9247dffab2955dc5ef8bae47c1ad9157cd0f5db61fa245d7179a8768bb3b2da7ae28129258fb8a22f9fd4a7906432eae33158d4ac1550e379efeb091c883a0102f7daebec2aa4eacd277a7e45dc03cc85fe952d326c3521bff980e16bb00426d2138a9f32593cd1355eb7ccde7fafa16ad8638a9c16ce34920879e753c723c494e4f8b18251d20ec437fd42fb178017e7569647720d309097c982aff3d6c54ab23dfc665023a01b3990e6a8999e7037c0405a4cab91876bb660faee8ac30fdb9b"
+            },
+            Test {
+                input: "9a219be43713bd578015e9fda66c0f2d83cac563b776ab9f38f3e4f7ef229cb443304fba401efb2bdbd7ece939102298651c86",
+                output_str: "58b040b46002bc13d05c76e840037b3eb08dd51881ca6281595d39b8b12d1c15f9cd40d94dad00469bf5eb73205fc649c501b57a33f4eb39a7fd76769a6eb0f84bcf985c6acb281e4989f5eda5e823c31e94f41e577b0069809e1c3b09f4480677d56c487ca148dd5260027bd9ef399a3f08f5f5be869ac7a403b53532b9775ddef6b80918bf367af8700d6b9e75fdcc45eb405d37e9a9d7f9bfe2517fb5ba5225c72aa292ac7835a5bf4fa245e782ea67081448f31854f91f21df99bc13c615a67adad644fa6336b2288f1e29c649341c6a4959e5060a99f69981a10fecc30e29cc7784153816bd228fd7859186375fd66dcc78ee4aa5e9dc0b190fb8a6cf2ce15c7f3e0b54597a559bdce7bcfab8fcd25eb0e0c7df02882ca67e2f04e6266558c7f36fd0a2bed459b50fa2d883c9b86ac8e40a8e92f4099cabbee9e7fd1282f06b3d590897bdafd8643729b09b47544ba3f3ae28defc3dee3cd6586b340835f3ad34d6e16053e2ac94b5cbd4fcbbce2d0245421af021e6e0c55c53584cc917d99818d4f0585ad66500afb13c7cf90b233d01dfddc738c325e20b63cf82a307f44c543be58974110bdaecf43468c902429dbfb0458936f67cb59c4e4415b5d03109e88451989cced136dba9002752cf608423ca52483b4253d24e5b45443016dee2d75e7eb9de415a148c439052621ac1df79e60cb585a4b08ca70286c77949"
+            },
+            Test {
+                input: "c8f2b693bd0d75ef99caebdc22adf4088a95a3542f637203e283bbc3268780e787d68d28cc3897452f6a22aa8573ccebf245972a",
+                output_str: "d0e4650c52bd1ff64c2f5b7853e8a906d7457b67cbea12322b5d1d5bcb8c3ebf49cc6dfe8fb41895131956661c772d2b90df4bd6b379715278c9e72b6fd93c3968fbfd3194c2c527d15c6311f1990dc2abee5b6645711251b3d39202c9d3fb147b39d1d3da108254ff8deaddae6599e17c301bc18deef2a9ba8fd035a084d5917fb9e4e56fa6ee7731332b50ca3d2bd069f793ac6867448697395cc5147481f9f6499433d6242502ea1e6226a88068032f656fc8d509d041f1d0978ebd4f2eb347e75758a29287f5be37f9d6c14e4934e5e16806d6de41ff8268bcaec27e999a7ba73b2131147fe05f9ee8a491e47a3a7c8cc93e6d2db374bd5e091810f0d7103215726a6f80d62c19d9beb92ddae8c459002376f58511792cfbe7a2158ebba922656ed88163072bf6667f121747f05b84d470193ecc8bbfab750d162cee7139efecf889accefb6cec328a184f5cbaecee51119a87cd21110fc20ee85560cc979362c12f1c7665abe62d5ada62da0ff3682b32c6da7150841205bfc43735741e07363b9cb15daedb03352bdff62cf00399cc429a8a25ca1cc765aed117b72917b25cd2729cf46f92d8d3f1131af9b6bf16226140cb57be5c96cb2e4a369d226fa82bf0df3fe2a4ee373434c5ca68682c0c594b783a0b2fa6604ef3828510e1c360a617588ac81ba8d1c18c23a30d245dadcd1c6893d3809d6eb305e538f39dca"
+            },
+            Test {
+                input: "ec0f99711016c6a2a07ad80d16427506ce6f441059fd269442baaa28c6ca037b22eeac49d5d894c0bf66219f2c08e9d0e8ab21de52",
+                output_str: "1eae5df54490647ff03985658785b5bc1480d5ddf3eb3a1fe649520e07c0174fdf1dde9a8518879833d64a99f3255568223e2dd0c9a67baabdf222c2a314936cd57578395288d40dd047d67adf8289207c6c672023e25a5f66d2baadbe2972ea32516ab753ca37ad5f436a94cfd62182b7d68ee0e7a016c8540840d1eadb3a158d88a9e7c90f551fe857c17265ac59bba6947f24582319490817b99a591978ca945d4d0f23499dd3aa73216b7c28eedb5c8f3c0851859d6ba9b04dc67fdb4bae4d73ba540e66536befe2ffbb5daaf91ceb627cf4869327c5d3c2ce79700795e7975a8c6f9c07b95265614df45e50ea89ddf9ff5f2ab150629937b9197e543ca30086e829afbde5524dc1064ad96ffb4d83ea91ce7ca8843c4b1a9722872057b0ac9ce57e7c97d22cc06ff1f74658aa28bf398ede9f186af6e485d6408ca4a4564689183ad52ec0f38250cdd837d684a1e4fae12306d066f2f1acd56797f1de2a9de8095dd464ba58d5b2d58f9312f1779eb2b2adf1773f82fbac43b18ea5b0cc9fe2ffbd9d2afdf61026363817b795a2590336ee1855384e2a26c7e15e8706aef41c671f2d8e2a0ea2b0a558cb35a80952825c845875b2a907e84397e2a3d125f64c313c15dcf0cdc6637176a58ff6c0be30315863c64a21a1fa147af0ecedc22fdbfa9cb892fb17d26c460b7ecec9713e90a46499bc30cd2735fe98b13e5fdf"
+            },
+            Test {
+                input: "0dc45181337ca32a8222fe7a3bf42fc9f89744259cff653504d6051fe84b1a7ffd20cb47d4696ce212a686bb9be9a8ab1c697b6d6a33",
+                output_str: "a8a37d45aacb607c3a2dd97a43e22e226f11eaa21daffb8ece97e42df057ddc9459eae2ad1c04abd300833e6d63600320ee9e368cd2deb5e38ed7726c583fc9eb411c193c42dd8a1d5577aca20b889a5382c0f1a59256bee99aa09a6b2cc7296a8de514ce14173e683268746738c2f8eb29d6f51ac434bf51872be626241e43183f6c7621479b62739b975b6f25e63d9668d3198e82e66e9e5fb871df0ad3a06da385c4a7fc914cb371dc1eaa929583f14db910c8883c7b90635e5d3fb5a3652e98ab62ac884c885c4606e8f453b89badb15f7b9de49efbdbd210859afc079fd2a1fd82ed87949af0906b5e75e561102739d4cc58ac9420694f5c043ddc463e0438e3851ab841ce31d994e1fe378ef75e7f979b7801a284aa8be26222b2baf06857e8ed6765c9c040798b2a6520e56877c1e4297aa43a860f734a6667c1613c0ea76eb70435bd64d34b11728113bc5ca24734a41f3203641d931cfc74e46f3d23037e3878740a6b152a77bb10791e09420b288d89e06dbd6b882913589d82dcd808918ac853ade79b7b8104637f8c73940890ab44e31dea7830f2bc08c26eba38e3b1b198650a9191f366d90bfe1a4caa7e03db8357bd8258f13e5be051e638689e99bfa6dbb5e2a623ba8b2107ab7a4c7551918a1c023f1fe7dd5564861faff0060e30c14941379117a3d1845842d935c4072b28913a3c89d1a63d4658048b8"
+            },
+            Test {
+                input: "de286ba4206e8b005714f80fb1cdfaebde91d29f84603e4a3ebc04686f99a46c9e880b96c574825582e8812a26e5a857ffc6579f63742f",
+                output_str: "140dfa98962ab4d69b6063b0252de5e4d65e4c00a9be1f8ede781a54011d1db01366193a4235f6e7d684b847b2dc4a0a5239589b4c0266817dc37d850e5b23a40b50a6d9d1bae6e64fda20a3d27f933ae866f9c8f00d455d97bc71d5f5a7c9778cc8fe1596191c2b1882dcebcd37a9a8c3605359e886942b04ebbcac83fe730b84ba3b4b3022e0b1a1110eb4d23d2e2d05d77c230e36a1accb885c0faaa312b7f975cf8da5d6b118ed773c5f1c75366e16a1ac75be309eb328da88c9fedd1a13c84e2f856eb0dbb249b3c166f9cfe917a93a3ef624dd4782b1f84b3e2ed70e493615d6ba9928886a59617a35aefed5b46d773fd5b22cba302205ccd97426b7095872bbc7d1932f6157bd3fc9d4a2182fbbcf4beab71a026aa212bd8ccc81eee265e4f53390740e3e9b1e37ca3a7c3a4fa824d0afaaab7cc89c35756d8f80896e8686260ccd94857870490aa8aee2fd3842c62a256107a7a06f87894ee70d218b6166eeb67b6f711d421c45ff2ccc903dd1683d12eb5ebb9464ec0b3c92cb62ea6cbf37591b61e6be15fceb0c1731b42d8d3587762167c3a43f62ff57d58f2a2247cdf43cb756f6a25fce0084d74baa73a8ce12e41953c03c2a9ff94468a69c03c2b5f6b85a2f16397326c7dd562e90f8439e720c1ac0b4273a7ddcb71581db1d6a57ba4e028bb96462dc54cec9ebe36c704c44e5f60d04b993454daf405795e2"
+            },
+            Test {
+                input: "eebcc18057252cbf3f9c070f1a73213356d5d4bc19ac2a411ec8cdeee7a571e2e20eaf61fd0c33a0ffeb297ddb77a97f0a415347db66bcaf",
+                output_str: "f0fc5662d4d28b3235e49cff708d90bcab50764c4081e2f30f0479573ed4fcada1a85443d1369e09caad970570a4ce3d8eab46ccce3e48df5f26c68c7485911286ddb1b369d13079498653b21e3ba7fba9007500be927490336082c1d7fa5b78bb741c459177c05e6294dee054fbe526d983b496e731b3379de525493733305da1e1e09612cd179efab1e6e67afccf60776e319651ce1a1fc66ac945bec6c45a99a5bd7763aba920314f04e67ee193484e54461c68e67a922daf9205faf10f4653541f2a5caae6d28449cc919341ce63939a0433a9dbd307020e80b65ab7b2ab39a9c29d167dcfc05624860b50b0c3fc3986b020b48f5fcf00c3a6bd8ffbec6a34add7e97b106b4c1daa9e5ef91b797c55de36b88e9ac19b301979bebf36fb86f4f72a6560a4125bc1f657769f89cfb1f3a29b2a0287072740e52a60c1c898ea42cd9fcfcb3987a015dedd297f8382d639cd7118ca85255d1f98abf1f5d94649a161082d7d5944b2b4efe4975d5ea38138b91ab5b61a790349d5463d2dd278196364115c18b95f916eeebd71a21de18c9aeb22566d3aef009a84ab5479222ef8f37dd29c7b22d0f1627c25ee467607f86debd8267a493ce5c361a6f6126dbc8263b6fa5d5c9b9f8ac9fdda42fad433bc9a76a218c1134c1cb5f03f3f7387e245089a5b18c96df31211b5983214b64ff3e1d90bc234a2f5ef7e993c8f4e5fa9be"
+            },
+            Test {
+                input: "416b5cdc9fe951bd361bd7abfc120a5054758eba88fdd68fd84e39d3b09ac25497d36b43cbe7b85a6a3cebda8db4e5549c3ee51bb6fcb6ac1e",
+                output_str: "aac37ff9fa6f64049b4d72457c87bee3ffc23044abe0f1d121392401b60e3fec089d4ae3340961915bbc79dca9337c4a02ee99ab932b346375169057e8bc731faa49422cf5296122471580ae4263b6c01d8bf9c7f736a4cb652aa5e3521bdfce2ce11332e53236ee4f613b2800c28e5907d2c3214f6071611496f80594193dcc09afce3eab1769a5fa2df9abe16ab019759a07154d21c3365dc20bdd7c9eca82045092ea5405b56861bba693f322871bdd64e2e41985775ed7a3f1095c74ebdca15b9eb9f2b86234967db868a082a146a439746901eba5dabde0f133d99c89a4d6f769d1c6fb1758b3cb1e8986a025f5ac2a8d6f1a9aeb66dd3c41d41221706a4824cfac6a6db69e3d157244294b9d25b59274b1fdf992988f3f18b91fd78767eccd352b7ccd335f96d3b3913902c885c470c2f7d2b00a92269709863e77d3fb4ea1c80cb58c9cfd996e0c6fb85f3bb5308b95e8b43555ccd4b589829da442bbcbf0a5c7b9b24e3de846e9e8433f1a4a326abc7af83a5bbcfe9b4bd848414b2560c58b3e9a3cad48f860ba46a5111d0ab629b91369a964bf22b5c2c6dc5c3a521de18dfcc43bb2e641afc466b75fc3529bc4b99b843a809773dd2130452e61ec162fcccb0a94b3ab0848ebd59c9fc25e84349cd2154e5e326cf2b97071e7c47f0f574d11729eedadb3d0dd0fc69a7f7224891efabe76942808d6459217f06a7d"
+            },
+            Test {
+                input: "5c5faf66f32e0f8311c32e8da8284a4ed60891a5a7e50fb2956b3cbaa79fc66ca376460e100415401fc2b8518c64502f187ea14bfc9503759705",
+                output_str: "3930d75f8aec436928f62ac548fd6b215c2e6fc22e918690f0cd699a0cb1ac218be324232295546cb3c421e939222827890a8fc563f6dc455b7d0caf24c7b1be44256de645ebfd281f263c9006f78a69e8939809538a74e646e75c4d23cd06ef68b617e6c5d36c85348373fcfccf19aa3bd69e18ca670091d2b50b0c2a3aaae21fbeff894a189512f4eef17258af048d073179f450d366295f609567eea83cb6a2e2b8170f69e739db47874e1f249ac9595442571d100ced32c151ed4399f5aec97875142ec1e8b748a9fa5c3ede5548b875e60a224d9830419e233fc9a88cf0f937566eb289591916c1d159bd68b380f784bd3e6a00d4c785694f38fe3d8fbfde5063b91fa397afca0731b97294269ef8157b531b08e15cc52ac8e5e768e6dd3905bb9e1b462481afa989441cf0780ce6b1926d71940d4ec82521a4347992b37af9970f47658b05ab54a617275f51fd723a35e72f9f965ba4330569573a58a0021e1dab0af22ea03e1bfe1e88eb2d2b97e5857793fe7b63371f3569c77a77e331924dcfa9fb8072f4eaf3a78fb6462a5c68f26d034bfc0b3bc8ada4992c66b4c8b2f0489a446b26333146b4420cf2b5aeb41934b3cc05b7ace62af74997b797c82845f4c4d7fed571879d255eb34482b86383e924d45b4c9ef52e76ff236a0daa1c9f6d342bff82305fcc88f8b13fbb724a9fe732cb33a6d53d95753fb350c4"
+            },
+            Test {
+                input: "7167e1e02be1a7ca69d788666f823ae4eef39271f3c26a5cf7cee05bca83161066dc2e217b330df821103799df6d74810eed363adc4ab99f36046a",
+                output_str: "1c8c8643b1fa6b0d217d21e542850127895dd4e455dfd136c4e221787a8f3caf76478bde517c7dc3edb97c8ad824292edf671bc4874044b96a109bb5821858e544090e892b3eeacb739af35eb05dce51b131394c9972247f1c0d7d335d18b9355509bbe94c4debb0c1b18614cf3fa8119b70fcf5b59e37673b470cab14302d805bc32352b340fb71f7e824efdf2732ef3d74998a5ad70898115c9cbff3d5067ef05d859ff932304a5ac5f6afc46c879f0bef369ecd7b5065acb19c655f7fc2dea4dd7ad38a2ae841a67ec1eb4869ec285b5a517c930350d7cbb9c61cdba188553b9d4ef140dd1a8ed312822e79ea68662bbb1ac3643aa56de5991f5f128f036b32023ce34b7a7af7cc43d6b67deada4849bffec361699ac7175311195822382051bbe20565552014d6a4343cd94f7f4aa705e1d5388afe2d96bbe8010fa0e82305b94b70ad954bd5f6fbdeaf090ac510b75cc91db450eb522183371d6b9d09d3fca171fd10174acf3fc47d915619dc0d06d8567c4e8875d0216de9c7ac1e7d1758dd59573273886897382ce8e77552961d51ed0b87ffca38bdb6734a23fe0c9a403abb4fed73dcd504289e7e14906a10b121a57b94c2c37542ea833c55c1130ad70f753c9a368f7c7d1b51450bbbe794f2824713153f83fe6af09545ed91f0e39fa732205025a49e1538ff7daaed5b72eec88862dc0213a012239debd24fcb07"
+            },
+            Test {
+                input: "2fda311dbba27321c5329510fae6948f03210b76d43e7448d1689a063877b6d14c4f6d0eaa96c150051371f7dd8a4119f7da5c483cc3e6723c01fb7d",
+                output_str: "1da38df421aadb3da692f4987e171113e15d3685db1017ebbfd07bb68db236903f3cd3ec679b6bc9004072e90ecbd0fe0f2fc4f5531d24fa6f25bc6eaf4b545a2149517ce19971e3afb866daa702dcb94982446e7af77418164c5e92edb14d98ea0dc32a3e0bfea4e71e9c8f58a751578200772a1e0460083021552feda426aec69346e0fd31fae18b894b67dc38d7e54b662ce051a8453c1db20f55095c177f5883625d40bc4b49965c48c4a1188954c50dfae423a12315deee0feb3548aa9752432cd6857aaf42bf80472178d0714d777135898f71d838058f9f31e6ac92d819c44775c2ede28038e565dc33f1a157d8715ae67ab993179469d6c98e8574a7d8ff2a5f12353f18544e2d623aa42af85159438f247aa947922a5aaf98bd562ae54599783853cbfa5cb67eb1fc36cfbe5af1c18c99d867cb02966d90ea8ed648831a2228657972642a17dd34fd43c11cd7d407cac86e20d8816e69763b60294c19497c151620a2b93b3b3e87639c233c17b9b865e920f6eab6c72218a182dd46177a7ad18e3775fc0a5a0ec956b5e92d8b48a22a6364006bfd2843b3ea4cb63b8c0ac10970853d196918dfd513d4e1a1558ebd3d4c60ba253078417304a50851bcb6e41b5758a08be338d62b0021851a42962313c11baaa95e434f6329fd5d6c85d67a665a675ca527c555c77c7435786bdb8d9642050931c57cb79aee5973aa"
+            },
+            Test {
+                input: "95d1474a5aab5d2422aca6e481187833a6212bd2d0f91451a67dd786dfc91dfed51b35f47e1deb8a8ab4b9cb67b70179cc26f553ae7b569969ce151b8d",
+                output_str: "660ba471fa9414c985a47b1941804295adae88bc1ba145defb407ad66f193be41eee4e0f71d175f6d1d65c4b227a899e0d282ac714e50e3002aaf8696b00a736a60c9ccf94d15e46db68228ba174dae1575138d3f9eb76cb16fb09a50a6f7024206d4a02277d2d0b53f189cd8e45e85f4c0fadfa235c963a9a63743d88fadfa6cb99bf47f32488b4e009b47f7bf59a01bd92c0b6e771e8784b67a0aeed96b29e6a1b110b868b144105b85c11cc01c589a89342dd456e154a0d2a638fefeb03058ccb301fd551294251d32b3f03bd62ac5ecf5a249940c2401f751a9fcf036a384ed26f569d227235cb47673f7003c4efb36676044d09cd586a54d744ab4922bb337d4436c4bc76cf4a478d1cff7f7d97ee2dae912c5bec910fef7baff0bc9e32df5ace8dab30840a31ca192e258a4141275534361977d2fc22eb1c1bb62a21b893a65b16c45addd3032f2ccae38beb6de32e1b5fc70214e2be1b7bcdecafd744f82edcec99f92d46aa66044efff26ef3bce081a19f1b7392c68d2414d92d426d78b4bbed4aa32d05bea547a8dcca688cef6b0bc754fae7c13915b97478bfa72ebd409fba5ae48cc89b37918f04c068aa1883f2a950675761120989a9f7821799f5eb64c07299ade85e1dc1bb488bca7b96ba7f04d49cab2b41803f17bb94cbf04b641e140d8686eedce954ed1a712bde789c31f02f721f467e167c3e9b035687"
+            },
+            Test {
+                input: "c71bd7941f41df044a2927a8ff55b4b467c33d089f0988aa253d294addbdb32530c0d4208b10d9959823f0c0f0734684006df79f7099870f6bf53211a88d",
+                output_str: "9d027f5434c6f6ec15b26bf3d61f31d81d46c0ff426d4209e0fd3f9a3e01d0af5bafea98f9e3fb66e8390aa2ed009c0d6dba82b3e36ced600fe79c0f50eb1c1f7530f20d51782c13a79ab1d0bc655112d745043911b5a9524e6ec88122cddaf702c34fa8840e8785a7046b6794e623526826b471cd9f62cf9af02e398c077c7f8608730578ad22a44cda39df8f101ccf21052c52fc12967ddfc77c153d8068a2b0b783376fe56b1dacd9a0b3e87645132bec0f3c2c9a521deac286750c2c42b4a29b29144fb1b0f5cc997ad57d04bea965343843788daba5600a7ac5403d649097eb402205ce4bb12ef836fd4b7ceff704f8a2baca5d6381504793f1c6b47d15dfa45f749a28c7fc16c695a0bef69437ad3f8c8d3da5386a6d9752529ebcd84cf92d641a4ca1755177bf7e16ca144e270e4191ea26bfb144528521d32dfa8319fe37cd026e5f707f81dee84327cd0b74c05cf69543e94848ce616fc118f73206b132f0257925b8d93db60fa6e034d27a65ea0b2eb18056cc4690be78d9bdcb4deb61fe5089c58ad8cd08db2ac9a2c2b0811ef71309db1831d9ed1032a1267d3152e4adbf2042ea48069d0519fc5b03a5375eb355bcc327766b4b3559737dd4eacdbdf5b28f121e7c13eee9a8c10e66f22cc80ec40ae72ceb0b2821bb7215cc9e645b65e766076ab78d04771da21b501987f8bad685c6eee40c9f60605da631cd"
+            },
+            Test {
+                input: "f57c64006d9ea761892e145c99df1b24640883da79d9ed5262859dcda8c3c32e05b03d984f1ab4a230242ab6b78d368dc5aaa1e6d3498d53371e84b0c1d4ba",
+                output_str: "3951b52498f3c2e30411a6d89c55340a73066b36b1ae55d9c95142fa1ee13ee8b7296074d82e44d752ee29705606d823809786df5a2312f8922e4c50ff0d7297b864fcc3bd81311d69d2657169773c41a8f7f0e62e076f5c0055da042dde07d82172bffefbbb031fb715546ca47903895dcb4807b9c435d16f90c41ab7836a53454e089a25951545f0b39a849f329ae9568a3640f08329b0422807ab15461f6c67e1a1e5b8439f4d0613c5b4a8ce10ac1db59da2cfdc1f8fa78c60e88a7e6c0f2488afebe16bbca680ee65bb53421e29c8238b7f0d1387c60eac50ecb43af4ff075520199bee31641ca433f35d62b96fe477c304265002440018e4a4c656679189eca635fe4090724784f56db38563ef05a8ebda4271adce14b8644baf09b83574ddb6803997ac473bf537f0f93a2fbbd0e0c75c387f21edb2eebe0088ce8886e6fa9952db209bc16e624a72da33878538549aa8f955caba17947fbeb6a304eb9b1b494a197814ee4281a74334f71780455a352ee1586bf298361c40140c3b6a384167632d7efd7f3fd327e18769dd481444400b669be07eddfd2783962751896b703b3e196edc111411db17531b96d0557066dd6d2fa3eabe0e4735837d1da7bea7543d6b591e55b2d95d46f822cfab994770f8f51a58bcfc10b4a7dc9c8a645937f5aff66a59687457ca35c42dc2c9d75ee0aafd9bef334d12dc33bc0881a9"
+            },
+            Test {
+                input: "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7",
+                output_str: "b21b2ed68fa53bf4edfb8ee5282964c8fc370a702a229d3c4bf87dfa5279b1ae2fbc85a00067f8407f586b52b5f1aaf97716025ec2e292206e18570ad50cb51e072a7a06781eb9e1b1b23c576c689deec4da40513361b413f513a0ec21491f0e6efb792688519c1e6b0760b3e1de34890c2bbb5c3a44dac9b0b0ef2b1b4cc4e30da7f93f52d656712eb12dfcf30c80273fe5a8f42b909aa2c9e1e9c82199418ab858e1b8897ad632c0c030c9f56776378a86df63a5cc284adafcef50df97847de927f296e63933fc174eb3009c5580cfe39b77bf359a865ded988d3bb631256de6eb736c637693dc5798429498609a6201c6e9cacd7782dee77b3bd4728ba32a0da88a14212bd204292b6eefd0c7ec1814b7002d8fcb08975d4a9c62100f94404cfd32ebf49407ba4c6697cd65d7c40951ce7774234c4a793265cae9037020e35d38c9c016b15d214550a94f6b245dc4f5b9b1c8298d683ac59acbf177f266f1818628b4174d66129c057b1336f718f67d5ce7a3627e31d8e64cab4baa5e89b7b2971b4c82d23c36305b01d30f830baeb2caca3baeda18f912e4dbcb1f5cdcfa9f562e3be2b01826eef5cf0d80da116765e0d467352264c8a9c1242f74d98d35f77472ca4df8234e76f7600b6052e7516c514695bbcfc1793a9c9af512e1d2edd7490d8be500710b305f9f54ffe4d87b50776a29c222b09f1913e71f63aedb32"
+            },
+            Test {
+                input: "16e8b3d8f988e9bb04de9c96f2627811c973ce4a5296b4772ca3eefeb80a652bdf21f50df79f32db23f9f73d393b2d57d9a0297f7a2f2e79cfda39fa393df1ac00",
+                output_str: "0a7a5cbfc9ed4a55b8c8cfe99e9d71d4ec34aa1c4fe8a69a39ddd2c0e1923a3d4d7eeb8769709172866f0f93d96504307700d75f4922eb0cc199acacf31e8bdbfa166342cd7294a723608528732bc85d7ac57307c37d07ac03d99009c2052de7536b9049b0750a5186855bf41fc58560eebb743f6572c102f21d3a92f8908434519d8f797db47cfb93bbe9a567aba819fa035f64e2a718497fd815968f70869066ae8db9314f006466fbc53660bca5cc65b6586cd75e58427dc7b3f7d1a7f0a5804775234c8d0907c5906aeb4ec4df01e081695897b324a97485c22f694e48eeddc010d198e5dc4c65a24f62d6fe7ee0e60b2e4f79a6bf349f9612303cb272c0f1d0a952312f151efbde16d17d3b2f2bb9729f444db0b1b993a6cd2ea973d430291d276cb479d8f07b9fe022f384743eb3c1593f062994d2853aec6267e68c724f959ed98d9ddc0919f53dbd54e28bbb28ae5f0eabbc36a81e25a02174c14387e8c1695f97de66c74ba20cc8ec1eb5d3dafd147a894aaad4b20df7a06eb9b676846133868f02eab7102e6d7ea8bba678b0dbbf1f6d6d6ad0fa43412a8a53c6d814ba26388bef08f89042e573facac5588e4b5c4e2806542f2e68148f4b7cff1ec3da21f633372b567005f2cbe81dddd450e597fab577a1935281f758193cef43961c380b62f0cfd084fb4ff19045ceb3422c01e5ccf9eae9c3b300a117f1d81d"
+            },
+            Test {
+                input: "fc424eeb27c18a11c01f39c555d8b78a805b88dba1dc2a42ed5e2c0ec737ff68b2456d80eb85e11714fa3f8eabfb906d3c17964cb4f5e76b29c1765db03d91be37fc",
+                output_str: "0f001a78a98382078267d5de881f8717b55a31c1781473ba089c72cdb201ce93b943687e3863bc24be5d255a4c02e43eb498b9ee4d8a0cb4778a742051de21c4fc7745525abf188f38b7b46db5dd7ab30906f7a31e0b030dda800c7766eb48e0f4b12c474c3535441985f40376edb99fc2a0bb2baa9adaec49c1f5fd3a604ee8db5d0c51af7edd29306686b3795653e2ebabd2e9118b789868a7f821fb5bc5e4cf732456448417f43f6027337b4e1d481d65d239dd15eb66f5c6c289ee85e065fca3dab1126e4522dfe9a1b428310c7df543bed5d4439e87549ab0be6aca17180714d2636fbad2f7bafdbb1961764f48518ea1ecdba3328de8a6684730e747174345b77052e8cce9765abad9f7b3ac4e8c2155fa5af14fbec002b20bd2ee417f6ca5eb8b95087c34ea52c8d1dc95453f6744272bbd1f14a1affebe475eb2d20cc26c5893f71995b63e725e7b02fa02b3145944d9d8a32f898dfe1f7fd7a73ed1d67dde341c4f95b603597f74269835762a1f348e10bf5ff15b7a325077aa6da99a8b92885a344af35d9fe34a5b5549d37ec1c536d7b71962e1a54e2601e0f0ef19a2f81151a477d35f36374e7f44e00b25c2f7c4fd804490bbb68bc755f19eb25f04ff370107237153e50bb1f8867917cbb70332b41441b6434458c848970bbe860a07dccb6e6f9c076998b54ad88d500634948a73a3478afb1cba9fbb399d39"
+            },
+            Test {
+                input: "abe3472b54e72734bdba7d9158736464251c4f21b33fbbc92d7fac9a35c4e3322ff01d2380cbaa4ef8fb07d21a2128b7b9f5b6d9f34e13f39c7ffc2e72e47888599ba5",
+                output_str: "d442b526ee0de0a7977ac04f9c822ef3369cd2cedacc05abebc71128f0c0a2f8d5c2566ccdfccee773afdd2c0f8aae2e59b56995f219a9b06b638dd91d0c2ac8d11ada3cc491a5985255716c75b474fbfe4df204b75176468511807478ff873f17225d022a78141b962e1a4edc7f93bde19dc7d804c11c49942a54ce606322693845c11eb0e20e60ac7a15287848c37eaceed986f98476ac62a23e366804ebd5690856d69e82cab976a79931fd5058f0562b006e822087dd8d277338a6e555c54a536d29831d6587b4796179a6f45c89dc9e85dd3067adf043e3cc90e96391d60145db31be7778df6402d7808f46e42c8bbe987591edf593ce50515d4dfd647afe7a65579e894ec6951c2f03ccb4fb4f4f212f3d87e953d4bf6093e4d390260791924ebc438b56693ecb11beb8b10b85cd56d39a95bfa7924b9f78e181337e550affe40cfe99c709994eb9f81ba4e14c6663733477320ee3a62955975e5f3f25eb3922ddb67f0a312d916b8ff2c14493981c7a6fae0e14f222f194b674173c051edb795ded1041073bfaf62b76d3623d065f797a82ba490cecee1136c08193d46ff6bb06b414c8a861a4604a4cbc87cc652eaae3d648e4d2cedea13344ac22cbd4dac4ac9d6662d3694b38bf12169320b5249021c85a7477e2587df9617d7d44e09bf7fdaed71e3d5818da093e6d019243a17d9f32a5046fc6ba19edb0ae6349"
+            },
+            Test {
+                input: "36f9f0a65f2ca498d739b944d6eff3da5ebba57e7d9c41598a2b0e4380f3cf4b479ec2348d015ffe6256273511154afcf3b4b4bf09d6c4744fdd0f62d75079d440706b05",
+                output_str: "6ec28683a74038f869a23b21669f27b746a1ac2bd41e3bbaed1cfdcf79d7d1a9499f2ad4701f64830f14c27fec0cf645e553b3d76d8512b879d2d19e37d93b0e9357160ffc00f20cd96fc1aa520b0870f853b3241b687549dc2d1f119198cffae38402ce4cc77a973cf49f19a52ef7232e39b5638c680d44334762657397cee9dc65fa37cf9fa1f902ab290f8ce4cec82aba455a794b576be404ed24bd50b9a4923d04c3f19cb812e00d6d9dca00a906ec0f3460f14d3cce6cfea1c78e8400c0fc1361a4a60810bf51afa3ca21b18c7df5fdfbbdd8fc1671d21ceb404f9dd37008419cdfefbf1d57f7ab7665baefd500c38a5ab04ed47e4b3256b0b015d0511657290418d5dfecced4aa47fa14a9a0e9766f3123c80b65fdc07cbed2c8b0753f2b20ee271d11d28fee068bdd3c4f449973463c17f21f60a5e59be4fb3a3490ed87aa1709a62643e65ff82f2980bf2460fabca0719e575614a1211d256c59f86abbca382b36f970c489660c484ceab850a13011faa07c93d2fc2e8e447a997b0bfc286769017189a68d7de05cddf696eb93fb8792f25b2979aeddaea7a935589be4825e83e9bb302c3a6e88d83bbad06ba6ba274a672ced23276a499dad01555d85c620b6fc64c62282c545195eee61c8a127ea8994ad5a706a2dc17ae5c6f165b477655d067267d88374f674be12f58a35da878346bd48351175ea72a0cb5e40"
+            },
+            Test {
+                input: "abc87763cae1ca98bd8c5b82caba54ac83286f87e9610128ae4de68ac95df5e329c360717bd349f26b872528492ca7c94c2c1e1ef56b74dbb65c2ac351981fdb31d06c77a4",
+                output_str: "ff0db45e2e8959375d3915dbb45fc32dc6cfe7d2bb227647f6877619bb6884d8bbf9668f407784739d34975576b99ab1325716c2b83212dbe9e5e33b5a6ec68fd75015124f1da731f519f983cc783f176286228e59068aec6241b24808406cd60f67d5a1ab7083d7854984a1f7030b7d700d5d48eefc6be0aea46c8022256866cecda897dc22d4a18b28126444d956b93190d7a060cebc2e8be65d90cf7837a90dfc9acf4be4193a892dba8b3a068e7bd20d12c47a95e0482a2cd4252a34e1f13bcbceb9c0a12e719a27e2759fde1b2f6e75a0a38cb80eb44c023fb0ebc33bc8290513d95c431d72450951ec1a86a89d59d435cd3d4b4e069556a00a443f045224d46a8dba8cd7e8bbc89a21d3ca024c4ec96bc7169e6affbb05def58a0f2535997f345c8660451e7cbcd83c622edd0d8a8f30d8377bb31bedefb546c989231c53447b7817ac3f822d596b5c746d5839d6cc8f6d45c48281357e87312c33f62ec568db4aef7f194de67981d67b2b6659268556ee38df95fec4bc340a3bb9539eb6143bfddc12bd233bfff5fe0743da3dc89f57dd159a475d6d8882bade66e4c93d6950ed026c747968f84ded68284f5f02a9f7549b88f244fdc261b34bd66cf2ff5a6925565a08bc8a5f8828775a5a35147c57cf327c49cfea4797cc130d1e8aa278256fcbe416420fb7683e6d0a5b1466a586e98c144f4cd5fb277c1e59b190"
+            },
+            Test {
+                input: "94f7ca8e1a54234c6d53cc734bb3d3150c8ba8c5f880eab8d25fed13793a9701ebe320509286fd8e422e931d99c98da4df7e70ae447bab8cffd92382d8a77760a259fc4fbd72",
+                output_str: "5c00245176070cd2f23f1c5e15b21a9161beba24ba71d989bed890782ed39eb857e325afa269adb03ff1aef7d26ee524d6ce821d2c842c43d0faf47b602e55b7960fb0a9638e6da8272dab5b8db784daac730bf0394d50a59c87b422080191769c21bd08a32af4c263b09d61a13d0ec26b6d1d63a2efa5b4fb9cd4214ea76b2c915f20e242d104745ea9af73251f2ccc9e78ac8fd3c5eae80ca665a87c517ea620ce5217c215ae38cc43f2756d9331b0359fdea9cef8fbbfd3606aa5fbe2d5bd31411a857b3c8e79a2ff1b00e3ef56bc25d0d83958b64dcdc095241837e333e58e4da64f3b5b57308b165924b4c5f70567779248ef4400be3e80f699fb3b6e40c36badc2bfb504bc777733ba9b59659f8661d57b3543bd26101fc3dfd6ccf430036776df0f2979b03dff7e6b2e98f161e050a38f71ee438088d953ef72d5651b5674ea6ffd3440af8ac94d5a808ee426959131e460c858a77c4690801b5b3a28c6bf555f02b5c60de30c4301363bd6322a289f36b30e00e152627ff7485f032b61041d4c1eb872365b8bd22f1a6308f5cc56d4707752dc3e32315c8559a3b8083d2f743779a3eab10394f8df71a878cce871e0835b57de865cf16ad2d2bd1e5e5705f68c6baee103c785e43f3582f591da55077c6b9efa8f93300822c6eaac9b5a71fb676c0e73928ade3102b61284c676c140f33a17fab48002394eb36265d1"
+            },
+            Test {
+                input: "13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d",
+                output_str: "812c14b78aeee6820ea1cf8e0f3c61ae7cbd2ae493017ade0756fbc57545830910ddc27f3183df48c1e1d6d1a9f3de220f17402830ac73f77ad2977bdef013c739ca0e9ec11ac4fbeef624f0fbbc534f0467f09e775bdbb8acbcac8b3dc6ecfa92f35ebd729a1bc90236f57ad32ffb46c055c93412d33cf612059c4d5bedb6e45807a7ce2e5029c0594cbfaecec3f9178eb01d60acb5a72d5dbabd6f95691a1f949e4da7b48aa78c1bee810b175218c5902753b88253fef57681e60fda1851a18ec1f3953cdaa6b9c32d085c7ef9beed9598354cea388f3d8eee372312168b590acd0c330816949211d8ceaea737eb87bf9e6d4929d83b87e287c887e32b66faf1540b64c53593bce073aae4bbf711fdc7af6e7cb0fe938d2f87643fc4dab4a7d4154015e82422c14600e44e41d005db80cbb4c297335ee0e616e32d7e9ba5bb0d88fbb05b4d5799df5462e4544d3883cc2c4850fbe5b43613841b0d515093d246b714e96656e1f6227341e76051d5c9c52730d66d075df0a9edeed5d8e878a1fde3ad2c962608ce17655ae769c484e676904a29f22a3b4524de2894aa633df9f65cffa329af056e9be4e67e7ebb786ac3541c00a792b4217e5ea2e51fbd979cc8c6e40f59b6a665f1be6e6f2ff4d1d48250be44572fc5b731707b8611e8cd7679037d565ba7b066781437fadbb47f68ae752e879286a25020f8e00fd7e62af6"
+            },
+            Test {
+                input: "1eed9cba179a009ec2ec5508773dd305477ca117e6d569e66b5f64c6bc64801ce25a8424ce4a26d575b8a6fb10ead3fd1992edddeec2ebe7150dc98f63adc3237ef57b91397aa8a7",
+                output_str: "cafa188ebd8cdf392eb8e67776d6f574f72615abbb5da35999507460fb1d357938f521bb18699510d353d3b42ef72e704ee769c02a1ee7e366871f28b25f798725ca3fd147f7da2b49329fc5a00e486a19e9465b782b1176b84465a96f083957f3d55512f6cef4af5e891108b468326c1051ee1519c21051353f1eaa2ad39a32e5adfd30026d4b56a2498309c27b03a195ff5a7ca27e5184e322b9b783c44c4e0842f6695bd89d5648be09b927990dc3980e7f818392380840e1c4310ea67abf7285cfe20c50933a92e74fef83afa6b6cd6a372aaff36dc582040b34e8521285ee9a67235d016cafc9478b80d7b9778caf5da4e7d1865bdfb903dedd7fb8477f007e60af960bc04a81e77a74ad25641fdb9d81aec87634d692e445807c0ace094f99db07ffa01c2da7517d12c830973d425839722ec0c5a2df093f01eb9f5a6d2e075caea8c7aa69bc899463d0e55c81596907f1b0f81baeae734b24fae3d99984d5e39eb4822c4adeea640228d72387656938cfe5db953c1ed993fd9705ca9c9c70e6df0075392f965682bc163bd85911c99511896bafc35d9378b12e00628eef3ea11e908f92498c90314c55698a6b9c6d8fd88ab4d7250166fe57e9c106fa674619c1d53cb3de576806742fa538b5653be7d0c08282a0159e7b4f3273c4cbe1735f3b07aa0004cd5c7f763983cde554ad9926fcff1d1ac48b9777c7266c8d"
+            },
+            Test {
+                input: "ba5b67b5ec3a3ffae2c19dd8176a2ef75c0cd903725d45c9cb7009a900c0b0ca7a2967a95ae68269a6dbf8466c7b6844a1d608ac661f7eff00538e323db5f2c644b78b2d48de1a08aa",
+                output_str: "105ada0018016331e288a355daca7426116c7c0af86060a1a652af34c6d6ba4504e5c681f493aa44bb869997cf024403fe9516112c732c26dee54865adf6594bf7a546b5998ea1026feb209e30d3baa289b81651b29916eecb48e6b4d6f8cee317f46732b2bc865d78ff0237dca71eec837215d67f9b7c244232529fb1801282f77cb08dd3b4992a0b4a551175173bd50fe8798836c60bb748e6d3112d7eab27f0ac52f48fb776f92d89c895d7b1f148f27ef57b47dfea43aaee0c8507654dca384fc7c64b39227b6e750b431588d56567eae250ed6aed8f987d5a6140f0a7c9a4d47de2b2036038d43d9630e849431b7a3f7c853399871ba360107009905164d9707c0a81d00a276699249accefcdaf118a8d28fe791fa0fc4d4a2ca862913400fd550513d0ccec4a487521ec53b33d4fbd2d5f6713f0f1f3c1e6a2895c4e2b56d86904cade3ef04af4cd1f3e8ab7876de83d133170e3918639f508858a335d4244c8da8893d51a7d6cad5a2411dba3b95ee3b95f3b2ec6db652868a8158ffad739199c47c32d9a4917ad06cdd7149738e8568b0eb6b7a0252e151538286d122ab6a6a68a6bbaba4958c0572625e7f4837bdf970db69a943e5c80e5f98dd0fcc590b782308650b86e0c12a0cf2feb059a2857118507639c4b56c749f3840ad13325c5e843ed1895f6ccd47bf2fd68d708c1b2001a083777896ba92bac91e280"
+            },
+            Test {
+                input: "0efa26ac5673167dcacab860932ed612f65ff49b80fa9ae65465e5542cb62075df1c5ae54fba4db807be25b070033efa223bdd5b1d3c94c6e1909c02b620d4b1b3a6c9fed24d70749604",
+                output_str: "b37f11d6837064d393422aa32ca502e6fc0de85697e9ddf15b45648d99cd2b0e35653fd071546d893acb91ea8438e768bf446781a2bae49c6cf7e589fe80b2c6f35628a9577cc1f902f061e425a84d224d2d8c5fd4c06f1c7cea72bbf53f982626dd1208ce375ee4f593eedf93f72011cab8281049a76ec1f90528d53aa2e0589bf90440907b0f02c51a1a1d9a4c4b31fdf378a548c4d65ce4ebbe77b4f95e9ae29a3ce0172a4d80c370d6967bf27dddb29065566b2c3205fea1e2871f6726dfd8fb5be9199c31e77615bf060a33f3adf9a1c86d205c2496dfa694d343c058f7f212d9e056d6525479df0c4c184d2d8191a9fa849fc0dbb2bc27741cd5b43c65db771dd99872862546b5d1c313456423e649e9869a43b6ecafb030897d049907f307c767885014f7dcb21fc4c7e52e1f6e95a017f9aad349bfe109ad8bcccda1e4fa761317bd7b7036a09095164a79a7a4952fa2512a5b826009414be0c504a27cc3af069718daecdbe4f43d93a1ae4e1a9b28a48f69533e6efceb17520d78ea41500797b18e193c98c574a5339d2879da6340d8ebe07723549e51f71bf956bd90e74325bd912fab8c63150bbdedd455973c084a6e96be7aa3b8ba503d5215b77151007a7d32eced117503f1f509a2f6750b242ac63d2a53873d8cbd3a30f105078f0adca870dc906c0cf7cbe1197c13c0c65fd8471bc52ed07d8090c83cffb4"
+            },
+            Test {
+                input: "bbfd933d1fd7bf594ac7f435277dc17d8d5a5b8e4d13d96d2f64e771abbd51a5a8aea741beccbddb177bcea05243ebd003cfdeae877cca4da94605b67691919d8b033f77d384ca01593c1b",
+                output_str: "a0042e6235aff4430623e540e15655139ef9fb84bf8199702ec9a68d4802e7f37328a5cd7af4153cd203938dcd947f0c7cb7f398a4867fcb38694bc3cff4c10971c44ec166f225cd4b0f1c264743815cf7bf37933edc38c3a1453852e3b220c5d5263d67c82a7e62fc19d24c9b32c10a8a6b2dbfa059197c97dec62a05456a26cb555546a4219a905bdd2a0ffefd1d63a56258f5a9fbd535276a163745e8911d55a5e47a4c3411a128f461149b3ff20b9eb422661a67b4785f38ccc43f7b87f5844d8e4665b0f010afc1270b14176913dd56b76bfddecad17374553fbc5c31a7a28e98f58036171bbfcf79ce10861cc0cf343822399546e100c532ba2e5013126976e02c7783193ec43c7e35fc2dff6ab1483f7b5e5955c91f7f7abcb52a132a038fce9387c4635e1a3394bfe589d6c9561d05cb210b25d575bfc0251374e541d72dc2c43e8fc51f98dba46bdbd7a4c6efd775e1e5cab94c8e03540fdf4d1ea7aefe8298958b618a288a31bbc9fe7b2381200652d5b2eafc6a89f806102f753824ecef4cdcc3e7329dc8f7c93d94f98ba5cb51db8f615d59476b32bbe20111ddeb7ac6b9ac8cf66cf7b338e225bdedad4a2c5f0c2941808ee7bd2d2e59da7010ce6656f6b11fe5925508e5a266e0c6f079533c97fc0fb5559e06793ae9bfbfec8bf4d3114783acf6d0e709aa1144326d08d415e7afca80725dec248313e982de"
+            },
+            Test {
+                input: "90078999fd3c35b8afbf4066cbde335891365f0fc75c1286cdd88fa51fab94f9b8def7c9ac582a5dbcd95817afb7d1b48f63704e19c2baa4df347f48d4a6d603013c23f1e9611d595ebac37c",
+                output_str: "439e31ecafd806b8e573af44aad0b7143d82fbc725c963633d67665a2116949eed1bd5338839cb0f41ff79e4b5a7f0b3a2fdadcadf52d7379a935ad0357e7658ff2538b99a993ea6e9afdc9a2b1da9b68f9c9377ddc1caabf7334099043e0997f446dbbaeab14a507220ce36ef110128e0abdd3da6f98d2413e4742e82d749433c545eaba95151695b38d1e485c49ca747a11b83cab42896cf35b275490cbcc856b227c0bbb11ee110e37054b9d8e64e645e1bce138eae18118357c362ae2a729407efeff38ad2acfa4d17203d17b933479946e39c4e4bbc467c7b623042c4b770c179991bf159f8a1df1d3a13218a441c7a3f296c34b1736a62f1c09005cbf972a66bb46d7dc124bb43cedccd07f9c7993c9e365a13abaf64859cd4244223d074005906558147ee618f8c68403b3733aa633df77f4f743652ee53c26fa64d251c09c8adc99aee3d6ca13cac5c6a4b95b389e2fe51e11d85e060cb76e331628d0494216fb2378917d09a7558262de00a345d7ae026bcc7938bc3bc039e9c50a62f8fa7aab5ae44e8b9a1fca0b65de335f5d72fcbec9010ba19040c38b5b37e1f03ced896106c3254663a5ac8a547e5e94738eb86787cb237a2ae65a0d7dc3ef44711325bd1bd4db4abb1c17db9fae2c7defc2ce08aa1e7b68654f936355ec50abba8a1ac45c9d95f1c0669e8812f313d63dbc7f7dc40d2ea71dc8f9f1581f43a"
+            },
+            Test {
+                input: "64105eca863515c20e7cfbaa0a0b8809046164f374d691cdbd6508aaabc1819f9ac84b52bafc1b0fe7cddbc554b608c01c8904c669d8db316a0953a4c68ece324ec5a49ffdb59a1bd6a292aa0e",
+                output_str: "91349c4aca2ee1a2646a6a92e4335e7c1da9f8482c2791fb96734e3301123e4059f603bb4c42b4ff5584cce75960b5ad5f667faa54da85aca5febd5908ffe7a1ebd05ad9e4dfa8c8d8d92b7f94666c119de471326e1f673ea67eda5d66c8035e047ab08157e1228b4b09309f19a0208efe7be1788c2f77347c644b4394933f6aa3e10c1b9a984d12a6d0c68e280785efa11f1731580d6c71c98d6e6fcbcdf56dd55d87865adb395e7913dad6e9a4ec938a1d7e2391fb11cf6007fc9c02ea70f44b67edb1206dc86c00d1df6906c878ffd93b034f830c05f8571a6068d87a2ac42692dec62f4318f8fe6df3690c480e48fe406b85c9fcdaf558ac040ff15011b6c1ac183aeda7b00bd48e16b7977098ba9412b470b7e7f4016209a02f0f585c29c554b5cf8aba78e7e5e71447929e598046bae2bc32958e65a7f7aa29a29c2ec8b34e521bd3601f755bd42edf60b0d04539d4bf63ecc09943e0c12860f0c5665797a840e85496c4e3df04b36ce8fba42dda559d630bc2cec7459020fc32f1545b520b0806bac854e6974a28fb95b41eeaf1cf01dfb3e89b8861f205c100dfc063cd8393330f6a00fb379901d0c47ec2e4ea5d96722ef13fe456e03107ad1179625f968864fb40d7b64879535cca63cfdd660651fac389ce4864bc3b382073d74d5346e6499801fbbdb590c1d4d983bea74fa6a26fafa4e57b65be886d55a54622"
+            },
+            Test {
+                input: "d4654be288b9f3b711c2d02015978a8cc57471d5680a092aa534f7372c71ceaab725a383c4fcf4d8deaa57fca3ce056f312961eccf9b86f14981ba5bed6ab5b4498e1f6c82c6cae6fc14845b3c8a",
+                output_str: "5f8ecc71a5d264abddaf1b4895cb11ec9dd50f3dccb1e1562f1840a0c196a85181be2b69011de4a3c75087a3a303555c074a281bee10e66aa2f15e6a531e5133b6075f84a82bacac7d771c3ebc74da2a1cc1921b3c20e99e2866031bf725d08b4400f38bfefa0f810f82fd1e4bc12dc9e20b3295745b7f132530583c44a18806f537d96b3f352e61adf285810d32758284d29ae60ff4845893ed07eaf2720282016cf95e28c9bd49f0ad80b87a4c71179ed9d5744843e811d9c162cf57013a7fa9aa9d0a313d44c6be7ff069506067817bfeb731eaff820c812765614f3c1a33abe050dcde56fd5c6fac1a43515e2f5cafbb00a75db2fa51145a994045b8f71a6998e6fe47cd467549e548ec4fb43c23e7759445bb36a444fb0c91db3f9a81f1048e21cf32bc3e427a6109de84fd0ea8b006ced78d08bb7c5678ee401eb2b73f0cd2638b2c7134edf7f40166eb23d56f7e4bed122b70981f8133b594121abead3e6c96e0c2d76d93b4323dc8cbd869a1811cab6285e0caf2c021792a759f8fb907fa45e2b276383f6a385eb299fa5c070ac7b1b713685d6454afb9ae4850aeeba6a042f25b1902d18cf5069edee770ca2b342b3d3208bdebfd50822b1ca0c9526306c061b2b4ec6724a35d86b352504d79f44ea7b1a8926c392001eaf2018d4840500e5500472ab05593f3aee0250c27ebdb3eeb5955dd7d73dda812d988ff45"
+            },
+            Test {
+                input: "12d9394888305ac96e65f2bf0e1b18c29c90fe9d714dd59f651f52b88b3008c588435548066ea2fc4c101118c91f32556224a540de6efddbca296ef1fb00341f5b01fecfc146bdb251b3bdad556cd2",
+                output_str: "ff65b09e0a806202e10997ec4f42a049e0a97654626056ebf7b92a44e06aa3d11769160a5ebf6357dd6591b373f9943110f609ba15b5893e7869b17c381b549267130047c1286ed9c56f83776a0f99124f8e8939c8ead777da433f8c786beb7b16b3ca4e4f13cef93b4236d82e870cd3c6945fd7b8f0ca527aee5ba66b753d0e6dc84e4acc7d51686c2d9e7e3a31bb0731fd0ef488f1cae2a8ca588b428068e09e63696f05b71bfdbd89f4e7dcac2bb804939868dfe7849fc68b095c8c6e7bfddb3f35e9a8c1b353158c1f3533a0a327789ca271f6b5ee1711adbe112166ecf76bd0bc91bf957d4b60d84440beaccacbce2c2775ad1a2437ffa3b7dcfe2b4a0cbde28b09e4c306d8133eca952810d22c132bdc680cfc7e74bf5949e7d532da24aa71b22b4576ca48ec1fb264d157a0cec81377adc125f29b27cff0640e0cde89d3875b749e412a50a919a08586a62b8788c4aceaacc2842c7799d125e99c6a2c1f6150cc503fd420f5900dc509b4815a54b893b8f36b1fe27052a5c66324d7eae83957db1ff627508b77fa072f2a01c4f406b6fefc5f552cb38ea06fc2dba6a9428f4980d880751e459a1d5b9b3e637917f177920314c7882afc3298b3e21e18cc126e690a594fefa0ab722e2b1edd1c24c0eb118f9c16e4964d637c4bfc6865b9e290c4db71c510a1ce623132fdc742ccb5c5bbbbaefcfe6f95f40c861964f5"
+            },
+            Test {
+                input: "871a0d7a5f36c3da1dfce57acd8ab8487c274fad336bc137ebd6ff4658b547c1dcfab65f037aa58f35ef16aff4abe77ba61f65826f7be681b5b6d5a1ea8085e2ae9cd5cf0991878a311b549a6d6af230",
+                output_str: "0c3f7284a63d46a75707ece96d5dd51409a0e601765e8760f696175433bf34a781b7dcf131e425f25c5cce52fb457cb5745e62e7a8f9bcbcb9113fba1299d82e403e34a6e7438660d0c7930b8a5cf3f127084885447a91d1f5d5f117e3ee8e2c529abe188745609e9948e02d82f1f87855bbf46e8e4fd39402f749ad00fe886759956faf77e0689485c08022343167e23180f5f1b1d33b8beb5f73ec818b92426ce60f5016b8e644dbacdba9900caa61d75985b5d063a3bbdd5b95937483a970bac40a0664e95c7c4f26a2791754d77a6fe5c8a80dc3d7321badcee567b7950a686b1490fb0ca411f08fdaa06753b67477f67a1caaa38f09530fe58184ca552decc0e54b4b0073e77ff4351fdfc5f7c6e6f153935c1e5288ecb57c3dd6022dd0854b2f986e292fcafad0421aaeb47a7ba53c981defe9cfb53c95eaa02ac7f1dd155e476b6746dd2f1692a7e2d6edf79e795924a0b919beb278a2e65af71fa1cac81c5d5efb138b1dd374f98b98cb5a14d96d9249f0f9cd42856a275f92075330b1926dde0bdbf123a8becbb6b6b3797dd89ba4eac728e6b56696a752a07eeb1a09810d450b2682f2699dc6117bfb45fe306abb889976838dd1bf31791402ce24f2895f70434fad1ad4dc86f0f309ee90fafacc7e72c0b717289d695e4000fadc058a119d9c4bde9ac0f8b45cad48c78bd2686105d9a27680cb82800509914206"
+            },
+            Test {
+                input: "e90b4ffef4d457bc7711ff4aa72231ca25af6b2e206f8bf859d8758b89a7cd36105db2538d06da83bad5f663ba11a5f6f61f236fd5f8d53c5e89f183a3cec615b50c7c681e773d109ff7491b5cc22296c5",
+                output_str: "88c391f4788dbba363859497f71794349f3a81cc9d1746ca273208680a0ce4accc12021e1efa31ae40ea75a009e95da25f9f0cf451f658739e2453280ec6253bfc1d8dd72e91b4abdcfcb240c6efb4e829934bef46069274a60b268df86a7f265b23089dcc09d77b8bf9a02a84ecfbca193208aed46101f48c10778619c154f880893fc0c440662ab04106b272a9fd18b8723eacdb8ad190dd58e9514bcd43a9299fb361da76f7e079a0e83615b6cce6e69ce3e724c36561c728010134ade4c44b18d1fce86289310d30195a936bb1e23c0cf98dfad41e6007e56c905f5db8dc13b56e16c3454146c31c9866628736b5f537268e0ffe463dbeb2f3daf103d24f95cf5ba0a4d94c68d61b6319389761ef1a0f22b3d416e67af916aa4772277f4e51d3a8df919300805a0caf8c36a43215e7307b49aa9697b6febeeec4f4f5f7f664c120ff27c8ddca2224cea4733db2d1a1c28f8c030a23039bd0514ad6808805fb5111f514a10efec4f425e1c91b0ee3dbff70ccf6346e6f4640db8184da28fd8c63156b28226491c1922b862203f23c870a2d88eb5ff5a6930820a4d81a62dd8c4f381f35c18012336011dcf71d58d167f8c5bbd3e5f0f278507d085f01b0db2ea2860490aabe253df4694288ea862f9ab78fc60827241768dfe617e725482df62275031474592a57fd33fffdd837654c22c96424a09a62a5f146fcbce1f2ad"
+            },
+            Test {
+                input: "e728de62d75856500c4c77a428612cd804f30c3f10d36fb219c5ca0aa30726ab190e5f3f279e0733d77e7267c17be27d21650a9a4d1e32f649627638dbada9702c7ca303269ed14014b2f3cf8b894eac8554",
+                output_str: "20f8fca8bc4274e6ce95c558fcf5efe7f6a43fb47ba3a4aeb4afbcb53dbf5bf224654a242dfc1f318a4a26924e5f2759abc96d8b9c50c7185b5a7c3ace2bc0adaf1e39c6eefd79cf89d2f3a8829f180699df802662f285960eb6676560655facd507528d862473623aae970e559117687f87af4a981c7f2f1e40a1e01f2a3ac0e89d1c62ed751b9b178155f2a72f215e51e49a4e585f4422c757f891ad4004fa618da654ba3ce4c6a7614924b9c0abb8b2c6cde9b8ccf22a1e30a21a33723992ade39424252850535da5fef4f047cd998ec7ad87dc784da7d755bfb9d5f6cdc9ee52ba15cfb7f1429a15f8f0c67f98d6e44cbc8ba16d0dfda6d72fbc1a44932aefc2d8a618814957d8b748e0ca0d3b5095bc8785b6c20053e4a204343316d74fc96e16c775ab43cc33ff2b4f4ce85086d47bcd132c0b0e196344b01cf6e8bda3e06e2618d5604bb5040474413fb54669bb744704d89c5b06deea58d4e29f6df9c926a6cea1297967dc66583654fdd3f6449033a496199e4b6f37e0fb31be50747376122951575095467010006d5f9ea709d0f15927a060d828af4180393eaafa27701b919daf424bfdb3f59af0b40d0a4890006c98894bdf402861c76655414ae631a50fd80f0e5c63002b604ad1ab9684c094bcdb82c0540fd6e5924ac51f3fc6da074ac7dd7da1a87a633c16ecde716641975182803039231320e9fa16430b"
+            },
+            Test {
+                input: "6348f229e7b1df3b770c77544e5166e081850fa1c6c88169db74c76e42eb983facb276ad6a0d1fa7b50d3e3b6fcd799ec97470920a7abed47d288ff883e24ca21c7f8016b93bb9b9e078bdb9703d2b781b616e",
+                output_str: "f0e4f184d33e8b5f8aabc173b04e61bfb420e34ad22e3e8ac318ad06d92e8b5dfdf4b0f28157fc9e7d64545f527c805d9f953626bc35923c922fc09e7d2947d342bf91e54ef34fb5987704f7d0c36c9a9347f3a99027e192907342b2531bd1da066d34ecc1fb50c85c261da65f4af9c2c9e93775f39d632e3dfc1216abbbcc8dd2680f8081a2816bbdc1646540cefe4881fce2ed57b4822e11461b5e6443ae2de5cca426258d68b01520594b9547a714b0a377ad398f42599358f7f33855e64f12f88d9e2909e6397acf34acf79632afde5711858814b84f472ebcd03ebc9671f3985c99dcab92fed40de97a3c425d38dbc48ed34c2023771edfa4f988931b7bab6fdd612d4ab6dc39d43e66d74307ea8a9359ad73e0965e885ad919f12e6c645c0dc9925ce65f5f3eb132c7090bdff4230cb16b6c9567aa62dd92949af10a6fe66cc50b29cf189dbb521477a99dc45c937856de855c303a5eec572da0cb0f584961971a15d8b0907151a046cc1b193e55f7e8419601c1699db52bbff3142270f22d628f53a18e64736c1dcc09f7497cb56abd9af5917ec07c35bfe8d041d00b379067f2d85e05732d5270c61c592f8088deda0cb76bb2826492a61be9270a8cd7f9d26f51db2207763bf41a465ecc8b877fc53139925d45541ec090deb2622864d9e3529f0f23b090912e04bb95f56b1bd33381611d973ae347fcc232cbff00"
+            },
+            Test {
+                input: "4b127fde5de733a1680c2790363627e63ac8a3f1b4707d982caea258655d9bf18f89afe54127482ba01e08845594b671306a025c9a5c5b6f93b0a39522dc877437be5c2436cbf300ce7ab6747934fcfc30aeaaf6",
+                output_str: "1893ff8490baef747390acac15d42cedb909c2ff3d30b2250a3f9de11e79943b9aaa5c5747736e29e559f93115b0c029ad6ad8779804083c3f211c8d6cee56ae65f0b650cc45b9df5436456879f62648ec81fbf968583582cf4063b5f007e1b04a9bcb2249833170c1968e3040c808f2d9eba238e74931cbafafd94690a275d1a1c1c29f71b8dcccacc4e9543ff05900417d7e46c64fb4454b3ddb7a0bc01b85a0aecbdf9272eefbda881d2abe77adc9f17a26c50de64def1ad2a09a79ec9f9c64895540fd56e93423dd7df3e566d168e2560d8336177937f46df87ac29f9fbdee919dd8d2462fc1db70e27b992e35f1376459fc15b76fdc3c6d9c3f6d994b300423f154b6fb28f845aa3dc8537de62d81c78326bbf8a89e39c865f395be31b38bad26cfd4cd866b872d427ece798968e66658839121301bc52e07cae272b6c373b01c4ecd42f75d3cd45b2cb1131179a9f21f8cc84c08368547dacccd56985477b4067b865b0268c1366d35c59d7c4ebe54e0c7eb383860eecffe308a2e71858ace60ee4a2898ffffc507f0011f47b16bc9d696955c8e2c7fb64f4ee9dc9f9cf9987ee2ccb0fb780bff780c4253e398763ac6668ff7082a848bd5e1e31e6b5e1e771f7ae21918c1ada32e788d89822ecd3029ac5604132a681aed4348b631a2c9ccf19d14cb10f570e3b7f9f301b041e6b901cc007cdb125ad9cfdf7a889aeb"
+            },
+            Test {
+                input: "08461f006cff4cc64b752c957287e5a0faabc05c9bff89d23fd902d324c79903b48fcb8f8f4b01f3e4ddb483593d25f000386698f5ade7faade9615fdc50d32785ea51d49894e45baa3dc707e224688c6408b68b11",
+                output_str: "56758ce6042783cf0d18a2c44fbf953065571bcfc3d19deec28f0d6564b18b227b6daebae658dd065f414e4ffaf756d10820fe38c61a767bf2fd0c242ea3e994ccc6516fcf68bd7514833e061a65392d175cb6eb87374de426730e4e771c7905706bb5d7e3364f946b8a061462519d0be6f72b0220451f2c6c6e5ce217262323e4fc81dbff169dca043487d88f02bb5c22434fc31043603a5140364b7c2cf179ff13241ced0911adce30c4d7b7eea34e094c86b522ea88f0126943fc2e3f8c1c81753c4a10b844add7868457dfc91094458806b2c115a052bd616161aed4bc1690e5daa09badffb3be59318d7abec04e7b5b439b92e63ba3ebde71aae8c5bec81c9073072ea49e85b53539c2462a446448f4d362136638eec10f227a0a977b3460499a77a9e951124b55340e49f9d2b0a60808153d357b585f2c940398b12bb807e730da556c3d156d84e5c0be2c625e3fa725ac5659e07348894842711a704a15201c72f4fd2e54cae47531c07c7d1fdbc61446e35666175b2cb7b25a5feedc1e5fefd2547f408f0e91d65c7ad0e636fc7d8bafba355275aacd0e2bfaae9ff7b750ae20c828d66793a7d275de882deb8a97002c9b7b90f5aba4d1e7b9d5e4bab59dcc44e487be10854c76d2ee6eb5628f1e791b731e5b1cf339270e90b3f25aa78b28efdb906ab2d5560d976aa8fd4a560a29de12c47a360131bb5f1f8fd71a"
+            },
+            Test {
+                input: "68c8f8849b120e6e0c9969a5866af591a829b92f33cd9a4a3196957a148c49138e1e2f5c7619a6d5edebe995acd81ec8bb9c7b9cfca678d081ea9e25a75d39db04e18d475920ce828b94e72241f24db72546b352a0e4",
+                output_str: "d5076fe06dc454041f41d77df1680958cb4eb8311940d58cba2d6ccc1b57ef7d66d0d947b068928e0284a292d6f3610be7ccdcd2117d59edf468f4cef33de2be52adfea056f586047f8fbd3bdfded58237c4cf541200488a3de301d5f36c735c387dd852959609a9609d370f63ec8e1649119f6966887c38c99f94b2293ce52ee234aa5af55b0eb3afb8b5a1d283bde8f3580f5ad1951d8bedb834eecbac86ca72435b52519091d94647acbbcb1b55dfd9a531c6c966b481fefa1396cf42fbe362ecf403fb046aff1b080d47bc282f4d053ba30c2a00364e11ef82feffc4096df1f8ab109b45331611a8ac84b8df0b7b94952a5ac80b075bffbf16065d8e5a47f771c0f983e045d4104b7e8e5226ebd9d7add387de852df26ee9da3ee70c7e20b877a45797de836548664026a380f306705232ed37f4104114d58065b1c74441eb9cbf00b8073325b40851b44033fa4e65148161b0de0c1517b6830cf5417ea3c004b7465c48f9b2766c43cce5738e9eef6d9d0f296dcbdb41db35924ec1b746225142775268908a63ebe1240cec4f02972523c8c7de4b44530d1821bd43694647f355fc0473d7bd4d3e6d30ea453efdeac396e0dc03f796f70709f118920f8a76d4d85da2b5dc2964a8824bb96aa892e43fcad95470cdde85433d5cab38424609a9682e1fedf7776f2d77f2ffd9707ff110387de49f9422f11933d6cce6ddf1"
+            },
+            Test {
+                input: "b8d56472954e31fb54e28fca743f84d8dc34891cb564c64b08f7b71636debd64ca1edbdba7fc5c3e40049ce982bba8c7e0703034e331384695e9de76b5104f2fbc4535ecbeebc33bc27f29f18f6f27e8023b0fbb6f563c",
+                output_str: "904786dcb5a8f3c4be4dc96cf168c65efd3de65fbe92dfd96b1cb99f33581f561e02a9d85740fc7295726f36f966392956b2c61122481d7da372662d0f2b42beb4228877bb85a3afb52c689b3da75637b52b81b9182ea56980e2c0afd0d27644d0cd86b770fb3f4ff2618ff000ff7846055449e1acb3721f03a0e65fc377f189824e06b13ea6a797dc7e8a8af064075a9424a709456cba62c43b51f4145d6f5456159678b09ff1a97bb19f4a41a836b0e6090617a2bb9b9abb7d4b6777489ff1cc36e6ff828bb27b26dd61245a3f583839f4efa1c453d6d5e9b2b3947eee25d006de476bb37d505fc5f0ac0ab97f8b56b8587a8ff2eb61c3f83598120b469e9cbc5fc03afe2f72ee0b117f818eb8b33cd538afad801cb75d4b2f51578d628a1701df56b9b9bbf10a30de0893b6e3cad4e264c5829b1c5c35b3a1b859ba7e49c29c93f98e69ebebf8909f535956dcf767c51e2afc49103c052aac1a39d02909383ac02ab8220e4985872916dd6deaa9e3f57475a33b0dec69f266f1b990df7f9f85eaa82fa226dbdb94292b91c3f124b8ba13c3abe0908e52b67ea7131e61afbf20293a61cb3659415ee890c151a5628225d61ded612dad545b62d819a4f3d1ade9cae43b9cfdfa4c32a8d16116a58ee3743483663e9401cf1280da465025efb103139e4e8850d1329f1b9bf5e1a8c05d20e963e824eae0af586635d19d13244d"
+            },
+            Test {
+                input: "0d58ac665fa84342e60cefee31b1a4eacdb092f122dfc68309077aed1f3e528f578859ee9e4cefb4a728e946324927b675cd4f4ac84f64db3dacfe850c1dd18744c74ceccd9fe4dc214085108f404eab6d8f452b5442a47d",
+                output_str: "9fb52b8120553ca1f4b801fcb753dbb0e45af3f160749a05fc2adf8ff1f507dc304214d785c5e0797c2f6f767d76a3ee22cbe0d114f5f8c32bbf8da8505090381e16064c001f1807289d0db586c09a85ef727f393bd2ef1f95cdc1777e137b43de60d425c5f5d685d43d5f6912458fda3f4acecdc2024cb7e6f4340fcf6333cb29ba1801aa80c0f8a248a21305ba62d62e689d55d905eb03368783cb32f765a55d3061774c9344e85c35f8b944420f47070b34c9e8996c281d890e591d5b5cef03463d86e88211917e7db7f5bd4f36565bd855efddb859c97c206d5f3836840ff3863b93e17aa19281202af6ec0b1b5dcc7c00d9dc08c2dcccae41ee2fb8e591a4aadadf2b28fc2133067d45f98b4ecbbb234593159888f832cdf1bd4864b8b720e42219a220c7feaf6c0d6a1c14af2f1020218c65a475386a71788f7bfdb172b12819f2d78d6d200382992d9f39500c4f15e44e1e48fd5734d110ffd1967e098f673492630074df33434c36ec9fe067e8e794794191f355c2d564fa4bb691702dc55f4e6c83d1c487abb281f0246814a1ebe626f05f06d09a371afb4e746653872f83b42509504b057db7bf06afdc913f679eae1fa4d945b93c4bb07e70f48f147bd668b121b05a777a5637cfe24a2bc155c97b9330b3e3b848f689a00ab1f916f321fec05763ddc6d6563e7aaa3ca309acecbb0884dec5815558d8ff72e820"
+            },
+            Test {
+                input: "1755e2d2e5d1c1b0156456b539753ff416651d44698e87002dcf61dcfa2b4e72f264d9ad591df1fdee7b41b2eb00283c5aebb3411323b672eaa145c5125185104f20f335804b02325b6dea65603f349f4d5d8b782dd3469ccd",
+                output_str: "906bfc0b13dbd86acc32b93c56c7187acc1e5984c1a7ab8cb4ec39a00355837f70b6790360ac9c447e28e93cdfb58cfab3dc8ee4c2378e68298eca240869fb5652803f590245f8f40810febd33ff25794e39758e9984e47626eea8ab2145cd2e260873d4524759a855b2da0c8a80c6c365e76e8b37ab4b9a6d9882870dc22f61a341fc932152be5c84af645eb71e6713b1d9b582491653a8365be531d565b27159f9c5c7faeca04fe1e626c1c9a7e7ff3882662b084b827ba96e865b753fe73e3936e47ef9f1ea151878f671af51722a4755041960ec2a7c2c4cd364c4914f64e90bcaffbef147e935a6b03166065506fa7f20a707ad4771ff026d7bb0db7e744fecd63782dcbd9da7573d77f82e6a5446b1595f7ef81084caeae91e522fa604a370612a6bf464d5872ecdddf46285a407d7835e22438e82e62ca0f1fdf7b420e15f9dc061a3519b8f389022bd06e9b31a34f854f0f75fb9cc538adc0ae1d981db68c17e6f3a91d6c60efbaa357a49fbd148ab7ee2d96eaa8909782e74a9895890d02fe8c8b09b8a9f2a8e18200825c51896c42c59af9ad93d847f4a4fcff008d1bb8d6bb2e7c75912a086a23646939de69d7bc42f568fcb076ef9c37912bcbc0259ffe04ca17f799ff7aca1d34fbea76ebefdcf8d22bda634de9b6852a5da831edd0b92ac09d9d8235a0af2bd5fa6b0157722115561efe7c14c22145137d729"
+            },
+            Test {
+                input: "b180de1a611111ee7584ba2c4b020598cd574ac77e404e853d15a101c6f5a2e5c801d7d85dc95286a1804c870bb9f00fd4dcb03aa8328275158819dcad7253f3e3d237aeaa7979268a5db1c6ce08a9ec7c2579783c8afc1f91a7",
+                output_str: "e2746cd339332913e436fdc5b21215b39d0326e95882f291849bef33afc6c7b9a02f438c2e6f4175de5ff04b79256b845213b917b34a0111814af58b06c8b5af9d2478ad18f012373b9f030abb79bd7bf380c2c2ef07061e75d7ba113845c80e43bb718377732064b80339e8316068bcfd37abe6aea6eda3c58bbf95a77799155b30fd6776012f098ef9f29db911e11baa67937a52ee25c429836fa45a2adcfbc704a404af8421fb3b75dfea979f65415ce0e9b6d17b2e5825929115dafa8e9a51e16f8e2563876702e04854d48ac2159bb782aa6b1b764a8359f7ec423cb00e9915bc63b27f6e758402b56799d7c3093b1a222ffb8c0f08273a6d5115d2cc7429b9382763807fcf97ba5ee82f78f835bcfa65645ad36f56d595ed06924574b581d6c460bb0209cd69581732ef9d1de78f0b8109a6d4c271f2ac07179a84bf36ae328b1d0862f65b4abfffc0e4b6a17fde288304234cc2447abaaa223d16db5aae8e026d17a9addba9c51f3b63446defbb9cc80323e6b22dfee9d9e438bcf5e14eddc490d9dcec2f5c635d32a1b6c64d1cfd07dc72e954c97db2a6e82db75575172f6ab0d4519158f84c836f3b7b4830ce0856c37839dd7d7fab6a9ab00f9dbc020ae45c6450c257b7c0661cd75f515ee380c2864f0610a682d49cb4d19409a317aa0d6667e3e61fbc2d9027f4a5bf4fb1a0d142183f84ffefeb92ead6ecb2a9"
+            },
+            Test {
+                input: "cf3583cbdfd4cbc17063b1e7d90b02f0e6e2ee05f99d77e24e560392535e47e05077157f96813544a17046914f9efb64762a23cf7a49fe52a0a4c01c630cfe8727b81fb99a89ff7cc11dca5173057e0417b8fe7a9efba6d95c555f",
+                output_str: "0b82455171770082ff4a4fad8a5de99df716033d27071278e9c1256d63c34778980889fdb7661153982eeb0ff904e24d31c8d48d89f412178e527d054f822dd2df6c4fd555e55ccf3452fec05f9cb3bd4f0b4d2ee851ee3e22ed180f0c02e618563ba89e42c4c6a7da1a9256029b6449a9c63625cefcd003f936613092cf59f676ac91298c820436f58bcbb2f61f3945e67353c854cc384d607dc11b906a1c1a5143d9aaa294cbe03f946cf2703c0983727faacafab85c6725e8a9caa7aa69891799c560bf6b885255674a2940deae220bbda252e636c4526449ba895de17312ee0bd0520fa68db28bf122219e571c081df18c2437e4174d1d6b529e394c4090e5fa957a996564d11a3b4652522fe2999903f6095422b4aee2d47f2cdd4301bbe42af671f58228d76d7cbfdce870242872ef85d0d1e18cea60c87565e48a1463030566c9e34df8829a58fa36770e861d6543b50ac6a439abc062236a065bbdd866a237c09897f3ce2ea5b0b1d8b576048685a53da7a409fc6f121da36ac23b9419f254c76e7024faff9d45bee4392ce4c968e737e8f9eecd4800f7c928e30ef664fd4d2a7150954e0599ce5c4f07b9351a408ce35166da4240f1e751ca4a7cc4946f5451a0bd137857dc003b61424a6682d942f4da9644672ece7a1eee295eef46b5aaba3f46099e93e01be7ad9a5e27d378701cf9514b374204d387145349f5"
+            },
+            Test {
+                input: "072fc02340ef99115bad72f92c01e4c093b9599f6cfc45cb380ee686cb5eb019e806ab9bd55e634ab10aa62a9510cc0672cd3eddb589c7df2b67fcd3329f61b1a4441eca87a33c8f55da4fbbad5cf2b2527b8e983bb31a2fadec7523",
+                output_str: "4167bce24865262adadc78e611a960807758ec6d0d46e3cac221b4fe9818937092bd3ac5219f0fd765b613f2eb7e36a5f48fcbe3cecc67540f9282db1842f95cecf0648c12e52e7ea0c96ff7249a8446d0ddd7625bc55568642da2f2cc897b14d2995dc382293cf2dba9a63eab9f6940ac9ca87fe5cffa196dc930ff3353e34313894a3d2a0a86b0fcf7631735a2c663bcb71d5947c4b2e97441982b791a4f20bb86f7fb033210e4fe58dce7256309fdbecd7d7f3fef2d1df7e0247ff981d417c56eb7b14b7c9453786c7b30f173c372275324e834d94dbc6d10714407ea7886d92f810f2dbafd57484a09d70951cf85c0b7820643d0e7ef706934cea0cccf94b1d1f75f1e05b5d033a5ce1f804c3bc7a9ccf00c8cfebdb62f8c654805c5acd4fbeecb6745803721d17f2b8303a98abb9b8618107b4493735b4001757890d772f78093aaeca244e5297cfbf0b9442370c9fe0efec199201e8667d61fe4b9ce20ede827433c91f521ef2b296b15cff658e18226f17df114675f57e988a14b9f104f933bb685a3a9dbda96a9b87f2eafe028a7c656300814692c3dcf00d9f07cff361f601bf2a1fac9ea58d7543604382ed7cf35de7ad7355247318796466081fbaa05fdaa65665448de1fe67ab560250a213fe60f506e9eee720fa762af7d2a23492597bf37e0067997095ffd63480bfaff67c084edc5be6c0bfff969bf06e25e"
+            },
+            Test {
+                input: "76eecf956a52649f877528146de33df249cd800e21830f65e90f0f25ca9d6540fde40603230eca6760f1139c7f268deba2060631eea92b1fff05f93fd5572fbe29579ecd48bc3a8d6c2eb4a6b26e38d6c5fbf2c08044aeea470a8f2f26",
+                output_str: "4ec44e5e1f62935eca450494add6aef7db1c1c8353f1354c4c9366e9e56a8d5bdd02383b9a04ba4927959531b9169606cd982b6b72927d2e433d900f3b402d7f5bca979b3742e2e2c1df8d4e163628357aeb37c94161f8a9269832dc28a4e4983b45140a5a7c9a4313fe39bb2c117453c2e5cec3c0d4d5c1169b042e319c77712c0171e3487c590fe9b223b7f681f6c4b46adc912baba3f1e190cb66da0b38b3389abcaca3d4eacc26046cc71c4b3ee1520ea84a1b8897a7e39b9efd65130de8f694a0a81f4ce994a0f4fe1cd94439d6551ca8b695a5f22ec51022ada24c3ebf42840c42b2e345f8ac07bd5561db40d66da87fff248909eafa8d35c380133ac87303c83a8368492406b45424cd0c7143bca5bf6ddb6b2fa45fdf45b96bd1cb33f16c1843985c5a8b1b902361d10b235f3965457ccbf2ade247cd371b9ad808fecfd503272d4918bc3ca6edf09bdecd56dff372de8e2e1d35ccf55e7e81ac5dd717c49f492bd1b242331eb66287f10e15d7bc69dee9c3f1032c162b0845083ed653d38f270747510f82e43f0eae6ebdfcaf296d360998a5ae8e735fce78aee2332f7766fa8b289b46cd1f129bec02dd6c3d7c63d544c22687ad7e4802e0363d05b8b7965c1d9c9ee8d08b0b54a8d55d2a52e0a053d31857ef350c713caf7d7b00fa5513cbbd6fcccaac97501e3964ddb3012d2e101c59cb8fd8b28aa567292e27"
+            },
+            Test {
+                input: "7adc0b6693e61c269f278e6944a5a2d8300981e40022f839ac644387bfac9086650085c2cdc585fea47b9d2e52d65a2b29a7dc370401ef5d60dd0d21f9e2b90fae919319b14b8c5565b0423cefb827d5f1203302a9d01523498a4db10374",
+                output_str: "4d2597545337647a12662a7a13065021a6d206ebd13459db348c1f5361c5990daff469677e61da9a4add24a1b4adc67a092bdcf80d98c0a858ea96b0be188619a82a1f5055b461660cf805ae75e4f869cb830e153e840d6f164deabe9065695f6c8f982bbb7d2acbfcd7de93e8028ac978e0d78ce878d3f813abf1e1b51806099da8d76e16c47d0c1d6cb70e766f5f3f2336642b9bdc2958deea3d6efc30fc4e54a90fdca6bfa5e8d4410d38cece522b3a32f11d4599d464e9cf16949385110d71d86a2943c03e67b19da04ecdf7d30a3b9e16d256d5cb1545b1312b6e62ae028d61317e689cc3eac351b034e83cbe91140e20e292a3af44c27a026dca5674b9497a10876ca0f21d79184922ce71fc11ac98072c2368f70d113a413e2b9faf616e3729e515fe22146a35cb93d0178c1c07ff9f403ba947759ca0fbb09fd66c7eb562307f46c074501ea7418fc64911ac940c28e75e2146231e0b94893efdb0ded97478796e87dd906fffe9232368cd0673f9966e7b312c44f26649355448fe2faeea198a5f6eb45040d56068e5b98c02dd948277e1fe5061effcb028b61748e2d10128e0e0f7b70ec8cc6ffd071c65b5c1b9ced47c9b0df76d3b0a5255e27391409b07b0c112ca444e2e926bfcffb1ae7b00252f6831fff4992d63ba2114502df0a3489ac58f463c8f9a1b3cbd3c8836f4caa301b7336d8dcd255c0762c15e24"
+            },
+            Test {
+                input: "e1fffa9826cce8b86bccefb8794e48c46cdf372013f782eced1e378269b7be2b7bf51374092261ae120e822be685f2e7a83664bcfbe38fe8633f24e633ffe1988e1bc5acf59a587079a57a910bda60060e85b5f5b6f776f0529639d9cce4bd",
+                output_str: "05a819096b5b6835090cad5109cd34f40a234f1569b226c42f0207ae06e6eb37a50ad688c81a98c9e747beb1bb2ad741454430c0e36a8b4de03a1de7c3d1fbd836f90ddbf10b10ad9dc427f0039de7c0a8336b10a5f2a24ef2a0de7d5765abe3eccae743ad3339521d78006f5859339f15b5a4c82fe758294cdcad306d30e57ebfca0c22042fd0ca678bf2e5d59cc39cf1174b1629243115b9247b620bb14217c7edea7cbfacd209fe77206275ca39d15f6995e27108c9740a27e98bc205606d68f4d5592756390dcf9c3b5c58585142bb6e31928ab39843538001d792db744145e5e148f15336c1d6f334608d514c8a0d28515c17cd88c47aafc95a7d42785d8425aae5d2d8d74a90914aa30bd428f0282e51445deef80b7c1a4429e4e810c753de4ab21d2e6e895fa4797f3b4c267cfb123c337cbe0ed977a9c3d4147780dd20b2e0c1781e3a8ec690f3d32f38d55d8ae641f61537e0649fd681857156837dd46d1e6005f5747882f895684a6817d40ea1df7b6b049db621ca257a3705896da9b5e38a6d5efd1d2fb4906285b1af522d34a5f141c1b72e74fbf02c9bfc38d744c4d6b77c32317774f4f3743b7e684a72ab54beae64994f20dc8ab350facab35726b55667abcdc7cdc18576076b5fcaab6264687d497d32ec0d0a5c42fef8899441f36f7b72925326885e1b67d59d7bc7de352f8844f44c3b634753812844e5"
+            },
+            Test {
+                input: "69f9abba65592ee01db4dce52dbab90b08fc04193602792ee4daa263033d59081587b09bbe49d0b49c9825d22840b2ff5d9c5155f975f8f2c2e7a90c75d2e4a8040fe39f63bbafb403d9e28cc3b86e04e394a9c9e8065bd3c85fa9f0c7891600",
+                output_str: "b83d4f95feafc7e5aa60bb1035f69c8074b1a25ff516ad6a18de1808ae64ae212b63fd05f983a65baf28b228ea3ab587b163e334a70ecea2691a77ac940259827355c5459d074532a3efd811f419e29fd67d8ce82bb4f79451f6ab0a8eac6bc48713a04f318aa45da6246fb8cd9c866fafc9a48c5e6c6d05d501d00e08f7d4320e5e294fca2b6439dd7ea3bef65cfcf256e9c4e6f902bd9f6aefa2af303e0028d0dd0b7e266f31e21a23f546fc4ceb9bea5a4034d3ddf7bf63b546f8a1d73f9f56e1c70b6b5e1ecbc244651322025086a933d94d1f21c9ba03493e38d28cddf351f4dec99c734589cc45684dee9aac79f367b940d6e1ab57afdaff422f9d60e83fd6a080d60267d19de6626fccde0759697dc7ccec6384b7ac7e936a7f12e134c053b80cfdc38609149b277b9f6881495562eb466b99d4d4a1b80c3751f51b3d53261dd5bbdaf1b5401373140c35d31907ea197397dfea7c420a80c2151e73e0ee8e27495b0c9eda13b93e8ddf9426c26995317cd273960301973faa9aafebdec14d92466b059d3fa7cdd533075f5861c538d69de08f490616b650ab5a0fd177b500f05e011ae3ac06c2480816770d0eef7908761af08302dfcac984be0b3e60affcf5281fc6e28aee30421e1dbef6775ca9bcb2803954c0be501d55d5d0a1cc7882ab5f1287b5a3ef564b91735b9ca85d5e7103d0175b2ca00eac7b627bae5e"
+            },
+            Test {
+                input: "38a10a352ca5aedfa8e19c64787d8e9c3a75dbf3b8674bfab29b5dbfc15a63d10fae66cd1a6e6d2452d557967eaad89a4c98449787b0b3164ca5b717a93f24eb0b506ceb70cbbcb8d72b2a72993f909aad92f044e0b5a2c9ac9cb16a0ca2f81f49",
+                output_str: "5a81fb81f8cb6473c04930bdc5c0a9ca96d4a500a7ba5a9167491573aa7178101d64f46a93486406614ab9f397e78b0198fc988cca849ef70c39b0b3a844493439ceca2b7cff8a32d18285bbd32b1e5ee26ab0f82626f4130c1b40cd6e2c9dbd6677e6644a1ed6a016dbda139b868fc2f7c9263bf4535e8ecc24dc626b1f3abf4b08e229ccd076dfccd89c8eddc77e9ff0252bdec35dbf712cf0a5bbba7b4c7b702cb9353ea4ba3d0e0df48d6c56d0b51ca269c9e428b22951555c8ce65b5704cc3f4ed38649474c4c049a63894405186e116e616d686c7c033cfdb75b8202fc6b6eeaef697a4f5277da6c5e7eb9814a6798262535292ab6791633cd687e68ef223464493ae8d1e27f8b2f483f5b137e48f4390cc27d96a694971b28c9cdb1a24648a0e0573141da6a1ab54789199e8e909f6fdb0766dea735e2d87ccbf975fe8cdd6c728df888fed6f049008d349a476eb63a87e0cda622f9b611278868e8396bf4e878bfb58aa847f04c2e3a90dbf386954874bb7b1e8cec42f1ac16c1824f328af9cb154cafd4c9e2348a02b0f9638c8562655cd5e3fc2bded644db61ea0c4dd27e8b79c7be52f55c321619b5c8beda60d00dd3da3c19d4c226adf2d5c4a66518940f2441bcaffa704c80900512516be2710301579f023393892fb27ee9dbc71ad34ef26651e133b3c21d8914bb6e9446f11288e1a76431c3999686881d62"
+            },
+            Test {
+                input: "6d8c6e449bc13634f115749c248c17cd148b72157a2c37bf8969ea83b4d6ba8c0ee2711c28ee11495f43049596520ce436004b026b6c1f7292b9c436b055cbb72d530d860d1276a1502a5140e3c3f54a93663e4d20edec32d284e25564f624955b52",
+                output_str: "e41027e76a055f0a826481c650fc24f7816460ed519af8802ab191e411eca719ca1696ea14cd62306071d4e1dd65333619d0193d9830b6e8796234f892010681923bf30a1a0ab89d82e36dcef3acc00dd286b84240d0282f5ae182ffb84bda59531c519374ed5a2e80db2137bee790cf49b9faa524f75abcdc5ac3c3027f6dca443b2cb5976b9b8d66e9eaa1f9f62a23d5c9a9d5fec16a5925eccf1021d3253bd67f471ba1530c0601dd96a4d7ed6e37dea3efb24284b61002158af78e35f8bd617c9e7d33fa4128c31980a6d8631a009feb0039b635d1030c200ab651c3701cebe8f2caaba57e452c0e8fe41facfb398a2769aabccb21ad2aa39ddb53ec706e796e7327e30fb4a631e6f2a35a8dca86769bf6697f8490ec5980f3143ea2fb79faa9a5f2ac7b5030170a4548af817cd80c26e1b013bdece9cbfc553464f1597077e3ed435804dcff5fe05bd39e87b9b35d9f2810c32eef8e30459566ea3cf380a7f9e1e2bd3e4843d06b018b55006fdb22ee1ccc0ae615917e8d17fb019f7419fedb242f0676ff4815989821135073e5cf91df42cc6c6f532d3bd8be9118ea6e583d360f1f8c20600a740d9310a984af3c82a48fba84a84aff42f2f1ec8c4115b5704704ac2073f2014bbef1913fef7862f514b198983ba63f4d38e81d822cfb548af76f561ebab987b208b11824481309b7aedf0ef44376847162326193dcaa"
+            },
+            Test {
+                input: "6efcbcaf451c129dbe00b9cef0c3749d3ee9d41c7bd500ade40cdc65dedbbbadb885a5b14b32a0c0d087825201e303288a733842fa7e599c0c514e078f05c821c7a4498b01c40032e9f1872a1c925fa17ce253e8935e4c3c71282242cb716b2089ccc1",
+                output_str: "28e204a3450796ba182a339cef54a3b224626681c51297a71c2bc0add56bf57c7653badcc1438e3cf7156ef7ed4ea9a084f3041a8157e1fd2aead827a5e79257c1bf7e37d4fbc089422acfbe116a2e3889614b8b01bddcf63b66589061a690790357bc31c68014ce422060cab07f2a254c83e1a7a9ac1a0807462e6de48b194ae5fa0d6bbf39ad1835c86bb25f5c273cb266dd5167350904ea22f912343e261e38b298495b38019724a1eec356ed016bde8a81b3764a39d153a5691c196557e6fd50dc5e42b6e6376e388d9c14970b67e9910499d94f5839ed933246dafb712a122043d7d5047f1b53923c14979244dfed3cb742c1bd30176985ae2f76b912a6a3ab059f2bdc49da4eb6a9d3fc9cba1dfb1ed0a4acf46829d51fda861b8dcd62424a6e4272a1bcf28ab878fa9709db43d800e9e6e33f6d644b62ea30bf758e496bd152e41715e6aadd766f1fc6bb95dbf19f497729bb30b29fdc4bc4f5502396969cf6957be8fa7f17a4f04a6fde71264b0f1b40effdfd560868056daa10a6cce695aa8a815e43121c971e4c4a3fc5e6eb27170d4539f3a37a4665f179cc6c804dbfb199814fb2d5121fbf93a472de6f4d1db176ced29f254f228538b065f8494adcdc3d1117b33a1a51eb1ac3f6d7c8315e5a674703827c0c506977d1cd68873b4f18d9a03ca54f74d7f82900a27e8863ce13e92e0eaa86c2cd5bc99121f1d0"
+            },
+            Test {
+                input: "433c5303131624c0021d868a30825475e8d0bd3052a022180398f4ca4423b98214b6beaac21c8807a2c33f8c93bd42b092cc1b06cedf3224d5ed1ec29784444f22e08a55aa58542b524b02cd3d5d5f6907afe71c5d7462224a3f9d9e53e7e0846dcbb4ce",
+                output_str: "fe3145a2e9e54b8888c1fb87a70402eb4600b0a2d636dfb23f869583900544f602b9dc325b6a9e8c0a9192602eb5ee581e3b0be65e918dbbb49ef017f174c3aeb12c20d13d20c3370e1cfc19634899833a91375631713db2954a8e33ca839ee5f12703c814a63496bb438195d89af5cde1f22ed8af340b72b6fd95660bb304568af54f162d47cc3783806274f967835038858719a4e3115e76690b4e848fd6acec695b3174c7bbed140db8fcc2187fc0585f4e975fa5ef3907588e415638f1487e6244f3a773f8e2b3d9c23b4154509f87564bc76fd437c718bfdedbdad24e3393a851eb30a82a641d3b144e3d9d223b1e92813de477daa28bc9cb621f8b3d06b4a3e3f9a52efd9095365976144325269160f7b859ec570a14dd43057bf4ab3cd2ecf13e921fb8212f4379c59b332fa1817360747f58a63e0f635fa52c59e31962951aaa64264dd3f26eca0af7c423c0d3dca624a4d33c383ba0f4e04630d74a40f760349116d6cc1a8ba17f228d7bf24af707d130d13ac825db8e6ed4b97b4aa589230ce9a471decbb2dbac9f68269030add24c712f1c2ce7e6dbd330deb3249f7af42e31e717666236de7299283063d3dd6cc88d0096359a1e83795844714bcc9d88da6fba06d1156114c62ffb5d9a58274ae471d544d7e9701ecdab9b63b2ec4feeb07126f8c1cf8bcae823e7bb18a9566627cf95e6d8af7be94275932629"
+            },
+            Test {
+                input: "a873e0c67ca639026b6683008f7aa6324d4979550e9bce064ca1e1fb97a30b147a24f3f666c0a72d71348ede701cf2d17e2253c34d1ec3b647dbcef2f879f4eb881c4830b791378c901eb725ea5c172316c6d606e0af7df4df7f76e490cd30b2badf45685f",
+                output_str: "4a021c69d45ecf926fe7592ac05951d86facb97509b459d0459cda7dcf2b084b91c8550a9f2a92c490c270ca90c41018c4f205e5a33b1584fb54bb1f163a3be83df0c721235e24d4410f73b2680c0835b840db4c4244c1f85598c2b3a50a896f40c8fd249e99588a8ae1fd6d706a394541b942ec543343fb377854141a35bd35f10983543b17fc5c30b31f86c48f601506c21ea462420c5992f5b5dd12ae33cdd99bdd92667d4bc87410b1456929350d06c91a558a2a17964c3eaf7bdf67f743af6adaaa92766f36655a9496263b38f26a7f1dadb95b6a5b63f3ff9e0081f61d0351ee557199851596e5d221ee891cba27349b4ba671eae59473ff0c30f0daa2f9706977c79746c8c1b70aa1397df9f692dc4d1182eb479c98343de7bc11d940dbb778ae8a75ff09d3ba328a032122318c021bf07ac179bef0ee42fde3d8a64fa0453057b1b2ff6804ac6719f6823270647e142be5d338b1458f8cc7ad7637942ad4f0fcab36ea6ff768273362b8ef001d50c4e5bdbe74f48dd91854a92ff02872c0963a2c2c52d0156e58ba1df0b7fd9a178de79cbcdedc20ca2a226551c86835ae9ecae09fff19aeb6b114f7cc602065cbf6a6a740874fbd6662a3ee1d407337b935c4975d269db7c54c453ac4674b9cff128dc20c62cc86b9d14259e06315eac81923d415e1f35bccf48f48bf655e6b87f8a0b55a21ac760bdb828ba351df"
+            },
+            Test {
+                input: "006917b64f9dcdf1d2d87c8a6173b64f6587168e80faa80f82d84f60301e561e312d9fbce62f39a6fb476e01e925f26bcc91de621449be6504c504830aae394096c8fc7694651051365d4ee9070101ec9b68086f2ea8f8ab7b811ea8ad934d5c9b62c60a4771",
+                output_str: "2d008f8ed51c6a86910c30ecaf2b6441262d7cc66e54b39b9aabceecaf2e96a0b5f1cba234f45242bd8f96a57baa98cad302814c95e067cf8f47b2a4e6fb6bcc5c70a7a750f754824e9f970e4c54d43cf8f4e0d433b931df2b6beb10fe5b28f2a6b5cce24d0c6b414dc8e3c064bd3b26ba82e4464b34c3735e935ec3b7aa36e6af002a0aaade986b0a15af0e9f1ac5b8cdf3e9022cb6d2be9cf5b30ac8e2bb5e766f528802fcab3c3c3405f25367feefc12f1c7d99717f2ea62d7001b4845793b288dd9e777270608fe40586605af8c9ff52d0fe4111e8da8c315958694abe386c85a86aaf2038df6281d8cd73e201973704d314dff7a5c3b4d6543a34c6ffc561195cb3b782c1acc2793ba6a75974126bd3e4188faa0e69b255336366ded52d809d6f70daf11ba57b604ddc8359c1e5d9e8f2863edfe71935ba18a4d373e4acb73cca7887b0f3a84b2bfbb5340afb87beab7e3708484bb4ea2e17cff49dab7236bd83dd11b2761af3e7e58452e9bafe5c665abc543f41d98c6478465bb67c6d9adffdefecb1adc2e22b97504590d07fc112e03d1e221cd860928d13995ff1db025927b2b7edb434df01f1692ab329d07a1c6947e64258e53a8082ea6945e1fe21acbcc1475054a0a9493acf37e5b607c79a54c985e70a99041f3eb3d5511390a1f81fc845c9e29fc39f12d019a0de262fa9426c123ec8c2c733adb2217deaab"
+            },
+            Test {
+                input: "f13c972c52cb3cc4a4df28c97f2df11ce089b815466be88863243eb318c2adb1a417cb1041308598541720197b9b1cb5ba2318bd5574d1df2174af14884149ba9b2f446d609df240ce335599957b8ec80876d9a085ae084907bc5961b20bf5f6ca58d5dab38adb",
+                output_str: "7a46b367baa023ee1922a3408b145dabc97a55ebc78cfff95fd8d6206e5c10efc9cbe3644a49c200097ba79f68b08193c6914e016dab98361705d27b8b046f087df7dd998c02bc80bb173772843645c4f93080b0ea657eb0902afddb28963bfc845adaff3a431705c74d92346bd678ee699fc12e9b06e0c0e08785a419cbc944e770ccbf89203faf5d3b629d541bd51eafa5857f585537ca60ece26e09d6b9d05166360417b5259dfcbddc5b6fa5b653423fe052e98387c97aed7dfac41274d9bd912bdd661a02cb80caae1bd1704320ba54acca5ec6854d4f83e938f8535ef287ad26f9d47d047c74ff6e4ec338222bc7a1e346ecb50a72572d3f7a9621dd0574a9a109979992f18690750d035a65b29f0387fe78e91948b8ea8ea31a074fa405ac30d44fa3cf16bec6d44b5c5791dc2376bd1c192175058c4ca5b1e0d989d866d9e076e8252aa53c5b89d7aafe5b753705020dd7f79c93d31f768ade1f54496b62f6d7b126a2558e4b2a3b7dff1f046f9fdc7bb2902389e1c0fa49e00f4e892d75fbb5a18b22f863b7d57a8f1895b13ac99042b8be114308b730adcc2b8e5c2e6db1c7df35cc9e8160df55bed2c9083a2bf79c8f141e44d48ab49da6a77d7ab22f4e8a6401c9a600657c4e3d66700f452219be1b5008344fd3b6e76d10445853c2814d7eaf753f57a70e0644c94a2e3d21478ed44d6c5d568e68231aa180bb"
+            },
+            Test {
+                input: "e35780eb9799ad4c77535d4ddb683cf33ef367715327cf4c4a58ed9cbdcdd486f669f80189d549a9364fa82a51a52654ec721bb3aab95dceb4a86a6afa93826db923517e928f33e3fba850d45660ef83b9876accafa2a9987a254b137c6e140a21691e1069413848",
+                output_str: "224e3495d98a8729f88069bc2578f98f76ee3d73b1309f75357ef595d217e4d851beef015dc7bb03f9b8c80ad1b132af1b99f42459527fb67abe4b5eb3dbecb90e679454903bfb51e9ace93a4784722b2d0453f3400632a86870a427df2aaf93081af99cfb012807766c440a010e6ea068c2bfe388f26d95bdb1947bdf1e364d252c81835ab7083ae5cdfc12eee193016e5bc5a90c2529419df2c0e14f8fd900d4b9519705221c70db7178b81817b0becaccee975b396e63383f03fc8097ce6ee9a612d53ebc572738b17442c8c5f2d8e7c67073b6fe241e6dd00d356641552eed0d1c32a09a34223f1d3e0305a38675ee066b63155bc2b7851e0f51967df90aac3ed7f88b1edbdf123d02c2f4ba23fd2f1da2cfc2410cad5188975bb5465f502b33a4f41d7b2dbf63b71085ddeeeeb6b9bd0c9f89f4424f55dda4804e86e2b983130b46403fde7b70c5006fea04cf3350fd6124c735613dcec7696fc3f75ceb8238d09d1b440e759afa129788a91c43ff7423f05c6e9132f644458ce8369dd714ca9e4841dfbb29b942475058837ffbf1f59706915ebc473868a718f2887aac888d2c7fecfc1f8e5cfdb5d3b2c71cf1ce400a0cab18982baa41b84415a0a49a25e18a8f4575b46a544f1079431e5f07915b92d8ba512340f2e43b689dee6118786a2410d58ce5ef6e8446ee49ccd2a50557d32fd1e9e0954a4373545da250cc"
+            },
+            Test {
+                input: "64ec021c9585e01ffe6d31bb50d44c79b6993d72678163db474947a053674619d158016adb243f5c8d50aa92f50ab36e579ff2dabb780a2b529370daa299207cfbcdd3a9a25006d19c4f1fe33e4b1eaec315d8c6ee1e730623fd1941875b924eb57d6d0c2edc4e78d6",
+                output_str: "cb85425a1cc6a4fa6d8593bd03206867737f8d749d2bd7135ade0d7a1f216fb92ac5c4897ce355835490699a0f715a2357100cb8932befadad55c0b5d90c909f0272f16beee79ca7f7f1002f711bfa3bde142fa6d5c908e8f5923291e0d48495e50de065cff609a24aaf17491d228e5ab226e21e790c13f8917c1284be0434c8b2b2a3cc672d484a25a47820390fc50f2736faf26e65e09db68f52a9a65280789017f1336250d41c0df4c93af9e94036e598e6f06494068f4a59813d1396b00e65e179572fbec6d30ddafb3a898cc244e1b0e82043c1470b7602d0a65e455d297770265f72d82d584657316e52caf4c8ba8cb4e3ecd82433dbdce526ebc60217529cf03548cb114d7208b93726b5556e4dcbf2764712144024510af30265fd4fb13e38ba677b34d69409f91f6f44df602c9f84362767d1e1b587054ff7cab98a3cd4bcd2319278f0144da884306660dade52096a10928c5af800819e3d890dbcdba7cdf1bfa4d992074d60cd6ba33c98ce2d9d849d60eda8307b0f509ae78215ba900d5a571b3eab6df1575d7d2b8cac2f03c4b552e5247aafe2349f5eeb0aaa56627eb4d5c33c92d8b1fe5d591fd25828a5114c0f8b3b6e799bb69adcfd03566c7959d1db21b6feb79e02006d1920ca35ceada75b22a0b8235e9c6182872377b56a762ac54a719d8aed8dba18ad925fd21c77e84d92a75f3feb8692144f7d28"
+            },
+            Test {
+                input: "5954bab512cf327d66b5d9f296180080402624ad7628506b555eea8382562324cf452fba4a2130de3e165d11831a270d9cb97ce8c2d32a96f50d71600bb4ca268cf98e90d6496b0a6619a5a8c63db6d8a0634dfc6c7ec8ea9c006b6c456f1b20cd19e781af20454ac880",
+                output_str: "93bf13dcddef177eecfac1d8731237cbf8ce4459adffc34289016a689e88e5b000553f08989ef2b007acb4ac69edeb6ce2e5a7f85c9d75f7656858a7b824472bb89c2d25701ccef18e8707d2c3444a28ae245d337cb3dbd4e2000d7c44d474ccb34033ab203d9b1ca69816ace4569771e1f7f66c7e482f81a332d8d16d0a4ab5142df5742570acd048c52e8bb777d68041a67e870946aec83db5464ae2863020a4126ec32e1d64b5b1a21425c66471c7fb6c5caca4091a96ace9bb25dfe5627562892149ef463ed60d03549cb9643e9bc7403b244a0e9a5a8a38fd785984661c926fd959117c229ebd357847f853768f632a0a2a0f1703ab5e130524a33f825731740ad0b08df92f8ff6ee73c1e60a35ded2882675c6a7941deff0d934bc2bce9005dfd49a9ceb0f08a27cc972a66232a068a93c2b4a143c57387c257218e850cdaeb93c474c8b5aec355bba3a4d0b09fa9f7f32534caaa727120c2d937cee1039de63aa5af5803f7a1bb2f203c87dab85aca2e68a88c9c7584c1444024109f9e02cb994cd7c89e87b976a6bf7d75e570d4a11d15640a4235667669bafad64cf940158bba56184aba70e6097ee4f2379727f7bfc5ff67595b3dbbb7efbc13ea4aa9c1093ee2174b5f0304b10a089ad1980c8a64a9b4e29f68f2bce9ab7d31ac30b9ecb5e009169413b64d661e7bc6d909396c25ee3e64de744ff937f2498a361"
+            },
+            Test {
+                input: "03d9f92b2c565709a568724a0aff90f8f347f43b02338f94a03ed32e6f33666ff5802da4c81bdce0d0e86c04afd4edc2fc8b4141c2975b6f07639b1994c973d9a9afce3d9d365862003498513bfa166d2629e314d97441667b007414e739d7febf0fe3c32c17aa188a8683",
+                output_str: "0da9bf94215fda7f85a36b7d31080f48fe09c92514a844e7f8e5a54e422997be17e0ead0c8caf75a27b4d721f63de3f4a9326e74081ec77a71de52aa4e7df346c7206c8acece21f739352b2efd6446878075b585735471a189b32f41cf0c48c0e92bf492752792d05e324fddbeaa786decd3c0e24be3cbfdf160f45cd87cf73e61c643e46772ef8c62daae119e0010fd84530025ecce198b2b86fb6e8ee88f6c47f6b4710e5764f405e7856688ef030e5fb84b24b48292df29260b918dd4fc54c325708b83a9e44ab92f67217b9ea0a488c9b45920b76a7644c38d36f9ae1a48f56284cc354bf35cb53f0e7a5745955e0e9a77400ecf97b0dee9f4b32e8e7dbb100a1749762821ac0746ccafeb49162b0115b4e3d26eb3b9fbf662cdca1cedaf5ad8933c7ec1ce6ebf154474fdecace144f8b86e24b85c4ff0ec29736bb0b778ac071d2286ea20302c98b6883520d5b4ba22afbec4b6188fefeefbc487d147622b3e97dab9319dcf6c7efd3374fec69d575bdac70d400923234cc41435a803dda6f1c1e91802f56d048b5147a1b9778fdce25afa4b0846d7d5fbd04614ea62263370b4caa6e87e0b6d2befca78e6a0b7e5a6b5e891f7bf4accb221359c98b3091c75ffd25805ec452f7251d8720ae51ac49620c6ad376f13a16a269942842facd25c2f68a4b93a5a7ce9ed38c7285b2777af32307d84a84cc5f937b7950689cf"
+            },
+            Test {
+                input: "f31e8b4f9e0621d531d22a380be5d9abd56faec53cbd39b1fab230ea67184440e5b1d15457bd25f56204fa917fa48e669016cb48c1ffc1e1e45274b3b47379e00a43843cf8601a5551411ec12503e5aac43d8676a1b2297ec7a0800dbfee04292e937f21c005f17411473041",
+                output_str: "5bc15e410825d711c7219161491c5f068dc27d0b66b5a7f0af4f86dba7392037e886d236ffc9ea19511aa43fa27dd2c4b8026d074b3033d7184c95858db5f237a84e93065f9aa4b40123aaf318356caba01c20c97df8ecf528f56b22a927c705f6db6c2e64b60d36fadb2d867c0f5a515a2dc7df26b151d700e43540b82a0cc2e105269eb6cabd3148871ccd3b2f36b101d051d60e28fa838c67e8f655b1532976e512db752a2941dbf6ffbcfc0afed99d379d4e86b8c32327f6105bb75d7669a2d69bd7a2c40df3b13899377a29ad7d724574f545cd91a67659b3781b788b4e9efb137be1b3b8d93c491bc70581c241b184c915b651737a0b2a99b50e8786df067cfe443879d4bf2efa9970a2c214e538c2086ac7bc47da706513bfcc4cbc6d5f387a9e3bac080138f2d713c6c9aad2e0ce7a938adf4bfa3cf688cbe7e22fd5707eef2d707e5004cf90dc880e3af23a435a2682f9c117beaeb8f5a57f521708ef7233bc6ad5750df2272ec379142283bf5ef492240335740f43dd5042124c9b37e726438357472013abe81abe2c32e8e859e4d064c3c4220e5f0b5dc984eb1a8bbfd6db41470174bfb8a1ed5df559a65b1ff02ccfef42dd546cff79d34fee13317be00eabe8c6ff6d722d048eb757e7a38c65ca1a7b2418994d53ce8090122c94a934554d0bc3856e041d0a29f8539246924f7634b5265708208b4c59dcc084"
+            },
+            Test {
+                input: "758ea3fea738973db0b8be7e599bbef4519373d6e6dcd7195ea885fc991d896762992759c2a09002912fb08e0cb5b76f49162aeb8cf87b172cf3ad190253df612f77b1f0c532e3b5fc99c2d31f8f65011695a087a35ee4eee5e334c369d8ee5d29f695815d866da99df3f79403",
+                output_str: "d289fc6490f9dfe3335fe9f43131ade538280b78dc2e16822d5fce70e0bb307fc497e1390e04108c66c682fd6edc0b47450ac2fca43c151982f2ede9f82196cab4381f873ac6e21085b2b64c21a1a5dc59c440adf566159798d6773a09fc737b6cf1bfe0cd0c9b90346f1290de5e6aecc1f464e1b3e522df1a986d8ad7c2a42b1a6067a3448fcf9e4bbb2335a3e4276b330c421894bacc448db09f72751d2ea50873a9df900c775d5e36579dc26830c37851bf456085925185b91ccf9a35b36e5358c4cc4f1c807d285421192be028cb7d5d3db67aa11ab666382641abde3f1690490de0d556b0a25016d5b7171ae26592b5c460e41296c01222d074b8c53a9f73aec29c63e54ef0d68fa1e57c604a2f4302b7af05b20d28e5722b0229eab76fdcdb1d2f7e58eebe4bfcc82b4e4b6d5e6faef0ac442b78b483622ebcd98efa538527d4c0e72526d9cfd1f13e24613be03a79ce2612b19d7c9b639d3c2bad28e968e7859d224958c017637458526521c770dcab61a84181cd0e92aa485ac2d3883070e8db9fb5f06eb5e71d10c175e0d7ec69947d1fbff8a857362383368f52c193efc3df83f5a9b6ddd53d736a3543d46388b2845632c00f0676715ce8c1aa3329515495eeaf860a9afdc9630b06e9b5cedcc7cb571179f35735d02d185d7b03eda48d30fc86c239aa3580816f3af360fe78e84364872c2cd9ac5eba876af94f"
+            },
+            Test {
+                input: "47c6e0c2b74948465921868804f0f7bd50dd323583dc784f998a93cd1ca4c6ef84d41dc81c2c40f34b5bee6a93867b3bdba0052c5f59e6f3657918c382e771d33109122cc8bb0e1e53c4e3d13b43ce44970f5e0c079d2ad7d7a3549cd75760c21bb15b447589e86e8d76b1e9ced2",
+                output_str: "b8c21de1f120c5744352eb71eaee81e9de8a8cf6ee3e2394438013d9b1d7780803c28186e334a34b4cf17550aefb58de785e358d2aa6a61bd59beb1b2f494cc9976d67085210d64fd1c8ffb0fe69814c2048d0937b17e79ac9ce6303562065d4c79438e87c7687b8b10ad1e8f9364eb9ef997b09b963c7a57fa9eafed8571f5ff9b7981418aa8904fcc2267f3723fd67a427e7cd3d5ee6620be53367aba1bf9d2ee74c33be1049356cd8a3b4ae481748872717394d6793a25cf02f95b6ee62efd8e269841234f07041d5c3940c7bdff37686b8e72c23342578fa0db4dc21f4dc03d3539b851f5441b54bcd991322ef0fcc85c14def9be72b8b4294ef34a6620854c291f91ca67152b48560683df13f4de00216180391aea39bdd22d563e48cc622bdc72c990f795cc6cdc280bf917743a04854bbcaa2cf64128de9c42e38b40107a97f71cd1b89dfeaf194674cdb35e036b45cac35c45eb2ed6bd9f8acb9402be9e57acc00e0ab6c5b32eebb9867878c23f4275dc2a8754328ded15e206ae31b60beeaf27f7e2a571c42994414355c28715621d39566fcaebe6251eb5955fb8a9b1bf4d897a4931c5e7c29f27f28ab4d2b9950a81dabba7ee63b679df6e5c1da4e23bb9529946e4f467a73ef02d1ff59d7141e6d59e14450b7a35bb4795eaeee51545563bdf99bdb5dc0b17cc60fa04dfb3070930ee46577250ffa863528a498"
+            },
+            Test {
+                input: "f690a132ab46b28edfa6479283d6444e371c6459108afd9c35dbd235e0b6b6ff4c4ea58e7554bd002460433b2164ca51e868f7947d7d7a0d792e4abf0be5f450853cc40d85485b2b8857ea31b5ea6e4ccfa2f3a7ef3380066d7d8979fdac618aad3d7e886dea4f005ae4ad05e5065f",
+                output_str: "f1e1e702011f4a39197d769a6af63160bed980db70888266afcb744a8fe41f1bd9a1b668b4a96a6c3c2fea3ec1564592134854b26e31102d1b95f112118c959475aa6f2dfc300e389fd061fd6667db36c32055901609ef59b3a8de4f9bc05d52745c78e8d155738f30eb3a8e3b61b36ad34a6bf7c59b59c1f973b9f94c9ed61a746f85610b060e8bd04cc9691e7979ebde5e9833aeef21f9dce96f61a21d2b8864f07fdcd6d3f2bb3db29cecb6670e859a4962a5fe0179236be7426e9c9b2a0b97d11b6c9e049abaab494513128471f88914e506c6a5006ed295f436410cd24b4cd1ec5aa0ca7a66e29df6c362389c7a9b731e0720400c0923bd8c4a98a651b62aa8aadaa5fad481e08a17a2b3f86ad23ff6303463da6300b47483f7696962d33af1de2739c30346665f60c90fa35b74cc240d3831c01ed8cb91fa34a584dea37846cf4a0b43b5d1c26597b2aa1c973a070f120f08c78a9fc8d524fec1f10274f03a4a7e8e8c4c1fdb415a1ab18b4c1f07e1936f81ffe7f2a0a1a815e2f29334f1b1e8029e7e12a798187ccb20f6c1eaf91b14b61b2fe4c3852bc670295bcdad418ca7fcf39c69fa9f9ce54af17e695f1d614bcbd49fee3935238ce59d9e378f3e596b34149149e14d9b81f0bb09c2df8e6e632436ebd525bbdb657822940d25713b737a2dfdcdf0b4f6dd7920a8d1e69eaf7b764d0a469cc1ce6deb70ddd69e"
+            },
+            Test {
+                input: "58d6a99bc6458824b256916770a8417040721cccfd4b79eacd8b65a3767ce5ba7e74104c985ac56b8cc9aebd16febd4cda5adb130b0ff2329cc8d611eb14dac268a2f9e633c99de33997fea41c52a7c5e1317d5b5daed35eba7d5a60e45d1fa7eaabc35f5c2b0a0f2379231953322c4e",
+                output_str: "98326be2f713456ec96c941fa0b58e311c226474487f78734c8d0514afde43293116d6c33fa3ec687d1e9087572c68479ae1080ff8b2238c11aea13d9a020a7b3feee56fc2fa69914489ee11b17cb9d3af448525c3992232b58f2182ad27d93ab88b22dc94368d10b112aaac096dcd8ab76250984ee4e4d3ccab7fa3124f7b02d05111d97ef0cc52c5b8221383a6256c42762e546acd6691de9810fc2271d92834da1992cf4031b98cd0919e01d35dddc738d6a305c6e400049a97e14afbf40822558832d23165cacaf16a514efd6d207a95f97c330ca333c810c19aefae12f3aa267cc9fcab0b73d2b7e5f3b007cd8055d0c4665c9c53fc818a53ecd9c0da776eeb3904409ed63b337f755cc7783da8cb713b51c720c2826711ff36d98723c8b00c4853eed1b3e2f8b8d74ecfad079a49f37665de5031f2fbf54da6f1fb796913b9dce2ba1206e4255f39c314a34aeea01f1965c36caf89a2f7fb9eaf7e9c97e2b70636abf0ed00f59d1ddad409ac33055e6f7517e962bc535eedfcbaec203f91fbd2b13c26a20f9c2236c55f4b506c7aea579ed3a0204bc67002d158d80139379dc23da06b0defea079e8fc1d51976757e9a455719c45b8965959a2958e75b7e6da966b86029d22fa50841494303ab6b16600324ef918aff9df161224f1a7f26b7df364772724d4b1afba11b5c114563f9da2604a2d1b60bcc3c116a5e9c58"
+            },
+            Test {
+                input: "befab574396d7f8b6705e2d5b58b2c1c820bb24e3f4bae3e8fbcd36dbf734ee14e5d6ab972aedd3540235466e825850ee4c512ea9795abfd33f330d9fd7f79e62bbb63a6ea85de15beaeea6f8d204a28956059e2632d11861dfb0e65bc07ac8a159388d5c3277e227286f65ff5e5b5aec1",
+                output_str: "d539b406312a6a14a2cb8c2b2bccb28b7c164dca4bc34564e65b807f59809e0844fc897bbda2fd7a0082be317b8cd94c2b2dc8a625691d56ab21a2c854cc6952a4374cc34374aaad9090326d493eaecc945848fc4653a15e2566a960cdeff139508882b766a1ed60cd292c696cc75136a6dbc0bda628ed1e16129a9025d715b7f83ce3a35f4efc7178bdad06fe6030e086d416775be9df9db66a365f56129f7b25a8701502bd36cd439a4cc122da4d78b1d832f5033123d9a9d72ede2ed7d7815eb7a3eabbd21e2e507de4ec4aea0b40792337953dcd9d7bb952f710f8bbcd7e8cc1acf3b7ab4eea9c066d9d0d27aad600405ab5daab1fe4551cddea659307b7ed1913bd8635aa409754a1860377e0453a63ee7c2c6cd1a33099a81240b92382572caf3698c809237548002eafcea5bd042db3a7506189e3fbb4dda6dfb1c95be136011fa127b0fa3a4a386da3c327b072417bbc5346a5060d770933142b6ceeee1021bc0de076c2fc8ecf7a16a6cb752f39b8fa1ead88a7d4364204bf613f5b108e2fb60854f801210180b9dc4757d145e715d4e2d79a7d4e8aa891977dfe08a92aa423a05d22b06c6a3d1ea5953214855be7cbe9c2e62f2a7171bf014f3f077ad244fabf9c1584ee12dfcbea4e4816c470aed4fcb900a5175c35189380829e92805e47969ff5a1c3b52fd850fb404bfe189866844e7b586dcdcbb236910011"
+            },
+            Test {
+                input: "8e58144fa9179d686478622ce450c748260c95d1ba43b8f9b59abeca8d93488da73463ef40198b4d16fb0b0707201347e0506ff19d01bea0f42b8af9e71a1f1bd168781069d4d338fdef00bf419fbb003031df671f4a37979564f69282de9c65407847dd0da505ab1641c02dea4f0d834986",
+                output_str: "60565a24b70c76463cdc5397bd0c077b77cc70cf33128a0366a7c30161e21c32f2f024511a9605040d699e1410311ec3e8952938c91d73ad71803be3f7ab60e2aac7a91d62fc0729294bcbb031ddd5926f775fa85d25c85e1cbc349237f9d1e400e64c15a797c1651fbe5b8079d586bb751e1b765c36a40008c9c612a8a67c49a2d4c15001562d7f7197ce107aa7601e490fd3cee738d397a5d9e1a9568385a243975b9aef5e24c4235cb3612527b7abb7dcfd22a124f9bf5e1e169f2f58512b8ab04f4953d40e6b1d4ffb920186e4c0751f5d8516f142c426f3893b6b4f45567461059968369b3d333b74f9a596e7585c6646af458173500b052213ec6074890af149a6554a92106868a64c3957f43c8730dfb3136040ec688adfd0e79ea74e07f6a6418656343d24e446013add76058241f19f5cd42f256f8e98c7a5f7b9c4ce3f5d19cfae69af8de868ffb5807dde0c4a5dac1409297c5b8ad27c1e1b8ffd570bc41f71f21af7c9639bc6502511ff9d6cf63bfe2e8ae791b50527d79334cb87d9bca919833d7123b8d77f96d07106bdb50a3c4b9860e5e1cdbfe4b49cd4063d0c4796bff2fe1507f43cee6ca6bd19038cd6b7118120c25ea0dd1bad05018df08db67af168880c284daf7dd33a7bf18248ba7e79bf18b68c3e14664d0e1349d458ce7e128999cda5ee706fd48fad8d0489ca8c5718cf3d2c16563178ae3309"
+            },
+            Test {
+                input: "b55c10eae0ec684c16d13463f29291bf26c82e2fa0422a99c71db4af14dd9c7f33eda52fd73d017cc0f2dbe734d831f0d820d06d5f89dacc485739144f8cfd4799223b1aff9031a105cb6a029ba71e6e5867d85a554991c38df3c9ef8c1e1e9a7630be61caabca69280c399c1fb7a12d12aefc",
+                output_str: "7fd57ac85310e74667c025609a2cd37d12eb3fa49f9d9b9aa4568c1300c4b5fa69b6591f82d4c7c5b25ee6f4a6e2521090aca1588d75b4f6bc1d58b106e825ba2409f84be64ab520cf4513a7bff52fa7a67a761b86e9d749ffc71532f202a2b619ff772ec25c00c269e7ff10ec38b93999dd8bc7b3db40cbe870cbcee6c0a6842a72f978ba9af677cf4f055762abb1c8da60cf57e9352c48b0bdc0031fde8a146b8d881dd4d0d05bd5d14b52c89adb6a27cfda2b3d7650ea650bb75d86748a722d7e3003e10e43d89ae21e9155231556b7335f576a922248ea2040de648a0d49d8eb88da240e586deaaf9895cb2f35cdfe60e61d6643e5b38fbe40e82bcc8462fac98f078dfef5d42e1d562997ebbeaef637fa8f65510e604e99933d92798ca05dfee0e935910be5086dbc8ba9493ce52cc49b85b062164f6be8ebfb4f0c27641b65c397b92182a47d4e926c6d6947aab598ea0d012efc47556ec7f6407a2dfb3cbae71237d968efcf9192379384fd2dda510bad5b30f01852064938a17c38b6166170fe15f09f645cc740383715dc35c98f6e2738473d324c7c6f63e76124824554b0ea34120facd2826c7f2a717d2817d871babacf1f061cac045ea61bed8d4aaaa1d41a277e50c09606b1786be65e1abef10f6dc6d28eb8206d3e3b8a56fc83728291420acbf606c34b2b3e852381ef31556fdaa341e05bee90dc9ab7173d"
+            },
+            Test {
+                input: "2eeea693f585f4ed6f6f8865bbae47a6908aecd7c429e4bec4f0de1d0ca0183fa201a0cb14a529b7d7ac0e6ff6607a3243ee9fb11bcf3e2304fe75ffcddd6c5c2e2a4cd45f63c962d010645058d36571404a6d2b4f44755434d76998e83409c3205aa1615db44057db991231d2cb42624574f545",
+                output_str: "cc03a5bacc26e1580f37813e60005111261ae521159086c7a6c3087e238d2731a02be233200fa54bded93d6959dd03b71a1a4c7cca20e9685406f70d722dfa1718b3a169be6a8c5fa275eac81667046a605ae8514bac24f216358a27f036bb618951a1ff5aeca2f64fe1571cd01ec7139f86d370bcba6a721520bc115330398f55691d7a212be824f27aa10305523f7c11262d2ea2520d72af1e34a887bbb4a8df9966fdea757351eb67df1df9f9dfd7d7892d3cfd1f0b8a3a16ad5055d5904ddd900e4a5f94941fa796e8f32a04e807ede1958191d58551378a57087a62f48e3ae2852ec03654cb142d2b851c5995324d15927f3daaaab188ddb6665e08596b71d9c2b740a15f8e78f02c6a820c79c3223a98d79d225375f6375ec21a5216a9d01d0238fb456857e7d6611cadc2df844d99c6380cf59e7bdc268ce91d733fe00ee99a50acfbed98e6ac17dd8a377ee4af9f318baf14143ad4873422dc56aa6e4dfb6b0c312ab14f16105d8cbeb7f57da85644005ca4294fc8667c1cc1fc78256562cd7aea9779899f431fb581ad6ce91a46f003248a42bd286e9f4a0909dde99e2ff674d4d5e71eda126995da15f9c00f11ba6691e3614ce6fff05aad6b7c63a72da235e900698d09ba3787742ef61701eb25c3d70927272441709d2625b23fc97fbfeb1fc06d3693509424ff5dbf005023ce06d80d7956d1dc0030bae8d0bc"
+            },
+            Test {
+                input: "dab11dc0b047db0420a585f56c42d93175562852428499f66a0db811fcdddab2f7cdffed1543e5fb72110b64686bc7b6887a538ad44c050f1e42631bc4ec8a9f2a047163d822a38989ee4aab01b4c1f161b062d873b1cfa388fd301514f62224157b9bef423c7783b7aac8d30d65cd1bba8d689c2d",
+                output_str: "fdaed26927dc53f12f002a9c47467a4eb53d941b08106d6cd0bdff6021b6ae116562d2255562f70be884427a8b6d593e0cb7040addb87663e5f03981992435c2baace87c49cdabda178d0663cf81e96c2edfcb6d50d48ed128128f6f3b56e33bf33187bccb5c2bceb418dacd4c820eaf880b80e32f00b7105615ce305065716316221019a84ca2d29fa57565cea5239484b8e9740ae07048bd0f75b50827c138979fc9671b4e684952df9a681e0c7ed8101df50620defd82132ec81f5073991e65e1dd72a52b596cdafe6c5b6d9205533ef15d137a1feea7564c03e3a19e2b9f40600ff1a66a241737ef7faa29eb83793bc40d1e48cdacf3936c499b572aebf2def5086354df7dfe682b9c281f4cf68405d0268168f5495913f930b6009357867398acc5f951d55d854b0c42d2e2127cac73ad0b75139111414f6d6a68e01cdb794ea6e524e45a62a82970d22168f37ed72575a513751368718af490e28acc47d2bb7d59f567daaed80093929fafc0eba01f66d67dac97a99886d0b11ec0c4c23a593bbf05f3f80a047a07c883063a9fb967cb9a796d18168d0a7f731132aadb3d105b1475c583bcd4b939015f460fee9b6f23b0d3bb3e2e7b7c5615ac8ef7305567397ec4c1de8ef5a05c2a14196ad00660dd0fd11838a707c0fad38d343ad9d65056a4c3701490b3ca235063d7d21bf02ffb2e0da3d9b9092e20da716bf450"
+            },
+            Test {
+                input: "42e99a2f80aee0e001279a2434f731e01d34a44b1a8101726921c0590c30f3120eb83059f325e894a5ac959dca71ce2214799916424e859d27d789437b9d27240bf8c35adbafcecc322b48aa205b293962d858652abacbd588bcf6cbc388d0993bd622f96ed54614c25b6a9aa527589eaaffcf17ddf7",
+                output_str: "f375fb504784706dcd5bc3a500bae8de6630009d865739a0b30c81c74e0379a59996410854fdff996b46f9f30bedd7dba1c5801a68d1d3792119d7feb29a648e08502ca04637afb9427027d59e9da235baa4d602ab2ff257bb5fba4aa79c9d285e99fc4314685181020c2e9c1cfb22d1e7b1add9c037a7f81b7e0135f9628cd67b8591271bc12d025322bc21e7bf4e91b049e291da2828de012384aa65e3ce26f98186828a3c144a095d82bbf5a325e41dc28a33828d9717baed4bb8bc50116cf39c8eb6df037e29ed6a32fc5039ec1704e199aff83768e58f1858ed741dddcf75e8b2621bbbe14420217cdae7561c24213f76530204141ef5c7ce0a76c587c2223181f5f2df58ba5d89ebd209c004f5a2155cbd896a17701b19d5cd5d555f2a964bfbef27d22fb428db161c0ab99d040af196efb7640efc55b7ca8e1bac86f4368f612edb120e2a7ca084b9f5ef8da0a11136c760dcf4426ca98f20514049bee2f9e6f66aafc4225cfbd4397bbbfba872a47be903ee0dbebc7ef85a1395b14504c18a8b5bc5416739daa543dfad6b4b8a88bb87b388a6974ab90756e836de528869ea2734e75d8aad84ef1a60bd371190808436d5c7632a2f027c3ccfe8f3d94b0c262fb7ac99103b0688238be68f26b8cf35876b6e214ed1973fb44b9c3f3dc7d7296be8e150f82e80594e34a3e008ef40d9647ee26e1e4cfdd8dc673f2ac5"
+            },
+            Test {
+                input: "3c9b46450c0f2cae8e3823f8bdb4277f31b744ce2eb17054bddc6dff36af7f49fb8a2320cc3bdf8e0a2ea29ad3a55de1165d219adeddb5175253e2d1489e9b6fdd02e2c3d3a4b54d60e3a47334c37913c5695378a669e9b72dec32af5434f93f46176ebf044c4784467c700470d0c0b40c8a088c815816",
+                output_str: "98d27ac62145261bf2cdf99f8f77ac04697d2fe6f1531d3b1e113a7bea4b9be780394cde5ec43ef820b0d39e20a287b29390a68091a8938ef5640437a0f09f5262bfb4c55f703d44e7e21eb69c27566b66bdc95a525b988be281243dac0cef5e04195b318cdc96035205ccc556ad42b220fcb0e01516e66d8ca2d045ae0af7fff91119cd4c92e664fb339203e8c0b3766c78874dc85d48fe668bace760a96f5d562fe4ace97fb33c93f160057c0475ec440111c46777b0e2c95df666ec753057596713ff452ee59dd7e1d4dc278238518e23c78e8882393b86427e8f6188d7a08d770b2d19e08ca672c89582431f30cf4a0ce89e87a635ec2e05765da600115b704e35b787fa90ac545877ebc8a5616eb998380d4ea1c6b127844a422789b9b3a41daee940f75cf975b464736616d80d89387c171d919874f38453af44ed16888212ac279d4890cbb5672254d76d5fb922412a2eeda598087558b1e89528fb1ea285303ecf4843b18edaf6130d1374273dede9eaafd6e6f448547e96aa385235919600e4bfd04cc2bdd89e6860adac61e73e37c563709f3187439a305b9ea8de8eb552a615712451d1da495a8e02b9733aa1f7b78de6c0f0cf6a379959efbfa8a78cb6e93a758889d826d7e3dc741a10bfb55544993683b2383419d3f5bfbab13eb1ea0575e528fcdd10fedb0c0133c8e78fa0dde413fd951262e0cc958d2850"
+            },
+            Test {
+                input: "d1e654b77cb155f5c77971a64df9e5d34c26a3cad6c7f6b300d39deb1910094691adaa095be4ba5d86690a976428635d5526f3e946f7dc3bd4dbc78999e653441187a81f9adcd5a3c5f254bc8256b0158f54673dcc1232f6e918ebfc6c51ce67eaeb042d9f57eec4bfe910e169af78b3de48d137df4f2840",
+                output_str: "6095c8caf02d995daac5f6cd94a33fe0cfc2743574b352fc35a056135d20be12fa7826dd41bacca18c90060c08c5bac8b3e706622a2bc8aad1fb6ef93259a5b8092540f68497f09e47476f9d94111b2fafe27cb04deeaff43a435e2a5c0e44aac6dc3104453896c9c702e8f59bb61a62acf889174955beac0319fc897bf989c97307a997f4570f3544e5a003f22a7c5295705201f025ee7d6b5b278deba559ffb82f22aff5db6d534e6c50fc4e55fdaa0dcdf977178db7ac2d98416a6e0f5ab5a49c29e414bc0ac0122d608a592c605e418edcd083b26429ba0a1a53584ebfeb4fc005f144f04ceacc971c9edd23950a1b7e6a4a9308c517ff80ebb1610f8e78d963e222bf148659bef6b0c8be1f466fe786128431a9950d3c70493d1cd72731d0a3c956e34f35339aea578f614806dbad3c02389643340db162661003d2cf42f1c913a7fab77ec3b9e8e3177dc0394305c21d6e9713f34516cee321992e4bfca4db5dd03e240a7fdbc83826efff82e2b36bda326d8fd0c858b00e02a83d0df7216a475cdf0a37b0389095f501cf47c497e23f199d711991fe71dfb56d789f30c86d3bd17c8bdef8a797bcfd3ebcd5e62cf99ba0403b79bbc8a0fcf4fa7c4e65b674a796af85e7d09134fe214ce8355ee337faf6f04660753c1a96d95964e587f72f0fa5bff435778084eadb1807dc66772850152aea381866202c8a38723121"
+            },
+            Test {
+                input: "626f68c18a69a6590159a9c46be03d5965698f2dac3de779b878b3d9c421e0f21b955a16c715c1ec1e22ce3eb645b8b4f263f60660ea3028981eebd6c8c3a367285b691c8ee56944a7cd1217997e1d9c21620b536bdbd5de8925ff71dec6fbc06624ab6b21e329813de90d1e572dfb89a18120c3f606355d25",
+                output_str: "765a48e25ee43ac1630c65bf5138f5f792095e182483de8887f0f56abdfc0526a5b9ee792a2533409f3fcad2b9cd43d7cfb5454194344169dea3fc67ccb5b9969449454e18869e7cfd821ed0f3d655f5b33c528bed1778bd504b2c84bd38dbcbfbf5cad7e46f37394622c4b065686773ac0171ef70717e8c6a887ad952343d02ee96b4129b3f189c631a719910f543540de4ad65993b634afcf313100771468c81b0e270769abe2bd6603e525682aaf172cedeadd12d9389b86dd6459dc490cb89a637f6e24c5819dfb51c817a3ac9837092d408c6816b57a4b0dcd0fd1c7ac49fc012bc9c22d16c779066a670252515938764f4e05fc57908fb67a3c6927b4639014aea06ef91f8d43e507c48a567f36b94591ea1319d7f266722bc9ad6f5cb8196994f7ddea570720edd94e6c56d215d8290cf0227de007b71e80b65301d53363d51c73303fdfe76a064bb1169862a02f541d782fc64c3da45fdfe2fefbef8a9383690f1d6c695855387cc206b9e7266d6e6c9a2160074a962de01febfabacc6e88cf7f724cb4b2f09862d63cfccf1d880d956e7e5381f44568de6bada3923f2f09cae80d25661b9431201c1918df1e442f26710314d8b3f88e94502e6e9514c2efeec7a816e82517767bf7972d6329bb54ad1bf67842c449f54c8cfe2ffa312129995f17059f59e7ae05d21ea17f8e93c1ff4d9e2e71c9ecc9dd5512fd374"
+            },
+            Test {
+                input: "651a6fb3c4b80c7c68c6011675e6094eb56abf5fc3057324ebc6477825061f9f27e7a94633abd1fa598a746e4a577caf524c52ec1788471f92b8c37f23795ca19d559d446cab16cbcdce90b79fa1026cee77bf4ab1b503c5b94c2256ad75b3eac6fd5dcb96aca4b03a834bfb4e9af988cecbf2ae597cb9097940",
+                output_str: "270ee64e434d9cfa8a81b256aa86959d6d9e92b10325a1816776a309002e7c9346f21bfcbeffb2fb31bf7214572a7f437e3450af26743b418cdea45ae28557078d8275e406864bca916f178181caa3396b8582b04148249102d761111507c48722506d0314a05767e89b3d9d5125a43a2b13ea8827ccecaeca6cbc864b8b7591b15bbe0bf1093cd15c5c14b4b3705e37cd97752cfcca1c1a4340c02298b028a633cab0e218525e94c3e150eeb8ba36c3ac4e8eafa5ed05d9a79519cee2a8b8eea9d8ebaf54624acb2bd593cbb353bd2f577cab60508dab081bd29200e9a9e9357978cc15f4b98a383c4a46594303143ad019d5bcb052504efd2ecdabd1731db02d6fa4ac9e1d3037b75b7a5cff8702f8eda7f2ce848a0b96ec2f7c62bdb1e23dec39af110a4e6c0597d61c8aee900276fc7b1ab2f63bc9874a00c79705d87de2135218ef233c8939671399a32c02db4a6d779f7f933e7f7a467d236178e2137f1e5ff53a3e8fbbdd8d01b737ea95c762b4d4d65bddf50c527e01da1a322151757e0f10525196d3293e1443bc7282496f3da971869ded47ddfb7bd99e799ee60fd3cc31bd4b3956daf6d70f79d4a5e4348004f526d90ca47d7c3a9eb09074eeb00d799f14de7ae5a4615d87496faf2c60d1074c194e7cdddc0765c7fe7c6fd419335189c2d584438d3879c50d43e6cb25d5776b4802819c5dec7cb2197b334615"
+            },
+            Test {
+                input: "8aaf072fce8a2d96bc10b3c91c809ee93072fb205ca7f10abd82ecd82cf040b1bc49ea13d1857815c0e99781de3adbb5443ce1c897e55188ceaf221aa9681638de05ae1b322938f46bce51543b57ecdb4c266272259d1798de13be90e10efec2d07484d9b21a3870e2aa9e06c21aa2d0c9cf420080a80a91dee16f",
+                output_str: "652a6b87d0e770909bbaa2172f47cd05b7a07b57d9ec47396e9cca40edb76b99bae0a8fafa517d12ed62b5e95ad89560f3eacd241a2af24bb1f02bda6f0a5acfa85f4f86cff75be9e7a57e0f182890c39acb6de889d24ea360dd5a4c59e54dca7306aae46768205c3440ad777a853dc8fe2d2ef2e6a5fdef23bf514472b89405fe1b7342aa4fb448e0eed8a46b6f259073057571b03a4df2eaf696838a51449a5f7dbe9644a9d092ac68b9a30034460c1891a389d06a2ac3165eca91f203ded47b5192c8f6aa2e5fabde178a012d94a8a35a1d446d08edf55f4e4163c2bb9c46025d8253b3f062926d17f853728efefb10d69e6846bce7e7a037996654e1c36c3a55404a1fa579a1d55fb95b30eb61eb14a29bfb54878c0d59a4209e1c746f7b2a2f2a28bb19a5f0342026bd807bb366363623bd68d4c9d9bb42d2ac67df49dd3727f4d2aab52a678f6f98816fc86ba0073f4afa336a32cd55daafff5d993926522d770aa44d62f6aff7e758ad33dae3c642318894c2da99f43adf2f97e53ba48657604259a8bac4268933f1b97bd47fb30f95ad284f8345d6e013aeb9dc2478ce49ceb054555d25e36b13b322e51bf1c1e7c062e328aa440f87ee883c7760fe2f86b487bba73163a13755e6cba804f0ea6399e875bdb2966d427933d66d82c4d17faf6cdfbcda36f09621a3923b4eb93a27e44796cd1c1770835b83e89d28ed"
+            },
+            Test {
+                input: "53f918fd00b1701bd504f8cdea803acca21ac18c564ab90c2a17da592c7d69688f6580575395551e8cd33e0fef08ca6ed4588d4d140b3e44c032355df1c531564d7f4835753344345a6781e11cd5e095b73df5f82c8ae3ad00877936896671e947cc52e2b29dcd463d90a0c9929128da222b5a211450bbc0e02448e2",
+                output_str: "2716a3a219bd690b9b0450cc0bf4f0713c46c4c02744f8f71de261b94159278566583d4dd04cd573e79c576c1f25834c91d3af69f3a301aefa516082869f3ceb0f916a903d902175ef29a0b29aee92cad8555a26e7cd0395bb937750246a8d5a722dcade4f44459a15ecc29b207fd8ffb8510722d925627372d86528b9b513967b5bcbbb233b459afb5aeace48e5355c3e7a387f9dcc9a55773276d14c85b8eebe3d211fa08cbdd8aac4656f028fc16a6d6083a969bd6eb5247695d8f6de51c036a743d2db7480dea41c228ffdfaf129bcf0d0d5f7644405ff8af778ad9a63eb54f62e1517ea4cfaa92f2f25e5f001a562b6b4d28bfb398c26df8e88c288aed5b7afe8686aa4aac77c032d21203fb7ba79707a7e00371f56fdfeb0e607252448cda319c39447ecb7c69f36424d74e33d723ae53996b35e5554182015493ae03daec5c31b00d481cd430f4723677c7b33f6e325a855300e66db559ddbccd550de02d797d6b28a1ee01fa13a62f721bcc577a6c3363a03ed976391e969379ba3bb6bbf99271f3e5dfadddbf0bb32db9ecd658f0da2863fe8f48ce2a13539d8e8276c083c4cab1aa9d92914acb238c3ef0a5952e5686e39d2804ded740e0457f69fee9489b7e548514feb18fce21f265dcd56f0081528a24fca7595e96d31caef0969f56b122749c74fa108c41d34902828b22f814bf352a1b5b52e9c65f75f232e"
+            },
+            Test {
+                input: "a64599b8a61b5ccec9e67aed69447459c8da3d1ec6c7c7c82a7428b9b584fa67e90f68e2c00fbbed4613666e5168da4a16f395f7a3c3832b3b134bfc9cbaa95d2a0fe252f44ac6681eb6d40ab91c1d0282fed6701c57463d3c5f2bb8c6a7301fb4576aa3b5f15510db8956ff77478c26a7c09bea7b398cfc83503f538e",
+                output_str: "6995a90158ea5fd54f6d4da0c129b92ea3e716e196de4ac014caf106ef4cabdfb9ed799545a0e53e32aba2ea78a6c7cb936947f79817d200f32053e81d10131278cbcb903980e13125c99b1696f26d355882a107fa65fa43766c929485696d56d49d371643e9d360e25668b5b7bc7cde13b678723fdc4598b60b6b19b47791ba99f4258acd94604f26d5587ee8dff613dd53e083cb2b0a202930d61435601a1d3ca8d97c198cc278967ba493b675d2f42cf4f41072b7a9403df36e0e15b8811e37ce1119542c5168c95396653f72fc9e59727de36b693ca58fe374aee8defc657035fc874b7851ec0dede274be064d258c0b39a238d2863bf8b7ebd0f7e2c3fb2a7eda6800dab2def61fa8f5e6891652796c2e9cf586bb0549f6f73b3374a4d7c6345ff73fbf99fb25ca47823a4b0470738aa67cd26d2eb954ef40a4121dfed58a1741ef335e8adb32a588452774ff26b04eae29ec1ac3bd83d2f3a27af2a464d29589aa837890d7711cc0af76ecd6142eeef1c904c0cfbb287babf951b8a10281a7cd1b49d766704350c7612a74606d2bb80de11a37ca9aaa1ccb91f4aac8d382a5a16e0cc7b426065f3af566592c51b52bbbf007f4f4b7910dd0c7042406f61e5efb6e04eaac76e07a7e86c6e3a5706b833c52bddf814e1261724f97da9b7887399b7fdcfb14321d8a16683c1dc615ea8c738f0bf6076e05855f80d8da43f0"
+            },
+            Test {
+                input: "0e3ab0e054739b00cdb6a87bd12cae024b54cb5e550e6c425360c2e87e59401f5ec24ef0314855f0f56c47695d56a7fb1417693af2a1ed5291f2fee95f75eed54a1b1c2e81226fbff6f63ade584911c71967a8eb70933bc3f5d15bc91b5c2644d9516d3c3a8c154ee48e118bd1442c043c7a0dba5ac5b1d5360aae5b9065",
+                output_str: "791c8b8021bee5393ffaf003b9c429a5abd2e35c5c7f556e843d735265c5b7807343ee946bff31f45b5626555cfd792f55465ad9ff95647a41d9759de484a0564492236fd770ed3f78c92514b90636ceec76d3fc44a6cca482bcf45d3b5bbcdbb1eef6d5d6eabfd0fd10b0b4aea88c5fa68182a8a9805b5e90b1767c9e79500237d07be59c0f09a9af2236aa954f9ddaade492d691e36f3f4043f28bf0ba6349591700c4211185d99cb25553e2f6f405f9d8e00fb658bdf4a091cbc7092934a6dc6d65e42cc9042f90d169662f80d66386489d2e7f750251130e1529cd8ba70929252551b0617c960203ede536cca5eb0c5217e9e4756d7b57ccbe5087a4fb9710ee89ff62355203df415975ad106d84dd5526b3ef3432770b163856b4d46f7315f1ed70055cbcc4c78c5c0cd4b19fced545ea00f0e2e9752a227445dec6d50b3d73abd2d81c9aac6b53e108da04c42d491254af39584068e34ce2f4026fb63c29a52b913e5d2fa42ff7adf413227b784711a3513bea6aaa97dc019a25a0f09ee27a46feac4ec13b43e341c505c308ada1db5d72e0609a0a68698c809067f2ef17434f3205e03be67433c1d67072e8cad0e2276723ae7d9f552df19c142a68a7b875cd7a73fb586e128856a9259f7373242c498e621e7f16e7af57f36953001925115806972ed2795b9a2f398676bf37f2ef8fd4325863d599e10fd84d8d77d1"
+            },
+            Test {
+                input: "a62fc595b4096e6336e53fcdfc8d1cc175d71dac9d750a6133d23199eaac288207944cea6b16d27631915b4619f743da2e30a0c00bbdb1bbb35ab852ef3b9aec6b0a8dcc6e9e1abaa3ad62ac0a6c5de765de2c3711b769e3fde44a74016fff82ac46fa8f1797d3b2a726b696e3dea5530439acee3a45c2a51bc32dd055650b",
+                output_str: "42aef4301642ed54cb1ff9b446bfab73cdfac0320167ca3460a9af1995b5dd50c1adb402a55a3e5c4f7be66bb2041f3e4c9eddf7f08826f8b9c1163b0ce8b31769aa72ab4c598b3bb1cd5791a6bc30d11f0591d0eaab34d80f134734d792bcc6ea61aa535f4f28331aa6e9a572d43f776341c971829c67c0e7d9321b09807965e1e9c70e611a4bbc3c42743a2d04f50804730c857f02e631c1b81dbd33d3ea2539f9aeeca9842b3c95fa1b8b1c330926fe5c6a396214537bd06b49b7951af0f9ae04d158f364757a52ab1f21b4155895929480d87ab365a7950b321d5fd0c18fe3ff63b10d3cfd74af45774500ad3fad98da5d240d613b386e677d57211b8781aea7ef4052a25e122064bae6dd59b00d533e6b041130b89778db87f88dd37deb78136b55a958744b9769612a0dc6d29b6c0ef863934302029c800b50ab385de742d436809c7665b868c83dc450e438e94ea3124dc080355ae5931797e75dfacd09a7c97345608e021bd2034f7660ecd194f628a9868bc0def0231da66ab89e2df1eda2c403203f971c1e61e4098fd306202b9f96c78ccc37efaa7983c5d7712034328d1e65fbe96db94b3bd88732e60ace5ef946e896abd4e1f6978700c12c4a8a372ca54b6f8efb3402b898838a26d8900f69393e56d2addd2a0ea26e7f630ba6d19c46de493c516277fc491f1fe273d013f4a32bde43994b031ea51c2cc8f5"
+            },
+            Test {
+                input: "2b6db7ced8665ebe9deb080295218426bdaa7c6da9add2088932cdffbaa1c14129bccdd70f369efb149285858d2b1d155d14de2fdb680a8b027284055182a0cae275234cc9c92863c1b4ab66f304cf0621cd54565f5bff461d3b461bd40df28198e3732501b4860eadd503d26d6e69338f4e0456e9e9baf3d827ae685fb1d817",
+                output_str: "5e0693e64dbe678055a31d80da85a81a1ba5eb1cb6394b7b1aa2adc2b8c1fee4f41dff3623502fcc349d4b2bebbc1311ef291ef47f490c6fc1323075b519c87dbd77cb94c213eb548278a6c11b0c321c941fbeb9742b690a9777875d8a1fd0627b5ce3679a6dbcc8b53d775e73ac9f951749fc353eee7220cab40f4f7c2eea311cd0b50974af188ea9742509c4121fc07a70fc28f0633b56babb451554bdf86396594b57b1f88dfa07dd4f8c47ab5ffbad03da1da642ef4a6e75a952e8acb3989136b8a792e6f33b24da2cc4e422192eebaf121561bd33a6d79df6517b3f001e674f39bb98d9aa0e15226389b17655e7b2796d75ede0430a0e7d07039b8e35642570f6457f8344a59dbdd5128f74f9ab83cd152db17987019aa0b27b6e7951cef67b574d05535ceb5eb023a39b5731b6afe6cbb8bfee0f71819d791c288bfe9ebe6706778fe62a80aef22cb9c0920938502f30a20fb4a4822d0c0d42d50d67fa6a76ef919c985c6306fea73a3bf41006f0fe60c0d92b80106d8c715b97e35e39fa8eca59220b86c2c46b9c61eebce07da4b64cad247a67112f6548aa693bfc4bfc9ae78144571cbe7b81b83c8832938a71fd3ac6b8e4aecf17fd2848fd9558dc5ddb261ccaaf083affa341ea295c7264f35734f5179038ab70c90e03bf53e3ff438a9c0655ec38f5b9dab7a4c3ba852a2a0593c80999818b460015c79093b1d6"
+            },
+            Test {
+                input: "10db509b2cdcaba6c062ae33be48116a29eb18e390e1bbada5ca0a2718afbcd23431440106594893043cc7f2625281bf7de2655880966a23705f0c5155c2f5cca9f2c2142e96d0a2e763b70686cd421b5db812daced0c6d65035fde558e94f26b3e6dde5bd13980cc80292b723013bd033284584bff27657871b0cf07a849f4ae2",
+                output_str: "b620ceaa437e16a85be761a8563ac80d9c49608dd0ebf9a4f049b9541623f4a3783c9e67b85820ba44a80f1afe3fd835791d9f3c785bd8a77c9623eaf11f695675e3a2fb951d54050d0500688860bd270d3b723be51579b81cf4ed94cebc294a97beebb5a851160012514d3bafee6e275adc7bcc64eb7879c32d8e0605241786dc3cc1bd44db64bbb2e9c6e1fc581a5124a734625cd811b6bbe00b203319a736eea07af977190d777c12465e1614fca56db7154f9c456f59989062d60899d7cd7925df1e1ac2eecd9b070f7e380b0775089f303b864d5ce049c55177e3421443b508edeedac6307967a4321121ee2227c47e357fa92b741fab390957ccd9337b42bc18e6981fd9efc9241fdd24bad0c6772216bcccb92c2eacab3a312ce020216ddc9175f3f86343e204e1a76573294de6ec6bb75679379645fb973c37354323e15202415172d7f3d6a1060fcd35dc011b3b2fb4fae21c69ad0119191ba4277ed6f71045fcd69f267e667dc4d219fa256bf35abfa06a05738d212c42eab91c2c993a5b6adf9adc0f276e79ec9eed6f115af4bcafba9cec43b0532038e863b2686996e997807ed67de7f48c14b17d40cfccefd9a943cfd7c96fc665eabc70e606213da37cd7eb6f942a6a5608305b8cd8b9bd4d625de5d7dccb554d3ce466d6ea8c1d9f111fa4e96b253ea11b4dee3be218c880844006d6401659c35c2a293da2"
+            },
+            Test {
+                input: "9334de60c997bda6086101a6314f64e4458f5ff9450c509df006e8c547983c651ca97879175aaba0c539e82d05c1e02c480975cbb30118121061b1ebac4f8d9a3781e2db6b18042e01ecf9017a64a0e57447ec7fcbe6a7f82585f7403ee2223d52d37b4bf426428613d6b4257980972a0acab508a7620c1cb28eb4e9d30fc41361ec",
+                output_str: "224d0de7b21690b72a375907a10a4284e9e730a20cb3b4fe396cc6078d9dda5d1a8e81934745361d8eed0b31b6276db8f280104cc0e0ff4b36723cb302381a9be703b0de4c624a27996155599204dd2e219ff77008463beb4461de2de3010a002fdb300c24b1a80c8df311c80d174590043ec365fac147a671daae41f38914e1e6614cb62c4db154735363d7c7b7135096d7edc6dbff1db407c0061c3135ba4577d5682e57007ad6e5b9adc87dc27eac3d03b3fece4d9b4c2b2667e6d9311e342d037d58bf67cf38a4ab448aa4db2c847e678f66ab45f0bd1b581af6e881e63fc170f44fd0f8d87d6fb160a78097a4896be055d0167007d9cba610da08c8c342e4bcdacec6f0bbb30108f29a21947a9d842510e68fb175078b9064364046e544023ccae9448c0727e8fd26330f26fa60ef891489b8cfaa623086372c09c0373c9ffd7e3648ea0f8da7fa99d9f2d6617c0467f2f069f85adee5535100c519a528c690ee9192a888acbc11befea2b81e8fd380cb8679b6d80e37cbe3271ad1ef633204a8b97da2e05565f8500db9b1fd8032c69f57409251932cbdf046e0ab99896109f2eb1217351b242eaf3236139f20eeac594750231186628453970f3c8452e454be3d4d80e99503f350be1eff8778ed13f3d8828768e2f66e03c246b4fb59cc2ced5cdd266d320195a601c4e4928d84c62cdd8ae2ea357e4a8f34223fb18a"
+            },
+            Test {
+                input: "e88ab086891693aa535ceb20e64c7ab97c7dd3548f3786339897a5f0c39031549ca870166e477743ccfbe016b4428d89738e426f5ffe81626137f17aecff61b72dbee2dc20961880cfe281dfab5ee38b1921881450e16032de5e4d55ad8d4fca609721b0692bac79be5a06e177fe8c80c0c83519fb3347de9f43d5561cb8107b9b5edc",
+                output_str: "78023c45dc98541f14c21df4148a80ecd01f52ebeaecf7c28e9fe2b2c69b4b882805515064800089e6f18223a624155de37ec8ec07e68e282204f3ac9bc33f8ed6dd98ed2ffd9ebbd0627b0efc88f7bbcb7815795928766698dd530bd0aa461ad9499971fe935bfe38b6a84ed2d842572eeb97d7290ace13c41899656bc30317a95efafe163494eb7e358fc31a39a20012a82f564813234d598efdba11edd2b0f3a2554bf4fb216084772df94e3d43e55f188bd8b8b5b297e406f2b8407ffdede7ede9227ed6ad78e098147a658269c26ccc0f2988f06de00651a7156407cad75884eddf56a755eddd45030a4c43a82d55600d8fdad155d13014cd27f827a30f6031e0173a2e8da9a8fd9f7590eca5f37747e5abcc9c0a0ea589422bf9647f3fa9893ba3616c38c15ed6cf1f9ec2a64b616a3c5e6c5862fdef36e2a44a911269f4ade8f7b90272eab51fda36d9cd0b88dc8951088eb0d7d68bebb332d22c4240f5dd354cc67650cfe4659d354742ada6828a7cdfa82f77f1c846361087d14173775f44c8601a56774280d941f256a89eeb850056b38480972a6bc0d893a2105c584bcc3e963df2dca0b39b82823f5a4261fb9d4412ababa7785fca635a84bb757e1380531f5ef986f3a771e4948653178b240a32f8672b8b655f0bc832f853c206d2f6e73dbbdc2669da67666947ee50ca82cca023b5a3c485a9d21623d8a3d8"
+            },
+            Test {
+                input: "fd19e01a83eb6ec810b94582cb8fbfa2fcb992b53684fb748d2264f020d3b960cb1d6b8c348c2b54a9fcea72330c2aaa9a24ecdb00c436abc702361a82bb8828b85369b8c72ece0082fe06557163899c2a0efa466c33c04343a839417057399a63a3929be1ee4805d6ce3e5d0d0967fe9004696a5663f4cac9179006a2ceb75542d75d68",
+                output_str: "31edb63fa182a6daadae56c08bc794e74677457c69cb23ec82d2b8f74b8649f79754a8d9bd42ba3bdabe0c4a161f7464d2cd80972824e6a04bd9cecca798c2e26937afa93194246468d66bc8769a26088513962435d3dad9b1db5544e6a2050238a242397ff6e7419569ab3ce2ec14c54481d634f56d1f32d453aaeb23b2078502190c8d1cf54e467cfd51dcbc6e82f95197ad1f6cd301849b76ccde540cff8403d19ecb88db81a45fc13629800d000fc5cfdf508014d4324ff6d2414535e5ef3418555b81aa3ccc74ffc80c6f4f170a3ddd304d1d5efacf554164e0ea798572dbb3393f63a7b9c066ad68cf25af0d36400e427a5db9b3ce639be2db8edac6ab1eb2e362682d6b0ed0d2b84cb28b56f1af4f4a9df0faf3447de9a2841b49cb2aff2423a2cf58930d0be6331349511c26d6f07a0abd32a54f70bff5f43c599aad00931ea7f28a85010abe8c93f941b4b4931813796419fb41f3bd0a6203b14bbb288116736b3a31cb53ff26eba377624c1a0a280b768dadaac7ac69835d8c324234eb907b64053678f629784c6cf34e0ab5522d6e9326998aaf24d1c1c62b93652896cc6a9bd7de4f4ce7f6d309ac957c2bb446e6beb8b026537f7fcb7e45ba1083f1d690bcda15b1487defbf59dcc1a5a6edb3dfc783b4224702a7f6e466b4e48da6c1abdd918512783b6a7fb6446d32fb580fd292f2ebf8e3d0302545b8c163"
+            },
+            Test {
+                input: "59ae20b6f7e0b3c7a989afb28324a40fca25d8651cf1f46ae383ef6d8441587aa1c04c3e3bf88e8131ce6145cfb8973d961e8432b202fa5af3e09d625faad825bc19da9b5c6c20d02abda2fcc58b5bd3fe507bf201263f30543819510c12bc23e2ddb4f711d087a86edb1b355313363a2de996b891025e147036087401ccf3ca7815bf3c49",
+                output_str: "2611992c1226b5b402f19662fdf3d9c44d118b949c8aa1073b8bf8a5daf30d9802df7b1ecfe6a9a1e9db9aade3b308867397bd48b89eeaf36c3ebdc97b35eecc2c241941ce702a0ae96f02e881f82ae2842e1a7ba19d3390b2d4b5e2bf3883ecadc81afeb6543dce3857fab5f926b1621d32aaa0b1be10452a4e4d2229b0e50b478e28595e564122318eca4de680e354a745501a8a11ad263e22b5a69e2f70a3f53594540b2b9160c3057a32e633c616f6dbdf8d6ee19936ce8ebe8bb7bbc118d720ec88f3536fad10fb623801c720d07365148672384bdc9039f0118c356ce20eeb8ce68e7c85a0e4ba3ac5bc7b21e6b567f13fa1d5a4db953589913cf2424b7b3def3b234388b7327a4e737b590b9ab1ee126d949c630420a04c32edce22da326236980734249cfae18ac0fc2a253ce77d2813694ffc66b0e60d3ad245ab4add0bdb1cca7e4228b73c18335558959a06bbdf24da8095184b31cde2f4dead983c9e29db2d4a3c5c40c7775ea30a80cdca44b4db2783379074017ffb6f27e45b86f26ca42742db1b11e11bc5b99d5642e482409aafab2bc833b31774a8ac578bff32131d714b2f8dfe91f4db4448c34e341d26fb64ae00e5e985f16a35857e44b9a846402858a192edc0ceb7a6fbfa90f0eb6d743bda4bb9c9e621d7433ae693cfcc991b71eec3b03df1fb03bdba05a63b9bf17c3caabd40808cbea2df0697c8"
+            },
+            Test {
+                input: "77ee804b9f3295ab2362798b72b0a1b2d3291dceb8139896355830f34b3b328561531f8079b79a6e9980705150866402fdc176c05897e359a6cb1a7ab067383eb497182a7e5aef7038e4c96d133b2782917417e391535b5e1b51f47d8ed7e4d4025fe98dc87b9c1622614bff3d1029e68e372de719803857ca52067cddaad958951cb2068cc6",
+                output_str: "6e722a099b2b47e38c69a0b967420fc5c1ca2926568bce435e5f97d945b261c61483b45f517827dca03ff3ae670883077d5625112aca377e731364932767e5b3ae406adc06283549d64fbf3eeafbd79064420edd544914fa479355f6bc6cd0a88269eb1b4c5e6e2f43f380ba5c1d343338fe73da047e9aa9a06c4a14aa7096b5ae025759244a99a8fbe61b7e326841edd3779a84591e9e44e810cc24870b42bce705f06039fe93627b51dbb8163cf8d4ac0ad3983eccd3a90a85c58ab222463323d5f786292dffe07e607c100d2c830436aa1e4741adc7a7439053045ee3538822cadfe37413ef7948b67f858951df901a7e3d39ebac040eaaf4c6277656eff711034ee862dcc247672dd0bff9b577286750083fef332f630348119461cadc2089c332f9a0078d074cebee2e8b5b8a1a5b4818a53e9c99c330da1682073a7631acf1bf621c59aa45935fb82e634d2549ff405d36b23327c66f9b4c7e092b409228f8b0c95539c3a9d89fd7ff92d2f811055f6ed23cfd984445f7be0b906f6a920ee0af326f4f60d8b5987c736710796b33e58d2661af11f8ddddb12a12b196308f6493567904d49124da69d291d73b104b5c99c002a6606718eac2ca92f8a6be6328a5df6968db53ca0df2990b68f0a15a7f8b006baff2483a0f6d93281c62fe689f5856909cf3c56c5b16169482cd779a3137b6c702c7641b2ef2e9987f5497"
+            },
+            Test {
+                input: "b771d5cef5d1a41a93d15643d7181d2a2ef0a8e84d91812f20ed21f147bef732bf3a60ef4067c3734b85bc8cd471780f10dc9e8291b58339a677b960218f71e793f2797aea349406512829065d37bb55ea796fa4f56fd8896b49b2cd19b43215ad967c712b24e5032d065232e02c127409d2ed4146b9d75d763d52db98d949d3b0fed6a8052fbb",
+                output_str: "7b35855b74d677ab6dbdbbbeed8f8bed3b08df15055606a7e7fe9f5e319bc70bd9df00a8571abb6e6c202461ea00a2d701da5c3942975c48d78ce565689e36379ea603fb1c6c53b508e0952b892a5aba6660980a38fbf7c91d43bdad1f3eb20910beb91502404b21d3c5283a0a88403c6aa47d9dd0a04a23dcefcd3527e4e961782a0e585aae6bc9b7e6acdbbbff9cc76f757887174cee9cfa531c380467388fd2153ba8acc2af706f35667253216d3a1e623a747748fad46ad65265e4530ab84d39d9988eb876853e976156900d9de464cc2c57385f55242608c9e9c26b67683293b1f83181c60bd77549c576f2beb8e54b3ec5be2feac8cd340cf104b0a49d9fb484b538296b31e30e55f7a8421e5e16b91869214d2f7f4dc68736e09ff2981518ff83f24d51e5f9d9300938600ea6c007c9c98a392b2e63216dc1f07ef4d602f47c1f234b857d8650d23edd344152ebb5daa47bff8e394931397ab2231df1e22c566384112e8560e69ee422758e8a76e03d16770e5d417b6fb5c68d9cc93e16759987fe02bb8c99b8d368248a6893adbea888315d4ad251fc57fb1eabb2ab314b24ecd374f4566989038134788f344453714f05a81ccaebe92c75200fd8a019e33a362722f222708c4f3894307d09a4b4d3666002a8eaf2d6cd19db119a957d2b66b0c788241cb7702ddecb63142aa7ca5b028327cb51d72904f2d819b707"
+            },
+            Test {
+                input: "b32d95b0b9aad2a8816de6d06d1f86008505bd8c14124f6e9a163b5a2ade55f835d0ec3880ef50700d3b25e42cc0af050ccd1be5e555b23087e04d7bf9813622780c7313a1954f8740b6ee2d3f71f768dd417f520482bd3a08d4f222b4ee9dbd015447b33507dd50f3ab4247c5de9a8abd62a8decea01e3b87c8b927f5b08beb37674c6f8e380c04",
+                output_str: "5b31c72a95d9ea4ab6ebfb2b2501f14ec41223a010e123b68865dfb7061f8cc00f69be86e56a376a377e9544860f44b543b48c8a56c6a25546aa7573c29daba9b746a94ee82a33825047c019eead9e7a79d50362f649acd1ef27df8bdeab02965aa0c0ce67312433e0511b19a5d213ef9720e688a80cbdc7ba1c50032701676bd4aab79675f85f76b7458f3e6d723c62802b1892f0c2b45138142ad9ef329d771e6873be098cb8c501c3732836eed9165b69ad40ae5a642d980c7bc843fa76b605fb68872de523c591ce09f21976ab47ff64f773b5d7eb54366bc003fd6f75745c4b14efbd1acdfec8439550681208543e469274a1fddb16d4125a01e9107855149aeddb7e21298dd8c309ab1c1bd506f2d377042f27fc275017b642456c93fc882e3cf44c1978307e7b9bba16f612e28e99d2e18d2d85ddaa235fe65ee40d905a845768372dd621e6394afa4c59378db5feeadee6e342d004598779f08eb9a231ba0ccda0a1c7d19ac741505f0d931c73f241d1999eede40aa53a8a47f629937d29d1a6d2aef1807be7c333daa332b4c5551a7f37177f484740be772eb03d04e82b2487aa65a2e4ad00f553060c6a9577d21a6c3b731d9d1659e54bf14ce4e4b7932250a8f3711feb7d9997a5c554dba364dd1f16ab4f34b37fcf5afba5b06bed58e6acd232d69963aaed993f51a1c4a2347d8119d381686ab0942190680cca"
+            },
+            Test {
+                input: "04410e31082a47584b406f051398a6abe74e4da59bb6f85e6b49e8a1f7f2ca00dfba5462c2cd2bfde8b64fb21d70c083f11318b56a52d03b81cac5eec29eb31bd0078b6156786da3d6d8c33098c5c47bb67ac64db14165af65b44544d806dde5f487d5373c7f9792c299e9686b7e5821e7c8e2458315b996b5677d926dac57b3f22da873c601016a0d",
+                output_str: "d4d8f990acbc762bf3bf4382ee78466d36aee8e7d3597c8acdae9a6245020ba5d936e82c2c8d7f861186d428f3abac5e1f5f4fa25ea3feb4fcb850abb7f654167118574a730ceb1ea5d4a3ef579ac58169cd02defb896fb0e8c0797d9a326c1aa696eb1ae150eb2ece9b49725fc6c285af8da2908eed93b6b01512b80e03bdc74e9a528843acd2b9fdeb352230bc1bd9f0f94eb5c9356259530e8e0060e0eb0751ee2f5cfcc2890e0fb8e5512530ea0d6a7475afd535c34bfd14ebc48a0268f3fa671e87effe404d63a03ee92759c6490adda245bc924d582209e7406905678cdde5529f68db56602d546d2e36f5417db7d3acbfdaac622a65560611ff98a262558b304728cbd7ba748174c0eb2faa8907e1056b4af0f820b849bd9411129f4fcf0ccbaa3400c2b7b16a2126c53ef6ca35122f8a8b92549e6ab330c4436268080898ac9c03c27cee9164ebb9c4b1e54d211b65284047f2c535d3f871ff50b81c437daebc09507a318c296f1ff48572e4babeaf96082b177b4b80bdfc2f99fc5b5bd6983e0defb28c98f5eb2ed1d4b36641d3ddded2d8268c10900284b8146359694f4d09f176eeb550b7629e6a936e0bce2877c8525cf4983327227e13b119791d465f9febaad25943ade5631f1dab35aeeb7312ea7b908d19f257015c1cf6bfaa29728437f7620cc9c0b00e79f684e4f4313375845b9b524b3842fa0dd1560b"
+            },
+            Test {
+                input: "8b81e9badde026f14d95c019977024c9e13db7a5cd21f9e9fc491d716164bbacdc7060d882615d411438aea056c340cdf977788f6e17d118de55026855f93270472d1fd18b9e7e812bae107e0dfde7063301b71f6cfe4e225cab3b232905a56e994f08ee2891ba922d49c3dafeb75f7c69750cb67d822c96176c46bd8a29f1701373fb09a1a6e3c7158f",
+                output_str: "77a1157dfd30a79c34d64cc29b9712c9e1ca76ca5565d0861d337627c20a25d85aa061b876a850b43c5ea74946d03e35b6669336aa47c5859ebff82333c03741bdb0930375c34275f2b2caeb83cfd28965da12f60a646ee52372773de04613a3ddee266e20e0ac047b09260e0b69f4f134b5ab8eeee481f887087c0f8639cd32c19fa514a3114e938ec70e8e7e6cf40d11342775c0aeaafd8f8b2dcc884caa603bc8ffb7a282fa6291bb3aa37f37cf9707632879532cc93c6f5c46fa6d6235d7fac64dd9104faf484275cc635c3f732c30b155e22552d2bec2967af002683df1286f98f25d916ea9972dc6d2c5af1a1572bc5363023621a33c0fe41285148ca9bfec731acf75743c9c64b48bf98fa32b6d92befc777f6b29996319bdd632d56f1bcea5c52db9e72bc71d6cc4d1ce7876b02fd48e4eb1110d727afba35afbf8c43e3445b650f06c91b90b12c3036ebbdaeb3d2193129b22e188469a3c2d469f24b530200a08e931b2e95891d966c7a50c2365a73d169d010fdccb7f3a739d4a589a84780ecdd84bb34d54ee5ced2c729a04b27f9c82deb329e491c7b462308c397beec649e4d76239a75bc8bf28b1a8cbb81f25f73e53e19b882f0855ab1e93d45f9293508c66c2211e978267686f5f54ae987d59d73db8144834fdb2df2d52631c7671aca994a99b8009c98a4f847b71a29b3a0636670721aa58baa5a11b6fe8"
+            },
+            Test {
+                input: "fa6eed24da6666a22208146b19a532c2ec9ba94f09f1def1e7fc13c399a48e41acc2a589d099276296348f396253b57cb0e40291bd282773656b6e0d8bea1cda084a3738816a840485fcf3fb307f777fa5feac48695c2af4769720258c77943fb4556c362d9cba8bf103aeb9034baa8ea8bfb9c4f8e6742ce0d52c49ea8e974f339612e830e9e7a9c29065",
+                output_str: "4031b77c2a88ab9a31a357652b5ec18239ea42fef5b390156d7a50a1c1d826a52297b169bc808725b00a671f83f856fc37ab8c48e5d12e277558896f19fde5038c03a95a3762ff48dfae4d644b904845dcba1145084e6b7316fcb5742f31325308942fc31d7f465f6c4d686be9788de37fb57a6cbc67ccc39f09831acb1b1d8010254e131ff7a05031f031e6375cfbed440bf0d66f7021a927ad249bd3c78e2596dcc4e4ffc58d0f7331bed5bcf249c8092832c17c701c65bda1dc9c50894726b04661f5fb4feb570d5d3773e33d2dcd957c171ed631e4ac5a8f42b3828f78ba032630596dd8b8462a2f25e502b25da1747d80f96dafff366e787a340a0af43aeb8d95d565b1bd8d7f8db4fa4c76f5f8422e6c240339c3dfe8d4d13e1db745d8212bcfe232aa5c519beccf64b38085109753e2fe5014f9eae6761d6d600ea05cf0ae6d4300c7670fa1849333bb739b43a7ce58998e4f834309e9505856ed020eb8205571d3fcbf3a9d316a4a8b6e3a397c0200977ca95e854aae35a5581c88448966112ffc0128f6a7b5de197019d830c619d70803b72d318d78fa067dbcad646857fd8ca5b6ffbcd7e0e3d02b6d13ea02b9c346e0000c2488fca6e8e868fdee7891fa12b095860b11b7c5459465d09b6a7b388d9bf6edb0b99486a8c949dcb2431cc8ef13870bb15956b17405dd1047b6d54cc74d0d4edc3df689e09d7381c2"
+            },
+            Test {
+                input: "9bb4af1b4f09c071ce3cafa92e4eb73ce8a6f5d82a85733440368dee4eb1cbc7b55ac150773b6fe47dbe036c45582ed67e23f4c74585dab509df1b83610564545642b2b1ec463e18048fc23477c6b2aa035594ecd33791af6af4cbc2a1166aba8d628c57e707f0b0e8707caf91cd44bdb915e0296e0190d56d33d8dde10b5b60377838973c1d943c22ed335e",
+                output_str: "31b51a74b7392b14e2fd94e248e7fb7740536fb6e88ca508d019066c6cdf83baf2162f4dd175bd7e78326f1a5d6bd3a9d9b5874c474c08612edc3935ee24bd643a0a3abee5626c43e99bfc73ea434872aa22bea87311ab71880096ce23085dcd489fbb2cefa4cfbb06d12ceabd4b1d28611606cae04ef71e7b37e881c2c1089e08268ce45e0d25aaf6843b45aa50f2bfcbf8fe291fb2745b770cbd758cb0a86c8fa439893d93b5667011a8ebf345fa5059f062da72d0e5c3417bbd3c6abff924eb6bc74f6dd0b30bf48848117e7820ac9892ec18dfb1b567612627f9c2585342d165418d211ca7fa4a1ad6511d3b68539cf2db2f6c3a4c1055785517e0528a6cfb006b54808d7f897b0386f7514897874c5a4a3a30d8d8a277a6a59710d0ba870df52f2a0916aedb0870963c205bf49c6a2251ea92e2f9b4a9b9df98bbe752a5dc258e55a8b3854bf19873f1908e95b537de470319ce3648bba5a038d11c87b4fb9dfc9ecca1bed391c0d48825b022132db26fa3d17d60985d5d0611353f96b03c4b5831fb9bc0c411d1909393b54734b59b15ee26a1952438c886d61c5faad119ebe8576aa904f18fbe19c549abd70f02b1be98d343ce0082cb6005db51a6a10ab5e50a89ee44f3502ab19d62c04637acd5c49de78f5a509674ae8eae906693fd8110e0d750f61562d088e0b87ddaf96fc775ceb0f13800669bf2a00424e6ed"
+            },
+            Test {
+                input: "2167f02118cc62043e9091a647cadbed95611a521fe0d64e8518f16c808ab297725598ae296880a773607a798f7c3cfce80d251ebec6885015f9abf7eaabae46798f82cb5926de5c23f44a3f9f9534b3c6f405b5364c2f8a8bdc5ca49c749bed8ce4ba48897062ae8424ca6dde5f55c0e42a95d1e292ca54fb46a84fbc9cd87f2d0c9e7448de3043ae22fdd229",
+                output_str: "3cc7fd2aa14a9dba70ada029992842231c54ecd7d14fa4687424fe1b54a58c7df8a1e9c87569b695cda9b2a27548398440c77a5a66ba94217dc24854462faac1caa8d171e610b6d280668bfbc87c8ee2160e148a6eea29dc04a57ffc139089ad5ea85f89eed89212ec7439530767563137a4c028a5fb28c1ac53b3696282560e15c1585e51b799273709cc5a1c1a93c774bdb19c4e336cdfdb696a39ef6a8ed8eeae92c5660718a7e90c691c84a56bfff85da418c9df7a913352fa53d8635f9ff4644b8ef03892ffffc937bcee4b9d66154964623db90bab15eb783eb14888411cfe2ea417a373beb4be6ca5771f6fc0ea8266d56275f139eb3a90c3915ad6355287e06ffce64d84fd8b0e06bad9dfaf7f7ebc17cd7ed316977ab481ac47253e2508d349993fed324fbf97067ad19c255275d7ee2e119fc0f4490c62edda700c27b5088d57a7223729a64ac1a418071f4365c61f898a350cb9b82f59562847016a40e72f862e10398fdcca0b86fa1f92d17f35a07c46b3ed570738d231df3b80b0c2261ed932822d811970509d7c664d20bfd597543b3ff61d6ce3b6ccf924ecab5fdd9d0b0deb0444e62d950cb6a688bf470c53930b44ff4fc9b4dc7903e97bf29c5373582ddd79c115f66d31f839d7bbd34808539025ae3da3ffd56778160e18f8fcdbf6744431d42caf155028e96ce1096f856e805d7435ab1da522708411"
+            },
+            Test {
+                input: "94b7fa0bc1c44e949b1d7617d31b4720cbe7ca57c6fa4f4094d4761567e389ecc64f6968e4064df70df836a47d0c713336b5028b35930d29eb7a7f9a5af9ad5cf441745baec9bb014ceeff5a41ba5c1ce085feb980bab9cf79f2158e03ef7e63e29c38d7816a84d4f71e0f548b7fc316085ae38a060ff9b8dec36f91ad9ebc0a5b6c338cbb8f6659d342a24368cf",
+                output_str: "4144315dae1fa8fa09e41ed69b72fb8fc64a62f8133eb9c4bd53d6ca7c3475048afe1d0bc778672d715ed01c5532b393888bddbdc4d43dfd82fbde560a80329d03ab5f4d62358e65d36eae4094880e810d022529a8945ac9be8255cac708fc435310a7741825257babd70e84be8a0099ca66754c135476340f1438237d7c227c31353d3878e67a1856868c665cf049e16fab2fa6a2316053712c3ee808762920fc814b3f336ff8c9846cb43422458f743acc398f922eea476823cce9aaba48d159c55bdce636d231f18f49c9b70794fbf1dbc4f71d87b917ec9d1ad5545a4471592883d63f91cfaf7e64805f82411e715bb61cd96eaf2aaf6a22c14790fc76310facf3c2fb78b34d3cff50bb3f3a19227a18a91e7a6d3cd38d5281cda2cebe333c7eff4d357c55889109d5e0b762471c565e1aad50839d0298eab2723eb4e9d1be73fbfe507189e5f20c54f256084e5ebc04cc622b080ef52c38329f301f8f97fff2a7d8249e2efca30bf77a8a3b9630cb5af5e9a34318b94e17bd8248edabdebfdc37e3476155434d32b7a7905786487ba232786c290bdd790ac255bd100efae4be59fa6b1674c651e8eb9fd2adc4bf5be6a763408dc558825b3a22bf141fa45e6df862959f9f47a91bde715afa65099573f1062333ffed43870cecfaa423fd2211f82389bd80f0f033b4fa12964448846e55ae2ba46ac9e7422c228d75a1bd"
+            },
+            Test {
+                input: "ea40e83cb18b3a242c1ecc6ccd0b7853a439dab2c569cfc6dc38a19f5c90acbf76aef9ea3742ff3b54ef7d36eb7ce4ff1c9ab3bc119cff6be93c03e208783335c0ab8137be5b10cdc66ff3f89a1bddc6a1eed74f504cbe7290690bb295a872b9e3fe2cee9e6c67c41db8efd7d863cf10f840fe618e7936da3dca5ca6df933f24f6954ba0801a1294cd8d7e66dfafec",
+                output_str: "95597492cd331a89c013d6179031ddaa08a90fa825c5a77bb5e27e32ee7eb1f02ea0d348b5372eef60a45a84b84d45c18695270fcfc07f3ec95e00a2ffe901e5c9ee3dad600273af0d73ffecfaf141c3b63f3faea90633917e260857cd1c4ed198fbd4753e82a42128f2525764b5a40a66e1623b81804bd3f17622598bf39fca57d8c8d0e2e2ec45a4ef13a2b6b0acd6e6878ba5baeed796e3b3498385ad7e88576ea08e148698be845b3d7483371b43fa9b35d785a0028ba84b0c8fd81122935dc09869e065d47d95287d3cb4346d8bca8bf5d4dca3bedb1aad70ea3b5acd48c5c02fed30b4706c104dc159ea96971e8f44248501bb782ddc201569622c1f98e893f820d149164f9c465c41a998ffb561cfcd7b3e327f78961636192d6158da80a7987533c01c2dd380912c1acf14330b85e93ce05f2238ad0c1a05995b631abc9cfbe70aca565e9a1cdd424d3f8ddfeddc0d3d3360ca917b30d7216a85a14bb13e8da29228e57aecf1906b084c72236b91d669a312f01a4b7787c4decee4f63ca276f63766edd2e46555c328d538581e86f2e3d74f5592c1016396082ed06adf8df9ea53b5e0c020ac75b636a828ccaffc064657a657f24e62107d772afb24a5eddfdaa4eaf2b99341affaa1651010e15f6f4e41a67c1ea2101bf5a61c491d5a88577c1fa3be0a0e0781c53ba9f9bb85da59c5d0f3b2aac31f45c9ca283928"
+            },
+            Test {
+                input: "157d5b7e4507f66d9a267476d33831e7bb768d4d04cc3438da12f9010263ea5fcafbde2579db2f6b58f911d593d5f79fb05fe3596e3fa80ff2f761d1b0e57080055c118c53e53cdb63055261d7c9b2b39bd90acc32520cbbdbda2c4fd8856dbcee173132a2679198daf83007a9b5c51511ae49766c792a29520388444ebefe28256fb33d4260439cba73a9479ee00c63",
+                output_str: "e7814e78cf280cd8d0b27b311476f21d6185abf37fdfe2851143ec3425f12dcccc0faa95b2e6f8ece8c4156124c9dfbffa77624e5a4a9553f11675844c3af0e816cefcc3eea430d7c730cf135ff6a34e542e50f25fcbdbf3a051f39cb028f20b8d6f85221b7dcde00d7e45b78529638508ab2e6bb8d885752ca6c97455e61564c2ffac68e5892bdedfbadfcc88018a92b599807583e9b8bad62306948fe52b397cf88d20d440898075e3674fd09469d1fdbbb2350751f21e48be74f2b04e7a148286fd25a90995b5a95716d67ab566b78394746da84326b83cff482f82df9b8cbdf3d92992d0f05275d37af3fcd4ce211a9480dad745b6cbc4789c9015ae23d1c3a25d067c9a9f7e611ad05b8d44940ad622c48730282789a839af93d0735725cbee9dc4231e8773b6dad31178053014f11421ad0abcbf32b1e6386691759d58ef7e2a6e2bbcc11b5e62ced89c4be975fda74abe9395dffd9e8c102a5142933252d94b0266ff776e9224985f3f2c96f7beed03ba881b99479862f8b7dfa96ae0b2d2a97f773164e1b473a0c671ecccea64dc67f3a53a21e51b794afc4531ae4f41898e250c80622e123b27fa28eb7f07d4b4fe63d75866fbdd730b54a9297697f541fb429084ad43dc69cce73c6c17253c481a002ad7ee11fe077554a4bb45aca4e9d8b8c8e8407866c011b749c3dba372c2966aa0c20f43c86c01ea74be5bff"
+            },
+            Test {
+                input: "836b34b515476f613fe447a4e0c3f3b8f20910ac89a3977055c960d2d5d2b72bd8acc715a9035321b86703a411dde0466d58a59769672aa60ad587b8481de4bba552a1645779789501ec53d540b904821f32b0bd1855b04e4848f9f8cfe9ebd8911be95781a759d7ad9724a7102dbe576776b7c632bc39b9b5e19057e226552a5994c1dbb3b5c7871a11f5537011044c53",
+                output_str: "50f678ce2970c84ea11dbdaf399535a692df95267340a394616760ba82bad865f920932dce65d0f10b5af1b378f76bbe05cd8c8e16e5720e527326fbf375a5f08aff54c4554282058636c69b6010330c1defba22f175bbfe434b6430c24c06f034f6bac59d1063a4db1fb4243162f368385c5083a93a7e693009bab0f3d8f24ab45f3d20e9582d1e9d0af578bfc8c9a0f09a92e4d76643eba46e71ab177307edbb2dc46139ded52fad1459a41114ee88f439ddd064600402e237835797b4be67efcecfac28d9f3f8b8cc773147400526202984c0cc2cc6616ad2ef5e0fc16509372f9efe63d66cd41c61ae88928411054953bd95813e520e02abbb52bc49cef99cf09bc3c83dcfecf2f6f4768ecccc8639752a28531c0a4038284c174b34978850b02e45d7810c4feb224e3de0c89ce69b06dfee9ce2abe8afb209e29194acb6c526eac490d5a9518d5a7e1c1a7cf734c92579d162f2862ebe0722e2dce53dffe84a52a459b9c1d0a677a41b0f1a945ab597ebd8544afdb1af97cc1e3027ec287df62ea1e81e91cf4325d202ddab62e09e6094fab327cdcfe2ba6f760c2ff7d7992a3fb675c07f77db5bad69056bbd3a50a0a24df64a73abc3ce3c1f131e7e6c76f0fb207f6d6db54c8d128f2c8b670350602d7b0a52153452cc92ee4f185f4570405e54cb95647758a31b8434ebcefdcbf00a43857a58f6506cf8b7aaff3b4b"
+            },
+            Test {
+                input: "cc7784a4912a7ab5ad3620aab29ba87077cd3cb83636adc9f3dc94f51edf521b2161ef108f21a0a298557981c0e53ce6ced45bdf782c1ef200d29bab81dd6460586964edab7cebdbbec75fd7925060f7da2b853b2b089588fa0f8c16ec6498b14c55dcee335cb3a91d698e4d393ab8e8eac0825f8adebeee196df41205c011674e53426caa453f8de1cbb57932b0b741d4c6",
+                output_str: "c860cd3e9223e1cb941e130f9f71c376ee3a9b89da339c61d90ff2b48d1f285fc48a4b6d87c199989d3cffce4fd84699fe385c7ca018d4f31f00e41216412932a833794af207132ea430b07201eed784c2fbaf9506957fb9f7e18eb9fdb06f051419bcc7d67acdb93a9f78529d9b5344ae3c4fccffc406350847e228be20c93b22760ba43977451b3740be9e3b283c86959cf062b69d5bcca35ba5362ef0b2ecfdae225cfeeac473e420ea1ab7ca03d4f4a82f6c32fff843712b78476acc46e4b88f280e3612d5ae2fdb94fc26d5c40812b0e9577dd995fd4f5282e180c37a02d6140fc88ebf5972739d591f13aeab894f240ed4be309daa4f3b0e2d536f3def87ba53a881794b80efeef855bd35026ee9d8492c90208c313288cde719a111bbbdc3bb56aa218ed1b466e6e01728da23950f821016f313a69665d43bf2c619884d20e83d6202acbf85bf86d271a1633f32372b067be55570ccc2c7600b0cea6133ffc787b743f3d2346564a2d598049d92f9c4160873ac7e03143bc3ac5366ee6c4621c25aac1e0ae4eff6a35add223a61dd044593629c082603847bf2b7f07a4115dc1c87af0f7854563eb18ffa8e24ee09e299738ffd4f1e79019fce4e4582b063ec1f36442b085f82ffb99d409b4f692a8ebe9aacf2589306204fe0f168373476393783874525fb808c2b90f1fc5d7a368c90aab7ae46e21feab48d667a5a"
+            },
+            Test {
+                input: "7639b461fff270b2455ac1d1afce782944aea5e9087eb4a39eb96bb5c3baaf0e868c8526d3404f9405e79e77bfac5ffb89bf1957b523e17d341d7323c302ea7083872dd5e8705694acdda36d5a1b895aaa16eca6104c82688532c8bfe1790b5dc9f4ec5fe95baed37e1d287be710431f1e5e8ee105bc42ed37d74b1e55984bf1c09fe6a1fa13ef3b96faeaed6a2a1950a12153",
+                output_str: "97afed51ea7ce6d0082a0ef242c37fd626db617daec0c967076d8e63e4861db3ae1308f19ef4b9f0b7246aa0e255e7535b5c70b341be15ea4537cd1f0235c0f9e60c2168c2b04fdb3dd871460e0bbf1e3193d04e171e0a24bece6517cb04a0b020ad042f28680ed42ee01d4a05c3892b0654c961743591722054ccb0756341b54643817802b3e05d70d71e339e487206ec34765f5c0d2346135070f50d28b8afd91ea2e88fb9dbc1a932feeb781f13fe5e047f7f43f51464b9d28ceb8b19bf34f03c1c9d1dc77a8fe475b349251e7ae0ad171c1fc81b862f7f73302f7b48337edc72d39c59785c5572929a6e4f947632b41ecb4ee9bc5e69cbb746e2512986d3a23c7f455fbe5f1891c7101bfd3aa738c5c84bc194753d9671b8f3eee5a35399615537121713dc85d23e0a7b47b55de82c8109db1e0ca96c471f366318e5fd9671d6468a36be694635f65249d65b9ab9a6e6a5361e35350cd258b8dd145a3b68dcc900673bd1a13369163e5b5d3bc524849f73c68f01c7c8b88c9643341d225e13daca45c62d9b5693e2e04163f96454a52b4baf64dfe2293e438e511854a99682059bad034712fa3e99384244f83aef74b96848d338ccf439bb073552137e903767117959a2d841a157f468e597522515bc43b121b257b698234d19280c4f41eb865882e4abfb4571dfcb2dec5a30cf7d6e867f8b5e0880dadff8da337230eb"
+            },
+            Test {
+                input: "eb6513fc61b30cfba58d4d7e80f94d14589090cf1d80b1df2e68088dc6104959ba0d583d585e9578ab0aec0cf36c48435eb52ed9ab4bbce7a5abe679c97ae2dbe35e8cc1d45b06dda3cf418665c57cbee4bbb47fa4caf78f4ee656fec237fe4eebbafa206e1ef2bd0ee4ae71bd0e9b2f54f91daadf1febfd7032381d636b733dcb3bf76fb14e23aff1f68ed3dbcf75c9b99c6f26",
+                output_str: "1a895365874a70f2304878b1334baa09ef898a0607f3243410ef04b14a8490c193a18fc2fc0af0655e219956a8dd3c7055da00345cb411af9167cb9bdab8939d1565647eb251b7459045184bb050f3700ceb6285114509c8167dfc122b33cd3df761f37a3573a75f5c16aa2376b3270a26522869157a3bf26c4d30a9c1d7b4e7490fc9fc5a4eeac331996b16574a27c32659d0af52e0e50f0c221342bbfe2ac04455b659b814cb888dbbc90dc3a899fdc538ae8e8fee2fb085fbdb79830392084fa1761a49619018f5ebfec31be185f0945f4cf9f5a21aac1dd3f1f3c7b9fa05069264f6368ee4d3be24add6ce5b70e328dffe08043587c39213dd66a6890ffad586f9b13cf08de44834278e04da2f91de05257e0afc44b5ba9bff15cc6f7ee306482704de0fb80b93ade6537358b252d050bef48b9a246ca75d62cee920272b9c4b06fd39fda8dad4d1c3b01acc5d507299d44ddd034d21802e1fac9e02a7c7cdb00f64fc7794a253b1bdc042c35416ec64a3392fdb954d63bde0c1bd7e08cfc655bcd02e27537ee61fae64c0187ccadc045f91f3bfb1758f224aa8768981617f20c889a390b59588e366648bb3a8680b3431a4d0596fc5b5f95c4184bf361b7a2cbeeb424fd08a98b322c37f703a73fa874946cf430a4f068bb1d16898da8f9bb04c03ab3f068a36eace3e2227e7e92bb189b1a4a14c9430ef5833214a62ea"
+            },
+            Test {
+                input: "1594d74bf5dde444265d4c04dad9721ff3e34cbf622daf341fe16b96431f6c4df1f760d34f296eb97d98d560ad5286fec4dce1724f20b54fd7df51d4bf137add656c80546fb1bf516d62ee82baa992910ef4cc18b70f3f8698276fcfb44e0ec546c2c39cfd8ee91034ff9303058b4252462f86c823eb15bf481e6b79cc3a02218595b3658e8b37382bd5048eaed5fd02c37944e73b",
+                output_str: "97fc612935aa839179bd26673524aeabc59fa66ad4f719106826d62d56ee0201965d4659877928087d079948d4b3ffe6cb55bb212e802807a0b9dce7c6ca2ca07c357943891a5abe2dda248b8f703236fce8ede40ec6609daf6e012791c53e10b0000ef3b8df19082a3eaf5c0c0b524816b66bb7b08cb6b65207d0d7c84432af10a552df425fcb2fa965728ef2b974fb59065eebb105719d2534a58435651d743c91fa1953255f777cf6f92d3345ab9af11bef3abc00fc46dc4eea0557df7b683fe58ca3887311224567880c7fb5ffdd5b24b3b8ee66e63fa09202d3133768ac2a4933c923159d651d616791a1a2bde91ea53736ea6b4a097bee70f0ef943dd246184efaea018b9dee2c4fadb93e7a93e40273b5938647a6a10d31a0354dec08a03937c9e5ac71f52db0f50f6d066169c03e883476ef512ecbe2d109d5015a1bf660ea842436060acca32e846612e8fd799eef914e1ee2093bb2e30257bf432d5daa8af87625b07c3c6327768f0867af0b80dce96888fe27203ba076e5b8b90acb51d2ae442b424d6651e8bb7b36bd770c3059caf189aa6cc8575f16b58241fb0b7454e089949fd3aa8b347e0a76d2c5be54a60d9da4be789656fcd7bd5abb9851ec7b72ad4be53d9d2d771ea11644a9aeb6061d74293866cb112d89e93ba0cdb02390aa66f5cec4f9651e306876fb5100f8eae6adcbfb87bce433983768d2cb"
+            },
+            Test {
+                input: "4cfa1278903026f66fedd41374558be1b585d03c5c55dac94361df286d4bd39c7cb8037ed3b267b07c346626449d0cc5b0dd2cf221f7e4c3449a4be99985d2d5e67bff2923357ddeab5abcb4619f3a3a57b2cf928a022eb27676c6cf805689004fca4d41ea6c2d0a4789c7605f7bb838dd883b3ad3e6027e775bcf262881428099c7fff95b14c095ea130e0b9938a5e22fc52650f591",
+                output_str: "531d6b06beff0af847cbf3484d1dc52b2e7799d3c5c384b25858603be71b0c57ac073a330b816bbee8164116424ac5af8e5b44e875e9a6ff54c54e4030cf51215552d53fdf24fa63e95590d4b11a86e305aab52a62f7f8b62fe3365d239b53b540adc34303d5ffde35b702844d05b3cc804365bc38c76f92f1ef81660fc8e8ba535ec58d2cbc4b0efa6d840f537740675a1ec1619a8956ba91d3b91d2417c4d151aff2cf54880b0f7b8ce36a432fc44b30312fe9817be795f07c8e521a183930ec5422079b915fe6ace193b7f59928a2f85605d257ffc3fab1762cbaace675fe130cd4fc90138ae5303332db73c0649459c4f8e0c44291aa61eb3d5982e77e1dd1ea3646c2557e62dc13938e805da7ae0cd2b3efcff6e6e61a8f2793e94665aa13456453282c7db7eccf7c52bd5bcd1a7a8d0fec0a5d69dc71fb78e8ff08c7ad7420c0ca52c80e274d9bc623531e375fe41436b4062efc72154657536391b91d43cec7ef9b19b901183b70866ea2c4416021a339b827d23626380d72aa8a3d66bd4e119b2d254ea426f1b40cc564db0605e015773907dd964471710e7eb3435c6cc7951be6ad4207f40485693f57ecb41d6774a840e495ca1dcdbe1f112f61f8e135f1245fb09059ddae40250862c79befc5432b50b8b8a4ce0804a3127697bdf3331d3cadea1d459f565e0f2ac133234160f8111766d31a89c64351817ae4a3"
+            },
+            Test {
+                input: "d3e65cb92cfa79662f6af493d696a07ccf32aaadcceff06e73e8d9f6f909209e66715d6e978788c49efb9087b170ecf3aa86d2d4d1a065ae0efc8924f365d676b3cb9e2bec918fd96d0b43dee83727c9a93bf56ca2b2e59adba85696546a815067fc7a78039629d4948d157e7b0d826d1bf8e81237bab7321312fdaa4d521744f988db6fdf04549d0fdca393d639c729af716e9c8bba48",
+                output_str: "4f56f2baadd2b624f6643c1dbb5ed95f05fbd0550c3e5829472734be3b4064529cc3dcb3f886c65f074539d3f1b13215256af4952784faddf00e184211db2ec238a5ebde55dafa606b0af6d108791f63121865b6d064ce12e446c0b719a856b1647dc4ba13614505d9b3a91417537e0b110d086750325ac8a1964b8a36bab91baa1141dce862167a1ee4daa01da6b3ec875af9636268cd995dd980dfb6476c0bcbdd8430462aa56bfbea69130dd43640e23ddc4d9b469a521a533dca9e8a197130c3a9503393e958a77cdbf9f93fca6921283c96ee38c7ee92c7f0781ae962c68a07014d6c623a3338a1a19216925a432a9971e7f6366adb701efc4d4404e02df452f9a6b9aece18aa61c56cab2582409e4e741b0ce17c6ff881e3f509f536f8f681268e71aea6376767f5d49df3239c65775199b68c84389d1d4a426ac10d42046fd6aee02d4e0f48ba2efcecf83130792996801e64b81797214a2eda5b2296550a13e38e7daf36f9f2a7b89c1dd0a95590e2b77415c3a35b9eeb89be993333551d52835fe36d91d2f205f626fc03cc4f9386e4d815f6b8b128a9c13af40386538afd481650ef886d3ddb7b0772252b73e9f44d7822cc99455fe118c6d1003fe24f304b83e6c76419527f1cec5e5ca57f7911554d1515a026e573d9d4bf5ff7536475ad14bdb8490ce353e1edfcb038dbc2819d4edf325d6c3479f2c3b02e67"
+            },
+            Test {
+                input: "842cc583504539622d7f71e7e31863a2b885c56a0ba62db4c2a3f2fd12e79660dc7205ca29a0dc0a87db4dc62ee47a41db36b9ddb3293b9ac4baae7df5c6e7201e17f717ab56e12cad476be49608ad2d50309e7d48d2d8de4fa58ac3cfeafeee48c0a9eec88498e3efc51f54d300d828dddccb9d0b06dd021a29cf5cb5b2506915beb8a11998b8b886e0f9b7a80e97d91a7d01270f9a7717",
+                output_str: "f153aff7498c363d04ff8beb191e394852b79f54681e8d03f04b31bc037102bfcd4e7d709a387a89c7dd124fc0192b586f7ad7755c36a8d5dfcb6dd855671298006ef379d2cbbd12cc5c05186717a3985594f19fb4ac62c673cec6d374114270ec32e8c0946c3034aeaccfc38b745d758791842995bedb09a4778bcd504a961cfde3208728b57d246abbc99dc632a2396aa5b3497d4f1f94fb2c90a5a1f51dfcffaaba610c747ce10e5ef2acc9ab03383c8b8dc73517e4d32fa7118bff599a83f937358f7407b4ea4771d5c504311dccebc1262b464415eca2e3662ca7dfccfe38157f15b36682221f65b6f65877726072b9a30c0028dbdfd14c7842d99657778c339a5248aeda1dfa8b9ed56b79f107cb3e690d56a3dcd5db03c47e46d29c433bea894d1386133a78e8eb83c2e6bc2e7593cc3ae4d2c0bda573bcb16e7c44732a370fde3af4dc452d029f44dbe0f539811ddee2cafa9daf752169fec82eec4f35093237f0ed1ca6ce62a1221afc870020b0ca219d03e5acfef2592df5916fea97154e62485a38efa4df203ee808b12692064c609f29ea0c6960569e102122ac74e99a992f37c1a090a9927deab998303e47487e2910760a6d604a73c78d66213a5d2c28c91528340b2d6371a391c3330fdfaa70c5d109a209152d21b63cf616c9c78621efbcf52064da08d90510ebfbd957e28053efd0b78f28dad025a72127"
+            },
+            Test {
+                input: "6c4b0a0719573e57248661e98febe326571f9a1ca813d3638531ae28b4860f23c3a3a8ac1c250034a660e2d71e16d3acc4bf9ce215c6f15b1c0fc7e77d3d27157e66da9ceec9258f8f2bf9e02b4ac93793dd6e29e307ede3695a0df63cbdc0fc66fb770813eb149ca2a916911bee4902c47c7802e69e405fe3c04ceb5522792a5503fa829f707272226621f7c488a7698c0d69aa561be9f378",
+                output_str: "d44138d25419fdcebb743314d267d3ab2839cd302edb06de0efeb5b837f19d7ccbe8a1f22922437fc4eb591bb23ee25af00bc1bb3fc6f43d524d5b8447afa47d966440f620d45c3ce7b482fccd768e436aeee5c25e9cf4c3fd814949b61b40a54ca867825ba2a55e6c3e778ff5cded4346530bbb8d1685a3300e995291b06ae05aebae336c37abde854e57180a79bf5be46f6c879b11ffa6573717ac168ac16cbfbbf5c46f81a4ebe14f0a0faee8d09d8664d26c327721d25e551676a00492442e3f73e4b748943b188ed3e10a22c54c16bdc78ab1fa8a50d6d46eb057dc0fb048ea4fbee4e5a1a653131855a03db2fcc39f698d14d28fd9c361818267e222abca88eb0326f4672dc1305af072e0b75674596a616401df9a53d44d53fa529a7c28ce7d5a71c97880725d51a58a065136034dc3d706f13648a68ab4665af00d5d0fa0ff44d1d1a4ebc44b3a13d273848a3bb558bbcb599300728b7fcc6fe16c5a6948bb09fd1b8185bc6863c1d9f5fff7f0a82edff0ce04ecf004587ad52afded64e4e094b3bc15a3f7511620958fcfaa69e869e85daf7ddcff6cea52c1631ed6418c822380fefdbec1255911829e780f99daa9c6f4d729a91f28ef1d3dfc505971593663710f82bb95fcfd1bfd5c3cbf916afdbd7cb89fbfe586982d0bb7e78d031ebe310606557f83a87fb1070b6839499e4d360e2d36607450c720ab8a72f5"
+            },
+            Test {
+                input: "51b7dbb7ce2ffeb427a91ccfe5218fd40f9e0b7e24756d4c47cd55606008bdc27d16400933906fd9f30effdd4880022d081155342af3fb6cd53672ab7fb5b3a3bcbe47be1fd3a2278cae8a5fd61c1433f7d350675dd21803746cadca574130f01200024c6340ab0cc2cf74f2234669f34e9009ef2eb94823d62b31407f4ba46f1a1eec41641e84d77727b59e746b8a671bef936f05be820759fa",
+                output_str: "d03ed7399e6fc424af6c4f08715b409ba54237cfbcc4b27a2d97811f1cfaf8fe8a1e72b72c9c0c04587d89d9d3b46487eda3ac473dc325e2477ffd14f37da4ae638a2b14e103e2ac9e2f94a8be49b28db4144e2ef8a673412b214ee502fb517c480123289de425543a51910bcb3b52e9b0a5f25baa700a3de0782d4bb409938e7bda9b9a31d1ade69571e4f1835e7a89c41f35606b9fd7dd513200c3cdaaa0b25b6b2baea99b79380d33a21678bf7fd80b2b714e894e61321e559645047f68597244ab611fba697a079634412b64e2ac53ec230859ec86300b4544239bbf88558cdd48bf183ff1026636a1a28b512704c60e805cab7e1f8534bcebb1d40eabb8b98877bca3a98375f2c305803637b75e77effdda79991f059f697910453d2e986c9e6450a6115ba82506376222fe56da466fa8740707116f50f27911ba028a633e30a4f83558ef664b63b6890b766e46875a6ab2feaf64c3587a3f3872d179e826d2e8c6079f159c8a54f36cb770025e7628e936b2bced01b339e13eedf21cf01b783731875bbf199227b9a87e5dd4efa361b86bee1198b54626d105ff05b293308a7da89398f50b736d04113f38e3eb803baf06f049d207e1b6e3c919139ba6a94ef97649151327b2649f7ae1ce88d42ccee07d826b34943cc5d240c20d084391ea0f3ac7dfa5772bfc3dd37443c14682acb0b127c66c284f341d5badcfc381"
+            },
+            Test {
+                input: "83599d93f5561e821bd01a472386bc2ff4efbd4aed60d5821e84aae74d8071029810f5e286f8f17651cd27da07b1eb4382f754cd1c95268783ad09220f5502840370d494beb17124220f6afce91ec8a0f55231f9652433e5ce3489b727716cf4aeba7dcda20cd29aa9a859201253f948dd94395aba9e3852bd1d60dda7ae5dc045b283da006e1cbad83cc13292a315db5553305c628dd091146597",
+                output_str: "5c28103be52c28589ec6b8ea53eb4769aa91cfb8a8f5875a6201be4f03fc9a1caa8e582a11ffc6c9fd4cba3f5e3f21549514cbf8470568dfa2ece224181b865e224f8f07caa4a0891dca60eeed7ccfd23a62731892a1ef32d515165bcc4885997add88f59d0124b53e14677f8c4fff979e9998a76e7a3041d3fb0ee9fe528d08c80481b8e3eb77189aa29e64497269f88894dbf7141f21175132eccc4e56bfe70cd2aac208a6a0898a474470a5961324e16821a78afc25fdb7cf1684295c5036c95dd52478bd2fda24a733fc7e08bffca82387327e69bb63f8e769b423cdafa965734b666c489044c23617594b309afb2f262bebf447a87f41e3824972fffd9f4a0d06b4bdce742123c6fc7b85939dd8f837abf2990c6def398df2b44e40e3c25a6d9e4987b1bd636fc276cb0000095cf441ba3fa274f1f95ab321de9a5a9bcf219449eab4e91edfd058674a4e8cc5f8c0831969de0c17d0eec98df883619fa1df794f2d09372a7ef20bb06427125b6c0849eb80238855cdd3cac4c4968601d053d7e972785aff96d5483aba9d55e3695655ffe879d27ff6cfef0328764d87f786f6bc74cd40b48c50bd1428bce5aa96a477ea02b70d17333ff176f2e70b6eb7bdebdbd0750414e5f32bc521f381f1827214f4d5746a40558064d49e5484d54442f7414bf25dd469181d524462ab73b9d31a729dbfb06da0615fbfe49869d98d"
+            },
+            Test {
+                input: "2be9bf526c9d5a75d565dd11ef63b979d068659c7f026c08bea4af161d85a462d80e45040e91f4165c074c43ac661380311a8cbed59cc8e4c4518e80cd2c78ab1cabf66bff83eab3a80148550307310950d034a6286c93a1ece8929e6385c5e3bb6ea8a7c0fb6d6332e320e71cc4eb462a2a62e2bfe08f0ccad93e61bedb5dd0b786a728ab666f07e0576d189c92bf9fb20dca49ac2d3956d47385e2",
+                output_str: "0aa13616e9ee0c4c35fe2b921118c67145b8458e6179431e8145da829a2efd5b8831b067409487ff6c865b8cd69695fbb2b1c4ae1fcb014540b842f5fb3ea40dcf7c16ff295b2271215f5367fdea93c17b530c472b6200362abf8d81f3840738eea11961f7262c163f5bae5fed2ed42a936ce1a1917df2360ddf4decdae45e1522400f37d55687cd334b47fb8b55464ab7cff75e9dc0ce51d60b43bc2d468f1dd5bf489b690c7dcfcf6e75301c24ba534047739fe592e8637107ccce1b3d2e4bc037aab54b3f8dfe57b9580cab38a983ec5de9184af589d939fb7f6edc886790d1ca4c780f82437eefe261ee4737545eb7379ff09b644936f8ec9775e9f118a1958e7e4687c205424e4a31c08ba819f6827654eed2451f6a2242f81aab3a9aedfa71437e5ac288bbac9505b07e302bcdb109fdc9e2b753432ac6502a3faf9ec54bfda1ce399561410b62c4ff8fd922a1bfba071348ed9f1b242df772bba66a76c0c1cb209ccf7828051f0a85ba54d10b4db0d71e37a77abdd510ea1ff02ec72ba6beb54523de49167bf01594d0c49020cea7809bcc89a6becf9a6c655d9d1f06c2cb1d2d15128fbec2fc388dc39aede65029954735285463e2684226a10770358156c98300fa70fbe2c200dbc0d60f3194bce21bca23aa6554d56503c56e8d4a4b246348a8dae6fd1150cb6663c113b3f15fe8df8066c9bf3979cbb3dbca43a4"
+            },
+            Test {
+                input: "ca76d3a12595a817682617006848675547d3e8f50c2210f9af906c0e7ce50b4460186fe70457a9e879e79fd4d1a688c70a347361c847ba0dd6aa52936eaf8e58a1be2f5c1c704e20146d366aeb3853bed9de9befe9569ac8aaea37a9fb7139a1a1a7d5c748605a8defb297869ebedd71d615a5da23496d11e11abbb126b206fa0a7797ee7de117986012d0362dcef775c2fe145ada6bda1ccb326bf644",
+                output_str: "e27b1c3ba27dc48f20b9605c4fffe0f610ff909b482d213c34b49f0fcb04a927f0b1c4d2c6ab6c9bbc6e7db696f7e41fa1875d08a65e21d0459170e4bc955e7e596aa01c8f52127e858687e53f17691ad1b1aef7bbe75d09613281cf96e86ef93850ab4277a54b45de3663a906b55bceb2528a55ca6e17094e5d0d63f3294d8bf4df2da524296cfceaec6f1063a7bfa92b300a1c4ba7e2cea76ec4c7fe9531e7d9205beb4e2b5fee32cc0881401c573a88ba9d29b5f5a5caf044b0a7931bd605073b19d50f82d822acdf1a6674cbba6c88362baf769f4220d731f3e8dbe707b12d44208e646a441fe742290e9ff783744b0f5627cee1b91de431dfdcd7aedccdbe04eead6dc6ef9e9c50131fe37b6707edf8a021b3d9bcb0f62ab331f43c80b49f3dd5ad47cd3956a2b45a510fec358bd211b2fbf06b6dceb82a3190bd0ab28c7cafcfba4432102ca3067201533d64d44dce8a632c204ccac68b248f0fdcd54beb300e32ca76f03413b4401ba4721863577860c892252db31774ebed6bf8418ef0a12508bbb15b41dc0f2ee5a890915adb2d0f6e28ed207ee8b6536015b763a60a1a96c9945aeb4616613a0eba3b87c02fb1da1f9aa169ef4a5ccd967e811bf83d2728b88bb5cf2a5fec6020137c668ee4f21eae6d2759f054ab1559f9241ee2b65cf36a907720a7dcce655fafb5e534ead32a4745a947ba6c4b20240dd1fc40"
+            },
+            Test {
+                input: "f76b85dc67421025d64e93096d1d712b7baf7fb001716f02d33b2160c2c882c310ef13a576b1c2d30ef8f78ef8d2f465007109aad93f74cb9e7d7bef7c9590e8af3b267c89c15db238138c45833c98cc4a471a7802723ef4c744a853cf80a0c2568dd4ed58a2c9644806f42104cee53628e5bdf7b63b0b338e931e31b87c24b146c6d040605567ceef5960df9e022cb469d4c787f4cba3c544a1ac91f95f",
+                output_str: "b0fc5eac13ad8a3cc49b96e1d9fa96ce4658efacc7394de19aa7a28ccbde37cf1201dea78b4c2f127d397ab5edb08a505f72c70b61678ae081e139f761dbd5741df0cdd04d5a9015c0a65975e7db09d9999fb77324366ef22bb63f2776f9a783a263ce31583d0860f3b91a6620312aca03eac2c38ba62c9c9fa0b060a4f8cc0fcdcae1d414323f2d649a8e9f808fb02dbf926da2fd36c64eccc04909e2308d2c0367a069dd64e2dfdfed7a5a941d2b84c5b6a69956d43843c9b7f14a0636036444870b1b9329b38285a1054a1019b6e01db1c66a39ef9b20ec4e51580ef546e885b99c0e3ea1cd724f8bcf56d1d00d1aa3b8d9b487964e773330b3f84577da7ce9385d37a8f503456897f8be8dfa9a60d129e538ae0ca2f6bbf851f1e56cd3f14864ee0b119a1bac4181c667ebb6c464ab76a6b72681758c70422207e6f62ee438ed6fa467408ca04e48c53350fb11282e89d41a35efb31c80b18bbf4e28cee577798b9726a270245f35faa53da25dcb9e445a842d843da21f197f36d6b43e83c3617b2ac92aa937697d5589564d0fb4c225857b6cef6ead6f193aad457a5f5f7efd7fd88b1ac34b00f4788c4a549474a852403efcfb151d941c949be41151a7130d54730f615e638dae243eaab7648a028ccd05a542054e66b3d5507d78117734180d7656d77677a2c61040dc7ae56819489c0d106b798b9c549046251163a4"
+            },
+            Test {
+                input: "25b8c9c032ea6bcd733ffc8718fbb2a503a4ea8f71dea1176189f694304f0ff68e862a8197b839957549ef243a5279fc2646bd4c009b6d1edebf24738197abb4c992f6b1dc9ba891f570879accd5a6b18691a93c7d0a8d38f95b639c1daeb48c4c2f15ccf5b9d508f8333c32de78781b41850f261b855c4bebcc125a380c54d501c5d3bd07e6b52102116088e53d76583b0161e2a58d0778f091206aabd5a1",
+                output_str: "7b6bfd2981cc29669a120d28930cc39ba577d26be4a822499fd5d36c7be1528dba41f2a60c0f1832aae0edcc384b5552013be17e1c81c326cce1fff5e32b24985a2e2121b072902bd2fc6ce05476acbf2d2719128ab1c35f93ef82290a56542a044b295a26c85e4baf8b8544816f0bac4753d405c9ce02afee0b312b5ec8ad12a07bd3d177f4bc7afef6e092d23c7d445f8b21db59c9a6e819af9afde919ab550e1a6640967d296d3df3d987b6e62cf781a65ba41177adb60b7ca83f57c5ffea1d1d96bf9eb2914ccd73162a8b61b85211d010afb8afede8ea96473b080e98eb7a2f000485bfe6e1e7e6e2ddc1901e77c60db3a65c2f5e57ae72b0ca4bab6e2ec40f62f33e865f04598f66fe14039fe03c5df379319413440a31782c2fe4092b0b701e4b792ee449fa452c023fa79eac7a11a458b497213e7facad5d5ed475e71fabb4d9f6a2c2613a8d4df3f574b5c2a884645b6d5fefcb355ff18db8abd8a85f2bc531efbeb96f24e204733e9ee3f0ed2acdaf99713adf32dca518d5d86659f25efb8ec5e5d82e64460094b88db621962f76c9f12e739a5061adb812043b9bd01fe9b4e549bee9e304940dc7f05d45acedd417b9b37f214411f75b427e2e9ce14b6dca4fab0bc893001cb7a0529c1421e5b721a9bf9031d164c6c6192fb38c229c852474cbadd6924cc8a401662db173d7fc9fc0028c905574802ea77820cd"
+            },
+            Test {
+                input: "21cfdc2a7ccb7f331b3d2eefff37e48ad9fa9c788c3f3c200e0173d99963e1cbca93623b264e920394ae48bb4c3a5bb96ffbc8f0e53f30e22956adabc2765f57fb761e147ecbf8567533db6e50c8a1f894310a94edf806dd8ca6a0e141c0fa7c9fae6c6ae65f18c93a8529e6e5b553bf55f25be2e80a9882bd37f145fecbeb3d447a3c4e46c21524cc55cdd62f521ab92a8ba72b897996c49bb273198b7b1c9e",
+                output_str: "6d3173f315362f961f2728c60effd5ec721d68eb7d2e11c1973a84a19060eb5e64dd8fac20c76a89d811ce260d7020ea9f7ecc78eb3dc91171cbbd0818b31c4d717274dc164ec5af48bd1916b0440b4bea6e4d482329c17aa557dcb4dbad69ad74be1560efb043b78301b3b1d42e9c2b096cf5d8138811dee6ff3753055c77fb2c490bf79e2f7c48d492e59b5d74798a1095d9bd03ef74cd171e615dd3845499a546bf69ad263c1b845b05b5b3cb32351ce01eb10b918d192d1605802a6607ec5de09824790b5750685a8c679b54789bec0d6fabf80e5438f9bed0da8dc5773fb21c4cf231e1163b30d676a68ba04f7c6bfe5aaa2807a52a84e1d12855ebfb2bdf44c34ad846293d71e3b05d17c1d4102d5c7775f30d13f8290c89dff886b1d126834516fd3acc848b988ed4c4f046b39ca0bf2f17a0876b5ea782160debf5a2709bd38fc0f6bf3d1e286b7a34a59afdf4b7559aeb2330d94576bc10bf5d1247eeb12b45516c2287d6738080569fe9179b83a27f007073428c7316ac974dbd98e137e771fc7f4ed1b779c3c6774a2a36a5cabaf10ccc742d9190a3278a33d6af490278796ea76d8706b99561390e06e90396c4caf101af1d86748171d07b5794fa831acc94a2452769c83203b2f845af987c81bbd02aa91a1ca481abb0b25991c0e61836ade076f25dd1852a032a223b3d8d12cd544ed0a2f97d735a0e1aa9ac"
+            },
+            Test {
+                input: "4e452ba42127dcc956ef4f8f35dd68cb225fb73b5bc7e1ec5a898bba2931563e74faff3b67314f241ec49f4a7061e3bd0213ae826bab380f1f14faab8b0efddd5fd1bb49373853a08f30553d5a55ccbbb8153de4704f29ca2bdeef0419468e05dd51557ccc80c0a96190bbcc4d77ecff21c66bdf486459d427f986410f883a80a5bcc32c20f0478bb9a97a126fc5f95451e40f292a4614930d054c851acd019ccf",
+                output_str: "07cd8e0f1916d265a748a8eacbc81b045d004fa104faa1e3752b9af131367ff0ca7f63db46480b67c405ec16eb2922e60667018b9abd91fce022ae9b0faa249444b12223cb43750a42b1f9166f54836c7866bee31acc681b521d61eea57c2e84a8f8cb9826e20ad2b14377b313225b50a1b49aff085f89aae22d3beaed142c585316615281d88c5482e9f7e23770da82f27d2511e30dd1958c903ef7af6b2077252c7701d474f8da4149ab45d80b6ce9ec1cf08877b6ab13ced7fde405a1ded59f856068d3619aea92789e8e31be67dbc2f402fddec3e3e505fbaa396bcb6dfc5861e497ef576fe4015ef743bc4d5936f8a5247b7667a321614539bd4dfbfd79f3bc90e6cce084e8aa6c9adc17c2e1704e4e2eb879db4d6a7a6621c972ee54ce582f3403c76bf3fe60adf14d21d6438146ec92673b4d277825f1ba515c86345cc280fd66a006a387488bcd537c5b0325b21bb69e629763259884e9c3202a16acb5234caf9882abc9b0935466f0c7104a04981f75488eedcaca9ef55f03e3323fd4086e19043db1f7ed7f9afafc968b7313fe6705673cc31387935f92c26af140d2aabc7bb76f976ecb2a6f6dd1d0e65dd997f8648b7bb9f1c9acebfe1988e9514f8770da4df0b5ef397e58470c656898667a2e0218c70ceabcce94025c3914c91bc1bc76e82b1c17a7b938e92a57e953cb80ab15726776382c74dbdb5faeea56"
+            },
+            Test {
+                input: "fa85671df7dadf99a6ffee97a3ab9991671f5629195049880497487867a6c446b60087fac9a0f2fcc8e3b24e97e42345b93b5f7d3691829d3f8ccd4bb36411b85fc2328eb0c51cb3151f70860ad3246ce0623a8dc8b3c49f958f8690f8e3860e71eb2b1479a5cea0b3f8befd87acaf5362435eaeccb52f38617bc6c5c2c6e269ead1fbd69e941d4ad2012da2c5b21bcfbf98e4a77ab2af1f3fda3233f046d38f1dc8",
+                output_str: "16caa902c04424d5fba44b3adda34326eeff62d6354e3ef5200dc07a0325b2004cfbc3c972a453fa32bbd68af381f78fd768158194adaf9b10a2a95d9ea9e8d0266c5d3271bb7b59226c8eaa9f15f9ed324ac91fd88b9a23f50eaf0f17d8582e8476e8806f31b58acc36ebab6b856ce1738704753a7ed31f822be83e4e08f2a3f3dd52d4bdf8090dad90a015e9184a3202974897d525f23a4eafd1a565b76411d8b78df548ad2bee3830faaa3e8add2dbde479236ad2df12841622877eb4ee895a0af9799dd727ed96acead478c8f4b9aeddfe7fa3879529c60026ba0a7966799b372b922b4cff3f6213c5d73c0d778cc4b9ce67013d905870b12cb3e2326223f57fdda8da32f3700e855fdf3da47bca440b219a925258d6b38625ad1408ab303855e3734067ed188fe122c5c279710e8edf954ce4f43f692da7eddd3b84164c567b2852efa262afb09f49e50b8db278ed215efe1f0f43eb8bed5c3f1ecab591e191cd36b6ea75260285f667c204e159e72072e165457a170f32a7fe29664051396ba1bc202663f1ca8f17a99598df58a512b6685798e5e93faf9b49c9af0ca8fe4b6544492027cb5599448643e1efc642c7c71821bc06d5c600a80cf43fa64342cface0c57071627903def82a0ab3a3089c06f89f99a5b3e11524ed2fad86b73f3f48bc5b912cf31286c498305b77cc8f7d54f343993888ced370dc93e0cac9"
+            },
+            Test {
+                input: "e90847ae6797fbc0b6b36d6e588c0a743d725788ca50b6d792352ea8294f5ba654a15366b8e1b288d84f5178240827975a763bc45c7b0430e8a559df4488505e009c63da994f1403f407958203cebb6e37d89c94a5eacf6039a327f6c4dbbc7a2a307d976aa39e41af6537243fc218dfa6ab4dd817b6a397df5ca69107a9198799ed248641b63b42cb4c29bfdd7975ac96edfc274ac562d0474c60347a078ce4c25e88",
+                output_str: "1e8fd76a766a100a4434ad568da7e753c08e76e515dc7a4d42a9cbe5369e3cfaab7a09799b9cb66940de779266051581e6b039e76f446327188a6b34565d738f1a926da3be16cf6ebd6ff7f788fdbabc0961158321e34c26207ece1a122e73d5f9675a2fcb2e4871fc04875fbdb9b6411bebbfdbe71dd643ba6bb2e2ccf46d1c1df9dc6c0777e7a19823c1d55a648b847e398f52d02d5632a69323e588acb113289260752be85a42746e62087b5a32df812817d0a2409c36f6c80912d4ab80d47c7de7ffe26e10b1c850b7339274dfca594d418c3c4948bb3528f4ea463cfb54f7944b32c050c1c3651168bddcc873ed8057372743a6cc8365763b523fb3d9752a4fdb167a768e96c7d4f277bea031b941bb7002db130b76123a0edc4544da03d9255bdcd896789123d9999aa6bdecca01e4fbfe33860c74ed2fdb54412db927df2d896d289a87591377923edbcf2d2ae204ae6ea85b1a9ad2c2a2729dba3d6e6fab6269288416d569532793e49f61e7002871b8f4a68de84ddc42d081d1c4cbe332ac58c3d81896a438d1861e594db79390ac2bc9398dc21b27e6f7677a94f91ebed0103b2e8ca4068d6489bd0ae5d6b77053616335ecc7d7218b1b2df70a279123268a06ea959965ca1aa26e1dc273142cfcad570330aadaa62e04c383a938ce349c997bdc41e9bc38c29767b964fe2d8f6df96ef1a5bd0a38f06734327315"
+            },
+            Test {
+                input: "f6d5c2b6c93954fc627602c00c4ca9a7d3ed12b27173f0b2c9b0e4a5939398a665e67e69d0b12fb7e4ceb253e8083d1ceb724ac07f009f094e42f2d6f2129489e846eaff0700a8d4453ef453a3eddc18f408c77a83275617fabc4ea3a2833aa73406c0e966276079d38e8e38539a70e194cc5513aaa457c699383fd1900b1e72bdfb835d1fd321b37ba80549b078a49ea08152869a918ca57f5b54ed71e4fd3ac5c06729",
+                output_str: "58407675270c110f4e998d9eb9f9bcab175e4d17f2c3a88896f31cc97a389728b3a93729aca3aaa426e2caf11ac9d121b3239915c857fd377fa2871f76e533a954e6790847ff03531111a89b35192bd624a5fe0823992f9a7c25721e10897fe397c2de7828c258ef6083544aab1c7fa5afcb7b27fc37e64ddfe827883fa0389b8e785676c92396c3e1c1e161e2776538cfe4b6e20653f5706f034929ea002926c0bfb6d9c31857bbbef51ca094faa6a7c9c6b34dd92182e21aa47923c908fa00617f9e910eebff2be3696b6bbd489d72510840f075e24c81f63a52772b8b5f3296c7f7095b4ed732f5dccef632a37f0419378edf651df2870119a4f1eb0c961ae792d7db1fec88ba12be14520648ac3c78d7304305b75d3b1aa631591c1b8128dbae0ebea7ae1dd44ed1950a87bba1bb72fd0bcf158f7cfa4881def36b30a36425c429e3d4bae81ec821b58b6ee1c5fb9c9d93993cc1c341921797797d39cc523d32987eb0d75c0e502f52ef1ffb3dc10a19766c2117122010aa729326ac5273bed622cd04b924c60cd405a14ed06adfcaf35b1ad5ea469cdea963d7e97b2058d2588bd866a17d701761439c491a0af937f7b8b5e8fc781737986505cdcc593dc0627c0ffabc0a1737afae194e24888377af99ad33aa8a0455cba1411a40d1d66abd03f2da49c34c74c65c830bc68c36f87f9e578072ae67a60c23a6ab0f02e0"
+            },
+            Test {
+                input: "cf8562b1bed89892d67ddaaf3deeb28246456e972326dbcdb5cf3fb289aca01e68da5d59896e3a6165358b071b304d6ab3d018944be5049d5e0e2bb819acf67a6006111089e6767132d72dd85beddcbb2d64496db0cc92955ab4c6234f1eea24f2d51483f2e209e4589bf9519fac51b4d061e801125e605f8093bb6997bc163d551596fe4ab7cfae8fb9a90f6980480ce0c229fd1675409bd788354daf316240cfe0af93eb",
+                output_str: "d102bf50a47c12ea4c8d5169bfd14cc92efbdc10b042631b1e0cfedb32de59947eb35402fbeab157062bc6e89e0cbae88bc68190b51ff1f45ee278a486e8535cd9d272a4439ec3f7e65f1c11209b77028b78eae7a19cac0be054fe0811ed8a1f230954fd78130d27d909555ec58dad0a7494bac5323fc56e616795de5d16c1e6427a02e7c33fa8c74459a24ac3a377a7d5d9036afe7f23830fa3ed8f4762e86b3abe0f3159377cebb1e6844835374534f86c04b5215345947ed2062872f3c8fcc82826b0ab63a9a5ef699687c44602f61bf1e9af303f977bfc3232235d95b5b6aeb5241010f01dca2807fbd43d84675c5839a6e2d73b60c037a9e2d98f3af199cb28e4ea6b3beb9de80a702c8b70c039b32b7d63c892a6db1b6fe5a9e2638e8344e4ec2e77394fa03735c7201a656ff0a95e19a6f8d5a8c41605a2731235ba721a4a74f7bce9cc2b1fed1b92f42c2eb665a41ef09b83e75d1b3a438defb704bb360404ba7d67bc00ddb8541949633a106a2ba75930f30f6079bdb01568e46435ca6bf80ceaf3f0d878a560c969263202a8ea9500b71369c958737d85bc3bfb4c3452a47cc9aba4d69570ae9a2449c1cb84ca47f226471423f0ab54516458c23e31df0f80f9a3eb37b0e74dabd4b27bd1ddb50650c92fd01adade439445a054d463f3b068e0f890c33d9f9bb4c31a15945080717ccc0cdb71199b7cf607afdf5e"
+            },
+            Test {
+                input: "2ace31abb0a2e3267944d2f75e1559985db7354c6e605f18dc8470423fca30b7331d9b33c4a4326783d1caae1b4f07060eff978e4746bf0c7e30cd61040bd5ec2746b29863eb7f103ebda614c4291a805b6a4c8214230564a0557bc7102e0bd3ed23719252f7435d64d210ee2aafc585be903fa41e1968c50fd5d5367926df7a05e3a42cf07e656ff92de73b036cf8b19898c0cb34557c0c12c2d8b84e91181af467bc75a9d1",
+                output_str: "29f1559d1ac3e5f5d6f36852e6fa06ae720b939f3ee14ff2b354c9b941a4f608313fd16527486e4dc5c032d0278297797cb591b80f3190ec0f1fa08f87a529eb22a2247e71f05fb4b1ed4127be219e73b8572f9ae21356d8c245fb3ad4de33a743536dd852f2772595d2cad5e85928b6199830ea78d6d0226e7d2cfc35af41ebb590215e416201a58d990a848125247a1a8319630db6fd7f5ff4cf2499f94f1c0041afc9764c2bdf2b0faca97b3a9f8f508162077fb21549afd5095ac0f2d744065b90b9cca781640213b3920b284c6ae6e9877366ac4695b19bc7de88f3e6113fe6491e7830b4cdf74d3e170d7390d9b0403923c8b6471eb5d639e2704d3c360f4e38f6774c6a440d68c2898d11f17601f33ea893c5e4b42d2a7be5d07492d20d1550ba335e3d105b4898a2707e5c97b61011707375d5af0fef1477fea62d383c227e2db4cd59b85e45a81a4562e7541dc2814f20c969028ca8a0e9c14386a648346898dbde372ed9c09a40a2af6e0ac541be0abbab84b2dd6a2fdac9eabbb8c87f58dd95bba7db96403b9bd2274367439775119da7ebb8bc46fba2a50c75454e386c3749d03691f6705e70ad716095cb30326b1e628b0e29d7af932f554a6fc0d0769c4d0a56779a1878de7c3671b68a4964c5a9fcd86daa7bc5b95c6044ac825baeb4f073afa2502cf3388290f5658094dff31f9c68efa7ac1d74881ce092"
+            },
+            Test {
+                input: "0d8d09aed19f1013969ce5e7eb92f83a209ae76be31c754844ea9116ceb39a22ebb6003017bbcf26555fa6624185187db8f0cb3564b8b1c06bf685d47f3286eda20b83358f599d2044bbf0583fab8d78f854fe0a596183230c5ef8e54426750eaf2cc4e29d3bdd037e734d863c2bd9789b4c243096138f7672c232314effdfc6513427e2da76916b5248933be312eb5dde4cf70804fb258ac5fb82d58d08177ac6f4756017fff5",
+                output_str: "c73d8faab5d0b4d660bd5082e44c3cac97e61648be0a04b116724e6f6b657684674b4b0e90d0ae96c0853ebd837bd8249adbd3b60a1ad1fcf8a6ab8e2f5aa7ff197a3d7dbedefb433b613536aec4d655b7bcd778526be667847acd2e0564d96ce5140c91357fade000efcb40457e1b6ced41fa102e36e799792db03e9a40c799bca91262948e17605065fbf638fb40a157b45cf7911a753d0d205df84716a57112beab44f6201ff75aade0bafba504745cfe23e4e60e67e3993622aed73a1dd6a465bd453dd3c5ba7d2cdf3f1d39376a67c23e555f5acf25bce1e55f307252b9aac2c0a39c885c7e44f204cb821c0d37a22de3a71f3a1909b11b7181c42be9b78aa0d0a15444f330007554bcfcc0d8fd87d6431fb93c7cc38767a55d30d3545560bd380db8c4c0eda9399f68f854644266c1b7958b270e75b79134aa01e7dcf1e6fdb6d9ae5d02cce8ce8e480475e9617cc42a91c08d9af6e5101b8ac5834adb2c66987f42a580bb503a4b34a9f15adcd0e23d0d4029479764831d06b5caf3f14b91449f15a291f4ac250b270b6cb3c304725c99e32645e1fc02a0cddd9e717911f2342d9482f8e0979985a0170d725dab4ea66d44f626ba475925fa39fc9dee929c06d009416c0adc1d987cd625a20acba4cc87f72f610867c3a7a928a3a0379676e8fe257107ab2f5c030bd2480e3d1863562e1fd0790280333ed9d5dd5a5c"
+            },
+            Test {
+                input: "c3236b73deb7662bf3f3daa58f137b358ba610560ef7455785a9befdb035a066e90704f929bd9689cef0ce3bda5acf4480bceb8d09d10b098ad8500d9b6071dfc3a14af6c77511d81e3aa8844986c3bea6f469f9e02194c92868cd5f51646256798ff0424954c1434bdfed9facb390b07d342e992936e0f88bfd0e884a0ddb679d0547ccdec6384285a45429d115ac7d235a717242021d1dc35641f5f0a48e8445dba58e6cb2c8ea",
+                output_str: "4a05f2ef1aad5ff4306429ec0f19044077fb64bfe1dcc50f74c3f045e9a9c3de4a3b5963aef771b049111b7b4640e20b1ba84ed7afee325571acf347e311f33c1d421f21d663065c4daddbd1785c5dac0d554cedb1a45a32e28145e98f49dee285b33de14c336d10950ecc30966b79e8613ffebb702fcc00a1c4250dd385abb537a284e9108d16b6f08f4e103f2c5e9e5c879cb5095534151e3c9a316d06dce53b7f01b424d375b564fe6839d1d1f00a2e62604060a9748bcdc8143737959fabbcae1851213e6dc28befda48149de6aaf4a60d4615bed67d11796f6173c3dcf139037b31eec9a8404df07597bc266d3c7d9eb9a7cabf749fb44e40d746d0e9dfb5c8bbeb25e3f1612d03d3eb0c154de4b2708c4f8a89762e171f744518aec134a02eeaf49db2e2c6c9914711288d6b0ce877861d9b10acfcc19643738287da005282f3fc82f9f50aa681f2f55fe1809c9e23a3a59e51c2e894f718372f9fa1564b47ab3f43f0747a17839e933369b6778053e1764f52c5f319e33c8b25678f72332e33cca97c68f19e058e70c31410df4de7e08169d6096b7b4ea48271eb684fee9fc8b561c3fee2dce83d092b142bec1478d26b48c3c6e597a7b2e44027e1eca23178d3afcc67bb530a529c7e1336e1adae74ef0be9cd61e91c6aea57f7ccb23b64b2f84861ce159209fef7a897a16a871aa99e63a5126df2b03387e42c3d18"
+            },
+            Test {
+                input: "b39feb8283eadc63e8184b51df5ae3fd41aac8a963bb0be1cd08aa5867d8d910c669221e73243360646f6553d1ca05a84e8dc0de05b6419ec349ca994480193d01c92525f3fb3dcefb08afc6d26947bdbbfd85193f53b50609c6140905c53a6686b58e53a319a57b962331ede98149af3de3118a819da4d76706a0424b4e1d2910b0ed26af61d150ebcb46595d4266a0bd7f651ba47d0c7f179ca28545007d92e8419d48fdfbd744ce",
+                output_str: "d99e2166e72399f4b775c8c446cb809f149095df22378ddab711b867e3cad17830efc3b9f7d90fba1327e103d3191595ad415ef71604c7a95dfc417f14f5b5ac1b6905396ed94d56ed993e240586e95d98f3d34630c32fc1719e7754bf4f12a321691efdcd42dca695bda56f975ebb08d59f76911ecec5b503e7030d1e626ec89cfde51042f1b75063afb50ff7b43563a09e209b7842507b67e85e87a99fffa72da7229ce5c9f5303eda061a209f46c76be4114bbf5ebc5aede7e22f5921da87265c19f87f1e37ccc218acb903bfb4d617cb95df94255f980924a045b959aae9c58dbfddafb47c9ad78324d27495eadfe665e8b7154ee52ad0219421014fe945aa8c2f3b6223f99e170d2d169c13c0d1cd481b6901a1770dfcb39eccbb40fc6790e69c61c9ec6e99af6e557eea2aad2e73d8a82ffdd2fd32c63dbe4858d97a5955c6b3420fa12af5cdd10dd8c9d6d3c230272187e855b9f405853e6b8e199f071f0ec781be8dfc29e93288f22f600302475ce1651d3cb671a0635baa3daefb73487a813a0448ea5f2efc915c847795bb0f4f5879df7b5c95a2dd3a5ce79df85bcfc1d99ae98748052a27b775b690ff9b0240e0bc0b79935af998bbcdfd37a2829482a9f51ffb253152eccd35588d2cd96bb19441a14d7cb3b7eb2f47cfff6bd8ff73bdf9d9c2a613ebfc5d69a3d7912c4cf2b41db244267af889d47a037eb961"
+            },
+            Test {
+                input: "a983d54f503803e8c7999f4edbbe82e9084f422143a932ddddc47a17b0b7564a7f37a99d0786e99476428d29e29d3c197a72bfab1342c12a0fc4787fd7017d7a6174049ea43b5779169ef7472bdbbd941dcb82fc73aac45a8a94c9f2bd3477f61fd3b796f02a1b8264a214c6fea74b7051b226c722099ec7883a462b83b6afdd4009248b8a237f605fe5a08fe7d8b45321421ebba67bd70a0b00ddbf94baab7f359d5d1eea105f28dcfb",
+                output_str: "cb7a1f8f3b4a92508eeda0287ef3407c5f1a51f2600d3f13c214a36f54f5fa63878dbf6e76e570b72ed63159e01bb948d0ed7602e9d649afea2bdd4c97c7b22ac32485816d9f0bd8fe1443c7709884334e4aeb5104fad05b6c62fbba4f5c5bd2cc9cf576991da24ae01827f3ea70509e45e1bb0742f3f21d673a34e9ae992abff4a33effe61c2c7acdd0b653757c987dc1f575b7181e79702c82a389b0dde618dde5ee97a1a515365d04f3413bff31c3f9f222bfba2061993c7562aa7761175fd51d48beafe94e16ac34179cfe68791ffad63358885c289c0d1d5c99dc42b7dee58d9ed595cf5158d4d5055cb249025f3fa9690a18c9459d7e8111b88aa37d26b384a7bd02e923c2aceddbe31a6f3237ccaa778d5f7c71ca96e72e11920377c785aee9da9d8f11a4d4caac6cb66ae4f251422104e5330bf06c004791ada67d687a0462070b51c0860f1af7af4968feaeb157a4a4448b69ae1166578804d384720a2baa55f06ab17fe0b4a5e4ef058a14d17f99bca359cd1e95de00b5f309052ff4231ace9e1bcb6684355edf7924bce95264c3ffc641588fecc3775af5e5361b5ee995f85f9a612a0055b22f2d440dfd80e91329a2fa02e20476cf84120634f9c320e6803992817947efd9bcf620f4b038cdfda1cd559801ce76ffcf4af63a4af6284293789b548314b2b88c2ddd31a6c92e4e62b705e196cfb2d978d6f32f3f"
+            },
+            Test {
+                input: "e4d1c1897a0a866ce564635b74222f9696bf2c7f640dd78d7e2aca66e1b61c642bb03ea7536aae597811e9bf4a7b453ede31f97b46a5f0ef51a071a2b3918df16b152519ae3776f9f1edab4c2a377c3292e96408359d3613844d5eb393000283d5ad3401a318b12fd1474b8612f2bb50fb6a8b9e023a54d7dde28c43d6d8854c8d9d1155935c199811dbfc87e9e0072e90eb88681cc7529714f8fb8a2c9d88567adfb974ee205a9bf7b848",
+                output_str: "908fc63fee9e11d44e7bceacbc161269a96993d101265f825b86c107c61cfd11eba3cfdb0983bc9ba3a81ddbd8517d2e313997acbe48a47aef48b3bc1a56eec2fac280c96d9adb557b14334c6c555f374aaf9f9560815eb7278dbc81a78e3dc4144b879119c310a2283862574d055d2b0d8d53219c479e8c2f6dac3186c1ea36a6517d26e14f2230f00a1b30b44bf987b3a3f47240498734e6858444a82ed1098442688034d38c578e995424e1fc2386fb10e682eba287f3757b8a4cef19544cda032c3592e13e07241ae38f0bfb77b030273b28d09637b4ad359c7798cf6a76980a3ea331597dab4e18add97b8404d4ae4e5ec874d0f31a60636b2bde4fcfcab9569205e7261fc728a701f19e3791b538bb1ae8e1435a85f7e8f7b95aa45d275af770fd9ff856f6666c8598626cb54404fba35b523f55ec971f70e10e09fab0a88e39ca1e7180b482985e82eacd81cbd2c8675f8bd41691cfba39228d4fe2561c2e8ba1da3124ae3204517f09cb4abd54698f1010e1836e141c706b9ff0916bacf70010a0f75110e79e95a48fcf4724bc0674c9afcf12de59d31c64e532572da4586bc73a6bebed22752a05bd1add51464180de96cdb44d11611fa661d0eac1080dbd25df51a2c7519489e05e1be5b05c60070eb8075a9f0b3fdf6c14d6c07076578ed3a16d8e048350ce9b2956ed00ab61b024aea9e07c87665b7f33e2f5ba"
+            },
+            Test {
+                input: "b10c59723e3dcadd6d75df87d0a1580e73133a9b7d00cb95ec19f5547027323be75158b11f80b6e142c6a78531886d9047b08e551e75e6261e79785366d7024bd7cd9cf322d9be7d57fb661069f2481c7bb759cd71b4b36ca2bc2df6d3a328faebdb995a9794a8d72155ed551a1f87c80bf6059b43fc764900b18a1c2441f7487743cf84e565f61f8dd2ece6b6ccc9444049197aaaf53e926fbee3bfca8be588ec77f29d211be89de18b15f6",
+                output_str: "080c392ee04a0d4efe020fa6c20236e7c1290088bf6ffc2cfcf72d1b16a21ed000fc7a064491899bda1ad4856449d89ac7bc54e3896534837ec4bf950a18a3ecd5ff286d1d0a02e90531298f2430484a667de0121e0d0b392679ad9168bfb4f0d020e7ec1aec006bd0e8a551bb7ef0b751d0075f615c02775c983f45212e4f394e7680d9f81254431bfb9e772ef2ca54600d2f1f4db12d6db49bb9adf03ba6c912e0a8bfab20c0f4d3da675a908277522c8964ace05f138d192b7a2efd8fe663fb4b2486339555aa1c35da18d8899149339f1ac47555080627c3aef75da932bb063fd3dacb6e0019c7ddc5627776250033e6f47eb5930907fcc1f1b627b520aa18b22b12103f3e361801c6eb8b72e18ca9c43efd1e8a04948a9a7ae1b92e177ac6d3cffa217e13cce790efc636153fe24821a7fb500e61f3098711f60fefd6ea90f6f63d6822331d8ceace7c192e3482192b0a408e5c5a36a7c7a5490756fe4022c7d16eb28232a70ec1bd675defe9f87a52cb633dc5bd99ca49d2bee54870fb0919217810ac08312aa2dd16556089fc8706d0293ebfebbdf11204793901190bfc7aff9c87c9b4fe9116dd1e1789e08776efeb71f619827a89287e183dd77c42d791e7cb4ed2e051f2cec42d2ad83b50ef3c0fb6adfcbaed484886a4dcff41844abbfa46016a0fbfdf2d891b982356b315dc17d9fb62517e3163a93aaf05a12a"
+            },
+            Test {
+                input: "db11f609baba7b0ca634926b1dd539c8cbada24967d7add4d9876f77c2d80c0f4dcefbd7121548373582705cca2495bd2a43716fe64ed26d059cfb566b3364bd49ee0717bdd9810dd14d8fad80dbbdc4cafb37cc60fb0fe2a80fb4541b8ca9d59dce457738a9d3d8f641af8c3fd6da162dc16fc01aac527a4a0255b4d231c0be50f44f0db0b713af03d968fe7f0f61ed0824c55c4b5265548febd6aad5c5eedf63efe793489c39b8fd29d104ce",
+                output_str: "85f82caf1a3d6db8e7c6cd49c697dc314aeaa79309fecaac21ff46639ee5cdcb719a6379d871138041f2908d4dd605ac31fde9f89a0136018682ff1cc0e36a3019a260fda0fe430b082445b7f10f56a50e69a8260954f72b356b710a35a5a2a22fafaa5b3e4e3f0919a1fd44c24d33efe5790f9fa707df0e06cb4f195f1af7b2578eec38b8565d34de9665987f3710d8388176aab6f3d7ccab61713b175d5343958419f7c2d65775b7becadc1ab8dfe486efb98d336aa17ec4083dee1253a7e2b32437d75fcbd338f77bb1548c704090c3417db225534f85c92ae1e9b16f66a624f5309297f2fa3df12fac8af36a1f2a11093d4544e0a67c826d7cda89730031d4a35c64bff9cb9512c09fe45f0d628c075737819252b38724bb5a341d3045b4fa4b8ba742b947eb66a9a9121a48b8cfb83b41c90a7a672a4b9bcf2d1a32266c8f13ec46df4d80384c117a56180398d2268c8009cf586abbb7452911fd73c9c3449004a11aed41b557a33d7825c42575c75c0641393346c753b1415d4d4ac224c831f185c2b635c4b6b1c388358c232dc629a090fc0d472a4cceed43fd9657eb33850171f9d6d2dea433874b47f77dca16cdcd782ec1a335d2da3c235914315a243eac2ab81e06d97dbaa25ec029a62f58a1dc78d586c226046886c23a3d9681d68503893f8a9ed9a5b53a22a1345db167be59a6ab8295b41fc464329a6cb739"
+            },
+            Test {
+                input: "bebd4f1a84fc8b15e4452a54bd02d69e304b7f32616aadd90537937106ae4e28de9d8aab02d19bc3e2fde1d651559e296453e4dba94370a14dbbb2d1d4e2022302ee90e208321efcd8528ad89e46dc839ea9df618ea8394a6bff308e7726bae0c19bcd4be52da6258e2ef4e96aa21244429f49ef5cb486d7ff35cac1bacb7e95711944bccb2ab34700d42d1eb38b5d536b947348a458ede3dc6bd6ec547b1b0cae5b257be36a7124e1060c170ffa",
+                output_str: "e07caeb114b9180ed922574badb071b5962ecab18474d1a82216b152dd0dae5cce14001fbe59e25f55604cc3c26e5d88a25393303ff47c1f14c87ea4d16b0a435a43a3ddd22aabc7adb4680c8ffa05baf28f45f95abf93f8453e267b5e584c7aab8e2cf2723ecf211b958dd8277b89d3ff2470cde45077de7535840b0bfef8d2af5fca3cd91fa6ea83c5f7b58c75da302a67154474b563ae9b59b1a3be93ba2bc2a5484ba24cc409896109cd57ab6357376fc0b65a46506d34dcca170da71cc52dff4fa34bc4b979a130ef5663ccc28fbd3e36b6cd103212a96b8710b49ebdacf4a8c41a5860175b694f75f077718c93170a98ee9757237ee90e8692e4ad6c1af6979d567c104fb3f30ebb5bc52b99a934d527fd44704de65431d8063df25e4b31a89629e1f7b7aed0e49c2ab6d3055675c7c63aa4e7686c880f3af3f6caf7251bd8b9ebc0a3c46c72b05ac4db44e85068811ef050f042be1e7ec841dc8f7eb2a7d9d2c10eb3603f952e307289c1634c7d9e648c36b75f31ea91c7125debc5bd3f70f7cca9330484abb5a73523013dc507e1fc5689848d6985f73866ed146506df21bc98d35bc24256c4f911c3d4ce437798431f68e7ea9f608e7bd98d7df892581b2756106a5c7590f6c33116b7c269d4a3010f121aeb0b10666afddebd18af9ff571241ee39e4f2e7802cc75dec1ed6e7f19985774f0733c833ccb9d82ca1a"
+            },
+            Test {
+                input: "5aca56a03a13784bdc3289d9364f79e2a85c12276b49b92db0adaa4f206d5028f213f678c3510e111f9dc4c1c1f8b6acb17a6413aa227607c515c62a733817ba5e762cc6748e7e0d6872c984d723c9bb3b117eb8963185300a80bfa65cde495d70a46c44858605fccbed086c2b45cef963d33294dbe9706b13af22f1b7c4cd5a001cfec251fba18e722c6e1c4b1166918b4f6f48a98b64b3c07fc86a6b17a6d0480ab79d4e6415b520f1c484d675b1",
+                output_str: "1ba3e5682b5210c2503367cf92fc02ba6fefa6c43cf725d9e0a5a796f949bf605c9401d6235c09265c000afcca9facf32b1c6cde831d051dbc604b72b90689cff3e9179bb0a8d151c2fca7db9147a8a95ae8831c475b16b2478fd794087d0d979fa66da5240ac77be4cecb3dbde50fe372c5045be23fde7cc0b6b86a0007d47de80d59a2dbc7883bbb2f76b74e7eb53e8c929ab73819bb09cd61010689dacef17beeada0311f2f6594922ee835dd09a61b41aaf5792c63cec79c40ec126a68deb00eeca6aaead43072ac65e7101b4c7a3fb42101bfa922e43329e736d1dbc90ef45032c82e26cd102176cf8490b554ac9c6fffe81d281cbf29bf5056c06ce2cda918bb3c9f8f49a045dd2cc4d680ba8a22562f1dc53838665720ec60e4e3bcb76014b619ee24ff41b2860b3ba4438527d975a1302e8ff1923211f36673b0be8b58bf0c7fefb0cd50a28a386ce6dad7c30b8f6a3a437e864143143e638fc6474a2a8a6640862ff4c4491fdd52ece0834128137011d46ee7b0cf611b237ad515bcc11fb7b0a4650fd6e60ba8b6bc601de5cf75a66c3f16aead1ef19c47420a9840ca4b1352af4c5c217350840ad035621eabf2eada2a517250d3a6ad834caf2a472b2d5dca3829c372edc64703226ebbccafd316e4ea3a9bc9aa8dd42a9715b29702bba9ae232c7806e5c0c02aea68602f4b580396b27b94385a3dcebece345828"
+            },
+            Test {
+                input: "a5aad0e4646a32c85cfcac73f02fc5300f1982fabb2f2179e28303e447854094cdfc854310e5c0f60993ceff54d84d6b46323d930adb07c17599b35b505f09e784bca5985e0172257797fb53649e2e9723efd16865c31b5c3d5113b58bb0bfc8920fabdda086d7537e66d709d050bd14d0c960873f156fad5b3d3840cdfcdc9be6af519db262a27f40896ab25cc39f96984d650611c0d5a3080d5b3a1bf186abd42956588b3b58cd948970d298776060",
+                output_str: "7f8d0ab3060b5a6acf3522a83ac1a432dd9ebdd62bee5ca14cc54fec0d3ab6d1eacc33603f214c35e8c256bbe7f0a1c110a65a6e7f5ebd6733350dcbba851271a0ea684a0afa032ef530511b5fd923399df93567d9bb1eec74d6fa4ac5451d81feefce00a7074a1f32498ae68380e2d9800ad3da75e0bfacdf66b9f34ce4c60615ab46a8310f85c2a7f9a737e8e19e0bcb540fa9f621378c44e2dbbf57c059d52f79fda1db8a3d5b44c558c8cc70901219ae76cf5f6db962adbb6515b25b5fc81cdca21b7a51911c5f5c52e8f2a863e9f09e927d8f66b063afc73cfa8592b710063544143a8b5d06cc78a604e9b72771de91f48ee55c9fdd831bf91171532ae5edcaca1bde2b96362d4e30115e12ada76aca05dd128fcb524ca8831cf2459a53d97ebc3ac5a25517f254a14316a402a509ff5868cd290c88f43229be54a3443bc547a093687b3c3d97a4d1a09004cbaa6939e86cd75f5135d9fbfdde568e651806af401095c3602ba958fb7a0f4276791b28a6bb75a6944eec6eb8cb9a7a9e288916a15a496df80777feea0f42695ac62e29f137e355a13b630f30e5d4e4435c3180ee86173f59bc19b79065cf3f33f8bbefefde35a8ab09c13dd9d326e98c9730bd033cb2dae20bf076ee9ce764d48bf8a0f7bb9181e60889293866e1c601ab38122220a2ccaac996fb1770cfdbc4e628bba2b3122e0ca351fada84f8183ff4"
+            },
+            Test {
+                input: "06cbbe67e94a978203ead6c057a1a5b098478b4b4cbef5a97e93c8e42f5572713575fc2a884531d7622f8f879387a859a80f10ef02708cd8f7413ab385afc357678b9578c0ebf641ef076a1a30f1f75379e9dcb2a885bdd295905ee80c0168a62a9597d10cf12dd2d8cee46645c7e5a141f6e0e23aa482abe5661c16e69ef1e28371e2e236c359ba4e92c25626a7b7ff13f6ea4ae906e1cfe163e91719b1f750a96cbde5fbc953d9e576cd216afc90323a",
+                output_str: "c625ec73e6d951eb899e865b5012ed72229958f2850a79cb8221ad2248a8d670a8072519ae6dff8cfbf7a20863fd01183d55093c80ccd14106426579ed2fd99578532f9b4d8e11be19a0f0a8336fcbf1bb1d6d91247dc87b563c1399f50144f563f8583dbc208165c106567ec51ffd321d9f2aba7ad2e7f2c1950d04e9027d7364ed831c2155e17c0b083b2ee2c4e720a2638cbbb971cccba1dac6860917d28d341a49cde2b8727179c8b596c045382e6e7c23a35d47880b4a47d3dc79687919194397c3ec00d9aa232e666ba24a1a39cbe847b2e864478af2f59f73b2abf2a98481430943980ba197db6e67a87f3782b7bd99a6e27f82f133dbc6d722b5cde09277f2407671ff44c1117e1265f5ec9faba0a946b67dd268c3b97be198bd2b5185eb07378fbdace2b4b97c8de2c05176cd186b0ad3f7d54da7701654eb1d1fa200191cea96d0f02c86caa277fec59e1c93097fb5d0d43600e3403c53798a33ef5ccab3d5405e5db570a26c3a0bdb304328fcd36e327b5d957913aacdc4d938bd00577963d5fa343109f4719d8192b12272ddfa338612aaacdbb4cb91e129e4401e16a673d6feb16294345fcd0e9bac8bdc30ebecc3bc6dcfdf25adbcb42777a6ff4c05b5981571af8a33d9e7d34534f8f89f555a1a55761fbe2dd66b93330820d3eb032d7a56db79aa7cc372340b953097453509f240bf9ac6dcd0df08d21e10"
+            },
+            Test {
+                input: "f1c528cf7739874707d4d8ad5b98f7c77169de0b57188df233b2dc8a5b31eda5db4291dd9f68e6bad37b8d7f6c9c0044b3bf74bbc3d7d1798e138709b0d75e7c593d3cccdc1b20c7174b4e692add820ace262d45ccfae2077e878796347168060a162ecca8c38c1a88350bd63bb539134f700fd4addd5959e255337daa06bc86358fabcbefdfb5bc889783d843c08aadc6c4f6c36f65f156e851c9a0f917e4a367b5ad93d874812a1de6a7b93cd53ad97232",
+                output_str: "5fcba2303da2ed78b7a3b3dbd3d7d57bbf37b25b75bf8330d39576ee26d830002f5fd36102bd09a6025532371a6246417f94a527220194f287bab34a936836ae84d87c251674f1bd361faf5ed3c023a96ac1e089050c7975d4fb6dda11305d73f2d9bf03fcdb4adc31c5356e231580af9e23b8ac79b28409dc4ede2cdc5d98c67508ed4d688377583e06fae8f195b10c60fa61ba10a7a57a8a52029371ca12c9fba5edd2378fe78e5cc119695fa5f6ecb4f7c27b0552b1231d4a1ba31196cfc7d30e92603cf2bf14e2d4cf8860a3b4b543e48401d9fdc6b8d0e1aaa559e91ed8fe3d6dde2f8a16a59aaca1fefd304d0c42b78441d4afe148b1abf86c92706c5c1528d54566ebf0f4f7f6ba0adaf6abaf5bf8dea607b6c86c789e7ea3229031bb69e60ba745f561208101dbe4774aae3ccd7da3e6c4625b0744b33e6697c31650ff94095c5cfb87024fac512d81cd395d8a30fc562e8e817d5de70e991e4b3abf091591769ea3b42197a4f4dec475f3cffb47700e832fb072b4783dcf44014642d9930f09a2e3c4984a20bed71e4d2ed1c5fe750b0f803d4891a128731f48df37d7e30ea34f7ed816c51f3ded629c7f430cb3f1ed74610e4d6535de05eb6e7520b1cf6653da236dc9e4f8cca8beb696af2a3c15c42e6f87c2ee1e9013e7fe31e891f6f9658f2e270a423154824ccd6be7498a6ffb8ea6c4e5b8a6cf1c33314c03"
+            },
+            Test {
+                input: "9d9f3a7ecd51b41f6572fd0d0881e30390dfb780991dae7db3b47619134718e6f987810e542619dfaa7b505c76b7350c6432d8bf1cfebdf1069b90a35f0d04cbdf130b0dfc7875f4a4e62cdb8e525aadd7ce842520a482ac18f09442d78305fe85a74e39e760a4837482ed2f437dd13b2ec1042afcf9decdc3e877e50ff4106ad10a525230d11920324a81094da31deab6476aa42f20c84843cfc1c58545ee80352bdd3740dd6a16792ae2d86f11641bb717c2",
+                output_str: "07f4933f2a7c2988b9d753240c1ebbea38e95aa1029508296bb49bbdf3bc164839c76d905596ea153c4746b4fea069d2a784d9cacb598a24baad6d215f83f72d4b52604eec0066344fd062b1835570028c1fd61d5b4785ff5b904f5db03c4efb61b424226578392b9e6259fd86dc979526c560057b9395e32116371b3737825a9579b92e1ab5ff9006afde8a618687205438d99b7e1ba038922b140be0dafb7423092f362f537cac8272aa5df14b2dfc2b73f5f4104ba1fe603e00af8e47898c0e955d57ded792c3c93518cd84fab72a2022f189773fae574d5342eebb23f7d7497f301023c1143cb3481ecb0ee732d1477e6bf872ea0d0dc0623a5c0ae526d8885db1d3c1ca0a513d2e4d53e13bfd82129dbaa7a2bf6004d2091e627928203d05b11d9f6335dfc73cb9a7f5c3cf43990e8df0269fa9bbb1fce7646c6ba85befd3f9ece88a93cbecc3f8f68ca4d0ae8197ca479efe0327463ab5b78685ba4000482558cec55d8b934726b820ea4fa9471aef2962a7e1cb4b2891c0b545547a146ca28ad3e9cc6abf69d7dfb87b298ca252387888e20ccabc9e9ed484262a3b6a1f857e6900330abe74454a62e2dedfec3aff7be28e4351c4ac0738032b81c0ff12afb4cb1b94f7119a6f2ab4157cb7c2fab41879943a075233cef8a64523f70e3c6f66c5ee3d5fdb99222b2a3eb09ffabcac867e0b2d06955cb80e7eae176788"
+            },
+            Test {
+                input: "5179888724819fbad3afa927d3577796660e6a81c52d98e9303261d5a4a83232f6f758934d50aa83ff9e20a5926dfebaac49529d006eb923c5ae5048ed544ec471ed7191edf46363383824f915769b3e688094c682b02151e5ee01e510b431c8865aff8b6b6f2f59cb6d129da79e97c6d2b8fa6c6da3f603199d2d1bcab547682a81cd6cf65f6551121391d78bcc23b5bd0e922ec6d8bf97c952e84dd28aef909aba31edb903b28fbfc33b7703cd996215a11238",
+                output_str: "7e3fbad2449b2f16426651ea24f642fb8cbb40b1969fbf10c5a6c3e7b1ad2d413c1f8a78ccd5f4ab0ba0a04529eeb3f72b656ea1030cd94da5ce6b6d7c44728c0cefebd7fa597073f8befd6baa5325918c1baac3b8de7d1e4b723c0518936cfde3f039941ffec3979aed13c16e5f24a8c01f4d87e07f797e2db4d5ce17e4ac40565d32896e3b6dbdb50fc2bbc4d13c2e375f171d8ec62c423a126b45d3c13b6e3ef9cfb9b8fd25bfa74a1793ebbe1168705b7a26ef12c2424e9689d993ba8c02790e83ce166ddb7c838de164744bab16743231569645b144a34bde3a40712f01dc02e476140d07ba3dc4f51da894727443892e7b12555932aaa5755fd9887a9eac8c949e71ee35414150b63b00247cadcdda9c2fb245748dc519c39ec8877c860729d90bbefb89c5d914f99af63725e91401ecae6f69c67cae0c94bacf3d6b13c273019cc3b5d416d6a24d314ef01c6348f2e539578f9368c234efb559352e5acedd53c14a35f680428bba25a252f056c4e452a921e4f83d648838ecb076f4764256912d41d504044ba68f2734d7236fccd924d22735f6cfada2349421bfd51341eaba98da57b3f1a1b9b7b4588cf3a0d1a7e116700fb90c3de339dfb9ea3662364807b91f7d2105d59034a6f5816070b5c4b24adae525c1bf2d267ea4b03079405a436da4264cc50b2b30a0881e4d22a1904dc7311ca397af7399734a0cdb79"
+            },
+            Test {
+                input: "576ef3520d30b7a4899b8c0d5e359e45c5189add100e43be429a02fb3de5ff4f8fd0e79d9663acca72cd29c94582b19292a557c5b1315297d168fbb54e9e2ecd13809c2b5fce998edc6570545e1499dbe7fb74d47cd7f35823b212b05bf3f5a79caa34224fdd670d335fcb106f5d92c3946f44d3afcbae2e41ac554d8e6759f332b76be89a0324aa12c5482d1ea3ee89ded4936f3e3c080436f539fa137e74c6d3389bdf5a45074c47bc7b20b0948407a66d855e2f",
+                output_str: "b6869f1189f52eafcc0353f7afdb8076c5ce063e2df404f3d1314a4de573541927e9f4c67a554bc82e97c3a2f6c679c812c9da6542681461baf009f3ed10d7d2c571288a41eff6fc73dff8aa3cb40288c84c9ed5cfa70f59395e09cf3cdd58b4d2a65187cf38828b981eb5ba8f7e591070f97b3a567188ad4c455fec91ecc2c9829e00639bf6ce1ddaee45ce19d9a183f0e93630886f511125a69218d86c5008760e8ee0cd299062cd1a06d0d2a5e07a0a30da7de30531136b4bae8546290469fa1b18557e3b1316ed8ff1bc94131e9797efc0a2d997f8da22ce6de0358128afaff496db6466210a8682f9d286ab66304e79ce92174abcdd0c4db508f03c2bee0c87f6c39d0fa2ef7f3dbd4201b4a46f418ca1de312a2fc9f82e6008bf06042050ca302c9a386aab9a3a8fb558eabea6771c6fc301f7dea5c13da704e4f41dfc2ea508f1efaf743fd4a3ebd9370cc3c872a41c4bd40eddf311c2f5b7c208bbdc7bc4a93804d10b32769a333e8bc2507143912ce4d918d0dcb4d6462f0790f10bfddcd7fd711e14f411a6ce58d50e70e1ea23645e97b6c154e3bba3ab35411537bc8830ecbf953bb8214df95e6fb5aabbce08f8d017958848916fe04b3d2d5f69db9234220da3388e3385ccb90194959027093a93f7048f35e3a5b0aef90a792820b242c34700fbe7f7e00c00d6abdfae26ddc95ca47a72133f97924d67291c6f"
+            },
+            Test {
+                input: "0df2152fa4f4357c8741529dd77e783925d3d76e95bafa2b542a2c33f3d1d117d159cf473f82310356fee4c90a9e505e70f8f24859656368ba09381fa245eb6c3d763f3093f0c89b972e66b53d59406d9f01aea07f8b3b615cac4ee4d05f542e7d0dab45d67ccccd3a606ccbeb31ea1fa7005ba07176e60dab7d78f6810ef086f42f08e595f0ec217372b98970cc6321576d92ce38f7c397a403bada1548d205c343ac09deca86325373c3b76d9f32028fea8eb32515",
+                output_str: "eedf8414acba3931ccb5c41b045e708926cc68c513372b2a5c9f8beb76c060461cdbde486f81952169b465061541e397192cab92b64cd5ae0072811017140d53861f56a96a66211fb30bd1e911d31fdd29ce66882529874724a64216c13aee8110b963ecc99cf46d2c1384cb39b27f2eb85b517893ac45a126f57e93dedec78cd2708e2c718d783d847e2fbc8b3fdc67260b33852576910d2e43923bcb8882d318ac5421b99be5e532101833585e744b65eea3104337ffafff4266b6add5f081e42a46c5365cc2f03df43c3aa3d0f9a9c477d65e5ebe634c806246544b97eac179c932e37948bb5e5c84db32450f3b9fa54c89fd03fe58861b8e8a6c8c3d7205b7a65a02b90e0412c493acbc3385e1a197df785b02ef42b0bebbd5431ee59df31520b88e30bd376bc4e720d71f1c0c9ae4c2fbe126dade6f667e2ce825ca1118f5b82f2a86fd5bd80621fa6fea14768efd08d75e4c416fd1245b0c07568df42244dbf76614e0f3010684210e49d0868c3abf1c89084510662bdccf932176daf9393b00a4fdf911ec8ba14e81b0648e5126b7b6cc1dfc902a53d0ba7204c256de67fbb525f6c2d4c4db08484a14431b350b76b0ddee9924a8e0ddc4e6b9dfa90fd9be0be70bffbf6f9abfe0ec489822b94dfeda911faa7626271264100e2a40a2ab932cbe92bf2dbf57d273b0b056a6ddf29ba36a7f8138390865ad9ecc76bbc6"
+            },
+            Test {
+                input: "3e15350d87d6ebb5c8ad99d42515cfe17980933c7a8f6b8bbbf0a63728cefaad2052623c0bd5931839112a48633fb3c2004e0749c87a41b26a8b48945539d1ff41a4b269462fd199bfecd45374756f55a9116e92093ac99451aefb2af9fd32d6d7f5fbc7f7a540d5097c096ebc3b3a721541de073a1cc02f7fb0fb1b9327fb0b1218ca49c9487ab5396622a13ae546c97abdef6b56380dda7012a8384091b6656d0ab272d363cea78163ff765cdd13ab1738b940d16cae",
+                output_str: "61b6e091f3a8bef3886484730629a32553b1ef7efa8689ae6c01062f505ecf48e8460b66448d355046fa728af5778feb8b827ba30211e5b1bb82f6beb7f2ed7450e9ee0a19a47af63bb687a0a4e611b3762b97bfdc6e212ede1f874c33636ab4ea613ba991e8b9558f24d1c02c5731b155dc1edd6e984c5cf51bc59be5e084ae89c87ac2af5792c6de0b76448aef8c5f248ca6fd1525770c8b4434a76552834cf1481843a9e3a2051108d3db6b8265f736395848da2c5755b504f4b958755ba1820deee9ead314c9515b996ab96c8f349bc12618fa4e8a026efc5508707f642f5cafe1ef135764515f4ce2de357d93a0f3bdfe8e3a7e01140212a735faecb49659039aa05f0c5ea0690e304c155a64804954e24039d001a1f7c2f1691e81120fd275a6fb292f3fc1bb16763887e3bf327fd36ff14d8b89d02990ae9d4b2b4f5492934079d17945613aa03771605b259446664fade2292036eca5894c4ec3d6673fb95617770af54ca581bdc6b52097938a98bede6ca627a9322d4ff7390df9a3e46fc5c0663a88a16a7d4ee708d92eb5ea6de0527fa5bc3454455b678791e07586123cec8864396b4b972ba29c935e6d3ba2f7b2fd315131c0f008d047e6cc234535d947f068548287140d4303365990e62b4845a3e7cd90667039c205bd1b836c4240b2120b54df12c462d2b10ffe2d61b456f090efa26c53e1f51d2292d31f"
+            },
+            Test {
+                input: "c38d6b0b757cb552be40940ece0009ef3b0b59307c1451686f1a22702922800d58bce7a636c1727ee547c01b214779e898fc0e560f8ae7f61bef4d75eaa696b921fd6b735d171535e9edd267c192b99880c87997711002009095d8a7a437e258104a41a505e5ef71e5613ddd2008195f0c574e6ba3fe40099cfa116e5f1a2fa8a6da04badcb4e2d5d0de31fdc4800891c45781a0aac7c907b56d631fca5ce8b2cde620d11d1777ed9fa603541de794ddc5758fcd5fad78c0",
+                output_str: "e4e5622998509e275aed8d103e2581877b09d570efe558cf03626fdf3a2c04044c1531d3f92a025ca693fcab59d90ed2a2dd33f4768f56b972b2e87d34e8f293862c22602de928714c34ffe22c118c474467005c250f77971d59bd93581e5edc4f2be3c61f5414da40ddfd3053595e616afeb18d3cce87691af4c228da5595e2c4498fdfde8360dbcf014b368a88c5ed7a71eeeb003e8839a371b8d86f7b58da353edfb2891bf5a5ccbeac1e5f2edec1442fd79b6a31b85e4702df68ed3a0504e26489b15c0c1a52b443581bd671fd207302b4badba9f41b974ba6179ea1671e4660cc8f5a35f71a8b9baaedc457ff13263b062db6059fb4275d2831218b04b2e24f1e3b3dc4cee9261a1919343d5274d64ce11e0c27866eca3c91be98762834142c730f4c3354f0866d9f0cbde0e54bf747e0d8e50c8654a1c87fdf7eb6d13c06a8d0a02fc6ea72c77d1d957b960d6726eb5f1d4b3c056b2b67d9c23dd393a25d03129fb4d894dcee892d4d7cbbeaf404fddef8707c5850b319e04df5d64bb9f256a6b2a7bfabe6487b16dba0cf415f8de98ac8d63498df68dd9e209b23297c79d108bee3756989d751d91fd0954a7f5b166109fa11c7af4bb18b695ff6110659e37683f92ba03c24db9276d88e6fa587543e785a4d49f37240cbd826162e0c2ab12deeb71552fb1ad45e7e5780f832d831d2aac556a3a0005c37c148c41ae1"
+            },
+            Test {
+                input: "8d2de3f0b37a6385c90739805b170057f091cd0c7a0bc951540f26a5a75b3e694631bb64c7635eed316f51318e9d8de13c70a2aba04a14836855f35e480528b776d0a1e8a23b547c8b8d6a0d09b241d3be9377160cca4e6793d00a515dc2992cb7fc741daca171431da99cce6f7789f129e2ac5cf65b40d703035cd2185bb936c82002daf8cbc27a7a9e554b06196630446a6f0a14ba155ed26d95bd627b7205c072d02b60db0fd7e49ea058c2e0ba202daff0de91e845cf79",
+                output_str: "f3addaa4382a61cf38c2963346547922642b064ce36b4d424f41acb02afe7aebbca83df589208fc828ef58300e96a4d20592bfd58640cda4c970e1ad58ba410accc75cf6d2566b6a10d7fdf02d169e6bbe8953e5812cebf84e6e79b952680b4cb59373d8a6741c3483389e611a290d1ca14178556d0cfe750c787c4db1558a1f39a2f39f9021f1e420f57ca91cd1efd2d61d0d8cd34ad1ff7e607096b9787a51cb7684d8040fc66710c63d85a510ddfdd3f60056051406e7f217f12867312197690ee8ea33e6935306b76ad816043fcd52255976f9691c31afb361612886758be8ae9112412456b4395017ae96a3d118e351ee2d17fba96b3af726ab1b2eff01fc3b8b4dce461a452f0e6885ee4937b34bbdd357a83a68a95d12bf9cde1c5abad70ce7a30b76bdb601b8eb533d57e4dab508956440ffa0ea3ef2773a446e2cb11f08226385a71d93ca67cf6ccc8eb8e48444d508ea035ab59aff79e076fff850cd497798f49bc633ef41b0a4239681da28a3bcfb2ffa3a992909e0a0148781a1bc03fe3fdf9b7b9971213f9ba331e5b1235314b3f173d48bc3249e946627f84070ac2d8b57e184b0e8eaf0321b38857383bc1c27cf9390e79a2e09a3b5552a7aa9cc55aab534bf7d7571d3ed97c258efc9e2d3c1d34dc84eaaf55d1725ab388c0a5fa4df270630e468980fef3a79a67cbb2289bb03cd239c14f15a50403787a3"
+            },
+            Test {
+                input: "c464bbdad275c50dcd983b65ad1019b9ff85a1e71c807f3204bb2c921dc31fbcd8c5fc45868ae9ef85b6c9b83bba2a5a822201ed68586ec5ec27fb2857a5d1a2d09d09115f22dcc39fe61f5e1ba0ff6e8b4acb4c6da748be7f3f0839739394ff7fa8e39f7f7e84a33c3866875c01bcb1263c9405d91908e9e0b50e7459fabb63d8c6bbb73d8e3483c099b55bc30ff092ff68b6adedfd477d63570c9f5515847f36e24ba0b705557130cec57ebad1d0b31a378e91894ee26e3a04",
+                output_str: "eb6ccaad9ef05b657b6835655748051e33250c4fa600b3431e96053b0ad6adef7d8e5cceda256d96cbcf713e1998b19f8033bf032c9b2a56309b31755db88a5cb11669a49af4999c551ece42e69dbc4d53b0ab2705295a649364e8ae495c793b73ac4f5aaa01a7a66f4542a4a5b29aa266158d3379abb4c26596cc3e7195ea9112507aba0c1bbd8efa5785254681e11acbf65a977199d0d489cd4357cdf61f0da3b640958ff3ec7cab5ed0c3e725ec64d18cbc8bdb097967fce3af9a717f591dd49afc38fbb4437915d7b161e6800c3d8c0eaab61c5ed05d8711b00e75892aac5169e42b95ac207a27981684a7a26b9c7e00f7ab9a2dd84437940a7169bc998a56e0a31693345ac53f45b9a7d0532acc80e093624c5341312e7f2e7fff5b0712e2b119f4c6f5ca1e55899f394c850eb038bef7eb1df1303b7c97292732f96f4f6b8cdfbad6c8d6fb5721a5441b4897fcfcb2959026deacf17a99a27ebdc108eb1d77518c342b8e9892ce44241f94b88803d7ef72e26e8209bc251faf58b8e0e2cdaca5b4509174b07c98aedbb2c3871fe972a4c31dfafca4109985904daacab1c124e659562b77287b6d9db73a38a26ad0e746b71fa086f6aa4e39207093a04cdbc69993c2205cfedc4d321694d3fab832cd729ec2501ef2d386eb170a011baae3e83a7efd110fd36c9a7fbddb835fa033891ff21c4b634368fbe8ad991649a0"
+            },
+            Test {
+                input: "8b8d68bb8a75732fe272815a68a1c9c5aa31b41dedc8493e76525d1d013d33cebd9e21a5bb95db2616976a8c07fcf411f5f6bc6f7e0b57aca78cc2790a6f9b898858ac9c79b165ff24e66677531e39f572be5d81eb3264524181115f32780257bfb9aeec6af12af28e587cac068a1a2953b59ad680f4c245b2e3ec36f59940d37e1d3db38e13edb29b5c0f404f6ff87f80fc8be7a225ff22fbb9c8b6b1d7330c57840d24bc75b06b80d30dad6806544d510af6c4785e823ac3e0b8",
+                output_str: "28721a5ca8a0b2f0ea39d1e51f18ff57f838b0f7f95106e13950d717e3be00f9cde1fb3eaa37e3b0dfb080b1a08eb6d07b4c36fbe73c248fb86e993a7a44a42501593b8721082af6836efb165084ab5dd13c26413aa4303d19183cbf09526e9d6f590990c7a61103f82c3e3e58a673f8ea1d00c85efd867d4d7f9a0e295636933238c39a721ed301d4168b2346b115998279ba080d3d63a7f8a5bee1db83f415f9fa26cb0c6511a3ab2ca7cee4b30188570fedca952b91a299db985e0ea5d884646de594f5a3acd3cf975cb8987018ef6d5cb6c7044d946111d250b0ee5f40329d6ec2423d085dc8a8f8beea38ee4f3e4d7e206b6d1b988aabe52b074673c1d74c6db329cc978b88b0c88a41bb91d541ba4d3abf38f892e90639ecb37c79172352fa2273addf88bd6cd6a76b305e001f78e9d6c29c46477de5ed69fd0d398c8008c839c87fd95c51d35af3ac874f9e33e60813a984ffee299547bdf305756a9f7560411b7bb475870d8ace7671c093e210d3bdb10d31f48e0a78d1d9e3e44199cc49b7d2a9e2ca0ea8ebed0d265fbe461a12883ee515fd738bac8299309c86b77adbea857c4c92ed8e0f380733b47853ce530091a6d700b4d1ebc9830c2443c7d82c3e0e446cc72d4fe75a5c3ab4e38971ea41fe993bf270c477fe90e2e207df59d011e23777fba3b454138b31f1e055818ce61649f0d4d06765247a9b8feb8d"
+            },
+            Test {
+                input: "6b018710446f368e7421f1bc0ccf562d9c1843846bc8d98d1c9bf7d9d6fcb48bfc3bf83b36d44c4fa93430af75cd190bde36a7f92f867f58a803900df8018150384d85d82132f123006ac2aeba58e02a037fe6afbd65eca7c44977dd3dc74f48b6e7a1bfd5cc4dcf24e4d52e92bd4455848e4928b0eac8b7476fe3cc03e862aa4dff4470dbfed6de48e410f25096487ecfc32a27277f3f5023b2725ade461b1355889554a8836c9cf53bd767f5737d55184eea1ab3f53edd0976c485",
+                output_str: "1e98d0535e8d9201a8e74f5d60fe3151ab5c246993d2c39ae2c906720f898da70500d14e94add0842ddd949ff614c1df73d57879b3649ccfa780d22131dcb51e14caf79948d497d0a4b8c3be023551c68d88dc3e36ab8d73820fd880f3964964fabf60bf9009927f25d3ebcee347c54b3e7b9a957f0cd10ad15d0a9a2daace6715633a9400da882337e8505a431251bfa1b31096004e6e0f40f00f6c389a9fd5ddbbf7e7f26f1259d25f2c176b4b71f0c00deb9185ff0e4508fdd0e057af4f4d2df3a15dfa5416abcaf086d0118be1aa70c7a14da41b9612814c39b6e7dbeb9a415fd4e7ac8f3e046f0be25bc0d05a183a4fffc498100c21d013d712d7fb48667454a4a54bc6ce355107267e245675002ac83e00a26a76ee6081f8c621620c37a03fbfbdc6f7bd88a5d996bea811f9f753a2486262e6452f896ab8f40b2bd97f95038db68fed4a52194b9e85815e67daca1eee6b0788343999453e8758afd73dc3e1b9088561305e929a0128c6d229743567c7885eaabfd9bea8644fe8db4d19187ff46388db5c1583dffe70da6349eca26e839db999f75c1c72455643a902466c24717069efaded38c138d6a499fca999ab653f5b5def624ee990f46177fec751f55833e721df57f6b813a55c2d0c463d25e96a53db14e6cb4340f6059c924cb7c4edf94812959251282b5f46add9a97dc8951b6ae72f7faf6efe2bd11d9b34"
+            },
+            Test {
+                input: "c9534a24714bd4be37c88a3da1082eda7cabd154c309d7bd670dccd95aa535594463058a29f79031d6ecaa9f675d1211e9359be82669a79c855ea8d89dd38c2c761ddd0ec0ce9e97597432e9a1beae062cdd71edfdfd464119be9e69d18a7a7fd7ce0e2106f0c8b0abf4715e2ca48ef9f454dc203c96656653b727083513f8efb86e49c513bb758b3b052fe21f1c05bb33c37129d6cc81f1aef6adc45b0e8827a830fe545cf57d0955802c117d23ccb55ea28f95c0d8c2f9c5a242b33f",
+                output_str: "518802fdc9fa52a2a70fdbf2af1b43ede346e59b2709319cb57fe6480c46c7513868686cd374aa43d656c6ba98a2a879a1a3d973c46a10e95bd0fe28029e5bc8af03029d744f4b2d9bc9d83ce895618b9e21e6c4c2d295a285f251c26d22cb1662a2aa4e8609c8503ca9c908ef853ba212a87411059118596c88795c972f8ff55607bf82b8c128ab5d041e86d5784b35edee160ffcd06314510dc4af9b9fc51999d70c9a10449c5b62b584614742032be710e50b42aca942c7c73776eab51b0fef37f5447e8ce2198266e7fd1e378d5cb2f296afb77600b64677fa13bbb19da426288f423ec6617bd19a77833f01ca5b684bdc5bae939a79b6203b22f4fb27f4be92ebf337f9153cd3d78da095c0e76c9877a1a80d2ae4df7ce56a8f876f32e1134e0c51e52798389c35646d3165dc164c5f77ed519345d21d055a332f87ccba7d3ef19be950977710e9706ad07e30928639148b1250026ff23b04a06e62c2799072a319e8346ee80f9a0a2389c4b80b9a397c45bc1f0e92620455a1a04b6bed80b1bb1b78370992c5e41fb56e984421fb1e8465132a33d6d227c85970df92d7159e6f59eb766c3511b84c85865de1fb3fb3405d2102f1ca0aa4c1eb6a0ec90f6b89d783423d848bd70c8220c7f024a43888b9947d1e9e52a6204ca17b04765f503a887ea929ac4866890110fed0713a0479c6fb619c08bf2cb24e026ebc6151"
+            },
+            Test {
+                input: "07906c87297b867abf4576e9f3cc7f82f22b154afcbf293b9319f1b0584da6a40c27b32e0b1b7f412c4f1b82480e70a9235b12ec27090a5a33175a2bb28d8adc475cefe33f7803f8ce27967217381f02e67a3b4f84a71f1c5228e0c2ad971373f6f672624fcea8d1a9f85170fad30fa0bbd25035c3b41a6175d467998bd1215f6f3866f53847f9cf68ef3e2fbb54bc994de2302b829c5eea68ec441fcbafd7d16ae4fe9fff98bf00e5bc2ad54dd91ff9fda4dd77b6c754a91955d1fbaad0",
+                output_str: "ddbb83438554c66aa9d9569af53eb13da65440e0b1afd88b80df59e767e069ae4c70741f68adc2a674d66e1829ab7df21bad9665e5ecd655f756a78eb9f78d838461a03c1a6d1836b27dda6d269ed65b7e352030401acc8266f41fba4e234d225ee32bff12406f7f620cb3484d6757ef3ab69ecd675a9250200735826b630b72e64f21e3d84b135a35e1f4ae48ab2e80424c10be6bb7aa78f8df9c91537fabb91db4d58428f6de62364292141e9a7ffed93f16d1d36c3ceb4960e7cb8fcd8b91eff75b027159586dc304051556e1401a6c555a804616ab2757d699bfb1e37426983c39f34df6c1fa6c084fdc9c633b6aa331c5e5028bd185a4ebf3eb0ca4cc397d481f404440f4ab2ab7dfe0ffc935d91d417d94d9858f89d28b4900e634a5caaade9f149c6ca1e011ec684cfa3b3042f9a320501522b6211da5f5555c87102df37f17e4ad3ba55a37381d204fba5711abed49ee51f3985ecea7e239fba0e8a060a4990590795edd1a936c185bf37af9b95fa3e6294a780dc9fffad7d9319002d18794ff0da59cc6ad9e3ad9d74bdbca343ef694cfd333f87278e59cc445fbe0e622857f3745ffd8c90a161f7f49ea875bb1cb234c63aa0c55e530a72b19cb770fe91872a91420fd1cab520ee922c2b6fb59cb8e516c303f4c74852769ef1787fbd7429d33b2fc0adc18b23034736fac59f926e88df27d811591f03e7009193d"
+            },
+            Test {
+                input: "588e94b9054abc2189df69b8ba34341b77cdd528e7860e5defcaa79b0c9a452ad4b82aa306be84536eb7cedcbe058d7b84a6aef826b028b8a0271b69ac3605a9635ea9f5ea0aa700f3eb7835bc54611b922964300c953efe7491e3677c2cebe0822e956cd16433b02c68c4a23252c3f9e151a416b4963257b783e038f6b4d5c9f110f871652c7a649a7bcedcbccc6f2d0725bb903cc196ba76c76aa9f10a190b1d1168993baa9ffc96a1655216773458bec72b0e39c9f2c121378feab4e76a",
+                output_str: "3a0476c8e248067f0f96f01561cd0f6e55bb31fed70d2ad5f282f030044a331c6a20f14f254d1ca11eee4226323874a1035c0f522284627b51f29ee43b291d24001c4a44c638aae5a89045c141e16b562fc1893f39cf49bba6d17efbcfa4919a1c60d60cdb132cef068a05a81fa5c374273fe366f4caa16887c5ad1288bd066b741d234ff63aae976e742f5dcff610caa33826a7856e5e5265fdbfa04007ff3f0f701850de3e911fd71e00012de9823d78e381ccbaf09976fd686811255423a7cdcadbd854bed848ee0ed2977fc192573f2f36c62a5539ce807c2b01ae7220c6139d1accec6ca37f2c964be922547bc692274d557abc1e7d521d1215cc56260d0c7ef4c3eefa6d54182fe1928d8179fd4508b8a4c7a3f78d2d0cdf76abf581f0689d1bbae1f7ed3a8af23d687c369398c715f71377da92a518eae81c7587876691af81b982340d71f3ff3836ae9e87eef7db14afece5f57e45746173e7834132f922ab5afde73076b67e446a0f096ed2bc87e12216bacceaf1e912cbe89483b5e0bc35df7c38f79f31c1567d16a321920b2d0e6f3637b2c65ac762239522433aa51eb34a2a174c93a693c187e97b3bfa4c8c9c7dd512a74f26ef74eee24d3f425f0cc05f0a3a630806fb960437f6edb2c31b0103b3933986ba9e0b2d26b554fb9af7db5454a18a8d52ea8445f6844ba7371511cd14fbe171bb4045c7377553e7"
+            },
+            Test {
+                input: "08959a7e4baae874928813364071194e2939772f20db7c3157078987c557c2a6d5abe68d520eef3dc491692e1e21bcd880adebf63bb4213b50897fa005256ed41b5690f78f52855c8d9168a4b666fce2da2b456d7a7e7c17ab5f2fb1ee90b79e698712e963715983fd07641ae4b4e9dc73203fac1ae11fa1f8c7941fcc82eab247addb56e2638447e9d609e610b60ce086656aaebf1da3c8a231d7d94e2fd0afe46b391ff14a72eaeb3f44ad4df85866def43d4781a0b3578bc996c87970b132",
+                output_str: "868c7566edf719d04d7457bca5ca9b4b62f309fbe1046a7351f24dcbe2e2224e34cc23e2c859e83b8b09e15fd575fe5225a03d1869cd1879728825a67008cbd1c7f0535086de803a3e55dbad1bd9998ebeace9cbe63c4500b5ed3380153a41c33948e82e2d375e70e2a8c3f1c1aeae72d000efcbd7f9da3fe0422aeb9a10b81b07eccee0c227947e7dd5e2b277a80718015bf5ca4c9b3ea5ec7cac5cbdc79642cc0b547729a0956c739c956d09faf013f402d764ef87a5027049c4fa0bd8ee8d77d99f3124710db8b274b1f8878ad74cf88f21abc520153b2668b79f824d74c4f113a66a275ff882b64794e307182c5ea6c96a719fec5fcddb619579246efacf142f976de21aceb21136e9aaabf231706c767a664602c676ea46c70f0be2a7f9907a484bd6064e1bf132fee115362dc13566f763f4cb29a3ccb68594d9e7427f2d29b1a3d02520a81af9d41990e04c9766260841e86965db59b764e1867f9f2b4bfc6c13bbc08c4db843982e262f75ce6f0e034b58de6ecdb71a5e32e9f91ca8398ec286277b0dd6a518031c16ab864971c243cebcf3755a72afcc186c5d200873eb27b070603a6fe494adcac893162cffb544c2b69083693a407dd92cb4f6b1b341ebe491738258ec5d109856bf106b56e6b96481b933093dc4dbe2cd075c5e3b760d36f3b92a286f91af57604b70206c8922ed21006e05a271f1415f84f6ba"
+            },
+            Test {
+                input: "cb2a234f45e2ecd5863895a451d389a369aab99cfef0d5c9ffca1e6e63f763b5c14fb9b478313c8e8c0efeb3ac9500cf5fd93791b789e67eac12fd038e2547cc8e0fc9db591f33a1e4907c64a922dda23ec9827310b306098554a4a78f050262db5b545b159e1ff1dca6eb734b872343b842c57eafcfda8405eedbb48ef32e99696d135979235c3a05364e371c2d76f1902f1d83146df9495c0a6c57d7bf9ee77e80f9787aee27be1fe126cdc9ef893a4a7dcbbc367e40fe4e1ee90b42ea25af01",
+                output_str: "49d7fa3a63ee1611e9ecefa88f80dfcad8d7ad69e6a899ad04d102885ae1419f8e9e6897f1d6937177e1bd8ca104a7c227b8dcdad473d0a2bc12c1a2287b5dc66a0f808d02c452bdfbf5ac4f43b38105b5a9f2e67a4c6c81fe5ddcc1ad3ead625b29031fd5f1ef18f4aae15eecc2b6f5a4336e5be3fd7d3970d50261ff6f992e5a0f818be342b910b267c8740b7f331e0623b5793d4146dbd8ba3636d12914df35ccfbeee62bf3e0033ddd26114ee709a641ed54c21a130c8b3e1f9a49965e48b8ab914aa2b2a377db1873a1882625ebcfdd1c366360b8dbc631db94bff615bcab90d8bab3c14f2cf4a6e4c4130af4255acf14b2b3699edf8753c745f9d8dc23afbf449a05fe05fcc83fb609856a5be79b06e57d3e42531edcc13b1aeb76be54cedf8665439731cee4144cedc0e8acf9ee2af245769d24da6261e368cf0d599225c397c61a87ea8c0ef648a74cb1e3c5ed2c6cdb766e83bc68299b1ad882cef5b436608847548141fe1db303bdb13771ef19674f196efe3502b14a7a47283ee6bbba86354b88a8fb15187e0ac84ce0e9cdf737f62c15ed3a4a6fa0708f91da2190268c0923d1e696b5e98251a6783479e6ba28336c39e27680bb86bec2991d82efb40cfe6985944ed3b18e2acc7e51bb24d0f2c19bde84cb271fda6bbb5de6b40203ab54ceeaab0d84a339dd84108929663a50ef23bcf1e79909e2275fddbe57"
+            },
+            Test {
+                input: "d16beadf02ab1d4dc6f88b8c4554c51e866df830b89c06e786a5f8757e8909310af51c840efe8d20b35331f4355d80f73295974653ddd620cdde4730fb6c8d0d2dcb2b45d92d4fbdb567c0a3e86bd1a8a795af26fbf29fc6c65941cddb090ff7cd230ac5268ab4606fccba9eded0a2b5d014ee0c34f0b2881ac036e24e151be89eeb6cd9a7a790afccff234d7cb11b99ebf58cd0c589f20bdac4f9f0e28f75e3e04e5b3debce607a496d848d67fa7b49132c71b878fd5557e082a18eca1fbda94d4b",
+                output_str: "815bb24a227ff0b94478ec10d6b4fac313d56fd9ded13e94a57869d8bc5e542e47cd97d42f1387757539a452c5c40492da8a4d65190ae36bf2e169446bbe5ce0742a1a9865126ea07ad3875d47c5ed5f85c1a7a57cc350e05a4dcb1f052d9ff4aed38c5e1d65c05c3c7db8a9a6c00ae2b3b45fedca8c309b2c369a7b9608aa365015af193f33092d084b2a7ac5cfcc018a045a1d89989faa5fb16f854453d9a6336b900ecc4d9eaef9de4c6a287c44d0e4866cc8e4f8cde5317eee01113da6a64b88a1469835bba057760ec1d03d63d9ca40aacd7cfd8619e92739cdd72c9a11b0705a4e50dc386d4d378e624818b2d36b4ffb6dd1ad2c9f9d2a8bc4a7fb73827930e98cfa03c221b7c9d648463b8c2af1dd195a817c0e986e8de6c11371ab830ef74cc5e734b56c6c013350c1212901322bfcb0cdddf13344473e3950c393466dfdb59fff9e582e9b79f5938b0476de125fc36ff74c03cfb685cb09bff4c234f272d9b1ba6a2560308464ce36ddc0eb6863ad42b7d0490091c05a745ca5f288b303a0fd08bff7ba2265b6c12b25840357dac735cead9e6087d38a97421cd4e54518d7c0cf0968860b6348d1531c56c1b4f6b5c7771377194ef24e91f9d9df96253b80009341e10122c14d919a037c820822a23e47620b35d0da729a1ae329f99ebcc26fcd8cb9c67334f8b04714d2b76d5d0ea6156187c9017e764aea66e88b"
+            },
+            Test {
+                input: "8f65f6bc59a85705016e2bae7fe57980de3127e5ab275f573d334f73f8603106ec3553016608ef2dd6e69b24be0b7113bf6a760ba6e9ce1c48f9e186012cf96a1d4849d75df5bb8315387fd78e9e153e76f8ba7ec6c8849810f59fb4bb9b004318210b37f1299526866f44059e017e22e96cbe418699d014c6ea01c9f0038b10299884dbec3199bb05adc94e955a1533219c1115fed0e5f21228b071f40dd57c4240d98d37b73e412fe0fa4703120d7c0c67972ed233e5deb300a22605472fa3a3ba86",
+                output_str: "47a1acf4036c3a62a24f7a2e1147f5729db886339c7ce7a9a6e7613bb60c475724d573e64e4027f296023e762ca20f880ab6c73142d3d1d36c19905bba147317880dd9210a75fd7c552076f2419432e46c858e69b7f7c72372be510f07f21977dea627514f6ecbb34ddcd6cf5d86b01be3da48481b25d56071ceee2142a9956aab4760666de359a36b8808d1df3f3c15f22163cec7c1181445df7d06e79bda799a6c4f278968b677fb78c8157cda2fb7447acc2d485e6922d82e1af596c760fcc2d7d83a6a4b52400e3fdf64a2a7e4d9d9c59930579d4516618fe9979b10562b35f26ceed8d53de5b322b3bb4f1b989eaf31517ad896ce3e57f879d6de9d4a847e4f7c9ee093d7ad482d84d947cab0b6619d8895facc2da8bac086e054b3eceb72689df5730fa6e51f98205b1fa5ac9daf82a78867b655b39792c686518be3024a5f975e97a021f64fc75014635371c9dcc8952f2b5404582855ffb049561f3e20013e74c8a05fd434516218cc6e463f62515b454b358c611f2902b9d11bad43862497532df84de73a02054459b79cb956e6dff229e8fbc8cc558d666e10660b87b9b0831df729cd87a22fa33891d9ceb2cc7ceeb1f316600b9432346d1fc211ce1946946f33ba59d6b53f9208f8f1fa8362524448cf87a851cae07d0cce86e594b5eaccf0b4f10f8c4d414ac194909cfe526cc87fcce1386c7f5537d10352f5"
+            },
+            Test {
+                input: "84891e52e0d451813210c3fd635b39a03a6b7a7317b221a7abc270dfa946c42669aacbbbdf801e1584f330e28c729847ea14152bd637b3d0f2b38b4bd5bf9c791c58806281103a3eabbaede5e711e539e6a8b2cf297cf351c078b4fa8f7f35cf61bebf8814bf248a01d41e86c5715ea40c63f7375379a7eb1d78f27622fb468ab784aaaba4e534a6dfd1df6fa15511341e725ed2e87f98737ccb7b6a6dfae416477472b046bf1811187d151bfa9f7b2bf9acdb23a3be507cdf14cfdf517d2cb5fb9e4ab6",
+                output_str: "2f06c83d5cbc776c9e2e490482d92bbd8d32b07b1028e046582dd17951c13cdfa27c065a2821d997f37ced1d3f69ed8a8eec35a55c1419b28770800a66a8ccc05332c64b0a310a1f4a99ee9a18ed342cc03a89193bb63849a6f0288b29b0801000ec0e3961fd85e6cf488031f028232b8fede6827c7c24fbc33a26a87a9b6210004038c67eecf0ef9d19c3dc8fe2c7db8a449f168a98cfc190043fd6e2ff366cc35556192e39d1664194d6943f9ea5b4675d5051100e1497c1970c2927506b5b717d2dbffcc9f62a0ac338340c8c473b397b98812bc77202a67426acb83f4a103687425d9f793312570ff6cbd897733ce7399a3853887918a9ef8d0bfac5a303b9e66ceb5ba52b826eada8e5e158422a6d42f89e986c30f9d8e14c8b3fc7daa5b012452666612acee1884c069f98e476f89e74b35ef94002744108a0eefb9a9992104973e1176f2ae0f560791b9486e7a27c75bad42054047e87fb95f43ae211fed7e3948745624f8eae4a81cffcb4ba389e169c9b55fde64dbc31e6287144d0803ec3f0e5a86de5fcd0cbebaac40d7103b3c0bcc8afde491b25aa472beef91d2afa59d980ef1a833002838a2159c0f9fdae39489b6e865adda3ea6dc8e675e45a45857111a2eb49fe3adcd52efae414b6ee423440419b310e3cf751f497aded9bd3cec9172a23ffc878dd9ff6033eac9c4ce7697ba9eef60b67665cebabc43b"
+            },
+            Test {
+                input: "fdd7a9433a3b4afabd7a3a5e3457e56debf78e84b7a0b0ca0e8c6d53bd0c2dae31b2700c6128334f43981be3b213b1d7a118d59c7e6b6493a86f866a1635c12859cfb9ad17460a77b4522a5c1883c3d6acc86e6162667ec414e9a104aa892053a2b1d72165a855bacd8faf8034a5dd9b716f47a0818c09bb6baf22aa503c06b4ca261f557761989d2afbd88b6a678ad128af68672107d0f1fc73c5ca740459297b3292b281e93bceb761bde7221c3a55708e5ec84472cddcaa84ecf23723cc0991355c6280",
+                output_str: "acb6638c5302bfd244f9c4f1adea0461562cdbc92670f2c0c9135ba8754bffedf6621fb48b702792f71ac3b800bacd3a18791642865247b75d086ae816ce17f6d0cdd63d0a2fdba9c743fc9e3273e6834d21f12554b977a146906682b5dfd85f41bebd1ed03ca3b67de188a0547493753465d76145f5f860edd2f8f3c09adea139c3e057ac64487962e3ee38e1fb9f29bb5fcf2d70993aef47e56a26c70d200d357758a4b34bd9327dbacf987754d805ccb5d2f4cab0e238de726e6ff78239c0f2e020a1fe4d4f6cc27c0747eca37b4f72a110b3b8715e3db07dbaabb0e580c4f20ddcb7ece60b295211ab7cef858153dbf3f8d0e27f621551b317534e9680576d629c5928f1a03c9928a93b67b4ffa019dbadf9aa71d37e79d40051f6bc6da2d567e3e48706346275daa4506a0ce668c2d4768fff917a11e4c1726842d315db4d189fcf686c8bc1061a63fb05a73720088c9fdca783ead1fb390abbbf0b6bdcc775ca9ac32a1cbbd66bd80da59152c97e295ab35ddeb7048b975c9e2a794993852f31a18840528d2f297454598a3f31bf9973b9ce54d5e2a8012eb2cee9d49fd8299dad5bb566629f6ee4eddd71e6d08c223d0a1f48bb804096b24bc6da27b80ac2eadf7b7b39c29f3dbe556af66463785707a23495e2ffaa815640bc925230dde6e5e545a7c414543d55cfa23330be5cc1720a816e4064fdc0bb45c0d9a426"
+            },
+            Test {
+                input: "70a40bfbef92277a1aad72f6b79d0177197c4ebd432668cfec05d099accb651062b5dff156c0b27336687a94b26679cfdd9daf7ad204338dd9c4d14114033a5c225bd11f217b5f4732da167ee3f939262d4043fc9cba92303b7b5e96aea12adda64859df4b86e9ee0b58e39091e6b188b408ac94e1294a8911245ee361e60e601eff58d1d37639f3753bec80ebb4efde25817436076623fc65415fe51d1b0280366d12c554d86743f3c3b6572e400361a60726131441ba493a83fbe9afda90f7af1ae717238d",
+                output_str: "2856032a7399bc2d4a4d43d7dc024aa3040ed171982042e0d1a4063b6603526eb4dea45fdb007ac0e61043a11a502d4c49440c174bb183979a5d3a35c593e1a01886c60472d40d161a0512e3372bd5f8d35a217391d5ad14db17eb23bcb74d7701286a158b03a927cfd03c4062ec0461f8c9c3d4b8de0d70cec5eb018375e138278ed9ed366d546d896dd885da0c3513c5ab7efe2eca848b270cdac3d2fe7e14f3de6848fe01d64d841f198c85ce57e16b06ff41ffd454b6c61569b71d538ce5729dc5a5aa1d4dfd5f1d3f4cca0f424701e8857ec66c8dc3d44daacab9d05626751240e1e8f1adc1e064aaf47c66d9edb0ee114a6155e28bf4769f88c053313792cd9bb2d9687e595d321e152cfb42f67ec9da6e373e7621e4379a3c22b4828412223aed28946784cf67b6ce99918e0c1217501624599e4e79e90016abd265e21e91205824b7fbb95e9ed999c50f90c5748f83e71eabb66dc2c16cab63c064bb88c865fd30eab8fafe0529312be74b55badc4c944c69b89d98e7e07054a0aac8aad91f53582b91cb22a56741c41998ec878b11671afc9df26b5261be5eead565be962e87a40a5200a0856123ed7d248431efec79d7932407a7d762137eefabbbe0c6c482cbce115fa9cb7254614de54e361c5cbc4eac03757b83f4e4a96bd47d8347ed5e2c9e96df3f03a9762988d671aa75ec9f3b5e833570f13cea7c323522"
+            },
+            Test {
+                input: "74356e449f4bf8644f77b14f4d67cb6bd9c1f5ae357621d5b8147e562b65c66585caf2e491b48529a01a34d226d436959153815380d5689e30b35357cdac6e08d3f2b0e88e200600d62bd9f5eaf488df86a4470ea227006182e44809009868c4c280c43d7d64a5268fa719074960087b3a6abc837882f882c837834535929389a12b2c78187e2ea07ef8b8eef27dc85002c3ae35f1a50bee6a1c48ba7e175f3316670b27983472aa6a61eed0a683a39ee323080620ea44a9f74411ae5ce99030528f9ab49c79f2",
+                output_str: "6ab8f0f45b860126332e32ad1819fd5a23dfeee2c7fe47081ac855901d2da3f590fb64f989ea616faa0533e49a3b08589ff2df8b8a27bae25a23fa93710032f2ddec4e3f905ca8ac37cba1d9d225b2f62343dd5418283db7d6e427ef537650944723ddd7dfed6394ba1540b2fe72944c330cfaef76a9cc3998c1b6c38a83ea71b075f1e65c9209bedd565149137a4be1c640f4ec86a556b196bdf14f5c336418dca1330cbe1781dfcbdfc26b562025c9db90461658c4f1947a1b1374d8120168a1ab8d0cea7527f0503f19c4605463ce134cabe1c72866f37ea2f105d44a3f2080dd42da509ecdb1ea8c0ad439820d4bcffcc5c34bf78cd8beed8e394567a78864517cd183ec4366249fa9340fe4a112dbb418b32aef24426cc95e12bd243f3bd4e744407f3b461b7e8c7ff096f2279962d60e778e1c362a5f47e4acae0561944be126c8ed384ba5e71f8c23fd914d525d3affa915ceba52cb3b6265e003d6b2483c7c331db0f56eb5f4d0b4a7db558a154e34f539136c6869126fe3a7fbbc07a92ca251a6ed301cb1a8415ff16cc28d1482fbb7a70df1ef2d5aa55a084116577301eaacd88bff5139d091d0bbae55e31e50fbf28952e7071594fd81b626fa4194d97572058f217ed070b97ed42d8c7d9dce730d270a01bf847929ff0e2190446d82f93d9c2bf309f836811de1e4700d9ba736672b407e539219634f32956ecc"
+            },
+            Test {
+                input: "8c3798e51bc68482d7337d3abb75dc9ffe860714a9ad73551e120059860dde24ab87327222b64cf774415a70f724cdf270de3fe47dda07b61c9ef2a3551f45a5584860248fabde676e1cd75f6355aa3eaeabe3b51dc813d9fb2eaa4f0f1d9f834d7cad9c7c695ae84b329385bc0bef895b9f1edf44a03d4b410cc23a79a6b62e4f346a5e8dd851c2857995ddbf5b2d717aeb847310e1f6a46ac3d26a7f9b44985af656d2b7c9406e8a9e8f47dcb4ef6b83caacf9aefb6118bfcff7e44bef6937ebddc89186839b77",
+                output_str: "6e9d7e55e8b258208fe6c1c50ce490bf81748deb2b4401800c2423e9479af3bc1b4c37249a2dc00f120dc5e2114ade14c830437d6b0190fec5aaaf57d4e9c5078b867b2905d48e6748e85cdbb3f1995389ab373014e6237948b8343ab418716f0e9971db6a179b11277acb2df6b6b5903ebf311f2d94b10c3ad0bedf2adc7486929c8c43cf0ed6673c6468cf69b493c9eac2ade0ab3987179570886a28c08d0dcc83b0162a8d459680fdd2422c2c40a44e3fe55d0ab24ceade4063c995915794b0c842573e2e7c4bff8e201d3f9b3e8f49d90186aabc9ddc6110e98e3410617da24ffba5a7e5c3193c16b70cd6cf919dd6f15da3627f42b6225eaf4bf1851a570e099fe3b8e7d746c34573a74744d42135332daac9a9341e598c714fafbe052f7e745ba1d424cbe0cb1932a9e497d2111ac597f7e5010a86567c51218451ec3d1461d1d2d54f5e8754c854cd4d60972bc09482084ab865dfda01d1c7ae4c749bfbddd19bbcd95e8a53009529468bc4c47d9015a119b9c37dd2c149c65e6c99699c69c3cfa405c65e0e51a3585d35ead701feb58f1ac72d74e87d2c65fb072c11b235ffcde39559a45f881dcb292caed95b3ab6e0e468f86a235e2d83708044d75e768a2f3eb13523338761dbc38a8e014052dbd46a0064ae0255bafba6a0c8fbfb40cb41dcdacbc5466787638b901ad452d7d50a0c610001fbb6f126902d2fd5"
+            },
+            Test {
+                input: "fa56bf730c4f8395875189c10c4fb251605757a8fecc31f9737e3c2503b02608e6731e85d7a38393c67de516b85304824bfb135e33bf22b3a23b913bf6acd2b7ab85198b8187b2bcd454d5e3318cacb32fd6261c31ae7f6c54ef6a7a2a4c9f3ecb81ce3555d4f0ad466dd4c108a90399d70041997c3b25345a9653f3c9a6711ab1b91d6a9d2216442da2c973cbd685ee7643bfd77327a2f7ae9cb283620a08716dfb462e5c1d65432ca9d56a90e811443cd1ecb8f0de179c9cb48ba4f6fec360c66f252f6e64edc96b",
+                output_str: "bf52aca76d241cb569d39eb2d8669d1b2642c0cdb8b141e87c3b1bdb1f202641a1600ad388806ba9f5db50a7cfff97cb23ee977c0d3899f414ff5c47d689840f59e7e7db2edd92aff3fb36fd198e7bf5d81fa279f743fdb6b9c00e974065802903dc40cc3e216ff727a72f267624894f114c62e7b101d9da391e3a205c7b492b7ea28d836ac6657960cbbe4c38a73f87ea1f8a155a62c0a5d5ba821d9adfd42bcf42cb3150267aeaae507a4009ba8dcf70a13afedcb2121503cffe786304e3aa980d0fcd7c908406fd2cd9cae45de97414647de04d03c1214c967a14756830afa6f83ad91ca66d9de50b8f0483f99572a284bf9468a6abeb45f335eaf0782c04563dfbf231956ba4575dd9bdfa10e2f6df8878415b357867e5c22b9cf349b480dd0ca1f7cd432fcda057a5f9ae580814a7cfe843fa831a5cdb87646bcbe70229a3ee7cbb3094e591facc8680f298e10e1383d3a6387a503fd537a6ed924903cc9149879a95a164a8b3bdd385a69a93c58aacc066fbe4e59c7f6e16c00e45bdc19ec267f7684705cef34d830accc03822efe9c1b3903c47fcfa91fc7a7b58240765eef217341ff96f0d0cdf5062d8b1939185c47fabe5498a784622d1b2da0dbf06dae6f661206f98ebdb257bb2fc4c86ef6e7c6e31e7756c8cfe7c4842cda9878d6257edd7f204a009a9e1a492f5abfd42b48593231324728f8a510c47f516e2"
+            },
+            Test {
+                input: "b6134f9c3e91dd8000740d009dd806240811d51ab1546a974bcb18d344642baa5cd5903af84d58ec5ba17301d5ec0f10ccd0509cbb3fd3fff9172d193af0f782252fd1338c7244d40e0e42362275b22d01c4c3389f19dd69bdf958ebe28e31a4ffe2b5f18a87831cfb7095f58a87c9fa21db72ba269379b2dc2384b3da953c7925761fed324620acea435e52b424a7723f6a2357374157a34cd8252351c25a1b232826cefe1bd3e70ffc15a31e7c0598219d7f00436294d11891b82497bc78aa5363892a2495df8c1eef",
+                output_str: "08e74b227985f88b7c1884a179d0b9c9f58bd2078f8938519f460511b00003e51a8ef4c93f69b716df11df2839688108adf72476d1675e4df3399c05257b1db542d92f0e27fc59a927f00c4758ada0fd95db9d3251c01cb9167b2d6310e051407a2eaf415a2e478be53c3945a702f04e25713ec2e2e1d51d636870642f6023a43fd0859a3b468a9502a8efecf19bf97906e199c095464600b0b7a1b180b841158c6c98d13c371f7ab56496ea14cff3110aa9d33869069a1f9215a6fd99ce9226eef5a272b004827dde0e1b1bf4b0c0cbb670caf16b1840c6e88e577acc2ed4493c598b938aece1824717964048786d9cab9ed14dad9f87df1e9c374010d89d4a8616ccdbf687e12d7cdfb388cbbb88b56fee3aedbc5360088a49fc1b2e1dd5518e0e00f50e3c922c8ca600a41f72b985f02e32a1f9a1fee1e1929f5746ffeb87ec41f08861ea3463abb9803cce8c8257853fdc0b0c077d4255dad1fa9e5d865c981ba15236828e7e425f5dacc4b738de18e6c68a6c925b72c14e3042916117e91cb69311081e4e845b09679ca0607bbafcc1341b283bad5465633073e5daeed6541b1fd09537eda2f0d2a51cfd8715d3064fb074b52d48d4e7175b4ad0a0a6084128424958275068bad56b5ad2769918b6aaba7ab1e8c9f88859b3dab310fba2ff67bdd3fc9e0b2edde0b716897220ab75611975e137db525de4465ecbb2d9d1"
+            },
+            Test {
+                input: "c941cdb9c28ab0a791f2e5c8e8bb52850626aa89205bec3a7e22682313d198b1fa33fc7295381354858758ae6c8ec6fac3245c6e454d16fa2f51c4166fab51df272858f2d603770c40987f64442d487af49cd5c3991ce858ea2a60dab6a65a34414965933973ac2457089e359160b7cdedc42f29e10a91921785f6b7224ee0b349393cdcff6151b50b377d609559923d0984cda6000829b916ab6896693ef6a2199b3c22f7dc5500a15b8258420e314c222bc000bc4e5413e6dd82c993f8330f5c6d1be4bc79f08a1a0a46",
+                output_str: "3b3e210e0fb73556801a2250f1e76c45dad31e12f9ee3448640b73d5afd6d2d6facdc1b0cfa53f46a56923cf16b6bdcab566f3a0105e442ed7e88c09d705249be34463d435c14d5118a7e028dc35faa98112f80d816abe04f7345ea55e7f7652995fc047aff6b8e4d05c24a0c78fd9fd40835e523be7867312630993fc9e5cbfb47048453c205880eeeea2ed9a198ac145537bea2c216a60774c400444c07cf6546159eae47fd6cc79ca43d0d26c79dd13f39748a696f181984b5b8eaed82976c9b0c63c915bc2a2df91139618ac82e4478ea26f9731d422c692ad1bcf483936d99f65cc8e5ce20cd94abc2c4176b668d1813aa3ed84cbe68b8c982a8f884671ccd29b70efba765cb4be7d0d139798fbf344d7d1829f3afa946c3558b4c958a9235e4e96b28be25641120e00efe178304804d90946cdd1db6229c0147339a1f75fbec606a3b3fdcddd9235ea6bd3f166ad132f8c222e45a805d166f8fec56d488a2ab66737e3238e67419e194665ddad4d8214394a4da1ae09e0ec4ec5b209c18004f4008abfe997e456bbf99f1fd9b31e69b934ba694acaddd534e4bb4472179403bf9014a9ec311b16ca2900c669a8981be3b5a8a9d3bf4d05028fe6d3d97d54b9be443f9b0f73e59780d09afc937d1f36c4cd8caa1eb2a8522aaa175ff2e4a3285849c059991174bec1ba6e42e399c4ab0a566bfbc09cf1b836bf42138026"
+            },
+            Test {
+                input: "4499efffac4bcea52747efd1e4f20b73e48758be915c88a1ffe5299b0b005837a46b2f20a9cb3c6e64a9e3c564a27c0f1c6ad1960373036ec5bfe1a8fc6a435c2185ed0f114c50e8b3e4c7ed96b06a036819c9463e864a58d6286f785e32a804443a56af0b4df6abc57ed5c2b185ddee8489ea080deeee66aa33c2e6dab36251c402682b6824821f998c32163164298e1fafd31babbcffb594c91888c6219079d907fdb438ed89529d6d96212fd55abe20399dbefd342248507436931cdead496eb6e4a80358acc78647d043",
+                output_str: "615fbf41d7184ef0edf7ab0b079b76a4a7bf2b10a79a2ffe8d22e2f0a8b6280559bfd74e4f68e7691264a5b4651ae0edc504f6ac0677e14389d92913660e75626615622dd458b7cae4ebf1da4f7adb0771a809bdb44e918f7d681711eae7ed84745a1e7f3aff0931162bbfbe975c394ae6843cead454a00ea54db5a55aa845413ec88bdf9119e238e6c84bcb76342fa8ba1a448af7cba6d0f1c964ee981aef20c5268bc1c3ae3f723e48d1932cdb14b95629dcc5269f2ea77f277354bf910b05bded92d6b8baf9601080156ef0d1600e80d8050b99243c64221e9b8ae82773c6be95829203fbee6caedf299509d6a2da570320ca6410e9853575a342f9e9ae76e27e1b0c892b2c932d80ad2b91a8d62d805ffde196dc1f169d2b9d51f28fae6546887182b91298b7b2fde472bffd86384ee1b78b4b5654f3dc38fe4400cef50338f1d79b478c6781eca2130cf3a86d9124c31754989a22f022658cfa62833cd5f25a021b03a84a7aa3f8890922ad179d589e46b535b0e6033c8383cd6b80324ef8efb3bc6cb9cf5ba0bf5f6b185b83edbe3f0bf27a9942fa87d172a5c9294bd63396ec8e1a5c7ee0bd7da1109a69e2ed928025b8383c55c6eded0bb9e23e15f50388209b3508fbacb7dac520e0327f2148fe27450d0c5c06712a45011c95d7b02c0e0f15bf8c222527451c1da4ab70cf649a025f8c95cd919e937b079f364c97"
+            },
+            Test {
+                input: "eecbb8fdfa4da62170fd06727f697d81f83f601ff61e478105d3cb7502f2c89bf3e8f56edd469d049807a38882a7eefbc85fc9a950952e9fa84b8afebd3ce782d4da598002827b1eb98882ea1f0a8f7aa9ce013a6e9bc462fb66c8d4a18da21401e1b93356eb12f3725b6db1684f2300a98b9a119e5d27ff704affb618e12708e77e6e5f34139a5a41131fd1d6336c272a8fc37080f041c71341bee6ab550cb4a20a6ddb6a8e0299f2b14bc730c54b8b1c1c487b494bdccfd3a53535ab2f231590bf2c4062fd2ad58f906a2d0d",
+                output_str: "8043574aa03d7c6409677e5e579fcbce191118e2161c214640d725d384a3d941857498cc75480574f9bf4f7613241183b7b1354d4d08a9ad1af03230636a14d40a30a1ce8d1dd9cbffe41011e40d3fc3dc1eccb83374f14209eb83bd16861e161882cfc86a5332bf0357de84d38cb6fe65ff8ec3c8a01ebadac09fbe960e5d55f752878a608b3e67ea840503d59b6625b42570f74671b4267246995b5575294d20b6e693d02395ac5329451f905b14d7fff86a4401f78e6cc7b83806c19f30af6c75787f56222b9ff673f5631165ed8f20da13167f4dfa4c53476d7e2d7f76f4ea6dd77072fef26ac3ac7f65ea2c4f113897d4f00ed38cba8ab162b1bc3151d769d24a42ddf88f9515a04e3fe57fb4ecaae26f608fa6a0e30166f5a12223c10adb56803343e938eb88c839ef9f91fc7a0b9df899ad3dc328166c8af33de8560ede98ec371a22938252432fa57716c4058b7cdfb1dd7f5087cd45eae5bf1a4c3ae03c19ccb580ec122dfd54dd2106a4e5a647558b24d15d30ce2fca05673f8991003ec61270f279b7c2de67d1930a5c948c9259d4e9dbdab2d94dc1e1403697499544a1fa1109956aa22da488b61a97e933fecac59711e1bd5967df18130ca394fda025ba334b2857a1edecb002ba56dccecf9044e579143dc47be03072d935607de1e674c955a63508cb5d42af7fdb80459f4a239dc78c31097e71c06924092a"
+            },
+            Test {
+                input: "e64f3e4ace5c8418d65fec2bc5d2a303dd458034736e3b0df719098be7a206deaf52d6ba82316caf330ef852375188cde2b39cc94aa449578a7e2a8e3f5a9d68e816b8d16889fbc0ebf0939d04f63033ae9ae2bdab73b88c26d6bd25ee460ee1ef58fb0afa92cc539f8c76d3d097e7a6a63ebb9b5887edf3cf076028c5bbd5b9db3211371ad3fe121d4e9bf44229f4e1ecf5a0f9f0eba4d5ceb72878ab22c3f0eb5a625323ac66f7061f4a81fac834471e0c59553f108475fe290d43e6a055ae3ee46fb67422f814a68c4be3e8c9",
+                output_str: "2aba810b7512b1b3b179995f76f843bf39fedb5b969267d5f545a605abbb3f627b59550678b4e3c3b8e0959d5907f88b814413a5d94b0011fc8bc445096cf1b49d11fb2a4ea1ef1f219f7ddec03b3678f2d95dd8fbdb7a1604af0d8a5f3dc33e257a54ca3eb50c49c03bc55545a36f807ace5a69f2d7069d3530f304f419b8d5dcb80890036299465c3c9c45fc49a73f9be6c869113ac03dc5daa116bc60f687df7db354201dad9cd841467c27e6f0abdf5eda1f8b7646365a93ba71e1ff6c28d83ab5ea309e2c902a6a1a6396525a97eabf4f69c56b3527811046674f99edd2779ae353654982a10c22baf7fdde401ce67e8044539995f528b398ddde5132fc156e5587a9a3b3d5329f8df4c55e86f3fec30788d8e00df696ccc46a564f2371932e21a45541315d8c31ded3a161e0f595ef47f8fb1dd7f1b57537fa36d105f1ad0e60c917f01d9c88fa0020349cca8b01d77affe23ca4b575abf1e42726b271fe77ff0fe81a8a20c06ac8db699aa2e11f05cc5e9bb794b7e1f847f411fc4621281d257219709d38ba231e7060f745feff6b4bef5df477a24ed763e2bd49929e6c8c83ec776be988a8528b1fb360bf5d7bcd654ff9a1cfe1ebd5f6f21954f155b1f6ecfaa7e6cd4e52d9b08c68943b29b54c5628f3ef3a966a94fa964a5874bd2fdaf65a663743f07eb0d6b3b3427dd419c8ef627675593728885a3ddb1e3c4d"
+            },
+            Test {
+                input: "d2cb2d733033f9e91395312808383cc4f0ca974e87ec68400d52e96b3fa6984ac58d9ad0938dde5a973008d818c49607d9de2284e7618f1b8aed8372fbd52ed54557af4220fac09dfa8443011699b97d743f8f2b1aef3537ebb45dcc9e13dfb438428ee190a4efdb3caeb7f3933117bf63abdc7e57beb4171c7e1ad260ab0587806c4d137b6316b50abc9cce0dff3acada47bbb86be777e617bbe578ff4519844db360e0a96c6701290e76bb95d26f0f804c8a4f2717eac4e7de9f2cff3bbc55a17e776c0d02856032a6cd10ad2838",
+                output_str: "3582def5c0ec3c751727cbdff5d9561e3a0f9effef28c063461605140a2126265fa88c15b9ea3ad5cfd82378f78ac98baa5ed67969473ed9177ef14f44ba210bafebfca9c8dda7e1ab5c6881aae8ee0c824b47493c38ea7b5180323c7e962aba1de928a0acba596b2f8b7af188265eb92c5bebc9ef0a41f692e4b762990a40866aec96ceecb20ef9f7ccbfb83a85485163789811fed7b8e0a43fd15cfa4bb13099f3cab95791f8b05f5027672eac2d397fde1cd7e06fad506ca1efc22ad9cbb354d98be5790b4021c7afe6ef25d223510664dec63d35158999c9cdcc513c8c7e93175a677a30259cb280aca38fc7a8997b663a29ebd98d1c35f7dc1daabd6770bfd3b84f1c0314e67f14e7fa9a881c21bc0e5c2afd5f1b14ef4edf9ad382f7d7e008934ef762b41782dcae9b64448abae73d5a3cc80094b4f9983cb92d61c3555e58c0d24726e8073c39c3480fb2ba9f8679b9e8618cfa04921741b3ee72a276568068334e61089cea277cf0d34ea33e02095be33202ec69d2314128ddad63f001df3809baa75e3a5720b34e8c7a63e06da419a4818e48b30d8b0ae2e2405053c9ce76ac45c52edeaf6237260f18940f0300125ce674be744dc2a07262a146cb3bf595b59eb499439d94f8135de7e58c0fd09744ebbb97bd4c10c178904f52c7481b4d808e663dddbbf3235844cea3db323bbcec1756bc4480c4fed0c14e14d3"
+            },
+            Test {
+                input: "f2998955613dd414cc111df5ce30a995bb792e260b0e37a5b1d942fe90171a4ac2f66d4928d7ad377f4d0554cbf4c523d21f6e5f379d6f4b028cdcb9b1758d3b39663242ff3cb6ede6a36a6f05db3bc41e0d861b384b6dec58bb096d0a422fd542df175e1be1571fb52ae66f2d86a2f6824a8cfaacbac4a7492ad0433eeb15454af8f312b3b2a577750e3efbd370e8a8cac1582581971fba3ba4bd0d76e718dacf8433d33a59d287f8cc92234e7a271041b526e389efb0e40b6a18b3aaf658e82ed1c78631fd23b4c3eb27c3faec8685",
+                output_str: "8c05c9635942c0661c29cda0375395b595a82e4b1ef87d767e5a820cc6975f2b1af87b76f69de5bb9b77e14753c2efefcb735601df5cb4ddaf5810bb89ac8863379192c578a3f2fea30994edf58f5a995857af481fc4fbaa552e6564ae091c3ec2c5fb5144798405972c6947d45696f7e918d6820274bac4ed1e721e85ee688e7ef7e6b4c87ca94cb6ad3221b5b0189d2f39a5482ffab8a928a8fe4c117827e33e9c8b024bc35e30a9475d54293f196c83eed3b458d7e676a48d2bc2e09ad96167e556f00799e63c8c0668aa3710769c6533af4f04816355bf4e88a2ebba1b442bef0bc9f7dd85a1fa42745893cd1f87614356e42e897821bbde09cba135ace56612ad79a99a3397d2bbb6fcbdc505a0372df7ace31b53231887a618e4e846e3e458078b4ab9fa4d6d4d118f16ec8aa376b40cdd1594c0c41fee2dfcc866ffb1f9b8aefa04435f895b6d73e2faa89bff85ff14c133729b3789251e2a2cb38b8d5f9e6f8f0eef26fa1a17a8255ae9ef58fa4ba9bd8a8fde46ed5b0cfe9bfcbc20bddab37812fa44b0a1a99a6f10cf0e6bd931b6afe22af298483fb4d45bcce9fd79c5a9ce2eb3359cbbb4673e0feb2d1677f06a15f0938086daa9cdf2b08fef130bc793134369d4344d474f93c3c9eb877d0de0cfef351fb2589436de6247b51352ca913c3e774b70655ad48befb6e4d494a6e610cd968e8cc613339d789c16df"
+            },
+            Test {
+                input: "447797e2899b72a356ba55bf4df3acca6cdb1041eb477bd1834a9f9acbc340a294d729f2f97df3a610be0ff15edb9c6d5db41644b9874360140fc64f52aa03f0286c8a640670067a84e017926a70438db1bb361defee7317021425f8821def26d1efd77fc853b818545d055adc9284796e583c76e6fe74c9ac2587aa46aa8f8804f2feb5836cc4b3ababab8429a5783e17d5999f32242eb59ef30cd7adabc16d72dbdb097623047c98989f88d14eaf02a7212be16ec2d07981aaa99949ddf89ecd90333a77bc4e1988a82abf7c7caf3291",
+                output_str: "84e7658f462f68915cccc917b3f7a01f18e9e883cda1fa6c856e2d3b77c53b9e9c3841ef72295ce3418319e1daff2f58aa0ccf89c1107c459b505a46df314e670b51753cce3701822c4fae1f08ea93789fae1a8a61755fcc17f57c8c8e344208a299995a3c3ed6266756d17dfb70e67f27621a6af9ef926ed36f3cb169c9bfbb84df0b2c51602902c12f519ea23c3b4b8bb2b1241798f72a748c6ae4e439cf4fcf0fba17407d1366047b4a8ded133da17a5cc2bcd4e9803df6e5fc76a732ec64cd4c556dc97c8e8be5bad0fe5fe440e462da16fb1c7b18a97f58da4b5ea9ae8700a3e2d1325ebde9dbad97faad13db86d8f438588ad1e966e4a7dabd0ba4a3907dbebd2b2599718b885730bc1d7491a0e2fa468f29843ebe5e551e0cefd21f85568d6a77b8515ef42908360b57cad79b0004724dd117028bbceaadb514d45d76fce77fabfa64c11b9ac2bcb830f77c79fcb67a71d669bf7df2f3b7f5f9fafaa9571c1f2a03892e6bc576699806539af01c1a840d6b168686c5f0874bba3ede49b161719927b5e32e4f19982d6d32a0453877f08c592ebcf7aa323f78a66ee81ce5297e3b81a01ef64fc9454fbedc15c13a39f6ac8bb9a0ceb14e879181f72719f325b8ee60b3cf56ccfb42fff90cf1fc987f4acd7f052f137572809bddfc6d6d0a7f082f9868f3492924f8b9ba5d924c961a4b9282f312916100aed0966523c6"
+            },
+            Test {
+                input: "9f2c18ade9b380c784e170fb763e9aa205f64303067eb1bcea93df5dac4bf5a2e00b78195f808df24fc76e26cb7be31dc35f0844cded1567bba29858cffc97fb29010331b01d6a3fb3159cc1b973d255da9843e34a0a4061cabdb9ed37f241bfabb3c20d32743f4026b59a4ccc385a2301f83c0b0a190b0f2d01acb8f0d41111e10f2f4e149379275599a52dc089b35fdd5234b0cfb7b6d8aebd563ca1fa653c5c021dfd6f5920e6f18bfafdbecbf0ab00281333ed50b9a999549c1c8f8c63d7626c48322e9791d5ff72294049bde91e73f8",
+                output_str: "83e17cb699843eaa6308f12943513ab4e4912203026f4653ef6711e5968cfd2cc135da5b4e87707cd732f538b904148b0a50bfdd3f72155d85a22936c2bd38bdbd2b13145ed531e85f2e0319b6022e8f2115e6fa99e8d92e8ab418a84aed36d574b82a282099db5fbbca069589a3ec308e76b03c8f6c3c5ce11df0d5635740384a22f9047c52f8c561a9848f0104167d8be0a4bc47bb8a6474180bbce3ee691147b74dc57fdf56420848decdf3fc5a06648c1c42a0172fa02df905f8318482f8189d5351751de1ed5a63512ae6a4c456fb7d55f83142cac479452879e71fc774c9bd9fea4560acb7786cf56fabbbd3881bea980061623645bcf1d20448acbf69fad1030008bfa7298fde63963386af5c2b230e9e367b78c4b172b142c7ef43022c866e975f71128719dcbc2663d892c6c4d888e66c67d9e767af52231b93da9ed7895b4b015d9d84623c3008871b95382ec788fb58222c4dd8834054c694722248f4a7d0a77e4bd2a5c418bb5229c0e2ec9ed3e03e79e3f824c2c6e1eecc72a13e341f46f3e30085b3a3fa0c55f59c56ce150537e305c37263aed88d8ef9bf0cdf9978636e03e7deb701345d9442725664fcb38edef923cc11cfb94ae152d0bae72e09a813a3c25002faba1dbcc0bf5102bc466d348e6027f5ad72ff9dc35d9c27c4c1e5dd39a647cf24269e6437fa114c74b6c1604b906c8f5aba1ae06b1bd9"
+            },
+            Test {
+                input: "ae159f3fa33619002ae6bcce8cbbdd7d28e5ed9d61534595c4c9f43c402a9bb31f3b301cbfd4a43ce4c24cd5c9849cc6259eca90e2a79e01ffbac07ba0e147fa42676a1d668570e0396387b5bcd599e8e66aaed1b8a191c5a47547f61373021fa6deadcb55363d233c24440f2c73dbb519f7c9fa5a8962efd5f6252c0407f190dfefad707f3c7007d69ff36b8489a5b6b7c557e79dd4f50c06511f599f56c896b35c917b63ba35c6ff8092baf7d1658e77fc95d8a6a43eeb4c01f33f03877f92774be89c1114dd531c011e53a34dc248a2f0e6",
+                output_str: "2bef02aaab7478a7f4b6e3c22aa5a979bdba90ce91a42782e785ad6d06f82ef0017b54c408cd7027fb3057beab1da1b150e54194bdeeb87f65eaef6754ad8e00ec4b3f98ed2e64b85a3907b353d68614515a2a2d110a1e3249286377446c5339284b3c3ebbf8d841d49a34f7c79c935a69ce342569e173d87df08b332f45c42c9b318c6b02f4550058e2e0697f1e1e76dc0dc78f1deaf7a44bbb58152964da263f633f09fefe2c62f4a482209fc9715b0c424221f7bc81c67f438d920e7d9cef3d98bab3a27ab5e136439da3c5b8774c01e6906416f0d48675751174f09dcd2185ad246cdd351414b9b5591e500b29aabc046f048bbd5776da155b13a5970f26b393eacb372bd28b4934a6f252bc45f7217b29fd77a1deccb20b060c9858a98485671e02abc45dcf956255e52b5d21a59902a33425bd6853d56c18000f5d637cde2f109ec6d9fd3c5427e6bc2468a71cff6c57476fb1a850df304645c0e64f969a541611298e1b19f95ea628937c2adfd563fa309838ee470fa4810317177d61ed849b9fea54410c877b1c5c59625ae5314e823cbc1d3dd79bc1b6498e22f7d15328eb55d0823aa19f0922be4d6f545b8a2256ee141eebd18fd1644368ae4dde10482e8758e4865fc1845cb50155f574e177a3b0a446361801c2847fedb035ebdbc0c7a67d216a4eaa7e04862d6c09d3d04693df25bd2e3fe0a43ad80a9212da"
+            },
+            Test {
+                input: "3b8e97c5ffc2d6a40fa7de7fcefc90f3b12c940e7ab415321e29ee692dfac799b009c99dcddb708fce5a178c5c35ee2b8617143edc4c40b4d313661f49abdd93cea79d117518805496fe6acf292c4c2a1f76b403a97d7c399daf85b46ad84e16246c67d6836757bde336c290d5d401e6c1386ab32797af6bb251e9b2d8fe754c47482b72e0b394eab76916126fd68ea7d65eb93d59f5b4c5ac40f7c3b37e7f3694f29424c24af8c8f0ef59cd9dbf1d28e0e10f799a6f78cad1d45b9db3d7dee4a7059abe99182714983b9c9d44d7f5643596d4f3",
+                output_str: "824271a836fe959710453742e9d957981c2cfa672894c8a886f57f79608dd62fa4310fc0582528e15ca09c7a92d1084d45ed2a3020a9a2a10c2355fdf052ebaa1007b0c01e1ca19d95b1b05c03167923927ac26e33ed6a823c72d105a2b35085926bded8e59a49cbd7c606116bf560fac1364c7e5860a919167e844086d648bcbdb5f148cadeebe2ca2d2c34e9bde155dcc9cf99db22785d8f5327af41ba93aa1dd59a25f26615fd6eb6d57ff6475fe10beddecbd16ce84096cdc6ae5a6b7fad0bfdf6e8cfc974b082a3f0c6d8c5b25295a81bd2650446e7447951f7002fd2f417f4f553f2733d294ff90c629eef9faf0b39dc9cc4ea6b50d438369fec506bbc185d37dda2ef1c6e7079b09be893e6c1c62c24e6296c8cad9921dc182f23c027cb753212e3ee41c401396322a43f4800c48acda4a6198e40b76f0f6ce78354bcbcc33017fb30c33d7a90af566f4bd3bc2cbb08e800bbc7f309d749f9d2a352d9b284c358ff2109bd2c2ceec6e85bc16b83a7d666e582c3e3d39a6a92c196a11a397203f9c5613e2ecc8b2b91c229fe785040a17485b3dbad2b155c270ab2a510cda80e99e1a79be01c7262c217dde69d068753f9e44a3b035e10bb7aa53f397d7a1ec95342ddc973cdde9583b8348d832b976b255362240c5927d24a00050f970334aa404c531d93621516dab81e0fd89611c238d85454c6d77f1ab5d7b2c5bb"
+            },
+            Test {
+                input: "3434ec31b10fafdbfeec0dd6bd94e80f7ba9dca19ef075f7eb017512af66d6a4bcf7d16ba0819a1892a6372f9b35bcc7ca8155ee19e8428bc22d214856ed5fa9374c3c09bde169602cc219679f65a1566fc7316f4cc3b631a18fb4449fa6afa16a3db2bc4212eff539c67cf184680826535589c7111d73bffce431b4c40492e763d9279560aaa38eb2dc14a212d723f994a1fe656ff4dd14551ce4e7c621b2aa5604a10001b2878a897a28a08095c325e10a26d2fb1a75bfd64c250309bb55a44f23bbac0d5516a1c687d3b41ef2fbbf9cc56d4739",
+                output_str: "3768c48bf02d0db9aadafffbd228a4119ac6b7a815d9c74c714eac4b4ba4a062f7e9962b98c361a6b596838c671c95892fa4e82a95c60b9e8ba787158808c2c00bea3bed0ab4846fd57e638dd29b2ed47df5cd19699329626f6bddd14bb709417a972ae8020d05aadfe12034a98f9121a191926566c499c536b2505aebb97c9c49780e5e0007ee5596717e7be42d40db322bde5b7fd227b15987b599c71f1f20eb8be722ddbf3c76f9ea58b490eb11395befa02c259505f038b40e312b5af1519bb6da9e99e0214c2249a1e8c534d768a7db9ef46970a64c6e5f746b7c50670cc8e7765c4b55b26f3a53e4c3178f9599435aac9b96a203cd04988d1d95e1b5c29f632ecd66204b7bb2b7f776f2de67dcbf7f0a81ffa1cd18506b8fd9dbbbd354e3cd388f21edec9a4eb319c766eba3e1e8565b0ccef3698592e19081472004afe38fd8b17e6d1a5afed52ee44990598ce17e09ded65965a380e3452cce6d053f22f1e8cd24a76c74f6a69550c36b43890c7e239658b7da6da768869d3d96333be7422ab7c2b5d90b2c3973d666b4e399a2c5f014566e3ba919ad1964a148da2d35476b17799b82ea54ab6ca0baa098d0734081c7d52b7da8150ab3c1b8dd1174418700c46036e3918e5a21e70679d72952025fb52e9348509b4f10f412a8c8c11ef59d57a3a77c5462253c87475f38911ad2b08732dbddcc6d6a1b438896327d"
+            },
+            Test {
+                input: "7c7953d81c8d208fd1c97681d48f49dd003456de60475b84070ef4847c333b74575b1fc8d2a186964485a3b8634feaa3595aaa1a2f4595a7d6b6153563dee31bbac443c8a33eed6d5d956a980a68366c2527b550ee950250dfb691eacbd5d56ae14b970668be174c89df2fea43ae52f13142639c884fd62a3683c0c3792f0f24ab1318bcb27e21f4737fab62c77ea38bc8fd1cf41f7dab64c13febe7152bf5bb7ab5a78f5346d43cc741cb6f72b7b8980f268b68bf62abdfb1577a52438fe14b591498cc95f071228460c7c5d5ceb4a7bde588e7f21c",
+                output_str: "ea94da7fedf4b2296823eb57f0fd81468f4476e6f9035043f84ba952015af88e68233219e4d31d809a9b13a703ee6e99c230e1e037d777fdc6b4bce3f81ff2e7a15b9dad86f4816d1adf0f5c34e6ee2fec26353444efc417babe16c45bde0cb3b06abd19f354f5ba5298cd486dda4c6216d4826c3eb1b221c24a63be7dc751f8ab5458000c28937809359a4c49200949048156d48d537466effd085610f221454addd95519071c8a671eaafba7b6f894a3274599c76bf0964801fa38b601869d4c04ee9fc6ac7e54b4a6d8522912f5f3f2a7c6cbec20faf1e164388d932c5260763457d27525288be09ecdfaa1a892b99ad0da9fc1cb3d60b1b85dc953ce9b37711ae6bb82a1f96cf2479155bc3b328803d1eaf56ee0f02223bf167fb33e6e7190f41a121de59b9fe9790c8fbbc2b1b77add9c316d75a7f4dbdb52da2edd9d2356c6aa77a1cecb5330abc382a748c8972fbd78315dd2a4addf335d18d5c97547641f6b5abc4c5f166265d6934c77879a5b4cadd27a8a7f9f817acb1307a88970d29dd929d5b03a71d5b863a997c84d01b58dba539ccf6693b6004812727b254d22480bd50c5e07f162db59ec112e1dcff813bc266f704357202ad0723b373bdf49b1ee3d4e24d942d2e8f95e41ff496b9f4f535601980366fa79b662507caf88aace17ed6498e6ddb65c799ea698c7b8a49bf48021cf3b41e96225c43481b7c1"
+            },
+            Test {
+                input: "7a6a4f4fdc59a1d223381ae5af498d74b7252ecf59e389e49130c7eaee626e7bd9897effd92017f4ccde66b0440462cdedfd352d8153e6a4c8d7a0812f701cc737b5178c2556f07111200eb627dbc299caa792dfa58f35935299fa3a3519e9b03166dffa159103ffa35e8577f7c0a86c6b46fe13db8e2cdd9dcfba85bdddcce0a7a8e155f81f712d8e9fe646153d3d22c811bd39f830433b2213dd46301941b59293fd0a33e2b63adbd95239bc01315c46fdb678875b3c81e053a40f581cfbec24a1404b1671a1b88a6d06120229518fb13a74ca0ac5ae",
+                output_str: "73e672e46b274d309899ff2c8186af4a9f42872135309c85621347c55edf8d3b5a7db51b0242618ab6d750ef75cf816c23a0ddfa21adc9976cf47a6957e914baab02e4c2dc809c0d2f67fe759e92d7755ce965ea4b4045d6172e1a0c749b4498795fc375aa6894118a1be2821a7878d25f597633cee5576b3d15e23ca7d664709ada20e3cc182d3004b102bdcf5566af522c5511049feccf80d4a6c21d7ccad1b24dddddda0dab0c2ff40e056d0a715a31dd35679fd4a4ca8bdd17293f7fd63319bb5b4abd3698d574ba5d36445e7fbda9eab049f6a8b277c0593949da84805036b776368566f622df37fd3d42efd06eb1d5c1c2847717f51d236d4317498514d95e1f4587669ce819de249ebc8d05d55e2c35dbbff3c017c7a8d55b1b184ecf72f288948027e2ac2cbe6589b351437e185a888ea5ae7219b9121e438ec3cb397133b75330b1418af085e7b42fb4c3b0f41a95bc6583ca7ded8a470e2cec237013df9cbb866454f276648b1dc0bfdc6bc5346348735764f19f08905f1d17fddd454be1b0e8df34879b4e7709bca044ad49a14f9ee971283f2a20cf6377c648e9d85599fce482697b8feb218418b1ef0979935e0f88ea5a2d38506955532a0b9da8ac1e7641622dca9f2e31642aa41db7fc73328590b69459741998ab90d796293999ba8a2111df20256d2fe50ac6b0bcfd5edd61c260512ec357e844596eff10"
+            },
+            Test {
+                input: "d9faa14cebe9b7de551b6c0765409a33938562013b5e8e0e1e0a6418df7399d0a6a771fb81c3ca9bd3bb8e2951b0bc792525a294ebd1083688806fe5e7f1e17fd4e3a41d00c89e8fcf4a363caedb1acb558e3d562f1302b3d83bb886ed27b76033798131dab05b4217381eaaa7ba15ec820bb5c13b516dd640eaec5a27d05fdfca0f35b3a5312146806b4c0275bcd0aaa3b2017f346975db566f9b4d137f4ee10644c2a2da66deeca5342e236495c3c6280528bfd32e90af4cd9bb908f34012b52b4bc56d48cc8a6b59bab014988eabd12e1a0a1c2e170e7",
+                output_str: "bdf536d8b28e91f00b710decd109897b4e96882aef06337fe83b053eac20cc54523d246c41c9de3115870b82a1bb2eb2b1e02ccf7a4e607bcea3dcafca38f237dfc72d447cf8c544f541c1b53e7769b0cd6f2ec6d756891dfc818323cc1e1ad565f9130f59889798e418fe5feb176e77f5ff8f10c6acddbc59c8d084ab19da2ee5b737e537609bfa6f81df1846b033663d586ced1f4e86d99131d37ea5807881d2de749803e333af2c360f8ee9fd99a166f3fb8f0c50bef02df50ee615c08e88299a1f3cddf290a3bc9e4357f3d93d76ec5df462175edc5de421a6ba456ea7c42ecea24eec74011132c27fc63f1e969b474438222c7de33762f5377c197dde9afa9912900ff25373efc3a3d023e091350d0d269bcbff64ef35e2e1e1c300214c3671932cccad7c871fef4c969b34cf6e8b0881c2f7704b455f118e3bd37a74be89354d8c8dfcf649fa03701ae17b705a865c7ce9ed81e4fb374eb643294356eed48b3579315bcb32ce6c7f302ed5bcd68f2183110ef7ff60aefac6bfb8252bc66c0f4026dc37ebe4d9783ca7459394e929b8a83fd8378d9e097afcb0a7163f16e5579e8f5546898c4b521264caa006b3fccdf46ffadc1925752ef47da30f354d66f763aae46a0bfb385ffbe153641569e5e222f374f8e21ee3ef8d42663a4c424803e7966f2f0a1ea723a06c92af2393c8fa6711d89514c20b6170dca448fd27"
+            },
+            Test {
+                input: "2d8427433d0c61f2d96cfe80cf1e932265a191365c3b61aaa3d6dcc039f6ba2ad52a6a8cc30fc10f705e6b7705105977fa496c1c708a277a124304f1fc40911e7441d1b5e77b951aad7b01fd5db1b377d165b05bbf898042e39660caf8b279fe5229d1a8db86c0999ed65e53d01ccbc4b43173ccf992b3a14586f6ba42f5fe30afa8ae40c5df29966f9346da5f8b35f16a1de3ab6de0f477d8d8660918060e88b9b9e9ca6a4207033b87a812dbf5544d39e4882010f82b6ce005f8e8ff6fe3c3806bc2b73c2b83afb704345629304f9f86358712e9fae3ca3e",
+                output_str: "b5becca38d903f2d87cfba9a80c51d4a0733674c78ef85bb236e8fa64bded9bdd01db1905e46f4210bb65bfd26965aa3adddc893087afb56089083c72f7649cd5987f449f9668ce66ed21514c05e7f09f52d84fde30e96353d48df0208415db51ea5d120a7182dc9458c471127253aca05d52fcc18b73ca1c3a5bcff4d3b6a41c450826397d9b38ac5c8e301c7a4077edcdb6a46b3979128f20b1080f7768edc1f651d1d122f97620bf2b4e9fd20189bb331ff9026ea58d7203ffc49e901fdb9233255f349a19aaeda9ea1e4f3c45ea9c54f41ce1625c0ef02db370909949bbdfbaea49fee3e3cbb74e1807f553a2000a3c753bc5d529b4e25154e2c86f755645304f2d18ed0e62b62c87931dbdad5d1cc9cbb64430d56afbe7d4c708ec992eaa8e13c5b3ce0343c30ae3f09ea3ed5c0c933a0c76f0fc18ffd4baf93bf95b2c1023dc87d4d641ebc6e1cea6e756f45fd2e58e0562f43389a1048a8bc12c8b3b19e05180597b5ca79b7531c6b8fcab88ac1aea686494b98e211c975b48b7157f985f25b168b93fea82218a227d0b89bef905a5f13eb37438831c2cd871fd8a36a4ea22879570b22c63b67bb60ec1e415f4654f6a3ea5acf74df41fe09de398351fdeee499cd98db89b320a58ee62f8569e10da4c68b9b61620e9d51a343d06ceb484ca532afa8ff141a4ed8eac22870d72f5e1085107781d2e422b3eecabf88fc"
+            },
+            Test {
+                input: "5e19d97887fcaac0387e22c6f803c34a3dacd2604172433f7a8a7a526ca4a2a1271ecfc5d5d7be5ac0d85d921095350dfc65997d443c21c8094e0a3fefd2961bcb94aed03291ae310ccda75d8ace4bc7d89e7d3e5d1650bda5d668b8b50bfc8e608e184f4d3a9a2badc4ff5f07e0c0bc8a9f2e0b2a26fd6d8c550008faaab75fd71af2a424bec9a7cd9d83fad4c8e9319115656a8717d3b523a68ff8004258b9990ed362308461804ba3e3a7e92d8f2ffae5c2fba55ba5a3c27c0a2f71bd711d2fe1799c2adb31b200035481e9ee5c4adf2ab9c0fa50b23975cf",
+                output_str: "ec7a09a04ec20de5ee683681d42177715f85562df50177cbe122ddfb9c5e81ee349d3e2a18726be2e46287759d6d28398851ed22afa78bb4b3a41c76f7006f785887d2d030428ed6ecf7decbe20bf09b1a321b96616f9d1f4ecc90bc2fed1c30c18baa23455303074f10aba5bdb596f3bb5bc1faa89589a92aa95db198915c1fec3420d6a4a5e79808012de71b41cc7a77ab96821b5bd1e822a06e698101e7e4de1e5e7ccf9093992c0b62419a660e1ac4fee0b1d0c4735416c18570697220adbbca56289c2475e17ac6fa89e96aaaa8d5f174d6d9a3edb4a6bee4b606d0b789f942a1f8d5baa758af6f6dfbbe59686ff6a8d625302931c34c8d908bbb0c5269adc95715f90259384a0f88b6baa1fdaa5bd57f5feb2fe0b968120aa0206f911d211c2d77cc465bb6e1839c0271cf55f12658a1fd1f2f4538bf7e9fd784e4c12ae95a5a2967d2847eabe150f2e113d8542b9a7cad092b3d86ad4219632c5f3740eee45aaca529d83f0bf3cd656384848ad577ce603d31b70c40a55db571868c1f5b7aba3cf853cb0ed682bde964c3051e7e81d4454906de1966491e1caf7073035268311bc1cd3590656b1321d8d6885d15c0bf840bb40c0fa4d127878e422dfca7c3bbe8ca4447d5228f83e453c94002c43f5d87e989627f89cf5b6057de6d86d2a82ed982035519f47807ce6c61ddcd9160ff0ddb3bfe08ed966c08317e4eb5"
+            },
+            Test {
+                input: "c8e976ab4638909387ce3b8d4e510c3230e5690e02c45093b1d297910abc481e56eea0f296f98379dfc9080af69e73b2399d1c143bee80ae1328162ce1ba7f6a8374679b20aacd380eb4e61382c99998704d62701afa914f9a2705cdb065885f50d086c3eb5753700c387118bb142f3e6da1e988dfb31ac75d7368931e45d1391a274b22f83ceb072f9bcabc0b216685bfd789f5023971024b1878a205442522f9ea7d8797a4102a3df41703768251fd5e017c85d1200a464118aa35654e7ca39f3c375b8ef8cbe7534dbc64bc20befb417cf60ec92f63d9ee7397",
+                output_str: "e65d36fd64b13db62cdf8640e6a217cd4952be909be1119b04ceb6c8a71550e953be0ace373231964d61b89a575af582a66d7bb1441ea399d59a7c585d762433d64f44c53dd9b8fe8f357a26dc66e04b15b9ffd0fc7c1b4ed07db3e4c80a3527602dd16bab1f8ed85a821056f97fe2912411f7cf6bdb9070997ca4d5bc16b0b26159f7f3cfac7252241c079633cd8287cc41fb3f7cb6185fccee1e3467e90788b9e943c936c1c82115eb5b5a1af3fc6b0104959e98e0ebb0f72fa02fa5745380952a6c2eb0ab84cee35661f34cf0de4e6985baeffaf545d48adf065f13b9272098d5906da5c8b688a3c922aa74d840dd9c1ee31becabc417ea07e2c45a90e1afe588e65109c8da674533d506e17eba1abbc25dd84cc79a4ca0e15013d9d014dacc5f696a7becac187f0a7b233d59a7ba6821b3edc71c8073f2ee0caa8c9f96032aee6d9fbc15bed15e879d0f497bb8de468b4050fddd15c97af4413c4cf60859ea04103a13704cc9b7076359e28a1b90949166f5b11055b415ec8b9a552ac94e4d1f45403af5ebac0762d1ed0967ae032db30dffc8132942f45626c7e50bbf80ddfab80103e423bf00ac575194489be02624bed16c4d1fdcd0011d0c64faf6bb6feb21e0f0653f05d8fb69cf891347dff0a39136bb5d4d20101cb3ee900b508a136185fdd0ff54fefbcc6c069e1a433742d51129a1b556cbcdb8a7e76dc43b5a"
+            },
+            Test {
+                input: "7145fa124b7429a1fc2231237a949ba7201bcc1822d3272de005b682398196c25f7e5cc2f289fbf44415f699cb7fe6757791b1443410234ae061edf623359e2b4e32c19bf88450432dd01caa5eb16a1dc378f391ca5e3c4e5f356728bddd4975db7c890da8bbc84cc73ff244394d0d48954978765e4a00b593f70f2ca082673a261ed88dbcef1127728d8cd89bc2c597e9102ced6010f65fa75a14ebe467fa57ce3bd4948b6867d74a9df5c0ec6f530cbf2ee61ce6f06bc8f2864dff5583776b31df8c7ffcb61428a56bf7bd37188b4a5123bbf338393af46eda85e6",
+                output_str: "2b6d5b37da462a050946d447375ea4dec9309ec30fb6c7fa68f67aeb7b6e1921a74ff35ed31560e695499f2a5afce3e900e1c6f199373951a406a8f57dedda8c9b9d2038e787cc54b62cbd97cd4247ed933de1bd68fa670158701f088c6e785e8dde870306b80decad2dbc40a8c2f02630499292a19339e4d63351ee5a44e36fea062d2253674f5531b1c51faf694a0e963859b26a11ce890a3e5c03815bac2ccc43aac806941befa00cc6bce72ff59f60c85b5096bd7e9d4b60d23a050d3b4333a26b0cb6b69e62f33e87e65fc1562e5d1384f439d717a940e2a291897a4eb3f941397eaffcf4ec738dc643e72721b5662f698bdd502ed1a82d924bc0d780a049f7d965bb585d0f674a06fe03f0b18ae56b7aea705328072e4a374b7b9715882bd73c34e99656ec073b653c2608a04d84adfb4607b62b4b504e43f07f9d4555935e3d432ddff23d9aafc87c743c1bf8a91ea4671a03e5461cf13e76e3c1779cd97da4055eab8e705556eb7538539fc6ffc1638e702ca2a60f0506693d54a35f7af6fe0773a67767865b3f1397674eff365b3849d261e29b160cdc91368899867689e599a85572464fd895cba2bfb4aba496f395e7950e064ca509ab8d8491bb193661e250f35d5e2af12e1f981970390f456953a8ffdf72bf998d0fd7393c33fcbace063c0d63f91e741f95fd542c6c509036824b2784f394e27f6bce88b1fc"
+            },
+            Test {
+                input: "7fdfadcc9d29bad23ae038c6c65cda1aef757221b8872ed3d75ff8df7da0627d266e224e812c39f7983e4558bfd0a1f2bef3feb56ba09120ef762917b9c093867948547aee98600d10d87b20106878a8d22c64378bf634f7f75900c03986b077b0bf8b740a82447b61b99fee5376c5eb6680ec9e3088f0bdd0c56883413d60c1357d3c811950e5890e7600103c916341b80c743c6a852b7b4fb60c3ba21f3bc15b8382437a68454779cf3cd7f9f90ccc8ef28d0b706535b1e4108eb5627bb45d719cb046839aee311ca1abdc8319e050d67972cb35a6b1601b25dbf487",
+                output_str: "e8b51670e0d27d9f7989447a97c07d8d142804f876e701a49e6c4a0ee149938881900637ac7329eeab1f1e032ddc2194b2417856401060eaf019ad4d9da3bc702bd70be5fd9d9c9b86f4044ac441560e887ae21e3c3ef3f05e38c7f8b078d3a66c6fc8b98e33ea8ad1d029433626ceae2468e3034cb44326c89d7a7188a5272c116d3783fa16af98ba3070ac96c07e459f1127304483a2394837ee1a10020a79f8519795895f4786f5a15134dd44fcbd9bd1efd0ebee9cd991001fccb6a92e490793b6f16471670e1d69f9ce49020c1e8e3b453cdc1a8498d8c510b8d21fa00239088e065b742c51257766f19e17b397362dec9453f50328c5e14bf800396a0a3a1a957b29cb1c8fa059bde39b995d45900b56e2c8cd2f4e8bac756350de38293d1fe4436489d9b23860e1ad35e2411d0210ddd1c3d8994635f29674a64aa5f92b2088f3e7b4fec26485d93483af96fc4c5fc9f34254e014ddbab361dc55e0f5019ba9ff8ed7b104e09122a80be3bd29a3e4c4c26a7d2b08f8915087d9a6a2e7888710a5b2b87448b81f889830e26e6813385b761fe97e3729ad04bcf08f536a152039f04c283dd36b9544c4d6cba97e26b61e034259caaaadce508343dafbd4dbcbce25957406b22e13dbbbb186c18dcbd5b8aa18c86d8660698af26997726fb7af26c397df8608708ad5d6524001634575a2f1070a5ef72d327e91c7184b4a"
+            },
+            Test {
+                input: "988638219fd3095421f826f56e4f09e356296b628c3ce6930c9f2e758fd1a80c8273f2f61e4daae65c4f110d3e7ca0965ac7d24e34c0dc4ba2d6ff0bf5bbe93b3585f354d7543cb542a1aa54674d375077f2d360a8f4d42f3db131c3b7ab7306267ba107659864a90c8c909460a73621d1f5d9d3fd95beb19b23db1cb6c0d0fba91d36891529b8bd8263caa1bab56a4affaed44962df096d8d5b1eb845ef31188b3e10f1af811a13f156beb7a288aae593ebd1471b624aa1a7c6adf01e2200b3d72d88a3aed3100c88231e41efc376906f0b580dc895f080fda5741db1cb",
+                output_str: "120ca7e361a65a0985563012cb908028105abdbcb51cd8eaca141662b0c184e9b2d6dfcdaded7d7cbd42455b3f5a9f15596d2bace19510256275209cc9899a87c6224df8e919458ea46a35cbc8d66a488069703cbbdeea6d767cc315fbf518f7b0a0154448f8d7c56da1b116730a76954c288b4891b56fed41b2efde6c27dd4b3de9bcc25a2a901d4c87975e82372af173982601b605d845dee7bac94eb410b369bbbde500d458f9f8a3933d3bcadbcc85ea05acefc9a7a77e26e28e82db157ec1cb2c99c272f33b1b2685533cd988dbdb6e850bd3c71e0589a165fc236a65b1f1db750a3fdc1392a76e7714469b47e20d8946af7d68ef9b16109178f662320d60a0d843efcc5b1e56cf6d8fa8b649ddc28e58983abac7b2ce019aa0e07b387d8ba46cd3faf47b522d766971ba603c84684bb094e38d82ebcb108ce0353e38fa0a4d7294f7b7baf745f3e036ec0231f6a194585ff7ce1c792e4879bb44e4ad65717952b080beaae1fd0cb8ae87e6f130f91bb06f95e54fa924e2d0c42921d7ca9965ae70a3587f12017cf1e4cb70d1704a51efe27dfdd919c7fe70f967cf7044c62d6ff232b6680278e9498f247ad92d5e9491db0f00d583c019142a8eb63678231e1273f0a263c57b98e0af650fa207d4b21650417dddb40830f89e15c85e934fc745aad87ba35dc16b7a82cc97926494bcc1feb4ed43d75f518acc22d208d3"
+            },
+            Test {
+                input: "5aab62756d307a669d146aba988d9074c5a159b3de85151a819b117ca1ff6597f6156e80fdd28c9c3176835164d37da7da11d94e09add770b68a6e081cd22ca0c004bfe7cd283bf43a588da91f509b27a6584c474a4a2f3ee0f1f56447379240a5ab1fb77fdca49b305f07ba86b62756fb9efb4fc225c86845f026ea542076b91a0bc2cdd136e122c659be259d98e5841df4c2f60330d4d8cdee7bf1a0a244524eecc68ff2aef5bf0069c9e87a11c6e519de1a4062a10c83837388f7ef58598a3846f49d499682b683c4a062b421594fafbc1383c943ba83bdef515efcf10d",
+                output_str: "f0715de35692fd70123dc68368d0feec06a0c74cf8adb05ddc255487b1a8d4d1213e9eabaf41f1161719d065d794b750f84be32a3234b4d536460d5520688a5a79a17a4ba8987fcb61bf7daa8b547bf5c1ce36b56a73257dbbf1babb64f249bdceb67ba1c888370a963dfd6b6a2ade2cefd14c3252cb3758520f0c65f4524682772499463ae1a341800183aa60efa05118a28201744f7ba0b0a3928dd7c0263fd264b7cd7b2e2e09b322bfcea8eed04275795be7c0f00e113827370d051d50269580300005ac1288fea6cd9ae9f4f37ce0f8ace8bf3ebe1d7056255954c761931d3c42ed62f7f1ce1b945cdecc0a74322d7f64d6004ff21684149307288b448e45433475b1ea1314b00f1fc450089a9d1f7710c6d7652ecf654f3b487d0283d4d8a28efb5066c4250d5ad698e15dba88e925e4de99b69bc383ac8045b7f1022add39d443546ae0924f13f4896096dfdf37ca72207987c4a7705a7abe724b7fa10c909f3925449f010d61e207add95219071aceedb9b9dced32a9e123561d6082d46aefae07ee1bd132765e3e513c66501b387ab2ee09a04ae63e25808517afea3e051169cfd2fff8c5858e2d9623897c9e85175ac5a86394cd0a32a0a62a8f5d6cccbf493daa43f78362bbca40adf733f871e0c00998d9bfd6880656666cd7be4fe9892c61dcd5cd23a5e4277eee8b4afd29b69bba55660a217112ff6e3456b1"
+            },
+            Test {
+                input: "47b8216aa0fbb5d67966f2e82c17c07aa2d6327e96fcd83e3de7333689f3ee79994a1bf45082c4d725ed8d41205cb5bcdf5c341f77facb1da46a5b9b2cbc49eadf786bcd881f371a95fa17df73f606519aea0ff79d5a11427b98ee7f13a5c00637e2854134691059839121fea9abe2cd1bcbbbf27c74caf3678e05bfb1c949897ea01f56ffa4dafbe8644611685c617a3206c7a7036e4ac816799f693dafe7f19f303ce4eba09d21e03610201bfc665b72400a547a1e00fa9b7ad8d84f84b34aef118515e74def11b9188bd1e1f97d9a12c30132ec2806339bdadacda2fd8b78",
+                output_str: "2e27811d2e132c58a1d053ccfaaa2813b620554c49c31cf208964cfa18a3eb5724d4ebb37e37398ce9201ca33c5f6a9409f262afc5ebf0970be0618ec7e56c15c13b2f0270ab5a9536fadeb84eb2d934b989354d47fcd1dbfb40fd96485fad8df7c6e62a60866f154901e4427c2b5e6059c76224589a6be352673430740903e4225c1379561ae5d361b67f3acaca9c7633cccd2601ed278b5c7d6a378d713bc549e2797ca34fcb0a00e649ac3a4b59001e5d8e1e2785433ed65c76f4fec4b0579059dd4da49bbe678279f534b84a280f89dfbda09e09c073ea11afcafd5685a714ec31e8f86b49d2c97e6a2a66b4f2aa76d9df2d27cfacc2423aa18492e2f4ef6a9f8971627839375307f45a8b26133ff1d02f100ef05df168a2be02f0c17ccb90f23a0fbc5f536c410923b154e81a6557935e2572165a7e39f64f57e2b8ced8d2cd1025edd5dea6dbdacc8860bd6a0c598eef14619d4bc11b6aeaeb5d10bff3f9d5b20b7f2ab8254db0c1765a10a125e98d762851f05261dae06b224e2076112a62b4c3f3a56074e01cb3dd264cb1f4b58eff2a1c9acc4764a68680a40fcacc719286684fe0a742f13b5bdac8aabfac68174c7e153796c240279b0acc719158d1fe4f78ec3d47ea8b8d3a1b3a6842970fd439c09096e8b032e551dbdfd0ef86da0537f4e72f78368b319b6db735affea80633f2f8eb9d26c8cfc321c7c346f7"
+            },
+            Test {
+                input: "8cff1f67fe53c098896d9136389bd8881816ccab34862bb67a656e3d98896f3ce6ffd4da73975809fcdf9666760d6e561c55238b205d8049c1cedeef374d1735daa533147bfa960b2cce4a4f254176bb4d1bd1e89654432b8dbe1a135c42115b394b024856a2a83dc85d6782be4b444239567ccec4b184d4548eae3ff6a192f343292ba2e32a0f267f31cc26719eb85245d415fb897ac2da433ee91a99424c9d7f1766a44171d1651001c38fc79294accc68ceb5665d36218454d3ba169ae058a831338c17743603f81ee173bfc0927464f9bd728dee94c6aeab7aae6ee3a627e8",
+                output_str: "76a498f8112b364e0db20cb4e7aeaa1c96400a3e1eb1a24ed865203c4a583ce5ca10b47e725c362696f0ade5fd75058d6882b435849030868486318e566be51b6d985a76b36d98d893a04cc715cd26c412bb4ccdc0db6d1b13cc071fbfc83f114c72d3b54cbcfe57243189251a7c0608bcaa1409b243f2652cf5cc4386cf4551d2955f371591c0a04cbfda2736a514e773b5ee8c5cfd820a7542cba65245f729e650d085b3f60ebce2cec0d8c952add51a664788b3197952e7d0d9fdcca35ee118bc0144688621dfb373c2bc1de7ca7bc751d539276a119ecae8ae2987e018e9fd70c632f2a54701302c12b971e0ee5308378669ea10d0e9a7b955be1c1bb9e7ff6857c39eb6b074c061f28d1979b33ab8d2f81078325c9f7966806d2cb62903fbaf4c12ac4aa15f010034080571bee9e863c1cb89cb01b86643db1d1a6c224934a79d969616cc3f9c1382b81eb83a8cfa2cdf20bb03cb67ddafcf9cd827d76a0661b85e82664bdced0ef34d2f807ad956724ea2cbc511632d2c9e9f8e4fd71e127d581cbbb39782be58902927b0c0d922493255f805c5cc78a96aee84ed086aa93f8fbf7282d78daa0b9c126216bd929ea4a4e53f78088ca154e9a63b3227a25705532f699606ee73a5fce6e6c94def1324ff2e0edf6807700ded2f088e2d77b7f690e646e7a73ca05febb2634d862d7b21ae2acfe3a5b3dc6ed1071b0f3e5e"
+            },
+            Test {
+                input: "eacd07971cff9b9939903f8c1d8cbb5d4db1b548a85d04e037514a583604e787f32992bf2111b97ac5e8a938233552731321522ab5e8583561260b7d13ebeef785b23a41fd8576a6da764a8ed6d822d4957a545d5244756c18aa80e1aad4d1f9c20d259dee1711e2cc8fd013169fb7cc4ce38b362f8e0936ae9198b7e838dcea4f7a5b9429bb3f6bbcf2dc92565e3676c1c5e6eb3dd2a0f86aa23edd3d0891f197447692794b3dfa269611ad97f72b795602b4fdb198f3fd3eb41b415064256e345e8d8c51c555dc8a21904a9b0f1ad0effab7786aac2da3b196507e9f33ca356427",
+                output_str: "760dd76e50c13b411d04ed9d81078f0e5b9fc5df9523f7c2aeeb418ca328e047071852fc5ec2f96c2133c4aa7c68306ffd70a782490f92812e04a3343b9502c14b781a4800a8928956ea457a3cfb94a63bb4407524dccdb6136c5228fc1cd426f75e1701f0ab7d7ada8079e4761fcc4dcc72155b4b27370a7eb6a5e3995a729ad8d8b5356a084b0678b114078b0d43c657a23f09d0862d606a8a485fed68ebbbc63a126fbabdf36151d5a39bf17632b3d967983fd62e19c944400f7a68393603243ce499947f3edce7f30206bcbff83615dbab7642c5d82de050d67c93b836b554949b96947b7d1534e0755859adb7ba5ac9f519b18c3aa66300acf9a26849665810250004529334169211624c6a63350b392f6dc6753d59a03997180980ee0e742388a2bdfca619524dd16250800918e95cab914ebbfb12232f1687be0b46426e126787e394a91f775fa91ee1c5d57ab1ffa151d554b79de8ee9a937aaf5c98497aaa726cf01a9dbce6e57a07f8d098b2844ecec9856d3d8b189d016b34c4ab61aa3191b3e4c2b44f6bcc9444e6093a56545230fcfad19a2cb124abf524689f4f665f2e84d10a2c93b8ca412b6d280c2680e946a6c9225db6f97a86fa3415a84d52ff3a0a15dc7ce97738b0b2dc1430bd56bb71ab89ee108b5bdb706c7919d5ec67c487d9c8dfa6d2333c59248104f33f4c162a5156a3a666948e3a6da13d0d"
+            },
+            Test {
+                input: "23ac4e9a42c6ef45c3336ce6dfc2ff7de8884cd23dc912fef0f7756c09d335c189f3ad3a23697abda851a81881a0c8ccafc980ab2c702564c2be15fe4c4b9f10dfb2248d0d0cb2e2887fd4598a1d4acda897944a2ffc580ff92719c95cf2aa42dc584674cb5a9bc5765b9d6ddf5789791d15f8dd925aa12bffafbce60827b490bb7df3dda6f2a143c8bf96abc903d83d59a791e2d62814a89b8080a28060568cf24a80ae61179fe84e0ffad00388178cb6a617d37efd54cc01970a4a41d1a8d3ddce46edbba4ab7c90ad565398d376f431189ce8c1c33e132feae6a8cd17a61c630012",
+                output_str: "76bbac5e72bfa9b5952d4fa8313c2c8995f1b762b0855ea28417a04cdf1bc9a72038014f4d1af37d6338e217daab8993cfc222510a869403dc46b5d798646bb76abf4006f31be334df8c6da07ab8c6e6523dcab9367e6b747600e785ea0bd3480a07d7ad1304019c0f00f90b2a650599b0b416655ae1b1d8facbce38d0dab5a6375144790b0f7e8c61b4a98297c78ee6fca19051dcf60b4eb1f6fc59dfbc5bd1b2ed6b9c72d7b5dc33e8d13566bc67013cc7114ead63d25eccad196a5c258de23d82e8cb2ba6753c9bc598a54f921ca924750a45353bd44593415aadd251b604457a3caf3da681c0fbf43e4f3814aead086a72a4787914fd08bc727a69ca5646ac709b9e0df5b56c8ff82edbe3c23218a1d5382aed38b3bf54ebfa6015c388c8e92d57ccb97fe8171e1d24360311d5ed53545b541e7f24ccca9c5b520feca2547ed6e1889a05eba1c0831d8ba9162b38491287b46bbcde9bd2198eeda5fd0869a83543713bd294d84371f1932e3eb370e30210fdbc2853f27372df095f71a34fa4bb0e1fdda682170a29f9e29c2bcf946cd2865865a70dac22a81bc387b6a06840230ff8790b6bf1953db882dacb6a9208709c121af24a6436b1a5312b3e6d77892fff968138dec8b933e3022b4141a4b4605524c95468cd89aa56bf577e16a365531434fb98fd8399dddb58c0e5ce66c8a8955ae1ed8eae5251026861c825a6"
+            },
+            Test {
+                input: "0172df732282c9d488669c358e3492260cbe91c95cfbc1e3fea6c4b0ec129b45f242ace09f152fc6234e1bee8aab8cd56e8b486e1dcba9c05407c2f95da8d8f1c0af78ee2ed82a3a79ec0cb0709396ee62aadb84f8a4ee8a7ccca3c1ee84e302a09ea802204afecf04097e67d0f8e8a9d2651126c0a598a37081e42d168b0ae8a71951c524259e4e2054e535b779679bdade566fe55700858618e626b4a0faf895bcce9011504a49e05fd56127eae3d1f8917afb548ecadabda1020111fec9314c413498a360b08640549a22cb23c731ace743252a8227a0d2689d4c6001606678dfb921",
+                output_str: "1e7cde630a92bd14100ae80073cce0301aa6566dfec50400147a9dfbe921bf35b110bc9c0b7ad6cfb50785c63881be1569495092866bce9ae303b3719b14a47dea8fa19cad3015d320c678cbd2b7488e71180d967bbacfca686eff014b7eed274f678cc43825e79c81269f99d1b824d913f8acba4dabf5441a29c2e769b44bbe9954a7444bfa438ef1ba2b6a3db11e11151a1736bb8ca22494d4a3d126f100a41d49e6114cd66cb44b80c2e3308a0b551b692bc5b693ba9634e219e0ee8e7f28df196d8c517f9d71a58f1d945e03fc25426e13612ef4158c17590922cd6a8de677398690a8a1816c6a01b162fe6e5f0f502314c542fb568f12ca86f5ca6da7b36255451360ca352c05d10c293a8a35417991efe965ba6f5bb845be9e8c021b2b4af2ae50200c60b7ba42fb5d3147615339fd71343662090f2e7fad4cd0ac0ed49c3fc8685116a8d51d4183ccc9f39b401d47cde7ef7eea63fc218c96edef7190a2529126633a7f3eee421478d66ce367fdfda6a9a60aca3b288c6462bdff20dbf78a3dd29e73d1a3e8f3fd824a3616722ee0b87a9e393ca89159ea8169dca108f8e2feb35c9372ec3b9112e534edf733397b7585051257a564b844c07db5dcf56403e59eab6f56759d50c47779dd900849c94dcdaac1af51048098bf95a0b9eda23df0520a3dbd86a0b59cee20822efdb9dba6d272a7cd5cc95498e340062539"
+            },
+            Test {
+                input: "3875b9240cf3e0a8b59c658540f26a701cf188496e2c2174788b126fd29402d6a75453ba0635284d08835f40051a2a9683dc92afb9383719191231170379ba6f4adc816fecbb0f9c446b785bf520796841e58878b73c58d3ebb097ce4761fdeabe15de2f319dfbaf1742cdeb389559c788131a6793e193856661376c81ce9568da19aa6925b47ffd77a43c7a0e758c37d69254909ff0fbd415ef8eb937bcd49f91468b49974c07dc819abd67395db0e05874ff83dddab895344abd0e7111b2df9e58d76d85ad98106b36295826be04d435615595605e4b4bb824b33c4afeb5e7bb0d19f909",
+                output_str: "9576636b4f4d13a576b2dd4fbb3092f358e7cce04cdda4f83a10a8b5d35b5ee034543098d9a063fac9cd26ca46837c5cb6e96f7596d4f07ea6fdd8af8b59f9e86611f1514d5dc0b7a4216c69b9c85366059bed3ea5ced38a16e4d6945c7c9539e062de51fa2dee1c666db1916369fa6bc0d7a2811ed1beeab61397b8a9faf224fb4acd7f8d9c7a8513c8a93d924fb4ee027821ab6de0415af9bac5cf3d5cb7075be5a6d410f12a9bbc96bf3ff254812c48423f383e4d74ffb5edd7ad34c6e0d64bbe7f45288a49f5de9ac14f317bd4862e1f25e338a0309739c8ddd27839b8ab3b04b9fbce65ceaab460dab0b969222250fcaad072c445d472bf251c4911c7d5d2b7d41c9d2840826e0ba6786309db6e8ec0fd94031e2ddfbb0d880cb780772a93c0b4c32377c3c8ce97c73412f5c3e1cc72aebc050737495c703459b9231c05477cd9a5df1662f5fc883a91b42ed7adabe6cb1ee654fe9e616b40ce9035cd3b91a05e050cb2558645a0939c536a2ef3b5c8353729c3ee238c5c88db75c05db6b2febe0a598f937ca7ad4faf495a10cb3c3b9e754a570bfa5e723b8c0cc107f0edff76ce07a2cf3acec4bb44e11c633bdbf89e5501d6001206d457962aa2f57c9c2f3fcdd1b76ace292728f21a6addad4551970b1532bd3e46d9a5160b1a55cf4be18fa15adf0db055bbb21abd9a5b0fbc474ced2b8787732fcbbb231475f29f"
+            },
+            Test {
+                input: "747cc1a59fefba94a9c75ba866c30dc5c1cb0c0f8e9361d98484956dd5d1a40f6184afbe3dac9f76028d1caeccfbf69199c6ce2b4c092a3f4d2a56fe5a33a00757f4d7dee5dfb0524311a97ae0668a47971b95766e2f6dd48c3f57841f91f04a00ad5ea70f2d479a2620dc5cd78eaab3a3b011719b7e78d19ddf70d9423798af77517ebc55392fcd01fc600d8d466b9e7a7a85bf33f9cc5419e9bd874ddfd60981150ddaf8d7febaa4374f0872a5628d318000311e2f5655365ad4d407c20e5c04df17a222e7deec79c5ab1116d8572f91cd06e1ccc7ced53736fc867fd49ecebe6bf8082e8a",
+                output_str: "68618f4b2868634d8ffd3483fa4aa9c200b43fe87d59107bac648665613805242b1cbb4db2761d4cbea5337e5e07005b5b4e8c80038019ddec76395ba981d36823522698c98b80d313a7b6110a0bde7ed5e9268fa655b8dcc2c762510ff03506dc1ca8769b372f07d0e325786fb1c58206578e600e9093aa84468f01a2df258e670959966b419ba5d4b6063c997822e073717565c6f9b4777e186a0bd6d72f65bb3cca7e82601f25667fa0186208f7988611a76bc4d116ab3944d6797828fc5fcf17adfa99d959f5013fb2516a2d3dc05508e9c28ab5f9e0770d0db2fbf9cd3c8ab90f255b465a9b724d90c25e1eef81b839a971dd84c4d610e00ed858c78b2fc6147cb6b1266adfac5fecda9a6f78b31ae35be6369c3e8290e6f297b7fdb35bbd59f0bfe16146cf3a5a75297ffd5d02685c39ed9394adfd3c7c814ae86eb652d152b7ae980b328f3e16f883c7c6df6672ea1ea6e08c61505e65852a1be11decb86d8386079e17e72ef8fa38b69ec192c0b90622150a5c43584c3159cf61189138089653ae6453d24f464d96a9bd0cfdef7c1c9d92d46e854d644982bdbf0e5be7c38edf469ad3c0ebae549322bf271590e38ae16a1fabda49ad6bf8b1218fd9072c25027ab31787b9f38529156113a82a8dd27bd22cfa719b3ab0d31297a0de9af901a443057d34cdc11747d6576b7602d7d6df58c292a69b4549ecb1518a02"
+            },
+            Test {
+                input: "57af971fccaec97435dc2ec9ef0429bcedc6b647729ea168858a6e49ac1071e706f4a5a645ca14e8c7746d65511620682c906c8b86ec901f3dded4167b3f00b06cbfac6aee3728051b3e5ff10b4f9ed8bd0b8da94303c833755b3ca3aeddf0b54bc8d6632138b5d25bab03d17b3458a9d782108006f5bb7de75b5c0ba854b423d8bb801e701e99dc4feaad59bc1c7112453b04d33ea3635639fb802c73c2b71d58a56bbd671b18fe34ed2e3dca38827d63fdb1d4fb3285405004b2b3e26081a8ff08cd6d2b08f8e7b7e90a2ab1ed7a41b1d0128522c2f8bff56a7fe67969422ce839a9d4608f03",
+                output_str: "9a3cda57019548e6a68d89cdebdf96557daacac29c5ef8532dca123231d0226d0d7f62042d70bc225cbb1ed8902d8e6be75b2b37504990471fd01f4c656e6f6b77961c753a780d91fe03598fa2d5f60b772b34918db836d2cd278fb41b223a6d1f25c91a4b98b64ba3eb32dfa5dc5e1cc5ba1467f287d56ce98478beee91087daca1e2fe0adca38883c9a73699ac98aadb5c4b087719eba775b0abb1b0e5acb4f79f0f75dcb2e7e25ca22c06b1629ec1ca989ad1f1f12c4580e43da76b2b58345b61085553a827ba0d3954b0befca8394b9d19022d33df6978148234cd16c7491075517081261e9af8fe42c66a7580132ea3307af3372489d8efe01c5ae579a92399b844266d13804b887538d70d2a4eae3c65e09f6bf877113992c42d490456cec22ff8c60b0c7d2517a49d2822cb2b2ab6bef74f87ce134f78141157d0498f267c94123e1606d4ce1ae8d7847cf9fb23d8a11901292cf36fb975fdf34aa0ce10b851e116ee7129b06d3ef10cc1aba6f761ee2f1e4b497da11fca3e844a8dd1a6129db5b3f863378d3488ce7e208241946bac2e4aafc912cc46e5a6451832a2a43176e06dbd49e9d379a69e6f08081f609b7207c5cd391445e10d10ff2b99e0d672c19cbd9f5ffc6ca46ad9536973368a747a7a2f23aade81a43e49d2e9cced3f64ca24c012cf3a306c40ecf36843317be8d29803a40f6f71e7e9229154b0c4"
+            },
+            Test {
+                input: "04e16dedc1227902baaf332d3d08923601bdd64f573faa1bb7201918cfe16b1e10151dae875da0c0d63c59c3dd050c4c6a874011b018421afc4623ab0381831b2da2a8ba42c96e4f70864ac44e106f94311051e74c77c1291bf5db9539e69567bf6a11cf6932bbbad33f8946bf5814c066d851633d1a513510039b349939bfd42b858c21827c8ff05f1d09b1b0765dc78a135b5ca4dfba0801bcaddfa175623c8b647eacfb4444b85a44f73890607d06d507a4f8393658788669f6ef4deb58d08c50ca0756d5e2f49d1a7ad73e0f0b3d3b5f090acf622b1878c59133e4a848e05153592ea81c6fbf",
+                output_str: "2dec1b61a2977a54ff13cefc08f9ec6f11be80e7f5b77c4ccf2692450ce86c9d57ea58cb34ab2995a6193935dde84bfd62283a881cedbf685ca26a8a727252223cd6e7bb8a3c7751b8721ed16d1209611803778df77c6a005e1a05aab97f6205e0c1c6b339f8d8346a84c6a6d86efeb17b6f8c8e30960dadba3dddb860f46d2718c7307c55b65aef1082b98e407f56b633a16578528b8211254fa6af384af0ee36ba49638386494e347e961d6d65ccdf2d5d221ac54f6a2f6c4eab62b7b55e26192a2e223bb053558a6c3646355f3686dd1d3712406677f183e94cf822d0afa9416815c14bab7f5c5b4e44f364446e08464370e60a436653b2dd29e60562712136940df4ae19617774776f0784f7e8ac600bcf8359e02b070c0480f372dfd69df9c33ecd3484678087087c7dad64e160b32a0372318aff1668f5a0b03c940c384239994f546fee94e3ed0fb8ac259002d09c3110806ffb56419cbdc76f28c8f828db0aec39a573a903a49c0c9f77f0504b9c8cbeca83b6d3a7af24631f7e4b99e9b42ee201cda0ac1ffb79ac24f3516d766b0f71e1efef8e6cbe38c24d86b83388d6d3c2f9bd6af94b8a56b6b5cd53af40837fecc5481f9af1fe216852c281e068f0891908b583845b58a4cb4169a0f2aab2c36fd184b15c3e4008e38e00c0b6db256b89c4c373e8328d13e840d65605c44ae017b0876cb5abe1ac4d9ca14a3b"
+            },
+            Test {
+                input: "7c815c384eee0f288ece27cced52a01603127b079c007378bc5d1e6c5e9e6d1c735723acbbd5801ac49854b2b569d4472d33f40bbb8882956245c366dc3582d71696a97a4e19557e41e54dee482a14229005f93afd2c4a7d8614d10a97a9dfa07f7cd946fa45263063ddd29db8f9e34db60daa32684f0072ea2a9426ecebfa5239fb67f29c18cbaa2af6ed4bf4283936823ac1790164fec5457a9cba7c767ca59392d94cab7448f50eb34e9a93a80027471ce59736f099c886dea1ab4cba4d89f5fc7ae2f21ccd27f611eca4626b2d08dc22382e92c1efb2f6afdc8fdc3d2172604f5035c46b8197d3",
+                output_str: "dc2038c613a5f836bd3d7a4881b5b3bff3023da72d253e1b520bcad5162e181685662d40252bee982eb3214aa70ddf0a95c5d1031de9781266b1e0972fc9777d4a74164da68a5d4585f7a8e7438fe28d8af577306b8e2cbf6863c83431cc4c898dda50c94efd4925432fca36a6304790fbf4fefaeee279c01b8b6a8d1c275e3cb4e8bf17d880903fbaf27bfa65a2e3db8e285878a94955f6fc14f05a0fa2556994b8612bb7a494b4dd8b3cf1bc9e4bf833d4bfbf878c4d3bdc8fc70d26d7b7edaf0afe2f963dc6884c871c1475f4b92378b9824970e40da0a59780e84ac5138aa1efa46c1b50c3b045be59037c6a0c89e1d3cf246f1362794e8107b7cba74888f0bf4b905cfb9c33517f472bac16259809797f2fc883ffbdd7cede9518f891b9117de5ddc6d3e29fa56eb617f25e9eb1b66f7e46ed54c1d43ac07471d35c57b8c73bc68f5612ed042bff5e68634a4fb81e2ef0d92fff1e11e43fd6d9a935678d2fdd04e06061da3ba7de415b93c5a8db1653cf08de1866f5c3d33be32a3b8d2b7bb39e9745c6e88c782f220c367f945828b9b9250de71e8a14ec847bbeec2b1a486ce61731cef21b4a3a6353c2c705759fafa50ad33fb6abc23b45f28ee7736df6f59aaf38d59881547274cf9af2cfc8fc1ecadf81ab72e38abccd281df956f279bacc1796ad1f90d6930a5829bb95e94a8682a51a6743ae91b6c12c08e1465a"
+            },
+            Test {
+                input: "e29d505158dbdd937d9e3d2145658ee6f5992a2fc790f4f608d9cdb44a091d5b94b88e81fac4fdf5c49442f13b911c55886469629551189eaff62488f1a479b7db11a1560e198ddccccf50159093425ff7f1cb8d1d1246d0978764087d6bac257026b090efae8cec5f22b6f21c59ace1ac7386f5b8837ca6a12b6fbf5534dd0560ef05ca78104d3b943ddb220feaec89aa5e692a00f822a2ab9a2fe60350d75e7be16ff2526dc643872502d01f42f188abed0a6e9a6f5fd0d1ce7d5755c9ffa66b0af0b20bd806f08e06156690d81ac811778ca3dac2c249b96002017fce93e507e3b953acf99964b847",
+                output_str: "91ecb5133525e291736cf8f4793bdb00a4ea32f48c3f24cbd3238e6408fedfa6e7a750409f197041001c1a090659f8879cb26912b46a0e7e4e791fbf5692fd36ec84a55462b7876724ea944ce7246261f26038b166668e6b7eab0b5119b44e4581f3a3280508cd8b3789ac37f992eb9777b9e11c0f19a3da5f4b8d304ac4de68b3c2cd6659f33fbe20b47e1f6b0ce06ec0963f8e7412fcd84e3da3867cff08f82aa17c43c19bdf3bc0d242fda4874ddec389564345ad11a267d7a466925d1e9beec667b029da0982b37b51413b4601cac17a02cbc681f927defaeddb0f6a69fdfc39ab735470e86a00f82eadc94018a6e2a29e7f393f30d954c82936e158a364fb139ff29e42f30c0b95bd5714eb7a535a5b1d1b3b36a862e35d10d1f8a5afbeedecc51a855724271da9ffb8efc6615c42b03a57a2d762b46d5d94e097dafe5d7a2ef522ddf2ddadc1f83eadb72510e770735463495b0217b8bc91db597683254f6e0ac0e9b1e56ed0216ec9618173b163cb3f393152469268c056b1a204567ebe7367f863ba145c3bb367fa3c01e556d62fbc8381cb3c8a9bed907d481c093f14b70d1bd31aaa41fa753ce31fc59740a47bf5980f8a0e32eaca8a488572a3a91db07a25c34330cb7da7e0fb7d1541c3f3c377963de4560a8d584e11e9c6a1b917f907c34f211cd78904471199fcf30d4180f88e7bddc0392197444adb1968d2"
+            },
+            Test {
+                input: "d85588696f576e65eca0155f395f0cfacd83f36a99111ed5768df2d116d2121e32357ba4f54ede927f189f297d3a97fad4e9a0f5b41d8d89dd7fe20156799c2b7b6bf9c957ba0d6763f5c3bc5129747bbb53652b49290cff1c87e2cdf2c4b95d8aaee09bc8fbfa6883e62d237885810491bfc101f1d8c636e3d0ede838ad05c207a3df4fad76452979eb99f29afaecedd1c63b8d36cf378454a1bb67a741c77ac6b6b3f95f4f02b64dabc15438613ea49750df42ee90101f115aa9abb9ff64324dde9dabbb01054e1bd6b4bcdc7930a44c2300d87ca78c06924d0323ad7887e46c90e8c4d100acd9eed21e",
+                output_str: "54a3c3f41ffa1a12309ccc1d6b7915e126cb13371a2953f33d6512241a5b835005a7fc8844e4e5bc097b9c5d8e388ddb5a55f43905e11c380b8ef1dc661b77593dbfafb6b2a4a28039abf57706ed1193e860cec1f5d9c522839607a02f3ae0d057100cddfe48bd84f60db063aa3011ef8a6aad3947d8f86e2a6a28e258a99d72e998e4148dc877945844094125db2be06b98508704e3901ad2d8d2cadb19291af8436dc4cd89d97060df9f7ce0738ed5c1456cfef18862dabe84a08a22bf310fe273496401619f156ede9311697566b11c38bb10d4ac5787d4d6491cb43b4d79c5f062645facdd48edf609737c7ffc226e36587b39759f23da6cf94349cfa50b9e18f1c6cd42dd22ea04a4a7a73acce723e4e5948fccc9857eebf22c9761ab8aff73386d470a34254750bce7edc88a46f54ab64f562bea863488f846671503e5e305f3cc61212e95d055851a4d4a9a145df52dfba84d27d084952f7e12af3c4e20860a479156b48cd65ab2bee5407aa200ce205e3e46c35dc4b50205c11187ec81eca5be3b2e90a170d53e6637947470220b2a6edba8c0d0e3525be456417e6ea0fd98bf54a5804aab6bfb728b22a5d01baf0cec173821f5e075a0e4b7649e303d17296981efb88327d5b1a3a8ca72129b979dfbcfdc45ec3d1bfd01d10814f225c6bf09962f0491756cf9607d3974c24fda6ddf6e87013ec5cb2b883bd0a50d"
+            },
+            Test {
+                input: "3a12f8508b40c32c74492b66323375dcfe49184c78f73179f3314b79e63376b8ac683f5a51f1534bd729b02b04d002f55cbd8e8fc9b5ec1ea6bbe6a0d0e7431518e6ba45d124035f9d3dce0a8bb7bf1430a9f657e0b4ea9f20eb20c786a58181a1e20a96f1628f8728a13bdf7a4b4b32fc8aa7054cc4881ae7fa19afa65c6c3ee1b3ade3192af42054a8a911b8ec1826865d46d93f1e7c5e2b7813c92a506e53886f3d4701bb93d2a681ad109c845904bb861af8af0646b6e399b38b614051d34f6842563a0f37ec00cb3d865fc5d746c4987de2a65071100883a2a9c7a2bfe1e2dd603d9ea24dc7c5fd06be",
+                output_str: "264a7d71ba8e67773ac5ab0ce3616f1147341edeeba1a177e8529b0def09c3a99d91029d77c3f9f85508ae74de172f358cdd2bc4efc8b27bf280e162b03a08272d0165d9012099b8ec0274801af9a0d672fda4510c09347add664505be434469ce78df597a7890381fbeebcee79fde94ee240a2b3dfd60b23f4126a5fc397b4b4e5e21893cafbabec64bf53f603434f168fcb667828e79f44b1526e9875f9ec9982648b9c6fc1ad6527d7fd2aad064227d9a85ef9733b2b484202e00f8929e18899bfa6b92c3aa8b05f9ead25df02e02c7e8c264b67ec07ab47a7d95905f660cc6722aca28215aee543fb7950f0204784aff77374b803e5ea679f22a0f5659a363ee122aa76bdc881eb28d5e347842b2cc81ff0447b68989e744e187808d7af0011a32b66f9050161168d6f246a5c7b212838b831e71d71606f21a40d8a9aef42b21465689b7ce967dc2e53f869f0584e19ddc629068c1acd7e6b986c3d1f1e24b1a907f7ed4e5b83eb7b0a5c6a4508e0dc21be2c1bb5506bb2b97d9721b57deb9d4d39d58b77dfe6c869f5fbfd74559082b5efc3692e72a9b961b6a669ed700cc41ffeaf370f88373d5bda8db6dd2c3bcbf1d833f4b9cbd3b4134502931178c58fcffa80cb496fd850352634f73d002fc4a6725848ce2541862b3c5566a915878e60b3b4c1ef7f014f0f32446298891a383f63568c849df2a208e75eae37ed8"
+            },
+            Test {
+                input: "1861edce46fa5ad17e1ff1deae084dec580f97d0a67885dfe834b9dfac1ae076742ce9e267512ca51f6df5a455af0c5fd6abf94acea103a3370c354485a7846fb84f3ac7c2904b5b2fbf227002ce512133bb7e1c4e50057bfd1e44db33c7cdb969a99e284b184f50a14b068a1fc5009d9b298dbe92239572a7627aac02abe8f3e3b473417f36d4d2505d16b7577f4526c9d94a270a2dfe450d06da8f6fa956879a0a55cfe99e742ea555ea477ba3e9b44ccd508c375423611af92e55345dc215779b2d5119eba49c71d49b9fe3f1569fa24e5ca3e332d042422a8b8158d3ec66a80012976f31ffdf305f0c9c5e",
+                output_str: "c87cc74fe777b2dc9a33473f88383dfece2244a807ff92babeb7bf08f37eabd9305be93213a63a4851bcdc648c2eb31bd509844a56b7b890772e040e67d32a4098efbccd0ed6d25b2ab9eefd0b65ebb76d540d0fecec277ac98139ae8f67025dec7ae76850e047098557d2ef7d9319bc153641b1d2a376f23e4a1f2fdf1168eb5901b3e11a0410c8563dc4bf1fb0f616cfeab2b086384207cf1a10d51634874493db0533787c0564c1400bc56cdb7c32a6fa4800f0e685156f2bb63a63b67f6d40ab574ce0ec54a4a533958b3a48266ee038e5d85e67f3ba429ea1671d89a083b406a568a0795c56ef042881ab67665258ededb97ad04b5a30388d7ef0dea494ba645f8fe47e81a2cc4a9c6885ed80c6f6d37bb0e81a60575201c0ec3e9ff30f70ae746b86aa3efb309f13fad5ca2c824c2fcd34af1dea5e60e4a8cd92e7b653301721937e03ecc2ad5642a3922d4d666448759961c6d830ccb45d666b675c920ac2486b100b5a51a7659f24735c173f9fdf02b1401a03ed5bc45ef098e799e7a3c29eb262d408ca9a6d2c18c5636f3b378e63f8c71c70058976e880d8a0f23e0f2f1cae00f4e06fd60673cf0968a2e3c5d97a79659bc81f6639fe69b18c6e4d1f3bf535814a4d6187f3f9bd7f7509b2eb899a6ed48526c665b706a526f0e5ee433dcb3b5c7bfc99078342b78edca9502d6f73566bab6afeaf63ec9a020a7ef5"
+            },
+            Test {
+                input: "08d0ffde3a6e4ef65608ea672e4830c12943d7187ccff08f4941cfc13e545f3b9c7ad5eebbe2b01642b486caf855c2c73f58c1e4e3391da8e2d63d96e15fd84953ae5c231911b00ad6050cd7aafdaac9b0f663ae6aab45519d0f5391a541707d479034e73a6ad805ae3598096af078f1393301493d663dd71f83869ca27ba508b7e91e81e128c1716dc3acfe3084b2201e04cf8006617eecf1b640474a5d45cfde9f4d3ef92d6d055b909892194d8a8218db6d8203a84261d200d71473d7488f3427416b6896c137d455f231071cacbc86e0415ab88aec841d96b7b8af41e05bb461a40645bf176601f1e760de5f",
+                output_str: "61390f3d091cfa220147b1c85c59f1d6b7d9f87db3a8910884aedd2db4ef65bd77f1d091d8375002713322f3ac618126d47dc4ea0404402fffe139c8163cf8746030b2e57bb2a74965159f4484e3a4c41e7f849bfe872db3b47eb91e4c9e67dc09ab0fb88fde8a9815baadca11238b97df04a0f5e5570ddc87d18e6e33339dd481d20cb746478162cd1464929dce1fb906b6545d846d891ce91358b9ea029f281ecdc557cb769ec8c1faaad10ffe13b8076072455bde3a3276ca458e8ffc4e377aca54833c31e906866e9dec7eaeaf74ae07339d70ad34278b076ca541cef4dd10f68fb29c17f030052702b7b87d857f462414bfcb9fba427beef0b930df09c7a6bb35620ef843c9866e242eb2b30e30c4427c1e5671f2390f6f9f42b77305cb9969224355fb7a751e2066fb8c492d6070049c768b5263642802d21632dcf50edc2c9357a4a3ca20c8446cd322cb5d8edf82d31871424575f022d8b7a6b7baa4f6326ce757ad523b8bd1b4a77c5d96e7eef9e2963b02b107f7f74c9341d964d70daa7c9e1ecbcc354935ee07192f22c15d693e5e10df094fa8b74cb2cc87b967f11237b3ab5d3f53eee9bb9e4ca16b7df02e46ea9f141dcda939b2d7c964574a0e11e3505706c0e9fe33be262a7e6589d7bd42276cc3146f0a728131e9d346b91da1eeb6b3e34ea5ae180396e219b5ffb6f87148ed8d4bac21e760861b49f248"
+            },
+            Test {
+                input: "d782abb72a5be3392757be02d3e45be6e2099d6f000d042c8a543f50ed6ebc055a7f133b0dd8e9bc348536edcaae2e12ec18e8837df7a1b3c87ec46d50c241dee820fd586197552dc20beea50f445a07a38f1768a39e2b2ff05dddedf751f1def612d2e4d810daa3a0cc904516f9a43af660315385178a529e51f8aae141808c8bc5d7b60cac26bb984ac1890d0436ef780426c547e94a7b08f01acbfc4a3825eae04f520a9016f2fb8bf5165ed12736fc71e36a49a73614739eaa3ec834069b1b40f1350c2b3ab885c02c640b9f7686ed5f99527e41cfcd796fe4c256c9173186c226169ff257954ebda81c0e5f99",
+                output_str: "39ec35d31923584fbd73a715015cef05b945a5afd2d109e72e356bdbe0f73cdf666aa7b01e77bd3bc0c409991f1129961f6bdd772ade7ea97af0b88a8875190b453664ffb64fc4fac3c1108a3c222f23b12b7613941b137449471ba4847eaa4a16beb50960fff5dfbb2e756938b38a93509bce5f900a59e69fb0305a19e460ffae88d74a727c82fc7138b88db07edb172b39566dd22f0e852f715af9d3c3f0089e9eba72ff6063357de9a744f20e1da367f27c6ab6fc9d231a606a79a621f8150773d1dfd52868820ee5bc28d286ed746beaf8f13213548df0a56bb0e01e5bf6bdd1c901ea8c791e7916e5679c88d4d85cb1acca63c211e7218fe6eb2abfd2badbb31147177f123fd111bac4880f1224ed01f3259e4eb91deb7562cb9c3009b3676998afab8d5d24bfe7d27be7f3a57a932c895b60a9fa74504472808479f332fd9915b8ed0c11604e80457c0de5f7015c19a607aafde448fc08bb185517e6ad7dd330a465f9043a0478e1cb4be9185187604f30a1680c67d3a0db1baccc05d401aaa8fc66d9189089eb7ddbaba05faa8dd83fa544fde68a793a36d854752f22fa13333c6152f7f18ed789848a13327071d85d5e36c4fc291cf5b4b9391f8e2513d4b660b1290790ab50d12b73fca21a93f8998d5706c037c387d662fc20be35228d85e5bd007a7173bd06e5cbb7e41063ae4843bf3f5a77c44e1a36fd2e1c31"
+            },
+            Test {
+                input: "5fce8109a358570e40983e1184e541833bb9091e280f258cfb144387b05d190e431cb19baa67273ba0c58abe91308e1844dcd0b3678baa42f335f2fa05267a0240b3c718a5942b3b3e3bfa98a55c25a1466e8d7a603722cb2bbf03afa54cd769a99f310735ee5a05dae2c22d397bd95635f58c48a67f90e1b73aafcd3f82117f0166657838691005b18da6f341d6e90fc1cdb352b30fae45d348294e501b63252de14740f2b85ae5299ddec3172de8b6d0ba219a20a23bb5e10ff434d39db3f583305e9f5c039d98569e377b75a70ab837d1df269b8a4b566f40bb91b577455fd3c356c914fa06b9a7ce24c7317a172d",
+                output_str: "9bcbaf72085f4ee5b2b237f520977c7cfe8780bd62b0aba13c161d0e7eb036ab27e9b08407bd501b2482c280997eae9c4b571ed6e39a13d74d7a1e2258cbf3583b28e738fb14ab2b60e6f1e188953d96a9361d282b85ddc243fe6c7cc644ba203b328fbc4e0088e40283b6a62122065a11a164dd1ea05f421b4ed60f44ec982636f0253ae4e6ea320eda2351dfde0285d1ed860a51699e702a0519b0c3119462bc9cb3decd66647823ee139dbfe3ee125a6f74aedf5044238389e0b0388698fd8d7d882d010c194f4478d6da8fc195529a475932e4fb178cf318ad8f24427bbb90c0b08adab27be5a48c9804acd9e56e1cb2bfeb236388917458408c446c6b5f1d3bd55ac0f6f1ad06ab419460f525b564dc67bc6bb2cfd08cdb510161f71a29aec95c67323259c214cc39401e483e982ee6576a7f1068b088348916a5c47d1378236ddf475733f394e14216d2ac112457295100eb70381e632876e700d355973944ed80ab91ac39f2d9df4e338c02082505c028eddf867e60aceffba59480e6953baea105652bac6d29def70962b6bb93e3d9424a77d31d3020fbb3be37e7905a6360c1b624327fd68ed02639a2b54fbafdd9804fcfd60aec2b044c921a77b25b7032cf685475f503d00d9a8db733cb6115c1bad1c847c1bbbd342e62470d6df7c21119a35179ad3c7f68cd246b8f3f51e2635dac460db83fcc5c0dd049a2b7"
+            },
+            Test {
+                input: "6172f1971a6e1e4e6170afbad95d5fec99bf69b24b674bc17dd78011615e502de6f56b86b1a71d3f4348087218ac7b7d09302993be272e4a591968aef18a1262d665610d1070ee91cc8da36e1f841a69a7a682c580e836941d21d909a3afc1f0b963e1ca5ab193e124a1a53df1c587470e5881fb54dae1b0d840f0c8f9d1b04c645ba1041c7d8dbf22030a623aa15638b3d99a2c400ff76f3252079af88d2b37f35ee66c1ad7801a28d3d388ac450b97d5f0f79e4541755356b3b1a5696b023f39ab7ab5f28df4202936bc97393b93bc915cb159ea1bd7a0a414cb4b7a1ac3af68f50d79f0c9c7314e750f7d02faa58bfa",
+                output_str: "8536a6c25934a44ff97c0a09e026eb12b9c81cc8357859ba736b29bb329b182b5da8ffd7b855200cb9d64fe463317c213997ebdf1810bf37e00d56f75791375c5fa84dcfa37ec196bb2dd3c66c1d33034ac48bc7feaf15f9702d7d11e4712ac87934e2064283d04b56bddbfb3b56c3cde69b7d736196b9dc5623a3132be33af12a386a3004eef98d4487b614547ba59edabb0b83b6ca39a5955f925f35a5209c0cd567369751312a6a63d0f4821d442c14cc26fc147e63a4656745663cd96b01064f60faa4ba98258b09c09833046412221a59e23d5266fad8c068cc949d172862ec30ebddea21e1cfdd6b5fe4af566a19d0d41fc9328ea915d8b97cb1d903bc40a4083f6997439055b44a695450039cc00931cf3bc9fc67bc417a8aa270b2b4a410bce4a2131523749a957d293c1438a993432941a9ff4210b33a5cf8b4434553b17cfe869b940669ca9f18b128ba354855f08a692fc6d23bf0fa12d9f4df0a571e44d4221e8018c4282559e6ff2eb02ccac7a7b83e34aca7d554c33f05cbaeec49d0516b10de06bcdedc09d0c4a9810b0797b62cffa75fc0d3bdd796327bb1fa5dcb546630e9bb0457d024e982d6d7930391066c58286beac627d6eca09b4f6dfccc71ce589b1da1e890ae0c5a0cf531d9c1d2330bc8397f09f248f9919995326fb92147959c3e6c569ed662f6968f4e9ef42b6c2fb954d79da22117373e27"
+            },
+            Test {
+                input: "5668ecd99dfbe215c4118398ac9c9eaf1a1433fab4ccdd3968064752b625ea944731f75d48a27d047d67547f14dd0ffaa55fa5e29f7af0d161d85eafc4f2029b717c918eab9d304543290bdba7158b68020c0ba4e079bc95b5bc0fc044a992b94b4ccd3bd66d0eabb5dbbab904d62e00752c4e3b0091d773bcf4c14b4377da3efff824b1cb2fa01b32d1e46c909e626ed2dae920f4c7dbeb635bc754facbd8d49beba3f23c1c41ccbfcd0ee0c114e69737f5597c0bf1d859f0c767e18002ae8e39c26261ffde2920d3d0baf0e906138696cfe5b7e32b600f45df3aaa39932f3a7df95b60fa8712a2271fcaf3911ce7b511b1",
+                output_str: "7201fc2af67d095a5e317269e750f965b8bec311edad18da2435d2872c0056617f0fccc80552010f996e5b34084b09f31f35870486a8c53d220d7d009ffc2c58f26ac41bae05eb486ed4a18e74fd1c31cea640e8d47d88c5d506c5719a3eaa4716ad4fb906a5085afd46570f2b048264d4bd3554f5ab0a8271d6529b9e2f1634b5c78abab6bbacf4f01a4e33377f9e1fb12fc20435de0afd62f90e2ca73bd5260285bf5cb9b4302a312bbe48c3b68a4da6e842b7d87b3be0ba82c9b7953cb63b7e7e86296b88557bee2ec9576a468d556b77f872bf728fe3051e4932988029d88320088b70c8b19b59fc03f2f32bf34f42746a6e9672c21ea85087a46d5bae484f460af64f8f62bc615e79adf67efa9941deb5b358a5833cce4a92da0f237a506d530d64435689e1db79f7afda051cfc065397c9393b3a87d6de9c08522bebaef1b33d2eaa746a5ae7fad267f168ece1db4bdf453a100fa3743d9dca3bd0c00dd7033ae1eb573bb79c6cf53bb38130af279c0a0f8198c5145a5dfa32b322716ef6115bb5466ce54eef73e68c4c2b1d0c321a03b6c7bd1be98dfcb50c08df2005dad35c430004de8e6c531368b5f37e53df3d376caaf854298657573be7038052c2169bc907341ceb02925385a9fc03400f53cccd6d3bc039bc49f7e5cadbb68fd5e1589cf1b97c9c6360a4dde6474ff39b96cc2f4c698300db2ad5668bc19f45"
+            },
+            Test {
+                input: "03d625488354df30e3f875a68edfcf340e8366a8e1ab67f9d5c5486a96829dfac0578289082b2a62117e1cf418b43b90e0adc881fc6ae8105c888e9ecd21aea1c9ae1a4038dfd17378fed71d02ae492087d7cdcd98f746855227967cb1ab4714261ee3bead3f4db118329d3ebef4bc48a875c19ba763966da0ebea800e01b2f50b00e9dd4caca6dcb314d00184ef71ea2391d760c950710db4a70f9212ffc54861f9dc752ce18867b8ad0c48df8466ef7231e7ac567f0eb55099e622ebb86cb237520190a61c66ad34f1f4e289cb3282ae3eaac6152ed24d2c92bae5a7658252a53c49b7b02dfe54fdb2e90074b6cf310ac661",
+                output_str: "c7b0ea1011bbe2d11df8353d06a6ad5176dac3e33039c621a635e1124edf2425ad88ba552d6b6034ae3a5fbdc735e4381064925bfd6cb5e3e753d27c7a77f4bfd3d33652461f5409ca29c060ac991f3ca90a29b9f67502a524795f1306430fe7961430b431e9cb7c21eabe1ec3d1d6440eea64496f30a3a44172b2c5670da2f4dea42f783f5138c966a642488231dca509c144b59e0f4a40c191c035e4a464abb6f4b9e0f9acd86b7bda0485238a56b2934c7aacb484287ee013c46e48fb648e73add7e8eca6b2a8fc34ea0ceb46b0c360a6004b34403ae5fd345a78b55634b242cbe07a6fb13fab721ef976b3e1f82ff4db06f86dca50348398f1dc831c70618fb387f0b13d84bc8a606e72d6b85991a4d7151e2d9b4b5e07d303e2d639d2a243e316b6c328eb01f52c524fa7d76763ede5f0fec6824d73efe546547798d9c78b22765e69ee0f72b538c816b230481214099acf758193aae0688cb5a9e11b323704ab7724e5f1c4355c11eeb595312a25277794b996c6bc19c77f0a048cd31fc8ab70c7b6b6b0dfef5f632879dccfcf462908f04afc8b440e9c4fbeb428b70a56511eb7b16053be225b72cee491366742a77152a9bb0fac5d261c01abea1b632289f26fcd628598c1f9b6ab1a5c36f926a2b96baf71644c0723a6a773dd14c66a770f11bd82ea85c6608c821139601f9b98232bfc21c7a3b54e0f7a2a6e4ce5"
+            },
+            Test {
+                input: "2edc282ffb90b97118dd03aaa03b145f363905e3cbd2d50ecd692b37bf000185c651d3e9726c690d3773ec1e48510e42b17742b0b0377e7de6b8f55e00a8a4db4740cee6db0830529dd19617501dc1e9359aa3bcf147e0a76b3ab70c4984c13e339e6806bb35e683af8527093670859f3d8a0fc7d493bcba6bb12b5f65e71e705ca5d6c948d66ed3d730b26db395b3447737c26fad089aa0ad0e306cb28bf0acf106f89af3745f0ec72d534968cca543cd2ca50c94b1456743254e358c1317c07a07bf2b0eca438a709367fafc89a57239028fc5fecfd53b8ef958ef10ee0608b7f5cb9923ad97058ec067700cc746c127a61ee3",
+                output_str: "fd6abc78d5ff667aee2029f1683e1ec57e82e69e6f3963e38486590650a18eb3a6b611d5ecdd6f8e556d2f8bed3726dc51b2086275923e2bac576625fca0a10ce1cab318ae80806929ec5ef10f3262f460db6d39d6db17fe364792ac2cf5b067f260366fda234ee09761858a3c5edfa7d8c8bb7e968bf78922cad2a276096e06164d15782b74e75abcb32d1d87cc5ba1b188ae777b5fa570dafc393c7fa0ca76623543ba75ff214a0f01ae3455a9c454bb6773721df3376bf92b4c6db9fd4edcd802e30cdd698a865c29912517e0d195b1d05c391be04710121c764df515fd0ecdef0d91603bc2a3b9f905b5d7c25133657fb6798aba7119ffbbb836028764298ec082fd36cbd7d32a81c549b32e6e82c8c897318eeed0c3720ae2b620a40abc87c28613aa2322edd83414b8a532d48fa5769e4e8a46e159d5bf9926c6647836527bf5ab23846ea38f321ee7303a1dafaf61c97d6059b10314f09f3d5dff337802edf70f27e0224d1b110453902d3f4d5a074f2fa532856eae37307507c2e9be3952ebccde1599a3a9b331fe760d29720afd9134b6f5c33cdfa60e9b700e0ff15e13d197830bd93e785482bba5dcecbe0977433ad8625280f0dac5c6a4963f23844c7ee7ac6c88d098b8189b274d49194727118d6e73898584ba8feac1947e0b0acb81dc7b580f06f52a5743f8e7e8066f6c76b5013da694072434508c2802e0"
+            },
+            Test {
+                input: "90b28a6aa1fe533915bcb8e81ed6cacdc10962b7ff82474f845eeb86977600cf70b07ba8e3796141ee340e3fce842a38a50afbe90301a3bdcc591f2e7d9de53e495525560b908c892439990a2ca2679c5539ffdf636777ad9c1cdef809cda9e8dcdb451abb9e9c17efa4379abd24b182bd981cafc792640a183b61694301d04c5b3eaad694a6bd4cc06ef5da8fa23b4fa2a64559c5a68397930079d250c51bcf00e2b16a6c49171433b0aadfd80231276560b80458dd77089b7a1bbcc9e7e4b9f881eacd6c92c4318348a13f4914eb27115a1cfc5d16d7fd94954c3532efaca2cab025103b2d02c6fd71da3a77f417d7932685888a",
+                output_str: "aeda7e54b44c4ec1dc28a305ab30cdc9fbb1bd923f41da60558acc8c3fb34d85ef153decd3090860e383151ebd008044b20b20b0c6216d16ea221addf00b99dfa692ce79e69ac853fd70c6d077860c54ff77ac55962cf0d06888ce0a95dec7ce760e8e0364ae935cc8ce962bafb617dbe45a4669f0f5c6a7767fb0c9bdc853c84cdef5f722da5c31d15181725158f946c8d810af7296ec91f3ec782d38b00563e454ac9299b8da2c4d2fe89c0c2c6e094a14dc3cde4b4b5a868cbe8c6032812ccf17a1e511e7e59c0239e6696c2ce093cbf79f641cf1b59d97b88a16359dae8366e23e13c7b8f9cccc099f9b6cc0a228223fbdd5242139f3be2c19c06a15563e404428052e32ed5f6ebc61afe642340625c29174ed962d6ea5d8d6b06daa63cdbe674ca6abf8aacdf727bcf6279d4ab7b2511d782c21db7ba2543c2273970cc18c136d74d6583782fd44422a2dd01bab97af2a420f8f1de60ac0f4727b91972289943b5dcb3d22030d93a6ed0863e1920dc8a6688dfcfabfc3ecee59afc7b349f5b6b061e599145e2242c05d63566906a40b98f8d280f31d25880d0db0a90af20108715ec9fee5ffe151bba41e594254b7eaf61c5b444094b307511a1799d2e983500fe9643ddc2652b7b77fa27db41b50f788224be4b4f7ded43b56a3bd7eb52620689b4d22859ed3e0771431168d12404b5c56347faffb9e133fc5730ee76a"
+            },
+            Test {
+                input: "2969447d175490f2aa9bb055014dbef2e6854c95f8d60950bfe8c0be8de254c26b2d31b9e4de9c68c9adf49e4ee9b1c2850967f29f5d08738483b417bb96b2a56f0c8aca632b552059c59aac3f61f7b45c966b75f1d9931ff4e596406378cee91aaa726a3a84c33f37e9cdbe626b5745a0b06064a8a8d56e53aaf102d23dd9df0a3fdf7a638509a6761a33fa42fa8ddbd8e16159c93008b53765019c3f0e9f10b144ce2ac57f5d7297f9c9949e4ff68b70d339f87501ce8550b772f32c6da8ad2ce2100a895d8b08fa1eead7c376b407709703c510b50f87e73e43f8e7348f87c3832a547ef2bbe5799abedcf5e1f372ea809233f006",
+                output_str: "9fef3f4fefef93b5124dc0c0d3fcd29fc5d6f680f511c682bd41e397eea9147441e698e4b420cf2a165b15aa36895be8ae914ed53fc9950f16d540ff5054c0d731789d126091a75fc5c7de3c28478e86e05c7a604ce904da8f7ef031dc9d957401b155d110745f3145c34754a45b7fef94d0253de536bfa0ed5e655243e689ff909ded44948a339cd55b897d015bf49e890192d051a13c26bfd5e8e71ae287a6e2c18017fc997bbc41a7d39a18de8b30f5f313d449c5095314e740501e2101807eaf33f596d0ad639c83bf7037e27c1d8597b4bc9f335433137ef4081e381b831f17ab09bc704bf1c581f4edaf9502290a92501cd7a0e5f0aa10674bfc9b2c9c2c812f4c3725d6e7975a1f181ba63349d18efb824dbc4d7d6267e7c4855afb5f4da4b26bf74785ac1e97d3e78de97179739481a47686545a7b81f9d6bca18cc3008be300c34134edcb9c87870d8bb4da18cad8c29ca349392fd82e0bbca5a06a043826194a52ad80e1c3bafa28751338bdac266d8245e055546611cbf929cc8ce6da35667a66ab87ec22cf3b54d8ec1d7cdec5c75e0ec3b53ed0c030ae30913c12aaaa71567c731ac8c9ca1279c7a8facca20554a506661630f2b6b9792dbf5c8fd545c283dfc65e9d758b4b86079f569af818138304e617d74081d80ccff0179542f6fff41151b85f84b2dd18fcd8c2b7790b645552c94c0348315bd91e1bea"
+            },
+            Test {
+                input: "721645633a44a2c78b19024eaecf58575ab23c27190833c26875dc0f0d50b46aea9c343d82ea7d5b3e50ec700545c615daeaea64726a0f05607576dcd396d812b03fb6551c641087856d050b10e6a4d5577b82a98afb89cee8594c9dc19e79feff0382fcfd127f1b803a4b9946f4ac9a4378e1e6e041b1389a53e3450cd32d9d2941b0cbabdb50da8ea2513145164c3ab6bcbd251c448d2d4b087ac57a59c2285d564f16da4ed5e607ed979592146ffb0ef3f3db308fb342df5eb5924a48256fc763141a278814c82d6d6348577545870ae3a83c7230ac02a1540fe1798f7ef09e335a865a2ae0949b21e4f748fb8a51f44750e213a8fb",
+                output_str: "e62cfe44b169a061faedfe6ce667056bc0255d1f22a56d3df255ffbb145433fbac3dbc0b998a40001b805927bdc1ea47762980586ca088d64babc0acbd488c5f08b8c220fd5a15ec679448532bb992360c8b166bd8efb59f2b5e091f06cb1df8d79ff9b69c4a49a9ececfd6403d6f984a987c0fce8e6ed4c0e9caede1c522e4f71495f8599f2864c42809c931771a32fca62b0cceb02e5d7ffa15754e6afa27e568d84fb041cd35140a48f4b23204cab939b5c48217711a5426f194ccbf07491c0dc2f885156b40c9f782f4a17bb7108e465d9ae1f52b494c74611a1d9d379ea8835e0f98ac6880c339d70b65436a07f056e9c118a89aa41a0e4463482b5b037e96736d265caecf4764e6f206ab47eb83689e3380db572bf815f7e2acc67bba3f4d074df16d3b95aed1c4718ea77d1e38608400ea88c6f5ffa084eaee206eec8d2560a601587ddc5804d86912e4b844d87f2cbf10634cc32f492bbfc32b4e746ee3fe9e9c9b03da7de441a53c0e3b648366a4a997a28df2a10628406c530175191f230a97e2248226ecf6293d39809b0dc0493ceec48337468831a5eef0038affc160732c097cf96bbb90f5a302406ffe8c0f1fbd7554c1c0679d2af199e565d96ac5697f2ff748cf0bdd87a0da1a9de71020da59bf69adc9e7fb7d6b8a38113c3370a120815ddaac8ce49ed4738c3a2805100de7c6b2279aaac367a930cadcc"
+            },
+            Test {
+                input: "6b860d39725a14b498bb714574b4d37ca787404768f64c648b1751b353ac92bac2c3a28ea909fdf0423336401a02e63ec24325300d823b6864bb701f9d7c7a1f8ec9d0ae3584aa6dd62ea1997cd831b4babd9a4da50932d4efda745c61e4130890e156aee6113716daf95764222a91187db2effea49d5d0596102d619bd26a616bbfda8335505fbb0d90b4c180d1a2335b91538e1668f9f9642790b4e55f9cab0fe2bdd2935d001ee6419abab5457880d0dbff20ed8758f4c20fe759efb33141cf0e892587fe8187e5fbc57786b7e8b089612c936dfc03d27efbbe7c8673f1606bd51d5ff386f4a7ab68edf59f385eb1291f117bfe717399",
+                output_str: "e55556489cff55ae9df1ab48f860e81c3eb95d979929bed9c747fd1467d201fcf041d0b3d72ef227c82c93e6346cb02a5c78afcf0b9cb6af551e9645c09244ea67e02e17bf1941f3910b069c04dcd5ff7b4b9c69bb973efa516b4aff0f8947da042e21bf838a94bc8d98e6a30fa830fb9774d14ced360125da945f44528b99df2095c5186776d434a4ab2202a8cd5443ff2636f6111228bf1f5c5bdfbcf6278598733776bb589230d74314083b983cbbc476e4c9f0996a01dde09c8341da4c2382923fbf32a1ab8e37e9a18da38f54154c44fab88ad8857ec5ff82cbe1c9d24d6aa676978fe7f18f1c2503af6981551710690db902f46aa5ab3856ebba8ebc644c7339d6e28eeb2aeb6d5f168e0447cbea439ecc89743bfdfa88f963a6b57f28157f55cf46b57c2396a357a8e44ec964ca32c51fa5dc17c1e0f6f80fa2c8d26e04f03c32cd763f6ccf0f16f915d72f6e9159174b69535d2229c8a543e992ab0e86bb51da378eb378a0f28ed49a8f57f224e03c9c1248f0133d70af45ac7f0d27c5804cc99e982a2a583ae566262f3cfbdb91bb0c2f2561651a812cbe22f1380929f85a94fa721afe6ba1ee27430f2cfe89966a9919ab21036e81962afda1026b3b4a95fdf0ba51940053f01eefcac57cd11c4c60d66de753f41a178cc56a938a72a0791874eab6dad49af265cfc6a03016f0a1a490ececd045b9f7509f1193f9"
+            },
+            Test {
+                input: "6a01830af3889a25183244decb508bd01253d5b508ab490d3124afbf42626b2e70894e9b562b288d0a2450cfacf14a0ddae5c04716e5a0082c33981f6037d23d5e045ee1ef2283fb8b6378a914c5d9441627a722c282ff452e25a7ea608d69cee4393a0725d17963d0342684f255496d8a18c2961145315130549311fc07f0312fb78e6077334f87eaa873bee8aa95698996eb21375eb2b4ef53c14401207deb4568398e5dd9a7cf97e8c9663e23334b46912f8344c19efcf8c2ba6f04325f1a27e062b62a58d0766fc6db4d2c6a1928604b0175d872d16b7908ebc041761187cc785526c2a3873feac3a642bb39f5351550af9770c328af7b",
+                output_str: "5c3cd7aefddd08e09f343a8226155bc3ba959998299aed4ce4e85c6758833685a58e5cb8002fa4788ecb673e810c98bdf71a18f7a2ddfc351056d0639bc600fa42bd03b1315cc4c9640a8d61d481bc7f9077c9efdea6fc3993993cec88481fcba0e4c519cfbb57b465fd1e3d33557d8da77321cb21e584e677f3a66d38c9e49d9a9545d6b84afa37547f1ceb22c2ed9d8d97693a69eaa2d15f376e6de77b0ee6c7dc28fb1c1bcb42bf8751400ea2470b87f19830a6ea33da0912dc894892c6c242e90d24238439c6794243a5a6512e3486680f4f9166150502a1bc049f48ec80d2694ff8334515eb4a97d483e7e401bf6e446035fddb8b600ca7478b8c40aec176b79cc671e90caae5d1ec05e51d5e7ef9d8b4ff3b3b319d80c093a83a3d21f22eb4dd3b88fab1345b29ab527f8d69cabe8fece7e26d40a63b3fa08340501a40d433d77dd212ffb48265901d9a05e17e8f24786c7c23e50cfa11d5ad497d98579b02b642d48fd74ca608dc32e76c3961e07064168b898fda5b4fec10554f32426dd818b7e207f3facad3525577b5fbc19f1cfd39fe6453b274362c456b8fdb3aa26306e306ef1bff87056ae99fd0cc9bbe36ec508532e8239b3c33b1705d6da65813621e8d319460cb6bbe94c9cc0a5ab5c9cf538775d42068d9665239e1fad0ee8fca7ea4829c8be493ac2de44b340028db1f27f9e4470d3ee6ab48b416ce36"
+            },
+            Test {
+                input: "b3c5e74b69933c2533106c563b4ca20238f2b6e675e8681e34a389894785bdade59652d4a73d80a5c85bd454fd1e9ffdad1c3815f5038e9ef432aac5c3c4fe840cc370cf86580a6011778bbedaf511a51b56d1a2eb68394aa299e26da9ada6a2f39b9faff7fba457689b9c1a577b2a1e505fdf75c7a0a64b1df81b3a356001bf0df4e02a1fc59f651c9d585ec6224bb279c6beba2966e8882d68376081b987468e7aed1ef90ebd090ae825795cdca1b4f09a979c8dfc21a48d8a53cdbb26c4db547fc06efe2f9850edd2685a4661cb4911f165d4b63ef25b87d0a96d3dff6ab0758999aad214d07bd4f133a6734fde445fe474711b69a98f7e2b",
+                output_str: "83d754c973e2f1cea0a8eef4cb2340f2bf78cb88cb3aa458e7c915b5c8412cee403cb18e062d2d896d5bffe7dd1c3ca2e5e37e193554a176beb2c636abb687e867af6b9eb5fba57f371c167cf210956c5855f27fbe890708a28321bbf2d1d44dc7a911906cc4054d6310cddc4573ebfc9f7227031ee0eaed3a810aa18367d2f6f56b478881f628897e2678fac39f76a745460da7913374c9af81415592891035f93286bff02dc737eb087db8fe7e77a188c206caec84832a120547d967107a49af42d422ee7364db5b6592185c07dc7fbc2d0abc2a02c3cce0070c23f2daff0c8fc61563cb7ce0e930b75c706ab8180bcecd4e2c47859217b42719ef341765ff7c59c239c1752a3ca73e04da7918b61a4d98df5481f3b2a23a4797d66786ccf940ed96d6817d6172f748262448a69844e59ce9673cd9aa3f5aee057608d4df64042d78a03920fa23de7bc65881465b31c4204f68d69cddcfaeb9a5a6f4aeac6572df206802403d169eb5b2b69cfe3fdfcde19b198385605c864b5f02bdcabbf646c5945899f52830c3cda909443c96df6dc1417677bd80675621755d47d076df56daeda124a3d6b1c7b6e050f6d3024c5627a62c57c94438a8a3c14c5f572210893baff4b7e4e84c99c6ca09eb3629087f1c700513f2447525ee23622099e8d8b5d2ca8918cc5775feb5f34fe5141ccc93ec172168638a736ceb0541a1b18369"
+            },
+            Test {
+                input: "83af34279ccb5430febec07a81950d30f4b66f484826afee7456f0071a51e1bbc55570b5cc7ec6f9309c17bf5befdd7c6ba6e968cf218a2b34bd5cf927ab846e38a40bbd81759e9e33381016a755f699df35d660007b5eadf292feefb735207ebf70b5bd17834f7bfa0e16cb219ad4af524ab1ea37334aa66435e5d397fc0a065c411ebbce32c240b90476d307ce802ec82c1c49bc1bec48c0675ec2a6c6f3ed3e5b741d13437095707c565e10d8a20b8c20468ff9514fcf31b4249cd82dcee58c0a2af538b291a87e3390d737191a07484a5d3f3fb8c8f15ce056e5e5f8febe5e1fb59d6740980aa06ca8a0c20f5712b4cde5d032e92ab89f0ae1",
+                output_str: "c6d3296ecce00f96e8e0224fc094279afdc51f4d65790b7de6612a536d16dca57edf5af53b7dcff98910f8c41af597692c5b9590b7ebd712076a74ba9923c364e042286f754143b2f1e00c47d4d01ed6a08fc3b62918d4c7fc8a5afeadf7b83a02acbfdad3032d72c60e5ff342ae9376c60cac094780d9f0a6fcfe63496a1fc660a33e1111ff441bdb600b37a33256a35e86cb245ce8dd2951e6b4c7c96c8561207d402d143902f085191084ee39e8fb472965f51c6e556cf4eae55c540adcedeb9e77699c161a88dd07093251dbf403e7a26ea6ff93b2e5c61e5c0538cc29d69de806d995c9bb59b52915a61b9daaa3b21fc325ae7e1d5923d7e2cdb4f71e9c1e9deb331916f09b22a34ca70fd20410eedb22118d606870188bbb9800445b136ffef3d7539b7104eed36e3e663b5167a5649b0fd2013424153b92bf520845972c146f8e15670be40cf2ef1e73e23e404f1753833abeb111327e862904c7ca969f5820b41c6484afce6374c72620c1b0df72c043c1bef6b33eb17a64b0fbe48d68e60f90cfa669214f96709777b9a278b65f197956345395008272e6cc3ddf43df36b39e491897323cea03b88d2fb8fb9f9f1219e951f4cd652aa28c1cd03a369d85c7ecee4c3016c89885373acabc20e40dea4bcfa7b499941d8bd06738a71f3b40ed89ffe85c7c84ecf5f644cf1f3a434d2b12ea3339303353890b3c4c5534"
+            },
+            Test {
+                input: "a7ed84749ccc56bb1dfba57119d279d412b8a986886d810f067af349e8749e9ea746a60b03742636c464fc1ee233acc52c1983914692b64309edfdf29f1ab912ec3e8da074d3f1d231511f5756f0b6eead3e89a6a88fe330a10face267bffbfc3e3090c7fd9a850561f363ad75ea881e7244f80ff55802d5ef7a1a4e7b89fcfa80f16df54d1b056ee637e6964b9e0ffd15b6196bdd7db270c56b47251485348e49813b4eb9ed122a01b3ea45ad5e1a929df61d5c0f3e77e1fdc356b63883a60e9cbb9fc3e00c2f32dbd469659883f690c6772e335f617bc33f161d6f6984252ee12e62b6000ac5231e0c9bc65be223d8dfd94c5004a101af9fd6c0fb",
+                output_str: "e7b210d8ac4395b2de4a9066a345b1592a5c0649d47ec8392816a65c03b5717ffed2427f513ec34d3db5ad59af61e0ec5df9664a1f24e50a31c6c146799745465e3a130c84b52edc04140aad1a8afdbc22d816339d5ad126c616b55302cea748e744c6f2f538e2285538697ed1b2e169d9b335b6194b59775cb19b14e2a5bb0754705e1342e25ee1824c75479d317ce844d477599cc6a637604dfdeaaa02a3cd2c1b707661dbd2b1fdd77d2187c1e2295d92d98d4e5ad4208db1771713bbaf33e63f16163f63ec956c7db48d265e53058363a923bd51bc3602b184eaf2b8855dfb15ab9015d5fa72999cecfdde888f95252885988052c9f1666d4e90f82c1ba1c27e4b0ff07f99bc4a54b9fde4be5c3882c395f69ae3754576f65ca8cb03eb2890447ccfb37a475748742ac932b615537b7ffdbd9e73feb1bd29a8039b1321f8b7f6bd80bce4522174ddbc4d6e95f18da7ea0d4dae4d14afde65f8ba726662563c225de20a218927e2ceef7573af8313db530d5feb42bb2fb7b4dd616d25dbcc6f443a9bc91ba616b858ad827b049a65916cfd0a823a2726243d8393e248a8e1a66a057350107d01b65f4bfa03e6f22a4c26645b7c2cc63767e89f2a8860632226cd6fa6a68db79949affd3ef91758168a295a5342e10c402f2b2076adc203ba107a177d6fa79f12de20d084cb463bf0c74b9d3ff6ed9455301a850008499cee"
+            },
+            Test {
+                input: "a6fe30dcfcda1a329e82ab50e32b5f50eb25c873c5d2305860a835aecee6264aa36a47429922c4b8b3afd00da16035830edb897831c4e7b00f2c23fc0b15fdc30d85fb70c30c431c638e1a25b51caf1d7e8b050b7f89bfb30f59f0f20fecff3d639abc4255b3868fc45dd81e47eb12ab40f2aac735df5d1dc1ad997cefc4d836b854cee9ac02900036f3867fe0d84afff37bde3308c2206c62c4743375094108877c73b87b2546fe05ea137bedfc06a2796274099a0d554da8f7d7223a48cbf31b7decaa1ebc8b145763e3673168c1b1b715c1cd99ecd3ddb238b06049885ecad9347c2436dff32c771f34a38587a44a82c5d3d137a03caa27e66c8ff6",
+                output_str: "8dd1f85c100c7f05b59a9a0a78581b5541ece6a40672d9af23e9f80a9d3fc96346e1b0f3dc309bb110e3f9f465e08371d93616258fc5cf5f3264b6f20cd795facecabad03bf361324e242f098fe715e14d0d207b5122b01e47238e8ad8cd9c2e874e816c970f8caba5c148b9d2638adc5d13384dd5867679b5821a37b77b5c8ae773f982d07f037e319b0c2a88b8716d8642edb7c51afdb44297aa2ad22ed1deffebbb8a89a601b3c8ed2bc1894ad8ee27d85e4b88547d64394709532582eb95a682aceb7c205f4a3cc9693e443d7cbb1e1def42905622ac0e12d0543be1786c13a913d45c63cd7f06e058440b34dd44007cd2b7ba489d89358276a3d597e19a0b973f558b4bee867712543c1bdc817495d3222d4472b00784d7cfd83bbcbce7e2fcd0f9c1ec0fd003b3d8ec74233a3bf7e95430189eaab5ce341739c8f198052a783b9ec0331cdc1e2bd8b25fbe9b471a768cc6b8f2c90298196bc65861678c7632b7914d365de4bb2cf9dbc4a0a06034711086a0d09a9c139132556efd7ceda2933eb9b86ad5ba22196df404684993a8e7fecfe6e582e5a3a4717753e5f3bef462dd8820bf3857881d54af1d0f2ace27ab1c208c3d5087db201f155164c398f2ade81ce38ce0d741920364c57580522fe1f0299a6263c3f4a78e03300372d379a4a9a550ffaeeda27b30b329435a8b2e3c127568b48b1a75462f576dafddf6"
+            },
+            Test {
+                input: "83167ff53704c3aa19e9fb3303539759c46dd4091a52ddae9ad86408b69335989e61414bc20ab4d01220e35241eff5c9522b079fba597674c8d716fe441e566110b6211531ceccf8fd06bc8e511d00785e57788ed9a1c5c73524f01830d2e1148c92d0edc97113e3b7b5cd3049627abdb8b39dd4d6890e0ee91993f92b03354a88f52251c546e64434d9c3d74544f23fb93e5a2d2f1fb15545b4e1367c97335b0291944c8b730ad3d4789273fa44fb98d78a36c3c3764abeeac7c569c1e43a352e5b770c3504f87090dee075a1c4c85c0c39cf421bdcc615f9eff6cb4fe6468004aece5f30e1ecc6db22ad9939bb2b0ccc96521dfbf4ae008b5b46bc006e",
+                output_str: "16322d3005bef6a6cd077c13f13a0dba11cac621605d78e2ca3ebb07386c0acc23d0b21573123e1bd43accc1f12dbcc34874b5c18b6d037b339e958972902ba3174a9831eaab3543b901b6cf4ef5cbd1ce1b60ac90e94f6e15c7dad13ac4b8affab3141326ae057852dab28fb1564a7375204805747a45c0e96e2e046611ffb1bddb6e6ef5c0bd75e4d654701bcd7f903daa5b2d32e017c5a81a907fa908c8523d821a9947e647767f04fe6a8d0a9297f65610b1ecb332d3dd37ec4501400c3c1e0035a48652de4f0bc038c90c5b4fc2d969b1951de5400184e6c761c7129711ecf3f4146c2b8d662c96a30491771dad21e0d9667f7312147d53b1377999f0274d239ada0e2e2843676ecec0d528c89a5e6c4ea111accfdea9d10bd3f79326283a609f1e2c9fdd4120367dc5403d53a6d0b0dfc3a3726096ec7f6ce189a29f23053f79e179f275e32db13567e108a63c7033286c4f6636afa91c37e32a5b2bf01995133fad11a96ba922ce4bf5192a0536f4f238f9cf0aead2265ae73ff3923682644cb414b8e92e9c5eb8d46e39e46a5a394d75ba2d01a18b2309dec99931fd9c29dd61073b23a19edcbacca8d9227e8fe23d313947ab6d9c807c8c3bc8e189158a1815410a94cac21d931560bae3afe409d4904c32d4aa5c7ff6463ec8c432f97effd812ddbbde53ea65956c9c2af72adb2c7b5bc1efcfc8ef4ff8a152aeb8"
+            },
+            Test {
+                input: "3a3a819c48efde2ad914fbf00e18ab6bc4f14513ab27d0c178a188b61431e7f5623cb66b23346775d386b50e982c493adbbfc54b9a3cd383382336a1a0b2150a15358f336d03ae18f666c7573d55c4fd181c29e6ccfde63ea35f0adf5885cfc0a3d84a2b2e4dd24496db789e663170cef74798aa1bbcd4574ea0bba40489d764b2f83aadc66b148b4a0cd95246c127d5871c4f11418690a5ddf01246a0c80a43c70088b6183639dcfda4125bd113a8f49ee23ed306faac576c3fb0c1e256671d817fc2534a52f5b439f72e424de376f4c565cca82307dd9ef76da5b7c4eb7e085172e328807c02d011ffbf33785378d79dc266f6a5be6bb0e4a92eceebaeb1",
+                output_str: "14236e75b9784df4f57935f945356cbe383fe513ed30286f91060759bcb0ef4baac858ecae7c6e7edd498f01a082b63fa57d22540231e2e25c83efb3b3f2953a5f674502ab635226446b84937643dcd5789ee73f1d734bc8fe5f7f0883ab10961b9a31ff60dee16159bc6982efb08545984bf71fed1c4cd81c0914b4c19fcfeef54af4bbe372f18cfcd3a18657f5b9450f99a78f0fa2c3cdca7461c4ed7569536883b66cd87e9c200962902eaa16a54db6a0a5cc26d889038c0760810b5bb4f33f1e5d639b6f9bc7ca62ba6f8c9f8de770260afe47f4e0f82f102198eba27f543252ac8ddd83e1b8db0a91ac65633fd12a550ebe96f93aa6704ed5905c234fa6d9203910cbd02de166c4c3348fb81ef7b84ae1455fe318b5fd170883f49ba2f24289c479a2c7531406ba989beaef3a79f659028642e9b033f7deb9ecec3a7a9f1dbd2451fcb47c81e21e91d20b924c6bd04c1f0b2710d2e570cd24bad5b5de4e49aa80b6add5507b4d2e510370c7afa814d7e1a7e278e53d7ccf49a0a866ca3a7b5bb71ef3425e460feeb29149f217066613695f85506a0946cf68979f04ae073af8028976bf0c5bdc2212e8c364583de9fbd03b34ddee5ec4cfa8ed8ce592971d0108faf76c8940e25e6c5f865584c34a233c14f00532673fdbe388cc7e98a5b867b1c591307a9015112b567ff6b4f318114111fc95e5bd7c9c60b74c1f8725"
+            }
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Shake128));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+
+    #[test]
+    fn test_sha3_shake256() {
+        let test_cases = vec![
+            Test {
+                input: "",
+                output_str: "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be141e96616fb13957692cc7edd0b45ae3dc07223c8e92937bef84bc0eab862853349ec75546f58fb7c2775c38462c5010d846c185c15111e595522a6bcd16cf86f3d122109e3b1fdd943b6aec468a2d621a7c06c6a957c62b54dafc3be87567d677231395f6147293b68ceab7a9e0c58d864e8efde4e1b9a46cbe854713672f5caaae314ed9083dab4b099f8e300f01b8650f1f4b1d8fcf3f3cb53fb8e9eb2ea203bdc970f50ae55428a91f7f53ac266b28419c3778a15fd248d339ede785fb7f5a1aaa96d313eacc890936c173cdcd0fab882c45755feb3aed96d477ff96390bf9a66d1368b208e21f7c10d04a3dbd4e360633e5db4b602601c14cea737db3dcf722632cc77851cbdde2aaf0a33a07b373445df490cc8fc1e4160ff118378f11f0477de055a81a9eda57a4a2cfb0c83929d310912f729ec6cfa36c6ac6a75837143045d791cc85eff5b21932f23861bcf23a52b5da67eaf7baae0f5fb1369db78f3ac45f8c4ac5671d85735cdddb09d2b1e34a1fc066ff4a162cb263d6541274ae2fcc865f618abe27c124cd8b074ccd516301b91875824d09958f341ef274bdab0bae316339894304e35877b0c28a9b1fd166c796b9cc258a064a8f57e27f2a"
+            },
+            Test {
+                input: "cc",
+                output_str: "ddbf55dbf65977e3e2a3674d33e479f78163d592666bc576feb5e4c404ea5e5329c3a416be758687de1a55e23d9e48a7d3f3ce6d8f0b2006a935800eca9c9fc903d86f065367221067658b4d7473ed54800d196fbe1089811dd9b47f21e3698b1573653adad231c39f145b586d6c0133378416138e4423f7af7dacffe965706a3c49024002b53ba05871e3f066694b163630b0053be41fa45d4317eaa84214254038a37a9c83d62eb9ea6e6acafa6bbfe5af9f389690d5a9e27bf97c1b93d93ecf36df6da212e12b2448154156e94687336b6da91e368512b9f34c616166542923f3618640d930f922a3dddd2f87920378541446f2223f593931bd1ba02e2907ce3404621f26b900d05a1119a9e4934a7cd818dd9237445bf50475a011ea0078788801d21dfecb7a2bb294e4956dfa71d8cc472405342bf80120fe18a551d88d6abc24d83f077bfb25ebde5f4b03678d677ee646dce3496d5138be108782ca5a00aaff3cb4bb873ec0f2e932dd74847033ec5f07254e3027b0ac12db7d6d3f90b53d8a5bd63b99c3bf5cd38b453d7cb12d0ae2bf1cfd3ee88af71bb6606b0b791defc2d762c8641bb8319fe17321eba407eb744699d92b35abd79f5b9a85408c93d61233fece638023875aa02b9edbacc84003a28cca2d55a0742d635fda888905986ca01c1e6420d49ec25224d84e915dfd1638a492282f1fd053770168953c"
+            },
+            Test {
+                input: "41fb",
+                output_str: "b64ecacd5f7499acc085c908d35dcc1fc0131816f28d360592e1265079f92a5f844c4bf6aa50d98d52720797e8c992f43c76a73fd95f9bc4cd272157842ada2518190fca342dc20d0c57cddf01b3ddf77977eded63445e40be82df8d26db629a2d307ee9fe28d2fe557e3971858c6d67c42be2cf44dd7570521ce06474467425b7aaae39db90945bad388009ed5715c684bb4e4981eea324ecf66584ad08d9f27c6a4dcf615591857bc7364e8a7c136661ae5ffe828c734dd5ea5a071276e8477b8525e02b7b445d91cc6e37d58740dc2b069be6d92e7df95c1ab52b76f7761ae34328962eac7156e460b3c04ffecaec8722a56e7373285e42d4cac5498f8d7dd5ecda9f9973a32f8d425171e1390bfc812c9ee4d4ab8fa9a0d93aa90a4c258fc64d77bbcf49977e87c3810c80c4585168996a31f446f9391a193b888cd321e22e9368f4f11495fe124141c04015532345d7cb0a13a4dd9007d737b3a176a88e5fc153d4ac2e8cd641c40c4261bba70e1b87114030ff67cb22acec90ac288d6b59d25b00038468b4780254fac4ef158ec2cd52c0ab9217eed1ed0a5e7b4c4b3a64b1824e2b27aa53398765d5352bd1ed0e9c7b3fb264d141741659f7d8fd0eeec9f9163c42afdb540d5f2c87833880a0c942ae4ccea7fff2f4c798b8aaf24c33be8054a09459a3af7200d555334241709a18ecf88ce93c99234d6ab0285916ae"
+            },
+            Test {
+                input: "1f877c",
+                output_str: "f6bf0397dbfbb20e4ae30f0a47fe976cd109b3aa09b0e3f29f560e4ed333c0d083326b03f6eaeb57e277bbfe1cce36c499434d838cb4c8cd8b02a87790f4a6717b22d46f9220391c420a1a1bfaa9ed5b85116ba1d9e17ff16f6bce6704c80a49fd9ac42689db0996c6bd3266694077c6de120043a827d44979ce8ccc6aa7e5308eba64acf9ffff51d36bc4401f8117d4b96340c62d106b0a6445f01987f9c4c0a420e1a9baeb594bcb1bdbfe59b6065eb91cbeb252473c7858eca475e1c81e8425c7e2c1706c4c4abb3aeae39332479ecdefdfa93c60ec4007a51c5dd093b527264155f2202e01d2083d27d71a6f6c92d839e6ea7d24afdb5c43630f1bd06e2b45b2c0d0ad70bda111363298ab9754f26db00a3fd93d72981dd463defd286320a274f5422e9400dc6e7c78d75534c75af6b0398596eee5048919b8fe33467c2b7c227bc88994b28819815d821dc27bad0458d57f40b12a8a933729a0f6bae74dbd150325d14c302835ab95dabde87a2acee9347609a6175dbb538fdfb278be0b3d5f062768f9e0eb1ac9c36b4e05e3adfca73981cebaf6e047a18196ea78846d9a782b6e1cee2036866dbca749644e74ef5a4538d4afb1706b360f734814313d20a1ac626bee7ac0fe9f277d48bc50816ac9743a61e32f8b26ca6f4dc81fe7f3558aa2f18586d89a8e3070868c76b4ca4727f541072dcdab3d547d52abb6f356"
+            },
+            Test {
+                input: "c1ecfdfc",
+                output_str: "ce7fbc15503986e3b84530d84a16ef64332a6ea57e354e9f2054bfc2aa8891f94b4fdd42fd227c94b33f9ad45cf3982239f81fbc2cbac7809f01e1c294073ad6d2821c1283c5c427f41fd46455ef7b4ea0d6d5e249af95fac80a8678c1a5318443e63122ddfed2591fc690527f97a09920941b02439af3ba36b17fd588e187fcbc1ff109ab4a9ecfc671926ef0cc9c82ee06ec6759e2758a8859b8fa9ddf46d6c049621ff589f3ff56c9419d6f48a68b68fefd068abec24824d7fc150277c2439bf78d15d59dbaa2cb17e5282e6e9ed744841f4a4bbb778cfeab0471ce850b2a2f948db3926f733ef7b3aa9ab8ea84278dca62b0691f5dd13ea11660a8e2fb5cd8ba74a352c044e7219e750f29b62f94ed268a68029b94b64f3d4f2193a7fc69ed34a59657471f04c4961084ebb581abcc9d50e3674a7debb285fc7215bf6606db1392a7f1619b347a4d07d230da07811fde2aebe45a70178cf841c619f712ef26beeecc4183a1040076e73fcf6fabe5c25a4b71d564a97cf3c88f1856d9c8b42e94f746ce4605d2aaeb56d1da5527598e17e5680d309788e09910beb74df7d3c3cd4ec680083f5845f4a1c15070e57979c01b89df7be64435ea4817bc0ad23acca6cb878f7131f02f9215e2d5c12cf3b4d24b29620c891a54ac8be6e3dec08397887de0ea86b81a5459b968fbae18b4b0324de7e7c1aeefc7598644ce1ff8f9"
+            },
+            Test {
+                input: "21f134ac57",
+                output_str: "bb8a8447517ba9ca7fa34ec99a80004f228ab282472841eb3d3a76225c9dbe77f7e40a066776d32c74941202f9f4aa43d12c6264afa59639c44e11f5e14f1e5695208db78f37cf3ac172469de67b80014d1a4b968a56f855baf35a275b8ec77b9ca591257aa2ef048663cd05d76b72cf3a9d2bb44b154b16e95eb8b61bd8415a867367f0031bff5d49237157c197473309fdaafc8146ab9fcd4254477b052ab306bb575eca6872863b5f43f026c2be3289e857d50441330ec02f6ab4c6329b18d3af0a1ed9db70f34016ea0caff1f0ef08ba6d26566df6cce9a457e1900fba3338a771e40cfb39581f16019d521e4f398539c4a6f2ca22ecf9158b96064c0f26b8a076e58b5f0ba3187342a5c9a5569e6d08a2ac27258cf0426d995724579c723a0fa8269b4239026a08d88738156943f1dff6e0fff5e4696149436cd97732424366626ce7b67a3bbe480e425b51872aae7ce59e70995c194e00fee82119a4320a4b91158db65b83195c9b799d3eaf3cbf8593d11dc67ee8c0cd7ca4fae69d9f46a7e70186a33dfaad510d8def82aa5710b0abb70dfc396ecfd33f56f66957b82a220d1eca09166f72358a71054a179c1961b64f26a3d7aafb030c28a73337862e8364d3f562b324ca2ebef58b7a8f089213178c8d0addb5a18022154cf010c722c279ae60aa984597ec6542ee1abdcaae8d5545ff45e781abc7145ae2a31249"
+            },
+            Test {
+                input: "c6f50bb74e29",
+                output_str: "69401ebf1d4c7ea500be60ef06783dcb009a13b4fcd8b341e5f2e40f39e732237e86716f26873c1820bc36d20f6d5e64a9c5e636855305cbc3f4be4a9905b5f79fb769a794299eafa8e81ffa51bb4d602480b1c40f9ee9bee017d5d7f6de68c8a79ee92a20b9da5bd3d01bc565cdd3e5786fc4d48f719c01cd6d3cafcd500f4f768600e6891102ffc10f1394e3a40a1bd54381775bb400ee6e20b95420fcb2c86bbfcf380bc95eefca33bc8de823e13b4b04a7ae1fdeb8279f3ef3e4fd50b2fde530b0d4c8dabda6f225a4121a79fed79d8a013c9df1103abf081294fcbbc5abf20ba38e0075169a9c13cfff94aeb271a46875710a60cd78915c33892d7fcd6c97a1c74846adda847f58adce8ef762d11c4f15ff8b97f9bedc97e1a8ae554c0b9e66ba1d48bcfad0d56f91b65e25b03a5e48cf4db0dbc467bbbc1e037743991ac72b4b259d65013a2708eb825dfdc65093a4f4f5e98427de7c60138467d8900adfce1f27408638dc66957d27cb774bbaff0bedee0f6553bcbac9724a20e8ed0ce6b2f764e4f0d80e4521788a5cc88c3d36f19925ac2f205cf6eb7e6d6888eefd0be49bc8bfd8a80b9e05dc7513beba7be52d39bf9bd2b2dcd03fdc8f8e7f90a83dab2ad85f51d040ba0f1c0a9dc38e929a50db7f99a26836612e601c6e4346e5e895ef4ccfcd6a5cc3777fc11fa64a9ac27d2cda67e29cb18a7e99e2ca0730c6"
+            },
+            Test {
+                input: "119713cc83eeef",
+                output_str: "c02561c12ccdd167ca959d9756cc70946f7fed8ba705e3edc433d3c45d9299d0aefe9e8e25d602c4db0d14ecaefdfdfed2de134ac5d0c4dfc02abefffdd7667a434936151d529a93cb266100b94ad0449597b1590398a1a63c42649385b4cfaa828c89037e0f97beda8450a68520143889a92c258645664eb57cba01c3b1134318e11a1848d912d0d2cbaebd59a71b52495671c548522f401394fe48db49956c03044cafbd40371ef657f1aa86e4969459bbbd21dea563a51482a47147ef85487a5ccdbc532bc2aebc3265e71bd8d56f4521cd93354a73d175fccf5aabef2768de2d8e851d4fc21ff032829411db2668300853ba5f8bb1ffdce3ff59197bd1833d2abfb8c3027b36b21969f7e36c3b6f3faba9454addecdafc213d347a44b0d364997a9e608bcff3d2004139cd05005b9bd8fec09e5976eab977b5de8e39373c10d9ee2d2ec196b33689783ef3abc3dbceca9bf33e8dee9a1afdeaa71a2fe42a3b0c60781c9a2d5714278cc7cb349a3b6e7251b96e4e2fac606b459c28ae81b551168d28acd01d4a08416b6714d8f82485a1c6d5348f7dc4981aa38e7f39edabc981022c4cd3345383d8c25c929fbf66026f91664998bc34f9689375d06ff95d208d4acc7791633b222acfd3ea26f8b5c4858997a1ff77050f280ac7b7e5325abe9e55fc27ea8ed1d9d32194b0c5d8807f94ae6f737276065ca08c323e9ed421"
+            },
+            Test {
+                input: "4a4f202484512526",
+                output_str: "8a804fc3a4fee6cef6808c756a17bcdf6b235808493fc78e79701e59a9e9a67d60f0f256aa69dc0258a2510f9936aee2bcbd0f679696f439f37bf9afb170d44a58dbcf71eff14cec1e624d3d8f1ddddd3e33421b1e305c794c2c88fcadf9d7c51f52e4352bf9c9c895aa457f5449e82fb36e2a64d1aa69771ef3d675f09030a95653837ab2237daa7fcec36651355b2507713cc6a2186e950de82dc699122644193f8f231c607ba7f3bdd0a214b4ec0155d30517f681fdc2a89d3143040be0e0b6dc7e5185c723464ccaa2fe321af3b4174283355fe3d1ced518e00b6063ddd607b166ba388978294244ea8ec773a528003a04914b76e9be3337d806ca20c584b2bb66afcd144417e3d93243f185d26dba90ea39259c7f23b8a6427aa8a7622f277605f4a463f78a0c189c8de2c553ae20773d7cb4f7e26a13f4204b3752d9ceddf29849798479a4bd0d7ce4d22cc51f88127435bd161f026b1811a723e786db1dc01f921fe076c3532fa969ef1f8993e0a4fb6c17597d8db38dd7af259e322751cc0a1cca2ee4940f4ea56ce9179941cf4696256cd04ab853266d12e7e679377d54e2c2f24832974c573192dd2fdd4da5efd72114109248b03f0ae03123252ffff977bde87af8d8022c4c51da68efb87abeeda7a72eb4d0d1a2eb65ea4cebc7ccabf3787b9be98e14e4a273635f69e3e4ba557a1a42d1bf69ebd359b895320a"
+            },
+            Test {
+                input: "1f66ab4185ed9b6375",
+                output_str: "7b5562aba86e6329693ce1caab2506af93ad28be4de045e66a7b277c4dc3c2c9e698ad5f6d8826230a38fce87142dd83b28f055fa7a9212f5017374a7eac5bb7824c1540597de34be9ec894eabcf751bfd5de029a1cada7e599d433bac0499aad9782579d28223a5d16264efbf55eb1370748e7dac4b56255468fa9694a93c4b3759f691d9a4a08b53a15f61faa1268e38aaeb43b3fcdbf0ba003e2037eb52c8e9931db9c60ffc1d1fcee7663d1017ab6dcc1b92472a88a3d568af5aff930aeadbae751753cbf2f987338deb1aa822fe28788866073319662438b6caf6bd8d79de14fdb6d30f7983f5711177765d7d5e1efb610fafc9de733c9db3fd2f1c35421d29cb96f87a0dd1e83ad19acdc7c2bf7a6f047994a96e6d91bec34aaaf18aab7b32a0b379a60f12afc697770cc6039031c13b5dd66e0d368609d3018accfb02fa4973bda707cda096d712faf59b43be3ef5eb7c227530c987dc4991955796b2f588359112b9e7566ca785cc5706ac333d12e2da37a97a13b69540084d1a5908ed3baf73a0e1c55a6bd036f1342f8ec671593b9b555defbabb3364914e4396d6e2b2adfa951a6a263aada6d879b4ff330f848d2598cb418e530bc63bb11e7a247c5a2c21d5c2a34d23721955567e4452df9f5e2108c1fea8fbf672422bb3b85c7c5664b918d3f3644339367cefbe609a9b00c250111801c3f365ba752709b76e"
+            },
+            Test {
+                input: "eed7422227613b6f53c9",
+                output_str: "c92fdfea927eeee73162c436c6a3fb97291c33787bf7c2cd80decf6004c043bc4509a2cfac1fbeeb0bcbc7c2974b168af3291dee1af2d0826935da79c5bf7cf3a211f347c2a44630dcc20e964e3be24a20766a2ec50310f4b1990a3987fd8d144d3a6f091c6f8ecb7b2069905a7a1bce8a49a9779e9132bae521fc44689f7861b7c735815448984d6809c2138ed64a45c4320e09bf459a985a41d024dc4ce0d95681dc9379fc4dee3c024436e7a949589a74b434f6b5d5742501d1e4761e0df89f4f1943614c5682086d31f6eb2b65a005fca29b48777748132a15bce74228e5cdcb95c05f51730e8e27e9de71d582a95ad3e78e64b978d872b91a88c6175ec3f92d5aac14bcefd0f6d8d5e2e19de467c530fde86aaf6fa5ae0254ea01d70860278c24be7f7c52669aeeec52c606fe664d7a8e857eb64948d663dc11e9de33a410dcb3eb61fdf6e9622b66b9b9f4a39c4b578a8d346906d14aa713d2b266db5b85aed05186ccb2809b38bbb3c9f99c2861793fc70d972b51f2199674e734d46fe0e8eb675777ac9e4b578a7de4dcfb5ac1e7a2eb0067237b985050d66885f85ce3410467b5ca374a9f420d8ce5da4a4934fe78065541c53d071c88f0ff132eeadefbdac5e98251c597930cdb32d79656eb44f95c78bbdafaa59b7e36da08a58af3daee99536efb56319643ff422cfb53d152ea302a6458f58b5eb9f2c81c31c4"
+            },
+            Test {
+                input: "eaeed5cdffd89dece455f1",
+                output_str: "f772deceff020d1be280e7f93df5056577e78d104cb1e2afd422b021c6206d94af56eb9404f8294403173e4a6932a1576bcc47580b6ce2cc80b20ffb274fac017fa05b3d804a6cd8e874cf258e5d46ccfe06d76dcc18c9874cd3b7543973ebe3367ad38e51f0a46b92d47a68018a819f2d90724ea9f5fc51f444003757b028fbf96f5413296aa9bb8532773eb8cb7cfc803578faf52082d4bb8af606301fa927a94fb62a73e2e9fe367e782351185516c181aa674e19301a38d1375e1658a181dbf927973c02207bac3a0b65c0c6904e8195a3c6550d13cfd46c1885987263e82ce56485759bffb2647f420625f2b483c2750fb0b4707a2014ff57b1a42375b37b444b0811ced4cb93d5c45551d5e1c8df20bccd9437b7e439156dd9ad4d905393afac1347ab2979811cd1beac7c454c4b7166b85bfe52ff6c4905c55d83c15c3a9a7760bda9fc4b90ec4aabf9cb3660a883be7137733a1477971d479049268add74e0c8210b1a9faba84fb940f62b1193ccaac3f020d10ce14dd8c058c46bc35846c07a10dae9c03c3edc323cbcc83987df1fb2abd141c7c0694624aa68df9c306d2e179fb4d603f42c99ea369c90c176495104fa7de772ea71a9fb014b467ca220f9c004f287f8f0786b3d47c9daf3feee80b2ce4a92aeb0ff8e8c09448dad76f5fb01d6997ebb139d7fa5df8c0bf12bbe0af2b6e354c4089f32b8c5294634"
+            },
+            Test {
+                input: "5be43c90f22902e4fe8ed2d3",
+                output_str: "00f3525289b33fb3c179398ec76f2e31b824a532b2aa6b2da6ffad5287e07f9f9a2fdd2f2032ac202119ca0a01b7c9c6de724877ffc874d5e578066a4be43757bc2d9b09aa7b483749e0f88582cf9cc3d47b8a0a98d70ac793326fc5eb6533f00eec34bfab3518ff4e98b79582621c2bc7bb7ac8afaa8d60df3f072fcaaf514fa7fd9efe2b1fcd3cb96a7f70a87436922584b93ef74bb0325416eefec14efd150432366c1c1e5f7949c2573cde16a24c42918c919abd988f8951207149f873f78d2793fd642f3b3e93041b8855b8ccf62a2f6a2b8ece4dc704cf693069bc789d470fc4938ad23d5b5dd20d13e31345b2169f750e69c4913e3dfa1f1e54a3019a8333b6648659a6a2e93882fc4f8ae0234fd149123d831f148213f578e8961dd07cedf94907abadf7efd84500e501bf2588e3b155e7d24815da9584595efd2fc6f1768f651c1eb10e00295534f89a8dde9d37c05f7e4ef9ea236b615f82bfd07e7f6feb1c62dfcdd4f598bdfb3cbb0fc3259ed96d52ae156b20f0f6ebb089127cf98f045bdcb12db84c2ee47800ce36ab10f982231fe746d32fc5002700e264aaa6432e7bc6bf4f4af41e82e256c3dd6ddedb24b3607015cddf78bc1ac56f835d03d8297bdee57f87effbd066c3de372f285eb2e7d7359684bd2072b090bb78c3ee71a45a0cb7c22eb4081ceb3cdb89cbaf3d124ad86a9a830457e273c8ab8b33"
+            },
+            Test {
+                input: "a746273228122f381c3b46e4f1",
+                output_str: "1cf1698f0702653368463a9eef102e8588fd5e711f4ba16e3798d7c7730acdce6c65ea3849cdca9d08437bee09f78d52397c92d0f00acc9d5e9450213f337b9a75697e8fbbddca67ccbb7f8b2cab1209397a4eda1ba9ab1b44366e4f7a0d2db47d5480247194d486d63d72fcfeceac8cfbdb7f8784d4cc9214b3893fc7eebc97a33b9ddec9605484c96bb77cae4d212f16229dd507622a01c861043320d9c06373e1e0d9649d95b42a990b0b447adfbd307dad1394c30d12e010ad5f6c8acc729904ccdfca2162c32c5ee5654316e10a97a192ec23baaf594b711277a301fe6eeb4b54903d1bb736d4788f65dbefecb4761685c683db56c05d0f26f179010cb323c2fc8b9a44dd4a172be2228c6b0a0779b0637e6b5de047776597a17fe94d86aaed911a1ddd27f8f61710cca8c5f38504a50f01304b559419f06b5f043dfe984b4dea2db6090c1a836f26c0728048c0d89401722b9576577f11700bbc5a6bbf1c23c687bb478112da0dda52c1ed622d0227382f76edae51db2ff14c098bae8d25a2a53d98508da98c99aecddb7ead8da98ae41bf21a59b3fe4b3dd68f0fb15242ef3056fbf77462d4ff67e0b344be02ccf03fb98f6dd5f6d306a4c2b2451ec8aa2933172689bd11a7e3911b236905d6d8ce1c030e754a0b493cfbaa39123b0dc4b7085f9fe5988b0447b706cf226edd34b644bcb591a002a08cba030f6b1927"
+            },
+            Test {
+                input: "3c5871cd619c69a63b540eb5a625",
+                output_str: "413131add0dba2b0a48443d3399896ad65bf5f4426d234ae20c9d2db3d9dfab81401d7722842a58312f837e7de13069802f58c7ce9a3ad1703e9c7170d1ae751023147464cf8694515ab5e26836b935ed493b9d66d9229bb0b66f1c5ac721d8aec1f883dec33d0380ba79be198a6aa1f2cf555818d54cd28c0682eb44fa0f1810df50a8f005557c9ba52f02d70ef769ee7724b852a94e1710c6758307ffee309c8f884dd0597012679f7c97cf59f8a41b06a845ccdefd5cbda268885a2781fee48fe4ecf4d0559868607f3524aa25d1a5cbe5c33fe0e8e8e47b6705203d49cae7f1749da49cbc469b8870c1cd7d029f6398cf7aa0d3114f56f78885093a59c0c188adaa40976827ae1000bd6ab4c7a2154d80ac6786cc23adef333a2c538152584045a87e942b8033c565506bd319ad99c85a4655f6e47979f55b5f9f9822f9a338cfbaa50d580e27953ba9d13bdb3fdb480226edd2a8f8f56c75015714a51ea63c73fffac63dc3fc6fb8d509bc40b87b9332fa37daaa441d05984ba56781ae25d324e508b300e6b07629ee5bd2de33d3bbe6fddb699e35c324fdb521cdefce30d01570ae82803b0b54a7c1af4b45121461a848477c11f535b700633d88a68ad2abd9afd09a4ddc1be5511b574ca6e525eac7a6cd7c26eed3e5656142ab8b24d97a76fab94edd8af21ca7170a98660a5cbda15925e67c5c579363dc4f6970c95"
+            },
+            Test {
+                input: "fa22874bcc068879e8ef11a69f0722",
+                output_str: "2feaf391d45b2b8632ea10806e35d465f2f767dccea9304502a4cf9cfd85f7cd46bf0e5cdf2c31a43c6aadeb0c4683b3fe54e042c014457d0542a8ac09529c1931fd1ceeb0eef6c5a1d28f7fd1e7998537d78b9dcead530b0ab257e273432d3d7205e451cefc6906451dddc6b3b0da1d1f2df3f043396858e7619b8a420d0cb2cdfbbe43e19bd2bc670e2f5da51a1b8141f7fa0fa79538fc909d31847c46653c8184114505c51c49c844ec18ae5c6ef7820400d0859b3820fed6b023d1a3455c2bd6e1a7d25169b58bb71a82107893f27e994ba04c79d209ed97e359d02b991e402cf0d14eb61d4c1ed931b4526d63e9e9517faa5bc83a23521620fb5b9e9ac1cdf45536af54e567f5d9bc31196d23c58c0c70939497a3e11fa544a37991b5c06b8d7f57d3057e83c3eaf1758ebd0f569e5a8979d340740a9fa1ade5a9d956f171d9a0d0efa871e98ae8d5f3d5733fdf0388fd8d9564e6c267c6438f0f78d7a224dbadf7e6e645ec6952b96a9d6fb441cdd640b576b2c92bc7c5fb11ce767b0105de7907dc00dd4f8f25dc85b6a84083500f3127708ecc1250aa15d350437664d0d6ed61e83dbeb951260c1746c0f06423c4b84fe75a752e7f034b2584920288ee697926b9bc87fd0862992c3d9934876a978744043d8949273a3583a7c5ddbc25ddc0c7befbda1f306c9ef7a2f21e15543ebd5ef87c39814c91e1b60b079700"
+            },
+            Test {
+                input: "52a608ab21ccdd8a4457a57ede782176",
+                output_str: "57119c4507f975ad0e9ea4f1166e5f9b590bf2671aaeb41d130d2c570bafc579b0b9ec485cc736a0a848bbc886cbaa79ffcd067ce64b3b410741ab011c54422568089405bf1e8ddd9e3bcefe1a713dda18cc2b73fde0eb323fa7518de2808c875a6c55111be3e0cd20663b794048f5ff44638ef871fba0f4c2ed41a96d3621606740935e9ea1abefe15a1a3bd55c8ae6b2c021cc772b34da219115c8f6072a09f2b718e26ecd2538e5f12068f577ed7d03a2bbcc7ca7db81d2cbaef2ac8f33b1355798576cd3545b9dc792fdbb9c8d1c123ee0407c6328e09103fa6ce1b4dc9ffb0be7236dab3abd29e704d0c352c524fac14e12fb61929d98ded973d7e8785a8acf52af56c01ce62ad93660c93b683fc22088d7302f72d0dae54553b0c3e6da7c498beb3aa46e7459779a1b0e1fb19556a71635b404c0bbbf3f34536f2776fa12206513fbb1f2a11ce9683460d22778867aba7335210d817b720b3d8a8c48243d128ea2a4ba8996d160351194c0ad3988ed0ac5ed61c1f576a33c914c2bebee0eebe55878e2b43a51e510251068e3c0f7c7292189573eb6af979cdaeba8b8e359e6b632babafe3528773cdd4a1861b7ab2532113f2b259d45598a76d54c739dc2f4af2700f3b5cf22431ed9f73d53caf41d134f5cc67ecf8f99549c091ca6697ff20e08bf6ae9b6be74bc77f26db50d25f48e67a94dd705521f02d3cbd5fd56"
+            },
+            Test {
+                input: "82e192e4043ddcd12ecf52969d0f807eed",
+                output_str: "87f2a509e9d42b0f595662cc93094f26f06a86d79d98398b7f87ee2bb5fb25384f9fe3f7a72ab5de21cb3b7836f73618307242d53937c67cc5f36a7552f917db12a4364736b08671314ebcd3f34c670e0bb066d3e8792ace223608f5a152ecbf9fcb4242fedc1e27143835f0c06320174e7eeeeb60f6b5a8dc9aae97eca494d79b3ddfddbe91d3294ab4c3b3cbd1341ea4917733fb13a15ba34b46f0d5981c9dc457a123c4152776e15b37870c24edc0bd9cb73cfa5d290739c17289c2de3a71aba0dface3b76df71cdb67697321772357587e3c2319c15d867a76f5c7bf5ca2f523265d4118ead7f96bb30349f5c4373d5e4fab4076ceb6ab8c11ccda6b7272121a11f00f67d7d5ae31e86edab458bcde042c58e3d3368dc485bdabd40a3f6b7294c038b8ed3026e70ecc9ec7d6060504f931aaba816d5aa5ec9fa7cefec123e71c5135178f252885a7153a4714e0d9c95af171a6aab936f0b464ab07e32aaf29cd4d931562f700ca1419bca2ed1243f8ee1b442cdb1f5252225954136e2e80a7fbaf9095108647aff7f31d4c4caa050eb1a90ab1d1ac0f67b9f411006a4b76d5cb4b48d2154da87303ed37c9f911064e4d2f0531474e98f3f96b1a0a008ddd0af4b86435f8b26bfc7693c338c6af5823ff7a9befa57d72e2f1bb2982da356a8b3d08d4c19355fd6efb35d68b3a41144b49713a470bf61d0ca05e52044768cd"
+            },
+            Test {
+                input: "75683dcb556140c522543bb6e9098b21a21e",
+                output_str: "20561970bf01e4108bc498da4b8f900a0fa378770daae9703e166898874a1821ab0432d7cb1d0a7006e5461dd3049387c4116327d1d3e0755cde00a3c40bb5fcfbde5ad0a7e46650ae7cb37dc2f0e4f506dba47437eeec9f823acd89f3eaef767aeb39d38f8800da54790f362a3c183cb9bc420047ee86b3ec22e2b2f4c029ef64a5270c21255d39363894aee6478788436c758e4101f2096cd7f13fe76e54cc5cd85c9183e6e1a1a3a218379997aef9da643d8012f402fbbf88e6d0ae991ec4645f3118fef0f66d7c8ee74528d622e1e9ef1a69e39ca7ea0e045bb568980d4659ed20f0ce68503620a94ed7d5c9337dc20805d2da7d0f14b5ab3b93637f771c9e63d0b57aaee353aff672596c4660cb39381a9010600ce93197cc6a06219a3778b89b0f6ae003b5f9bef76ccf6d551b852e076a678a74e75e408e1d4d6b1960488ff21b6f6b7c308205f93bd9da1c6da1de9707307410bd7ae22ff24e24bbfdae849ffe2666b1bdbca2e08cf9d0f3f7698c4f983d4b92ee28b5b4b8bd98c317aefcb41e56dd5534f59da6c84b3d21587d2ee740f54a0c7fad62a63b98af747237b68f78a39cba4596f81a223367d34557688b324b5335cfaa67e78a8095c92d70802a2aa76129dee69b91d175bdc0a485a58c91cb8ef326b2c8d1d82325c4abe4a0f764fc01a9f0a743e7f107ce384dc223d7ad7481ac8ab7bb273237cd735e"
+            },
+            Test {
+                input: "06e4efe45035e61faaf4287b4d8d1f12ca97e5",
+                output_str: "f29097e10de56c3a4a24746ee4e7a6507050d18e40f1cb8c701b5e589fb645a4e400a3fd2c9c4d48e57bb9e146abb1ef98d0bbc6375c266754c7f1cf62682f0c6a6d6b11e2e0aea41533dcdc851319a34fb197d56f4a35d3b82c3d314eca59e03774e84391e8846d236d0cc51e7a5591205c6c1738b746e616b2a8267709103f51d0acf3156ba42cb226be3e94f2293e9e0fbc19bdf5717633e17b5944a02505cc53b01325d1d77965295ea6b6b50e12941767f7288b9f4e6ccf3f567a1ea3d17379bd1ddc357039fb356d9457956a8e149e30aa5092a4f85dbee2083a62610f04fd28a5a1880183366211287e9cdbe8b261e93557a38f6ec2d13fcddb5dd905599b5469257f3f2e83125dae5f30e8e7514d55241121d968508d1fb55c8f339530a437bdbbe04c42b6b229666763400f5493e31caab061a67accf41954c2aa0a7fa0087a4b828a1afbc62ba09e91a3aa44fa4a74652882b7ff38c9c1692bf83fbaaa17f32dee6d25518fa0721463334fadfc6d050e0cb195e477150ca1198ebe4d19ecae1b1321003823bf04d8f9d4866ba3013c9a47ff0b53fa6c70f57d220d86e8bfe71a61354f099245004487b65e7c45e090630e6f73fdc56b2efe6b3469bd31d23384cd4a830a716d50c7a91dd09a45a79f47d73bb32d14bbe85cfb56bbaac47d973a6f3f9fc23edd774a31b533fcf7e78a2a75872c5954788097e04845"
+            },
+            Test {
+                input: "e26193989d06568fe688e75540aea06747d9f851",
+                output_str: "bf4eee53baeca39e2884780a1f007b5069e7a90f1abbd12ef77c77a4038ca56609d52b9bee113536d8fec7d264f2951072fadbf2d3a0b21690ed5478a540c02d903b3675787929ac44a2bdc6597b2ef2956b3640b3771edb189e98fbe8fb4cddc8c641adc707d47ea2dbe17616aa0acb4af8d7197626577a5ab5a71af7223327fe96c4472b3f21fba242416a266bd863be3598d57dd910a265335d17a7b51f59debf9f4049abea37cad33b8f2032a4fd5fc6f124044fbf2a9e47421fd6c1488df87b942cf01f9fc7f13f7824c7c09aaf6d739f4e3876b383546ec682deaa6f633e630101646bd1456cc22a7bac50190548ee56c5fb0115809be6b1d7cf5488a26660e0a80dca89ef655a963e8013a61ce27da232430183d41c9c9af96c14e846addf3684782e207916820f57e04c60e999340f9630e8505c98f467e2a122fefd1031d67789f890be96d7b629828cda153f9cc19bf8b6d0b0716f931f17014d9ac4b6d983dd41edffabcf33693f7558dab690f669c53c21a4d8de7bc32aca6cc45225a2c980aef2307a7097995d97ee060005cb965512cc85cc81a75d3f2f0975183d9cee293bc69a06c896634962369e01f475098c62d574a0d6a57a5fdab004ddd8c3d96aefacb39b3e4e1523447bc8fe397b488d8a5da6e4978aed897ad0a2fb88c5ecf86cca7a67438b988c04f3c14a754a74ed3d03d478ce9efd752c0531"
+            },
+            Test {
+                input: "d8dc8fdefbdce9d44e4cbafe78447bae3b5436102a",
+                output_str: "a697f36886208cfbd55c3cc1c407c3f978a31574e4b9a790716e601c6ee0abc421aa5e5488b57e293cad8af40065c161407d0dcdfcbd172ffe700b60d7efa289c4755733fa535365db90082eee0b812442e367bcd4451f152fcd54687de4ae20f7fc60fcb3dcd1c419edf74251ec84471d35e4ea43e684995101acaacdc0d8ecf5f39840850557c70be1477a2f168cbe97fea85ea188594a4bdb583ef9dd2c5b682774e7e7e0cc85c1723cf91603793c711e2da65869be3a24d481c032a8674c1e0cd91a267302cc084b53c84af3d0a7d350bb62a2f3b9027e1f253c24d481a34ab8d8b164a78b0a60c95c13454bc4ae87c5e4e101b7d04c6c3f00e6bc4b4bb922f39c87a4ad843704e125f5cfcfd8a1e8e894230cdd7dbd7bd40a9cababeb5bae9cc49db656ac90ebee4afbe3897b0f7a64059bb331a4767983403df36c919759ad6bfa379920594d0f775ba2390a522c3fa7b0348781155edd29be53891b41f44e16bc5c290c1cf31ec33e66e588addd70e79fb26eee21dfdf40a3c54d8e1cd79f2848b4238f7b803891ec01623ad92e53d3ea22197df29bb6554aea8cf2d29ec4b673faa0a0c64675f3bdce07288eed03d980c36e4d10689dd5e525f34df78b1e76cd87f8fac22da1db1fd9533f58577d136fe161a688f3fb9cfb42d909efb98085fefbd8d26498a847c9493e02e5364290cbfe45570ba39bce1415dd5bcc"
+            },
+            Test {
+                input: "57085fd7e14216ab102d8317b0cb338a786d5fc32d8f",
+                output_str: "da7660020d2eff07955c3724cf85b1b9533278ffd2ec05522b8a876db92c7f9998f0f029b2156d630df390b3f8f5a31a8e74b943d6b36e1c97bc4f059408de495462a8e039f590d5fcbc3965a663f33be332f9e56bf37d9108554dc9fcdea2e771a5e22ede61ad5476153969d1ecf5abb108bbaaf6323d7e570b2747ec04c35e7de5ea2ac0306042caecf38b0060984460d000ddd3dcabcdcacc83414e56ee2c44f6d6dcf4875eedcc4eed761b62e1a3386970571ee127d84563034f1ba93d2a84310956c532f0ec4414bb01ad19beda20c714125176ec202a9f8f9917359794239ddf0376fab51a5160f0fc5cd16e7b7dfb0943cd524064104bd1cce97a342035fa47138c27dd9fb00f6528409e10bec016503b17687c66f2a00072b6245ec061598da570f36b9fe8f4c35e3e8fcb3ca1a8d913feab1890c8aede727e63c6085b5c196e82bbf872906c81440ec8b0a65b2271285616c7111c702964e3232ac34e7cd4ad5f5568c9e30b813941c02466b817cb1523d6717e58b4eccbcd74a923e806d82af352395f22526e06a71585b71569e87c3d1aafe8c06098204042cb2e41e92117e4264ecd229a7f2bf2a9188a53264195766707430b432fc332e160d786a9415a0260dfd91482b683aec0e62b0d1a480650041eb7cdcffdc9601ab353d9197ca15604351fc226bd574c3b66b1c6227b7cf6577df01520214a961d0403"
+            },
+            Test {
+                input: "a05404df5dbb57697e2c16fa29defac8ab3560d6126fa0",
+                output_str: "f887a018985c64ab3d5609be2121e73f7ab70d4a90bf47660e535b72dfc0a1df20ec0c372862bbdd1c74db76a0ed12bbc032283aa5fa615af320e1c15315ea171eb224184691d13d38ef39debfa2629df136fee74c49d61282db8dbfd0cac30b135330dd4f25644b73fe8276c66325ba588c7178d39ead3c8db5bfb6a5f30f590181c84c6b88c421a4ade52b6dfb74d1f1d82eb206fbf8678d95442db8292189ea349d3335c8a4b57e88c4f91b12cd0a3fb10830783869acc88ba943acd63acddfa8634fed8339626233614efce39d60dd2d8b1f6bc87799c4b7ebbb7d407c5621e56cb2e8d3952e07d5560544f810b2bbc56054dcfa0731a9b67067cd1c8c4951fb2ad6466098da17c9547bc5831646ac73bbd06e596aedcc57804b01eb817edaf9d46e3728f003d286b95664317361ef0b5adc00dcb1f6368295656df2a41c950367bdd25ba8db2b6b7aeeb1161fd089d02e35bb9188e7a91415dba172f906264905be8ee1e9da5af53b3acffb44437157dc275d26323402c07c77070d479cc89afba181029fb97f9f0c9df1b4be0f0b000a218e380cb84a40abdd79e267578ee379c3b674a25a30e902400b0bfa6a69cb7ab96661781e7cf05a6f225f301065b59c033c5d873a5be3307b6e59708599595fab5d2a91c601fc75e97daf27b9453bfe95029ed5b7f2b95c35377e5153de2fe9afc847a82888e9469e8ddcf4e7"
+            },
+            Test {
+                input: "aecbb02759f7433d6fcb06963c74061cd83b5b3ffa6f13c6",
+                output_str: "2dbe1b6f378f1c56aacb5f9a71a12eb3516942f2d45cd4628e2d6dbaaa4ca282d640806c927c93b3dc6d1c96d528fc2fbdc91d7773bdbc26b2e5429063889f0842640d4eb0a69f2c705a11fd40484f16a0248077897c8039c575c1a1c7bcca09952ebb4914576c9a9d35b2043c7a5ade1ec97b6d46cd647815941164bcd8d117e5c4892b6a5a5155b066bca61a9293e705edd00ded6402f12d0dafccf608391f24657283102c30e71777b7b9f39f069b90b44a6e84d87660d1bcf9587a25eb59f814cffa8cbce7d7eac35b27e8707f65f5b78fb16be7c17812857b8cb6a447bafc1cdf793f83b6d29824b3c355ecd204631ef1e176b53a6b82fdaf3d224851fc7bc0f6b83a6d05d0432fb34567a48be56368272d2012c0f296324ba45b7438f13759a4a1af293c244c5b326d6c68d28a5a3fcef1ae25ceec38d866d747d62cb9b5f8cb38b047151192ff44ffe1b35b5d08e95344e09bd7194cac4d66722c9e365f3c0b7b48fe0a2293e478b4e6c8e6b7c93f41637bb0fd15fdc24e6443595faac6c342e8def79f01dfd96e624a8954b0ae93591375b8fa6d7eda21578a51ae0eb69d97de7afc1f4fa797fa6d11d5c2663a8b09665463770000249db5a23233bf83d36c7a15d3e8673f52dcc06270b246086e5ad0648236c68efbf04a311a9a090c72a6a79116ebba4bacfe7f46b5630f27c99f257a3c563b864933b8fc3672a3"
+            },
+            Test {
+                input: "aafdc9243d3d4a096558a360cc27c8d862f0be73db5e88aa55",
+                output_str: "59425fe5b259ead7e04232543c65eb5abd0c4db6f9e03c184928e877805b9e7ec156d8c1bd0ee27e4fa931832b41781dad3c7d23bea681c74251b1ec51a90077356d3c5ca2a2779bde6f45be6adc20fe6dd0bc489b3d6e43dec4ff6e33a24c62421a20b8740ba1e13bd6447e2d6ccedacb692a4468c898f815df88b8a3e0240bcd64d2277d8456642cb129f8627eba5380a9329932977021dfd641498b40f8d75db5a4f9f62ed2efe831eba92ea600bc95152b3e2fda2873f54800c15c2256768099ba5acad759734533e8f4b5c729b42fcaccfea0d6c7b5dead8a5a1d0d115836d63476eb3c90325f3ffc48c964f69b2957e121d9501405ecf5cdf5c7827019bf4a92417b1e44c444d8b714ee85154bad6462317515cf1b680aadccad3f3b69d70875020fa770a0f7a969e4b1672dca70ccdb8d7122a7e8ae77ca7e0819d6cee706d71f0732dd1aef5106c65ad8c66fd350c13f2d02237d2b4b9ac3dda52e3771fe5473c47c77bf84dd90ef38104d8571ae25f6b7ae6b292708f0b967a998a6d8f66429c1c81ce5c03843877ae4c56f14fe4f5a24c8f93072ce79e3a3be409d902881b73d9bdd3aa0c8eda88f0511e98eb93b271ff5f244b956b1da8c7a8f377f39c803355f1d70d55775c7fba96cc98c02999a47eefd94e52811faf30c099078c7c1c50772057fe65e954fbf28cc414cbd5c2eb12ae86a0912d3812a04adfd"
+            },
+            Test {
+                input: "7bc84867f6f9e9fdc3e1046cae3a52c77ed485860ee260e30b15",
+                output_str: "48612b3a4374024bf509409fbc6b12e049f2f5065a0cc31c49eedd57ffd19f1c1af6263ade73b4c29aa77e5c05bc0aad40c904106a19a8fd55db489ac77904569acd0d62f18bac28a287299ef6cacd0b342760abae5a35a2e67f85e854df55c5bfe831408c14ea2b0a3c0ffdf29d8b9fea747edb856df6591b3cc76d3f4bc7770e38fcf603f4455c9b5019b7d8a2c939340bec5247e597cfce386a458bdd4ba5007d03bc82bf310b4a8cd328a62e2fa1e8fae543736c10633b3c70b21b98c769adf07567c3f6d89a006be4b2ad21643bec00de1ec9f7ca7ca733ecdbce3c58b45119e5f593dcdc5c95bd07082cf5d9b9a1aa11530e302e1fc8d6d2fc3b0fa834ae3b2e98b428853c8a1b9266aeb7b8436543bffaf69467d7eece47f2dbc790fcf2efe2791213482b641388d58b504577430878ef15485e437a4a1f2febcd994c088283d92c90975c976331d051ea2c2ea887a20df5c90e4fc77a9370306152fd2ca6c6410fbd529bf9ca22b4c8ffd4444eef136ef0b61276e42b0d0424f2682f291c7a704aca96b355aeda4d382c16b3ad879bc6b688197294203661f21e3e881bbf4265c6b71431b5dc29f614e090d723ba086b23051b00b7e81ae8d2315c41a90e1205ce8a1c5a744f82b7582a099d61fc5fa6b2e9a28920e503b32a84f4831201daf2baea8cb98e034f7ab63655e670952eea74e3ddbed01ea9dca9533184"
+            },
+            Test {
+                input: "fac523575a99ec48279a7a459e98ff901918a475034327efb55843",
+                output_str: "775025e1e1e0a1c865e2b57b7b43ed67ff002df27de0a62ac1776f894e1dbdb2921029afe631201298cd5d51b9a2a6e49717e68a180eb27b9954a807667e4d24024dc3a60a60a819edf2870260aea535698f9b5d83b820013547e570847ef9f4563931138791b44ad298217000f039a9933ff02b99ab66a571d2d5e16507dca9eef54b1910e26ef361887512d646cbad74f99deb082f7ad971e2e9ee37af77b80b2a763de07d91229e8b5a0e9bf220b0c15dc939253bdf45caf4a8172afda5d096b47793461654341d08599bfaee496369d5d6e37562f9aac399a413ff892f9dc07e624ddbab1c72fa0f2d1aa98ec442bb1bbf7609074e61ed16d25367869a5f54e33b52dee5020b9ace4dfe5115ed049a6ce62227661bddeddbf77ac1d45114cb734d9cabc634908ff540c2ac162cbaab655cb35138cbdf81cf5318e92516ec9c4cf05e14547cadd18093755458621c0903fe6abc29ad174187f0d5d6b314cae5a4f9586012d396bbc69d81a66927352a9f4b926e1cae962a73401587ffbc6d9fafa35ecc1b678d0d050f790bd8cf4b6ea3c3b663cd77fc6004c257328256f26205ea41ef7a423cc757e81bd7bc408988dab45e8d632b669dcad4585dcf6348c8c5d2dc651a4ac1806f3a55dbe5fae59d50e2b9f25f89200dd88baac59c14ea0798194b90641642b425317bde993ad1467200432b1ebf23440d0f789ea5a83d"
+            },
+            Test {
+                input: "0f8b2d8fcfd9d68cffc17ccfb117709b53d26462a3f346fb7c79b85e",
+                output_str: "36da0700fd13a62a128d5c87f69863a9ee8dfc65e5e1f97c495a675ed8253cade4f79d45d9e34c8fcd3d5af760344fa76b271a916a539d467f9fea26df0cb98dca0409602910d7f298d6e93600eae6447cd2ede4a76526014fb58abd4a48abb38da5acca349f140cbb391a6705e4e153c87a80c93e912c912b9c97cb89b101e6bcd0b739cf89d18b522a1ffb858b837c643240dcc8f8553508596edba0282847ea724b5d25ce6704cd3df3ef40e5410d0c6746f97f390dcd77f69e6c41cb009ffcc9ef3c6f9b2daa646dd07fce398a9603bc223aa22af0676931d4fdd5d2c06c6f2f4d31d4854f72e44ea149ed172bf152cdd08d33af58878b8e268ce44e8246360ad41076fc4e9bd9f460cf5ad24ea05f4e32ee2af4b1f56b8813599f23ddda7fbd9195a40c5683988d1a84fbfc951d3613ab6ff84d372aa4a0eb2b68fff9b37ad1abf88725a5479e77e55f320bd8bf69a2e174f715b10d8ff4e8ca72f2e29ab501f9a74cd4ddffa99522d1c48c619b1669acf555f5e5221d34c7b36c56c53c3ea3ac302c197d74735a1fb295a39ae38d87f451f86c327b67c16a1d1be50c453f3ca5c9bbc5f78d7c46f5fbe1b44c366159af8797fbd29c6b025894b66266332078860d083a58873b8edde27300b4177f4b1a70ef2557610f19b2fd8df4692fa548a018a014f55b90d77ed357987a033ed8e83e07a5d5d3648612854eb10430"
+            },
+            Test {
+                input: "a963c3e895ff5a0be4824400518d81412f875fa50521e26e85eac90c04",
+                output_str: "4d2453d01b5b3fbf0fbc4e6f7d2f28914efde730877568f3da9ca256c3252560dc9f9ac94ac203ab2a3829a3202e6f4d385d215b843d64b52b3cc28b11e3876248b4cc692d4f7ddd46c36fb7292794875d8353d945438bff037737e3e9133fb6559cf65e7129b98644141a1e5870b22751076f4af9a14f2b0d198ff4772b91f4f5329b5bf9326fe39d5bea9b6d4cd19beee8a6b8fe1cf3ea3e256c7e1a6a95c5b9336ac8cd2af6d35c776b5563563cc59906abf1acfa707ae71e6e52d6a77cba9e960bce2d3c11e7a6ad237874f6316d982207cd5cdeaab3c5eae28a3e5364626891555721f81068f60301b1db9cc8d8fe00d9949ef2998273bcedf012a9824b5942831afd4922908624f4c2d3d218fd440652f59f536f8b33ec88cc3e9db8a4513eb8880b95f29876c4747a8f83d089879b29350dcb6cab4497a8eb14afa848432310c213d7439968d4942cda32b5e6df26d29f42bcd98fe7c67020804380d0d9e4a931ef9aa117f872c7c0aff2e5f11451af753c383144e60e661d6db11fa78e542fd2c9df493da608cdead669e0ae4acd76744cfa68088420fa24a43b6e2c1706a10db468d8a7b6e18ce68c4eaf1cb1b9d794af9457292c2999dc18337531adca5be1225be1825b31427efa14be2b500c0174333cbd3553e05ad1e4e27858bca6f2bf2a966a8eaa6012f4ecf1f3387f3e3409d3986f2e2bf7dd239832c9fb"
+            },
+            Test {
+                input: "03a18688b10cc0edf83adf0a84808a9718383c4070c6c4f295098699ac2c",
+                output_str: "2d46d78b2bd91664cf875974d2cfdb0ae27e00faedec3370c5cb83129ebe05ec438a0a02232601c33ad623162b8bb160f5d8f5c892bba4606d1937a1e4f90782205cf7edef07c0edacedd95f486157a0c64e0303d30029cef36894100e79693f3e794596ce99adbaf2e3d4b4ada5d43b9735de4b24520ea9c8041cacea8ac659699df823c7be9ae82d52bcb294a43a751a71f6e0b939bf9f0831443026a292058b62817fc9eb139dd0637b7efa73344858078aed6fe93a6f22e1e14b92e87cc3cb5c4fd7170413c4949e5d06ddd44fe90ac4ebeae413a7baab1fd2b99baff442e155e94eb49d75efddd9c0bbb6c1ec6ac6496145c755788dfeb766ca0256df9c658b7bc660808f875e9e38b3e297543d2c9032b454161f9cee80b0a7f9f49039728d2f12142ea22c4708307b6593cfd0ef5f38a1e29fe43058a735ba02d4edc010c02f4b625aaf832030949e81264b213aa8a16bfb10d35c5a369b86cbbf4eee8df699b302b052315ab495b9b287e9883b05c6273b4c32fca1d186d2df481f54355da3af3e7eab49c1406857cb9f590e7b1b8ea5b7a0c5dbb7fd778a4fb570be2cb735f21ca599af8903596e80f8379b517d6a0f7f7d5125a7d4375bd90175efcf5316f13c8b09219bc84052b7fd2bc1d55656fdb9cf1918997717c6e2aa0fdb46530c27114263e017fe5d91153fdda221dd63f14c25e3439e05f5dddb3ac966"
+            },
+            Test {
+                input: "84fb51b517df6c5accb5d022f8f28da09b10232d42320ffc32dbecc3835b29",
+                output_str: "b3dc434bad278ece68c6dfbac1416bf47fb37645ac6e6b7e4dfd79e4605ee32b9795ed18683fcb56f910e223704ff1200f015eafb2ee06181e9eab1ba17bc5d84bc22a2d5c134991c906a71d8b20f6ecd6bbc27fe715edabdcf1c4e1a374b15ab4d76ea6ac580904bc66010cd8352caf365da80094f461070cffa34a86df705b87cc277d80196c86c602326e8e3aace1be7f0136c0988faa11a2ff91ae941799ec4de96e9f167e4088c822bbacc46dfa327df7210c9b31a9f7306ae753152a86f9e0ecb03fdeb7415c9adba6d61fca7f4d3c776ee6fbe6901860292fcc6cb89fb45a68f6165e36885dd40671ee372283591bc90c2b4a542282b13bee71ebba4e12797df59fe47649a27af116da9f41e0f0b6b962f7260dfa2f569a97bf47405a4ec4a6463680e3903cc7c3ca2f39e9366fceca8031da89e447b37f3b80769fdc0449291faf1bb8f9ceced3c175062dae783f51637581e913104c7042bc328e1f2571caa5572e75ee3f5a0f559b50191f3ecbc1ffc039bd3dba90f7007aaded690ff35d8d84fd0a9d427b2171072f1ed51a8ea9aa8a066fef6b88915265d80ca283eab1056b6bca093d60bfe288e3b9029e5aa395c9f3e3913d4b22bada270a282ff83c963e97f1f7543aa92b5f419973671ee03a79d1392c40ee57265fdaf75977c9f0e98c2ceddd7f7c52b4122a4e517280c9547df99ffb30692ed39929fa16"
+            },
+            Test {
+                input: "9f2fcc7c90de090d6b87cd7e9718c1ea6cb21118fc2d5de9f97e5db6ac1e9c10",
+                output_str: "bf7a4fff6c7b53893bfba9505594dfff317a09278c3a59221b8dfbdbafd08ee237fcc272ecb1c7672b41b8dec7d54b988b4cca65cf297e1d54da65a176350ac489947359e11e34ab3e4d6744ead1775df90bd5be0712bd54ef46dc279587527976461d6b8f9d0c0fe14b10372550ecf74b3cb30c463f25090abf7db84d32f51e8aee7298c49607e4d3dd79b9348e33f2e58a7d0d76394c0b1c79642cf2c3077ca0764f291ff48a8cd723c953276a829cc1e7b798beca33e8b0fc0bd44224cab89ba334e52d6943a1ecac72ca3bc825bd61dc4caee1a12e053ef31115456da434747aa8d6defe56e35fe67d5e761881d681ad8efd3ad5c69430ff75794faea5553fd91a4ecf7730ee8205aaaa0db99aede2c52591696514aed17f7b8942026ae16d67588a943e5d13bf47f15f1a458f06ed83a48641941dab491594dd02c681950b84718caef0e6187f23c89fe46a40d5c22ae297a05e8b613b264d204334be5922a6dedff5b978767233ac58925c672f4f4b0b77326a5b283cb1df217bddfdfbf12e4feba42e23c18675e0fbf0269e2d53a024b4286fa90685c2d8e67e3a60be0d7072c3ad8be9f4a389fbbafe191cf06eff95605a89c3c668baab7657a90f23b6b791421d214767736cb617bf1481ce103768e5a8a3384978eaa8f56a6f2e729d6307973ed19b270247867e5861172467821a22872e52657ba2ffddf6052025"
+            },
+            Test {
+                input: "de8f1b3faa4b7040ed4563c3b8e598253178e87e4d0df75e4ff2f2dedd5a0be046",
+                output_str: "2ea40ca6662a79d253a43db2845535098f8f4d791e45ef610b47f90d0f28309ec047bf1c565f799253e32a3c538ec6ad842406d9bf127cc56aebc442b4b8fbb5da5c759e1be0c201246b960324a087b3a3093ef07cdf45d915c2a4b0ff70d64c1611c17c629be9852cc408afe212fc303c196f422a085a72684c10460e294fb60ce9f2d5e2a599e4f1e3fab86740f61ee2dcdaf7e1c8d8bc298f40b993cbd0a8edbbe0eb8715b6a58d2cecd21fc637b02e05bad75e3b8ef0c2bdb157288f763f0b190468016c186a945032572e71952325d30d2dcde2a915169c51d0c448644d785ac658b0f0132b3cc96884c41ddead9b57425fdc013d067697c0fde6a2dd31afe31cccf9d85b46325d6cedd80b70ec717278d70c4344757088906a577c2eb030f8ad2b18a1a196de26648915560d228f702956b27046ed63ea6bb863f797cde111a02b19a6f49bdc7eab20e040938b9977d534bdd01d19b15781235c249a24ec832770a76520f5c0e5f5acc6e6df757fde79de7ad8c43028515b82614d0da808400c574e5a982d0cf9461bd25eb6521064152dc7bf3295595b7a16410012fb01aef4ed6ecf22c209fce011888e29b8c3f84cb29f42ae0ec1c4c6d4c02619f90baaaf7219be0f2129723ead133eca7e0d50478de346f90089baed5d1d04563f64e3a3d5e228988d71da3df85d906c9afc972ca6314482ba62c557ce7ce8986e"
+            },
+            Test {
+                input: "62f154ec394d0bc757d045c798c8b87a00e0655d0481a7d2d9fb58d93aedc676b5a0",
+                output_str: "489a2da0386ad9f87188cef4bc2b22186f74b1561d79d8ade98ec2190003b99795dafefe1851276ecf233ec9acc0142dbaa3ff1d94692430f67c2b1d809a88a683b73e00bbd678d3728ea98dc1a751fd5839b8efad1f4cb45009411b8f9b9442ac797b55e1827b0b6fd2a4b1e9f078fd43d9553399b9a52e7567cdce4a27647820d8483f16360104a7ac8f3594cd786f51a9ed172443bcac49e1f4b32e4e915a3cbd7ac18fe691e4b9bf35f31d1e8fa401ea37458ebbb1cb6c4e99c6b031c6c6981d95422ec1a9af5e74c0218f403ab62d54e28aa116ff96ce0d6e8076420846dccf95c9aacfab3a4864f93b5d3869a7dada5bbf8197411966166b2f4f52e3150fe802c96c47afd6a9f64f7554fe3d52b79bdacd6c95401c9a78f11594347e77f727acd5e0131cf898c4f36dbb067ee05e438b6faa70d8b7720eb94728440147b159577cb5cfccfe9a9ec321081d429ff88c4abe02c7bea2b10b61e521889e5ccc29470dc16132489fb43092b6c9efc9517ccdc0b0824a95501d74b44560662141114f0eb6c7a0b469ccabd358546cf1df37dea67e3946acd70a504a787acf86b07298938882d0b67ee67d69a8cabd0b835152633bca5a76c2e6db958fda265756669d1105a67889f83c01918398bd296ed801a0b5f0fc8aefdd5205793adb85a8d6ea15cfbb6a82153ee69c10c2c92cb38c90ce0e73e32489522994096f08d4"
+            },
+            Test {
+                input: "b2dcfe9ff19e2b23ce7da2a4207d3e5ec7c6112a8a22aec9675a886378e14e5bfbad4e",
+                output_str: "578b2d3b14b19c349dce30cad612bc2fd7ce8d6f034fbf4d328e7a570eadef3f9624b65251f992132d25e5363bd653122d5257002f806dce93d0b15919ff9ef2c303c748d9782588c90e3b236d51b69b1eaa1301a703b8b6eafb6c200745d5b08a07a69b6204be3db36cf6127e5f8399e5901318f9f0c18cef9201cbd31324d87ce630a64518aa7042ab3e2c64f39231ac3de7bbe859cd3a4d90109b2955fbe75a38f45c4b841c7e1e32f22eb69db97f6aa4d45d12ec5180aff7863c17fe1cb7dff337da46f7f5b0dbef813b40dd67f985c978b9eccc5685e059f55e503b5be924769a11fe1873ea406ac79242ffd6d45334d7c51fd4d1d5eaa28e1388e3bceb4d67320d9723d060eff815766587fc11c13675dcc53f30ea1660dc8c20332a3ff05e2e70ac821e0cd250132a59dcc4f40abbc8783690fab8bd7693bf106e8f8c7a6d59495fb7301390819c87c86bd94442185de8b4cc784a690d742a439f73ae7e8252a3d5c0e4c0410fe919cd7a53f85f522c138a3d654d9b947963bcf293bec3d253dbab8fd39a48a340f8afd75c97519bff4506550be8f1c1c7c345c89edaa8a56f128af2da8e86a19a6494bc33dad412e6ddde813e3338d16c4c34d40c2e6e1ca61faecb934d4ed0bb0a19d3ab88ea32f7e277bf8521aa733d7240394733a3a1fd7623463857e1633f0face8bb83437dcc308e4f6791d8790a54ff8e06f8"
+            },
+            Test {
+                input: "47f5697ac8c31409c0868827347a613a3562041c633cf1f1f86865a576e02835ed2c2492",
+                output_str: "abed83f7273f3c7a73a700565f16aecbb0e03d278594a29fac83b38689ae49a72411cb6fca5d636eba8c560cc038b47da874429be7c50a9215b5098f94110ef4e38f88d8db1c483d3ea4728f43b25d94e0c89bb50c66cfa25a62fbf536ebe3d8e7e71529ec5333a2823de42c50f02414c99cfc61b1e7b4c767828748216bf6b14658c114c52b7a53c52a3f8bb35048343b19c5b19fa11fcf5d78769f1712e6f8fb5b31c017d3e23091b1e8184752ed0669ab38e890d3d7880a71b0b22149038e81af04c4cc7ccba8487027908cf2f50ef3d6563141dbb9b898d06b7253b4057e9a69d026a27f5df48bbf2fee2b603240d44b9453ff485b2212828061ceb54cddc17c8de430d2e86045c790b23c84499c6bb04151bea457c8a18dcf0094f969365ae1f25032ae0524c2a09b69f71bd3ef46e8871aad3b58c92bc4b694bd5d47a8a80ca8daeba6584e5d5b4d6b5671c823e6f78d8b67a6745236bf675e28a17c2f8cacb4b5d167991d27813c5500951a5e78086eb87c18d0e26863260f6919989f5eb180ea48de6a3750b9e2c1f780230e0070e216d373d3e0ed3daa0f668a8810da759cff1494e3bd17b369ea71de73cf0e7eb3912515e454544be78178db41f9fbc4be73d1eac8c015496b08839344d963f070e5aefdbf29bd056b77c2b98826ae397ece0701dca8aa45245f26d718d9f46c90f34ad8ef70972acc600bf5eea9"
+            },
+            Test {
+                input: "512a6d292e67ecb2fe486bfe92660953a75484ff4c4f2eca2b0af0edcdd4339c6b2ee4e542",
+                output_str: "a9d48cdde90093ff80dc7846baecf4c7d6f876703aa4404be050345bf7d2f9ff3f93ce132e38ebea01ab691bac9f8943cb33aae7887e9783e0a11eba2d139a615df8a62ee4ab9e57bce1f7fa19c3b3f6aa88b547f0bd5ac0e2237b514145173ae8deeb6f606caf1545c9f442d84d36080ba514759e3c0d1d3688a3d8b7c28dd8404aa5e09aac0af3c14792d78434762169caa935e2aed3264a1c0a005c359b3b58bb5f9b9a6e5ece5186f9dc26c952a298b76c49138d20798bfcb843d06cf20aa1d540111bcd50c6d39dfc23ef7a8aa8e93526690c8608623a109b1554c840f15e670dc4c33e3bd81784287c3fe98ffcde6aef5da5c0038e31d111c333f48ad6634ecb47c45213f23ac0c5787cb9665d3b31ec2a0ff9c597a4372df2ce34d443a86b8091729049c4ee58e4ed17ec9503360739c966b1b3a005237c668a6258e67cf9b5b3611a91ab5779d6282adcb74958b7d45c06819e78e904b4c557bec431704ffc563f40321e64a7cc456211b5c981c6c987469fce101a81076ddabe22408e949e86457658e07f61f5be6bfc68b968fffe044bfd278bd91180a05a40fe65f26d907d205411b880d3eb4945652fc0c112525e06c4795c01f4b67be8868594e617bda761465d7beebb2c564ab66fbf976d38521f83b8df85a203197f0b6aea473d3cf3946e4dc87739a418101aef50d1a4355b1e8e5e1d638191dd815a5445"
+            },
+            Test {
+                input: "973cf2b4dcf0bfa872b41194cb05bb4e16760a1840d8343301802576197ec19e2a1493d8f4fb",
+                output_str: "41cd43af243be7f0580a9b406aa597e72958d24e45f52a2e1a59bc535c207efcbc9d8b65a567ca05da450458c2ffd58ca8ca3b01617ab6df19a4c384294aa174d728cb93d6d82bc135ec92f13870dcd556db4421c1c6563803eee5ebdbcf14b3ad79edb4e062970bafb3e801d5de4acaf052a6e07b0235b0cfa4cdde1e54c3a0cec7e8401a4d38e12193e7cbd66213b7c7b0b8046220ffafe868e31ce93fe8bb7ead861d96cc5a3edd4820bc2c62dd8a4d449fe9b938f1a55262e7cc25bde92315e329d8f612df71649ee0aaa3983fb4984b6e1127188ea9f3d40590d854f5be570543addd8e330bba204919d7911e56702efba881793087ecf5cea975a88db706fb08aa8a10ba5f72d2302db1a01bf15fcc3b05c969370050cac51f54990d57d9a37790b5e26d08b56de0aafa61eb238687d4396b2899ff6d250f92b1dd2acbedbcc1c0a194ba00da478d0bb659d901009ff593f6a4f66092f67238909056e1a0ee1c8d51cd39ba3794ca92786aab18d03c13cfc41f08373d1275d75fc58a9314133e62c14e05467ec5829967856817e7af85dc0a83af3e87097210e71d7325748022e25194512e54b9b18697c3b70b96ca8d572861d25178cba90e503b84930bf714aafce91cecc995b2623c63f15a1f0f50849f57f5037beec1056d4163d728c59bde6f526f331df17b5a34177d7b05103735461cd325eec332fe02a85b15"
+            },
+            Test {
+                input: "80beebcd2e3f8a9451d4499961c9731ae667cdc24ea020ce3b9aa4bbc0a7f79e30a934467da4b0",
+                output_str: "a0b529dd351c0f7c539bfac5a3302f5e88906a29e665daf30571447c3dce7bcdea802e364b65b3037903c5edbda2412e084cbcd4f51a4024ca6e154da70c4781dcfc7836f06e5e4606d16d2e1bed0d60fb36b84f582eafb152191cf804d121f0f69324156b733dbc79e1355b9b4d1726e393c22c82bf1ee85372cf04a594018c63a02edfbb2892221875f20dc73330edcee0e62cb57d2ba43fa1e8af7adf157a79861fb48ed49c97104c6d89d290061229d51bdfaba62cb77c498a8d71f627372244452549d4f7469ace1e29ec39e60e8563d3ffbaca5804d6660c7c1559879ff1804cf864ae8d1c8ef258b41b21b48400adf439a76c0bdd62fbbc2607d85f4295aa0875601fcc1c3be531b526ed081188da38b0e40f7ff4d7a41c4cbdbf8db3f46c00d2da9d7f8fa3459f60c7419ac6f691473136eced7c342d3eb5a39f611eedbb0ddb3eb12ad67f1be696795b951a7308df5fdb83be7bf1b650c1c9222c22677a4b37efe0cce03d7237699fca345a31238067f83547c5442946fab4e129bddd409f8a0176ce87a341bbc353cf8a3eb72e5c7aa696b12b16e12c13fcd597d864771c43777e8433899f157a0dd21117839d2ba21e85ff2e09fa0ed73c9af26173b9c3b8ac5b1fc4bf7c87f06b5af7626ca15eef79d529454acd23a7643f91811365146fb18cd0ddc3d46c72c7d1e97e4414225a76b55a19b226d5a77fb1b5d4"
+            },
+            Test {
+                input: "7abaa12ec2a7347674e444140ae0fb659d08e1c66decd8d6eae925fa451d65f3c0308e29446b8ed3",
+                output_str: "5eb982a2754fe46d19d8cbf86b4d594d14b421c8ab3ae44762447e9f789271f5a1175ca9b6c604fe8046a9a8c11a9ff9354bdc91bdf051ab6fa1f6a44d0e42977897f5342958adbcc1e612a49b46ee66420e34f2233e8ad857359ea92e3fbe3f84191127833d6bdff88019ba5b6982f446326877b3d3662767c6e91b0a6f9d2888bea239b25f1b6a248a6cdac1775976958fa9624edfa7de3050cb73602d24d13763c2d67a016308bf4c53d9c7b4a95ab542549944b74a2eb30f688b1fc9138b57fb76ab320ac7bd48727cf4ce4bd34fc3b0c2ec0e95bddd0ef0f5f70fd34c6c890982978613d2132fccf37541042415fdde4af368a207d59251f50e14d7a5310bbbd378781df611b425495fc69a2a6644fc6b29accfa9918ebe05436ee9e191946af9cbf15011bb53cced508c4cec0bc4e156d0884347aa46a902f216ed6577e56129b441efe731cf6c0eeaf378f5a29586f5a62d10bab2778f106fc6c3efbf2452c75045d578c38222e14247db42fa60fa6d909e0aec09edfff90cc41b32a9725714e41ffa9f350ff3c1008511534337dece84a0f3d5df085993bd3d5c755b95e6ed4b36fcee70b68af427c3c80386983920307878c1a01c5d782af85c89c8bcbb0edb2274bf7172dbf16ae9ba1cdd7a97d6b2bc2d06f20bd0431618115097621a36c41c9788dc68b95955ea5e097177d66b0897c7bfdaed8487a79e14dcda"
+            },
+            Test {
+                input: "c88dee9927679b8af422abcbacf283b904ff31e1cac58c7819809f65d5807d46723b20f67ba610c2b7",
+                output_str: "78c7d0d0fdb5ffbcfe55ac06f0e6e58c805fbf76fc2d13911b6b63888088cbed5f7e2071f7bbc12063de085394a691dee09dd1dae2eee0dd9491c23b0949c870102eaee2f39e20a62d9ae95b0426c0fa05545c0f128fb53e0b8be090c1c82f0b66df4d7cd0f63c9a85e17844988523296849af7105f845e0f26200a260912128fe7f2265c9e41d7fe587becd50b8b729ec445c7ce9135c95914c6c9686f43a56cf652a6dd275ca6a883651f78e8fcb8168e8dd8fd780735f087203ee1a30b5a13d5f6b7cea34ccca3bd336b208dac5878e85bf147b0b4e70d87f73de0487bcafb6ed9c3002e2df56f215b78c7020a1bc9f433161ba7fc94b4ce3679ee955d80363420768c9c7e3c6696e94eccb0a748fc1f1f402ebec068078862f1e2dfc8cd6fc23fe1051e51dfe3d65b3779cde8824bfba8ab63fef474d648fe4a8f9c083ee0e6cf8ff6768d1f54f313705f4a3d7568192d91e9f0408e8ebb101cbe97ad9ff76a1f347ff152f45d9b20aeb7de7cc2047e47635032953fc5cc5ce45d66acd2e11c77fad0da8dcf15ff123365dc9f35de92838173ebcbda9da15fa35d10b64e7bb71539708d8806145a1892fbd4176b2e9931514bec17fda5cdd82c8ef9f6eb4e2900d039115d5b1e940e8796fa8fd74127fa53990639f130732eb48cf50620a9ddcfb01fd69490a8b5105cfc7a3ea274006f51221c2356212581fb16963e7ea"
+            },
+            Test {
+                input: "01e43fe350fcec450ec9b102053e6b5d56e09896e0ddd9074fe138e6038210270c834ce6eadc2bb86bf6",
+                output_str: "832befaeca90fef41577649b6348182753ebee32ea688306dbeef8665d6ffc6c5a26ec69ec8c90a0fea854893c0c4885a2dca4ae77243f735048ff31b80d1a4c84f055deb1c11f76bf45dad9516899555aafea86a129c4eed1d4cfc7604045d22120c8e06f67793644533202a69b683b2ecb19aed3db158397c922dc3a90b64a8825541ba5dd9afd7f82dbc603f156b9f619a83c7132a0d8ad71205c83aa4a52b6223507493e0f9fab9530762a190c9fc59680c961b08cf36deb67a9a472ff93698fdb84dcf3cff84c6e9d48804abeb6aa47ad62dc9463c131bffdb127f9f63f8ff88d9eadecc6b0e00c657ce54e7bf800b9a35173dfc6669bb54a069d9ee62bafe9b3c791dd51a21994cee03fa37faa5d56518a6b65572c1b3a17ef52f642c7b2cee065282fe742e5f9c9ba5003bf1676ab07439cccfff7d7b76df84e3d99faa269f0475cb5ea7db25d3bebee36b96634b58596ac788c5f31b8daba35211d4708eb1f778ca38adb4c15a831d8769aa16110ddfc406b05bcf25b45611319603c17a40a24cb2c38079e5684b473dbdfb98877ffe06298c33337326cc2ad1baeef678bdbffd89bb1e35827ce296e20b0084eeaa0ab1fc647efcc0231df9b9b5aded6dab34c75e6cbe206dee3e794aa42500fbd837b6f6aa015bb4c923f8f1f769b049888933773cd24b688b0f787a2b74ad15275ad6c4c336cdfb1bd929ace58ce"
+            },
+            Test {
+                input: "337023370a48b62ee43546f17c4ef2bf8d7ecd1d49f90bab604b839c2e6e5bd21540d29ba27ab8e309a4b7",
+                output_str: "0cb8ab1e6149f41d29171dbb444b0f3c07fefde56d9cbd1150fc43e29009e0f5edc50f89ea7cc0ea6c9e23236c6aac72bb3321a51afcb32f9ab5d1051ed244e2a8d417431863649699077079e1687b36f75c995d6a78b87a9e949a56a2cfbcc15cefcaa6c2cb51f054072a05c12fba86b10d303b3efeac18f8515bfcddb1172d56b8c92c1afd4ad5de2476cf073b7fb4b7ddb8fb2c4ba8ab0c53474857f1ff47cd3b1060612f7c564988d2881189248cd13d5ea347f10e1f21e299294651342ebdba1657862306844e274d7b2dc9dc6d92f395af2f5bd01b13fc7c7aff630e854db63ec517fd3251d12c10b5f6c17dcb8990fb39cf1ad3b65f2f019b24591b813d56d661a904405dd814aae4334a8eef7cfa455c994c3e31b9507fc0e2de00a1a0af4dbccbcdbf393391c5aec9e3b4d3c8e5f879d8e75f63078e686a1bdd5e6358c5807a669f89f90d4ebb31b7396c0152d5dbf665d28bc59327bbfeb466f1e7570462ed898a31e386de5538db505fbd1b9020c984a49bc39968a69d5b3e2b9a9b61d6776d5349d4334c3042c0317a2a34234e8cb64b89d29e3a8b6e8799822f57c3c6c739b3c263cb4b283ef0f859305c84d11a9dd0dee36cc8976e6ea1bcd04451b0e0efe343634dfec7868ad52ebc551d5cfc0277b15b854614fad548337f20467d175ef3dbb135fc37367b916ca35e714b998c3553d5f494903a8b9a4b7e"
+            },
+            Test {
+                input: "6892540f964c8c74bd2db02c0ad884510cb38afd4438af31fc912756f3efec6b32b58ebc38fc2a6b913596a8",
+                output_str: "9fa49c101d9901053c789b01a505853c8370fdd00f7fec13abffc91c7b06e1211dc293fc0d52911cc12aa9ced634b398284f3870e82b7f5af9c3298d53bcfc3a3de488985cd1047318c2319b9e2ac85752b3b0ba2c151fcd08c99e1176ca599557d3a63f4f1ebf2fa31ccf9afb729713387a7ceffb6f61ff8162b1cd943d9154ecb362e6ecc6e2669f746b1422904a3dcd93313e4031238b6eb117166b374fa8ae8440a358c1ea7b11b88fddbde57370836644b72c0219747a0fe793a1d77f42e66d2d695bc1d9567cf1a1b743c33ee309cb4956bfc426b06fe20ffce98a72fcdad31ec5ded9ea45d494c89ae577bcb79967cb532b97ccc1708eb2ae8e830cac0953c34ed28be988e89992c9f0c8fc58fd5e7346db2f24bbb57606302b0520d7aae54f3492df6040916af04b30f7f2480b22b93ac47fc5de2ccdeb27a47c25045695ae9f3e54fb27052cb58141918105e0621156ff4bad6a35df5bcaa0fba8d67a18130f117a09ff90b8760a7027614be569fb67659bf0dcd1f3b7d13222a338f9e5736d5dad6032189e149d22d56861b72a561a9da575d720f56c365c5c8bd0455c18b7b73dfa4652c1d570a338a5b1d2a2d00a4387613d11baa57160a513f4b64d91739e032ed72bb2dcfafe6ba6136fb381857071250cf63051059f9ba3719305d33ef9dc8d33fd6d427402ee348324c78920278d6e5b2678c1c4fd408760"
+            },
+            Test {
+                input: "f5961dfd2b1ffffda4ffbf30560c165bfedab8ce0be525845deb8dc61004b7db38467205f5dcfb34a2acfe96c0",
+                output_str: "7818ec8e1a13963c319bd2199294e1459323556d3e1ca05ea11081fd706655c1cad1a9270495e550dd34a71d6d6b2554c2cce9776b30bf0cb151ed0a87cd09735cebbb03a188eb8a1d62ec0fb614bb8d1d67418f91df9e7fef2ea9971cd46a1e6ad52d2433dffe98dd59e0c9f32a4a493acce9e6b2d946a56da432a43e45a7914959af23f1d08f5cc55b3c06669308021c004f0afb3df5bc10a7f19a7ed2dca14297281d49952d067b094a4068493e7df99403063ad007ce8ce76e2a7ed02f7023543e43e9cfece94601379a048a73663a9b06b04704d59fdb6deba49799d3e8052c1ab34302a2a2392b53a5fb9547628ed4f8f157db8d795cdea73f99212297512a04269b0d5f418e2795bfe76e939f8bc9f2137141da25cf095f2b754f6d0cfd84b3901a903445b7a71612539f4f736dfc1d4da1b9a8cfa87f15e34d4a813808ccfe2c9a9a710a1b9752166996ede550e14b55dad529c8a99bb9fe2688cf2cf29424570715c49eaf94c0ea0bff227ed445435e3626f31cd5e887cf1490a9a2b7951ad42eba5b24b02ee726f95e1e6862dc30636983c88dc915361f209dd5603672c9b4d4ada1703f56955015b9128ff7c0547dfedf772e63ad7ec847b946a66b6e4d3dc8a8ec3b50745ff7841318bd115ba649b662c99b973f4e7c26cb1604d407ae95ce967406e70396558ca27abd91fa7190a5d0f4ac89a070f45b858b86"
+            },
+            Test {
+                input: "ca061a2eb6ceed8881ce2057172d869d73a1951e63d57261384b80ceb5451e77b06cf0f5a0ea15ca907ee1c27eba",
+                output_str: "5f6539a11001926ef3e0dffb0142588d4e48ed4a212753128c4c944cc6503e5fd4111583d67fbfd4b2ed2d82447e985dd03cb4da9ccd8ecf25069e84b4741a4c5756d6295e55075601098d996a375dfc3156d5f56e28fd8f3bd4793601603bc999bf93659d63f3b95ad0af1f5e1749df5197c95aeb05c683dcf37e9f362db1dd64578e8ed9c1ccf0a3ad93e69b82fac004abb2489b0734c4cac5b1a9316cc30f44ac42914ae696698862938dd0dbb3d8fa6a53d1f70d25a175cf810ad901d29dc3be40e4f19a5308ccb795f44f2ec364946d99f59d2dc1dc21c5dd162b7c8cd5bbe8f4ca8f606a0ef5b4619ea93b278dcdc2e943455f178ed62fa747193215d76c8f76077f9209a9311f1f848009483c82a82be1a9fa17ee69d1de59aa305da992f709f2c9a1efb33dbc8108a7d22ad38934d2995a3a5d58dcdb8e435d18099d9b3a5f9cab18b940f9e1b2db9bc9768b6d29c2098273be3eb77d07dc6e48868ceed85484a46d94a3807ced72c292fd699acfb6b1da030eabff5456fcdfaae70e851ba49142ca528d91d00ce148758b54f0293e6c53c7540b55288322b015b6067dd16c0cb711c63970cc16bafa980a8c3d8da5ff2236d8dab951a2fafe29fc72257ad99409f418e405858fbd1a9eab6930977c034b3d020a86c25586f8524d6577557d73268d225cb8e38892d3e7f0095f68a98c1b7355b5e331d69bd487fe4f"
+            },
+            Test {
+                input: "1743a77251d69242750c4f1140532cd3c33f9b5ccdf7514e8584d4a5f9fbd730bcf84d0d4726364b9bf95ab251d9bb",
+                output_str: "b3120c516e7a7039b7f8d2a886b4774fa9e14b80a7f7b1f33d1b4faaad74d549e2195e5b6345b19afcdeba3acd5ade7200500bcb9c94d6848357d6fa88cf9125e59d0cbce876d681a68b6ae4e25dd5994d496b7c64f0b9124beac30348ea6b80803ff17c0846e19f9acee413e07e6ff849801c131daf7a36f2ede51cf9d21cc0ed6300ec5d6b64e6fb9f2a9b909deb4069738d60d6f9f6cc50d749aa7ef264e2bbd6dc680823c45aa8d3a349255823efbe4cac62c0d38a4388b1fed31efdc5bd3d6227106fe03b4a40f21f3f0411405a4a80e92f3cc045c7967cb7af2f33879dcf9da5e7adf813091eb357ec9c0dd097b868fe2d715c124ad0a44e2b6dadf5b360faf6a727448d5d7b76ab2c716543a09e2f75d570103a8e9589ae58d01904acfa0df54e6fff01ed725266f7e52b992fb34144568173065e406a1e98d8dde1889d0b7274011ca00357bcd07d4cf8323f103d682b272a98395a60a95237482f00ddd52204332947d4708d9b8697f9ce529adf3599c440e2b435f4f6d039b351fbb198bf360d3a184616b86573e7e32113b1a5e1eb52a1d15bebb3c49407ad6282ee2551859f9cf87d0d8f0ab362a439ec53540b4b024eb49b525ed29626db292d1333f579b1896a6357f9d0b51bd283718d2a7abd8f3786a7df2b512070a2c9a1b53457f27c6b859a2c6956bff50aa7906d546c67786b68ec1df3e93cc60c6968"
+            },
+            Test {
+                input: "d8faba1f5194c4db5f176fabfff856924ef627a37cd08cf55608bba8f1e324d7c7f157298eabc4dce7d89ce5162499f9",
+                output_str: "f59933f9e9fc474342b7bcb8b4dd6ba7b02af5edd2c1824b227bbd2a56287267804534e943ea69b571990ead3ad5dad06ca9c0bf97fea1f3878824782e244d77407e3e83d5f527a1f5bfd8c747fc08c5170e4f6cb114a9cc34e96ac2758782344451bfdcb0902ec52a9fc82087195cd1019a8e5b03e496a42762fdccba6ec573d5c0740391697d95934f983231ed9642a0c6a2f92198b49670aa7f76c1715f3c80648e606b97cf708596ab9d8ddc7d039dea1f4de4d22e6ed297790ad73d9ebc2b1bc55315bb60e90ec7a2fa9a7922fa5a4e824be742edf41693f595571ca33eeaff4efdf58fbc0b9b1cb610ab2e658caf31fe6e0ae74064db62ce339c1f439a55fda0f594635573c511d040cb59f2bef552f38d87f31af2e98b59e9f0e67bc57d59f51204663511865bffe1cfc42b00ac0d69487aabcc648bdd8201362a43ae19a9570def75bcffa6d000962e931ad32e36a9118d74c777f9a6d853496e9638332c3e6d7b0a5f030b2b4198c9b31a82ce117412c144914e784d9b0dbcb8a3320ff22c4f4f4810d5885c7df3d0fef30b4f2272230278c600834133c4e11ae65bcae2069fdc1c863cdd701db750dae4cdf37a2314e39dba691ed7d4a0087b8057ee27b3f6af14ac0a742826feada8c5b5d52557952da2ffe45e7c328e04c3cd61a5d8f5e11b3acb6667a08498ae0582fe0e06105101ccec61c63ff3cde8bd1798"
+            },
+            Test {
+                input: "be9684be70340860373c9c482ba517e899fc81baaa12e5c6d7727975d1d41ba8bef788cdb5cf4606c9c1c7f61aed59f97d",
+                output_str: "5db567b895164625131b8049728a0a66bcdd2b27d37828af41353df5afa10df9fccccc110dda3071a35319ef50821cf1796b5c319d4fae433e8a2599325c511c3c03e6ebb7c10e3be3545175675f7ab719e906640dfeccdadf77c345dd798ac7e2b7ee83c98dd194ca19bc1131200494a4b67428c23061cdc4000762c12565fa1c731a574530d282c2502356a75f03685a4fd08d1e938bcc2d6e7eee748dd1391950a44afd63b73ed549895f0cb38f7d292697994520de110f782b0cf47bfb07cffbcca6d476d468b227b3406f44cbf3c6ef6920b293fac69927dcb2d153350c7c8ba2d84d411e3ca70edd9321cc0387a6dfb84221915094eee0a272f267dc111f18e46c6d82cd6b98933261b5a880fedfd23ab2f7b6ce349789ede97cc034d0e0408e3e3b75d951d7df039700629ce147bfb2e2772ea80c8681d6db87667a63e3ff358e74ab45712f0bc1c747551dd96f72a6290c5e9679a45f37934e7e22378a2bb4a03152dfd450b98d76c233e107c57142b72389350072027bcdf9bd182a304e8b255f28459d96687083765e46f9b4bb14dbc374bb401ea0da7557acb2684a96f2791e1b8db0919365820cd315b730ef8bb83124577e55a139de4c9236182b885adff4ca2298f157fc460972d6bd67d538cba7e32f9051afcc00fcdf797fc8231360ba6b7ecd5c4d647338f23e1f578469e1558f49f87fefe28cd761bde6"
+            },
+            Test {
+                input: "7e15d2b9ea74ca60f66c8dfab377d9198b7b16deb6a1ba0ea3c7ee2042f89d3786e779cf053c77785aa9e692f821f14a7f51",
+                output_str: "b3d7178bc88bd577c5d95a67b110545c8acf8f6fb56b5da15f5738785e6c950347905b928dca2e70cd2a5e574811ddbc894ef7fa8ec3446c7897b2bb2d68a61763a892632a3c5c6a3764aa0f576717ada5ccda30baccdaf71740316910cc08e8272b67521292fe1749026faddea743358421eab011087d10d4208fae8d5d607ee0d89976bcd79a12f4ed8b1c5d0189b0e2ed5b0b396c85b27763bdbf52d56b92e015cf080df4f2ec80398dfbd733519f3915d3f102d0066d425ef9fe1aa3afc8584c8f4d594aba86ad52e71fa77893266c4c606a63891c41a679964a5e3aef1c277d6d35d410eca6156f8cfed13dadf8022ac9159f913c4838ae1af73ec268f9d3bf085639d69f2cc51c39ea594948fcd238d093a799f266fbd90b07f4619e342e38afd178864760ab109cb4949e518305b82adcd68fe6e922d1abab2d132d10e0aabdaf78f0cfb74deef78cbcb422bbde5083e57f016f4c5679e9d5010d4091b3fe61545886a65afa49716ef8cb5a6c0ebba4a2386a6591bcedb3563bda7f0e792cf28d257bd066d44e3aeae8478d093fa9482fc26c77d73dd3150d53d9f1a030063122916fda66bac51c69ceae533f7a1569a3b9536cd35067eb190d2812eb2cd089d3e1db98f2dfe5a6839f5b04b6edca6732837d23f985e1cc9444ac04df0b2bbdbb44e24d39df2f447d72ffb90b7e9c68a46329ed630cdae94707704428"
+            },
+            Test {
+                input: "9a219be43713bd578015e9fda66c0f2d83cac563b776ab9f38f3e4f7ef229cb443304fba401efb2bdbd7ece939102298651c86",
+                output_str: "341aa5c875eb43f10e8de28505858865870e62a9a4ff45bf977b947d0be17b2dcb74d5880fb5316c5c0b5e1c7da24d8c8c72e5cda4a9405912d12ec5316611eb40ae84a903703f67d3817bb73ac7c2c449d4d6d737cbe06c144a20f99dffc12a8f104df9e448a96de38dc6d7f83324fb3a2626bc91405ee5917f3765d9f22887777226be829584d6e0f6544b5e1c25f939fc9136ba2e0c0d6f6ee5f4ea97de937352d9428222667d974f4840fee0770657dae58bbadb5f47eb9c88232fb7bcc6f1feda76600fa2659f7e831129b3e3856aca6d78e0d7c582852503a67876877dc6599c10d42dbb81e6afd2919a18e4ec01ec7a032acf2a8320c5ae348d28cab36c85cd256db5c30ba1f8891005e68f91d7b0cb0ac4476937d1748f2ace0a1c512ad07514e31cb0cfd743e5c29633c2646ad1882176ba15e7cc8427fa20b2295100621a6e01f7ff4f27a6ac0766f9c25934e64546f16f61b5cec865028bd0d7dcafdb3d6912c5786372e1e4adc6cc8dd3e0a0f299b65beac5fae69e8219787a8effefcb50e40c8bc1c3d033742d98ff30d64d72d089aeee28489791f6099ce354385db83256150a1f9b6cc7444665bb95614ae6e6f511cee0c49288b3eb31f9c7d04b3d126a1535531505f0c2710cf6ce7a6db31f043c7c535f89467ce1f6e85a10aaf5486a3a6953cd351d865f818fe959e6e74f2de42c1fd6e219deb6066c86"
+            },
+            Test {
+                input: "c8f2b693bd0d75ef99caebdc22adf4088a95a3542f637203e283bbc3268780e787d68d28cc3897452f6a22aa8573ccebf245972a",
+                output_str: "ba270d4dad10865df673f0dbb9d72ef788689673116cdc469a8cb9c89e6d8d511dbfff6fa38e29257c9a5820781094300c088cdda2a17afbf164d13e360ec04fa44ae98cbfb972a68d35e6feee3ae61cc217487d7461f7315449e201d707f8cd0e9fbc64d92012b22175e677a304d903e556a5d1fefaf8177a8ec3e506354496cd693531adb22be09ba71b4710549bcdd6d5ee1ed3975258c77760725d1c4416ef3f3b45dd8210433bb44882667a2154d41792a37f2b7c5c85dff707bc2a89afd652d83904ec084d1e03496a7f402feba9f77254772904580cffb1e7a0a8d489b6cad6d97c9a5824545fda36fcfa2e0a6f7e11710a8bec33767303fe8843195e9f17b1b75a4625c67e39fdadecada6a7e7755da7742548b797662b6a24194e07ce2e0302feff4671e6cd972324173f14f5a60d443f6162cf2d6a3e2e0a7f2a6bbadacec5f4b43d4aad809003722982fc7af821ae4143d123aea6b7d8550541da9d704d81d9e12820ec03e8443866eaa80a534a5983581f1dafc7f124915d42f9a24887207c2232b5ef9d8ded3a3adcb4d493fa2fdd6061f39f28ca3b489676cce7e0600dfae247a62e96be8a63abb977a4f35f8361b71c8578bdd63f35d17cea1463ae0709353f4667367f0fa0b6b6b6eebfa049be6133350f71e9cc1b157ed18c9d90a1a4d134e553165549c18004279aba0c4ead5f342cc05039dae1c9cfaf"
+            },
+            Test {
+                input: "ec0f99711016c6a2a07ad80d16427506ce6f441059fd269442baaa28c6ca037b22eeac49d5d894c0bf66219f2c08e9d0e8ab21de52",
+                output_str: "c2911768c4579e3876b6abf0a4a30646d8271fcbf3dc682c48c10e41a878609301f10073f3ea87bfd934854147d129deba9124fc69b6e29c271062cc8b3a5785367fdec382d365d4d60e7e63e946154f948b55e7e31a0cab5d25bea7cdcc82d8b6e200c28c7b4946b4ca30b46970ebb415fc18d9bb60c4f81a308becfb2e40f796b8d6f914fa7f134664b8eef9ffca684b296d26bba051bf45f3edb68acc5d0c79c08724bc7eacf702633c99c47dbf4e08af43a48a51a25620c1f16bbfe4ce1a52a60b4dd603524de38acc2be65240f51e36c6533d85a7b0fb06fdae420a7e84c4644b943e5cc4ac48505cf042ece8fbb4ab90b16b7af3ade3e24f871da2d86813a100c82e62f949c3570fb117407ab71a660bb4284a114b1f6817621eefe246cc0169ca7c09fe6684a9709bb5e7c5c09a35b4d5e109e133d23cefff9e438be621577a98d9b49b0f30740e7e3038c8bcf07e88acb767f9a43b60da387b617d6fff8a8d8784513d649ef3a142abac0bcd8159f4fb65db24616225fb4fc636d6c1d94db757e647934ba77c946bb7d010ae5c78e05157466590cbda903630809649bef7f0d27000a9156b2d05db89ac90a91f4d1f295d296d7783e6872faccb70cbccd244bf620d5499382421c8cb3829e756e6b415af3c26f952539d14bbbe56c034b58124ad973a726676b7f278e7d4111701d69681412bdf08731c4cb14eabfb"
+            },
+            Test {
+                input: "0dc45181337ca32a8222fe7a3bf42fc9f89744259cff653504d6051fe84b1a7ffd20cb47d4696ce212a686bb9be9a8ab1c697b6d6a33",
+                output_str: "c2afc53cc5dbe46697f64d5b6b37bf1db7ddd06d54ee9da7873c77d91de47377dbc5d525ba8c14d5f24a2bdd473de53fb1bcbae0adf93b4525c0a77d1952a21ba5e575ab9aa889a19d85a02a1ae4d420613bbeb7bd2a7032137f196e0566c284cd11822ef938c191763beb392eae3fd6fad77ea7252ee72798e5b4318961ef67e595bfe0be036c478c88b80c50c3f7bd047066f4cbe031a867644529afbbe607c6fa77602acef9a635de3b1fbd6c967b6133040d1a6649f1ff5598ce0e76af8ace89406fc02f2818ef8c29faff1f46a551b534bce2c30e6fca6f62df3bddde56ffd8550466f48c0d14bebb386f5badca240d848efb66ac2d339a54aa1accb5c753b081f0b6f782388e7b82c77304f30e03b5d3bfce0f1b5158aedecab4749c17305dcf231a04ea2436f423f5a818c461e90d65eda69ddc5d977b19f26e4c9db874f2602a3f5be5ab8c5c70cdbc57e5bf757037768e1962d0ac697645b598c46d639c7a0dd31b7ccfb88e4745bf2776505308c28fddb084f67618b84d0451ab2aa45437202474abaa0780935ee78d47ebb4e07c6466d3f8e83c1b27effc1064fe01880d2a7d571a955dcd4f55d631dfbb3cb550e3541254c0d4041479fbb331ec591f8afe5b644f6df9f4300375805bed126eb96893bcab7fc5ac5ccad3596d8c011258f3ed269a6b0a6c4736d467bee9d495d414b475d9354174b36e975655c8"
+            },
+            Test {
+                input: "de286ba4206e8b005714f80fb1cdfaebde91d29f84603e4a3ebc04686f99a46c9e880b96c574825582e8812a26e5a857ffc6579f63742f",
+                output_str: "b9e75f5d4b74ffbd244cd9566df861526b5de9584d3280ba5a684eac9d44c91c0dcec5827da4ec0fa7f60d29286d348f576f4e2fa03ac5be8f27e9f9912bf500d0cd549f5e5799697c61f0403c264c4b2d986ddbffe72fd8ca6439fc01d1f7138a92947364d586d67c300f27ec2e3e75f9088a5b787490494ebe0c42d00401a2aba6374cb3e33bbd737ecfbf80ee24d4985f6d11fe24fedbefb387d4edbf4ae1f409e67f10719f47397968e406a51b0dabb4e9391fef03f9f7bc47193215205386914fade37017edfb0dfe8c51b4c35c0aeb6f8a8e6d4d69fb538ecdbf65cf92325a7f280e8069cf9fcfcde610bd024cba87827e92caf22482413c694f9f1ade65b67f8e1d32e4b5d51f038c2fa9d89fdb2bc1848e3e7b54c4cd4d021f4c8baff61875899b79ef4a1468b0443691981fabc95d076070bbd5890efaee194a6484e584364bac001fcb37c22858f74e1a01ea8eebd49d9a55a19f5967b898c5b71d5f2ce93f4e52ce4b4d00d7c42e58d71c174e9326c5ae1e40bfbd8bd37dbce9369062124cb47d683db245a4f289f052f89812440be2ed28b40049a9dbc75b3fb1003be8a1b996be44270a83dc20a38d62c5971d09d06ffdc3f89379a99923f2be2fb6651407ee37f4bc8073e396887166ad4f0a4e156c72463a524edbf462f62aab251e32159cb3d79a2cb3a8fcbc196721642682646a83ee60425dd7207f7360"
+            },
+            Test {
+                input: "eebcc18057252cbf3f9c070f1a73213356d5d4bc19ac2a411ec8cdeee7a571e2e20eaf61fd0c33a0ffeb297ddb77a97f0a415347db66bcaf",
+                output_str: "eb24ecb6c9cccda1e8ab1ca26683b63a43ca864e23aa7681a4927affbd8adee82704b24b321d6c909a1cbfcb453ac084557fe84ab25e044885ed8051a0ebbb457d9821e9c132230ff27c4f27951432da415d90d59cf7148569cba02af32a8f4b774d5e4667ae594c2cc4776aeba2ca7d5f678c522a03b426ab2325127e56a4057837cfee2607207dea5f913cd64bed09e7fa723148aca13f522b584af9a36e74e86415f7c064c7575176488895f0ee6a6795b51729ac947bf09668a9adeec199592b77227d62205857b75e01e62e3d2757f02c4892a9e9c2a9187f7f3ddb16b7adc28c33f5889f87f949eb0a61e5fe431a3c11191da6d127bfc899cda0787eb269d0296f31f3580d9f630e0693f292d2b9954444e56a82d6c81319cd99d5ddb2f042e9242244455d5d9f59ce9dadf0be780494fdcabc72aee397f13cbd656d246b6240a1c21bad6e0126caea1c93096a41cf648bc0ed7a051e03dcb51e2c48ae32c88188634021a4b64adc4b2ca9a5118d4b6698e87c1e3d4c2666996f8754242214f3b07806c8eac8cb63afce0a03b64d63d46ad53f0345dc3a9fe550d43e9e569f8c2babb2c025d843f7d568dee6bc762d3b4db80b8a3119dcb19a17cf5fe1639ca313fc74eaceab5f9bac2e546c36dd7c292b959a2c9ca98cd143c5822bc94179def33d146a16091688ce192bf03a7e334bd033db66a3d544a8fe17d2f5cb"
+            },
+            Test {
+                input: "416b5cdc9fe951bd361bd7abfc120a5054758eba88fdd68fd84e39d3b09ac25497d36b43cbe7b85a6a3cebda8db4e5549c3ee51bb6fcb6ac1e",
+                output_str: "75102a95654d885655b910e6778f8a72b263b0854442230f8d8923afcc92c5bc98ee5f2e8d53ee1eb7f7a85a7562fb96535af6c78f0491eb11b4be2cc71ccad0442dba422b84fb16ed529278c57a543a3b8910d17232b2b7fc4b81bea56a6e99f64a50dd73acd26e506edd60a788548dba27aa66bf6d41c8ca0cc603d8ca515f3bc948afee2e7ec3f8cebc56a01682e66a082846e8edd0ced85a6d5ada77a9567424c73f049dbb2cdc180e6dd85ad73d624bfe10ba0ce3609771e50b51004bd62029259300e333d18697a3dd0408d37c5e275cc8a4c6c5ad85040365b3a427f21bff9f1660dad79d439c5dad6855e75840577b6aa822f614b42cf57561a70ee8216f9ccdd8b10f36455a2677cf93756a3e30e2e177029c4e0a3860cc01619549aab73b52e7e5340b42ebae37478cd899b71f9fbaf7dde36c57450cb5793e371c903ede8143f9ca3c8ea2231bf5f3191a49681ee8f45374d81a774e9f8c6ee5465b567bcce1c77e8289c72411a1c8f5402906046f42cafe88b54a5e8c7fbc5311b1a7c43a1094047935a27b2d89e9470ea28569211f1e6d99e9fcd1aea301a6271f90f51ddab660e90a50d10003bf425858cfb0d67ed630f74d6ff46e57ffb7236d55703a55531f89d92eeac17c6a050f56b46bd0466a0a918ec972e0947a991b024af21d9f92b6147155a1ef08ebf620fbb65c309863a25f3bd1d9ecd818e354"
+            },
+            Test {
+                input: "5c5faf66f32e0f8311c32e8da8284a4ed60891a5a7e50fb2956b3cbaa79fc66ca376460e100415401fc2b8518c64502f187ea14bfc9503759705",
+                output_str: "603cfb5e53d83ccdecb22c5c75e67f5dfa0db7d874e6d280de014555b1300192d9b769482878950acdb484e87c26f366d2db049ffe8c92799954fe31dde56a061e2f80a5da15b65a0c9382c7790ebee8e676373405bc1bcfbe974797cbaa998a0315cd9051bf669e00611880aedd88dc690192d8d485726b47879861a85349c2017d9892692de8df315ec3eb4e6c508b85002fc7e6d7812fc7e025fca92f14ee57ec9f507ec05fb8d143db2ef6b83b8785289c2faba51e962b77754c0081cc1253de4cf8c36d2150b263fa01e19e5157eac5521e29414407fbcb604a442fdce7de9c99d46d71f78d1b9931033af38940d70651884b766762605eae11457a60f44bf5ceed9c0e9a9c600da70b87b57e4b5c280e3aa568bc6e3988b5481006298bcf9239583f39c5ef439e551b6166daf31970ddf7bb6b7e068dae50c15d7a1b3d4f3587a91bdeaa59dc666220c2dfd238bef11f99dd47b87dba8c60598b531013468ea5f15edb0e2f43d4f4efa673e88aadf4572a50c25b3b7953c4ff0ca8f32d374fdc3c130ccf67e95abdd315fe7390d5160f6b307f3a20497c76f69ccf18151e5995452f01adf1d55bf3a678d0acff44c50852f940da91aa3fa8a5bc8cc72df7af11af0e19c167f6031dc780df8583f290059f5abec6917f7ef54339538424234454004be4398cd0ca6cd1e71d0372f2229591f7647142c13c5b0897806f30"
+            },
+            Test {
+                input: "7167e1e02be1a7ca69d788666f823ae4eef39271f3c26a5cf7cee05bca83161066dc2e217b330df821103799df6d74810eed363adc4ab99f36046a",
+                output_str: "724e26ad36068e3825e1f997cfed8ad10194b96e76ef425bd347254bf19bb862dd449e0182e9b8e20c8cb5440e34cb7391935b6f5d49f3319a984e313a9f4ed7107c43d737f016bd20d7f454a670199566cab98c4d05f0d31b2811a48eba4df019936b0c6e983c3557dcffd42238885a7cba1376cdad15bc2fef1e75013cd3aca86fde4b616f2bfe310131aa5ee826f5b0451d4dfc0f0ebdeacb36a8b6ab96d7d81b2a21f7e09c5e908fcacfa763ded4361e2d9ec86559df71a827662ef692d503c72987cc9f5a9fd69f9aac4231bf27e8c64ade3f9b51ff7df4775b966a6c2fa6f913fd191f9b79dddfc077363e1e62810f9d82c82a0ca9fd45b9267b17998c2fb7e812195cafb0a08831ca47857e00e329072037b3a96dc9780fdb52379e7180ed0e84866d42779d89f56f94a8d86c0600302a09255f838efabbd08fa7b342ebce887cbde92743a36c14f61386bc9fa5662f7a2e39e0cd165e0e0f635478eb28217c1e97ee7df96d6e6143918c7cfe29236e9911d10c756871e749e2ca721dc4f1d0dafb1715591f3708971409a54712588af7cea3fd2d0d06c036cae4f76b885f50b3fe11a39f304c9702bf5f24dd5a2006e9fe6ad23aec9598e34b4b043b092caed032c3fa42306064805e73fe03560ace3bd87d974c8fb95da0c68e0ec4b245c849bbd06b94a319209514707bf5447113ee3b14afca06a6bf308dbe03a8"
+            },
+            Test {
+                input: "2fda311dbba27321c5329510fae6948f03210b76d43e7448d1689a063877b6d14c4f6d0eaa96c150051371f7dd8a4119f7da5c483cc3e6723c01fb7d",
+                output_str: "d0f92c3953c2696fc132fa48ba36eb7576d34c5bacfa4e9d9f6dea8f7b0b6b746f6f7914ee8b9c25ebca91d601e781b29c99d0da92a1c8670918927a45b2af16e9bf00ce9a877e361e797f9511b9a116ab72209d7e8dbf0e299991b173e4c654021517a94f9f4cbfe6fc4bb3c3eb5171435219ec0d80be57e3900bce9327d10dfdce70bcd32c129fd5d5bcc54c4bc972f67562796466f9bcc7399db8444c2ee896ecda88e0f9ed729985992f0bd707ed3ece97064480aa1d10d4bb176f65db3327a0f34d3cc32140a95594da7707f565849d1258435285c1b9828723ef42c475d30040aafb3237a759141ede73070e8995d2ff72c727b1f8a215af3e5113852febc029413c2d2f21849ccff5269b8d188c147d4fe3843d1950fc09409ba0e5fd2c5567f11f0dd098810924e56463ce5b6c7437163c6201a9252dc484800303facf0d6b004cc856bc68aedec5496021b37a667b02f5f7e7234484b531f07ed78b6eb747cf595367ec3ef33df41d25424a858f50a63d5d503efeb895334466fc3b01da6246a5801b9d06071d765a65e64f2214f93b6f072115343d711697ef2e1463e021cf3ed9cfcbe5a81e54dab729d52f2f309becf754e3d420cf0ca060c7be4589d748b84028517af7923767833858a35b26b0ab5c5e3b14e68bbf50ac28a3129f6ae086bf783612749daf4cfe87e75a4c89def988064e32d616f1ccc17d46"
+            },
+            Test {
+                input: "95d1474a5aab5d2422aca6e481187833a6212bd2d0f91451a67dd786dfc91dfed51b35f47e1deb8a8ab4b9cb67b70179cc26f553ae7b569969ce151b8d",
+                output_str: "f31de8cad77a334c3480d93e3b30844df1ec344a8d44cdd277b0099f28001239eb0da5b566fdc383f0e1577f67edd2bc0f11de67f3e7a4d97c56c9f3bb0fcb4d3e4d08f7f3d5c30fbd2d964cd45f36826f614668193554a33bf0170ac3e64c10e4e3570eef84df387944a6436a814dcc53645d01968c4ebd1bd0bdd76354580805bfadac96470fd354ba2630f7ff8f7ab29282aba946b1a9e063c316a6d337a7cec2fb4b562b899f626418bb61eb4f9e9bd7b294c7eca75ab522d642ce495640e4bb1e2b14a10775704dce5adc7d7e3c091520b48dd18a291841cece5ef56e1969915fb497960d011a8f46a5b08eb39232283ef332f7ab0d8fdbd900bc200183186be31a6eff7f5f4cd27c12bbeedb0715a0e6e1f6e35753fe7f3996c75ae34d2e8e76e43f49ebdd505dee66536e5f2332daf4ee462b7b524f3bed1293bc45df9511fc03d2734da036eb3f8c62bb0e623031939e83745744f7dbe93e57ed65eac1016e414715b54ae83a15fac6e76057d77c3811491f390c0b4ea0bce292372a8633e26c10c11e301e57983109903dbbf4d08434a6287b8df665bdbfb03957cea7ae4eef506ab1f7af1358eb48e7fffc9606c266e6cd903c75772e2e88e954585de90111a250ee62fc12d75c5c58cb7c03c9c06c2aac9edbfeb02a1207ae5f9a92d32dce6528a13725edbe757f309449a40e93286388d8c09f9bfbf49e5fb826"
+            },
+            Test {
+                input: "c71bd7941f41df044a2927a8ff55b4b467c33d089f0988aa253d294addbdb32530c0d4208b10d9959823f0c0f0734684006df79f7099870f6bf53211a88d",
+                output_str: "a3d9ececa03a1016a8546ad75c7b35102d5abb0021fb5f2b1f53b591624ef0f6c199f64dbcf325e37f4a361368cf60f3bda9f11bcf5ff2eb1a4c0b0546b5e898204ea5e4117f519f72f2f5de1017b2bae0723d91a430b2b3c1987fdd24ff0d0f1cde2483a22fc37f296ce16998c12994603cfab4b496d3333b25ed48adb1ec926a44cd5db14c2072588f15ea752a31a8a3aa559a35ebc900fce948111af7522afbdf7c56065b196cdd00fdbaade3a80d2db10271bdf6418f0f817fe991ec055cca474b61e1af6be6ff6396ab04716809433bc8af75369049e605c1c0028a0d370e7cd0c1eb571fb379b757e8bd21aa61c2e2f2b0d0dbd2d73acb2dd0887923b840079bc74f6c69682118b2b3dfd3fe94d3a76eb8bd68cfa94034df0b5419104675b9f5e56f8c6e0eff12d9b20e27535a09e9fa103803b62c66d7ae09f8e39a5f505f3bf93d27eee1b16546f97af0616bd4923425a1f0fea1655334a528c5da469850a0257496c820a351d826eedab469a3871182b8435615e8cb1c8c81d34f8904df7f81d48ffde990b69f0608e6b05ac130709d3dfa9e8d9f343622991bc686e80b4f0877c03d9b1e0a190d4c33c11246a20cfb297e127fc359afd037b1a90c040d9e10f77a3f6d9fc45a2877711559c8b09348b203fc49a1770730d1206dd03b9e64c390a308bc27896309be2ebced1a7ade8d7187e8f6f9a76523fc820e30"
+            },
+            Test {
+                input: "f57c64006d9ea761892e145c99df1b24640883da79d9ed5262859dcda8c3c32e05b03d984f1ab4a230242ab6b78d368dc5aaa1e6d3498d53371e84b0c1d4ba",
+                output_str: "46f35dce4ff3a34e944ac51b64ab60d314e30c2ca9c5b4675d759e1e852835977b6e247c025a8ff0248c622c492a04b87c5a2c906b2c1cc8f9cf2e03dbbe046644ed26f37b2c4eb2d16b558d82e2a3400ea2bee9b4d0a3641b7065fcbc34abd67eabdf5ab7b3f278c47d24ee127515a2c94ba955a01a098befb59261082f23383210fe82208574b95763fca6132afb3e644461b1d78f3c8e04d860fb0952f9a33a7e56c1aec1cd3ca913ca62fd35fbcff62b0032484ed07ab9c510c589f62965d676382ec7e55e359f5bfa7124a54b83c245725ad796987ef4e9186c74e8b1b53cf027533341278b0a6b621d7fc68b556f0b3e1a95312f4fd3471ef1bf3c3c5ece8269b29a51470ade59a3f15f2600b858eaf8b6b109339cf1b15b0edf36e0004992bed6e1b187ba60ed3e92a542a83753e14e0ca85a0df441e5b03a9709eb1ae714615c7c5f2f54c373bc5abe342124bca909bd4f6696950e0483bc798059a94cd8d852d6c5e596a6ce12ff053874f459e68062c5650ecc934eede1e7206bde104cf33c95fe103d279108b60b4078db9522f2ceb28b77def8e4e59c93552b8c09c0d74e8aecb3b6c50be0c123e2eb39470908bb7288e451c51f6f7154143dc78d5f5c4ed402217a3b61466ce80cca2257d77dbb99b6069fdc6cdca949bcf279b3e4de57968dd0ef83c19c5e1a07b19b85fc60e593600470c3f4603178ba08ca"
+            },
+            Test {
+                input: "e926ae8b0af6e53176dbffcc2a6b88c6bd765f939d3d178a9bde9ef3aa131c61e31c1e42cdfaf4b4dcde579a37e150efbef5555b4c1cb40439d835a724e2fae7",
+                output_str: "77b7496ed08c3933bd75983c0c0494bdd8262493a4b55ddccc64167e67eac0f6e6307acc15c33f3963744e26ca6c504d393b3ee8165e4d49eb3b6e649207653048f8b822ff884dc74937443b1c4a888c7a768c63d5b5d29e7446873923b9d7a56fa5d9e90760ab86d5718e3464821b79eb46d169141ff16120bfb650c76d4b3e5b3f6ce61febdbe09aed7f4c91066d903af6e56531e8ff71549508b6e420cac6bedfe0cbeae6bc228476bc8c00eae43d40c82cbdf6b460c376d7c11648eb2815b6506abd4339b25d58d45cdd0a0b9e35a88e251fdc34d4810d659d179f59ebd03717fd31a6394ce12cd5569066e138885cb2bdebba06367557ce849eb869f3cac38800d51c22b666ae2701e580796394dfa02f4910bf5f86aab53951233364ea20cda35afbab445be7f686643856f825394be7b4b6d2c918d0151f46fb9aee8a7ba2d706e48cb0bc429b064262c1a0eb3524ff14632f5184575c15f6f4a3446e93cb4e86b6a931ba268409ce30b4595fd2059a27183b3ba8d0ace8e482866d5c7d5b03db8dbd24b99d59eb6eeffd209e124535d154b98f9991d84fe1aa763c5133d41ecc233930957dceb7896af70f735a2f5c1e79480afd50943bc5014bcf0a7354aa7f713163b55a1e41bdd05fbba9c1db2c69043ed9eea4fa45c990ccb4a8dc41afab18164018e54c47ac5bd6980fd796acf0ddb42c7042a4877e8be3de29"
+            },
+            Test {
+                input: "16e8b3d8f988e9bb04de9c96f2627811c973ce4a5296b4772ca3eefeb80a652bdf21f50df79f32db23f9f73d393b2d57d9a0297f7a2f2e79cfda39fa393df1ac00",
+                output_str: "8229bfc635a769d86656396b7723fb46bba9868712f27c377925ca6b358b8391e0ad8c30da71fc8f0716bb95acb0da00c61f3a7bc8df1315715e925f1ebfbfb5d72cb3e098f0c014a80e88a44231dda194dfa8e35e359f60ea5d7a5e0d1e64a8fde294f4ed2e3e98294dab838b2c6b3fafcb2995ac17af67669a24fb71318233a82dc8b934c8693b3df784a5bb34ce9cb3fde79afcbfa66c07d1202c954e849dadc0c1d5ba79bfa74919c1c6fffdbb834287c852522a65ae3d32e337c2bf16c3b5e22d4577f5b05f1b87218532041b9692b0ec561881479c924ba92e154b57a1afba6214f68fd067d109a92a9b0e127a0a6b78e85808268567cbd1a2653201233b4e80be103eb951748a1d1f8a205856a650c58df15e8e1c76644e52614ab4dabf51a2320a98d259f8295412291464e1d918c9bb8f5282301be5f91dcc507f140d8642b7a6fd37327cf38f510679845853cfa039ff4cbf749d48032d6650bc7ac2becaefc5672ca7c61a8f6a1bd69d321d2ac1e6095b3af7111f509be0062707617c62da3336c3086c39b2dcb9da7f23be732ef32f906243250ce4d38668acc8ceebee87c43f077df2df1ea4f6345477490fe37725eccb8d4f47b14a85b0d36feeadd4a020da3dda4a48895ddaa45b5ef8499e937d06bfe6df88897a828dc19d9ad93c622e0263e74f818f921c4200856c9ec9d36cc99a6b0bd59fccce72ce3d"
+            },
+            Test {
+                input: "fc424eeb27c18a11c01f39c555d8b78a805b88dba1dc2a42ed5e2c0ec737ff68b2456d80eb85e11714fa3f8eabfb906d3c17964cb4f5e76b29c1765db03d91be37fc",
+                output_str: "66126e27da8c1600b68d0ed65e9f47c4165faa43dc4eb1b99ffeddc33e61e20b01b160c84740b0f9fe29fda1fb5eff2819d98c047cdd0cf8a0d396864e54a34657bd0c0355c75c77e5c3d9ad203e71fc2785a83d254b953277b262ee0a5bb7d0c24ed57faed4fdb96d5fd7820e6efeeb5a9e9df48c619c4872cf3b2516dbb28073273e2693544e271d6f0f64be8dc236ecd021c00039fd362a843dc3681b166cbc2407495e18903e469403807fe623f3648f799f18fbd60fff7705d07464e801e0aed4f2f0642b9a2c5cdd0c902b59b1da19a09375c1c13175b618091b8882a0e7205ee63a9219ecbcfa943a10d2d9a50c8c0b5d43b003f67ef0d52adbf9f659bb62fa6e00678bb8d4449648872a99eecdbb3dc381b5199fd500912afa93c63a6b23d00d0a416468fdab93aedd9115265be3a4440dd4029ff7f88d9755623e77f9430b934dae529be9a6b307b1b292ab5918eb24b14598554b4cc6269419c701494b7cba5b3d69f6cdcd5181fd03e0748d08e1e0aa5c4ec62c47877c1085873c016ef24e7e45da71d3db9db23b153cceda9a9ab5ccd8c5466cef29810098e976e4867075601f83a2d2cda1a476a1e990ce04c4567ffb99aac428922d9d8b25af68c36463d3aa4f689cd778f79e743e0bb5f935e6d45f978dcb2aed12dfcdca469556556e19f25d4c959c98785fb471d4bd1675d3b84742766d5ba4bff2a3f912"
+            },
+            Test {
+                input: "abe3472b54e72734bdba7d9158736464251c4f21b33fbbc92d7fac9a35c4e3322ff01d2380cbaa4ef8fb07d21a2128b7b9f5b6d9f34e13f39c7ffc2e72e47888599ba5",
+                output_str: "efaee039c0412fce8f55f6e7772889ec18d0604fb18040dc1e5783596cd820b421a0dcaa528c8a62b17a22164430672da6d818e2e555aa8e79665a6f8f5721a4e17fe8feda551acc9116f1f50e95839fff2427dc1d988b0269838102547d4d46c11d2548be3f885111d53f3061a74972c56579c681c20bd5d47a4c2a9523bce154068fdf3813f5d45a8d446758c212614e3a6e80ebcfef81e44034e0f2d02fcd0ae5e6b10dc24ea09b94dbc47873768c0dc6cf2991b9477448540924cb57d3582d7b8e453e946c57129285b548fcc831b3e311cfffa3161941689e3cd649c3f47d96037804d0c6a4fa8c09b11a7d5a35f6c4ab89b64c735153422a3e529e19b9ad7f7cc346f904912e1a6c098cced3be9755137a26907cfd7f7aeb1a573a971c4a5760ca5399cbe642f0106497aa1d364ddcdabf375c547bddb6011f26b564d0ccf4e055dc0869bc280391e5c0203005d92246e377dc560d16f3a9588068473b14fe7e39f9c25108ea279d98df21902e60dd4eb03266e873d3b0c24dd33066991386c4311e58197f24af80fa150068407821c2327e900340550e7826b2f510ac65d4b21e9336610945a0e5a0ec8d132d694316f2b8a21cc24520c6204ef036116b2fe66a79cbb202f65e1d1782ae10cc71be51dd44718e2fe9d229c705b94b9ba6b27a3925e55da290875588c8edb8a1866fac9efb7fb292f69a89ed772cc68d"
+            },
+            Test {
+                input: "36f9f0a65f2ca498d739b944d6eff3da5ebba57e7d9c41598a2b0e4380f3cf4b479ec2348d015ffe6256273511154afcf3b4b4bf09d6c4744fdd0f62d75079d440706b05",
+                output_str: "f64cb396701785b64767d4f17a768ee198297a74e5d1617ff74a3323c096579c0279e351c2407bb889cd4ae718b09aba711fe3ac14ae7d7de0072e8bb0b6a1f92a1c93ddb46de891cfb1f36814e585f672ba871601e817bcd6327f3a7fa7de35af6a0948dcf3dedbc8a7154ce8529033f67fc656f95fd47b60e49681895ebe0824df50f8ea0480b50eb3264243a88bef29f5f4fba012b86a5dfc98054af4d15248cdadcb160193de7068ce71eb76e32acdd0dd94f6b27b5158d9e63eb25831219768454c8a951e9678f41ef6f654caacb0f2ab5dd614bf0bbd932de06fc31d7259309b23df8b5864322eb2d8f39a07e5a3f324b64876612be4a1c47b06f7c5bb814169d94b78ce22aeb7249c96a29c52bdb5550c7b292c96ea9ed6700f5d3032d2a81cd68ed3a6de8fcaf9379ed0d95c94bcb0082915ff7db5ea1bc25645ef3b546a728aff4ca20c6f8288ff0ff4b7dbf838e1a3ec5463ab88cc827d03a748fbb924797a98d309bac09e73215bf8be798c151d322d6110c280d85b45785d854da39a80f64897918c169bd7e1fc52d003999c084bf69b696e6d747e859dd2d6ec6fa1339a395858477bc49241b302fc74e0188a2a8138507331923c357ab4eed3f64ffa908cdad9116039a469229f9a62070799026097ec7f5a71a7fb01b5473e8035d383b9f236f2faa0e06dbb135a939ef9cb31af1e312f47c6c9be1f50da36"
+            },
+            Test {
+                input: "abc87763cae1ca98bd8c5b82caba54ac83286f87e9610128ae4de68ac95df5e329c360717bd349f26b872528492ca7c94c2c1e1ef56b74dbb65c2ac351981fdb31d06c77a4",
+                output_str: "cd85deb9da581af66c0b3125b697371f16ee34606a577ad6d8ac7e4e4a948b36c844ec9ea85eb168d7a5a1eb4b72a685aeb80a75075b420c9b53b963d960f7bc88dced631c734114c28b2e20f0657d9256ab01b1afedda9b9f85fd30d0de3b98db38ab90de60045836cfb12c41e5bdae57b937b637c11ed47f7de242eb9f72d3253c5d883b22333f181ffad60a541da08601791fc0f8d9f44a94b551b1a879b76fc2b7931a2f4301d121a4e6861f5c84ffcb0139fc37268b5f8a4c3fd490809cf44f68bc1e665b369d4d74dd0bdea71ed0514c37a47124ce146927274d95067c80036ed9f1a5b0a10ae71e837a09dbe4dc358df4687392d99b2ace8beada9656677518b1607c8e13b7f45100bfcefa1d4e38b9bb29eb23d17b9cc66f70635a6c531be9cb890ae833cd7ce35498cc9f81c576493913bad87532b711f3f88873e9ed48a83b6b2c503e096a33f824feb4ccc702e82cef00fbd938ff9bef6e3f80e149eb3433816a1d3fe7f005734192ccb5a8b0d7d43327b535547a9cc7f5fa286f9eac26e9e6a1cfb86db35831f75a9902a3e78f6bf9b4728836c81b3c614923c3ea88d6c5f55449a83eba0f5ff7b4f07084206d4590bf817c1feb43595462037afb6969a91eeb963bd244adb1b654fc98a0b0be99029b3d5bdd69d2158939d677b054ce55decf0f332851e0a74eaf2bf3eb672d4cb1f467d0e5391f98501fec2e"
+            },
+            Test {
+                input: "94f7ca8e1a54234c6d53cc734bb3d3150c8ba8c5f880eab8d25fed13793a9701ebe320509286fd8e422e931d99c98da4df7e70ae447bab8cffd92382d8a77760a259fc4fbd72",
+                output_str: "a90053a8f738a68c18cb87fbaa8370bd14270412d0014c5de8008fbb74e619182a0442c121f7e2449a5b019dc0ce597bf1d7d3e64d1184946d45208a864723a73cc1e242f7187811c522f880acf53056d835bd150fcb7db61363d22074349ff54a3e5ff2571272910a7333959d8cc29f69b540e5ecca50df7799236338e29255656930e22679a3a585e32b88c27452be75bde73789b45623e695fb7408dc51891d50a3bf84c5088c5f6fbb1b740deb7fe38bca05f1a3bbb516e9afed0a41f8fce94411cb84d8bfd51ef917184a66c56b31a190ae02b86f62cda2fd7471ec030e94edb56c144025a1ba9b792a515dbbf402d33bb6451825e52a87b7b82c44cee32669f96f3d8daac5923127b51ab5c5ed43e5a9344b32c5a3705345ee98ccc5259c9d3342cc10d660274dd628f1c2c031fe9ed282500d5c3982c7976620fb46190c57856e519c6fc1760a306c3497f2e001c7113248f53ea1a4bf9db370285ee441e4b43459b6f8690cf10bc1785138f8855df859bcf1aa581db4a6efb576d938fc273e7d126caab7fbcbad62dbed1fe2c33f24640afa899def2825ac2c0fe928df223b1043117c061f1c7eec723c5cbfa8314e1b18ea6cb63c02b9d6fa3b27929b4d42f1d785813fefe1249f65b725d4de59ae071a4f6a40aaa26935f4defdfa3760c98cbe805a50debb3011e006015fbe8400cfb1b6b3d2162014d675df4246"
+            },
+            Test {
+                input: "13bd2811f6ed2b6f04ff3895aceed7bef8dcd45eb121791bc194a0f806206bffc3b9281c2b308b1a729ce008119dd3066e9378acdcc50a98a82e20738800b6cddbe5fe9694ad6d",
+                output_str: "27bf218a01125514bb1b78e582aad16720267373bb27ff96a594b7f10cc1d0a393fa753f50437c89301542d27c12c03f53ff771cd0df4b38f40b607b67cf419020d34c18f5bd3bd424d39f47d118c84a53a635e17365f84fa0340be3212056c155fd227d3b52f9be75538fc23287b5deec0e5737c8484abba0be6cc43d956f17a41cf81dce5e78326633cf09326e0004b172763089a593dfbbc1a0960a16f207f464f9ea2affe732208e970e00aa0bf1228634e98031155b61f6ee509648d4b0bf58fc9cddd0b470b95a0aed8a3a96deb2f7fcf65ce08a826300d4e48a681019c5a8eed66e7fd5ff098308138b4e11886528aa9ed32617392b0f6e133a99683daddac328838008befe9dc680720bf4231e88848660c8ef4a2973046d8e70d8ee8d8497aed8a748b3185a77b238b5650c99095d8702209c0c31fe1770042fe3bdc2582f5fb841eb5a234cb4c9b637fb4c5dd9f90225db4c62da420f3d1895fb2eb05e3a3d6767f73fdbc8b94d48a555ce4cde5045bf5325b782e0c242fb3cd27d963a9ef014ddba4b0608f2627fcabb2edf570a49ad5377b1bc7193d9cccc23f5d35c2db59d05df8d4a8e5146298b6ebe1de25ba1089dc746efef6bce22b43fb99eeabddaa76566452f544eaa85ce4559ba683a122ce76927242050fb236bda091480ab1b9adca148b639f986a3e936bba565b54f727a0d45f369df25b9ae8528"
+            },
+            Test {
+                input: "1eed9cba179a009ec2ec5508773dd305477ca117e6d569e66b5f64c6bc64801ce25a8424ce4a26d575b8a6fb10ead3fd1992edddeec2ebe7150dc98f63adc3237ef57b91397aa8a7",
+                output_str: "2fce215362a523d7b76fb836eb458667099c58bc51d7ee6f6deb9894b6a337576b0daf9a806488c3d238762b7a2e7b12aacd1d696517eed142aa5dc5a0747f08e5e39a2486d75f497cbd6c4899d6f5bf2aaac9189a6abc6e787b0d9c5283c840e518c6ab0393cf60337369251df935a02de0463dbfa4dcdc1de9034fc9c21ffb9dbd7c48384dff31012bd5f5a9cdfdb7139c3c35f560913d643ddb728910413f1267bf1bf1586c5ee69dad26b53154934762d4c80c34d511bdd8a391f83d224f9f8f83b61daa046c542bc78f153a3aed27e1268058f6952258d274f11c8d9634a5bdd4e69c60dcf1f89df2238eadfe783cba652a554186d9e8307c7773722d1049c3815526f583612bbd8f6c587d058b80fbd38113957e60212777a9f67b612312583fefb67533c065286cf371001440b1a7a43de2405e5e92d633f12a63ee2ebc408164545df22803ff239dee66eaa20780d103d940880e8bf68b9d815efcf16f59e0d858af33fe4d287a2b8e61c6ebf26e16e354b3ef63774ee01a14691b149d81f010a655f308e966c990e1befcb6e4253ff43bf473afa78aa88c36ebbe735b6b2f92ba9d07a738e000c9b42bf8a3a4d8fb6c38aa36b3329f909676183fbb520196d0dedc80dc6ba0db4d72ac6544551cc38b23afe000a91f10a89956d2120494543e3ff5d7d1b2791207860a0b921debbae769e55713a1d611f6b1175bd0"
+            },
+            Test {
+                input: "ba5b67b5ec3a3ffae2c19dd8176a2ef75c0cd903725d45c9cb7009a900c0b0ca7a2967a95ae68269a6dbf8466c7b6844a1d608ac661f7eff00538e323db5f2c644b78b2d48de1a08aa",
+                output_str: "992e831e9bf5fd994a73f17699ca0acaef65e8212e5c4a495569654b5db523bb04431b7910a343ff254f4432485b4a6a88701afa889b11c45c53b4a1c4a1872fc685d644deb5de2340511f29d062f6cf0f39803bc333044cde83103155a49f77ff8946a77fb092d1cf1715f02297ed4f6b0a43254863641c4c244db87fe486a3eb78dd3b57cce06722ccbbf53eccc862a8256625ab03563fe4730f74c8f78037bde37d538da822ae9141b8098a8b57d74fceaa072746dbed8c4b23f91b3de8b9b733d06ccfa2fc18747590c9ac01a9fa675d8cb51505098f8993c494592c2561f8f2fee3b267d8fb77a1ab853432850f90b8c52d08e23a19226a61e0589842eceb48059f8f1b749d563e2c652b70c426b91b8b0e19ef2b319f2d7dfc25f0d712a76ca9332f92bb38cf89ded9802bb7ad5654b2357325cb1cf6f1c9fb364ef41ee8b0a8baf5ff9e8878e56ba4beeae384bdf029e4911df8e84f5b570704d53b67d6bb1aef37976b38f405d9aea67c6a6d77370e37bd78034645a9b6405672366dc061bf384eb0e9e73466ff5d018c9ba52dd262dc97970cb4b8ab467847c23da0fb101f5a7b9eba51ace6c0119ed03c7a14afca676bed44922edcbacbc79b6db231c60dcd4abbbfa0c13c0ab3d680aeca78eb9bf0f71ce6886aff6c309594a9df2d01692c56265a6e9256c366c4c53b6c0fc38b6ef18ed8c571d94ee27e850d4c"
+            },
+            Test {
+                input: "0efa26ac5673167dcacab860932ed612f65ff49b80fa9ae65465e5542cb62075df1c5ae54fba4db807be25b070033efa223bdd5b1d3c94c6e1909c02b620d4b1b3a6c9fed24d70749604",
+                output_str: "47cb72fc64aeb3f76085626534ea346a2b4797b5d61839bd7a15df05d5e3552c2751c697bc2c532e2b3a8934b9acd8985671450db65d6f44d9b6e27972fbe050e6a76537eed3e9fb15849ed61c3b2f6e30a8523df8e95bfae3a93bb306343212f1c28811359442759c85c3e6829a179c03f86a442dbabf49940297de3f29ca9f6ee25eef49b9c7b37dc4499a9d16d3b32da2ab391ac1e6ba6f3967532fa18e50b1e52d6d3eb2447ee20ce459ed970d71e33d80a20e933f09e494a753d15590a29b15733fbc93217b47b3685100aa31d5029db16fd7e293c51c55e54e15457f99009590ef8c7b7be110453b73b4652b2f9c048bd7f2ea2590d33ecc5508bd62be3a0918c174d99c5939fee9c48592cfc220f59f28f57777ddd43aaacbd23a61a8473d4ccf01389e982877282e8694f03683ebb44406c798104b9f3223b0df50ec964665492eee586cbded57a75f17762a2903604f8120fd1d981afed7d6aea59fe70ddce738a41f53f611b927ec3dd3ab7e89a0b0b3943eaa2a74fa2c020984dceb577f6b3e7ae98cbb81f3cd9780e52d44bdeffaf466fdac7a4429bc89295204b0fbb9c8a22a5f202e8536542c244cbf3000c0cc1cbb0c4e18a29cc92697b0e58ab1ae77ae10b1d3ec92eb697364ca69279c4eeef39d27c06e63dac76028df7a5a974f8c97af5c7aa31b5bb5f1f4db2e63b3d4c9f6849129084c77ade97562b6"
+            },
+            Test {
+                input: "bbfd933d1fd7bf594ac7f435277dc17d8d5a5b8e4d13d96d2f64e771abbd51a5a8aea741beccbddb177bcea05243ebd003cfdeae877cca4da94605b67691919d8b033f77d384ca01593c1b",
+                output_str: "458ff16e716ee4c47f3b60b3e473d91157767621e9e3a200ea0ba18b511b00c9ba311c7d542289d03f07adfa6110675dcb43d5d8ec69c0eef6aaf4664f917e01ff8dc5f203e89540eb96640ff807ed60d761c4d3d92f55604efa648c5caba130731fc2bb535146ef6ea4ff3a7cf388647ec25c3879671874ba259c6abb31b4a8090bea5aa7d6b05f5647caeada7ba35b45feeee744bc0e76d8ea6b84cc4103d358192bacb126800cb5a6e114709e7da7766b761b6fd0a83203b82b74e87d426e71ac1afae590f4f06008537e79e2025007cf2f5ecd0bc1a0e14c5cb8384b9daec501cd985c9858212ce2b9ab2422f6f7ee0e081fda987aa90a6d51ddc1173ccbee0592e970cd3dda52431c57fa323758ac0a4e47d049ef3c51211a4f9312614312b6dc119336d7bebbf325c2c4d24727e2909058543be4065c58f4e9e3f3f0ed88b8c392cbf610680123210d5214650ef8de411b7f6ebbcf2dd95f7feacd074a29516e42efbe37c239e9aaae6e0e1e1c61b418bff50f0d7d56347579a75aca891d51cb5299987734ee208f0d85512c846aed6db2a2f453b110fe2475852c92ff1bb3439d9d6f3eb76b49e239f72883d067bf9d1bffbb1b668d677f940940b9d042c06edfa9256b6afaa37f918a99309e4e40cd3d374db5a37bb43da60682ffd1d01cd1ebf9e90971fe16176dffda5867150fb83f271e4402ed52c1df78f2bf52"
+            },
+            Test {
+                input: "90078999fd3c35b8afbf4066cbde335891365f0fc75c1286cdd88fa51fab94f9b8def7c9ac582a5dbcd95817afb7d1b48f63704e19c2baa4df347f48d4a6d603013c23f1e9611d595ebac37c",
+                output_str: "021f06c7138f663522bcd444e597c2b78f4c8369c88747a155080005e09a68c6a73c4f8d1c7c088d3cda2b48f310d5371f336bc261697542028d48ff92523dd78c100cd858fc5fd1f4918142447e11281881d9c22680800dac76d690444458d53e35d263b2e081f470c9e8577565ef7f8c530f78aef2039a0b253a28e29e6c30fd26fff9677e65121b5175822d0942d0dbba9f764514fb936369f74324e8f950bfcc192a30921f04552245ee79cbfa319063e4dec133e10ec6b02002fa61ebc288b8404de81d9a513fa7fe6db2c61bc4ada6dfddb4b49b5caee1d7ccf5ba6f40a39af92ea26222850d4f4fa9079f79365806440b89663c705a247629c8e28e77fd17d39acb37bda2def7847c12d7f180a67bc788795d6ae9187e6aedf164e282c1e76322a8f38856c6d95460977fe8f6a760f49111400467e7e0eaa5ad7e9c5f9a17b462cc8b45f308cba6771cab434f407ca6cca371a6c7313cac055a13d5c79195dbd949a4fc9c176c26e6d5ecf343b199e478a25dda55fec4fd416e2708af001bb8ac3773e7824bbac1c0656953984b1109f1f95db0aade0cb53be77e88ca83a86563e1e87011e718fb3616ba3e54a2bf9dff761a42ee1e809dd1a431c7a832442461da90e7ad5fcd581827bfb2c8fdb0a046f09d30773fbc1481da0fbb92a6afd073ba96811acdeeedaadafce7c70e4ce75421c85e9c1afb270d120e186a"
+            },
+            Test {
+                input: "64105eca863515c20e7cfbaa0a0b8809046164f374d691cdbd6508aaabc1819f9ac84b52bafc1b0fe7cddbc554b608c01c8904c669d8db316a0953a4c68ece324ec5a49ffdb59a1bd6a292aa0e",
+                output_str: "dbc0350ccaaee7f6e18576e435cafc7cc65ebc81b27da2f18a888adee19418bf6f4d1b3088e5824bf663028a690354f4a953ae73cdce6b095a835cd45ed5752d72e699acf031529d73348218eab5dd6f98d675e33880f6e79d0fb3a78e843f26e018f543872a313560f8024a6756013db3ab13fb23661d33ef9520ea60a04675454b5f3069230447000ed2a879a1b342f560a8ad2f37afaa80668e90001d315ba266d03152e714434fb0f52e287a235ef5dc4252aabc8722b6920a069c98f69c64bfc31b1e13d01dd00524401d4f8494111137ee283efe82c2215fea54304c3297e6a1a88e46f000084ad090551a994308165aa2d0d96585dd4c826554ce80d3c00344140d4387322650f857350812c6c4e660d2e3ee5dec73d27a6455d6170569fb0f56313a561bc6fd1bb6fc11bc6a830f32847050eac3451e153c00bdab83d8cef319894db18dd80f1112e560e2353de9c2db6bfd428327aaba644c218fabf3d75cc42b3773db2113d037588af31f1b1f21d076f285f1f5cafe5312e7c2fca07af2e6fe3651aefa91bea2740afd1c2ac77ef03bbccea36940aa9a7d733289f9575e9e14617aae7402dd7847114c75eb4432ffc2d3d0bd56117f9286609dc91e9ca63e1e064f09f2653ba905cb12c8ab6d7772203b0afe6332c4e9f73ba4b652ff16e9759fb70ad5f548540c7ecf6c6dd7d17c5d2a9b45c548b7ec8819e8a5"
+            },
+            Test {
+                input: "d4654be288b9f3b711c2d02015978a8cc57471d5680a092aa534f7372c71ceaab725a383c4fcf4d8deaa57fca3ce056f312961eccf9b86f14981ba5bed6ab5b4498e1f6c82c6cae6fc14845b3c8a",
+                output_str: "7ac057c0dda89d3a001ab997f2e405b4c1d1906191c3a50399a9a49b2e01cb2c3d20db6618a7aec42f8143c580505145e60d6e1d4559fe3f46f5aa1373502eb0661a608c31839bc4d7fa44ad6586fbb53fbad598c05b9443d6cad708c8664079fb276947c4ef022c1bc7267b41c1764b249c8e7b347bf006df1498e31cc9ef2558f96f7f7ae323d6a633e1bf23312c1e9e2146676730954648727b61a5db507f1959250d49a52f9804668ab3a56ecb6c49ea7819d093e85a0a1335ccd4f54360466f7c37df0f65ce52f7b396b49d39a3aaaa0fe33f053ea711351bfec78a1e05f55954d7056b7380430b45275e2cf57ac13f7fe332b760d8bd793ce4f886130c3e4581a5995f865df2c68cb2fc01b558997a54ab8a684f5bd67855972cb3bd54a9620f71cfd3c9f0ff260b80cb14cfe4fa9d61583cfabb12be42c4c64c85d1f26d3b0645ac60065f9e85c70883be7f06b9376737f83313debecaac3f1146b050f8b360a614b6c72ec91a3e44b196713f5754f1249f6dceebaea8049ff32f308513f9c0c2353c9814c0e67cad64a1f332624490a39df8f9bcfa61c315cf2563031429567334038f1d086be0b9a4badcd9c4a0840348bd476c00a7cdfd8862e80eb9a833bd2bb56d88cb55d3d064326b8fa084f92f3dc2d8cdfba3e3a0e3eb9e44b1efe0563bc7a75f9a736a87a89a15a6812110fe92abf5b8f77ea88c2207517f"
+            },
+            Test {
+                input: "12d9394888305ac96e65f2bf0e1b18c29c90fe9d714dd59f651f52b88b3008c588435548066ea2fc4c101118c91f32556224a540de6efddbca296ef1fb00341f5b01fecfc146bdb251b3bdad556cd2",
+                output_str: "f0c453711d0ce1b3a120bfaf25570e3e949207f575782ffbeb8a6600d7caa9938d28ec6872d1fc914bf8bb02331c40728d3be531197694ce644ddd148d0ef54c077d56b6506a4a941b087a61d3d57b8ae53824da8d8cf069d1cf5df46e309108d74f318d38fe1968f1550ad7921d976ed5abc60953e4fd073a3ae7fa378a105e0fc3bccb3ce3469a536efa3f9e5c8590f19ec7e8708af92a9ca35caec1743f2284da30e613afb371507ec61c5574771bd7436583415d8e4406ef39150e50cbe233a781e8867639dd491b1f53217fde1fc5b93671c1b6931e07966de705d162f14ef3c95e67c40ab1c0841380f9a9165c5222477feb97e9a3c88104d7cee9b3ec6876a0ecf0198d258b9e308083b826f32fee17e2a59fc20046ca815fe0955ca88a81fb56a7c90bc922136ab0b3f3e034b62634fc830837f2dfd86798a11b335d5fba27398e5023cde6f1340241509e92c6a4b298b3bd330ecb2012b8f95dedf67b68d5309fa1ac9db856561d6e81666a49aade4de719e1a4b519aece0bd4941a36492e0b79cb7efefadf4edc6a344c4b0640a17f0e7f70e90e77dde40a82457dcd58658316b4b9378bf058b05ae39d0c750692b92bb2d16b5f43200def81ccc61b2a26cce991bf939534d61592328bfba68aa8c9f51f3a04466759d7d1b966789fcba85ee120c66a8f3c308e6a1533220e4a38c21ddaa4b2fc51fb49f59c84b3"
+            },
+            Test {
+                input: "871a0d7a5f36c3da1dfce57acd8ab8487c274fad336bc137ebd6ff4658b547c1dcfab65f037aa58f35ef16aff4abe77ba61f65826f7be681b5b6d5a1ea8085e2ae9cd5cf0991878a311b549a6d6af230",
+                output_str: "23f75edbcd5d5f329f01e45502b66995cfb9a5f0748e9e1bcb344b639873bba79d21ef36b8cc1bd8a2357d8dfbf3c32ba6c0c2e8936fb968389d8d1388c20b9f572bf9cef93891c643d672c8655bd67ecc3d0ec9452c6d1a0789ad3c734b926188e4a1b3d684f14c0a5d9e72cd2a10c5cfa8bedc0ba5f3ac6b5150a256f2b945586981f8092e0827294fb846986d3885f38bc6f945b900ebb546094e29facdeab1bdc1d7fe1c6c83e562d09e08319e2bca1f3ebd4a82b9ecbd8e6b38906d861e2e0704ee4f55ded4e7a74f188210ee439183e80dfa8795a1f75f0efd49a4fcefeb97f18736069bca02273ff542adbb6eec13128f1d74c87d6c6b45726f62ea57ed49321be6fa516b1aa2349b3c85a5f971c4e15715badeafd2e8a217d1188129cf49a54fd85803ebb361d73f0d8d0a7d557d0e17c8d83c27ddce473908a1cf9ecf0f8085e77fda3dc89c82609a647e25ffa8d2fc86194b2a793c7b32b4c893115eab9a704085047f9225a29236c6188f017ad4972661c796a3258ed49493533bef9a59a27dcbcf614aeaaf20bef156ad261bfa23fbee2d84d76af0e721739af02df710d020cb80e895bf20685d3ae61deca82d34206351870aabbce23cda3567dc1affef9319bb1a212d52baad92d069a332bd020420fd34e6fb6f97102c9af3c877abd9a790bdab7e7940b1cc01702d2e4ceea1a3a2f20e3b4027bddc6e2fe0"
+            },
+            Test {
+                input: "e90b4ffef4d457bc7711ff4aa72231ca25af6b2e206f8bf859d8758b89a7cd36105db2538d06da83bad5f663ba11a5f6f61f236fd5f8d53c5e89f183a3cec615b50c7c681e773d109ff7491b5cc22296c5",
+                output_str: "0af273f2384078bf8becf3731049a763753edb89ca1ae2ba03b82ef5dde8c5e23e692982c524035d406dbad8fb897af5d7db961652a0d6f5c18d71ef1f1a541d0a29085aaa1d26d2c4366da7e41781c34fa40a3fc7e9132c3f0cffff267e2bc771dd29266e2c649a94f3f15fbc71a561968e0a755d4d0ac7540b9e674539aa4d15d2fe81ae969ee492ce89104f994c6201eab2f6a726d9ab88479e324789bfd003eabc2944c43bc061c1e24b7ddfe1c980f65dd598c33942482475f4d717deae78ba3d8a7a887120d9a814d581be9d593422ab033a1776c3c7a6da30d4d83e8e120ac733303c401b68d1ca76b2a20af4ff0fe49780e25b43850d495ba91aa727dbe6e28b677c8c7ddabfebcfaaf67b8ecd8be1b459bdd68b429e7b25b6b0a02dd2bf0acefc5cbcfe5cd07c814e3266027eae612c39077c810e766a872a79d68bc8fe8edfa04ce2c80325c2feb03b5c838425860b24a6bb2d91bfa5f67102a3f6acd3dd6c9337bde3e94699f3b3431d8293f793886238228bddf4b38f229fe244abe471b16a1bcc73bb7bae6a93788de0d349cb75729d422afb32caecceffc42b7bd0694b154286f4cda4517534d0c2fa7b98e72aef0e2b8d8e0bb6a5fa82eb802c27511256c1352b20d2e59d0d3d63ff5ec33670fa27ca69d2f586826d3a1ea098cd9cca9231e74b91e999efda12f63fa8076a44894b40840fdbc4d25dfe1cf7"
+            },
+            Test {
+                input: "e728de62d75856500c4c77a428612cd804f30c3f10d36fb219c5ca0aa30726ab190e5f3f279e0733d77e7267c17be27d21650a9a4d1e32f649627638dbada9702c7ca303269ed14014b2f3cf8b894eac8554",
+                output_str: "7fc1f7fc27223766c8f4310087a3c54a5a8aa061eb20d367194243bb62c7d90099684bbf368cb6bb71802c62c9f3258992c0c979557622a5fb15ca0e50a26891e73790ea3df4859829b4f683c7f5c2db0fe08ecf76b9d4e897ab80530d9f1d1242b42170c198c7852566dfadac5740d61a52c4882f46e29afe2c7335c5a1157e5b93610d0a8e4529d8473330547efe22dd9757503c7a67ada4e9b2ceab8ac5b383f2d6170d6d6a17c03ea9f9b9399fd6c1cba624e7911dee9892b31d463b3a44946fbf246d773629ea484cd20b03d8ac428bc8ae87cc8182d96f8d220a7312ddbf191f458493769691e7585ccd740c30fe7d63101023867c9a3f02d999bc0ad653b71dc9a611be56a44d4df2dbde402a0b7b6d7644b5754d50dc81f59fb17f7c38e62427a844db406846bc74dae737e24ff806505c5c4351a54aa920cad01ddd8a5960ae143f476608a6db6168fd5d72453ea010b1139417277e6c5116d1d32008a40cb3006fb65ee9d4f5f9aab1648b3990f5b9dd338836460075b8bc504b4dd2fc04ec57dbc63d32ca39c07ec7c2348a459fde1533b30f496f84502367be809d0ab0c6e86474eb2d7a3a4ce29cc8d0ecfb87b4662fdd789a99034a64c5b40f763d098888fb32346eb644c28fd6bd6bb62e0d5aadaffef0bf0bdb801a809f76d79b84606183067b5056528cfff3aba4f0ec0dc926ffcfc2377035c8b5f10d57"
+            },
+            Test {
+                input: "6348f229e7b1df3b770c77544e5166e081850fa1c6c88169db74c76e42eb983facb276ad6a0d1fa7b50d3e3b6fcd799ec97470920a7abed47d288ff883e24ca21c7f8016b93bb9b9e078bdb9703d2b781b616e",
+                output_str: "1bdc443b8f1e6a47c575a1158c00ec9e69048be22ac067cdc1233171a69e773b6319b0bfe0281f0cabb4da1f75c583320a96a62fe8ddf10d0c3f7871023562177e827fe0b58a02d38c5a4903b7cd8b0ca80012238372dc5dda701a4287d071fa2b29771f70548ce43acb0f2e5a49313fc76ebafe8b75e121f0294e417323ec9bca9faffa81fed2aa775aa2d2c641d7be624ea861bd5c24ccfdac1ffdfac4627c3985a41ee5eb57e229e1a1b9312c6fda4291605d26ba4401ef106dfb5befa7deb27500f11a09617e8cffbd39ae95d9eee736eba41ae469988947a863ff6bfeea212eea29297025f96453dc3ad935e75f12c5a7f0e6c12213bd7be910d70eb978624843ca772959b5918e29aa377a7b4413946a97e546a9a05bf107c881c9499b9e907a667ccd1b3c64d674e3a5796ec33f6d6e4a2ae7d114d744bee7729773a627c063133aeeec4757f999ea7f01298a783c32934d29fee45e2048322aa3fbaf20f9d70c1d8a0183a630e3e73cb2eb1c934db4dc9101c949c46c1954d95a17b7d362b87fc51be9fe98fb76b19b7fe9d1d76104d3d49fa7f1cafc252f2e4ff32c3ca43a23947eedd4b88ea640e58de625cb0a9e11212ec1fbb24bccb39b06ac90973bbdd279578666e4d169290b0321c5b2197b6a5759fccfd8cfa820aba055f81f1030840f3bef889e8ecff87d0ee1c53db99f67827710dd0cf59346f2cd53db"
+            },
+            Test {
+                input: "4b127fde5de733a1680c2790363627e63ac8a3f1b4707d982caea258655d9bf18f89afe54127482ba01e08845594b671306a025c9a5c5b6f93b0a39522dc877437be5c2436cbf300ce7ab6747934fcfc30aeaaf6",
+                output_str: "78fa82e4172cd8cf41cad3d431e39ea0c6a88544402b5cad9ff3d8cd6dc8890260d989aee087dab49c092a94975ee3d5b8706d0f1f522e5ac350306b01b4b19a81377667b20c201241315c3c05a9f7484ebb70e79588eead5d9bebe5acc3e226b807b46192d64a2cb886e4b811817cf7f219934c57d5dc2d00e3ee234b579b6b6e2d5346d3876cdb3752624e65434e88d55e1284297cae624995b1b37671b89c57e876fb361ed8ac6345693d82bdebe00ac37de6617239205aef566c1619f406f4cb1c9777af2c07f693e35e4289acbd91c59f067c502446f21ca1602d10cb1d78d18dcb043c4b4e06972178bab4c90062342ff3646cec8120a5cd14e19715f66ec6f619da0edbf1c9d9bada80f0bb210f09476085cdf383206fcdeb987623cd69d591f301d8db94018ea3f90b8f067c3e147771f148a60b440ca6be7a1943f544375d50d45db2baf33944190f19446f7a1f04f7e45d59b9548e01eaf6e4d6d525b37a65769d280db6db391f27a9d84e4d97c7ce0afca3bcca7a97636ff3756c6cba855dd5c625574277eca6a2195027705827c0e4ff945aa57e25efbb65f5128d312145c5a8da0a4d46d805c3f6acffb151b0484ef811770bdd87935cdde0444276cc8b64e84b877a31d817e95963f3621afe6fce57d94d50771f91cd0ab1bc61dd97bcf03ebcbc2c2ec687b705a2bcc5d0deb20cbe6459644d14633c65b256"
+            },
+            Test {
+                input: "08461f006cff4cc64b752c957287e5a0faabc05c9bff89d23fd902d324c79903b48fcb8f8f4b01f3e4ddb483593d25f000386698f5ade7faade9615fdc50d32785ea51d49894e45baa3dc707e224688c6408b68b11",
+                output_str: "414eadc6832f91a04b7700e668aa487e63db05151e29ef1718c7d9f4c6edd1c88b05910f23d8a854b94c7156c421126272edb73a6e158350ec7a39980da19316346d1f330c3fb987d7b4c46b6469b7a59eb6b1649bbb7bc0e074c00a152517624f22a4a58800447e7505d55f687f08fb939d1aa6df8e73bac6ce88467b30976150636146526031bac9f6667aa71516f9c5f70e502d7d18868f6dd359d8d026a040af3cab533ea5a95dd7cb2006552796c5e1eb2c3b46dbd9f2481f1b428cfdd1287299e7c7129b377e3954ae0ee96f955b7f0354610b84652705a0594c045c3cdbd1b564bec43fdb5928b905023b1ba41b448e39e649c0b65cabe745c1dabe9352d05f165bbed160dc2c52794c5d0f07d1e18f47cb94f2f97190944be08c4bae53755b30d062b3d697575ad56fd4c75ed40cf7c239941f7b052500ee5ca7cedaa9190988f47a21216e907a63c795d2292ce926d541f331cbffa9f16516d54999dfc9911310cf564d8f1f00b92bd9fac0aac99a951eae3175ad20558e8b934e05ff58351056466a61ec5cf4f11a01e3fe0cd6ea280e27838899bcaf7fbd8cd4308098e2ee71a4e9ec258d03118f0bc4619c66e52f35f1aad2378d82bda8adb750313705d41263cf2fdeba1ad5e025fc76dc620cdc3b684ecde0283f9a7d69a8463b58f4ac7f5b1e2f3f580ca7f4188f32706d722be4543e8e0942b316960349b3"
+            },
+            Test {
+                input: "68c8f8849b120e6e0c9969a5866af591a829b92f33cd9a4a3196957a148c49138e1e2f5c7619a6d5edebe995acd81ec8bb9c7b9cfca678d081ea9e25a75d39db04e18d475920ce828b94e72241f24db72546b352a0e4",
+                output_str: "0cf9aa0f0478443df90bedfc2457009f3e58b06efb22d1f282da4a2320623a250d584f27e2d45f708da667a9bcc26e35c19c55b16a993ae9d98948ff2366d8a0aa06915ee5712d137d46d48c536db9a25bdf88f99a941683e342b5541ae481b1ba6a889b7acbe9a6593c53349c1b7d6fc8fc66627a2faf7811c0f0a49d904246b95e9b668e8bb25d521f0905841b7b2ac64b2e359fb48ff29d7a314b1d2e7e01b0d210986664c249dc711346449fc77baee4df54344cc18a816ad9c980bd0d9d01c4ad4ef0c702cfd87805103910e81cd3f6cf4d13d1398e755e5470e23acca6b510ca59ffa0b523a9d7ff7a5d85fbaeb3e5a9c11d947ac5fdac04b0b77e4ae7943f696849df0ff931e2300cb099f0def86d835a8af4b53fc6c3d38ba33158a1f95690e8c5560c060b0e48783af1e2001bb04cb4399cd27280715aa0eda7ae754b8a13f84916b003f87dceebab5938fc4342167efaa2a889c48cf92f6892bd9ba41b61cd1b3bf94d612c2ed603687de8644613605fe9f066e4fcd8ff75da8fbc9c63c37d1828c173bc4ac668aacd20ab1e3f449a7bc4f4ef0a6ab8d5b0a70cc2d706b6c6821771dead7cb29f2332f4292df7e397bdee393d57b06a1aad3da51cb8f1d11e43d2fdbe72f69f951d0fd9217f4462cbe5c701fff1025515829cebbaed488fc26798bee9ad6ce88f33029061a588e177bc1cbb24eb393481f3b61616"
+            },
+            Test {
+                input: "b8d56472954e31fb54e28fca743f84d8dc34891cb564c64b08f7b71636debd64ca1edbdba7fc5c3e40049ce982bba8c7e0703034e331384695e9de76b5104f2fbc4535ecbeebc33bc27f29f18f6f27e8023b0fbb6f563c",
+                output_str: "2b8f5423a417d9b827d98ac1d21eb7c1cdf4348f28ff08b6f06389e4cc2311c5721509a5888df03f7f4b94d42cb66f3b885ea8b130934a1025220769d1c352f72d378f3a63cea1e762acea57466c3af188772872c16d889f06bf0aa321170fc1aa842b413bff9fa32fc1e060f868a370434c99fe586e8df4c6df1d167912f35e7bb983d668225dfe5a00241a1050702a5cef8cb5ec957b779d6ca1c9f6858aceb4e927e104a1dc59c5e90b31f4a6e27623b46d40d472d6d4b6ea6ce8ba4721a5a765de104c4ed808b4ebd73d60a56363727ce0273710e63fb8a2d565c49823823f7b001e44c8571b885aac4e14f8651cc95c11edb3599bd85989c931f866b7c63f80eff135db2fe1b17d5dff147959606faca0fe22e5bfc88d43f6057db91eb0ad0c5491b66b2ec9b20ea01e215f40922f41ed4ed64616960272617f32d62f28897ba03c5a8657b1dd4adbf0f8e53492998922a47bb2d7897502f8687c465c8a7615089062108d70164677e11e1f63917a4f230e8c577346f880b7b8ecd0640d10622131731cf447662afebbb230c902b28d8445c5f3ea031ae7af04f5b22d3ae7ce58c6cb4ec4158dca5266af0c50f609b12c5f4527f836f8804777bd6c80f5d7d9b0f317cb5a663d3b7f3225361ea81415cd5af56bf24629d511a80ecd169aaf9558af487d46a569495a70c76cfe83462733bf58b2a7c78a7ea1fd05611ddf"
+            },
+            Test {
+                input: "0d58ac665fa84342e60cefee31b1a4eacdb092f122dfc68309077aed1f3e528f578859ee9e4cefb4a728e946324927b675cd4f4ac84f64db3dacfe850c1dd18744c74ceccd9fe4dc214085108f404eab6d8f452b5442a47d",
+                output_str: "c52001ee31f26adb120ead7699ee35ac178d71fb5b0731299552b57df2a4f521a021cc56d54f2b43d18d7726fa977fec221f6819b5b7f933bee2ec643b67e16bcc26a7dc1bb1da3b40f2fe02645cf5bdf3140e89abace926e710abf0f07205291a336187aaecad9371da35867ee8d8845e09fb47269ed94d04b47a3b6c460bf419f13ad2f65d63824805ed264affca9e7ec9774c4e3669580686c0a02eccd98277365940f4cbea5dd5b0bc84f981c16fa6cf2d6f1a292ec956c7d0714c6895e96a7c884173e662ce5db1018fb512ce773ed4752cfabf9045269922d11718c572a94acca1edc04ce16d533b064b416684d921d46a8f2859e7d09660f620dafcc232029a20886a552d29ccc30509a3941847244609911ca6c596e2fd915fa8be37d7eb41d403043683ae9c74dc7d6f4770086cf8c6e101e989fd6a5c60e34183c4ef08ea869fe2af0fe5ef701a6a64ee0d0f813a14e574d504e219292c103469f9a11de750832c2bde0261475856d5c9fb4727ca49ea81908a1f7faa20248c739179cc09d93e4901ed63f14a57b20ef9190176a27bc07f912cc62dd1328b032b893642118ef3426b1a8b95a0e36fcb8a7757025606e9e485b56e84d0e691234e072ad64fb8e836118634074fd8362405dbec4d8aa12e9e84068ee3b29b7f573ce1b52649ca0dc1f758c1d4f5e2b72a861d6326f01084b6b49e478fb4cd8ee92750"
+            },
+            Test {
+                input: "1755e2d2e5d1c1b0156456b539753ff416651d44698e87002dcf61dcfa2b4e72f264d9ad591df1fdee7b41b2eb00283c5aebb3411323b672eaa145c5125185104f20f335804b02325b6dea65603f349f4d5d8b782dd3469ccd",
+                output_str: "386c3b1a524f2ec39c33fb31cdd3981fdd57f1e33d04fac54828c54f42ef763856b72202799d4cdf4aecf073b8b9eac39f0f6954545bf60dd55ce2fab4558decd7e1a5a40b87a293d35394da64a4f606956213326ff4d8849a3f19781afa9dbc0ad0e0bed551164275d4fc11638af3acf95c86994c27ab72f0e5ee366ca8ef39c000661bddf23551aa368f347b4526474496ce14c30503c2513501404987446a193dae20c4b384d0d9926814baaa863320946b9759c7bf1bc890f88826da59e028f641cfdf7223db20b34b6389b048cbb85c4a0e4e84dc5c5241d2daeaa82e9092ed266971fd185d3b661971160c05c4b42ba8e1e8e31fe588c0baa81a2bf2017b1e0b99bc360faf13315ce88ce653c20bbcfaaa8ed013eb89fa5da39fc49d99e3c050e622122b7e393bd933b72c5392b165e60538bb6e29de30a5947053d4a23038aaefb13db8ba4fb3b1a65b474d94e4cf985b2402bf22ca7fb723dcdd83ba875df3c60350886cab6a1bd02fab32f1dca0ccd879b351196e1f8bcc3531ac653604932b69e7365b8b61e557585b7a836379d0229844f6b5d2c4f31a6ba2cf4a2585b7153c6005d10526dbc144189b0747cbe58edf2f4ffca80ff99a4bd7c8cce3bcac36aa5d0d7dc2b231a5b888198ad71042cda93c5aef246cf3fbe7a663fe60bc04cec70480cc2d83c847371ff5347a93d54059926b6b8f52ce6afd2e5630"
+            },
+            Test {
+                input: "b180de1a611111ee7584ba2c4b020598cd574ac77e404e853d15a101c6f5a2e5c801d7d85dc95286a1804c870bb9f00fd4dcb03aa8328275158819dcad7253f3e3d237aeaa7979268a5db1c6ce08a9ec7c2579783c8afc1f91a7",
+                output_str: "6bb18c45be71508441ee815061ed782f4bb5acf5393bc9bb825fc79cad025c6d970d615f4285185696ce226969d5e06e1643f8ba93f5617afb096abf46de2ee7d32bbaa335628c41f1ff308418556c51e6da30639ba5da36a14976dfdc013551f632133723aa9555b8b11bf0594457a6b288b01185927a48412019e58621806faa968ca26366b884c428607d2d6fe9e8924e6d8d769a7d2de90195ab6dee4896abac3119fd15ee61251fcab1d3858527e2e6e1b8ec05bf8659ea345e519cadedd779e40d2508bc6eac6fb531de15cf7f3478a4288df556d4b6c9ddc5f1b6071fedf3c4f9a960b18f8301064b4f83620f2402614c600ea80fb2b24bb9b8b777bba3010ac1fbe61ae18bfff9502f66111b8ca1e0df671c311a6f11697dd8c245c4b946b8db03d6c07ef14c45cffc328e6c12948d4137d6803469e996c1d84c3c1dbb8cfce592217155dc8f9e1e558cb58693620f57f5f81578f060b23a1a75abe8010fc538524dc1b5543d84f5f28cde4aa509b8a034522f2f61f8e3a683ead34ece04ee84663475d65d6db75cd6fbe011d6f1994d76be356604d93311cd0410d3b022fc328cc850d7bcc1bb96ae45e8b4c9e53904fd8bb8b0fa1d8aab9bbebba0724dba6a2c71f28ad705fbe6bfd958fe493ac47d70a1c4b3bd738c519558df9f66130c68831a7d748b7b382023810865cd9989735e25186690fa187e8e24b77b"
+            },
+            Test {
+                input: "cf3583cbdfd4cbc17063b1e7d90b02f0e6e2ee05f99d77e24e560392535e47e05077157f96813544a17046914f9efb64762a23cf7a49fe52a0a4c01c630cfe8727b81fb99a89ff7cc11dca5173057e0417b8fe7a9efba6d95c555f",
+                output_str: "51f3de30531335b02c0a8cda5285fbef9af618e433142e9e9713388602b0486a99707be420aeab53dcfaca68cc6cc6a3133075a518d2eb1c500f0ac2e0b8a91d3303594bb38ffc45b80afb8e25c4304a85280e6124891e739fc9df8e34abd9262dcb4330c2c0f22e78447b3fa67677acc1f3d8e836eea94aea4d616132650c9288804c3cca5f1c0139624e198643d52c42960052fbbcf89af00d58600a9597bd12a39a33aeceeb161ee527398bd915abf642746e4c965a77e916e700ca905cb70222a3a8b8c5de3acf75a9a0065681497f27aee6b1f4402ea711ce6b24592bc637f83baf912d3e10e0a7e03ce9314fb264e5ffdc3564307362837c28afbe2c94bd89ad3cd4a48c1a2ec38090c38e6cb4174149cf0d5841049c1d7dda1e51df8f3216caa119a9e3229caa062039eb165f4d5de68fcb76ed32f1e191166be83cb6384fec4528588d8a3188a9da7bc1f5de68c42d9e2934cc1010dc535ec87804810c009982be6646b3c50dcab7eaf4dc7786503f29eb3f1558a7341e49348f73479a2d3ee6b8ac076bf5ad17375d81f9e4dbb365b2489f17c40b9a4cc10f6de034b4b81a3d4f81475babb9581c4bfee62c5626fc436983570d5c6144fdd5a55e1898919a8be4ce3780fb254832cca90f988004d12039a947502216651775160d987df82f43275fc7b8a308c63db7c28959ad9d8e6d27a5a551e685b663974465d9"
+            },
+            Test {
+                input: "072fc02340ef99115bad72f92c01e4c093b9599f6cfc45cb380ee686cb5eb019e806ab9bd55e634ab10aa62a9510cc0672cd3eddb589c7df2b67fcd3329f61b1a4441eca87a33c8f55da4fbbad5cf2b2527b8e983bb31a2fadec7523",
+                output_str: "41143ce195b170fc23ed53d7ae8ca61f397cdbb72f261750a7bd26cff56212ac7bb1b18d002493f418185acc703df4417f44b93f4a7684d3d68f8f042a73c3841b6b5fa0079163d4881c39bcecaa548a50237e3f8df20f986552978ada9c4eb2e57062db8d91564ba4eb96503b932b5fbe3d88efabf452a03eece5b3e78492dc555ecc95714a1c5c1b201cb42e10852c9a5fe101ecd53fc6acd7e1d0d6efecf81ba76582e6e9cf80e70e52c0384ee05978a31234ddd1c2d501dec0bf1f26706f1c6af4a6dcfe1e7245d7bfbb96da619ef27b4cd67527bd6b5117e4e55297b9474a5bcd251f0f17b10f196cfa95ed3ce61458acc55cc2ba83904796aadd71e978d4615e6588954f7d48b1bc705b497e073dfe2abd5224792eca6c09d611c311c544bb332b2c9d144d24950f3a27857b9f9ad1db4dfb9aef65bce2c224ee9fe9785593cc9cc74d076bb5dc575b4ea65fa59a6dfce634ef83072cbbabc5aaa53aef5cb4d2c19a613d0054eda3954be7e649c2c38cfa9f7746941e2b77deb63e62a9ffec59d15329cd7d02fce7006406f3119cf579e1f6f0a1f4fc74c7031894d240b5bcc9a7306754af9b43df80005c7b62f885574ae9c44b90d5cfb93990cab41fc3e9962cd0f8047ca1aeb1399faafc6d6fccf66b2f02cfb9532899cce1aa8e822ee9498a67c3972407dfe98969f9df9ce328a4b9a1dae1651bafb32ae29bf666"
+            },
+            Test {
+                input: "76eecf956a52649f877528146de33df249cd800e21830f65e90f0f25ca9d6540fde40603230eca6760f1139c7f268deba2060631eea92b1fff05f93fd5572fbe29579ecd48bc3a8d6c2eb4a6b26e38d6c5fbf2c08044aeea470a8f2f26",
+                output_str: "1b0d344de5a414960e67d684d301901d8e89c25ebdf7494db9a1ffed44e5d688207f4533cadd09fc8bd428fdc3592959e9095613bd808797bfef5130fbfcc1fc72b58d93bc4a291284115d5eb47911fbc0a4aa5875aa2b6ee1e1bcb296507183aa5399ae8192ec6ae579d9ad172f72f5a1957ba10b0fa4e9666fee9611b048730275a0f4d6d48f98d860939936c9b41d1af5d729b11c93085346d8769c141b81fed9f17fd85c0197380482483c5f45b3d8bea2c2e90eef2eb489b6986a891bc0f29ee7e2943355e4223c241427c49d7a897c956323ed10b074132449fb6371a9bffdab8d113282016af1f7e8e26807a0b0b4809bc035bae86f476f7ffe002bbe7e30b4c06b00e712f1d54e954d59af083da123034e73b9854b45e9bc2efbbb7282743dc5942bf372d94432379ebea4a656997088004a5c2aefd6a4ce6fe94c2a06c8a0446495df224269e310f1dc184dd37ece4ee46038369c031ff90ad3787331ab6bb1cbaab7a0194fba947fc6485b371a684e7e1ccf4e9f4d272158a36b559451e48095b3c09328dbb52c7659c7e163504587962d87a5e60bb3c4868cebc204238fa08b97af71de9abe7f409ad0d29455e1ce59433685efeaaeccbe01462b1760fe25bace44cfa6e1b5c28dca00790d96d2b6fae377ce4bac7ce64a97af68ee913c33107e4a62efd4cc752dadb23877b54795a43a7af8593e085480f9b43c"
+            },
+            Test {
+                input: "7adc0b6693e61c269f278e6944a5a2d8300981e40022f839ac644387bfac9086650085c2cdc585fea47b9d2e52d65a2b29a7dc370401ef5d60dd0d21f9e2b90fae919319b14b8c5565b0423cefb827d5f1203302a9d01523498a4db10374",
+                output_str: "69271e30637ce53639a9a80582f8e9d91e0a19af1c25a4e316a4acbfc4534d7b6db55bbdea37f2526e5ca0407d0a39d06e2afb6538c125b3390a860e033378440419ff91634bca42eec9ad80e55e65d43147358146038c9baebab808c1a9b2d796bf22baaa54d92298212e7101e56d1a0a229cbcf9e08791c6bd464eb997164502445c2993b1d2a6ac4242d1f4108c2ae4dbf48fc403fb8f353c5ca3edc09c5d4993048962d1ddb474928bfee27df6af8beaeb264edd09db4950ac5e12561751bd3abc41c9a81f6c5c339aa9f7266cb4a28ee26f29571a7f4c9b350974beb0aaad642d9934e9eff77ed136bf825a845041b9c01f0559bb1987fd6fc951322e4a4b4ee50c7a7cc43324391603d689bd19ada54982e03a2bd12610a09bd076c0c3f6d6e0ca348110d8dc5daa5c842198ac5ec92a79099adea1fda0df0b35e8871373b312d61554391dbc9e1c5f9007c9d3799c24dc4a0894e175706df7d04eb2d69d90bab57117e04b681fb24945f3ba3dd7f1912171556464500d4fbb9084008a79eac50d8bf59163afba8e0f1e5f82e15255398f62890c9521a0571813210fccb582818a6d1747a31822db55c4b6bf15a19076b7d6349873c88e86bd87d08e0058a212780c86915ca559e581ec3dc7d5bfab9c5403661f09484f908dfb2d98b65f8543fb3f102c2c5d0b89b15e565e9b04e07f7141e35102bdb056801100b160"
+            },
+            Test {
+                input: "e1fffa9826cce8b86bccefb8794e48c46cdf372013f782eced1e378269b7be2b7bf51374092261ae120e822be685f2e7a83664bcfbe38fe8633f24e633ffe1988e1bc5acf59a587079a57a910bda60060e85b5f5b6f776f0529639d9cce4bd",
+                output_str: "2730675f5f4db76d342eae88cf856b370982277e24a1f95e071eb0c28d6655d9517cba67dde32ba6a4a322d37ad4a4eef90a60e2fe3a568417be75432f57964bb1dd7a5a165c24f38f4085cc4551c35bd0e2663198df04ee86803d75ee5ecbb14d7ba616693432b0ffc83f27e82016d7e3436c2384d1a7ab87e4ce758a5a83a4fd63831d6f88e4e80d1cd257ed4b418fe1bb498004d1ce8cdacede429a53f06eb77d0a6ab47beeaee12febeb07d434e26a71957e55f4f3284ba0f8157de3f1c8e0e4874db4e65e5243982bfd57a9e70d18be390834a9c3791e6ab6341739a963a946e1da81a4d9b3722bac231191eaa013e424c2b965967ae986d50426d9830e92499e0808fd6ea92a8a1054f93a0f84c11bf417de01a7b0ba5890172bcaabb3d2cc23853822960e666558b2b4695f38a22b576757c0a1a84437e7b627989a4053b14954eca09df2221d6c6e88654eea2a741df3bbd6ef2a8c463d797222e72de8e44c8c6f2feb44e3d2310ecbb139aaf3fe2c4b2bc9d7142c0291bf9fc9771178a484417202dc721876800e010e53f1972e3630b5dce0216351e687552af2faba699a4e3e0c5385d80dc367fd0d07258dd59a6ba5d2e0ffae60a5e0c48243794913cacdfc14d20001cd9a097a9cc57d313006e0b8945ade9791812b63e98a291cb009e899dfcc7bdf9f58f3866f6c33ae77718081a517720c34daeefa527641"
+            },
+            Test {
+                input: "69f9abba65592ee01db4dce52dbab90b08fc04193602792ee4daa263033d59081587b09bbe49d0b49c9825d22840b2ff5d9c5155f975f8f2c2e7a90c75d2e4a8040fe39f63bbafb403d9e28cc3b86e04e394a9c9e8065bd3c85fa9f0c7891600",
+                output_str: "df6fd8f4e768031b0ce25c199f02ec29053ea8200b7eb306e802c8df23cb213cfa06c37630a3b14570968948c5269a6770622527c87d432098f0cbccb733a5d28b035cada562bd0fcc032d2f45db8d2c948fb341ac2b0c5c699c62bab551553099e8a21518aff800c8ed42b44de7c30f29e691c1435ce72cb67060307d1b1c38192fe198ad3d20e9e12a8c9529f8a134a0ccac8de552af3fc05d48fe2e3ed1de5adfa0b7c324320e262232a14d3a7163a04980cfbf087bec24e356dfd8ae4de9b0620bffd1ff904e58b3908522ac13d1d541f662d95008b1f8c52da67829b7cd208bc9b8a3b6927e575bfbf7e29f1cad832d9d01ed41e5512ace419b92f71fa0cf5f79e33016d5e19eeff561c94827584623118ea367d768bc24927c92fc19999feff28e3a09d2f266b28433cdcd515895711fc081f8b1d143323b680e8b7469eb0fdd467143c292c8d822cc16111e9ab2a0c9ead40b2867303686ff4b9bb4dec4c8b552e3796cd91443af8c4542897769eadeaea39a366e91d65e92f06cd6554a1f6ca905996f5f62cfd559d1b300d912e6ff91668534880e6a8c414fad3c107a180be3e0bbf4f33cda343032d01c98c6320f6de582dab7b15fdd6e75ac3ac7fd079b191233d872ab351ae1a56f0a4cca8d0215ca1fd5f9c45ee171f4bc72d18e78ed6d9d651e40aa77522f6e3451995fbc3207fc0f30d1b39ee836f9371a36"
+            },
+            Test {
+                input: "38a10a352ca5aedfa8e19c64787d8e9c3a75dbf3b8674bfab29b5dbfc15a63d10fae66cd1a6e6d2452d557967eaad89a4c98449787b0b3164ca5b717a93f24eb0b506ceb70cbbcb8d72b2a72993f909aad92f044e0b5a2c9ac9cb16a0ca2f81f49",
+                output_str: "3c891240ed9f62f45658b5c1d3e4d77975e45cfb10c45513927ea9d911b3e41414dc0eea38c8a6868a9e0af20f96bac833c1daf71d0bfeabf41b8c26c011495f8dec94d72acb5c5c9abb1c372f8b779be741c860e722a0f85caac3d21c6c9ebe61c6489ff5581adf5650b6416e0e88a889ca60cc641052d601d491057bef36b4dc3b5b76baf0de4e7248a40d9be6d55a7e8c26663828d08495db33f94acc7e7e49a7a61f352816d8c4c0e23f36540418ae6dc009fab33c945c6e48ed60bc466478788002220da9a5560425a6162aa03afd5700cebfae439d20a85f2cb826cc8814940f2cf25e34754d8df03de448fd1d1ab38bbc2b1577bb1bc39da7b91b7e63f78c5f43a875c427bb110e0d5ff07e004ac9d810d333300a2778a06369b7cd684ac86aebc97d7b9c09442c35e66925bb0e4c04c5b3d11267f0f3812a5bee8e18653d98b6b586d5735d4d3c92e3b76db5be509ab32060e954d97fc8b6a428509ea98e4f8210f42db3229e07e1eeda684b47911556a8c34fb0dcc0998a781fbca574fa891c24b35251c9d0d8429763468cbf0214b2d1ec94ab3fae82e57c748122531c615bdbd4cda56abf319d6eaff738bda7683ba4cdd78737941dcac4fc45e379bd6512eab6d14c4f3d5748a3cf45713792d314f81f1d1f5aced67a0a9aa026433f320530632e5f72122b63acf01f2bccda9bd4fc579e6ddc1371dfcbf7347b"
+            },
+            Test {
+                input: "6d8c6e449bc13634f115749c248c17cd148b72157a2c37bf8969ea83b4d6ba8c0ee2711c28ee11495f43049596520ce436004b026b6c1f7292b9c436b055cbb72d530d860d1276a1502a5140e3c3f54a93663e4d20edec32d284e25564f624955b52",
+                output_str: "201561b1d68f1afb93098777b7d95e56b790194f45057b3b50f08ea89436e54bac9a5e945bd1cbb51acfbb0d61e539d1b3e896a1bc1426c1fa408b5d16d706457c35e3d67377ab2817127a852da463fe06d2efdd25016521f19b8d5e54014a54e297014230c81c917a983fe4429b47f6a460fcc4aa5a4e1e322cf74a9dafd30d313d2c0f9ebd1a8468a300f12e6cdc0e971bb7bff172593c7db286f467899b9a23ed3e222bd6124cb9c4fe2afac157cf81ff098f021b95f1069d7609963621c368afd3eeaf84a17f1469aeeddaec2db5bfffbcc39a73aa2a62578775100a92ad74ddce3a0dcb27a740a6e7c0f4c3e36e4ae55b04f04cb7d9527176bcd94df3b884fd4cc2ead608caa016eda2e2232d0af888a3add12cde0d8488650ec6047199842056744b77fa806bbbb96a47ed253192d46b47d828eedb9dc0cb38d576735e870826f829d76f58ca7f3a80fcaea1cac1bc38a6339c307f23dc25e3231094211fc867b0f0bd9d1584fbff5a52ec3b5624dc814208e484b5d069b78a577eccc017fedbbd139c13b50b395ad16cc551430229b56b4d75a14588a765728774cc234d1dc46f0e64e7845cf237330c3d2422cdef5cb1d741741da30f39d99035d7f7c49d6a3149d02dd061f85323d6e0054db7395ab8fc496418b7770355b854fd36fc1de72cef330976c2fa6fc73469b71b80f5d9b5cad008c38746a54578c3d195"
+            },
+            Test {
+                input: "6efcbcaf451c129dbe00b9cef0c3749d3ee9d41c7bd500ade40cdc65dedbbbadb885a5b14b32a0c0d087825201e303288a733842fa7e599c0c514e078f05c821c7a4498b01c40032e9f1872a1c925fa17ce253e8935e4c3c71282242cb716b2089ccc1",
+                output_str: "42a5915cc1dbac56ff74825db482afb8752991edd5b8f5d040fe45b30161c75178d5d56f8a6fe9b11a71e19d0ee241a656171ebd9501aa4b5f2cf0344fbd23ea5035d9a2c42fcfacb5f13d9212805f353932169a0628d015644ed450e8f8717a1901d5a21fd9f8360054946a29ca31debe683956fcc9f862bb5ab04f07ab11f751fc8d7cdb0fa9c616df691794c6d26cc1a18a45847fea76017d57d9bd6bfd1e5cea4c92604acc860252dd0f53886c48d0187054bdfe1939a2e6d5c570a82c300a6553bee5e107ee319435f0ad18b92552ed9b4fffd472cc482df76b6daae5432d17c2475444bb76cd79313cd14620c1d2b3487d91c25a47ade446e1defa7c6d2c2eca3163106f10eda5779ea6c21f8d778c29ca3601fe5f456b74dd08c7ecde8ff599b26540624bab26314453247a9456124f680e68cb91b8247e0e5a06cd366e46055f31712dcba81b590fba34c8e619c8f3efd39d2b69ccc6c3d184fd058a9bed65148ce65680f31715373526c509eff8ddf378a0127e1482809ca13a834fb3a1b00231f6b69a8523f72ef580150a4805981f9b1a7488ac880bc4018105545707b85f24569e4f864c30e66e750ae2065bfceaa2db440250568c6909590afac5c1df88d3e6f02d2b4d609460a6bf76ff7994eb5f64b00831c849f7851a3e743daed38668fd1548b333a01568140b1dcaa00e180429ec6bfef620b06c98ddad"
+            },
+            Test {
+                input: "433c5303131624c0021d868a30825475e8d0bd3052a022180398f4ca4423b98214b6beaac21c8807a2c33f8c93bd42b092cc1b06cedf3224d5ed1ec29784444f22e08a55aa58542b524b02cd3d5d5f6907afe71c5d7462224a3f9d9e53e7e0846dcbb4ce",
+                output_str: "bda93eafdedde22b029f4618b2135e9f7afa583c8bafc3b62cc667c4704cbcdd4ac6620361a0690ab8e857335c150c2d70fac2c2f2d60d6472ae760c082775d54c8eec450421d536b1a94a5da5d803d951709a7f5bffe63454306d7b229ccd3a89dbf9436c9c91c01a1d0964d86de868b4feae6e3b88592a85e2bdc82cd5c52968c85f429b08a2e61e1faac0945606ec462ea7b2af859609eaae3025e43b4489f7b1274922fa72619b9eade2f6c04d5863b03ef76189a81b9bed9a47bcc53501e96c2367067012036d07b95ac0604fb0e6a793881cd81d9577bf495ff769b72dc8b0d554ce70fed81fd3aed5426525241924423a4b11391d3ab16c02577ade31301960a579833c3ff5f9dc0ec068c3c92234b9de3051b58330ad87d0bb6f704b210e1c5a167684025af9791757cb0da0517e4a271c89aeeeebe529609529b69e9a53c1631ab89afa3d0fdc582e923e5f2293903b75a4c321117bbecf2e114be505de8cac608c1deac6fa33c658d72454fc5c3784989803a839d565da08436e700f3bc8df99bd3465cb4c1e8886fb20354e132a629fc964b10714f006978121e9737d70a77dc73ff77830e2dfb3adbaabc83657d8700206af318714867a1ba3bdcb8354b91f4f1a8b09bf54805ba01bc303e5f9887210584913c5130b643f15ab603adca3d918c3d5f15e97ec27fda51e4e6cb73402afad08678217e46b0e2283"
+            },
+            Test {
+                input: "a873e0c67ca639026b6683008f7aa6324d4979550e9bce064ca1e1fb97a30b147a24f3f666c0a72d71348ede701cf2d17e2253c34d1ec3b647dbcef2f879f4eb881c4830b791378c901eb725ea5c172316c6d606e0af7df4df7f76e490cd30b2badf45685f",
+                output_str: "e4d90a392bab78dd363c8747c586035358f051ee8909762c3d9ab4b2f1b7eb50b4738423c4a5087a5b12a9deefe186d0086f4dd0f9131acce891e43d131627316ae63c4e7d1250d809e78f94d276ef45c3c8ef4a37ac5910f1dd5f95989c938c98c55771b6de1ae68f3a9015c1fbf2447f3f72c15847eb55e0296b711881e0c8518995bd7f75c3aa9c1193f3f7b47b9c133af09cf53e1f55c17cd96318c821db4a6c7e79dd718684cd83d43e3eaad165fe26fa204b797c59f33589e92c43e7e799e5a857acee310e66f1c99a2406cf4d2690daec060cc7e3019cc4a842881657e58818ba193e4c8b8113ea7b3ba930abd58a7965f4a176cd5ea1447b41747694fb36775fa90999d1898949f8cb5943013a9cbe7654fc5d7bd7c915c1d251a22d6d8f7671d77417459366581c5587065c55aaeaeac19488876ed0d5e5f2f3f0a07006500d03ef8cc151ab6b46d587dff8930ac8edc3845bd2596387a56825a0036e1fefe70e2a53a4c19b5e45af6ad1c463042eee139b244a7751daacd4ca7c5ca075d2b639fb6aee355ddd4fec35f13c74e822e5f2c23a52eb2c2e209b62106195bdb80f19ef1636ca813e2fdd96425c971b6d0ed6b468a5e8f462d521e41586d7c848fe3103559d65b388a0d0f84ff6c4a48318ba3860ce5f2c419696931cd89f41733bab732fcf8551b4ed28a3fd2f1dd14d2bd570048fabd6026c984ecbc8"
+            },
+            Test {
+                input: "006917b64f9dcdf1d2d87c8a6173b64f6587168e80faa80f82d84f60301e561e312d9fbce62f39a6fb476e01e925f26bcc91de621449be6504c504830aae394096c8fc7694651051365d4ee9070101ec9b68086f2ea8f8ab7b811ea8ad934d5c9b62c60a4771",
+                output_str: "ab362a6667c3143e58db5d5e18294445643f1fb212faafcea656b4c9c9da509609e7b99ab0bc1c7f782cc8bdd2c2c49a0299109f842442a6433d9515badcb9e961c0eaa0cd90906c2970171ef25193cd49ffbe6609bc0f5702cc3ff1caa859b50e59ed6407d9da7ad2d44ea36bcf8b3f48aab75c1eaf0c2a8a41e33135358eaed3c5005cdf6114d35e4ea2b14e2f8ee6b995ca73fd75e281c3a145309c620b66718e058e171740649dbf4786e8b83c19a5cd0fe67b68e3fe2509662d968f4212224b466d04e4878c70b47409e5fb56ff2a5f324a96e799ccfc6613b28df7787a6d9670569687d8345ff1f187deb2a909c66f5b890cbcdfe18594dd52328f5e1d3b15f6398f9c3b880af4d314b1924cf2fc30f96b45869e40e4a147d94a4bd92e3cbf64ccca69b3476477b79b571fc5f911529e151c3dd2faea561e9fddf7de4c93e5ce3bf3b90d25642ef62740eeafa53cb4356cd598e9cf40339cd8166fe3cbefc35b5990e642d5e2578d893c0a46505af49280d544ce6865733c1ab75bbf194a4b6ab0447ee0f33fdbe80a41e860d80026a2d0c3fc2274c9a1be2c07c57482b3e3982ce5495bfa0f9b5a10d2bc46f5dc78e78168b552ce4d6fc9effc0faa5cba0cfb66ae078e6dc8db2459c127f970b379e87a267c3a0a5e1672b5a16c93e8e239c9c3e51a96ec777361d0583010d4a0773921dc48b63ba3155da483c03d5c"
+            },
+            Test {
+                input: "f13c972c52cb3cc4a4df28c97f2df11ce089b815466be88863243eb318c2adb1a417cb1041308598541720197b9b1cb5ba2318bd5574d1df2174af14884149ba9b2f446d609df240ce335599957b8ec80876d9a085ae084907bc5961b20bf5f6ca58d5dab38adb",
+                output_str: "d5d2074e7d45403d43d0fce78c3ab81e2bd601a0337b163ab2e2e11cc4f0e73bc0e41adeaecb5ce2b0422ee97ddd18869bcfdf9b4cfa9cdff5ddfde53b05d65b5ed250911b83be8b9e58655685a8d33c72826a1ebc1f244a433a9440b24dcfc691d9a78f32379bd8bbdf4f8e2f8eda7ca1cf74fc4e8c3c07349de823980d9ec8229a3c43bea5feb0bb8f25610127ed1fa1741f90cf25dfe73315d440088c3523d9d5be12431eb81e23ef5f5e9cb1571f08dd24a7eb421caa74c374f7ccdcddeb4ed57297222210fa4930888c9aaef06e36c78c43bf9196848cb07e1d941c719cbfb6af8a5014eda9df9b205dc905b28ef6f29e2c29cf457317e01bb34acd8e34c67f468cf41729bee3532833d147ce4e5618855f28936d3a4eb6e0382049614a5de0b05b317240a6e091cef8a26c7e13280e02d19a6635033633efb03fcd57ae2678c639b262f016647c61ce5ded0151951c7eb1fa1e3bbd1808210a3d22aba98835a686df3612ae6536d2180de2db5103e4be1b2d74a8482450bf1b9f4fa91861505f5739f64d7c8cb8c5a3a2f864161f9b495445a1f668eb9a86e0c25d1bd0c50fa6431c4d4beed9f53b6e918008b3dcef98b484161a8dac12c642df9278601ccd80f789b770f05e8359495ddef5d6fe54086827ffa8e7b2bdf03a33397ca2898214de5a36d18ac33ee1cc0ee0fc4416a86815c7b98ea08c63d23ceea1977d"
+            },
+            Test {
+                input: "e35780eb9799ad4c77535d4ddb683cf33ef367715327cf4c4a58ed9cbdcdd486f669f80189d549a9364fa82a51a52654ec721bb3aab95dceb4a86a6afa93826db923517e928f33e3fba850d45660ef83b9876accafa2a9987a254b137c6e140a21691e1069413848",
+                output_str: "8a80e00c325a49d17acbb96fd41e874eaf00a0d141cb59dd1363365db060f20c1015929e88e0ba0589fb35ca348b3f02cb256cd5fafc7b1d1a7445c238167f325a2611f7c5e2b7ed44395938a5ce501d6cf78c9b9560d8f84210eca3ac12ed40954ea0c8ef362de08cf11fcf47c34a3d56f271453bd62f74578f06b1c3958be6d87331d8128070c244900b6dde1423b2561504156fbc045755e1b591234960e1a44fa54cacb1795ad8eeaad38faaac0a4eb846a18b42a526018eac0a5041dd1200c4169124590acf93f2f26db5d173608fb0b6c3c83f5c0b01349c558ed0e5851c9de615ceb684a3c9c663119444008da4a12e9386c98e15cf23cfeeb2f8632ebf15381d17268a5f92fd15d464d9e1f6ef896828420c9367b14c2b7e886f42c439801e0f119d1086f2a99b5e402e786b8c5a3b7902d2274ff1b5cb706ae0b5da9ce63ea943b8ad8743c0af4cacfa6ec9a2bfb45ef680385568aacc518755b7a2c4ed40f276e25be1447f1131d064a5c54f3bdb80d4e6e1338108251b8294cbe4d3f182f3f462b3983abb7f25b4d9ac8a3e2f3cca397148ebcc154de7dba5a4820c677faddcb502b6a67af0dc0602cde5ba983c7be0235c8bedf1916f51433d80ad87b4815c6c397a9906b2d075bfc0f72431da10f04aae61545a62364f336754248606ab062799988e6b0d71c2dbf907e211c963a3823332d6abf4450d311080"
+            },
+            Test {
+                input: "64ec021c9585e01ffe6d31bb50d44c79b6993d72678163db474947a053674619d158016adb243f5c8d50aa92f50ab36e579ff2dabb780a2b529370daa299207cfbcdd3a9a25006d19c4f1fe33e4b1eaec315d8c6ee1e730623fd1941875b924eb57d6d0c2edc4e78d6",
+                output_str: "b645903f62e2a0394b7d98a526ce6c1725a03f4b35cab927ad4fc2831f460ca6eb0959bdc5d90bb37e1d0e3ddc6cbdbb8f61d921b7cc496d903a92166bab4a436bbe6e9230dd0f91a6ed791889b67727338ea636f54affe59d52cad1b0d26aba8a29c92874b5d6276369fc45769a3323c9788a7ab268081689614622bed3dfa207a0382680219d24b2854eef3024a34de3fd4acc827d52ff2f1a4b40f1e957729609f8d3afef23a94d9e3efbfa3e66bc1ed44c426d27ed4fda0b4bbbac6050dc71d064de236dd800d0e24188ea0b1899ab6d0ac16986034bb1c8a21c7ad7f069e706730450f046d5f9b3c066c6cbf98c5151e5b45d6b0f3ecef0377aee19d83941cad4484ad07338e7da24439ee38875498207cfd01349a3cb8bcab058c70b48827c22278667026acce65a8f643bda30a3a6febb5eb7b981963cf07f6fdf20aed8769c8ec35425c4366eeea26ab28bf43e7fdc8b4f762a2cac06d10e1a8c6ee35bda64c6f71cc02675ea4cd20b112b6e12d45df6d37d83f04ce55dadb9f54c8a68e2c76ac55aafb1a3231c277ae27bf2742d08ffedf08df3f098c5c60b59d2a89d2af150b3fc73e399ef94b5002dc0ad1097767f47ba07f442d4df4a4d72e5aeca7b2a37899f50fa3cded91474da106fcc96b28d8418ea340bc983344bb58f244ed6755ac342b9e6b00cb19f9afeeb3135e0374ce803cda44e316eaa0b6e1e93"
+            },
+            Test {
+                input: "5954bab512cf327d66b5d9f296180080402624ad7628506b555eea8382562324cf452fba4a2130de3e165d11831a270d9cb97ce8c2d32a96f50d71600bb4ca268cf98e90d6496b0a6619a5a8c63db6d8a0634dfc6c7ec8ea9c006b6c456f1b20cd19e781af20454ac880",
+                output_str: "b15d1dcc49b25b2ecd567e1d0f46732cad3f9559efcfbbd1793da46a5d9bcfad723e504b12b7c1b65eafb9647dc35a484485344b9dec5c378dde04227f7224cfe6f06a962f380ae104146dbc2425fee1d7ae7305e2d2c4e2f91d9188bc88799b730abf3647a4365562acda20cbcc7dfdc5c6dea8dddb20443b9253466e4e215360f4066d918d938fdd204ca826e4a3358d169fb34410d45f8e783e7fcbf97a9cf0168e8ee6402c8b627de5bc4dffd8ae2c8807f863d10edd57503a99a46035173a20dc10df3e6bda62b518e58e94e5624659890f1174b3b7d798206691d3ffa6924948293821616184e160f237c1241f11779cdeb4fdd858b73f3df45f05f43bc81e0ead584999da04f71ea4914f8d8ae17de086cdf69c31fccb48b528781fbf8dcfc710ac421d28e93ea95db4a6d38c1d47c800fcb3f816e36c86d6b3e5d6bb31c325c7a0dca4d395867f436f077c6711bb96dcba9a6dec6318fb9bab829ae40bf70c55146b87d9fad9a839cef462249bdc49b8022926e3c664d6659523123a6ee980b69bea87437322da1dd6235a74163968c0994ac0c21156476d83f2b8697a1b510795d936dbfc2cfe67ed401ce708c7531f1b4de75e8506db082fd9b3b24673938242fff4f30be97cad8ecd2f88bb5f497a8f154465921c9469b70fba1f45d76c9a40228a93d67836cb7cfe2f25a5f56c216084521484a7224a7a976323"
+            },
+            Test {
+                input: "03d9f92b2c565709a568724a0aff90f8f347f43b02338f94a03ed32e6f33666ff5802da4c81bdce0d0e86c04afd4edc2fc8b4141c2975b6f07639b1994c973d9a9afce3d9d365862003498513bfa166d2629e314d97441667b007414e739d7febf0fe3c32c17aa188a8683",
+                output_str: "7af1cd3572930b440f871cc3388678a1c612d6a590cd2b8692e0b96010ab4e122cf856925dc84aa0a87c7fb1661c5c74b0811488d3d486014e81b0d29b73450a0670a6f8223df95b542590b3f6506cc18949fb6593f1a552e064b4e1576ad7a7cf202e0b8f90eaf90147d44ef16031d390940da5d74c35a269b4adf4a663584292007da777b04c15c03f7635bef56c1ca807d1cb3a8dae8218821c44c7e6275cbf64d82453f764b458aceb881816234494f717f5240cfaddb3f11c1af02b269f0f76b9dbc8ed643fb3b7c9f8a540a453c1ec85abf9e8417b1e4de9dc65181ee32802abd6170a581aa2dd01188752c73d406461892d0d0909c5d3fe0ecbca3d28f65b905a2dff142e61cb088f9086d3c492e73c0eff3afbc37216ee98533b236406d80797933e54d3c21ae6b1b81f459ffd7b8bd1eb872fd62cc0b95f5384668a1bf91a474bfb97335dbd8c4761f3bb936e2032365256b534f98e9f4b3c50b4034478efa268e9ed9eb9864044e90dcedf4a2ecb9e8617c4e4abe7cb499051143c30bf73d397836e422a2ccd222a299603a3e4eaea9bd2c3d64a0ecb3cc7c0bc3d867c79231bbbc8c2ed4212edc8b25c04c57e9a3ee8c103aee4ad6af025016c1a177288f4a17fe20a2e210b24a7aab63d3fb4e687ed3ba2bc163f17c9067d07c18204d0af96a41cdf5be9c6b89502d7cf1283e82410b11537cc931443076d60cd"
+            },
+            Test {
+                input: "f31e8b4f9e0621d531d22a380be5d9abd56faec53cbd39b1fab230ea67184440e5b1d15457bd25f56204fa917fa48e669016cb48c1ffc1e1e45274b3b47379e00a43843cf8601a5551411ec12503e5aac43d8676a1b2297ec7a0800dbfee04292e937f21c005f17411473041",
+                output_str: "6b1b8aac47f782208f50af3f977eaf8f2d69fc02390ee17bf1761ecb73d1088d236a5345380b6297ad1fdcd5117d16a3c410aeea092d9892ae95c7b977930655c75cf7834c101f69d2e33a1a17a489e040c5db3f83a5216ed5778d391630d17405ee0a96fd7b834448fe0bc61cec5014a6af9b0f85827832e7469869b0872497033822d3419d43379aeb6c31406afd1199abaecf3ac8e2546b9736f8c4e399c8698b674df5cf6be81c73e52dca979d3281200b9df8d99bb6c65a7b6f620e1e4e6538a918c99cde6cb33150f0896bb75421b8265aabc241c02d93e63476c351396e5b86dc66a05c74ae2ec87ea1d175d15a12adf18f9792970de3b9e30890d8896309815d57ae238895aa7e76dd6a46019f005f193c737b452d32649a8f39b1ed00ab8961a6eb04f699ea62357b7a38c423ba9d421529266459ef292b324a16062538e8c6550f822c2c140816340f907d5d10b563198bb1539b82e5bede700f7fab66eb8da045b23035decd3f8df11df98a297a49f5b896a3536bb5a3e17a9da1b266ee18ff6d4a6e59af619306bf30316fdccb7fbf5800916c18832f4cd21659774411f105ded35de8b0d4b0b54755440e26230e519b66319696e6abd180ff5314ee184d3b2781f338fdd3e3935855f4c8b4021154eafe67497599d0ae393a516673a970cfb9b7058826d7f0fc29f3ed34ed31f45790a63e5ac7918a4c3cb494"
+            },
+            Test {
+                input: "758ea3fea738973db0b8be7e599bbef4519373d6e6dcd7195ea885fc991d896762992759c2a09002912fb08e0cb5b76f49162aeb8cf87b172cf3ad190253df612f77b1f0c532e3b5fc99c2d31f8f65011695a087a35ee4eee5e334c369d8ee5d29f695815d866da99df3f79403",
+                output_str: "f76b436c25e0bf2d75a0df0152d04117ed8dc0ae55b13a2cf839e41a90c6070415eb8ef70a90bf205b0bb330435abb41bb3329d015e9e56e86418bd671d0375e3af8056eb882ae4191f82e062339d5505526ab42bf6cd54f0d36251a78ef274cbc797b89672ca224cb9b94e36648b362338d4981821b0b388e08ce97253b5e8c776e9b3aea33dfc3815b5929a3800bb83543d42e0f331c264b1855ad3c002bd80d035932268dfe4cd6600f2b1f215f1670d7a4512e89c3d1509271abb42e2608d7b4a900e00593e0509f7c882ab0008aa83f5879f30d95a319a4058987804e5014212d415ba0e1c2407b9aa7b80945cf460e60609ac885bd7d639c9bcc961d6c32a96f041528b64747b5ab9557971eada1ebeac47f78b3992eef2bf2806213952489934e7f5410602ed0987d8470af3728a7f5ba326b77835694e32675e463c604c18db4e4f5e1abd05668966b8d102172e232b4eaedb3c73e7a406c36ddc641469350d593336e9e5c8ba3c246154bd3cac8e14cd60c9ea724ff059c931b778b00a3c6e1016c1c41b3002f01d937499518a969d02ad08b5ab385a60cf5d018ef405df9caa63bc49015407b04aebbe02f206dab67e72388022d99d5ba4f6d57695186873276770452d602635aebbc988b7718f6ee99f9f05a6028e074bce86fc134aba4cb82e1529acc2e50e53f466b9b38fd3fc7181163d9a3b58f143aab6297"
+            },
+            Test {
+                input: "47c6e0c2b74948465921868804f0f7bd50dd323583dc784f998a93cd1ca4c6ef84d41dc81c2c40f34b5bee6a93867b3bdba0052c5f59e6f3657918c382e771d33109122cc8bb0e1e53c4e3d13b43ce44970f5e0c079d2ad7d7a3549cd75760c21bb15b447589e86e8d76b1e9ced2",
+                output_str: "c870ccf74f9a979827e1d0ff8e1dac93a2e0f10a0ba7a4de041853915db7d86c65010db41421201025d3465ff1267ea5dfc8e90cdb4d933fa58f5a5e830c646a74e5bf807495d973929cd2d4763a0615902b8df2d04a9d2553bca94696db2a332ec56b5612de10cbd2e117ab226769a0f5e12e380e890489c4cee3156b4cf1d4fa2fe55e20db06d84dbb0f9833a3364f64481567c74049517db8d75f6607467efed0d8976adc7c7f265371a552767bf6ddf87f88dd1bd326c46cc7c9a895d1d88d4452a1d72e7adbff6c02c5114ed5799c4e75944294bff16dc782d529341bd289da6136e0a4223f27e886d8ad057446e6bd41ab8efd676b5084084a313e0bba30c1dbc3c461afd8b5c0ee02aa0d1bfd0a1ace35369f78d5531286fb268f94d4ef50ba6a502c2eb2b744651b71b59974202a8088780cdebcaf18ab8ca8e5ae928309efdb5d5a639d7c83bef87e5aab4d403f7a9d22edd1cbcd409b822f33225f05ae21c2bbe9e7a0b116b502da93d6547e3931763f4fbe1507dc031cbafdb08f4492396d4d32fdf8936d0bd082d45e70b3cdf8b807d974a70bf17fc54a4a034bcd7f5dda8c1002b92a641da7e717d8c742b7f22fab4918b1b3929c2cf7533666121184383746fc5fbb06e2796eee83e6387dc610717fe4c7ff316d87367f6236e36524cf525691d656f77732b4989d87fbadcc67886e151f7a61fc9141af81b4"
+            },
+            Test {
+                input: "f690a132ab46b28edfa6479283d6444e371c6459108afd9c35dbd235e0b6b6ff4c4ea58e7554bd002460433b2164ca51e868f7947d7d7a0d792e4abf0be5f450853cc40d85485b2b8857ea31b5ea6e4ccfa2f3a7ef3380066d7d8979fdac618aad3d7e886dea4f005ae4ad05e5065f",
+                output_str: "7aa373d1ad451f79a4b17bc9d3e2ec4d43457c6251e958e44f8d5ef360eb256ce5ed5082b938095df2ec30deac299eea5268946cc240ae0cfc0b8565235a77bed4b58560f111fa5630996ad51065a6a957979344c26c0fbc9843251b64c899aba1dbe5124a21a604e706a50478db8e93f239cd11d53b2f168a946e979aef98d6a3ceae032713c241b8176f1f32a7f132ecece3fc57309f6f0dc9876b9327c4c03c42a74ec216e0dbe026dd167ee94fe8b0032f9ba033ed3e6bef8dcddcb288ce5f8d1b4dbc01a5bf51fd725206283c7028d8013a170f0dc4ab107a442c95b0214a71d3bd7a27cc48cabe6bde4a5aa4698f56258e175ba1c6f7be6d7ee60cb5bc4926cec0d94a422554fecd2d7666462e125fa3c2fb84e98f2095b119ac492ef8eb3666a3bbe51a6e4ce3cfd1375a21d1570be8a1cd22009e8261b3cd6f2e2085443a6aa76c91a349a7c49cf5f477fc017ad18439c580dbafc94e96739732ddadf4829f9da5fcfb6851afa968e208d4090ad99f61f9657ee958698fdd1dd5ef21543d238d05c4c604e26d21dccc8c878344ea888f127372218a4511b803e3e6ea03cddb2574e636eb40ca242fb31698290eb9c017d326a35d884a88c98b89c33e8656b717dd734223ee76b5eb147af7521bf1f827827b37a6563e601afdc3796d8da4d1084fa462cd4af969a800f522375e2c754bf20104f13a95ff2dada5674f"
+            },
+            Test {
+                input: "58d6a99bc6458824b256916770a8417040721cccfd4b79eacd8b65a3767ce5ba7e74104c985ac56b8cc9aebd16febd4cda5adb130b0ff2329cc8d611eb14dac268a2f9e633c99de33997fea41c52a7c5e1317d5b5daed35eba7d5a60e45d1fa7eaabc35f5c2b0a0f2379231953322c4e",
+                output_str: "a1d00913cc206be2d1c38c22b6c732a05368c8aab30865be5343be3c73aa6b7e8aff69a544257db1e6b6677e6ccdb6eb358a0ed096bc9fff0dbf89b1e5345037864132fa7b820ddddd5a88b953ce834f1aa89bf56fbb02670dfc9fa29892fffe61daba4195850ca669f6e4ae00687ae4af3a15b27a4e489a4aa01ae62e23fa012cfe38bb601b343095b5da20cc2b48352cb245c5306a2fa9f6cfb324b6debda6513221197b24eb1ec2564e2527491b539289eaf593912458d835e3f8f46e058cd6b3b85d0833de691a1e08cd6742e7b2957ddcd0e04858fd64987c66b6bafa7a082f32d515852e931a382792ab4ffe17b39d8918cff002cb01c0cb1e1fd32bb8b02df964752523e64df6c74b8442719c3d7dc75ce9dce5474ad6f235280cbd1f0268f19e695549016e948a7141ff4602330a096c67699b29ddbbb8f6600770cbd0e398b013932b04526a055b51d92f0ae8535a7e91936bf21ae70368e09005b14f3fd9e3635f35960d89e134e9b1447971b0d1cacf554845ae74cd93f73fafe94189bc22d1db9815a65b414dde694fd053aecce3bbc3ce7362f353a9434a49fabcdfd7e3cbe73ece064deca30e4be01b1135ff6303e45e8065ef415befefa948adf42dcef4520c2772c8e8438b60113919975ca0dcd2798bb026d4b59d3904fbca4998533aded822b15ccc86457e8507aaadc7e3ee221543472a87b730f4e5c2"
+            },
+            Test {
+                input: "befab574396d7f8b6705e2d5b58b2c1c820bb24e3f4bae3e8fbcd36dbf734ee14e5d6ab972aedd3540235466e825850ee4c512ea9795abfd33f330d9fd7f79e62bbb63a6ea85de15beaeea6f8d204a28956059e2632d11861dfb0e65bc07ac8a159388d5c3277e227286f65ff5e5b5aec1",
+                output_str: "e28d36bd926b9e8c105fe0099cff1957ed7accb9618027421febf9ddd3129f4e6713376b3b7ee710430ef381cb12b831c80c7b1b93765f7693506733a75ac0e8fb5d3c30c6f4dc735c4c3599161ed02f4abb5cdb174e53d93d91e1321edfd79c0f63c92c7e5a253c1b8c4842f053ced0033405fae5f16e2dc30024a6b1663a86829abff72de6f2a91c1cfe5955cfb584f8c65b9334590c9c468a9b0fac172792aa152f7dedeaa4fa22fa7ba44131a1143f79053c7e2cb5aaf8adccb6ac72300892f792590bf5a1a9745fe5934c712ced382a316c487efe0e6f146c8a562e6b40834fe20c362e495fe9e5cc871edd2d61361492ee60cef26ed38b4da0480b4dfa66f5e71d44f10159016093841e02c34001800c5cdaad0f9cd2a3144911031139cd6c54443a1d82405921b86deb03e8f0c1ecd58f63b88944182f034bd07b0d021ebb7447f660e66bbc0a821c7852d183b806f0855ae194d80073280f3d07c2dc03571d5c6d0f0675afd58ecfb211ea27733e870a6e86ae5108d8c1c3524b99648541b61935746310fc6e99935e7c9a5d144e0735f2cc32b6dc42b34679052203a777aecf26d9461946699f834940bd34f8fcac7c22e29b2b0cecc60183c44a5a63078127c10c1c14112226520cebf9d47a7fbd4002ad482cde289e7dad3aa891bba0b6b2b2fa378d26d629b4ce428f375bae3fea5e5c6b048928ec92099f3c3e"
+            },
+            Test {
+                input: "8e58144fa9179d686478622ce450c748260c95d1ba43b8f9b59abeca8d93488da73463ef40198b4d16fb0b0707201347e0506ff19d01bea0f42b8af9e71a1f1bd168781069d4d338fdef00bf419fbb003031df671f4a37979564f69282de9c65407847dd0da505ab1641c02dea4f0d834986",
+                output_str: "e3e693b2585c32926882c97bea160d46ace5abf0fa47a9084fcfdb22de3c65f43717358c2c2ce680d6d132443d478478a304711be3c5795f3eb0a7bf043cae06e84443eb599dc259b3ce1f4184abf1e6794556e9f2aba99e5363dbc7e9c2c802976c87fdd7e0e3884b971ab33da6cafb65ccabd6ce492a59d359bc17d2216381ad838989de9fe82245ce07ccb1239fa5a3d664d5b8f2e3410c023066aa47e030fc73be5eba27d83d656106401bea73e36cc09f8a78bc0f4fd7c4b2b4e7d36f4e3cc31867d1ee207a7936fb3d5fcf512669af63b9f01e4188ed39b1142caf6578f788b53c3d6303c25c545dce3f0b037456e3e7870392f43051fb2e8fde663c80350f94f7a52d511a56cc268335d1ed24c9948c6e0426aedbe1e082c0f075863e3dc0269be5c83ace9a98af1ee45c79ba263aa81902e11f880205b7bbcdba54f766150e744bd1e2c97e64b4a50a179b940c01a7aefea23e22dc3443d655e31ffafa67fc555727c8d02c3fb3de7d6c13438f6323b89b7c975fc5b90d80be8efd41bbce90f636ca01ffbe3ab39aa0f43460f33dfa492718a411711e9e7d38eab956655314f35d36120237bea48eeedc549256090ddee8ab4bf2669131cfb590c65bbce018ceea3ce349a8cb83e3518ce8f353eb07f9007600c206c7f6b6b1da24f1a263f039773ef5f99fae6d9b2b3160199f17d49ad69d51bf66915451f43ecdf4"
+            },
+            Test {
+                input: "b55c10eae0ec684c16d13463f29291bf26c82e2fa0422a99c71db4af14dd9c7f33eda52fd73d017cc0f2dbe734d831f0d820d06d5f89dacc485739144f8cfd4799223b1aff9031a105cb6a029ba71e6e5867d85a554991c38df3c9ef8c1e1e9a7630be61caabca69280c399c1fb7a12d12aefc",
+                output_str: "a178f3b574a841c88ef21b6a20a100625334f4fee5966ab2164686151ab9fed082ca4a9115a0b5f099c5dd4be4ef1082d533212bb862f084225655d8856e29f279418de6fb723ed15c341ce310b53e695c08689f776e4474fb6dbdb7da46a9a2dfb7bc374af86984e1e10ad9d48b744a5fa98a0b161738468e06ee4e836bb718befa381cabe18e9973ff07dce1920b19dd797f84cddc52dbd49b4a462fd1a12acd364804a290beab30af0376ca098d44e5d141d1636f6073569f2ce7213f6407ee376680e8d676942211a9efb756ef9dca40574aad2084fae0b617d727d7951c1321616f26569d96de5ada8ee101bcfd2c43c338f8957dec234e23f5a1a0f663ebecb98c35102de1c101b99e8f42bd8ee7c528b1651099545f7bc9bc315c8861fd7ebf26b97a519931a63e0b06a73b14cd2365383b44a2107fe1af0998f1574d9fa8818dc51d642240dbd0c104e89393b2c381944308d828720564763d3bfee221bfa99d976701717d4214cce2fc25763c1b25ef67286bb7e497593b1a077912e3af76993a4e20d4e8add7aef4f715e5f1c8bd68e8913d9d8057447f273fc41f70a0290a5ebfdce46209090032801f2cef44c8015e865d75759c7b2117c6e8eb6b57398b992b0e073c1fac374c819b7ae16c464ab5019a45e7a6ad57b75380ff42d35339f23436a0d58497f7a12e4c3eb34816c4aab9a2d3655079c12e05ea36"
+            },
+            Test {
+                input: "2eeea693f585f4ed6f6f8865bbae47a6908aecd7c429e4bec4f0de1d0ca0183fa201a0cb14a529b7d7ac0e6ff6607a3243ee9fb11bcf3e2304fe75ffcddd6c5c2e2a4cd45f63c962d010645058d36571404a6d2b4f44755434d76998e83409c3205aa1615db44057db991231d2cb42624574f545",
+                output_str: "11c57a7af45809863e024835f2a86bcb81763412dbceb53f31153730fdfdc32a8adbe3a8bd6d4778ea33afc063d9767bc9e3afeea3c78ffaf5fa3023093c798f39111a182516218f0bc78c0307c75eb212b0edad184500261e00823f423d84bc2dad3ffc6c2ab675a24ccfdf0de5f669d1eaf91973071d50ec7d2c0cc4b6e42552199cac4b65938f7e704248cbff272c647e953fb9719fa8aa9c319fcc45e4fad0752e7416f9df0063f1a8bf43e316533c046c4f2e7254a02feeaebdcd4df19b01c18b8dfec1d291fd670ba6d434b41eb6068a365973082107abd6dfb62fd428b9b183e1fcfcb654a6c7a55b91e0615658529fa4f6178fa4f5cef329376169af143b137b9b81b273796cd26cfd8372ac3184600ebcb2dce06aa7f22c055a7b622717db8e15571acc61d94d8da250fb8e63549528cb53050322520925fe7fcd065bdef0ec79aa38f1f105348614a57605c94bcd50df80e692d1117c13ba3563afb44e91117c9f6e4e7fa35397dfc58fe7f2daadcdfc756edaf5bda38d6e1eb819a1080cf354f2ab779f63e2bcc763c8ac73c6d811ae2b5252e6fdec79e2e97d8971d1ef39e2a144e84ee8087c673aadf3c46c4e6c1d9832e68bcaff8c1e4df1a5454d3a677040413ba32bed431b2f7d3f356cb060431a7f5b1b6cfbd5709736a408ef6cef1b455ea74191f09feef230a1a0296807e8ab33403a9e3ea1650cd2af"
+            },
+            Test {
+                input: "dab11dc0b047db0420a585f56c42d93175562852428499f66a0db811fcdddab2f7cdffed1543e5fb72110b64686bc7b6887a538ad44c050f1e42631bc4ec8a9f2a047163d822a38989ee4aab01b4c1f161b062d873b1cfa388fd301514f62224157b9bef423c7783b7aac8d30d65cd1bba8d689c2d",
+                output_str: "8e03c6b48b4e91bf5364cf9311172442253b6ed58b95d147a4674bca639d75820ffe93509ab08fbe7eba70544a9331c3ba3347b0b44e0fe36f9b799963212514ab2e673133ea5d9cf3181ffac7f79475971369f7a0188f1a3687792258617c7521cf2ec979241d8e9345b9205243a1cda692418f8855ba61b57c75ce8a7b2d019880d2c56c61dc0e3caca0cd632e8819dcaff9336498e1d573c16269d2d56509beced579c80c3f09e4165081ea7910bb8d13f0373fa802f498af190ebf8d7565a93a771afcc8c417ea460e67f4aea898c73ecce5b17ebcf6eef8a6e31d160038604499b39965212588826d1f896915500497bf4f949e2ccc4c3439315e7aacc2904a77ac0113a2aefe64f6d625a7ef547e99fdcf9374300a1cc15373494bc1210b8dd5b5ce04b190a824566a9ae4a02dfc70ff8df3191528a91e97dad97057aafb0357ae7f509ff7e464675124d0d23399ab6db37b80397bcaae48b8520860b79efd72d955f53611e8d782a28c729f51d3174850e4fd61a4328709de8170d1bb7b5a811bc3e0fd06f20f03ce1567ccdc5891673cd8e659472015ee6a557d89b104e22e70315b40701b49c76ba0196f68a9255eef2623e531d73d151a7f321409bdd8183caaffc18c6dd63c1eba47f07b5b3d404c2203373ef356cd26d89dfd8f5ba2f700646507af3cf63db907f9f70ddcb125259f28275ce8f41b63d14058c3"
+            },
+            Test {
+                input: "42e99a2f80aee0e001279a2434f731e01d34a44b1a8101726921c0590c30f3120eb83059f325e894a5ac959dca71ce2214799916424e859d27d789437b9d27240bf8c35adbafcecc322b48aa205b293962d858652abacbd588bcf6cbc388d0993bd622f96ed54614c25b6a9aa527589eaaffcf17ddf7",
+                output_str: "845e0dd7fcea5e19e5dbc6cd03d58c2bac4b81ce809ba7d0c75cb867da6ecdc9cebca177ab9c3273c8ead7b8c9f571d6d1d14ed0caf6ffaae4f1b7ebe653443e9bf099dd54ce3a021e0944bb1f8b34cb8cf199ed9b23ffc94e2fcb6fba03d50d0c84c2c943f17c1bd9eec662420ee42acd5c5f18223b92ac269b320bc1903550c1d55b7ae5804eaeb6f67c57537161ef8460e45e34fab823ac0eefa232404c7907db88e4b1d74af7da5a2e38f82f96a86a506df1e717e636af1fa85bca3259c78fe7cde8ff56cd2461997ff8d3b31be985b73e4eb0dbf36d39923cba9982870ddeb52acc02a97cae8688e230364d5637170c328175208f8d225e2b19289a29205a9568f426fdbda7bb04224808b2f21e4e80e2f18f4e790654e0d6e486340464b6fa48c95f99a4106e95a6a378458b8636556c700d79fc45697c09a84d2ec41bcfd560f0a147ece640060713a86516ecc642396e16a63203cce11809e7dadb5bde418348e91e30dc65e66242e29b69b9cec5548d4bef3e15a6cd4937c492b2f0ff83dd3acef224ef66aa27726161a418820196738ebd9569b49d51d1583129afaee4f9128c55813151895a046e4d5b4e7d1695b0d47bc657ef7795107148b165d0484f346c9c49a8dee187e3c1f28a6d57fc3b7da49042b37250dd02bc9807fe1af57d5a31664c90d5371542b28965e805224651f96836147e0300c2a938639e"
+            },
+            Test {
+                input: "3c9b46450c0f2cae8e3823f8bdb4277f31b744ce2eb17054bddc6dff36af7f49fb8a2320cc3bdf8e0a2ea29ad3a55de1165d219adeddb5175253e2d1489e9b6fdd02e2c3d3a4b54d60e3a47334c37913c5695378a669e9b72dec32af5434f93f46176ebf044c4784467c700470d0c0b40c8a088c815816",
+                output_str: "ef1a40b1819ac20c49ee1f31e36b853619c8e960da1a5bc86674c5720c0f255e8099cd4572d09fa5b8f035abee5fca1725f988954513e2e7fdca92a55a757145b0e1a223a7cd4e0d18d3ec7c8bb33221b24aedea4a08f01b2130d58e19570272456697df883ab29f4d4f86ddbfd1d97f1018277f84ffb615451190762b9b72556677591e6eba3fe45f8769072e234602e222c77dfd8cc095b73d1b231f3f09b89c2ecdcb741fed58085cd763e2b016623bf2392631984b6e4d2fe558b7f17973a8f58be66d73afae5de5c5b46a6205e15f8a7f5b3ecce65985edbfe4c86d3830e642c99e44ef35aa55b834696dc519635240d6a693ac09cb3d567105420449664eb7b6bc367c482cb2682b1a34a9a051470ee3daf8045b0defae0ef10581830a1c21f75045d1297c9ef4b874e9004d4bf86fd770b820a9aa1fe967388215aaf00ddac57f9b3b9cf0a67fc81e27565f1f3378a620c9a99b50af301359e98d31ead034dcb0334bf45d3cecae0a95e4f0f0d60b0725f97aaf0ec1c4ea1d7d062d5b13a69b68ce5fb382ff7e25a219c7fe8cd1d78b47660319f6ea04418970eb3b5fa6778d84ebd4377c8b3db2632cb616631db82cf68cc4a03a44768b082f8a5fb606fbede8ac366b9d0813bb58017098a9b2d5baf9c5313451f7fc5144f8a89ec34da3cddacb079a963bad7e08a4d68de34612b116a0587731f4df8135599940b3"
+            },
+            Test {
+                input: "d1e654b77cb155f5c77971a64df9e5d34c26a3cad6c7f6b300d39deb1910094691adaa095be4ba5d86690a976428635d5526f3e946f7dc3bd4dbc78999e653441187a81f9adcd5a3c5f254bc8256b0158f54673dcc1232f6e918ebfc6c51ce67eaeb042d9f57eec4bfe910e169af78b3de48d137df4f2840",
+                output_str: "b9a11246d631a7c9f33911215f36281030aa4959e598f2e36602ad66e236f4eadc9e87a662fbb5e30555f7f2048571db711d9b28389525dc1bff502c1766bf7ec7a26688cf30eaa16a23d00bd408e11756bf0e9dc3265abed5b83643260da0f7b58919078edcc9f62b2d14029657426407cfe5b514e17410f3351c401ee163d1897525441d6738eccb5976c16ebf309abe15fc5b15b362338516bb8fc50dc69ebfd5e3cfc7b79571c7dca79d57970ae0904547677b30cdd7d09a0973ae65d6e00f3f9205ba0d806cf3ddb5acbfb5ac1def3aa8766e4921b42df7b9e3ad5299747300c9d26406cf195dca47a673e232454dc80031fdaa0e3da4b66da9df72b040893378aedd6911d35d3e007828eb749bed4e16657e9d33867e0319e6d4bada0f16c466f3b1b8502bdc2584bcbd7128a976c6c8bf2d553d38ab28b982802d1e626c47b5ee08530ff22a9852ac113c560ddef6931f6e6145c3e525f5e6269e7dfcd4c0517c16884c681b1bd78d4a415039439bc5947c65cc35bd52e7e2d0fe0c88b2c92c903a0db75d5bac3d3d6a5a323caee0e55c61e8bbc1113a7d8aed0b031020cd7c50346b2c9eefe61c20c14ab947cdb7b3d153172d5f32bd267b4d77a7606cfb5080058f56e51ce9f73e7d75c94a46a4e917bf575827d37773f2f9eb5a552420aead98df822a7eed212538e2b27df5ee2188561775bd862902f3dd19a9c6"
+            },
+            Test {
+                input: "626f68c18a69a6590159a9c46be03d5965698f2dac3de779b878b3d9c421e0f21b955a16c715c1ec1e22ce3eb645b8b4f263f60660ea3028981eebd6c8c3a367285b691c8ee56944a7cd1217997e1d9c21620b536bdbd5de8925ff71dec6fbc06624ab6b21e329813de90d1e572dfb89a18120c3f606355d25",
+                output_str: "ea756978ce1bc77f9c84a151604f37ced854b00328df4a486e9626c7da6098f1a6380efd8434fa59b037ab18c3488b404c03a4838a9e6c60b37c9348aa2cc3e09f016b1f07fed8d4a0b93bfd9121b4200a706887297a91ae12e1b385830536a88afadda80d4b14fc5cc9c49916cccbb47f970378aeb5ea6f6f583d131e53aa708196f749644dd153a3177f424921254a7fc92ca5ca241d54c6a1e565298d2baffcb173d22160241a535d34358fd0b54640cff9e04890bdf23bda5dc770240febb778d1d0b4b3c98ca7afd2512596ebdf02f8e1ee5c74ba26a35e1482784f6284d0d5fa17cbc695508026cd49f30d82fe5819378de13150805555406b8ebb6bbb8debf55a28b5f1350ef5af18dac71c9a02e76054eaf28e2d1259ee670492e75e1b3be45492d6e3bc5096ba2952e7b1e97dbf5e18618ee7b197e6fc3b0a31b2f071376f6c55cea08bbdfa37cf676a24de82f23878566b48269141c17c7304d6252952158078b481fa4270c2dd631afee7d7518d1f1df43b9841f10871d3b80e4680dbb89ce8c4cdaf4e16a4892a83f927ac7e4ea692c6ef1fe6a6b2fed3c8393a5100ddef4b56fd158e45a95844e2195160c3d3e02fbf51a715c0117627c783d503cb241c636dde3443adfdad82f5d9226d49921ff60788295a47b0d76af43977fcafea4d61dad09e2318ea16e32c44b14aaab6224193c3b9eef105057a2bae72"
+            },
+            Test {
+                input: "651a6fb3c4b80c7c68c6011675e6094eb56abf5fc3057324ebc6477825061f9f27e7a94633abd1fa598a746e4a577caf524c52ec1788471f92b8c37f23795ca19d559d446cab16cbcdce90b79fa1026cee77bf4ab1b503c5b94c2256ad75b3eac6fd5dcb96aca4b03a834bfb4e9af988cecbf2ae597cb9097940",
+                output_str: "609d7e2f634d0457e311972039e1645e66392cdbd1414d5a8c839f8b22618ac73be81a745b9e2b83814a527f78d588119f7464cfb235e56d9e2f794a5bd510008689ece3ee818707be101a3b8a5e1211e3116ac0e9746f79a01ab9dcd01783e961c316ef4ee908cd69c7c2b0e3560fb6dd5649896403d07f021539f8adf22ca4e3535a81ef643ac230a0c94913e9584fd8af77926360d280feca2283f8097dd843d509c5e34a9fa8b02bba9015753d3f728aef7053407a90dc48f15ea272df1f478b967da4c02c8d4f2903f9a98f90ca1589bee5590195e0f6b24913641c2ffb42da043b4548d82f8f0f580356e9946022b06ddb0bde4947d4a25767c65d1ca02148954d1f33f07ed0886552c23286696067facdf37b5d468b1a5f29126a2805bcba687f61d920c53b8346579ee0d312691dfda9e53b3a0ebda1ce213c78de4cdaa3c5d9c6d5a4c66a5b53237a7e5d80e8c1db49656e28b2df50c02e9bc580a62ee5e6f72d9681435baa70c0b51afd2ccc109d0d45634072bd404964fb44d2107a68e1a9cd60e63b847ea9c75ef14d19101e391d8f80d05f6bf0966c949da6d9c8e2c865c0468c825e29bfb9ca2070518ad838a6b1530723f6261277ec7d1291104049503198b6c3b95d1d0efce786d5982f6d0120d9ab2d1c0dd9ea89644103442a76e6804a57b54fca199e6d714576d631422bda28c2a7f8838ceff879e0d3"
+            },
+            Test {
+                input: "8aaf072fce8a2d96bc10b3c91c809ee93072fb205ca7f10abd82ecd82cf040b1bc49ea13d1857815c0e99781de3adbb5443ce1c897e55188ceaf221aa9681638de05ae1b322938f46bce51543b57ecdb4c266272259d1798de13be90e10efec2d07484d9b21a3870e2aa9e06c21aa2d0c9cf420080a80a91dee16f",
+                output_str: "f5d0630d6bd21787a4101e2287550aded2c2baeb0ca91d24cb61eaccf83b0d15700c6a95e643d8ea2383929d23de5a1819eb7571f38ce173f378ab7275776a771380443b0cc1cfe1b9efbaa8579fe6e002fe75b80fdc73ad20c727b003b6281a8befb7f7cb2545f42586ab879c9ff523d6acf70f24994342ebadbda27d3168a755c2dfc3c99360fe377c8a19f1465f6157cff76a1d7c8a6fb991058d582d5f2e19ed583136320c4da569d9eba4692e0bb19e620c600260bfb0c95f7a8fa4560b1b715727cb04a8d37410dabe2adc5cab24465bbfb41aec1e946be1c50eca676f47ea99d217d68f6b8f3536e879fde16a355e71857143f7d07c9a207f4d61b89b82354f0a0273aeca1361c3f949efc2a45bec3933e8a6e7a86e90e0efe5d11f6a20ed9811a1cca507e33cf47fea26d7e67fa88d374245b1a24d8f5c584dae932be1ee25ecc5ee61d31111a3d1eebf220665ec401e28bb85b93d615b64ead0fef0e6af725ca5ea8454b571a784ef95a020251fe236952d130692d81702b16f8dcf03cd82a809877b08774635a4859e1a516e9c4135fb415100359ca6da69426d4139e90f00efcadd155f85a4ab1ce154f8cbc84efdfa7603ff48d5d1ee94a4d27dc9a450e35c60d9cf43594c9182b69fe9df540f498c5c92db68065f2ecdc52ee7d22736561fa617970375f6ea3d01ff39e2e22c979ab58df80ffdb75b4258f49a"
+            },
+            Test {
+                input: "53f918fd00b1701bd504f8cdea803acca21ac18c564ab90c2a17da592c7d69688f6580575395551e8cd33e0fef08ca6ed4588d4d140b3e44c032355df1c531564d7f4835753344345a6781e11cd5e095b73df5f82c8ae3ad00877936896671e947cc52e2b29dcd463d90a0c9929128da222b5a211450bbc0e02448e2",
+                output_str: "f3b73032fbc450b21db7c6c263aba819accb297b724cd95c55280fb7f4e6a5100181fdd6e010964c62fc51c0fb540794cd3bacd695a082b20016e1be1f8fd89e77aada0747afad6acb2f963bb476f1b515cc0604ce5a7b18506bfeb875bf483189d268255146fab7b7820a26dffe97c737a7d5bee677524c4b64539ce760cb4ab6d03fba155d05130a50d5c1ea81873c8a45f1fb83c2ebc11a2a1bddd45aabbcc572d9e93611c4a1429b802eaf44ee19a417243c069c99825959093a9e0e5bff186c757a7270e33d02b81768d94014f17effaa3b2d92fef370e552c8a8ef2b3557c2f930b7c79e9f6c0573bffd8585000954d9264611e3d6bb305b08973d0583c7c2c5b2b0b5aa1b0ed46877fb02646472672121a6042419481d4a0a5ee001e1e067f6a7ee1ea4b880d00f7815fa9658ad9dd643139a37b3febb46585a2a74be0ec2b8bcebfd8f63672f2c1f213511e611c677cd92b2d6c4e43792ce3709ae1caca3103f7d267940a0ca5868afe6296458811ba67205a5bd4b27f96573f8b88f8df2733b83c420cb2015dbecc6e0146657cdae3c7a2d2de5eaf8bc9ebd0a7fab0fa37b24206b6118cc56087b0f573fbee9bd0c4b70512ea4784d85d8a89e75e08f86d204a4a03d4c247cbf9af7c20fd532a65d0c89311246cb572c77a35cbc9c65be40fd7ea2d41a3f5a4aef0be01c4df6aef0190171932b03eb960172a38101"
+            },
+            Test {
+                input: "a64599b8a61b5ccec9e67aed69447459c8da3d1ec6c7c7c82a7428b9b584fa67e90f68e2c00fbbed4613666e5168da4a16f395f7a3c3832b3b134bfc9cbaa95d2a0fe252f44ac6681eb6d40ab91c1d0282fed6701c57463d3c5f2bb8c6a7301fb4576aa3b5f15510db8956ff77478c26a7c09bea7b398cfc83503f538e",
+                output_str: "fbba34f9b8b88c9851e1b6a8613641a26e5e6944788449e7f78c66f32aab088229599e67b048058a2bb6713c84033a2177b563407bf832d136fba8a506b3e0c3ac8632f8c6dd058e1d242a24754d64d8a0e8db424000561ea5298edf2e5620237f4297cd4b2e48c87af4abb28167662b032f617d89c4cbbf064ef09ac2a122785d55c411970a610ade46475cc0e371ace344b3bee172d73e9fa4cffd1806070e7cf48b722dcec0756eb1ea059e8481def23bdf94a0050ce2848af21b49b59320d5f4edfbf2c1a653306be31f3634e5871156c44d15f8c39c7f50fcebb93c61df9258f81941aee98c0aae76d92560fc4987c0ca8cbf07cdd9b96e1f24e83f5977a2c561870d6fd4752796900cc41aa4f2b256988403065a9c506fa78c50e0b5b9592a4116fde380ee9e6c7fc67ffcb5123fce3b27a6d71eb875e88e0a8f20acb50b3f2d46963913fce830fb5e01baf0f2fedfa8e9717576b96f788ff8f8734c33c3cd9595ec2f6270be920aa2a4fd56f83442141c1c1834820c1a41a51da308f5cb8457e6c835c4f075706051a7cdb3901413fb9b42dd9e0a2b8664be7490cb4043acad67cc806886ea5c41bc8d81e00ea1cc7afb5bc34e150ec26e4d6d8d5f0c5a362a28c98ed6b3915a0935d7a237bb24aa18d41db5271be154f4f51dc25af823a978b8d41f46ae142470adc4d008b260928f7382bb08c320f4802705af6eed"
+            },
+            Test {
+                input: "0e3ab0e054739b00cdb6a87bd12cae024b54cb5e550e6c425360c2e87e59401f5ec24ef0314855f0f56c47695d56a7fb1417693af2a1ed5291f2fee95f75eed54a1b1c2e81226fbff6f63ade584911c71967a8eb70933bc3f5d15bc91b5c2644d9516d3c3a8c154ee48e118bd1442c043c7a0dba5ac5b1d5360aae5b9065",
+                output_str: "dd4fc79f3b1d5201767ce9a0f89d3ad0a3949bd75668744b95523562a5107cf45adfb39b5999d79cd3cbdb1f622b2b250c86647a45419a243adf4e7fbcfe227ffa2995ba39fdbc5bae183b786704d8631eff1f88ccb8563f112440dc48d87b97bf8e8cd8b894ceed6b43c857627ad1efa81045ce505fee7f370cfa478bcb4a4174d133d9a7057702e7122229f53ce03d281771cfe58ebd825c4285b4d7aac7cb00a835fa094683f503e92b690a4a35d0e4f5f01dede83fc829e4f3c5f783737a68dfc9eaa3cce682e3d5278675d17a2469fb0a814bf71fc212d7162ed80707aaa514cd5b682b95b948a8a9d79ee3ce1b9ad44d3e6e6eb455cf198927072d8f28950aae0b5fdb628ed5280695e7a83665c94a23ebd163536797ee6733166af631f21f6c1ff398d8d363d6f7ed518feac9eea1f98e9e3976706f2ebb3430af64cb788a2461b736d91876fd481f5f0135b458b57cc00959bcc1d145b2b776d7b5b1bd0ed154dfb602f78c8d567f30acf34341c9356be887dc85e9415602e19db053e965601ce5db866c1a9ede8c12a81850f1a46cdc154112560a1e38c40a014e1109195ff23054954f463aa825ffe1a377d3cb1db279d2e5bc7fea045cf3b2681170cf42d4c0518bc9e51c3f854052263d31c50867426552e6caefe37267a7725a4460fe2a7f2d951ddcf55a66ab59de1a66a7fd15169bfee7339428308c0477b0"
+            },
+            Test {
+                input: "a62fc595b4096e6336e53fcdfc8d1cc175d71dac9d750a6133d23199eaac288207944cea6b16d27631915b4619f743da2e30a0c00bbdb1bbb35ab852ef3b9aec6b0a8dcc6e9e1abaa3ad62ac0a6c5de765de2c3711b769e3fde44a74016fff82ac46fa8f1797d3b2a726b696e3dea5530439acee3a45c2a51bc32dd055650b",
+                output_str: "fe149a9560e60dd76dac07cd65722403ac64637033653bd60053f3958d0df1ef1daeb343ff6488587f49945a19479820a98df8484cec8e3608a8c7d15594f61faf8547fb0ba643aba3fe942e191d61e2a84a548a4b76e0144b71e061d01e5b46629dc585eda21696b6f716ecd7d98e54fe49692b5ff7e74ed15183c4a4728a6a4fdc85fa56d49615e0141c65614de51776c73a46d19e2eda71226b5716ffd83c06813b631cdef6bac2b5f480cb59fb54dbd0e0fff0539ff70fc1f5872d8b78b3e03335675925e2a6fb7fdc9378d3202f396f05dfcd0a2193ffa3da954eb44486c054d7d8bc22194612047f2f8c5fd5423504d6a06f0fcd4e611880c74bc84d7d5c3b66e017dcc79ef5ee41f9322f7dd863aa5428439d8e5ed3222f2346e305759b46826e039ffa8a2b0c7147c2aa440602626fb79b0699ed15ed9ca54125603e9a9525db238a518708e78709d5cee0f3a196b4cab52198ed5a58c98775eecbde3ec721214db7a981c81d419f013f1db230746ba5ebf30ce37882376df8785adca0e04e9e18d0ec75778369f7516f5215ae92d67c4c4751090246a8f3a719bf83e3b310d61faddb911b2080266d2b43f31fc9e3a5d9747eebfc8816f63e398c9f506c00821d0f1097349fecc2dc05fc420fe673f5398ffe828cb99b3eeebe817eab6208803339d8d905c845fc934487f51ffcdb4e83d8e337dacbcdc57f867ebd"
+            },
+            Test {
+                input: "2b6db7ced8665ebe9deb080295218426bdaa7c6da9add2088932cdffbaa1c14129bccdd70f369efb149285858d2b1d155d14de2fdb680a8b027284055182a0cae275234cc9c92863c1b4ab66f304cf0621cd54565f5bff461d3b461bd40df28198e3732501b4860eadd503d26d6e69338f4e0456e9e9baf3d827ae685fb1d817",
+                output_str: "e38785ed93686fa741fbb6e5be64933963c3c872f7a4e8c8d540ec3f82284605625d32a24bce8b40264eb51b164dd86f318acfd9867f3bf23998275042aaf23bda01f602622448957b81e51475f15cdb31a9297ee390f681e460ec01a024f183110c728bb09a12dde89e6f5de2b4f8c17d981e3e9c531e6d4c19448a4a6be28853afa2fba216f7c8e2ce4e4de31f6b0e129cb5da118b4a59569a439c1095eb50c51cd83105b1a12b3f7086947ea7381969a78308f8fddac8b2d87f4540a8e7cac8932ca76201f86561add09d833361851ceb9759ad1eeed4e00ed19c642bc6d0aed034276b66d818e8791a7c1f42f8604e8b026d4635e3bdb27ca0fb28e7517bf662bb99ae3a3c698ad0aa2f02408e76a5f93abfc933b1691a89ee3ebca2885ea633d0fea4dbcd03b05b68e0f4d267144fdc0898de46011832adc872f4a7f0d8933cdd482ca54ffa81774ba083d3d9fe07de94f8e03ff66d9f1bfe7504e8a497591ba8f52758f92e0a4ca6a93979cd1f55ee9dba17bac6c69e83dded4ce2dbffb0b48c0c6aed657405de18e7891b3c854127459e89fe5442ca6d5c223b046147bfdee435cf4efaefd705373dc87e20b7d31c7d37907d30b8b32054bb9eca80d0afabb5ec5053d94d517f158ea958c7458cf71fca85b607a352a9a3b8f4f161e3b8853f6bb61864bad12dd9b57ecda507a3caa63a1dec726b518cb4fddeed6a34"
+            },
+            Test {
+                input: "10db509b2cdcaba6c062ae33be48116a29eb18e390e1bbada5ca0a2718afbcd23431440106594893043cc7f2625281bf7de2655880966a23705f0c5155c2f5cca9f2c2142e96d0a2e763b70686cd421b5db812daced0c6d65035fde558e94f26b3e6dde5bd13980cc80292b723013bd033284584bff27657871b0cf07a849f4ae2",
+                output_str: "66fb94b62645f96fd55ea261e08a93aabe783f160aaffe07253a1c3d45dc65f6afde9df121a894a1a13ced4e5d492675bda35926a1b147d5317d3cc09d4d34ebc1bb223663b349d3f66f05dde7a66616e7f89b0bc6859a3eb8402b881890b21979be6f60cfdb9f6c2fde570d79ca9d24099820e433dd995e4c2271eb269937cbb96839a03ba7af726adf23b7fa2f86348c0489e09a559d0febffcbf33d77ced28a439f09e2efaa7d6334a783075b588134c69433aef0f8665c05e97ec2afe49336ee2cec0724842a64123c7f43689d1ee88873f89aaae9730b1a29768be0e49a87b52c1f5ad08d700ef9b57a20f5dcc7c238a5e56cea3a0ee1f9bde550f2792741f607e81744855a5f109fe91887bc580199966dfe28a30fd1fbea9ac4259e7bdf7135e4a9d83234f9d7abe3bfb1f264e23a67f456096e27f540fbbd5df0e8ddb5a6a455ece063d4d528c2582be8f111e1f7c7f204b82d40f60c2af6099dbdfd64df85899ba2a02a26870e3feca6c07e99ad43f93d21dc275e1afd1e136d2f49142b4d208ec865f91ddba5822148c6884b7cb283de5aacc4e8bb66be3b08804246c808569b2df0aeb08bd4c255ae1829aa62ae9495a89d238dd93e2bdf5d14159e48510fc82b572402302c63956cd215341a1d367135623c644094cd845b08abc7a8cbd4f3b66f48375df7155bc5a781e69272ec1b3ae4e3cfa1d8d39bf0b4b1"
+            },
+            Test {
+                input: "9334de60c997bda6086101a6314f64e4458f5ff9450c509df006e8c547983c651ca97879175aaba0c539e82d05c1e02c480975cbb30118121061b1ebac4f8d9a3781e2db6b18042e01ecf9017a64a0e57447ec7fcbe6a7f82585f7403ee2223d52d37b4bf426428613d6b4257980972a0acab508a7620c1cb28eb4e9d30fc41361ec",
+                output_str: "295e0fbf3c5b510d6b244381bedf20f8bc3d915cfa4bf9fc42dbf6932f44dca91744d812cb9f639a9c3d376c49ce3c7da90d267d794805a61d20d00c79f42c37be018c67857b6a02e46b6d6a147506210651e31b280043610584a1440a07bdc8540ac46e637f7d947792a65adce3b790636fe1794e90598ca6340982ec58f3b24ae1c703fbb91412f1ae7c23a3caf78c4bbbf32c90c365726ed4832016c5a19e94685a7ccee376184a10beed6da7e26d1a4260effb7e9f7a0a0c71d7f164cc967c7526a0f1edf1ff54aeb114109f7b34361db5aaef9ead31a4d4896cb86556d2619de0ace07c133b14006119bd4bc8cf4f8ec09cd2ed91b4e524012261ec9537b3bc4c67100102293836e22ab5524c979f1c1af51fbaa2abf3f0efe6818bdaf37cec4d6cddc98a994bff1ac458637d528ba5f701de0bf4e4e9e691149a6cd4677bbd9821511ddfa6561c419b473d2ba019cf1b83b7aaa3bbee141e2fa38f032635aa559ca629068dd4639ccf579118496a903ba7dde88ff54806ae89ba3974b9dc0ac520241bee278e3eba1b3df1c026a8e5f0d5f28c35c5b04145b570d2f06d25f45bebf4de2785d75b0bc9f1e6f9aebe2ae510d422180cef13f6b0c8a0caf76609a158fb6f3b17e7282e168dcba19e76db7841e384b54f3ab29d78c86861560cdd934cdb63742933253d7bb82b453cf829f33b99b8e56b906c86131bd64f64"
+            },
+            Test {
+                input: "e88ab086891693aa535ceb20e64c7ab97c7dd3548f3786339897a5f0c39031549ca870166e477743ccfbe016b4428d89738e426f5ffe81626137f17aecff61b72dbee2dc20961880cfe281dfab5ee38b1921881450e16032de5e4d55ad8d4fca609721b0692bac79be5a06e177fe8c80c0c83519fb3347de9f43d5561cb8107b9b5edc",
+                output_str: "9e8438cffc23a52d75838690e7074d2c713b1188375d1a77f8fc8c24a4b89ca5979f58692d90db14dfbfcaa5ef0ac0c2d16f3e84e6f771adc26fa9081f3b10e02a3ee1a3de40db5de17f7628ba3e20e5563bad66bc32bbfb1ceba7598aa4480c86a0c4ed103608cceb103aa13182f48d9fb363913000ba6559c855652b4ec29d06bc99148569b66c77f58a757b75c3bd5ef2ff832fae020ec1c9e19c1117a107f0529ea66f0607a499db0c32966a95d882699b96c4949912380150f951991ae7768e5a26267a8a43ca76ae9c5edf31d7c52f2b09c9eb15e1cf47f85b20bd55ca47fec048b8df899a08dbe2e9c2f72bfdf3bb803af10b5a1bbcd7b4e1915e099c22307154012c67a39fa77720d7006b86a1ed4f095b6644af972ced451453b3de57b1fad8b4280ac62e1ed09e219873b92bfb50646343c46cd3c42e84e9c7f05f1aa5afd583f685a20f996b7c0683002691cd28d454f71334c2387dfc43d32e633900699c8fc5e3a3f6494ca0bba96ef10b7f367dd31623ddc14e9907f9ffc2c65da666d06987db1df8adce1c74bda7bc6c6d5263e3cd777a78b9020db37d331a16c38d7419ec5036fd95b896373461e6b8384b2acf96e46c7c9ab6d43c6eeebf62b7be5f95f8ab6b2aa5e05d66bc4df8a2fa1ad9c3cd9362cd183c10c8cce216fe48aab2b1c4f6ffa39ca9f8d7b14ac5bbd8c71f55776f6c0ea8583accd1956a"
+            },
+            Test {
+                input: "fd19e01a83eb6ec810b94582cb8fbfa2fcb992b53684fb748d2264f020d3b960cb1d6b8c348c2b54a9fcea72330c2aaa9a24ecdb00c436abc702361a82bb8828b85369b8c72ece0082fe06557163899c2a0efa466c33c04343a839417057399a63a3929be1ee4805d6ce3e5d0d0967fe9004696a5663f4cac9179006a2ceb75542d75d68",
+                output_str: "07024716b8e95d104783a37f82e66d4f5b0bae8897f1ef6c45dabf3a59253261300371a4fd20601503f6d187ced1067aecb11b4a4b5a31fdbdf4a2b1ba9c0eeb0c2be7730178fe435905c1b80afd9cd27bcc631c57a10f3bf3f285bb80d9c4f1c70ed30996941d1ed225386b7f4777c18a01efb5f1086be223efdd082e01755ed517ad6a3e423e924147761c95b74f6bd338f1dc0e53715aa31bac84f7e5beddcaf56574626b23dc247d0aee8ed77760f53e7ffe467564aa3159aa300ad159159259dc3252d95942215c81ed5fafe0cb065758f72366e50df7fe6f2b41e36371408503c5e23a4ca0c93460c0ed713872f35cc71d1b71a34a80210069b12cca79cbbb04836e6d9a15e78a638b0879f74034339bb4fb39eed0c8d6684a67dd89b201b46010fa73ce5fbaee87fd89d4b5c40f04d9cec8510bdc3d07539c82031fe9734826cf36bb41b30426d32a10225209c24b631a071feb2a9b834810e81b6f87a6128f67815e4af6a6582ea36d9be5dcbb1d7fd0bda2d583d1f6bc2aed7a534c33a8d183d5edf42f3080bd07ce9d78647df008d417d0ded5021d7b6996d6b541de75dd175e820728037b531521851c9743ed03f8daf292846b2ec019238655256ee960e0981db7b65a3692b50f62033fd79a29f4a36c27bbe7a3b7bd1e813f3a2eda1cebb29979d91720ccd125d0c43d708892bc38d0d297047637447a19cb09"
+            },
+            Test {
+                input: "59ae20b6f7e0b3c7a989afb28324a40fca25d8651cf1f46ae383ef6d8441587aa1c04c3e3bf88e8131ce6145cfb8973d961e8432b202fa5af3e09d625faad825bc19da9b5c6c20d02abda2fcc58b5bd3fe507bf201263f30543819510c12bc23e2ddb4f711d087a86edb1b355313363a2de996b891025e147036087401ccf3ca7815bf3c49",
+                output_str: "585f27af67fee2446767b05ce40627bb06d403430d94a62719dae2864cd44e7a8eea340b98dad0520d8c16c1bb1ab562c0fdcfe6f1de4f8a0601eb9a73ffdbab82444e77487213d17ba31e2bc39fec719979080a501c8e15932ad588000959a18447b98735c73a2a8f4a949a8ff187520e6a9901647f47db442bfb2772e8e8e22fd759f88722a98d24d01308b15a0bc715abe9568a34201b8675204bf68afeae8cb063d6cc9ea68af9e4cd692f9718fb5eab270a2b74ab623b521b4b085700cace113168f56a994a639517f36e3165029bf100a6f19162a8696b858a0b0716751430db7bf07480427c2cda01070f5e78e3ded7471874ddb05d2944bfb04487629a98e06cc4c984ae8c5f7695248d01cee11d75a9c7f545cf86ba745b8ad5564f33b0a8b72e78954a7fb253c07ec8fb3d3bde29ddd91dbbd94d332fe9b7438937018e8243c2d2c30657959ea4d23a319854fb2cb994ced4286836e83324fea54c58db55a969165a1755d965c416e1d67468abc701925f4a80bbd9aa9da82d148a26158712c2b9830804a4cd1ca14a2b246dfe8e8a12eac9c107e8cbbf34ef9517674350973e75799a251e72a352d2700291cc3f1aad40adc9050bef9881170eacd3207ac0c573e238b65500b997dceb347b94fcd5069cf43bf15aeef15e4c135dd21b4046b201f411513aea9629b9887d21cdc43768fc1c1b12ea4ca4595ad463"
+            },
+            Test {
+                input: "77ee804b9f3295ab2362798b72b0a1b2d3291dceb8139896355830f34b3b328561531f8079b79a6e9980705150866402fdc176c05897e359a6cb1a7ab067383eb497182a7e5aef7038e4c96d133b2782917417e391535b5e1b51f47d8ed7e4d4025fe98dc87b9c1622614bff3d1029e68e372de719803857ca52067cddaad958951cb2068cc6",
+                output_str: "e57dd7df74504f52d00b8079631f542a532610d77ddb4bff8915bdfbc9b8f25352aa3d9a2d00ca2e14c77ff661b3aa44e30bcd3d4b110a8ceb65e150dfd9109ee948fff11cd01f6a98c0100d2323f52e323e32e9fe7bba6d4411eee3ccf70122da5bfec8b92e72119d4b1cb1a1626dc0cb79fb4e4c938a4a7caa7962b04a1129b4a0a9c457ff38e8d3379044e4b65b82336709b95401cd0ca64c10f5d22a226678a1ea4e2c54509085abdc41aeead761c7946f33140ab775d61f7b001f141d00f5209081b11fc2ace5d9143fbcb710176bcc8aee25d0182461ac1a446f3a94788b3513b88dddf5db0beefcb331cd2553416a3606f44b5cf36318c72501fa2007f76ba506ec510508b27d692cfddebf075b39e531ba243f3e271b5f70ea6b58afeaa0b8264202ba2c430c33d1409693ac52519f44b001abfa9c5595c0726dd1ed36c8b7cd2f29faa912e2613d1c51e2d0c6f8b27fbcdd6137307abdfc54c0e6c6fce06303862a8efecee12eb87cbf8423bfef01c6fb87225dc467ca7a0b0243ca9d531811a5e5090351313fa6f73d413755551f6e7187057fdf4cb58a1b3b3a63f28a17339a835a73bf21ec013ef4b2bf89cb3bf1369a87239a546a6816d8b06ec5b1d5a179e67a86665eefcf439d667f5f9890da8b9e1e7e1ad08f757cb0e3ec6d8cb8fd4a140846e3768076d342fdf0be4cb135d68faf5c93fafba4813786d1"
+            },
+            Test {
+                input: "b771d5cef5d1a41a93d15643d7181d2a2ef0a8e84d91812f20ed21f147bef732bf3a60ef4067c3734b85bc8cd471780f10dc9e8291b58339a677b960218f71e793f2797aea349406512829065d37bb55ea796fa4f56fd8896b49b2cd19b43215ad967c712b24e5032d065232e02c127409d2ed4146b9d75d763d52db98d949d3b0fed6a8052fbb",
+                output_str: "6c60955dcb8a663b6dc7f5ef7e069ca8fe3da99a66df6596925d557fed91f47091407d6fde32023b57e2ee4c6ac97b077624fac25f6e13f4191696b40a4df75f61cd5521d982c6d09d8342c17a366ec6346e3528b26cff915be9442b9ebcc30ff2f6add0e82ba904c73700cc99acff480caf0487cee54cba3753b6a5dd6f0dfe6571f0115e8737b071031023b6bb0d79864c3f33162e78269cee23fce47b91b4fdf91f98464a1d21e799d17f76c1bb807dee667b0b273054be298299bd12b7a80fb354ce3e6d1acf98443879a554eca6b96df061d04a117c98aeec1cde1afa9cef62dd686da91bb2b1f12379bbdc9fa32a6b6998b77e8eb0b50507862afa7799d018e272091f51cadd81adb587ef67ba67618c45d1f3d559dbd299abc26ec712da8fa34ba33bff400d1f0f8b6345cf57269b858578c0072a91a63ef85f9d378900cd1a55d2bd4630db829eb484d89ce7a414aca173c52534ad5f9355e80e395e79156d751a930f7f8b5d9f4d5a2c9a753723083c5e8ec6cb24d8ef93c8fef2d1be4eca222c6e6c2acfd684893cea65cbf5b096b3d866007136126a33ef496bf2310f293bfa4c93ab826821e2b93259c464e0aeb06d6df8ffa30b1c1e7e384c7e427a2ba3d99ff8a666380c5c1b678f742c57b0c3b08849fd65300df13499dd894efc33116e7d0774064331fdd407487417d13bba4285299af650d3065d951131"
+            },
+            Test {
+                input: "b32d95b0b9aad2a8816de6d06d1f86008505bd8c14124f6e9a163b5a2ade55f835d0ec3880ef50700d3b25e42cc0af050ccd1be5e555b23087e04d7bf9813622780c7313a1954f8740b6ee2d3f71f768dd417f520482bd3a08d4f222b4ee9dbd015447b33507dd50f3ab4247c5de9a8abd62a8decea01e3b87c8b927f5b08beb37674c6f8e380c04",
+                output_str: "cc2eaa04eef8479cdae8566eb8ffa1100a407995bf999ae97ede526681dc3490616f28442d20da92124ce081588b81491aedf65caaf0d27e82a4b0e1d1cab23833328f1b8da430c8a08766a86370fa848a79b5998db3cffd057b96e1e2ee0ef229eca133c15548f9839902043730e44bc52c39fadc1ddeead95f9939f220ca300661540df7edd9af378a5d4a19b2b93e6c78f49c353343a0b5f119132b5312d004831d01769a316d2f51bf64ccb20a21c2cf7ac8fb6f6e90706126bdae0611dd13962e8b53d6eae26c7b0d2551daf6248e9d65817382b04d23392d108e4d3443de5adc7273c721a8f8320ecfe8177ac067ca8a50169a6e73000ebcdc1e4ee6339fc867c3d7aeab84146398d7bade121d1989fa457335564e975770a3a00259ca08706108261aa2d34de00f8cac7d45d35e5aa63ea69e1d1a2f7dab3900d51e0bc65348a25554007039a52c3c309980d17cad20f1156310a39cd393760cfe58f6f8ade42131288280a35e1db8708183b91cfaf5827e96b0f774c45093b417aff9dd6417e59964a01bd2a612ffcfba18a0f193db297b9a6cc1d270d97aae8f8a3a6b26695ab66431c202e139d63dd3a24778676cefe3e21b02ec4e8f5cfd66587a12b44078fcd39eee44bbef4a949a63c0dfd58cf2fb2cd5f002e2b0219266cfc031817486de70b4285a8a70f3d38a61d3155d99aaf4c25390d73645ab3e8d80f0"
+            },
+            Test {
+                input: "04410e31082a47584b406f051398a6abe74e4da59bb6f85e6b49e8a1f7f2ca00dfba5462c2cd2bfde8b64fb21d70c083f11318b56a52d03b81cac5eec29eb31bd0078b6156786da3d6d8c33098c5c47bb67ac64db14165af65b44544d806dde5f487d5373c7f9792c299e9686b7e5821e7c8e2458315b996b5677d926dac57b3f22da873c601016a0d",
+                output_str: "1279a95cb87b1cdf2f8a8a47ce55f0da3766e35ec58cf921e07b43b176cfd6ce8508a208c9d6f5412515e0235c95397a47d2a4b13a357db4882f69b9c910c985a5f82187bfcc46bd48cddda7f65c3e95481a37202eff9c116bb3f784bd46574fbd49e19b45e5e2d18f57be7dac826a447eca6e2a6bb44b0061930df56864c378e020a183deee8445648ec2f95ee5f09cfb196e3d809053566446fca6bc36896215bce115b0aee55737a4421316d2058f24c36d46279b458e901d3a8062300024068d99d8c1b8bfb6f3e5883bfef3c1aed55989151c2cad1eb940cc82398dea1e5a92351f0d5aa7d47e16a949f396194eae2ebea1fb731bec12d2734c2f1e7464ca2fe27f036bfb28a32a9657c75eaee79f86f2ce5eff1aadb68da0b32a4bf88a37f1d66d13df4ece65059bd4abf91a3ebf982a1f5e9a6da639623d0c8e5fc5c0c8071965221c4b79cde7d44fc258f20cabe3c38862851952741fc9e9e87c06ab0cf8b8fed6c18666c5c70ea25973fed36d90429c54b157174a2583e142e26f2ed492a9fa74f1985fe52a421c2f97f94b73ec7d881f0d0b0f930461fb896b1806c704307cef682834cb583b6e996bd31a6f1d8586d416fd8c91eba59935feb12a1e77d0f3e05f80842b14f34f27add947ee3ca2e54bbe018fb8ca27ffd1c24227572cc277f723535cba0133e359217d5522676485181abbefdbc31c8164f17847"
+            },
+            Test {
+                input: "8b81e9badde026f14d95c019977024c9e13db7a5cd21f9e9fc491d716164bbacdc7060d882615d411438aea056c340cdf977788f6e17d118de55026855f93270472d1fd18b9e7e812bae107e0dfde7063301b71f6cfe4e225cab3b232905a56e994f08ee2891ba922d49c3dafeb75f7c69750cb67d822c96176c46bd8a29f1701373fb09a1a6e3c7158f",
+                output_str: "7a2dfe06b3afa54b49414379bb9c7a80efbc8d0630b8ca170f6b22cf65bff168f2ba6e32806e6e7d9d366d53a319bc2c8b8aac7cf8158128617229d76ae594ad71c0e0541b86078a62d71e2992e555ee6fbea906ccfe58fdc7101964ee8c3c05d0c2c7d8a01b7e1629bcf62233c0487e36e1c25474e129b72f1f9bafd6e0f7c9fde8dd44ddc1dd9668840294c5b39c408aa1bd1395d1f4a2368d9d1e5168093a63732545fe594b32ee91f89b297e3a33f53be9a1a00642c17da7061c10d1525f34180d04c78babf6b1c866a8ac1d19fc17c24f13ca4032d650dda748e2a09d3d97a2125d52e670c1da4afe56e60dd789608f50e914317ebdaf125bcca849ce37f38eefe8998bb2b1b10cc1b28aead1fc48fbf1c95b2a0f0637609cd569050bb5f3711024cde92bbeff1c73c9b6c8dba71b2aa238aa26b4007978efb346d3fe0031c391a70f362c4c5fe1da2d3c73e4bc52a400e5998660d8c127c46cc7fd589db2c952d2f077e4001b2b6b46ee5e56a44578b4b8dc1afa33c3994ce7ce49b4d8181195076b938bf605f61a74f9c505c64c2a75601e7ec3a94b22157308bbd481553abfd8ed5575b828cf247f6d321ff25fbaa245f9b30b39171e1cff354b9f20d55196ef66d32c4693fdf249f528c86eb82779b5fea03f8a95f31dc0579b1cbf178b23b276e5618941760b117af65b83374c919d6d423b575c5c459b5aad6a2d"
+            },
+            Test {
+                input: "fa6eed24da6666a22208146b19a532c2ec9ba94f09f1def1e7fc13c399a48e41acc2a589d099276296348f396253b57cb0e40291bd282773656b6e0d8bea1cda084a3738816a840485fcf3fb307f777fa5feac48695c2af4769720258c77943fb4556c362d9cba8bf103aeb9034baa8ea8bfb9c4f8e6742ce0d52c49ea8e974f339612e830e9e7a9c29065",
+                output_str: "fba46834a6995933aaddf85b59f60eb3b77b5ad38bc21a862079d8d2227cb9b3ce3ece89d90c70b990f7507d5c3a565974446b54d43288adcce2bfba8914eb498dc6001ba169417af6da3acf685dcbe3cfa0c59963f0f0ab94d39f05a69d5dfd320ef409de76ff85e01636f57db9b2df436d94ec2845f0c0d1959db6308941e40c946f4c3b3277a065847c9e3ccdcf113dec5dcbef5aaa1c5b91c19e05eeb66f6e698178b7b02fe00b89dcc98526fa0e7b2c6247e1c175a21ea34f5260b0c0a625d7aee1680b20b4667b44f72f1353bc71df6cca4346eb54306de3c380438a9b8e6cc47e6d18d84fbecbf9a6132f63c191635999105967c2e171b74615f456d2e111e7fee5df00217b49bb49270befe5bdfce1486c13c6a94e31a20c1d377c410324c08a17c2d04710ca267e85a2cc1e17ada367c0f65ac3a70aa5fe14378371132026169657d1bc1b84c1908ab46689494c3e8a34835f4dc43d19e9328ed0a16341e5e9abb80bddef1bf5feb5ddea560253532a6607e2e128480dee2083af54c67e971cc6b56383a564b0bbd2d802c6faa7bc62629595b17d04c3ae20f73b35a9ae4d356d401345e0a0d5174bc457256dbbd844f9a4bfce0dd48f35c5f8a915e61a23899c40fa63a51f0d1160e16260bf4da1902af01c67e8997b2aafe1989d013846cf985164c03418930e61fd06f9d30f06897460dfa1987d4b5d73b68caf"
+            },
+            Test {
+                input: "9bb4af1b4f09c071ce3cafa92e4eb73ce8a6f5d82a85733440368dee4eb1cbc7b55ac150773b6fe47dbe036c45582ed67e23f4c74585dab509df1b83610564545642b2b1ec463e18048fc23477c6b2aa035594ecd33791af6af4cbc2a1166aba8d628c57e707f0b0e8707caf91cd44bdb915e0296e0190d56d33d8dde10b5b60377838973c1d943c22ed335e",
+                output_str: "4b60950081987c82c2f1a1bb9ebaa9a72e125557e296bce9895561c6a959371eb1ac9a13914f4419b4a0a1048b3d422b53261b0ac26eb9852e9933251e154996dec6219a7063d87228a8d72f13fe94a0e75485c8f23db2341ee7439faf87a1b359ceafe4290319f4705b49cba0adc24db4fe8800ae05664c544d53ee119cf4f1572daa355e48db605695bdae5bf22cffb60c019934f2aa952918b388edd9c53dc8fac2186ca0f77ac6543ac379b1acee9913cd75ca8e0f9d89616383c9541603430aa548e9a9dd8f90f64263fe42a9b8f66991cb2b8b45aaf683f51d194a01098a10d4ba1107c56173825afd79ee0a334ce739915d4f046c814412df526adff4f23811bf1c6a254372e8e46f0008f6332637980417043bab8fc21e3715b713ab4bd1ddb3d50fb9d5d6aebf94ffda51d3bd4e25c82b295badc7f8f11ca787dca045de2b52a79226abb945f69732a1d0da3a3228d44d8f43828d8958e621851f4824590c0719982cdbb3602465c28a97cd4cfa33d6eba65a3f6428acd37d66967b8c996969d866a02ff6efc1b6240ab557321260eb4c9d233ff4e1c293ecca825dac943dd1b9a624ac37acd1a818d2f74ab99b2883f0837f77d4d00a52de0924ef55c7536916677d2ab4faa8f19e8dce97c05690570ff0117c32a3f500c2fe817ad651df2e3c28f5e867083f607e8d0509745588add19f1bb7482087a508217daa"
+            },
+            Test {
+                input: "2167f02118cc62043e9091a647cadbed95611a521fe0d64e8518f16c808ab297725598ae296880a773607a798f7c3cfce80d251ebec6885015f9abf7eaabae46798f82cb5926de5c23f44a3f9f9534b3c6f405b5364c2f8a8bdc5ca49c749bed8ce4ba48897062ae8424ca6dde5f55c0e42a95d1e292ca54fb46a84fbc9cd87f2d0c9e7448de3043ae22fdd229",
+                output_str: "5cbbc93fed206474a11100e1973984d5bc5d06ad92996fc8928c1e6bfdcfad5e32665f4743eae8fd28289dd226a0136abbd5edba5016e975381d4c3cc95065fa4cdac2336b39342be8070ab2b59dbabdc77b8742e4b3c86f1ee9ed0c2b5030fe1adbe28f827111fb137c180b9994fe150b1f5144081ad59131a6017ceb8fb0715dd2de6b3bbecd2fda4c3e9e8a652b5dab4d0b39caf68413838cb1960241af59a46c8b5fca40552693ceda564862df42c5827eb371311fef9231fe1b23ed07f72db6410172597eafb5d077aed168197f20c3b01cc3c52a94546b722b4ab56211b48192f908e7e7a7b7020a8f6370a0b73e046e3211df3352deb1d59e4940e45129a6667f160d2ed6eb703ef962683540e3a9c7c94a61875cac09c4e22ecced9e2ca6dc519698042f67aa518eaf3d338c5accd5c2de5c3df6b4a2273a0fb8880cf3f81d046ad8b24e73a8f3bd7ca65cd21ac2d950a7e36d0a25362788f1aa26b71ca434ad14ef3b002baf6327d4a5293d91cb838e4212949675df185b70d8b42c0c01f289478f0a9ff736e6838eec5e54413ca6f7f22f51aada7f3e9c69b9009599bc437c0d806baede6dc1b2fb9bbba43fc3bfb5cfb408a9d8ec1c1dd1528cc2aaf144fbf9079f86577a4a042a085975bb1cb5ddbcd728df6ba69cb23a8bda0368924466a89da791d4328dc55800fe8639987efc172bb29836a901b3f4f3fe9f"
+            },
+            Test {
+                input: "94b7fa0bc1c44e949b1d7617d31b4720cbe7ca57c6fa4f4094d4761567e389ecc64f6968e4064df70df836a47d0c713336b5028b35930d29eb7a7f9a5af9ad5cf441745baec9bb014ceeff5a41ba5c1ce085feb980bab9cf79f2158e03ef7e63e29c38d7816a84d4f71e0f548b7fc316085ae38a060ff9b8dec36f91ad9ebc0a5b6c338cbb8f6659d342a24368cf",
+                output_str: "ca9cf74aded61a4bc20ba078e8053702bc1a444cef69ab058b9c0f586286c138cf02aa36cb69e0cbcc52f455623d27b9597c9368ea5daec4278e75ad5e3fbcd480ddf8ef39b3d10808d202470d18118a215838a0f6c547d324faab761f7c8cef462be150dd49a26df4e453f997c31fcd27280e846b15f640ff8c39be270df9e44ce57ca82f6f6762777089276a3e67d8eab0e4a0c2e1946fb08b3fdd3fae438cc2e9ec8bc1754275fcf4060e31428b9f08e953f9fb4f80560f2040e4b6cc7bfd6c278ff01aba41f43549dc0aa0407e5c8346543b1f1c24d1e05475327a48821c1c1058850c180776ead66996dd5a02865702e0e4705e8e2e7d4d25f058528ac980eb831d6b70e7cc06eda314d80e1433b2a63eec405bee2acb18cac238abdf254ddbbe72640c8c609f70d04c77d2be9190f78c8e448035a9206841c55cf9152ae5f7cacd798ac696299551a5d45ed113c94cd862197ee118cad47b8c08bf4fa1c6270a61de6d538d608e126c0ffbebc7f44d418bb87e557e550cdda20c2c47f2cf635411189d30deddbb9075fa6f0521d2c4ff0e4d641006cf5eea1231a87d020664366eba5c5610b63ee5b5a50c2c8ca6d7eb8cdcbddc34aed08ed7e0ee437e235449d4c1cf095514e581e3c8a15eafdaef19fdeb31de6619bee6b17b31a96140cdebf7534e0c277ee33c54319b140af0135d6f91f7d2166026c67c71a21287"
+            },
+            Test {
+                input: "ea40e83cb18b3a242c1ecc6ccd0b7853a439dab2c569cfc6dc38a19f5c90acbf76aef9ea3742ff3b54ef7d36eb7ce4ff1c9ab3bc119cff6be93c03e208783335c0ab8137be5b10cdc66ff3f89a1bddc6a1eed74f504cbe7290690bb295a872b9e3fe2cee9e6c67c41db8efd7d863cf10f840fe618e7936da3dca5ca6df933f24f6954ba0801a1294cd8d7e66dfafec",
+                output_str: "9fb76f906cef4a8c7a9cdde3254e6d4581dcf745b26995fcbc123e716f079e0a0b9f7c8ccd9dc5af8894b2d9783395f7bc05d95e20419c15d74eeafb23b6f1ba427b4b20bae38c2f6812b74a7a671384235df3618a7531123412113d57b9c2924ee4afdb9cc055070485a2960e8e5cf1971171f604781865624b075c3c01fa27f9b602c29e257821ed92b35f7941637c2bc6f0048a579e384503182ca8498ae7493d398476727a2ad321785d2273f9f548f6aca80fa7f1acc1144eae7c0ae58c3c4bca20eedc93c3742954f2e2963282084853af5c8f30a1a4333374b4a66188de73f773ff6a576a0a0df3c690cc59521378cadb123bd673a04fafb26db9d653d60a87f2834683d97f5d6e23ff2ace2ad0a5fcac71cb0032039ee01a2c3e37b3e1c14ace44a5a6e43b1e1a0fbc8afb0c811c911f2853c85f10d06253d29362d08523834273961e37c4bb0ead4f79e33d77ebd0d843709b121f8b509c24396549d2187df52c996eea9805c4a3c4f7729003d7bd7ffafd6384779d6b6163ad7c632a408922507188ea22d685e05c8851ea9c6e625d9461ef06af864e93f9b4544f00244264dc57f4a91920fec0120357b54304ecd0a45dd8a6879ee01f66f222c6cbebe8617fc06b28805f480cbfe90d42a38d1981a4176985775cc92e3aa632cf4d5a49b201eae275628a3ca7bbd4992a39ed5737ce0b4c32ed4c4d84d9e15a46"
+            },
+            Test {
+                input: "157d5b7e4507f66d9a267476d33831e7bb768d4d04cc3438da12f9010263ea5fcafbde2579db2f6b58f911d593d5f79fb05fe3596e3fa80ff2f761d1b0e57080055c118c53e53cdb63055261d7c9b2b39bd90acc32520cbbdbda2c4fd8856dbcee173132a2679198daf83007a9b5c51511ae49766c792a29520388444ebefe28256fb33d4260439cba73a9479ee00c63",
+                output_str: "d512ef86b19c0fab408df09a8ceff07e8259cdccbf0c060cfefd8fcd3951bed94bcc30005dad8002227ac4524a8e62709612666f54866074f2272e6cca23a88d5a05dd5b44dcf411e137f44645187bf03d8ca19db835974ce314ed8f3f1cb3407cc48650a61a8352fa34c4c307b8dc438634c292e91871a5dc55775ba740b8e1085c14bc779a0260288b48c80ab4b2ceff645fc47751d6dfd3039246a5e7f8b1d66fae0e2b71172c24d599cd5836faf10b567cbb834804c16d111b56d8961ec67ce6ddc989b0ac0fb3975581d3bd70043725331685b959e22af6509d4c9cbb8d4e10c9876ddf6460d62ab09a97a220038952f7025993f3f3c5eaaedc9d9ab2ae948f56f956ccfa1dc670c47ce1946ebbc7f1f537cbddd3938686e65e58f1573806ee42db6e22e1d5070820787198f27b842409b337bf0a5647c63dd0355838f52971616fd7318164cf331641fab6e3b2282547288a76bba5b973e138e4182783fadb159cdb1141dc950b70ef4609055076e7efb532c9a944c419baee914ebeeef7e1890b292f27ecb8b7da25b0c7debc52fa75f50247bb671087a0dfc15ff3dff6a3e57791f2471889f356d44a3a10228db2c3ce778ecbac53f127de3f4621e6d83f8714c0d66763460a011958101123e9ce31f5562b73ebd4f08947475e62c6d815bd02a3bcb12b8d058def7a9de8b4a70a00d039381d61dc6c0317a0de62aa"
+            },
+            Test {
+                input: "836b34b515476f613fe447a4e0c3f3b8f20910ac89a3977055c960d2d5d2b72bd8acc715a9035321b86703a411dde0466d58a59769672aa60ad587b8481de4bba552a1645779789501ec53d540b904821f32b0bd1855b04e4848f9f8cfe9ebd8911be95781a759d7ad9724a7102dbe576776b7c632bc39b9b5e19057e226552a5994c1dbb3b5c7871a11f5537011044c53",
+                output_str: "fbe450f412e4dea6df16609a1c5513ddc550f7d7fbefc4f5f9f193f3ac88351ccfb1c25955818dffe5df50ad08b3dfafacfd7bfd484a628f6c9bb4e32f271f4846bfb90be00b80572c12457ad35541c7fe0fcaf156ab66548a7d90458713f8e10e725c5759086d33685d43f3ed682b1f53453707fe17f0d389d0a8497e258566e93062b31e3538ed95691ce730b1df2f498f010a2c2de04dc698410a3d4669329e685827deae4baf2c15dbbe975c9daa13430c440543ad94624501aa63ac4d012edae314df68d7d4954d4119c5b9505d566b8ab9b54007f4b8d92d9feec562b9e0e37fd8643907d8e7b6fde785195650580373d3fc69619fdd039606064e84c6c6e44118e4921a2dbd185e7de90508ffe7380ed1c9917e0e38de26d8941d6ab0d0b4fa213db4b075a362b314bc7c3cf21a8341c611551057f9e07492c8d923d54336f3f0aa44422c423e2db0d598216889753280b08103417f431658f1ebe267237802e1ebfca862027a29aebadf8ed9a603983e0bdbbe84b3d9a5f862abbf5e18e5552c0d3e7577b96916123b4504aaf2107f643067b88ade293f5b3fd3f6955ccd9ad7e134c9f5ee60f6da78032ad1c85d710bc21939008111602147e0bf1d79f7f5302686729d44e44a7a6521b8270cc57cc8a6f16770ba66ede8fa823fa088bb7da7eee980c6c947d7f510deb93bf0b5f4380390408823aa8eb980ce0f04"
+            },
+            Test {
+                input: "cc7784a4912a7ab5ad3620aab29ba87077cd3cb83636adc9f3dc94f51edf521b2161ef108f21a0a298557981c0e53ce6ced45bdf782c1ef200d29bab81dd6460586964edab7cebdbbec75fd7925060f7da2b853b2b089588fa0f8c16ec6498b14c55dcee335cb3a91d698e4d393ab8e8eac0825f8adebeee196df41205c011674e53426caa453f8de1cbb57932b0b741d4c6",
+                output_str: "6658eb2feb9a739ff1724fe1526089d0ae807945741c2c6cb630e8f5b9c88f3455017bd81a5ed8f441afd50414ed0b9c267e527786041c4e3f8daccf1db60a0ade7199f689c8f0c04cc846318f0b8c34b122bb98386f48b0e69317938df76c9c6d502bfae1fda37ddba108af9e2d07cfeb50bb79d828fd5a67c9c3771ffaa07c7a47fa681a1358611ba76b079f4fe14dab9a0d3a4e5d2ac41f4f1374319ff9b81d970511464f5da9ae9d6312fa8baf22fceca2b4bec1a8d887f47811f1e7acc1884dee4740ab2f6e2b4f8c11c81c7e40be19f90f27fd1722ab95baa214b4096b4b11a1a9b553c4ecd789aed9f22fce58ae1963a62e450d754cb048c68eef0e7d2c2a146300a902c56ed8d149bb5c36566cb8a3dfa8582562a48927ddec45be750f639881cbc33d3b48c128d91108f2a55724bdc5162b652cc03d5f591e96f4bb40a571e1b22f504a6bb6d8d897a73884057e1d2eb15de0d3585bc14cddfafce3ad5d6a861d7cf82b5f1af784637a99b79f91528c4976720f34a3a12ba0a4bc84975cee3167d4e72292e9295629503d642a29196b934e71c63425ad701820e79ddc9220da7c7a2aaaffb852793e822b6915734fec8b93344bbbc66c5192b7f1ab6bcc63713b11cc23d541441c04428ed11444bb2f7ea981603ed4103f86e6623014ff97cd32da3c6e1ccc22ea8bbf3b6853764a733e61397302a96434abf2905f"
+            },
+            Test {
+                input: "7639b461fff270b2455ac1d1afce782944aea5e9087eb4a39eb96bb5c3baaf0e868c8526d3404f9405e79e77bfac5ffb89bf1957b523e17d341d7323c302ea7083872dd5e8705694acdda36d5a1b895aaa16eca6104c82688532c8bfe1790b5dc9f4ec5fe95baed37e1d287be710431f1e5e8ee105bc42ed37d74b1e55984bf1c09fe6a1fa13ef3b96faeaed6a2a1950a12153",
+                output_str: "cf7d80ded88e700ded518b2f0049405aea695691924b4ef06205dd2849e7a0090647c3a23407cd4ebd5b582c32b6554c506e416b9d13903a3ad69234826e36e3c5862baef9bd93ef345125678e32ebd5bae0961935232d5be54ac721fd75fe1165341a41fd880d239de12065471aee6cf970cb6a0f02addea861fefff91e6c2e482ea9bc255fb00cce1fe8ce3da479eb28768f356c2ef83f400a0f0ce859606f3862a3579e609de48f1ced3c86a9ea302462de9a27b0f251798f9d0acb22e6c71011f0dd45b11e8e33543a3275b24b6464980a5b6ffab2e9c8055cda16be6c60fb616a8f3e8b759552a2df2b05b846beae18a01dcab1e92545b0b3cc2dc25134379021dd7dc294bd97a775c174a04f2f67591841e080308c587e208d1b497e229220c38469944ef41f61a64c83e06a4390bcf318e53e4a6e9214f943d1ee957b71e8580e0a183c6b05924cf32809772cdba700ea369448ab56f399385d4b8d851cc8d6e8003f1035c6e739c91e03f1fcd9662ac99e372b45fc08610265e530f53ff726f599c33820ab468e6bc2c551204260271fe46c0a2975a18bccfd87a53b2a7eee2095a180b0a5bc7d64d57ff8efa628349e00c84b271ddfe13eb009387b1055f3b0e7b556ce6a738b9dc880b22e79666148a6c4d97b2ca581864ff4400749750bab03af9232815bd21a1a6460483505c34f282d59863b9f491a39d028d5"
+            },
+            Test {
+                input: "eb6513fc61b30cfba58d4d7e80f94d14589090cf1d80b1df2e68088dc6104959ba0d583d585e9578ab0aec0cf36c48435eb52ed9ab4bbce7a5abe679c97ae2dbe35e8cc1d45b06dda3cf418665c57cbee4bbb47fa4caf78f4ee656fec237fe4eebbafa206e1ef2bd0ee4ae71bd0e9b2f54f91daadf1febfd7032381d636b733dcb3bf76fb14e23aff1f68ed3dbcf75c9b99c6f26",
+                output_str: "fdb4cbef885524710f96f1b489099a8e5f9f5ef2bcccc23b6a619bc81f9dbff63b9ac609bd5da0fa7afac0e67bb96a54a1a64b4b943e0a492a5bfff399cc9a1fddb5787434f5034a30ca767cd8a31b69276435c99c64f3c567ebaf3c69fbcec540cb2fb671ca3835ecd228c7c7649410107d399edd661bc8947d43d5bc441ab2ef39afac6788bccdac5462d5698f60616114a8346707606d1501c834447031cfea921a85ac882194750fb8e4d22573a27f2901b75c6887d085a6b47e2bed5af785c9b60da38bc9f61750f16b2e06caa1cc77cad2b95c5d583d0e1bcd7e10b0d8fa8da7e097507d11873395166e3591bab851ef4cd7e1f05cd8401ae496737894ec50da4ef475424485be599a4e8387b0309629d5b634bd70c4c95be723932efc24ca8ff978cd31b08666f2f6df9e94a6f8afcdde6c6a01aecb63950a4b4bcfb4ecbc1feaf3b54454cbc7292a65282c9b0d7c6a053ffc11f6888da2bbcd6496ca74cfaf0f49a6f5f56e14e51955b73994015313404d46bcf0ca0854407707c176f36c3ae5986f67984a33f252b86b2758cdb7d2fbd63606b2e43f7bf0919cbf97d2e38f01aca8b3983421ca447a78ba415add0580fe56e391817783f11533c8d70e3b8ffc4a3ccdec56297ed51f80215be98c26b343736196f5c68a65b308835c8693280061865435383272a77397dd6fc3249b2ce17ab3417ac9dda62ee74c43"
+            },
+            Test {
+                input: "1594d74bf5dde444265d4c04dad9721ff3e34cbf622daf341fe16b96431f6c4df1f760d34f296eb97d98d560ad5286fec4dce1724f20b54fd7df51d4bf137add656c80546fb1bf516d62ee82baa992910ef4cc18b70f3f8698276fcfb44e0ec546c2c39cfd8ee91034ff9303058b4252462f86c823eb15bf481e6b79cc3a02218595b3658e8b37382bd5048eaed5fd02c37944e73b",
+                output_str: "748de9c6e6a8886e9c34d67a5b2625315d8b0057766ce2853f8dd047a3b58a410b2327e56234572db7ea886c90f6df31b795e93af95a4c52632d7e03d255668255f54c0dc1264ee989e25dd0ea77a8855bc74ea1066f201c999c0be63d1817df33db624f540ebf463c4b48569136e891c1082a37e6add6922c08fe512d925639cc37536a324f3850932b474f313647e65fbf28cc1804d2ef15492ce09e84413a465c69fca84014f15f2ff3ff5bfa6a9c38cb69e75d66145bcbdc462e3a6fcdbd7835c44b9d95e1f6d72c1a7af0e9e9730559499553715b0a7edeb6e5c8c5a3536caba0b67f619ab317aa8f60a005860599bd1a1ed20ffd191cf7ad26b63264ce022e1ca0eec821d6a4bfc1e97482cc33a14be20d3f6ef96a47da800ce1a8fd6939069df50c10145bee28799f8a1c43d37caa377aeae5a2a19e6da2f173124ced0aa5652aa34632be11cfeb8fc3c9a0b4c45a7933b671432aa666faffe679562d727f786960609a91d0972c35b4b9ad27dada6a24e00589cb1eb9e4706a476c5bf749091df4370cf99ff6adbe1b029505bbad815ad50ebdcf22208937fba80a453a99ca49004706a3cc3a95cfab7f0c2fd2e03617f379fdfb8a91442754de62805797adb4cdafdfb7a69f2b0ce9dc530a9ec8c741e892758512c4aac208564935791713b49b95a9df215fdd74f906f8eaa7b13a0eaa443d78a482364abb883813"
+            },
+            Test {
+                input: "4cfa1278903026f66fedd41374558be1b585d03c5c55dac94361df286d4bd39c7cb8037ed3b267b07c346626449d0cc5b0dd2cf221f7e4c3449a4be99985d2d5e67bff2923357ddeab5abcb4619f3a3a57b2cf928a022eb27676c6cf805689004fca4d41ea6c2d0a4789c7605f7bb838dd883b3ad3e6027e775bcf262881428099c7fff95b14c095ea130e0b9938a5e22fc52650f591",
+                output_str: "1060697962ea79b9519fe3aaef385c997b2e8028d68deb08ab3b76f71ce161eade98c89d223ef0384232ab3af3a6cb1d43ef5d20c1b3bb819423c026bef0bf54f4800cbf8e9e2d40f9a4c6cbe7487600bf451783a378558ba27268a5074af0630f5f2cb890bda971a4ab65cdc37c0215db1c09ba96240be066f95f158cf863cc18346866522529503e615e4cfef990f49583ede896beb63b1489b6a62bbad9330d5c3deb673d42151ed98a3854c1e80e0868e27d8cbcdb90dbf3505610fe170537919ec7c191579148e06d7d89be3f5c88c430e38fd36d820db5a941680e08b5d1859ea327c82ef50adb1d8e6e5184652064cae2c617337ed36cbd1ed42cdf3ed0c411cbe1a9e92e0f4ecd3cf84cb6c07093d51cd4d5e7c7543d385b9f420248749675cabe9fbb87f56c865325b826c4d32e28b1e4bf1889f2d00ba87ef01720d73eefbc38828ca76027c656e3758ddd1ce730e2aaac0354ea71e79d53c0d3526ed8fc024bb8cd675ab290feed6ceda91a29a71f5c128473ec94ee59a29a381e5046efefa8be3af7ff0858dd54065b41fde35f618235d5221aabe2b4be62c1e7fde8bead94f7bddbafb8a471199b3bc099e77d8190029cc7508d576db31f362b09e5c1131b0572d86d4a7d4b533737eb4d7e504dd0852e079f2a1b2b3a526175948227ea2511ecd4385f616b3bb086c54f191046bd1782eee9625796010493b3"
+            },
+            Test {
+                input: "d3e65cb92cfa79662f6af493d696a07ccf32aaadcceff06e73e8d9f6f909209e66715d6e978788c49efb9087b170ecf3aa86d2d4d1a065ae0efc8924f365d676b3cb9e2bec918fd96d0b43dee83727c9a93bf56ca2b2e59adba85696546a815067fc7a78039629d4948d157e7b0d826d1bf8e81237bab7321312fdaa4d521744f988db6fdf04549d0fdca393d639c729af716e9c8bba48",
+                output_str: "f31639ca0f9455e11389937e9e58792e3d73b9cb950adbe806607b1ad53d80f2a199f577e278137035136ad2afe7f8faffcf0e60f0b2a71e0bd9b938b28fcba94a912f249fb9ae1779f87bb1aa714d1fcc57d4bfb899a233b99586f81f4885de6693dce78d9b6631957f1689e843c1463045cda6b921173054e14be9dbd068890df88932f68ecefab3ad3eecac1b4c398292446b17e826aa8e35f6067c908afce46fd92899726677e2c0589f525ae021a22a601839beafed00f6a8ff6223fc5a92ebcf6207341b63fa2e66e9dee2fef1217d9d39915924e522bb52fd29501247b1a7b9dbc06678c5f29af7cea3d8722374446992a4bffb0e3e623e881efa7f957db1946496c2eaae98f0929ef3df633e67730d06483770197b9dd17c7c9838aa5003c5bdb4bc54e7389d453e769765879485abb3d565749c8cd5e50da9c4517f31abba38f1d7a0fae0d2816ca0ba1dffe569df4215d215676de0fcf55a75fa5f7e899f045a4b6051dd9355032dac56fc56c4988a4c082fb85b74a4c8a407ce1a06c344b2e833281ca64c2f23fd8a9f996c563e9af8742137617c0e46c5168e0b43877446e07563deb3d7654d9ea3c8ae3dec58c5753f34fded605a49236336f0b355e95def3bea7a367507f19f4e0a6dd03ed3090c285f761c48a3d3c5795cf277a87fca688495effdf5d10fbe07840c3f202d85044fa3bc41cdec4d0aaf59bb"
+            },
+            Test {
+                input: "842cc583504539622d7f71e7e31863a2b885c56a0ba62db4c2a3f2fd12e79660dc7205ca29a0dc0a87db4dc62ee47a41db36b9ddb3293b9ac4baae7df5c6e7201e17f717ab56e12cad476be49608ad2d50309e7d48d2d8de4fa58ac3cfeafeee48c0a9eec88498e3efc51f54d300d828dddccb9d0b06dd021a29cf5cb5b2506915beb8a11998b8b886e0f9b7a80e97d91a7d01270f9a7717",
+                output_str: "f04b251f8f1a9fe87e9f8b0bd8a641566174cd2157adfba255a4ddb7a001ecd9b479b7877c38e487dff1d830d01dab9684f1438c4812bef8da03ecfe57e7eb68a68e4fefd3e0a70d607ec77102538d5535c293339532953138995cb4f23af709f5c103e662e7edc447995fe5bc716c7bc482cd0cd13f17ab48d33c8bfaa67ab6ad30482b6db8ba5b1290656be81e1b543793d47c1d0ee7bc953c812e187535a0659b2cae6be47284419744c6aa66b9e53f76b9f90d4aef8dfcb04a98c82fb434c0946e5b98f2c3bf25c128cef77efb9f6412eb11f36e484faf2043a40cf44c6c3d28761f9cb7149c3db4620d09b220720767ae41bb097c865720185c19a474e4c3d706a636e42050a23766c2ff3a21c4e9dd7af62f47eca671f473e2b487a65abbfca74ced063e33f75955e9958240bc3907bb90ec6f49f384df5e936ae14fcb308f8acc1f7a406da680e4efdc2d2bb74b922c7b49e4972e388596b4f05fba68adf9a22fe16737394dfdffe2f0d32f1283ea81996b8309c2d10d4e32d4b7bc3d88484bab364d0b7e35ff5647053cb34180e037a66349a254ae2aa8f81cc7fb5514e76d9a01f96394e3a0044039c452ecf0fdf5b8a57a2a5600ab31affd1e15d4642f1a37deca0ec60ef753797ad668b7d9f2bc02de248c719311e5696e11688ddddf71f2f1994331cbcfbb9ff22438825620033734c27f9fe72766bd9c7fb021"
+            },
+            Test {
+                input: "6c4b0a0719573e57248661e98febe326571f9a1ca813d3638531ae28b4860f23c3a3a8ac1c250034a660e2d71e16d3acc4bf9ce215c6f15b1c0fc7e77d3d27157e66da9ceec9258f8f2bf9e02b4ac93793dd6e29e307ede3695a0df63cbdc0fc66fb770813eb149ca2a916911bee4902c47c7802e69e405fe3c04ceb5522792a5503fa829f707272226621f7c488a7698c0d69aa561be9f378",
+                output_str: "8728a95b55d97271b701b1bf2c2987ab3045d39fe0978c9467c41d44c006486cf3ca11b8c0d22c619a8e4652aebe67fe9fd7d35357633c8e11b865bd4c55571d764e6f92e29b5c93606273522a958eee0cb2315e89a1b5c45e763b145b1166a4717784e993e4a7a699fac6385957aa914bfc856e8ccc62dd39159f0fa5d2f4c74a4c9e1f3a1bf04f8d73ba5a3133243973562afe874c40331086e7a9705ac76ce8482b7b029278ca61cf74b5aed280a6e795906c4c3f525c5cb382e55af0ac5c9eafdc520b0ac74f14e0203f1209fe6641d1d971c76370204fc14bcd6a8223e30ca81b7d9e94f35dc53634646a21c28e873baf741705e4862ab6945653a312125f534a75b6f2d1cd4409d8f842dbdff9fea090f6677937daf354f6130ed77c32711aa0c7cd448d92075909ed7cfed67bbd5ccedfa34495624ee4373d66fc2f3b25b78ad6a1a9e9fa9a714ea24240161c8cd88f24fe72cc3160d5f68f2387347b580e945f401b0b025a21e97feec0d4dcc412d2597504489b3cc20e3c883c0d88f26591ab840799b5e9b253fe02656ca6ae1a1ef1be5f1961f29cdbe35a40bdaf2760c7bbf051ecb62322dd178753b3922af4cef0aff4955c32f32ac28d3a44b7f1e8cf93fe6547e8c3dd35159e92a9f3c6e4cf2a75c97cacc0d732b984a8b7a6af9b8189896fec2dbbea60c3b94904f154bdc8fc291e027ed03eeecfed067969"
+            },
+            Test {
+                input: "51b7dbb7ce2ffeb427a91ccfe5218fd40f9e0b7e24756d4c47cd55606008bdc27d16400933906fd9f30effdd4880022d081155342af3fb6cd53672ab7fb5b3a3bcbe47be1fd3a2278cae8a5fd61c1433f7d350675dd21803746cadca574130f01200024c6340ab0cc2cf74f2234669f34e9009ef2eb94823d62b31407f4ba46f1a1eec41641e84d77727b59e746b8a671bef936f05be820759fa",
+                output_str: "b0ee2d0215f195934d2937d523d38f1af153fc142c04e5d684834596f3b909241938a56209d414bd1ae0cb43eb2b46c314c1a0a0b155d432947c318642fe5c5b4fd6d0e4c21a9dc594db205307b41effd14141454ee55dad5667cc7459d0283ca6652cd5092ef8bc35c908add07fd5daed66afc6740baec7fcd64b838368a8ff0dcfe25b0d46fee0b842f9e9f59eee18d73c2549cce009c388b5a8ebbd54b35676b6140deed07efd4624d5a7f816189dfa779929c5f6b1b9489e27492ad0f1bd085ee890794529b75e10ba006c1b66f3f662c30df8b1295e1ffc301dc7060010862caa14d7fa09817f0d91e928ecd89fd8e76e69b3ef4986a15dffcedc9ac24e5e28783667731f07998f8a36da512bb5ba0ce50640a1a5328fe037f5872a85288158cd5c66b6c03f1925c12258ac4b5e675acd73716aeac389f9c235b02fe363a98cb10d9a0b44feed935ab067c2eeb499ca83fede967f576681a13c999fc7c1c0fde2754dfba713453545c6ae722f4faca5f5f2647378ba9308dc27d91bd1538624f459d0769f303ae818cc52647ac15e2af9bec6476a232c1ae81ba4b355c9dbcd37323d125228a53086e0afdc98c95f56e12a48843170e9cae703f5001b52da42c0ac9d285c8a13ad720104244f19c30b38ccd620ef8453401ca0feebc8b58025bbc6e6c2c788899871d3a5a363d51d8991b5cb5085f8ad525a71e985b3de"
+            },
+            Test {
+                input: "83599d93f5561e821bd01a472386bc2ff4efbd4aed60d5821e84aae74d8071029810f5e286f8f17651cd27da07b1eb4382f754cd1c95268783ad09220f5502840370d494beb17124220f6afce91ec8a0f55231f9652433e5ce3489b727716cf4aeba7dcda20cd29aa9a859201253f948dd94395aba9e3852bd1d60dda7ae5dc045b283da006e1cbad83cc13292a315db5553305c628dd091146597",
+                output_str: "19e39f7444a4a0e1c003631423a621c055d0e07f0e11ef5be1836b71690cb0de1565684c355ee9f2e6e65983b8101b5100f39157ddb8c8d92c736604693abc56491c58cd66bd66498143554d0ce34d601072bf9d0e18ea1b018a7ed9a65edbd0b81212ec13ab745728ed3a328ea157b9c4b3195f8cb8bad94a977015b94fe8050f37a0bc14e58eec7654b336a9e30baad27c441cf8afe093132234ce47ce3fb3722990f6c5916468b50a13c611b194d148a151b9ac97a89539d1efd2f9c6f72f56a8d22a557b23ec7d932a6e41b3f2c177ca9f2ecc2a1ead4061ddfc04ab1198db0e26c4b00301e35b18754df79332a46190ecf89c0da6834731cd19e2c8da3a09ed16813d2a41f7a0a4abe02c93f7307fec1537aba546865a3130d38ecc496e548a8ebd2858ec00a57e15e307c1a35d1355b8b97e9dece5a63ad7cbc97b30f2c9de69e4975dbacc31e04f15a8c02e5d23ed01506aefee60a449de20c5a50f1208097bddedf6d2cb34036da708ba53dff7bd6a1e41057e05bb57b3f7561979eb69c40348def728bfa8382f5bc8db63fbc08e6506ad80bce0c71fc94036eeab1c0c89a2c8af4002bd15617834a901ffa42aa249f7ea700e6ff4b211f7b052ed5bde9b242c9874ecf39b318a3713f1dc3066425abe76c4ad47f43ecfedc86a45e1e93544989ce7adea7e4cb3cf91047c4f9ead7c98ae963f34e99874b4002e3ff1"
+            },
+            Test {
+                input: "2be9bf526c9d5a75d565dd11ef63b979d068659c7f026c08bea4af161d85a462d80e45040e91f4165c074c43ac661380311a8cbed59cc8e4c4518e80cd2c78ab1cabf66bff83eab3a80148550307310950d034a6286c93a1ece8929e6385c5e3bb6ea8a7c0fb6d6332e320e71cc4eb462a2a62e2bfe08f0ccad93e61bedb5dd0b786a728ab666f07e0576d189c92bf9fb20dca49ac2d3956d47385e2",
+                output_str: "18af27fe1b4ae8a470778480f2586a370c93640bcddc33453e6f3ea1346b5a4ed3ea3e2ea43b143a22fc66501dd52df724c0e8f222380b4ba8bc23f2967d0a56ec241a0574e2783a461098f263533389d503b5d8550c8f60fd6fe953c5631635b6990434f8c68f8e9ac3701b3600c2d80f5b12d14218481904d1f15a776cfe1fa745103b995f9ca8e8e2ca062c5a3f1fdc848bfb0de4a47eeada11c51c743cd15c32bf921d07f242b83086660605b29fc36ae394c215251b49e9777a93ad91179cfb0551e113dc372f992674adbcc2d90aebc572b4c82b454ceb33910b60cf81b1ba558c2e01ec1d837fee34b86124e15d7beb7155e5456dc94d2427f7d916b9c34d24312eb2610a48002415182037afe89b29ddf5dd7e70b28bec4a1f3febd72ccfee8360e838fd787d0aa2af3a502d645433aeb1cff47e8e6769834cf0a2a85bafe9a89b43302bbc64c88ab6fe4712f3181a056921f6ac281c872e3eb21590c50b915f38172849cc8415bad8161dfe0a39c2532a34551441d78825fe7904b3febd8f645be5aa6f7dcc6eef96431086781c17615141d4159d6da40a3a5c22631bddb7f00040f0d39107bb366d82747851548f3ed3dbd028e3261561c8d7fcc077d3905ff42bf3caa9e351207137f7e8271ee970117e56d30b35294e8b91588dd9d9900274dba4108be1595833284047739dc4e90f9e20ba5efb2b736de6548c"
+            },
+            Test {
+                input: "ca76d3a12595a817682617006848675547d3e8f50c2210f9af906c0e7ce50b4460186fe70457a9e879e79fd4d1a688c70a347361c847ba0dd6aa52936eaf8e58a1be2f5c1c704e20146d366aeb3853bed9de9befe9569ac8aaea37a9fb7139a1a1a7d5c748605a8defb297869ebedd71d615a5da23496d11e11abbb126b206fa0a7797ee7de117986012d0362dcef775c2fe145ada6bda1ccb326bf644",
+                output_str: "ae82057ac5ea69cc1b5ebac395b0eff26850c394af8178b55ad808879ad634569bfd8d0c5f34f9a3b26821f63082c5d2c322f347fa6976aa88acfa9ed8393e126f7f47dfb523c0560da5357937a74488b51fa67583c7a7e1230c015fb5f233e25b744f2fb6830278b123f7784c4f6070c8f905f96486b2d5fe137be8d57150f47cc7dcc0011fd99f35df4d9e15f0f937762c87153ac17645ed67581b38e2b34899a7d726a9ecc1cf2e5198ed5aff13f2544aaa1a069ce8a30cb66e1b984002d20f769c0f94c95f99f914d32402741d5c4d631b9d6e561d32d1adbd1f1dd692bb89f48c6bc4f88b669fe4bd2922ce6a3184605053322952e113c98b330385d6c4b6527303563dcdf099bc2102f915ddf3be0989ec8bceb029ce61974ac41a26d6dc7f53405a4f3a9130c5cceaf71f828b3f7f58117eb476a46263423f68ecc3427d9a94c292ef7c4c1d67b323fe15f69894df362e54b441ba5c94d3e0b56b772afb5fcbf8ce62647dffd78ba7f48dedd2e457ae9fee60580084a05f318907dfb90faaeb9f4d9c160259a6f8523af77c8cd8af344f41dd511e46c699a8f9a5a85eaca57780005af313705820d8051d780506d02a09b04470398d0ad323adbaa8b3dbf61af68d9fd9df29a76e0a37678c08c9d102ba960db0b5d20b6bcdad7750d3f8cde6e994267e190d7f3da06c36cf7539b6b574034b43f55ef8dd370f727b97"
+            },
+            Test {
+                input: "f76b85dc67421025d64e93096d1d712b7baf7fb001716f02d33b2160c2c882c310ef13a576b1c2d30ef8f78ef8d2f465007109aad93f74cb9e7d7bef7c9590e8af3b267c89c15db238138c45833c98cc4a471a7802723ef4c744a853cf80a0c2568dd4ed58a2c9644806f42104cee53628e5bdf7b63b0b338e931e31b87c24b146c6d040605567ceef5960df9e022cb469d4c787f4cba3c544a1ac91f95f",
+                output_str: "39b12fe62b75d707c8e18fe1c8cd23d3c1e15b7f46ffcb24c70a1d86604fe6bbc36282595346a3374b0b2305f60cebd77de1125373f5230535ab0e4ba011c6154f65216ce58a65856c7ef60912877e44ed2527c3038ca202b5445e97bf817bb6419725abe41ea1529b6ddc64920dd8396a7fe3b26054c09e310465bf65aa7b56b1877d949dda06057b7373023eb09e4ca1790d66a773bf34f1b9d4011322e08bbb7139b1750278c2dce88626ab16813803e320515640ddd9d6a7c5b0dff8fdb445cd65d6bb454edf83d6bf4f3387cc98e381c65ad3811c8dc3b6a42c203fd2ad6bc464783b073c1a9d37c1d29f85061e9c426dd195a98df3eb0c258421962857ef89d643f8bb18db27f339ba178e85144040bbefeeb1160882c3ef2a1c4950873ac4e5c853e48dd7788250dab58a06beee1903c2e68ff0f8d7e8f55aeb58cb0d65f5e74fb5e301bae2258314d5b82e3c0d7c7782aa1b34e80bef2eb258e0bd322451097b0df4532a717e2f0fc166817e2a9e24a318e6a4db618b6a8382a1bd1a600918ca08ebbc224ae9a7c1ccc8978759f512d7a97e4d1f05173b33f670bf3c40e2807128f752fd2995ec3a608915754275ebd215821a4f04ad21dd823341b15a484d0c12bb3d829bf99e182fe774d2efc726eb37638cbbb521ff14e10d73c7ffbbd8b79eb86470da14236c087ec3bdd336e8244e780454da1a8e70524a19da"
+            },
+            Test {
+                input: "25b8c9c032ea6bcd733ffc8718fbb2a503a4ea8f71dea1176189f694304f0ff68e862a8197b839957549ef243a5279fc2646bd4c009b6d1edebf24738197abb4c992f6b1dc9ba891f570879accd5a6b18691a93c7d0a8d38f95b639c1daeb48c4c2f15ccf5b9d508f8333c32de78781b41850f261b855c4bebcc125a380c54d501c5d3bd07e6b52102116088e53d76583b0161e2a58d0778f091206aabd5a1",
+                output_str: "939d443f3aaf7809342b2ec600a9d1a47e0c4195c9e1d95ce22f95cb98aa970f4fdd29a7ec9de471a1c342d4830d20dfc5abfa98f8bfd4cdf752e00bff151d7ca44d5bbe7ac18a9ecc1157354b2055ab08b1ae7b304623d643f6d471f23a82c2e1c67f11d527985208c5494138815c3cf6227a6a6facc9e2a1e3d58b32e296415e5889e58e1dc8657b0324bd1eac60ff8db83674b75683348d69978f04697a1d1d3e6d29d02094c277cf034d8203dc4d705df8eab7046c4811c18f2ec906b735bfd1c2aa3306fa0c9aa47e160b6eab89e0b390f37e53b92a1a160560e9a30ea3f005d100f0521aff20a2de0ade53bcbefc517647c81ab8684b2754fd62e5eda0ebbf56aeed4f4992a0fd4d26aec29bd186b2e254da07e1c5ad03f8194ab350510998a3bc11f08ef33c61069d1cb7d271f7d7c799057e6c2acc1d3fd8dd666e1b2c2e15ca2f99e55163bb01bca7f9d53f6389704874b3e5dbe6e74d91f110cf8a4d5eacc7a519f664c962b11a48e022cf65d4db4e4e506951513d83669c786fdf84a79aefdad75414a6cc82ea84eb3a173e887d39230631b6cc2ad26c55c938c6c82181f57820fe88dea96aea2b20e330c29c09a645134472b1b1303b1f46da40901a63c079689db2c84e46fc548270fe88a4a2fb5ea27c58a4374f72849b9c5c7c18ae2075546868a05eedc3d867f9601c5c8ee585f14a1e3a84e2fe9a1a99a0"
+            },
+            Test {
+                input: "21cfdc2a7ccb7f331b3d2eefff37e48ad9fa9c788c3f3c200e0173d99963e1cbca93623b264e920394ae48bb4c3a5bb96ffbc8f0e53f30e22956adabc2765f57fb761e147ecbf8567533db6e50c8a1f894310a94edf806dd8ca6a0e141c0fa7c9fae6c6ae65f18c93a8529e6e5b553bf55f25be2e80a9882bd37f145fecbeb3d447a3c4e46c21524cc55cdd62f521ab92a8ba72b897996c49bb273198b7b1c9e",
+                output_str: "fe0e80e36e66e0610581835d69a73908f1d951a81de93fd2bc5f10736def8a887eefede8bb6074862eea4bb0f131e48d2c3fdc8b8b8b93aef4c06bf97214f4d0c9000940f81664e04d88316f3732b39e7f9685be377b90fd7343947e7a79fee7bdf5757c386de6d02035fd4082735ce2fe898f18bdf00f3df5bd160d792d3a156584eee92b273f9a52ed221831942eb0f148dfbbdbc21960064d0e9e1cfe4e08c7927fdf1f0956288419b0372d3dff7d1a2528062d31d97d17f7f8cb09ace01187710e9dc2cd842cc8c09a0d1fe34424283fce75e64446608cae796c1f6385f989fc93b31f1edc36bd2c3ef3b71d14f25048b2e30a5f279180ff3fd0b8308ca93f4d1e72f7f45c7313ab6315d1f0b198f8d5b47742e94edbd33643397661391a82832744ef99cab293f26c8e9b0f9d6c9c82beeee0a4b4e6ed3ef2e7395fef4222f3df7b032ea28430478c038e45d36379dfd182877f827d86081647db55b2a05067913de694f84ee85bccb1f60902f787ce27407f14c445eb5159bbf643ef6195df2f23b0bc41ed595665d47b91223740709dbc82a86e35f615897bcde5f597fe05047a6cefd2529394cb85c4945f4188a078693c56a6124e040070771a4e509036df1c9b24e2185908a43e4ff81adc7d10d5578b00a6db9fb56cea6d51590b1cda9bcee86cbd8263557aaafb7f81418fb9dceb0dd67ee6ee7bc761920ef784"
+            },
+            Test {
+                input: "4e452ba42127dcc956ef4f8f35dd68cb225fb73b5bc7e1ec5a898bba2931563e74faff3b67314f241ec49f4a7061e3bd0213ae826bab380f1f14faab8b0efddd5fd1bb49373853a08f30553d5a55ccbbb8153de4704f29ca2bdeef0419468e05dd51557ccc80c0a96190bbcc4d77ecff21c66bdf486459d427f986410f883a80a5bcc32c20f0478bb9a97a126fc5f95451e40f292a4614930d054c851acd019ccf",
+                output_str: "083a1eba0ee14492af390762e0673f2b41c1179c8616870fa5aa69c40236a6cff19f322a4fb8aebdd659c5ffb5f1a953e65fc88c42c12e37fbffd6184035f0f31ad80f7e257fb2e898c9e5daa5a20603a0ea41fae59e7684646a826c4501f0a7a8c622cf5a27d37e998ed954f0dfda36a86ce59c8a8df3da65da575df05419269438f0dc0f41fb34064e48bc4efeec93bba805b5dc97f7aedff9e08e3d4b7e2aaf58747255f09a4b53658d7ae61d97ef42396161cbc2080dc7bb7392bfb348aef7f4b2925cdf9f641f3bffa3f140c0142d0e61cbe3d1df06b016579a748b56c89d5ba88466db79e891cfa7b70532a4d6649c4176fc21531f62f7baf5d9ef2976227ed6eb614dc44ca99f9580c82418ff886e169506f8bbed568faea7ce2551346efcf70fd5c32b6a30572bb72c87c62b8992edb3db0b4c3ef8ca466b5144658bc4148909bd8d9e1ab5ce3a1801d15f93946217ce9d8c0ed536b3c2e75c17b7fea2e99820c901e80efeb0ff7fb8226cad685cd768a41b8cde2c5cc8bc44b673ce5c44f63840c99e557f3b45c9ec92981cfdb3e20ee040af13a92df41e8a0877d0559f6ff5d9dbca2f53a4e2a8b47218cfad9ca6ae3892f21a0d9c0fe91a4f027bc25985947af0c906537e827b3c79bba1f37ee38f2897cbe9aba9438cce9d972ec262d358c33e2e6f2f814f0e28b4709c2ed119b50594be98f594ccd2b7d56f03"
+            },
+            Test {
+                input: "fa85671df7dadf99a6ffee97a3ab9991671f5629195049880497487867a6c446b60087fac9a0f2fcc8e3b24e97e42345b93b5f7d3691829d3f8ccd4bb36411b85fc2328eb0c51cb3151f70860ad3246ce0623a8dc8b3c49f958f8690f8e3860e71eb2b1479a5cea0b3f8befd87acaf5362435eaeccb52f38617bc6c5c2c6e269ead1fbd69e941d4ad2012da2c5b21bcfbf98e4a77ab2af1f3fda3233f046d38f1dc8",
+                output_str: "af0ff42ee50b300f202648fbe2dc08423944429568354570f787b96531a0045c76189e453369381cb7b0a537b9ec05aa22679e96c7bd7ca55793ddc73b6c3faa3a0d2b03d7561d321fcb377a1ba87c098d9fcd1c03d7b7bba6262687d71b1b608bf1486946739a69dbe87b95f0e7010103af17a6b0c50db308de00442641b51c5852e91e621133eb561c24655c9d59c22b6aea470e4d23535046fb88105e7ddfc08339e99d8a750b641e81eaab46a18cae3efaa493790a9e942eeb6990eb0e14beb6fcddaaa0bdc5d67bee8fddf1931201f18d0b0ea4227d1e89bcee6c293eeac60d3a724fa6fdda3af62d5c4c5200e14e2d40f3e031e71a8de27ce3d3956cabe9c6a5bcd67c0fe25dbbdeb5720b823777815ec277b594c914f07c989824cf0b1060ed0d4b3ece3fb65a5ae726412e6eb6fcf3047c6326922a0bd1ba7604830dc4d4981ff12b0364435544d4836505719eef8bcd246a326ca1a756193fa0a94ebe98a632ce5a0d88e115a4ccd1b030ea7b1651f43f22d2d2a530e2821f2380857e916920fab974aeb69fdd7c3af313b46f2dbd14d5b4bea514041e015ec93a6a633bd6477de78b51e592b3d87a708b831a37b70ac70730c606a7c880ce3fbc11b727e25849f2be6586d32cf7f31e20a739ccb25b62c03c1db5afa7b1c00b003dd9c5bfa49606830cd5a9b9204e1a51efa571688496d5a49f4733daaa295aee26"
+            },
+            Test {
+                input: "e90847ae6797fbc0b6b36d6e588c0a743d725788ca50b6d792352ea8294f5ba654a15366b8e1b288d84f5178240827975a763bc45c7b0430e8a559df4488505e009c63da994f1403f407958203cebb6e37d89c94a5eacf6039a327f6c4dbbc7a2a307d976aa39e41af6537243fc218dfa6ab4dd817b6a397df5ca69107a9198799ed248641b63b42cb4c29bfdd7975ac96edfc274ac562d0474c60347a078ce4c25e88",
+                output_str: "95d216d4fb11c900cb83674fcd99d4a0b0909b307a2020bb00d6d6a5590b6f82268d377e255bddd9179249c3769ab3ea09d9357447e99f9c8e924fa8c39b378790cb629c46c914ec79bdb4aef7c4d0ed5092b620a3cb3bf6d19dcb0ed4ecfdafc9c049e7a8edacd6c91a3c15d7587c58669e0ac51e151b613503db2afca0ae81782ca58bea22467b9fe7cf5f095b376badfd9ebc0bdaedbcc0832d80aecdd6919ab2d31646d9426cc46da1e5398dd475e94fdfba98129c8997ab4ede6a204c17caf9b1691160fa4362909b1c1be81420092a8f5005a3fcd26fe0fcdead650665e4ed9cd22db75382d898075bd2e68d240e13bc340c6e4a59ae944a626349a3e27f9c82f4dee5b593cbbeba0a2ba46a5c0febc5290675b2fb636ee868afebe35f7bd08f1137acb12c6d8376cc8e737827f199c899b3d8aaa937349cc04b3c64691931dc13f10ec5c57f4d5a13a38e26614302c23e30f28ae09669c4a01f7fac9ff0b2e1068343862364e799c63d74c7bfbc5f7cffe79c24a58bc2ce1041045fb01653157c9945b626b3cd315d9d25cb0b694074ae8f29d372067c308f6bf0c44cecbe47e5528e0ef9e373db63e554fda5212e35898975d708652ad71c14a51c6e5e8a04cd9b7365abd43f61fc7b3efbe60715574c0ad0bcb0c1d53dbf51172e669e35b19f333a3caedbc4e08617c47e51ab3863d61a13a8a2b2d5fb54190a0b80"
+            },
+            Test {
+                input: "f6d5c2b6c93954fc627602c00c4ca9a7d3ed12b27173f0b2c9b0e4a5939398a665e67e69d0b12fb7e4ceb253e8083d1ceb724ac07f009f094e42f2d6f2129489e846eaff0700a8d4453ef453a3eddc18f408c77a83275617fabc4ea3a2833aa73406c0e966276079d38e8e38539a70e194cc5513aaa457c699383fd1900b1e72bdfb835d1fd321b37ba80549b078a49ea08152869a918ca57f5b54ed71e4fd3ac5c06729",
+                output_str: "c2c5a2155ab4fbd3a3997bd00ed2ea8f049205a6e0668da09e0daac49484b0168e6767ad78868347272e6d8c97eef06ad0a3cb9ff91678dec7385124aac34817a6dd435a0a88db8e19a4fc75e8f9eb34376e8c1cc7951623171db22db1cc5df9d3d607e5fb17e450c15a20a748c340a56142289e0b1ec83ce82d7706ddba124759e895cb7b91522bc46e011b4eb98927d860d09ba48eaf80d1ffdf9cca026b5360ac8c2f04e9b0c30582611b8e8085b8e986d28c330bcfe80dcf11246d3544f4ae7c655e46654dc5151242cfa7b620c429757b1d527071fee890c73eabf1bd1630dc5bb4621ed4c5c6ff7f41f4bced4d31b215dd2be6a5952bd06dadc42a355f628616db922db19cec424bfcb893f948f1364ae7be1f79413a879fa372efbd59f62fc3879fba03622cf947d0fd2c02460d1d735e41ece1a2ab970fa9784dc67f0f7c2a3a0a5460f1b31029fb65d1a9a6809b4f2ae29f3a68cc2c780d0000f0790998c0febfaa59a1a56ced99f752684af6dfce832901b998156c73e007c77bf401cfdab4e6bc582b6cd477fccbb1549c870fd6e62633b90ed103edb47d749d04c39d2dcaa3dd4793957efd12d78b73f58d43087f456833432124e312d499779cdae6332ee8d884f5719d07786a7c85a9642fec61b66834f98c25e0a802b3f84dde862d9127923e3a20e5a20e184984f8661058d53ffaa70c5abbbcab51ca8e0f"
+            },
+            Test {
+                input: "cf8562b1bed89892d67ddaaf3deeb28246456e972326dbcdb5cf3fb289aca01e68da5d59896e3a6165358b071b304d6ab3d018944be5049d5e0e2bb819acf67a6006111089e6767132d72dd85beddcbb2d64496db0cc92955ab4c6234f1eea24f2d51483f2e209e4589bf9519fac51b4d061e801125e605f8093bb6997bc163d551596fe4ab7cfae8fb9a90f6980480ce0c229fd1675409bd788354daf316240cfe0af93eb",
+                output_str: "b3cc34c482e9402ea5a209ccaf5d017bc118f61e52bedee634fd56c7616e6adaed42d02f072ab4ee1d8bccb8038b00ff3072dcd971616fd6a2b0012581638f835e5441842631d12fe303d6e533d22eab7cfcb702e4bda509c832bbb5c24ec62a468ca885ab7e4e3b951c5380a30cb6f132408d31faddec570800b8eb58aaed9ebd8a0d6618d439b46f83116715568a5957d2db94e0c2cdcf9821d86a71a96c622ba5c0f7c214375686e71f4ae74fcf5a75a6db5f8eb274e6d93b52a2a5110c0b77a1e21e599ed0abb78a93a5469747a6d1fc4e3e3baecf8ef33580f00d55cdf9124e2beedb8814c8f5d5171cf6596de35afce94cec25fe5d6877f40dac4b2d2fdaa0e98fc08db03fdafc3a4a2a98d0e865c99b766f55349b688506d7b701bb01bb06f80d6be98dd374bd84211c61112dd0b9a25efa21f9804d724154881906a7bf815f206f4aa1175348212c54538bee673b56582501a659061a157444dce84c226936e99e51252418498dfeb02f2dc665b8cc4622c0326978fa7a7a8d171d445cee519a32d81721f99df529614bf09e4273b24a6809cfab9a1e81e5280c84ed3cba6d4b232080bdd034f1895f4010baef462074898949a1cd5892aef5dcb2b09d46201509847179505980a2846e58ddb22ea9fa0fcbe3ad9dffaaa42f4fef4a9dd8391495ba470a2eb80d5992da78dcc8e893c1ba2c909cf8208a18c31ebacc"
+            },
+            Test {
+                input: "2ace31abb0a2e3267944d2f75e1559985db7354c6e605f18dc8470423fca30b7331d9b33c4a4326783d1caae1b4f07060eff978e4746bf0c7e30cd61040bd5ec2746b29863eb7f103ebda614c4291a805b6a4c8214230564a0557bc7102e0bd3ed23719252f7435d64d210ee2aafc585be903fa41e1968c50fd5d5367926df7a05e3a42cf07e656ff92de73b036cf8b19898c0cb34557c0c12c2d8b84e91181af467bc75a9d1",
+                output_str: "1a2eb5a7e3266cdadc696d082dbad5d9f73777f5b95dad3e9c6a936271f12762ff3e8d1d959abbac6933bb19d2a0125ad59477611f9f912f935d662ade6e1e40412bde3e00a99c06a4906b90855af6095dd7e6114ea48ddc1a76f3c8ffffde5ac246f5c0f854831ee7b48df6a32cecec0e4243a792ce3fce40bd5ab22838dec6155c817d272f3ad602f58ef870d0126ea18afd1f1527931c321a8d6da1bf60665d077ad15ef615584a249ecf7d3728c0e9d3fc09bf8d3fbb9d260fa4ff13bbd4dba6835590d67eabfafb92cb3b0435f26e7ec265f7e2077446e1580fd1747e871d7ad1e992c1a909e068ca3f8b8a927053cf31ef7e071d5c7b4044f2cf61ddd48e7b7115ae0cc2861db7e26302df02cad460358d06acb7e2d07615c0f3786ba02000893febd088584aca9fbe9f14f85c88943671d24e9cd0b8fa46601c2e40d3177eeb500e8aa2931473dc3bc46f71c749c281e02b67d8f0b3d012de4942b1b3c60a2595e845ca454028489417842d9a6c4706424c5c0a073bfd080e5f820cccee99cc4fd372b0bbc447c5f3f54d87755c0a59c986d98e316f8f1899821cfae312b9416a4622786b2910910b86d19692c8a7ed50d63e252a3a5655d6e49af3082bdbbd07690dc6d4ea42f8a7bc57db816929b9ff8375c4596f57d9359f9fcdf8a3fab33ae27624265296a093dbcbdea292450d345b8116b86fc54a0b4b55f12f"
+            },
+            Test {
+                input: "0d8d09aed19f1013969ce5e7eb92f83a209ae76be31c754844ea9116ceb39a22ebb6003017bbcf26555fa6624185187db8f0cb3564b8b1c06bf685d47f3286eda20b83358f599d2044bbf0583fab8d78f854fe0a596183230c5ef8e54426750eaf2cc4e29d3bdd037e734d863c2bd9789b4c243096138f7672c232314effdfc6513427e2da76916b5248933be312eb5dde4cf70804fb258ac5fb82d58d08177ac6f4756017fff5",
+                output_str: "1e67e9fbb0568660eba48d1c701d75653d97d9a94e770c355e2f3f6dd9b7c3cdc771fe82ec87befe4aab21ba7c689facf51593cb278f7a8a4d81b9ce798cc2fba50145eeb0de079f016362fde491620cb0a3c26cb5d5fb09980e783774c8fd2c9d8900ebb103d73f0bab02d0a8e2827d2471db29f3d6ee5d9d620d4d13d8925f1933b1c66869bf74ef967204238e095927961ed5925d1a271b9277ab9dd7a30de1fecd4c6bd9615618bf79850ee7e247121c928ac9be6f81d2b41378e984f4ba494180d7e45cb7abb6de308db53804bcf43dacc10ab3a98157285fbac9b183aa49ec18e98e9b40d12b022f40b213641cb2e18e3303e4c9078da836466db8e2e85962e5520e9ff66cf99f96e7699212816124313e5ba6347f99da7109940081419b4eed3f4ed2763d655a00ec6d183ca879074f237bbc49d40d598ff2bd8f47d0d69f2e41397042b4398d4fe449cf553f6096ba25c1a2185a13bce5545fd0defe4d11168bd81b85ca5b0502233c43b6e863447578eb6f074ee2eefbbe6c52d0e8b1046f304de2caf6484ac24783dd77774f0fafebac731e429dbacb0d95be662ed9c71fdd6c0e6595ca063c748ecff99206441f8e96c96063ef61d741b4d622b6ef6a6d547b738ab27b50fad2ec5c479ea8069b9d67654c2f12d8232ab8a97c83af190b8f09e2b8f62b7daa334dc8f26a3ea62a999433fba70a27b9cf7fcb61a2"
+            },
+            Test {
+                input: "c3236b73deb7662bf3f3daa58f137b358ba610560ef7455785a9befdb035a066e90704f929bd9689cef0ce3bda5acf4480bceb8d09d10b098ad8500d9b6071dfc3a14af6c77511d81e3aa8844986c3bea6f469f9e02194c92868cd5f51646256798ff0424954c1434bdfed9facb390b07d342e992936e0f88bfd0e884a0ddb679d0547ccdec6384285a45429d115ac7d235a717242021d1dc35641f5f0a48e8445dba58e6cb2c8ea",
+                output_str: "7204f8652f37d125bf692544b8ba0c8859beae66e4b04ada5685c6b4c3c1b8a3825b2ad6bcb2f5443b4c28adf57388fcff481ca629934cabf872354e4a33942b738ccd4e1941621524e895188d2acc9efc69de7a170bc974c430b9830e25df96097b3785a2f6b86f39e59574e1d9c2b91eed2231d4d1aefbd5dcee3e5faa42472949d0d19da8980bfc6276e41ddd600ddf78e82393eee5a9ae0c87578071d667b886eabbe6757a52af9826f65e7ca8052982523f61184b5892465b3f82bae68fe2fec1577eb935309ede804163dee46efbf5c93e7a9dc3ba79cd9a866966ba1fc0a721ca4ad17364c3a4033e805616faa6075672dd6fae31a67d891646b74dd8aa916e078ba7736a9b00f73df90b09732a42e38fe3ec9f8fc907a5868ca170c669abaf99571d14771b91f46c68f57dc6215b94dc0bb03f890bde02dd41ce5d0f8f48e4fdaead1f0a05da9a456da80b82f44efa53db9899f42ba31cecd9d7ce6a5de33b70dd6427d3a9b31c83adee1ee073e06ec4238fee4ea0029876fe6eca5de76e4d32b65564efcaa326af3519eda46eb3e443a85e78a8e26d21b158328a56af40b07ad19734e341a45a5f43d1ec2c9effbc7c5dd92acef61607f3cfda8bc72d33c045a6b883972cf4fd1282a0ade3978d1803ee78bc6f6fd297ec9e3052460483dbf79e6c35afdbc10fa87d769ae6a4e2849ad112eddec1135cdec2ecfb6c"
+            },
+            Test {
+                input: "b39feb8283eadc63e8184b51df5ae3fd41aac8a963bb0be1cd08aa5867d8d910c669221e73243360646f6553d1ca05a84e8dc0de05b6419ec349ca994480193d01c92525f3fb3dcefb08afc6d26947bdbbfd85193f53b50609c6140905c53a6686b58e53a319a57b962331ede98149af3de3118a819da4d76706a0424b4e1d2910b0ed26af61d150ebcb46595d4266a0bd7f651ba47d0c7f179ca28545007d92e8419d48fdfbd744ce",
+                output_str: "a3d5cfcdcc03334632027fa1b1adb97c740f9c5d33f0b6d8468b4aa9b37a5eae697d6de7717b6f7c3e872dcc4a62682ddd76d87657096d143dedf97f2b9ba36734b9ff5816e247243b1f32f5ca122ab49647fda690b83ae0fee45625b4a2606c8e366cd5031a0c938407cc9421414ce4631477c3d4494570916bb41c60fc05ac125a3e81346759dca0cebdd763b61493997b774a582475d2261f6f8500d2c51c70de11123756eb6b958ee5f20fb4a49429358d743e4b62d76904d23fd5dac9ecbff14854bf27dda819b3f52421329b0576cc399eac734d73fd9bb8729168e35e2a3490d7bfaa39e53e54340457aec4c5c8f4c0fee9339053646e4d74ef1a1406eba208822b8e66de410cfcd49a464d9ff545604c26caa4fe84b018c69be18112b5c3d7325481078c712979dc88842e2842df19f39025d28fdf45a5dd6e8fd2d12bf27d227e79210f6266b86cdc7bc6f81db57af57aa252c5bb95a235746b9c869ba7f8c90e0ad3f5ded409947173d071de216ed1b137846752653cc6cfa3c52a32ad6ca0bce29a5b12475c049488f0a79adf5adc4510e6468e714bba37c0005a9cfa3ddb24363290a04bafbba92bbb2c2e16cdd9d40707c56f49c05c5276c89beac3b239de284867611ca3dd8250e8c7fdf522e0e84ea47a3a06554dfff6b7da13349a5f36ca447499c45da4c491dfc113892672b036507ff3a1e7e07b43fb95"
+            },
+            Test {
+                input: "a983d54f503803e8c7999f4edbbe82e9084f422143a932ddddc47a17b0b7564a7f37a99d0786e99476428d29e29d3c197a72bfab1342c12a0fc4787fd7017d7a6174049ea43b5779169ef7472bdbbd941dcb82fc73aac45a8a94c9f2bd3477f61fd3b796f02a1b8264a214c6fea74b7051b226c722099ec7883a462b83b6afdd4009248b8a237f605fe5a08fe7d8b45321421ebba67bd70a0b00ddbf94baab7f359d5d1eea105f28dcfb",
+                output_str: "23397cf5c6041fca9f1503b12a47f1389c4c35301f1747d574b48deb270cc2fd79da5718d0d5acb78a7f30782617aa2e03b9f46736620e512a6aa4e55e2b94537a74357e5c1e6216bda724677bfc4ccac3e3dcf4ae21d7e56d55ed2efe6fb50a2222e98139dfc739fc759be57963d8427d0b5d2093cf5f42347a6d9832e1febb4576935fa18e93ddb20e8cef2f2eba33c66f1e5741171bb64c49f128a7b0a9f095a35f5a20a996a3f9d7a68ab3b0d0f84e8f4fd43078a80266377d0d7020de67e18de20656bd59b86726c99b1dc8fa25b83a1fc8b7c256ddafcc67540c1287cc377ac10d39288ce00839af31a1c078b403a863171cc669dd72abf4d48cc72af222fe939a2d75cd7f195d3bd8cf8069f6557f1fb37bc8f9b677865e0d23bdd29c9b240cd2993874fbdd5fd3b8cc57b6226c40890057994a2e13129f4613d3ed31ea5804006f5753047f1128f9b8c0a7aba719a1449b3a2d02acfa0877e81306179f9ab717ac84819029006d73d48ee55ca13a3d39ed293ad0afc8eac8f8d41971242877788ec1286ed35f06330683fe33042a6255835cd54aa07c0166350b851f98f2ad2a06fda56b180f11b9616bb51ed98a2fed5bc2f9eef7046a38754b91543ebe97b8375a81b7fe9ce58de4dcafcdf8183541e44cc96f855cad024c24ea87313dc05eaa1d933d6e238e9b3a0b9628239344e8e81b5341d615b63d881ffe45"
+            },
+            Test {
+                input: "e4d1c1897a0a866ce564635b74222f9696bf2c7f640dd78d7e2aca66e1b61c642bb03ea7536aae597811e9bf4a7b453ede31f97b46a5f0ef51a071a2b3918df16b152519ae3776f9f1edab4c2a377c3292e96408359d3613844d5eb393000283d5ad3401a318b12fd1474b8612f2bb50fb6a8b9e023a54d7dde28c43d6d8854c8d9d1155935c199811dbfc87e9e0072e90eb88681cc7529714f8fb8a2c9d88567adfb974ee205a9bf7b848",
+                output_str: "3753866fc2d045059fa925412d3ff0fd1254724dec38e00f1096af36d0a7603903089900f95cf9bcfecec4cea14b7d80cb324c56e60569aad9e0f45d3a726f87e6f18559701ee6ae0e7a8622b45dcc6991a1ff15de6b78bbcb96f976089f26a38ef190ee0c609db54f443f5f1014762f336f62eb5f7cb7b102e99fabd87f36aed3359eb0dbf739df4eec4aac458546c00d16d412841142acd2e08caadbdde86843add14e3d28426295762e564e1f4854e7c617f48eb6f2fac79ffa8cddb09fa09a8dd73ec389285036a5244041dbd60ab71f8fb59eb73629bb4a827a7584b20c12b96fb1f0b950bd3c87117da69c7eda0c1645b6c8c81da8a6397dd821a983de84390b1ca902f135160db58f9f7b7ac9d010ce8d6bf7136270fae0d3994f80612bb12916993aa73f22fae642784d75e1cb5acdbcc20a3ab148d6f3f171402391121bb404f8f576eefc9acd1903bf9ad2cd4eb1208f143dc84643e52570d406ba31f8dc9f3283b2691f826c4adbaf431eb2f1de1e860f9b4c0153c9f002c809822875f915f7131ef63262abbd8bf4a5d9d1699d893435c731de48756c8d03c94d11d1d484dddbc5c35660b3318468fefd82778cf907ff52d652bcdf68c20349f64006c640e7a544dec1fe1709056ffd9ea7d41590f84f653ad4f7474d008765bfaeffba015de99d523a56a6c989ba11afae097f4d5fa63f04ae0917212e4eaf48"
+            },
+            Test {
+                input: "b10c59723e3dcadd6d75df87d0a1580e73133a9b7d00cb95ec19f5547027323be75158b11f80b6e142c6a78531886d9047b08e551e75e6261e79785366d7024bd7cd9cf322d9be7d57fb661069f2481c7bb759cd71b4b36ca2bc2df6d3a328faebdb995a9794a8d72155ed551a1f87c80bf6059b43fc764900b18a1c2441f7487743cf84e565f61f8dd2ece6b6ccc9444049197aaaf53e926fbee3bfca8be588ec77f29d211be89de18b15f6",
+                output_str: "2381aa1e335043c1f7360d64c703fcf6190747a616c550f787c33a573b2f9e83de427ad8ee50610a2fbb07ac92e4f912b3e5c10001044fa2cc3ff1c2182c672bc03183af502d6530443d890af4571611df65a2fc50879d08e9d664d78d5f81d74957d38726caee5451ab88df8853cc4a034065c532346a4f0d548d65745ab649683cfe185c649ceea12d79e0904e2c059549f895dcb1ed12d1cdf00d530d4653b56ef9fcf8d3bcc70fa91397b87f34ff839d3c0deb053d46fdff9262219004961af9d03f50e1016e737605f35eded16ed51f4aa8ffe0a253aa21011dc002c5c0e0b1ac706e53dbfddcb1b02c0148c3afa9d69b6cf7a72b1f793edac9a99acc99f988ebee210ee108093ce8eed146fbd98436299b159760edf3d07bfec6a9c1d844e98dd632b1e773d93b9604cb635457e33c063991d2a6d4dd8aa72883fdd742e34eca12975afdbfa2eb997609f91cb4bd53ca40ba4793b9849abd509a2b6c01094400526c493ff33e0f8f1908bbf783e0dfd92105830947338537c9f7b6b2d193cb2923f95caf113c9248c601eb39147661f7c639fb05281e0728b916c59d98f36daec1f61fad84e7292b6a5821009fcc30ee7267969243b36134675f3c8f1f18e9c341afeb5377426bb04517d1498fa7a271029936ffbbb4248a786eab072387b991222017025bb84eb4dc084781f21251cd8d8ccea15ea2c37c89632bb67e"
+            },
+            Test {
+                input: "db11f609baba7b0ca634926b1dd539c8cbada24967d7add4d9876f77c2d80c0f4dcefbd7121548373582705cca2495bd2a43716fe64ed26d059cfb566b3364bd49ee0717bdd9810dd14d8fad80dbbdc4cafb37cc60fb0fe2a80fb4541b8ca9d59dce457738a9d3d8f641af8c3fd6da162dc16fc01aac527a4a0255b4d231c0be50f44f0db0b713af03d968fe7f0f61ed0824c55c4b5265548febd6aad5c5eedf63efe793489c39b8fd29d104ce",
+                output_str: "325a6883e6918057acc4d7e6863d245ed59957957af4e8e59ec6eca35eb380641bd39550268a68ebad703a51f9b47dd05ca25681bdc853ef0897cbd4a0da6be9e911c26e801da8f5360140fea2ee9276747e1ad0879fd741e52a7dc8f0ee3cb199826f9c1d397e150641e8ec348300ba4f7ea7746ed0e94520577fdd253e04c47223521661a308d1c996a90df8a9ad18418193d590e75f0f17fe0443b5b130c1aabe9f60e538e6193a19690368a2c17516d7febc3df95ded8445ecc260ba46156c88b5218e582fee9ebc4f28cc4171936f7c5bef008d7ad76a70be3cd3f0701791702a237160798223eefbfeed7bc108e9c793cc42f93381bb9d5f97103499bda63610303a55088fef10fee330c4f35d0a4d0f36c1ca06cd08496db0d06553bd612848212539de0d698a530dc287f2fbaddedbaaef0195e050e3968850fe8e1c72f8e3f11f24bcac475593aa28ab2cc69c3fe6f3ed03a38d8b278fd678697a3f6dfed6cd52afa4e9947ca56d1cdf10ecef90ba6ef87d9c2765f2777c1432325c464c685557129808ce3b91310c301547b673d498a41058334562074a3bd3c64fc8b02bee8ea642b12783ed71e990ca90b95b7020d5458ffac57bd93f882f3eadd4707c98591caa667bb0daee9880c3549fe9ddf7c9314387a85d308516c64ff98cce50e253cdc710927dda784deec547c4442a0818045696f4d4ba4e0d729d13"
+            },
+            Test {
+                input: "bebd4f1a84fc8b15e4452a54bd02d69e304b7f32616aadd90537937106ae4e28de9d8aab02d19bc3e2fde1d651559e296453e4dba94370a14dbbb2d1d4e2022302ee90e208321efcd8528ad89e46dc839ea9df618ea8394a6bff308e7726bae0c19bcd4be52da6258e2ef4e96aa21244429f49ef5cb486d7ff35cac1bacb7e95711944bccb2ab34700d42d1eb38b5d536b947348a458ede3dc6bd6ec547b1b0cae5b257be36a7124e1060c170ffa",
+                output_str: "0e479e6c1c78b597de67ff30f0be1d251dc86ff0ab0f4d5c6f64bdefdcd6a77daf29b772fcab3eed9344d32bc3ed616c10f69cf4ab3b34709f3941f3951fca1a173ca2cd707fa41b8e458634377596865bef5cc8a3cf52c0ecda7ccc0dfd8aa8ce0cd7cc1917a7bb9a3bc9084afe456e5dc02569b3fa4d9b9da03b8e4b223f7cf033c1a8bbd6002b3a457c0de35a222a30a0e86f3ef9c9f255d449ce4ef5afb51577391574f8271e07ea98820e0308ee56b1eea91b35058030ab6afde356cc83d526bdae2e55b1ad4e4d8016fef14247bc7d95c34f06dab7d9ffd1a9fef761ae01f8dee1d4675172c1f0ca15361cba994ef062596bb767c52a275792f48b191b1078968c1793a9d274166db592267e1822585fcb1a9734d4b503f5e1cb0754a7d9f47359cc91e0646c4a2e754a29584363ed4c8c806797fd102d6220de1814e665409104d32be7a346d3b126fcd51f55e5625a6bcaab74f0e69ba1f75a4d5c4625e2f5ae124cec4ea6a702858a3b03cbcb0b014d3d841cd7a87d02c622f96aaf3aad96a62939602a2aa1f9d88dc555038560217baab657ee87367e05345e1612532f9b6d83043db59837e1f75d82b8149b93f1105be13bf51e20f18cecd5df87067a0716d3f860de8c998a487c8a197149e7c8af4b414217b8579c314f698fd6a3b612b2dd67ff6e3471856fd9f66799fcee14627293ea94d1c32d915cb81c5c"
+            },
+            Test {
+                input: "5aca56a03a13784bdc3289d9364f79e2a85c12276b49b92db0adaa4f206d5028f213f678c3510e111f9dc4c1c1f8b6acb17a6413aa227607c515c62a733817ba5e762cc6748e7e0d6872c984d723c9bb3b117eb8963185300a80bfa65cde495d70a46c44858605fccbed086c2b45cef963d33294dbe9706b13af22f1b7c4cd5a001cfec251fba18e722c6e1c4b1166918b4f6f48a98b64b3c07fc86a6b17a6d0480ab79d4e6415b520f1c484d675b1",
+                output_str: "0a5995025c3dd9437884196ff09c0b92b5b0b51b59d0c3c9041ab172a1685ddcb3b0324186f11e2d7dcb6851f888ade68052497bd16c4f1d98dc468d833e4afdd2a9e3dadcfd188c9b1e35ba9fb9549f88c8c7c74352a7b420c1019d2e7cdf02601e5609635ead96cc57fe29a5ad98b2fff301b3640ba441cbbed877477c0dc1d6143454456c0efea8c4038281e97c02774a7ed709a446941a2819f3372e18bc1a6c119eb24cd16a623cbf91816cf2921d2fc65deac91f3e0ef24f97ca518d167f295454af8208ab25540228a9ab1bfd0ed0c8d09ae579b7116389b9baa6ee388612f323d1e1627d1667f4e524c562b0993a807baa0e81d02241049a4c0bc8ec95701e9cb045a91c4340d8c3067686347867d4fd94d48c566672da8c89468d71b488f7d5e1409b3f1aa17b019c57d5a94c0153a887ea366253dad36e9ecbb20de67e5f09f4516daf93761700bb4e094b88ed56cf935f9d0e5454d2168fe5f5ce0682838386ad55b4c664526b48138ec270be30135ed84a63fe04cfb99dbce6b70cbdb32110f954491044970d3aafb62b5123f2b43f3b8275cd2d1034068864a94a1b63532f31d2e65b9c197e13199f86638808d17dc9e3d914ac6e078cde60a1ef9db9f94e56c29f385418aab5f5d5cc324f0b1e2b9f9cc9259971fc57a2bd18686045e04a3a74c3606b8ede2e2e49e2b3f01ceb4b4516e695388ae331cec186"
+            },
+            Test {
+                input: "a5aad0e4646a32c85cfcac73f02fc5300f1982fabb2f2179e28303e447854094cdfc854310e5c0f60993ceff54d84d6b46323d930adb07c17599b35b505f09e784bca5985e0172257797fb53649e2e9723efd16865c31b5c3d5113b58bb0bfc8920fabdda086d7537e66d709d050bd14d0c960873f156fad5b3d3840cdfcdc9be6af519db262a27f40896ab25cc39f96984d650611c0d5a3080d5b3a1bf186abd42956588b3b58cd948970d298776060",
+                output_str: "9ff0e63d6e1bd2c9b671298ef08fb86024eecf3a41662d465d8011e44c55e4312a2f4680a92984471b885fd730a3c3aaa6329ccc06e9684350543475d8cfe2f18079dafab03b9aa1368aafd265c5ed3d0d160ef317bf5ca211642f7c86d4c59504c8e6d8ef5d52c7770659c91ae1121eabce4318d58f2644df56d18909ec977d75d27d25d291ec706a39a3eb13e49691f6c3188c300b827e3ad1f6f8088318da476d07666ae4192c08d4ab797e53445239cea485704f0266c49acd7ed67d24da7333af799b40b301aad8883703f03869628f8f1513629ff0888656782c23d43d435962a022bd19fd7e4af8be40cf34abdb1d0dbac698079312cdfd5b01d166e6933de574914a62472c5b2954740a5a26217e9a67329cf47205701d8baf5e660e231e16bb87efdfcca4e982f44cad53b2893a83dfe251ace8c49b225c3e929221d4fbe452cbbee2f6e59f7868f876e20af55f8b1dcb4ad5cce9f0b8966d51128d08698ad8fb267d3164023985f5f5e48a237f4b638437e074fa4cf83030da5846e64e03a23ed2ee12ee42646d1075b8f91b861d6daa8bbdb07fbd56ac72fe8675031c1cd0622affdfc9227f4dcbb642146f87d2930b859181cf5ad7d6afcc87bb905ad387ac8b8a7da70ce626cbe3e13e115572780d38dce4f3aa6a95641842109b9750ad3fb5f711e1f1363119bea84b4589d0b7287bb4cd094564db63251cfd"
+            },
+            Test {
+                input: "06cbbe67e94a978203ead6c057a1a5b098478b4b4cbef5a97e93c8e42f5572713575fc2a884531d7622f8f879387a859a80f10ef02708cd8f7413ab385afc357678b9578c0ebf641ef076a1a30f1f75379e9dcb2a885bdd295905ee80c0168a62a9597d10cf12dd2d8cee46645c7e5a141f6e0e23aa482abe5661c16e69ef1e28371e2e236c359ba4e92c25626a7b7ff13f6ea4ae906e1cfe163e91719b1f750a96cbde5fbc953d9e576cd216afc90323a",
+                output_str: "9ec7d516bb276ee7be68912e86fcd71ee08ea4bcb5a44b9520e84f7433811160e5a742bf8e444329f4fbe22d72f002f82459dd538d7c26401399b8882463cbcbf2457a7080f8ecc02a05f357baf6bf8de31984abbff66ad082cb995a180d7455bdfbafaa83b74cd95488cd8f5cfce16ebb2d9f08e54ba341345648d0fc557002487fe6f0d0418858698caa9fd4171ccf3880fc0a9e751bfb566ba907e13bb78a19e7d0cc543f9b7303c74bd957149bc505530b246a8d41638023b83b84beec79a91cd21d3982b7e57582780c92be8ca813218b287c280a42e73deb3a84f1027010f79ea2ce9d4ee57de696dd1d4a13f099e4e1cf4bc7cceae2c7a454775628d09fdcdc55c6b38f545566682d3546a6f6aa8b57d44edc36b0c4b9c1b92cc2465b6bc7091eb78ca0030db7d7e31805ab459040494df1120307a2de8315c3ce802491ebb0ff3f83fcf2f99d9f569d3e3f32f0caf2d7d6057ffb6183d274919b9d4b4cbeb125c9002a816a83941abb5120ad9af40a76398d31b07e464482faac767bfec63cc221db2a54860bed4d5e9405821cb176b47838249c689ff1d9990cb3cec4ef1a0d9280f35e8f23246537313b77f26d517221f0a21e7e6d4d28d88632b44d7f1c381f8e7442a71c0b0473f7bc702326364489a943b6a0cd0a8b868f21d7f26a1aa3b8c7a4c7ceb574fc2b266cd8067d83a53ad469dffca9088ece439207"
+            },
+            Test {
+                input: "f1c528cf7739874707d4d8ad5b98f7c77169de0b57188df233b2dc8a5b31eda5db4291dd9f68e6bad37b8d7f6c9c0044b3bf74bbc3d7d1798e138709b0d75e7c593d3cccdc1b20c7174b4e692add820ace262d45ccfae2077e878796347168060a162ecca8c38c1a88350bd63bb539134f700fd4addd5959e255337daa06bc86358fabcbefdfb5bc889783d843c08aadc6c4f6c36f65f156e851c9a0f917e4a367b5ad93d874812a1de6a7b93cd53ad97232",
+                output_str: "045e2bef203b8e72121fc29e68f01176b8ad2e0f24352fe555c9f0b70ffb38aafddae1b2fa04c3bc2dabaf4bf3bacdf7658a623446fd6840536572eff9393f5ab66c080a68d2341af34aa2a13b6eb57d8dc6caaccabaea593970b4d91a3b861aee0b6e53f3263da68ddf75cde76e5bd94afb4ac78abed89788ba89804d6f1997684cffed40b3761a782e3ec1f1a1ff12f8151e91a935a088d2aa2311c43fd731cef31503c775781ef5724508b910976dd89ecbfe79b17f1813b01b82b6dcceaadd6615cfb8d2eea27ec7377f8911a39e9a15e622f3a91f88333811cda86007e57ee652797bf9177c898cd8951b8c123b8188bdb2e60d32493f4e94c34b9ff3a00893795ae0028061050e9c03a53ac787787a332dd4c75fecc1b7ac1e6da30e69a46dc94c87368c2150eeb3717582d5e5851bb5695ccb416e4d8462f0448e0d711b42f1b6fa0dbad40e96c6b69e67bb1907b460dc319b8f01591867c73655f8a28f594ea2458e163ef0d562b36580aabc8e9fcce61d09cd83bc4dec826c8f7dbd76028588bc905777ab6b5a5dbe81665971b23c94dbae8b513afd7df0b6c83469acd22cbef596359ba0203c6f320983a55274812b49e7663a6f48b420748ab10062ebca4dce4440d1ef9b72bf4e121b76075d209eb82de30c074cfff86cc28e464a6959691c66db995c279bf50ce2abecb94cbc850a33315e4ecf650ffc271dad"
+            },
+            Test {
+                input: "9d9f3a7ecd51b41f6572fd0d0881e30390dfb780991dae7db3b47619134718e6f987810e542619dfaa7b505c76b7350c6432d8bf1cfebdf1069b90a35f0d04cbdf130b0dfc7875f4a4e62cdb8e525aadd7ce842520a482ac18f09442d78305fe85a74e39e760a4837482ed2f437dd13b2ec1042afcf9decdc3e877e50ff4106ad10a525230d11920324a81094da31deab6476aa42f20c84843cfc1c58545ee80352bdd3740dd6a16792ae2d86f11641bb717c2",
+                output_str: "7fd29d970989b8f0dad5286cd8ce7f5e793b80ef8f62506f75a119fb3acb39d726cdbe6f4914f8a5930d30a0ac1e36e285aed490cd30fe63a2713ab0dd473a7a764a19a70bbd9ad5bcb2b2a0ad63a84fad80466d1c9f513d4336e3d6c7f93645c3fa30ac5a54b46205322265d3edbe4c8c58b5d8aea1856d2fa81c81e12f27eade6958f014ed3fa3c844a65321eaf484a2e7543d362627f2cbc4a83415fa3ca616b9cd7ea8cd1724f426c0161ae41ce8175f0598fe4aae91a3f12d6c8659b063ff5c64fed548c206329f0c5da4aefbad704d16a1b67a38d807e64f03a3a9dae4b464c78462b842b0dae0036eb466ac7cbda234f2de626d14764f6f49a8afeb062402cc9dba983268333225a6678d2fd9e506ece66135e6afe7a9dc3a16295f71440ed04e8e391edc134e91c1699f0d31f81fca6105f485566c13a93a2db218dbe8d64f4b2e242462a67fe3a98a785bf276e510ada824e88c5adbd9889ef2857d5347544e431603e717ec7a7d17c98a7c326c0a4a83955c7ee31379b241c2f2abe038b2357d3a9d940d875f2a5634cb47255dc92ff11ab7dac4d675e13134c24ff7b058c2f99c985840287cb3009b6cc3d75aa5e79c29c68dffd9d95e37592b6036a4ceec5e34eec8de7ebca4b80f0e103cf07d46e73734c831c0cc2b6e31c14f304d88d77d433699ffea902058f8f4ed0fc7afbc4874cd6786e6d82a96893a68"
+            },
+            Test {
+                input: "5179888724819fbad3afa927d3577796660e6a81c52d98e9303261d5a4a83232f6f758934d50aa83ff9e20a5926dfebaac49529d006eb923c5ae5048ed544ec471ed7191edf46363383824f915769b3e688094c682b02151e5ee01e510b431c8865aff8b6b6f2f59cb6d129da79e97c6d2b8fa6c6da3f603199d2d1bcab547682a81cd6cf65f6551121391d78bcc23b5bd0e922ec6d8bf97c952e84dd28aef909aba31edb903b28fbfc33b7703cd996215a11238",
+                output_str: "efa2939b59dc8f3527c78e384b1cf12c7e184687a0c3a1fd9ffb9797d72f13df8e199b2916a6ba82fd7a914703687ee707c6f87845442deca59f08e1d5def48bcc43bb1a64744d4dd020c866627ae212e5ff4ef9f63c14d2d1cfbb404e03573f9d110001abd156754ef41a4c48e664e31b5922a27bba26d2b3ac79f57720a4190ae55a5634af6e43cdfb87450ee8cc690749a45367250a44b07e54fc1ca8ec1caccc979751544568f0117aebbe6f5415a35244a9255fb023e7c30b013d6c47de992141929f25b3a43da91cf8853ec88ba42da3b17cf27351785bb16849e6ba680745f0294a85601d5a08cc924bb962cd8b67ee0667af1e118e2e5144169da0fbf03c974ecb202ffc473315185723b57521737cdfbce99ddb81f88d81c71c5f02ac5db801437d46daf31bb9308074a21da98f6899f6280e449c1b55ceb3e04522d038307aabe964b720ab331a172a53ccef174a82f046f42820d11947d1b316edf390c86eabe22408e0008f396a0e7f3d51b9988cd2ffbc49869fe0ec03a338a1a8e0a663246a37dea111de5249196114996102223d628ab70fb7f53b842b60f375dd6779d9426aebaee547662b6962e361009c83cdcef6d8bc6311cc1760e784cb3cf6241257ebe14fd9550ec8316d95508390909bcd23ef9f78cdcb485e4c403671e5f20e7eaf4e0c06344d54e157791fc1b581aac0c4ef947accb642e78cfb"
+            },
+            Test {
+                input: "576ef3520d30b7a4899b8c0d5e359e45c5189add100e43be429a02fb3de5ff4f8fd0e79d9663acca72cd29c94582b19292a557c5b1315297d168fbb54e9e2ecd13809c2b5fce998edc6570545e1499dbe7fb74d47cd7f35823b212b05bf3f5a79caa34224fdd670d335fcb106f5d92c3946f44d3afcbae2e41ac554d8e6759f332b76be89a0324aa12c5482d1ea3ee89ded4936f3e3c080436f539fa137e74c6d3389bdf5a45074c47bc7b20b0948407a66d855e2f",
+                output_str: "97922e827163b8869d9a7654ae4532ea26f9895625152012f147be1e818df802689d96b469c8b0e9010d0423da90ab6eed2c835a01ca4c386c630a22d885b511f12799eacea96d157a4432a320f3ec1cbbb6b8efede3e92d99b1e79389b93af7acb27d7dc97cf88485de6c85400a2dd88aca540b3c921180002847b34a454465d014f4742815ec64f5fbfed6229294ba5ea89211e35327cdbac7ce85565eb8f23c4154afec0dee188e9d854ed56bca174e14fefcd0ed039b8ddac3a3242ceb72d9116482f8b750a126505397ed261d7cdfe88f8e2f4e4a80628d66a7676e28d4e68c3e97a47c3844fb06692e5f4664b8a583a1836ada9aec095d011f12b3ad6688b0039b1b74d016f1bd477c932ddc1944b5f301f4d5690e212e45d26908ba09c52d6ca22098b7a080b0056f0cb891411d0b041cea27030a2f9066aaf58ca5357344dd9aea0b0d80932e98e205ee315312d19413240b2ec4b854c21bc2dc16040718d2509515bd45b6557083677c1882d48f687ea0ea86b05cc3f5e330dd4bcc17e5b4f2cc4f2c64773edf3045fa48c53081929ecf31e84a905586d3afb3120031ff75abd8cdad7cee66386a7a718a90b98ee970864a167fa48bb7a3f78adcc2105e0feb27414b1b6c59c7be5f7509e55d561c32523fc8c1c12628ee642d9a69f7d300b49a5b6551b487655b21fdc690f865196a35f138bb8e69571280fef496"
+            },
+            Test {
+                input: "0df2152fa4f4357c8741529dd77e783925d3d76e95bafa2b542a2c33f3d1d117d159cf473f82310356fee4c90a9e505e70f8f24859656368ba09381fa245eb6c3d763f3093f0c89b972e66b53d59406d9f01aea07f8b3b615cac4ee4d05f542e7d0dab45d67ccccd3a606ccbeb31ea1fa7005ba07176e60dab7d78f6810ef086f42f08e595f0ec217372b98970cc6321576d92ce38f7c397a403bada1548d205c343ac09deca86325373c3b76d9f32028fea8eb32515",
+                output_str: "289c52c39044bce5ce8d320e2ac43ddf8dbb4a5e6698d536e304424cddc251f7b181f58ad4948360972835cfa265e9b658f6f7d4b7bd92d68e75f0da84f47c969c7f12cf5170117b7eeed8b77e3aef06e52adbf8f0ee6ad01de3ec5e726bae631a68f6ff364baa1754d928386496010f0ee59390e041cc0a6eb8f3864087bf7ba5a57a116808bd496632081400b89ccb2a8a8ec795bf07c60951b46815e6ba72db555b9cc03caac4bb8d60bad5ec6c5e48d66f4c5b2d1669115e0f0bc80106ef06d48ba29e2899c0ef4d5c5f4e29cb29c8f578a824cd462a4018e889b67da31a90bc58178d904c43296e4d3f4977f0cc1009fe51f37b2f8979c97dacc92c8d0e0fc45a004928f96260fe2a6f27da15307af55effbac4814c9f4446253064897fa1e1747fe65e4c406a3879f8e2ebe5cfde3765f2d7a2065a6e0d38b6b6a5f9fc3ec3cb1b35d33386ea75edce250d5917a17a6cb9d1517684472fcdf27d61bd03f4bb43c3a6359286e73b67d1a618a75efc9ae2212bb507dd1bcb12d0b11fe2030bac84dec40d04324c8354c3f3c6ed79d7257b8a189c565a41f72ae3585a9bd91c9fd43184814bd64f7303607cd02b6613be736bd13b3aa8c668f91f398a8f5aa6bf8ef4d9058637faa3f0f0710ed60c2fa0f6dce8ef0675efa719eb03fea27abde60c5b381ef4026fcef49ac245483da8b9b50dadcc310cd15c61e7a0aeaa6f"
+            },
+            Test {
+                input: "3e15350d87d6ebb5c8ad99d42515cfe17980933c7a8f6b8bbbf0a63728cefaad2052623c0bd5931839112a48633fb3c2004e0749c87a41b26a8b48945539d1ff41a4b269462fd199bfecd45374756f55a9116e92093ac99451aefb2af9fd32d6d7f5fbc7f7a540d5097c096ebc3b3a721541de073a1cc02f7fb0fb1b9327fb0b1218ca49c9487ab5396622a13ae546c97abdef6b56380dda7012a8384091b6656d0ab272d363cea78163ff765cdd13ab1738b940d16cae",
+                output_str: "03e492e2e4c353a74245745981aee10cb10ecd72015fc37621d2e07411aab55daaeae78ec376cb20f268fe40392876a29b4163c3f1732fb58fbe26379f88c4388513c9e65dfb7a4b76dba139b28673ea6691096ec526de0084fbc516360b07adc853a690264ec8c6e7f200d71b593faae6723c0a08b7cac263d7f7dc5376b51a2c7c640359721fa93a950a7a1f07f366b0fcd5c79471ee237d11936b763840173710fb8cfe41da287f61d13fbb174b451f30da1a1fb0f02c2b34689a725b1f86a96247e6f48897e524e84d91bcc9f08deaf189efa84af2a32da7480ada982e579a832fc3cb1fed55e8d0d4aa710ea5b0b779cf0667ecbe9f5827fd0adf6fa6d98defdc0a3f3e84d5ae28d676ce703e1f060e4bae4c0d931f84a76c2777d71b02f0dfd3dd00604c6ebb32642a9ebe9d34601fb78ae60145e32b6ad2a362bff609cb2efcdc66781b5ae2976f0249fda97dcc06a8f7cebdb32a2849b61142a7e55cd15ff51a821d233b3c35d9f69d47abb6d2b55169aea211a67475fd48d39b6863ef6e4adae89530b0a84f6d6aa9b0475289c084ae2e6078785289e03c6440dbee352b9d39d11c9300730e4d224fe008696b8f27f6a9261c30c577b48401b2e90ed5830bd38c13416d19f9b6ec96f235f7a0571961f18c0f3a977740e9f5cc9ce62f695f9a9f797a33a2fb247a62bc635449e4ffeb2f24298bdb152e7772260f9e"
+            },
+            Test {
+                input: "c38d6b0b757cb552be40940ece0009ef3b0b59307c1451686f1a22702922800d58bce7a636c1727ee547c01b214779e898fc0e560f8ae7f61bef4d75eaa696b921fd6b735d171535e9edd267c192b99880c87997711002009095d8a7a437e258104a41a505e5ef71e5613ddd2008195f0c574e6ba3fe40099cfa116e5f1a2fa8a6da04badcb4e2d5d0de31fdc4800891c45781a0aac7c907b56d631fca5ce8b2cde620d11d1777ed9fa603541de794ddc5758fcd5fad78c0",
+                output_str: "6c937d60095b762b69a69116dde17251b6fc76117d2173e0702408bfd8a215a057f25d720fab9410bf39ec033d68cc87572c7fc8b3c920c720c0a34ff468711f32753e8e6813d9d8abc30ac3a5ea3f6509a22e01a389399fa09052465316be70501b70cebc21b5ce57fd935f7a265fb101232e95289e4234b43ac0bb45bfb8a29489e7c3410f4a64028ca7bdeb97b327193a30fcc54f1a9835e5bf497e0bbde269e3f01bad497ac3e09425b7e4d5d5a345b9cdc256683c3d73722b6b33f525dfdf21106574ed3a1b38990c0a18aeaa51621c6d603d58aae2b1d89f57e802e66f8a7122bf4c4c1df38ff9b147bbd4d084e119298c9c4af1bc6390aac20bd1db5e68eaa7361601a40119a51ef26e2328f6cd52874e6f24b3460a7d531dbc5de94b0d62c35c6f56d4e8984b20be06a248e597543e29c314d67db0b112e158321e6bc9494e14c9e33705e678af9a6dc44bb567146e6d03ae590cf76c76398a4d5bfb9f0f12cb707ec79bb52b5488dbcf1a19623c9777f30f153c3e71e5f9a4841e1f53e88421947903c9dbb58cdf75cad297755b704e6919f25ebf43520cef6d71fd41aad277aab2bbc86b997b6a35c4c1a8b8c04e6c7741e88ce198a650841997287e53cf24a2fd939f1aef79ac90dc787789ae0b344b658bf493f6da6ef59112ef76fd39a8e0cf7973e002fc7ac455cc4fd98c0030c7c76178d1edd1ab12e3493e"
+            },
+            Test {
+                input: "8d2de3f0b37a6385c90739805b170057f091cd0c7a0bc951540f26a5a75b3e694631bb64c7635eed316f51318e9d8de13c70a2aba04a14836855f35e480528b776d0a1e8a23b547c8b8d6a0d09b241d3be9377160cca4e6793d00a515dc2992cb7fc741daca171431da99cce6f7789f129e2ac5cf65b40d703035cd2185bb936c82002daf8cbc27a7a9e554b06196630446a6f0a14ba155ed26d95bd627b7205c072d02b60db0fd7e49ea058c2e0ba202daff0de91e845cf79",
+                output_str: "176c854006ac910006248f1ceffcf0bca14015b7939b0065e59a838f213b9ed46c68a377ac3110dd08ae358d4c3c926d262a4906c196822d2d2031990d1f02b472b635ebd7b48ad7469671ea85683328a949c4b01e9afdd0e780ec10f2a6eecd0524b77e6c9893416eb73c53286cd52dce11550e96b70154f0a06521195b7bf6b260ad67d85fd2d3ba79d96b3c84d2eaf96350342fb33cbf5e4dc12d7f7b6c5aa0f82ae2864a38026b6392deb539637d323c5a246ebb7a87ec7048dfcec1dca98d3239ff560598ac31d0e7229ee0a36bd7500b991badc5f7275bd650de740dae8421e1a723013c9e52af448e21919ec70fcf5d4c5fd888b96676e65b6c52d2353fe5d3d1423a73410234a2ff632cb09e922656fc233be050fbab499d3b0864439f79b56df983cc67fc460b027ad14b8e112f898771545061ddf52652dd14aa034137764dee5f896e3fcca26f70b63b37cd8d8df7106876f4eaecf211875d4a3392e09b8e4219326ba939df7500183c3f039d1586d00bd36fbb97835fc4c73845dab9639a0231c27e3c3815b4478780cd646f1157bbda472577faa829f8b13e2c8da1f7685719f8b979e895996dd05d1bc5f0ed8f8f302e38e44a0f5174fceb3253ee9cea73315a1dd655e9a6bb59a3b67f5f15f41a8e483d8c98733916638d5e8efbea8c5bba2000d2ddf330eaf3db1e9a6072e5bbfdd5fd201f8a13800e7719"
+            },
+            Test {
+                input: "c464bbdad275c50dcd983b65ad1019b9ff85a1e71c807f3204bb2c921dc31fbcd8c5fc45868ae9ef85b6c9b83bba2a5a822201ed68586ec5ec27fb2857a5d1a2d09d09115f22dcc39fe61f5e1ba0ff6e8b4acb4c6da748be7f3f0839739394ff7fa8e39f7f7e84a33c3866875c01bcb1263c9405d91908e9e0b50e7459fabb63d8c6bbb73d8e3483c099b55bc30ff092ff68b6adedfd477d63570c9f5515847f36e24ba0b705557130cec57ebad1d0b31a378e91894ee26e3a04",
+                output_str: "f59ca6abc514df7ee5af9b918a5355cae65addca95c80866ede16594f5147ded549bb9187e4f51535d3eefc20f59703e1ef74b86adc45f8de3265207b5a3b4223c3b70e9a9b24f08c2b1f15f858763381c89f2ab14aec657e7e4ccadb9eae9348b26450e9cabf9b54a56893796b2d4c04aa2b3b741d6f85e9a8cb6fbb0dd91ffb91e9b179d5692f9c689c4315ace33c2e7934d49183a5305b8f50051242d73a225c557d787bac8894d5987c8b4c91502c295fdebb492285561286262da7a78a87f068e07b4cbf82344e6fba3c8b70a7cae9023bb004c18a446df8432c895a531dcaab8d910c5623651a362c4e2034a314f00154a421da604cbaab56b40f9f3242e8f61cc9a9ab4c91304588af9805180c8adbfcd727c20d38f2dfdc24cc1a84ffff83cde8f94359ac5d1848d3385b419eafaf09ef0317f99409f732ebaf75a7fcc74a4f0b7d038626078c8a775b1ee75591c6cf99ee2754eeeea7dc9fb382f25f55d030293d53ed2f9d9ddaecb41172387fb19731639b37e3a26af58b033e850880ffca4ebacb945f7d445983042fd3ebf4f70dc2bf0e95a7ca9da3c8f094bc937568a03486ebc127abf44d150ac6dc0b7080a41884102172d6e6b6d819ab088ca55287d6912018b5d7f4c0c2a6973e532b40f9d0402c1525b2e7e11a948a5c833efd7788b3cda4501dd7884aeacd53b503313500c3d4adaffffc69a2eaaeedc"
+            },
+            Test {
+                input: "8b8d68bb8a75732fe272815a68a1c9c5aa31b41dedc8493e76525d1d013d33cebd9e21a5bb95db2616976a8c07fcf411f5f6bc6f7e0b57aca78cc2790a6f9b898858ac9c79b165ff24e66677531e39f572be5d81eb3264524181115f32780257bfb9aeec6af12af28e587cac068a1a2953b59ad680f4c245b2e3ec36f59940d37e1d3db38e13edb29b5c0f404f6ff87f80fc8be7a225ff22fbb9c8b6b1d7330c57840d24bc75b06b80d30dad6806544d510af6c4785e823ac3e0b8",
+                output_str: "a8c3dd2cb2c0b8cd01c2550a1c20308b3a4280aaf80447484dcdfc69b5c2c2fba310272e606d1cfb61d078e2d860f1a056a3e086af9d7485611d64d1ce5f850b91920e778010a23390033dc15e372af077611c9b5a945981cd27801c9b701d892143da0f882c5d8f7f06b72b7107fbd22a4d890d1b00857fde7e9b188088ccc9a67bc12b0a496f3fac72789e7e52ed7cbf36bc7b846f0b4d3a221a8297a4be76a1658a1547b32f534fd13c466bf1803c1300593f8c53cb5530632dabc03acb369d7e87cdd61ea7db6d5980c68f00ad5d28f50b5b499a373dae132811c5dafbbedca231e74610271bcd0e733a59d5ed6a6ee77ab4ee0d64cb00ac7ec586ad30f1f3bf5066268519209a9ee408b0dbb1e6e7cafb63bca7742a5a7c78d7933b30cdce0f8b502e3666fba0c2caab6cb0826641a74c02e5f9df0616c001273487487c2eb693e8818a281cb58d10e0f911fa8eda5def3cea2136197e79a17f58e56c4262f3bddd87d9bd40aa21762c43f7091659693d2bf5d8bc03632ead0c680b6ebe53eadfed63727143fe47684188ada6391efedb6a59770da406b00905c124680b3b23d54c0255967c3ba8722ddf064f10f3253972c0a4ff5b1ba17f8b9247e2d81fa1e4f7e3bd064e71a3f4f18858d040027b45cbfbae7cc6f04c125b867ccf3513c40f008c2c961020b597f864bff2347b8ecdcbf4ae460b1915a5a5eb98ad31"
+            },
+            Test {
+                input: "6b018710446f368e7421f1bc0ccf562d9c1843846bc8d98d1c9bf7d9d6fcb48bfc3bf83b36d44c4fa93430af75cd190bde36a7f92f867f58a803900df8018150384d85d82132f123006ac2aeba58e02a037fe6afbd65eca7c44977dd3dc74f48b6e7a1bfd5cc4dcf24e4d52e92bd4455848e4928b0eac8b7476fe3cc03e862aa4dff4470dbfed6de48e410f25096487ecfc32a27277f3f5023b2725ade461b1355889554a8836c9cf53bd767f5737d55184eea1ab3f53edd0976c485",
+                output_str: "066f28311feed21d06d61eef566deec1f88e8d99da9f6ae33e50321fbf7c1c458db1e0c85c2685e806c583336f5620f44ff35596a725d37b1a7f149b30eee6edf2c46ee8f7ff1b51d5abbc09ead9aef74188fba0efeb82df86c304bf505fb02ff05b1797a7eb3549eb9e74bf685b15fe615bc7fab569a2e8eac5136f97e39397e091f97d7c11d8e6b6390961c0a1a08d2a75d00cb679c870879c24a4ad0fb4eef187e60297668634f06b7f2d98b85cdceec842db321cc7b7823d8f332ff5ab7c44d9f862b61d3423aca663929eea2b47c9c78f890d50a4fd04079d4f77a9b303fbca8a852d5cbe0b09df7dcd2178c8450370f60ce76afeccfd3b4b346c79631439d879109357fab4ade37832d42d70b6390176fd864251fc65b695db788f535b76077e3f69b1b2bb2bd26bbc0d1273109f71199a58053a8ab6d33c9a75b8c7d4423a330d03c5bf6a2b2ce43f27536aac58d9d7ca8397bae7c6c96d7279c19ace6f7487412c7370992fafce97342e145795d7cd22f2135d627f5bd528fa3511b3efcaa28ada12b8f229bb594e802615a213d21cfda091b736daa0b18d9e77e9ad98441f23926f6c06deca62bb91f6430352e857aa1488b82820f3624be30e7abd2785e8e9d6a3cba0a926ae425253e1417ad70f80c1cfe49c730e1b287ef47fe65255aaef1408c66f622cd1b6484fec1675f1a74afcc349ef4746b4468dabf577"
+            },
+            Test {
+                input: "c9534a24714bd4be37c88a3da1082eda7cabd154c309d7bd670dccd95aa535594463058a29f79031d6ecaa9f675d1211e9359be82669a79c855ea8d89dd38c2c761ddd0ec0ce9e97597432e9a1beae062cdd71edfdfd464119be9e69d18a7a7fd7ce0e2106f0c8b0abf4715e2ca48ef9f454dc203c96656653b727083513f8efb86e49c513bb758b3b052fe21f1c05bb33c37129d6cc81f1aef6adc45b0e8827a830fe545cf57d0955802c117d23ccb55ea28f95c0d8c2f9c5a242b33f",
+                output_str: "dc2a3560c3644c4ed659240cc9b275b7163f5c88b28839fa74fca4a055b265e8e8de186ec35097511d12f125b9edac4665efe2e41defffd4feca65386d9a5b06dde6b1ad1f70772ecc871c44529d413c603d7d8bf2cfddc72c11d3b9684cdf4696ebee1a88f939a997802aee46bbe7abe0915c4df68c43eb06a1412c690edef8fd21f94d16ec47d42168c30b8a3c2a87e348352200040cec7697835dd66a8e0596db943acd2ba8424a7d031c5ad0322c913aa9b11c4c1e09accf8b941fda2ceffac3f38bd43feb3e67d002e8d45d9c091d287a5f6c4b70a58129867c46ff1e98d402202c27e088da5063157e0be4a7c82638eb623947a59d15b1fbc965a73449711feeef521b61c4f94b7afb015185bc7c696200f10c2657e233f643c0b20a72ee57e7e17ec806b0b4a128f9f0f6baf129ccd82b19fcc72f62fa10456cbe37317bde49ba0ee9fd83559e32204387cbb5d26064127448d2f2702cb37c3ca5b49989c7b903854907e1a748fd9e589a01eeda6fb374178ce57c6027334399a7896c91fba3f8c2ec917f2fde3942d60fd37befda64909a34f5d8bdeeec6dedad93894e9c6a894637b8193895973c5dd8424326b592723c06583f683281aa90c3fb3a754ac8aef614dc30dc608ad26eaab42b4899137f4d42e4142f93706f88c8c98bb6b15e0992834785a27ffcc9fc2037a3a3b4b3c262ade59e3a6718c79a8c0c82"
+            },
+            Test {
+                input: "07906c87297b867abf4576e9f3cc7f82f22b154afcbf293b9319f1b0584da6a40c27b32e0b1b7f412c4f1b82480e70a9235b12ec27090a5a33175a2bb28d8adc475cefe33f7803f8ce27967217381f02e67a3b4f84a71f1c5228e0c2ad971373f6f672624fcea8d1a9f85170fad30fa0bbd25035c3b41a6175d467998bd1215f6f3866f53847f9cf68ef3e2fbb54bc994de2302b829c5eea68ec441fcbafd7d16ae4fe9fff98bf00e5bc2ad54dd91ff9fda4dd77b6c754a91955d1fbaad0",
+                output_str: "5d5ae597772925f37c5d78176e15392bd53fb65b2925bf589ddf97d92ee412f2847ace1b5a4a22515c910a0a7479ad4cff5948c4a736ef021f062850383ea778389bf5f33c5357ce1d11d11de27bdd076720692737e5887b0fc6b8fa46f2675650072848e26d94d596b921280649389a9c1621037ae9d91d460bda8febda7627c181f8ebb77f43de66f9d64ef1d7cb66622e13faceebc7ab346c0c71a1faa0df2659d980ae4acf04317379b81dbf8e9206f667ebcd2a8d736766d2fc64ea442a4ba0e331e7d3ec0ab1618bd90a9b97a4ab6556eb09da3c551ac3f2714be4cb094ac454f0debd1964ecf15118f677464c60108a87e8895046269db21168e35ec4dff11487e93b49a8faee8ee6c3ff05394d1d0c9030123cbfb9576c9015c30f9da04331c995101f4589d27ce664d2d6928c803ee6ed655b661f286f12499427b0b3d4c19a870cc6065528d0d482fae121766275acd12731b127c454d17bbd32f779bdfd59d2221cc923764a023d48a109f259c2c4d9213e35411a7e4f03c1878e576f9af4b84a983f64ed1255ee7ca9a4696762701950c97f374f207acf4023c0e42651c650c330eba2a7773af833a9a7b1c9360bec7fd788db63af83b699e1bac014a86ae976f15809e4dfc8eb8225de57c97cccd0683ed0beb67b752a6bd5ef128d9bc6ad343b04aeae8c76d7a24e3025d436ecd9f03432991a19d1b1642af5"
+            },
+            Test {
+                input: "588e94b9054abc2189df69b8ba34341b77cdd528e7860e5defcaa79b0c9a452ad4b82aa306be84536eb7cedcbe058d7b84a6aef826b028b8a0271b69ac3605a9635ea9f5ea0aa700f3eb7835bc54611b922964300c953efe7491e3677c2cebe0822e956cd16433b02c68c4a23252c3f9e151a416b4963257b783e038f6b4d5c9f110f871652c7a649a7bcedcbccc6f2d0725bb903cc196ba76c76aa9f10a190b1d1168993baa9ffc96a1655216773458bec72b0e39c9f2c121378feab4e76a",
+                output_str: "b34e968bdd16e68c71ed69202a38c554f8362fa382f1deccf89536b0d2ffa7cf8725cec1d2d7af57665496b643e8206566f8cbe4cbc42db65481750319bbf37d9def13d050b2dac53e163ac365e81aae03bdb40b67d0786edefc2b339fee7176dedc90c92b16a726e61a3e4ab5b29741869a4e8ff254d335c62053ee9fcb5bad309b11b916ede9ba5d1594b0abbcf73a7a231b4104037d10c32433f99dc35a356088f90298bb9bd150fc8252017becf06111daeeac705bccf25e8098995a8f7efcbb10fd2c443223325fac9172be8b5fef5fbccc8d9361deb61b361fbea3d5cf13f4731e8ad4f567bbef2655a79213193131020123e5fadc2782e8224208eb98c736fa9af25ea3d00cafda04eb8f0544b58b29da5d438a96914ca1d47f2a729128f60e56f5634a73133c1a0435a40fb7ff6f88105ba307b4b6479d0dcbb80a5f1a71954ee049e99b944e41ee89de4b78a78786660a1516a3bf64779df724bd82045245413cd82890340d29d07879c000934fbe4b4feda2eb4cd795c528e83ba11a92c9476e3273dd5d4553798489b8ffe76104ef154fece05e4be9775256f278deb61552266745fc21dfd699db5a34f4dae4fb3e23146db6767561f15ea776b67240c92c695ec83ee10978fcdab7a57c692861f15e5e6ae0e3dc2c58489445def81f884a50df8e78ce67c23967b27b419f36b905dc2d9ef1d27bfc94b456836a"
+            },
+            Test {
+                input: "08959a7e4baae874928813364071194e2939772f20db7c3157078987c557c2a6d5abe68d520eef3dc491692e1e21bcd880adebf63bb4213b50897fa005256ed41b5690f78f52855c8d9168a4b666fce2da2b456d7a7e7c17ab5f2fb1ee90b79e698712e963715983fd07641ae4b4e9dc73203fac1ae11fa1f8c7941fcc82eab247addb56e2638447e9d609e610b60ce086656aaebf1da3c8a231d7d94e2fd0afe46b391ff14a72eaeb3f44ad4df85866def43d4781a0b3578bc996c87970b132",
+                output_str: "2d48caa033f0273cee712401a35d143c7e91216139682a77ca775f08ba77620dd02ea885667355740363d95da3cefd3e9f8d0575a41213c1e7f2a6c4b7212dd617c9b0a41d48674b6a19c63c1ab3f2ce7f1a0fa694ca8401a0121077f281cd5d6a5424ac1d3a11aa97f88783722e68abdd3684907f63ee045d7f3e10545f33b84c30200de3b135b4be5033b854084e5912f17b14f2ac16d027fd02fcff1ae096c983f0f4fce7d6b641d2280dfb90d8a066d8cf53e2a5a1620dc50008ca375743c416c379fdc5aed3de23244de23aadc33bfd9609702da4776881a1f588ee1fd98602fb831c8d857cb73da50c99acb34dc79d0f32fabe25fefb54dbd494014a24ec55b4d4ecef9d4b7a98a8bde06e324e6b2bdbe7beee6a45e4fe8948d331561090b737ce14d302c9cb1d7ee3e78d0b7cda6fd12cf038f8b92e35f7bd6e1664a5f4f75ee569f67c41a434330dfc06f8c6c7156208a11bd6708b22f3115e5d4d99f54451d967bb7935fc937ab2ee21c3da93b1a3df94ddd600d6ae8f43a35f85794e3bdabd82d4ecc923b0bc91ea85c3a2599f492495e8aae970e1605fb642b6b93e3947b45d78ed6a563fa9d10cdff934c61d78b46aeb754cffecf00aed06839365d1a4b7d9cc5852a4f755f01723c8e3961c92f320a43ec23d8292c4f44336e78424a4e650d74bc47ec05ea8d692560206b9dc2310c893598370e5df5d93acb6"
+            },
+            Test {
+                input: "cb2a234f45e2ecd5863895a451d389a369aab99cfef0d5c9ffca1e6e63f763b5c14fb9b478313c8e8c0efeb3ac9500cf5fd93791b789e67eac12fd038e2547cc8e0fc9db591f33a1e4907c64a922dda23ec9827310b306098554a4a78f050262db5b545b159e1ff1dca6eb734b872343b842c57eafcfda8405eedbb48ef32e99696d135979235c3a05364e371c2d76f1902f1d83146df9495c0a6c57d7bf9ee77e80f9787aee27be1fe126cdc9ef893a4a7dcbbc367e40fe4e1ee90b42ea25af01",
+                output_str: "6f7549d58e91d97f0c1243c519eb6ad2cd72ae27e3c5da2c6b92407823d1275210ed93b95692880015bbc14e72892a36d4d4924a48dbdd2e774ed36b739f587d200d9a789ff56542061ab4de006b08749c31bac057ddafa581c6f756bc3ff23bbc43c1048bd2848204588c89e6c3199ec38dc9f4bb10bcec5a5d236ab28113e4e43d529de8424f118cb14a5fb02ba721ba4650cffa35663820148e00a2a8c0b8f4c20dbbe20c146e4b5294a17c99c2df7ea62f9107acd5feeb01ecdc064f2911a466bc1024b1afe10f3dd7843bdeb8682339a95f7a0e615a216c89ae7e8a688926884f82bc2a487cb2695c658db670ec286e63afb5b244950497be33081cca0fd14a4958ae4ec94b642e3a9bfeca9481feedcee34b6c13f301cfaf882105c14f20679b5e7e4263c29397f62b094490bde56cbb1cffec550819e0add12da85935af2a9c08537ed3034d39933b80471d98b1562ba12c9b98a462093e79d247bfe4ee59cdf9f6533dae9c2abb66437b90d845b16c5318d0d12ec5ce30aa63b8a754ca93f04a3e3013a197a34dd8af463a7aae48d51c7eeedc45b5bd4f9e5be06d47c7991956e7bd828dee21a4c4a69c3bcbeb914fb93832be8a986a077fc3a990301532cedb59cc03a0efbe5ff88413f0db07481d134b77200e05341c21c43a7fc0ef20f254a4438f9f49c28136eb7ff5d64e8812d4137cb3410b2482d3289acc07"
+            },
+            Test {
+                input: "d16beadf02ab1d4dc6f88b8c4554c51e866df830b89c06e786a5f8757e8909310af51c840efe8d20b35331f4355d80f73295974653ddd620cdde4730fb6c8d0d2dcb2b45d92d4fbdb567c0a3e86bd1a8a795af26fbf29fc6c65941cddb090ff7cd230ac5268ab4606fccba9eded0a2b5d014ee0c34f0b2881ac036e24e151be89eeb6cd9a7a790afccff234d7cb11b99ebf58cd0c589f20bdac4f9f0e28f75e3e04e5b3debce607a496d848d67fa7b49132c71b878fd5557e082a18eca1fbda94d4b",
+                output_str: "2d534dc9501c6b18f9662128e227e3c7d8bc7f6773945b8ca653bf93f9b07bfbad84f195ccfeaf35ffe97e1109212ddaf5701bf2f81a72b51a66fc1590534823172927bc3ea342a96df9b0cf5952690804c37814bad3a41849d71aace71304183a4477d313654c731cb0a9af39cac8a8e4b6883af7c4f94720a5919c2371c1ae472724f7062e47754066976b583cdff98cb41796664c9b0c763c4530fb62dc22ae7b3c6b4db593942f6144da79aac3f3cd53f90b7b634cab679ed27341c83a3f9de8763a0d083c4ea4eb3b8c189967e6970178ce26a3f2d43d1a62e4d26d61636257db145a89eeefb8c38aa9d69f0630b99b4ffaf9395a6aed9c63e78a7f8ceaf4884e4663e7c9e39f737703f5d1c73b2e846fa5af03528c7f1d1378c9ac7ce02599278455fa6e1b7bedf453ecd680a89a8c77fb727a688ac573a5ecb545218f5ddab304dfb7862194514674a52f2f0eb2151bd936974fb5b677f621ff9e92a10c76e3b6a34e4279bf2e395743ec8feee4f4bb1d951af744f9bb923a13c1d6f159f96b90d0371b135a8f64351dc8c9dfc0af38098d3a8583dda8978103b25495bfab2b144e4d82774c06c4ccebe085a5b902dc391b60035f4ea929de8a56db1efecfb928be97c23e6dacc79ef2c05d5c08f2cb3eca5cf7626f13a95f29239ac8f457dce85815ba83f099b1dce79a32c6e04280b8cefe8ec213e2375553d2214d"
+            },
+            Test {
+                input: "8f65f6bc59a85705016e2bae7fe57980de3127e5ab275f573d334f73f8603106ec3553016608ef2dd6e69b24be0b7113bf6a760ba6e9ce1c48f9e186012cf96a1d4849d75df5bb8315387fd78e9e153e76f8ba7ec6c8849810f59fb4bb9b004318210b37f1299526866f44059e017e22e96cbe418699d014c6ea01c9f0038b10299884dbec3199bb05adc94e955a1533219c1115fed0e5f21228b071f40dd57c4240d98d37b73e412fe0fa4703120d7c0c67972ed233e5deb300a22605472fa3a3ba86",
+                output_str: "4d0e55472faeda7e9f092ec4a561e835e261935ba5e6d115e9d4c4021725e7831c5b7f102f2d1494b019ffe9bf5525822c497883f0e5194b0b0989dbdac834cbfcfdd31294dae5752adb56c23d45668f370963219d3a9be504d8e93721242db7d4d1ccd22f84687e3945e2037ba24670649913712fe6b5d99bb6c8492c3b853e481ca9c32b3e601d31c60d6b5f43a240b0711fdfcfc0aac6a6e5f881b2ae1123f7568663d8415db5ecb3000aab268256888dd47c0fbb5c95aaa9450947244ee4cbcfabd76326d2d079c9f1bc4f3d43ae1d01028fc1705f74cd16132c79d3a43539d2a842df2b69243cd37491cdab57ac7e4e00350f8c08737b6ccb8a7c48dd50365a85c07a525c15af65ec3b2ac1c73aa6b3433483d5ec77ed832b73a30c672e9dbf0778dbc20ba5a3513ec93b4165a60e68717aaabed5041d9ee445611ebddc8597fda3ba05245228d7c567be1ce5d2ba75a256361e8259f43f3402e09b96a14014389b8ce19461a6512a4dd7f866e73ed26b1c454e014f901dd313d5e7214ce7a62c476dd28e4152eeee89f309161c8f494f0bee613b72696f496bb41659a3804683729b40682de5d0f17afc0fa9c27b2c96b55a05c536d283957783bb93c8f3e021a30d6051c9839dc48a70c127611449823b06f0dd460ca1dd990aebcf3fca9732d012e9650907bfc44729df2827ae4055fcca246ed3d75dc3b69ddb3666"
+            },
+            Test {
+                input: "84891e52e0d451813210c3fd635b39a03a6b7a7317b221a7abc270dfa946c42669aacbbbdf801e1584f330e28c729847ea14152bd637b3d0f2b38b4bd5bf9c791c58806281103a3eabbaede5e711e539e6a8b2cf297cf351c078b4fa8f7f35cf61bebf8814bf248a01d41e86c5715ea40c63f7375379a7eb1d78f27622fb468ab784aaaba4e534a6dfd1df6fa15511341e725ed2e87f98737ccb7b6a6dfae416477472b046bf1811187d151bfa9f7b2bf9acdb23a3be507cdf14cfdf517d2cb5fb9e4ab6",
+                output_str: "c7eaaae0ca10aa1cb0225920a8f2288eec0e5889abeb096a98310782d918af4cb8c0a41384d8e0c408950eea95de8ca6eb87f5e86780fb91293c5d14a798dad9b77ea8a5b50e17c19ef37acc5166a74a1b37712290cfcf98ae6349dbd4842d8abec6735ecd392d59591824963d403b2804135bd46d17e26d5c498fd7111bf2782f758802a20ae6a169aa65cb0d6640396e982e30126c37f68e19cae5ff9ae3743e38f902d306d8fec8042dd914003f960625e8f2104c369cec0cb8d3847c28d050802eeb53c5af08d70ec02979019700e182b7127661df869807c16f309eb08f376c5c30b0189f1b4b32423be060402c1ec9b1e7af2432fafc09e4eff7dc6f55a52108c5599bbd5a07f433b3eb4d439d43ea79407fa711132ca9a5e2f528e18821f38b894f624ee42400832f8c85aaad0fea54261e2b55647d9ff5f31ac212e7c38cc96689c72a4f543a2567d8ea79913727dac3172f69cb16694e5d4eed7c16494a297c876c73256f6b30f88b6e180e8e62db68458f2ca416c4a0317f70a3e2465bc543fb07ae518b6571664fe9c2e49e2aad57ad933869c04a1cab60903f9ab1c14e4fb3b6502f387b30693ae4a85a172fe6813c42026de57291b3d854a191f553893b3d4a79c84b08c37e80c1abdf03fab58966410c2b8b950a275f68852f006b2b38a49e09165aae5ba74b934a6b7133e431f01099f930b5fad2790f126e"
+            },
+            Test {
+                input: "fdd7a9433a3b4afabd7a3a5e3457e56debf78e84b7a0b0ca0e8c6d53bd0c2dae31b2700c6128334f43981be3b213b1d7a118d59c7e6b6493a86f866a1635c12859cfb9ad17460a77b4522a5c1883c3d6acc86e6162667ec414e9a104aa892053a2b1d72165a855bacd8faf8034a5dd9b716f47a0818c09bb6baf22aa503c06b4ca261f557761989d2afbd88b6a678ad128af68672107d0f1fc73c5ca740459297b3292b281e93bceb761bde7221c3a55708e5ec84472cddcaa84ecf23723cc0991355c6280",
+                output_str: "cf55585ad2cf64217e5ca23319eba00c4ec74b7b9a453d1d7c144e8b68fa8eaa16b853344abc905eec90b35b681fd8a4a52460999bee62489c467151ea5c0d7c8ef2b9959fd44d171d530ad4a576a0c76b147127921817b167fb43050d7f2f552f8e77ed5161ab00907599ab80fc546c859dbdc04f2ca3e38a7593dcd22ec89e73c4924152c7d1b5281699154a3325196e97e73da29251f60bc68706885462002c126517e00d02da6a23b0ca9410eb916c19fec76de9a907447a8dc1f8304eebb6e38d0694821ee03865a5bede036e01ad74ab397afbef6c62c5dc211a47bcdcddecb48b17bf5336ff831db7ef9ce7643b285504d495161d4e864b6fee67d0efad2888c04a8992f019e52a6632f72539fd65271e81537afbe9e7795c658aa0c3b2c64eb34bdd0e5f19ea217b6ec9520fcde446c2207c9aee94a6aaff4f1f39a91927dafdc37bca8173034a54fd535bf03212995975240f3002446da1d111c0f97c92e395d96e120b958f643cb4ec52c6d2c148e6a0a497323565500ab117421c4a0cf0a055dc8b4d287f66fcf7edaf931b614589ef6c6f4684a80a9dbfbaaad85059b9399ce2617b55e04c2112b32a210d7530a3c58678b1d48ef24e2fb6b6f90d4fc605805b903085198b2c50432d9a99454b68aef0c9d0d81931123d7d14c0dcff84a54f3d4dcdc9e232bed26e2ef3334220f7b39efadab2cb9e247ee4e880"
+            },
+            Test {
+                input: "70a40bfbef92277a1aad72f6b79d0177197c4ebd432668cfec05d099accb651062b5dff156c0b27336687a94b26679cfdd9daf7ad204338dd9c4d14114033a5c225bd11f217b5f4732da167ee3f939262d4043fc9cba92303b7b5e96aea12adda64859df4b86e9ee0b58e39091e6b188b408ac94e1294a8911245ee361e60e601eff58d1d37639f3753bec80ebb4efde25817436076623fc65415fe51d1b0280366d12c554d86743f3c3b6572e400361a60726131441ba493a83fbe9afda90f7af1ae717238d",
+                output_str: "85225e389df45458881a78277858d3b12ec5527bee0d03f41efba24671f1c245ef33bc8cecf3cfb7ea82263ef8f5f4e2c0d033d1df6ad35f1ecaeb2e40f22ed9f4cd0d1b9fb1ff5afc3ed60549f1836e325ad6641e4444913a9aeacf36067a7e6eafae4f5d1738f4b42f5185af334feee2838faea6203032f3c5c3d22863c02783d1562e12b0c73df3098cec208bc855bf84a9c231021ad5f1fbbe51a21e2bb66bc555612500822f43db5594d0d60532b726e3a430c26d9e5bccd57f83cd1ce3a5a31ddcc21dfd8a76d03a106fc77eb55edf19a46023b5d70835c865952c463475769067fab2ba2a11fbf7f29d6400d10a34b1db497b5b1d8d8a30a5c4dfc40ebdd1bdc992380074accac904dc24f22547a99e7f5acc53bb83bf94a522e595d9ab54c4e7ee052abf95fc5ff52967ca2fbb927acf7127349ba7fd26ac820c380107b0e341866a9f57852df4ce28c2989f04a40ff14033b3d36ae7d24a8e377aa40babfb8502b0b9b12df9b42c2a9982aa29697a2ed522e344814e59d91132f39aa537a521bb4b781cbcb5e1503354fe6a25072a52c54d248e13f8253fcaf93e849597c23f6952d0f7f38d1a4e7d08fafaef3acbfc4371779c6795d1cac6bf86c34fb227aaef0ab51c480c4510c9f1f463ce311cf931e8219d71bcd3fb55d3a8e9a6c86710d18f9fef6a00d1fb878069ad4a4e32653b0ee15866268d5772bd4990"
+            },
+            Test {
+                input: "74356e449f4bf8644f77b14f4d67cb6bd9c1f5ae357621d5b8147e562b65c66585caf2e491b48529a01a34d226d436959153815380d5689e30b35357cdac6e08d3f2b0e88e200600d62bd9f5eaf488df86a4470ea227006182e44809009868c4c280c43d7d64a5268fa719074960087b3a6abc837882f882c837834535929389a12b2c78187e2ea07ef8b8eef27dc85002c3ae35f1a50bee6a1c48ba7e175f3316670b27983472aa6a61eed0a683a39ee323080620ea44a9f74411ae5ce99030528f9ab49c79f2",
+                output_str: "561a3e8d8d57e0e32d7e9ea8ab6f58aeea509cce8740fe54e8db9aabbb14ad782ba33c7f9a5007796ca2ba9089f525bcf80bcedf4c09e24e8d14f1766aa97a82b807fb1adf65430bbf5f87af0a7ff26578c97ab50148b6b15711311fee962a8b9c3d1abaf62441ceb100df3a8e588dfe3f6a356b348e312ca017c94143b3df17f255dfad5a7341b163c0562d24897fe9e4b99262fe5bf6920b79abbaf856ce38afc756a77f2bfd5c3a039c08480bac81d641f8b955b22b66b455bc0637dd49a1218c4e8ca73bdb68b8849d2148c021c75bf8470d36167ac32fc88128c4e0568724bb2d631e7fedfabb91f0343d267bf3a57bbca57c21d56e339cb13dfa5e56f3a90f0241dbc0d0d73f40ba282abd5e031364abaf427713463ec5072b7aecca62e074097bd0cb3169ddc06243f08b62527921f5fdc9332e99b2e6903d65bf809dca706c5c0f93af85b9bfeea40504a3dbb390c6a417203979687a7c86cfe5ad3f0737da1b907f8f941edf44f8367b65ea8bb92b5285a3ed8e1f7eb0fc00536c15005e4f6d9f2969ad96721bfe7a6a4824a37159ef08b0fc60c68518fd4ce54e4033c41ade6cb218cd7daee76622b711a1609168bc115ad4f6219eafbc492e35bdc446e866433c744650669294e8d1827a2500f3e30893c14820dc24e36b3b451e9459bfdcae62168706228bcd9c3ea22c4f1d0286367c7939df31e28e7a2b28cf"
+            },
+            Test {
+                input: "8c3798e51bc68482d7337d3abb75dc9ffe860714a9ad73551e120059860dde24ab87327222b64cf774415a70f724cdf270de3fe47dda07b61c9ef2a3551f45a5584860248fabde676e1cd75f6355aa3eaeabe3b51dc813d9fb2eaa4f0f1d9f834d7cad9c7c695ae84b329385bc0bef895b9f1edf44a03d4b410cc23a79a6b62e4f346a5e8dd851c2857995ddbf5b2d717aeb847310e1f6a46ac3d26a7f9b44985af656d2b7c9406e8a9e8f47dcb4ef6b83caacf9aefb6118bfcff7e44bef6937ebddc89186839b77",
+                output_str: "3340b37aedd2f0c66f2483abdc66c97b45055275231f1c7a925687b946c9135bb75aab2d11e6463073a1a8ced0ea83a42736ae85d1b99d1d2ee9aafb6fb9f4e7abacb39bc9f6d59883a9d1b0df86c259394a05842684e8a4573f1a3ceb46ece59df77259a0b025b831c2cc0dae259551c86db7de0c434fcbc35328810201903b92802cd5dacf9a6f4adcb05ec5e0629a3fa99bdf2a5cbda2af81cbd1438821a319408d67e5995342bf9bb4da85bdcf43c5a2ead9cb4fa26542eac044dc70857ff1b1cf95026b6464b96a46f3a138fcb26b525e6a09f71ed05e57adf4a3fab611cd8069e016fed7b9f2f14c38102612d66803ef0854b2c7678e870ae7be6ce43edf447e476c0ad407f0d1aeae1265521f43ad6ccf1f2e0c82e5395abfc41e08aab436a806083e246cac452513bf8e9c9e47de645055ae184d988d0d3cc1e5dff6aa98b3eed26e788ea342c6b1914269113248b15d0b79a6bd71eea6c0bf9d89698a2b943ae24f843b00b34620dee9de5ae1fa1e00677d8fd9716cf43ea1ebdbbfc2984fb1b27d444af3b2d01a86412a32090a45385a912f394373f0610af7d3c06d8564fafaad3b88c70196a1dedf247ab515e5fcc8490a889f974e12d8dd5fdddf8de55500cdaf60ff2b70e7d26b481389c2232fdee43ae99b221893fb7cdb688c06486571a09b9a9b5d2dac509ba166d0c5f5d8eac363324234c657678a0cd7"
+            },
+            Test {
+                input: "fa56bf730c4f8395875189c10c4fb251605757a8fecc31f9737e3c2503b02608e6731e85d7a38393c67de516b85304824bfb135e33bf22b3a23b913bf6acd2b7ab85198b8187b2bcd454d5e3318cacb32fd6261c31ae7f6c54ef6a7a2a4c9f3ecb81ce3555d4f0ad466dd4c108a90399d70041997c3b25345a9653f3c9a6711ab1b91d6a9d2216442da2c973cbd685ee7643bfd77327a2f7ae9cb283620a08716dfb462e5c1d65432ca9d56a90e811443cd1ecb8f0de179c9cb48ba4f6fec360c66f252f6e64edc96b",
+                output_str: "fc9c58940908e1f78aa90e888879c9ef903cd450db94e5bee0d8acf6a4e453a32a610c6209d9f5a44ecabd634d45d04f5d946bcd388e2943d00ad8a6c4682d985f45d796abea85f419d3990bbdc5a21294970fd42b6d06363e18ef7c00250e96aa96ff730de2d92e69bd19c2ec40ba78f94b7d120cece0b0a44890cc17529a054edc97c25bf7ab6bc3c955466f656fe450bb25c34997da94258a4473128ddbbf6efba41c1843f69ac2b86a5f13ea652ec19caa10fd0d605b4f31ce170f9ff1d6c7dc064eb4106c6f4f54c88a463ea9b97206e567b370dce4dca5b998831362de38d8dcbc0fe04e87ba9ec6ca571e6a3bdc246d316a55fab5ce8ab0b71e0e8edd9790b26e3482a95c732a304c1dd48a3955ed995ddb86aa7b4e6406d08e189596bc8c5a5f61a2ad336e39d94f6188da5a1e4f2cc9593e92b0d89e12cb4e6fdf89c5c24ed83d66f5ac6bb0a6a3c88b151c35123de2f3d2d18d8d302fb10299f68f65c9ea2e5521aed6cb9ff5e357ddc1b9d4d5bd7b13dc9b4ff63941bec300cc787fa6dd0bc617f5389eb6058d05bfcaa16f08393f4f1dc5fd4226542f49f771e5e93d87e06c4e663acfb2cc365f3f79016356656f92ee52dc6dde14482e2cc8a9eda71189e3c5a431efe0a8768d014f05d45685e472bf22e359b8a6c8429d8f048314bfef49af2637108e774d5e41d6b38fda700fa2145b0235e1dba03bc8dbf3"
+            },
+            Test {
+                input: "b6134f9c3e91dd8000740d009dd806240811d51ab1546a974bcb18d344642baa5cd5903af84d58ec5ba17301d5ec0f10ccd0509cbb3fd3fff9172d193af0f782252fd1338c7244d40e0e42362275b22d01c4c3389f19dd69bdf958ebe28e31a4ffe2b5f18a87831cfb7095f58a87c9fa21db72ba269379b2dc2384b3da953c7925761fed324620acea435e52b424a7723f6a2357374157a34cd8252351c25a1b232826cefe1bd3e70ffc15a31e7c0598219d7f00436294d11891b82497bc78aa5363892a2495df8c1eef",
+                output_str: "f723334037ce684cdebeee3f14b0d109b075ede85c489edf7981b3bf88b946e2851c9453b0e891349080405bc3b16a99879fd63ad7314fb7d26c050061d3a2f971e2a79c4b23338fc92e21466c27beabb1fe045a0a10f33516bd77e7d87c49003f1cc173b61d4abae5151d5a723c2e6571b0b7039fcfda72c149744512d5fa20db8c736a70fc009211fdbe0d7245c5c26dd878ce52da760aa90d45a5501efa74677b85a736b2860876b23424d1cc47660040e919ddee1f67314fd902a1d5c1dc69b70baea890b5691322c81b210ddcaa3caabcc770e68b1bba5b08c3d7676771608924a853fd770b2aedd8d42b1e7ca6cc0499e22646732edaefb94761405b76c3a58d5cdd1439ed1bb06cedec79dcdf38e373ed17798a51b80665c026dc2bba3eeab43cb9024ff6f04b371c07423ce2d0b2e2a800b213d9fe193403fe868180569ebd002591959b8687e09f81c9b2b8de7672d173f8ebd0794acd309a2629ed0aa7e14b58635115a58cead5be08d3105e2e65429d1f7823bd8dab99084e1d63bbc637ee37ad4627e57e15de35ca52fb8407760bd2aed167b6ea65b0c72b9b53c58a16d030a227cd92f19f14ba5ad6bb00a5775e4a091d7844ad2de44cb9d866154127ca1b1a2422483a146c729aeb85e67d597ec6f700c9dc615f2bdfa6a1c9ab038b81ad0307daeeff021ebe7abba47ba002c27c2a07611027fc69c9b63992"
+            },
+            Test {
+                input: "c941cdb9c28ab0a791f2e5c8e8bb52850626aa89205bec3a7e22682313d198b1fa33fc7295381354858758ae6c8ec6fac3245c6e454d16fa2f51c4166fab51df272858f2d603770c40987f64442d487af49cd5c3991ce858ea2a60dab6a65a34414965933973ac2457089e359160b7cdedc42f29e10a91921785f6b7224ee0b349393cdcff6151b50b377d609559923d0984cda6000829b916ab6896693ef6a2199b3c22f7dc5500a15b8258420e314c222bc000bc4e5413e6dd82c993f8330f5c6d1be4bc79f08a1a0a46",
+                output_str: "37a534cc68de78f87b85212464858780e143a5e0dc7d46419eb17e45e1872186df8051353a6af703c167b9233612ed68e9535244dd99a613fb43f277c833588f7a2adf2ead15ada2d6ed7cca6ac786741b7453eed605c7f8ea3a8e2aa8d5688d72edf964c08542422de589d402da18e10e7ecbbd132a10fe382a7ea0a94c9e5c7f31c7bdf018f44bb6693ec64b266e1aef1a3a941e336e479efbe2bc897c93576f5f1bc9c6d4f6e948a14464287d1e82dfdd1e0cf0a68e9ff696b5d5392f4c46845df19ad5bbf2b158659e856bbf6732a9ac0ed722bb5eb2c25d35ff83b892dd30bb01fe20f49a28c52b6f28550fe56d176790ae2d96648c66e389569bc2d47d0a5775e0f6f1b7ab8f999415b3eee8aae8a3b663f13e0ede5c81cd001307ffb5aea2801cafcd1b09d31182220f52d39855e1df732f1cf2671538ae37726b3b47760830b391edbbae70b52f1f2116762c685fb8523742d90a427c991f80db823e349699456610720744bd2e4fb9c40d1371debdc7d01b2f5be45c0231d297de09d66616509bbdb854d84a2d7c140e8489884794d3679ff8e24f7f04cd72058ec305ec21823ab5a47ae9af8d10efdbe2642a97dadd44f174622597e4bd88698fa75f24314e82aca60b42f66f84602c831fb9fa73e95955151f931841f1b9de7c3f95dd786893b45ddf66045aae6533aaa59060b415fe392bc585eb4c39115cc163"
+            },
+            Test {
+                input: "4499efffac4bcea52747efd1e4f20b73e48758be915c88a1ffe5299b0b005837a46b2f20a9cb3c6e64a9e3c564a27c0f1c6ad1960373036ec5bfe1a8fc6a435c2185ed0f114c50e8b3e4c7ed96b06a036819c9463e864a58d6286f785e32a804443a56af0b4df6abc57ed5c2b185ddee8489ea080deeee66aa33c2e6dab36251c402682b6824821f998c32163164298e1fafd31babbcffb594c91888c6219079d907fdb438ed89529d6d96212fd55abe20399dbefd342248507436931cdead496eb6e4a80358acc78647d043",
+                output_str: "60c681e527396d6c9dc1e5fd71842f760f9873621a9bf2b9b98c5df450dc7194379991d7a94397a206913ae1821259d308a5dc4d53e552dbf2287b8694f0b6184b737d5e32e1258cd7ff58e5aa9b5f37571413395b833ccc5620e37b0a64112968d4d7acffa3a66e044c36e23363f1a09eee48eb6713fbacea29ed63af0db94ed2bb22cc01b89d05391c1bc8844be8bf105448925ad2373d46d3417f920046e8e4afa0c11a8057b4a42fa4cafec592f8c2f8f1e2d603612fa38dfc3d3fd768ef7317802342e76e70d30745fbafc0bd007eff874cb32761d700c88e27dbedb57cbfeea688e0f06801847c1046cbf47e2c12ec0a4016d5e8238916da887deab825f965f936c79a7316465b48a2b8bd5889bd04580ff7dc91c50de8eb60af74e74bb4f896ff73cd3d1c55948c19dc0abc841d7bc3384ae4d60bd855f24bd2e402faf5e47d66ddd2f0533f9a73fd483e3965e967c979382f643cda535c4ae3aecbbdaa51cd7a89c8b2d9ebc0b7f9cc1c1ea355f9feccb62345be39a7d1073cba7c5c46f2163dbc1e9a6190ef620d6053b88586e73b18e816206a72f297ef946c8b302a6e3fc92a3e7a9aa87e26c1466251ce1bbd204bba7d08feb28f99cf27bdb3e8479c9c57fab8f00797938d471d53a1666156b66853c067e64695978d2e9ad5250fff6cd1491f7bac09b77abf42249fbbd63deb5919a1fc96a4e26db9d789320a"
+            },
+            Test {
+                input: "eecbb8fdfa4da62170fd06727f697d81f83f601ff61e478105d3cb7502f2c89bf3e8f56edd469d049807a38882a7eefbc85fc9a950952e9fa84b8afebd3ce782d4da598002827b1eb98882ea1f0a8f7aa9ce013a6e9bc462fb66c8d4a18da21401e1b93356eb12f3725b6db1684f2300a98b9a119e5d27ff704affb618e12708e77e6e5f34139a5a41131fd1d6336c272a8fc37080f041c71341bee6ab550cb4a20a6ddb6a8e0299f2b14bc730c54b8b1c1c487b494bdccfd3a53535ab2f231590bf2c4062fd2ad58f906a2d0d",
+                output_str: "d8ef59e48fe97b07649929b9194bcc57ead8e0ef010fd65031c18b4cfcc0933152054ae17841d06c36bc375cb1f98d83e2f9c3dfd54b88312ae71d7a00590a759e4b8d524124cf480bcec6816fceecabc9e13356f99ada2319c3eb0cc9e3bb504eddcf7d3839511ba0b412a72c3a8c49f7964a4f2eed7b814722a487e3ea6e347cdc2585090130b4dc535c3fa98e085f107fa43222b167ebdf2bbd65ace691d8c23d64de52f966983a3d4479ceac8aab177947079656a454b7ba4548bcd5762974264c7beb17dcb4fdae572bd67067f304990611e7c7f4d50bbd2b29d19c02d51918d5be6e856bfd8dceceab2ea9f82f5be53e57d4b00ac371436eff3898e930193dd1a21c5b54506c6c91ea665d0d9992be999f1dc434ba587da4ef05bb296087314c4408ce0c5851660d0b5d1746232e031934284f85b7aa38420fa6eb469171faabe88f85ce64a7fef8420ada1f9baaa4bc93d779c5a268a3f1f8a57cd2fd3b19cdd4e648e622552c1f16455f32631a3d91ec2f7a882dfd0eb13c4b85b0a23e2477b53e0fe5e174f058268f6a24ba3cfa38d090ae6088339957863733e1da245432ab0394eac05ed82428c4418ddea00c45e57a1719c7d2d04a781f8d0187c7c33117a3ff5473bd5c1211476fb4eb64aede5a9e2dbfee00671e7a9ccfef7624e1f688b77cbc755b95b6ec391d8e9dd0b65cff4e1fc22f566f0b598bf7ed6e"
+            },
+            Test {
+                input: "e64f3e4ace5c8418d65fec2bc5d2a303dd458034736e3b0df719098be7a206deaf52d6ba82316caf330ef852375188cde2b39cc94aa449578a7e2a8e3f5a9d68e816b8d16889fbc0ebf0939d04f63033ae9ae2bdab73b88c26d6bd25ee460ee1ef58fb0afa92cc539f8c76d3d097e7a6a63ebb9b5887edf3cf076028c5bbd5b9db3211371ad3fe121d4e9bf44229f4e1ecf5a0f9f0eba4d5ceb72878ab22c3f0eb5a625323ac66f7061f4a81fac834471e0c59553f108475fe290d43e6a055ae3ee46fb67422f814a68c4be3e8c9",
+                output_str: "984570a811cb6b53213280f8c06c69ff1d17e767b163f8afd76674ac018a1cafda4d94b69bcf58f3ae8a53b107976abea6c616d85aeb98bc10f29177a3590bfe943f53d2512323e5e79d64f9f1319d47d6ba84c7ea37392bd15224d94bb16d99e0e1e7062fbc3edd7c81418d816e875fbc9d7434249d89a6002bb777e367f79219bc7faca03e1b9488307dea98f304258fbcc53c58a483a6fcc78d9d9b28d99db3709e32c1ee91fe305f72b041933c8cae6f68c6229658d591ce9b1100d6974706bc21a45224778d12dfba63cbe9a1a3fe9680a34771d9bae39b4dc9c191c0a4e092f8ee92af2a02c95242cbb24580e04774ab41b07fcb6f61ecc6acb2e48a77e544ad9f25ec0ed7f440c26b8c9d25c7cf4494af0802c4b482da80251f7d1572dae337725b9a976f70bb70b5037f333d53bc3c252ad9aa13eaa7c9de1ae4b24f6c91d17a489ac9d392038b80ef7679e75ca6994821f153c62d6cd7ef58927636edf95ef6f05520025c4bbba23685a862f244ab3802ae1d842184a5f5f344d1193e1239990c331488c1a8b98f1707c389c05afa919f5c17eac158064350adfb9532eb0ac9111e256251b11d082db28206af2ac514707d956a35e26495ede4e98c2578427b48bc99b9aeb29b0fcbe44a0e51ce9bb37864dedc30bbb5ff9a055423d8bbd453a65ab54e65cdf773ca695303ffd4767193d65f26706fed1cf35e740c"
+            },
+            Test {
+                input: "d2cb2d733033f9e91395312808383cc4f0ca974e87ec68400d52e96b3fa6984ac58d9ad0938dde5a973008d818c49607d9de2284e7618f1b8aed8372fbd52ed54557af4220fac09dfa8443011699b97d743f8f2b1aef3537ebb45dcc9e13dfb438428ee190a4efdb3caeb7f3933117bf63abdc7e57beb4171c7e1ad260ab0587806c4d137b6316b50abc9cce0dff3acada47bbb86be777e617bbe578ff4519844db360e0a96c6701290e76bb95d26f0f804c8a4f2717eac4e7de9f2cff3bbc55a17e776c0d02856032a6cd10ad2838",
+                output_str: "2c2e6afffdc10d54f74afaad553cca0dda3ae5a5ede3beb611e4c1441ad4e51b67eaa2306abbb39115457fdf15fce9607ebcf0537e4f9aa2703d222a2b5fe602f87f6b54cc7a9427807a10e56be5b29bc3dd91fed0322f291d87f563baf5b705534ae8bac35d4af68a23963c040f4a1aed9b3e51124303dfebbaedbab35d7ccbd38d482ee45e261bcefc53d0a25dfca5dfb60cb2672d34cd4154873f92b33fafb8068a95458bc1166b36c3977643ba159b655654d1755fd5e396ab9690718266ef6ae670452fbe332be84750bf7a26778e555fdb59ae0f48d6ec3ff4a1feabf2ff7f1ce4dbf3269dcd91e3ca9962d88db9c527874df15f7a6db9682b1f0d904aa875d29a8885ae63e90461c69b688046fc771321fd6a61a6f1a93fc95fac72bf86ed76eebdff0cd6960d72fc460753aba0324f2d7cd7372f413d4a49e761cade4f5911d18f7c712f61ce1a5c9f07ed2b042d5c86b4db97e1b7aba57e2f2db98ccb4041a16ee21e08ace213412c6d61cd3c42bb5d8dabd7b5a945fe512f2e64c3b1817d9bc5840d6e16f7e5e2ac36585bf8107addd0c269b8510dfe11222de1be13ccc2a5ba8536887a11a0a733eb81d93729d487481655f531bf4aae624918401097ec0951f7fc535cbd85691e0e0eeeac4a5848a61ae8d6d6121d3fbcba345ab755c4e8441ed7853ff46caa48090728a7ac39496c3002baa99dc90f049efe4c"
+            },
+            Test {
+                input: "f2998955613dd414cc111df5ce30a995bb792e260b0e37a5b1d942fe90171a4ac2f66d4928d7ad377f4d0554cbf4c523d21f6e5f379d6f4b028cdcb9b1758d3b39663242ff3cb6ede6a36a6f05db3bc41e0d861b384b6dec58bb096d0a422fd542df175e1be1571fb52ae66f2d86a2f6824a8cfaacbac4a7492ad0433eeb15454af8f312b3b2a577750e3efbd370e8a8cac1582581971fba3ba4bd0d76e718dacf8433d33a59d287f8cc92234e7a271041b526e389efb0e40b6a18b3aaf658e82ed1c78631fd23b4c3eb27c3faec8685",
+                output_str: "e36806ac60d67682d34d80ad11a1415901fccc216d7548de3f2428b1963023a9394bc0e1766e279ae3509ae85d773d11dc8f11ae65c5c0d6401575cb33835081492c2b657f34514ed6b0dfcc2639fb758b5fddf638576a64bd34759d629ff133112cc5200267d8c9997e1538d602ca356e821f06ef84c3125d8466673312c6903ce166fb97fcb3eac9d30d61e13a1deabb922da6e5675dc8976cd4426edf7a7a797ded8936e0a3e721de5c4d956e8287c4b05d1210bbd36ce0e36b7f2a31945fca6bac1caab3c46d4c8245e3e589dbddbd00a3b99d8dfe33783235026c1a990f1c383cf71c755446d8f5df4a114b9004541065bdb81ab81b98ed47a1d05595ad5e168159ec620b1da439c6ccb6c4d57a2adb33a0e113fd0d8acbff5c759bffa29b36e8416eba1b8f45285ef3f496f6946ee1dde798cf8f5bb78900e59785597101dac9ec5e5f5ce0f0d6b173b6418a75be30a84140fac4899c4eb8ddcf87a0f78f22e237806e0871cda9976da0e7e42c4ad73fa49d3f9c257ed1cc6c389806bb2c32b1f7744ddca53ba515237f1588f5fa7c636360b6b8d98dafa7175db320a1a3fd1b3a092d9e8a4466971b87e5b05189829ad8d3b407f3c5e4265026c8b801c391be0f9c9dbab2f56362f820384d859eae1ed9b291f5f03f14f12d0ff8addac128988a59707facbe23814873246c99db793099e6dc79712c612d41302f8b59"
+            },
+            Test {
+                input: "447797e2899b72a356ba55bf4df3acca6cdb1041eb477bd1834a9f9acbc340a294d729f2f97df3a610be0ff15edb9c6d5db41644b9874360140fc64f52aa03f0286c8a640670067a84e017926a70438db1bb361defee7317021425f8821def26d1efd77fc853b818545d055adc9284796e583c76e6fe74c9ac2587aa46aa8f8804f2feb5836cc4b3ababab8429a5783e17d5999f32242eb59ef30cd7adabc16d72dbdb097623047c98989f88d14eaf02a7212be16ec2d07981aaa99949ddf89ecd90333a77bc4e1988a82abf7c7caf3291",
+                output_str: "939f4a4b5e37b675450782b0e8554bd6a2821ec805ce07fd4f5a3bc3816a2305f2353ffaf15883e760a3dea064df1583cff5ed83a97a62df9d174aa80958e7649460fb4880dfa21dd7c00f373aa9f010ebd1de7e1aa73f51f84df36bd2dce6b37d7a1112c6c69efb734cce2ab12517fae38f0f3592a4693251cb4f41af7e820f1e6f432cb9f88b82fcf579b2a5fd0e9a5b3c28542abdaa9c651ef1a05a385051682b3238262475aeeb53894b8274ef37b223f66a32c0d3df45f3f191414fc0e8878e3d58852b4cdbd826d236a7010ca49c43095786cde671070ede3f5bb74f34dffaceee281042eaf3d2b39e53c25a61f3b0b2d79e4305b9a17c47787747d3cca46e88be79464bdfd16bb44ec7d862503077d3e4e3c55ba1a1fcda217d53f5c22a35f883fbd0e786af38276b341733f82beebc4118d486c32a3e7a460e24951bfbe760556e36981805b40b837b514fac3e8213937ecb018449319ad3fe1c0ec19b502e8e0399398f3f8c74601f61a9ba3021f153ed45a99bc150aa886bf090b0134da25b2740ee5156cfe28151eda24a2c758303f505e465f9d6a409651d4705a80b3ff660b2d66ad061960a3c6b81fa8d831659830c5243aae26334917660ffff3b977fbda3730313753facf7e319cdfefc064f2072af7195a70ea74db24e5fbd36d6fa78c0d0d1085d05e81a62d3449f16007d3cca29e4403dce5de01d579b"
+            },
+            Test {
+                input: "9f2c18ade9b380c784e170fb763e9aa205f64303067eb1bcea93df5dac4bf5a2e00b78195f808df24fc76e26cb7be31dc35f0844cded1567bba29858cffc97fb29010331b01d6a3fb3159cc1b973d255da9843e34a0a4061cabdb9ed37f241bfabb3c20d32743f4026b59a4ccc385a2301f83c0b0a190b0f2d01acb8f0d41111e10f2f4e149379275599a52dc089b35fdd5234b0cfb7b6d8aebd563ca1fa653c5c021dfd6f5920e6f18bfafdbecbf0ab00281333ed50b9a999549c1c8f8c63d7626c48322e9791d5ff72294049bde91e73f8",
+                output_str: "3c78c3bd49493560231a71a867bbb666536b22562f1502245991e3ff28e6f058264b382bbd61f9a16d4dda0b3a72f84606f97e7ce53f4a57c132a920fe738f818e987095c1292d9873a772e12f74bf42ee1281f408dc2ed7bceeb2fa6fd856b7a01a955350582c111b2cfbb65e26b745939e1dd4781a0265ec5ad4bdafde1ea40ad504efb0e9f34e15e1526b1873f251d33c280f9cad71bca17c4925af9c3dbd4c6798bd393625017c5d3b03666fbc3aee276ae669af2e9e10ae2d608247f3dce876a8ea3bee6ee001c3d5f847fc92a2a9cd0fddead45c1f92414b23722005aaf8a7a0159d91b77f4a0e44debb9a0967977b04072633b4588df0d699c8f990d60ff5a2e09690a624dbe88b998424620b5634acdc02c75ded6dba9431aa7a0febc01cc5daa3094cdc818b2a6ca4d80890113408565a714558b6bdc3e1735bd1fc9fe84210d7d78e0c50e8961c39725f68f083094277b7b7ed3300a1fbf42f72ac9a79ff927e4f76abf0ba233a9e82e535c32d7054078a6a4a63f1ea454c6aa33c5a2299df7becb5f911c25bd74532edc882ff4312d2ae0add4d0f67958a520011851988f9d3846c0100b4c119ea818062a3c69401344cf94f49ab995c286f441d8241f60a73863628ad8ae1cc780ea99ceff0dc18a3d85e16ca00756627f6a1b754635945120890313ee136438e01a41593b6efd26926f48309122cf1dd806c8c"
+            },
+            Test {
+                input: "ae159f3fa33619002ae6bcce8cbbdd7d28e5ed9d61534595c4c9f43c402a9bb31f3b301cbfd4a43ce4c24cd5c9849cc6259eca90e2a79e01ffbac07ba0e147fa42676a1d668570e0396387b5bcd599e8e66aaed1b8a191c5a47547f61373021fa6deadcb55363d233c24440f2c73dbb519f7c9fa5a8962efd5f6252c0407f190dfefad707f3c7007d69ff36b8489a5b6b7c557e79dd4f50c06511f599f56c896b35c917b63ba35c6ff8092baf7d1658e77fc95d8a6a43eeb4c01f33f03877f92774be89c1114dd531c011e53a34dc248a2f0e6",
+                output_str: "1a73a838fbe2aeac592433b7caabfd17068510b165896f00217a1f9e2093591a77330e656fc53d1223bc9446c11d329673b4186a85dc6091140c070843760effa56918f414a9c6f2d198e7d0c19f44ad19d1e89e25365cef40890987d255a616524ad68574c3c284825a48c3bcb0b48d41ee284b53be97127decf90402e8fe1317263d179814177b79df92b9c71efe9c3c2f3cbf8329bd9711e6393457f076c8bcf16a70e854daf7bce58c31f55b4d0e9681b39fdc19d0703a795c234016c5879857f25a64eaf0700c681e590b6d29605311f1bdbea47762bbfb012bf103d34c2cab53d53e1962ba6850b779b8673ba280b0fb79cc387e2559105ddba2884fe493b85ee0f0747436013ced0ace7280854e9bed8a42fc98dcf1ae5f845b677f4b802d01aef9529fffb6acfba047429d4de3181fa959a3b74aeb5934e3f25498ccc850bfaed46738736db5e5bda73ac03162923d310a1f91658d15cfc5268fd5bcd9ae6f9d5652558f74c1dd85696233ab9efef5ceee75f0a3489f46867b0bb1344ce24e5be88abb706cb49a07fee3dd5911dcc0486b58ff2b024f844c3773a1c03ce35f02256157a6a2e6616569fb751ecc3e4cf01ef99bb0ea61e4aefebcc65450ef2999505427b23c7cb9278e27ab58c5fa2d5b0a432a6172cb1c23dac420c92631495dc30dbe0af3b6944f1e101d1566f0a1f4ba06b82c36a7cd068864fd3b"
+            },
+            Test {
+                input: "3b8e97c5ffc2d6a40fa7de7fcefc90f3b12c940e7ab415321e29ee692dfac799b009c99dcddb708fce5a178c5c35ee2b8617143edc4c40b4d313661f49abdd93cea79d117518805496fe6acf292c4c2a1f76b403a97d7c399daf85b46ad84e16246c67d6836757bde336c290d5d401e6c1386ab32797af6bb251e9b2d8fe754c47482b72e0b394eab76916126fd68ea7d65eb93d59f5b4c5ac40f7c3b37e7f3694f29424c24af8c8f0ef59cd9dbf1d28e0e10f799a6f78cad1d45b9db3d7dee4a7059abe99182714983b9c9d44d7f5643596d4f3",
+                output_str: "674343644b198da1cb0709f842239ca1559ab643e48f8eedb373671473ca24a99a74e20ac6368b661ba1824af92985b3e7f957f9c935c715531703a6b8b5113a364f52c7df7c5488997a3ff71873fdacb1a6f4ac3b631a3341bc36cb742f8100b28029ed6c44fcb41e93b6f171a064b0f13b2f83b1790330def22a387c52cef7f16d1e398123ca0231b76494d708cc694a28e281b34ed163b7931312daa56752080c4966f8638134680cb96c4f815ac678106fb243ed3b9c9a5599d3851bf3d89cb7ba463c71a868f74d07f0c6f9c6f940f53d88e18892ee6cfe5fe9c17b92569e5c1222fee87792987663757459c35630cb355f445630826807909bb5cbc4f5c8e0bc669be6c705c12bcb2b39552d4af42204d237fac5bec56ef9ae6f60ba836ad865983df2f25a1f8c3f5df93f87eb76472dbebdb20fdf894c0167287ef1a6355040c4d4a6949f488697498529217e4532a445cded47687cfaa14db98260de9321a16fe84e4d82d2b1b0c2ee639b2aba48d85e4d06a369cdd9b03a0a846ebf83ecd5ed257876bd5e3e7838108fb3b86b6558f8bb454f1e76fabe18f3b66ca1448c1b02dab1bcd485e709ca800d5271952602e9b1bd585f61936d8dd678c900407892756a08730b891c154b33d83bcd1b2f441f1dfa79af235316be9a3e20eceb4eb23ab76d9e9564c367bc27424dae397e35ba16a8cd4ba15cfb7d9eee2b82"
+            },
+            Test {
+                input: "3434ec31b10fafdbfeec0dd6bd94e80f7ba9dca19ef075f7eb017512af66d6a4bcf7d16ba0819a1892a6372f9b35bcc7ca8155ee19e8428bc22d214856ed5fa9374c3c09bde169602cc219679f65a1566fc7316f4cc3b631a18fb4449fa6afa16a3db2bc4212eff539c67cf184680826535589c7111d73bffce431b4c40492e763d9279560aaa38eb2dc14a212d723f994a1fe656ff4dd14551ce4e7c621b2aa5604a10001b2878a897a28a08095c325e10a26d2fb1a75bfd64c250309bb55a44f23bbac0d5516a1c687d3b41ef2fbbf9cc56d4739",
+                output_str: "791be2551f426cd350322eb1ac0e6902996546d446c229e03d74e25cdfcad06cd99bdd3658026edbe8708ad18db913057702450baa457ee767b7f6085b0f1d35a86d8c5c62a35e5a11b81d409c12c8ad5777e245acc369abb5ea9d8d9517ae7fb4033efbbbcbb70fd6cc1e55187aa8a27c75e5116eba46de2c8378997504a82390e6b085a45c5fae52fc314e876da7a7f90226cedd3c4e985887f162513bddac323e85737f3954dc58d12e986bb1840d0eb046102c01381db2915981b23dece4987661b41b56d30c35a13da21c6d2ab0bb7951f04804986dc2127f7f33c4937d27427c7b7062ef7ede944efd0015681c2fa0c115b67652a7ef1aad03c0fc4542bade7cda11f0afc57d8e2c6df0e5bb5440c2b3ed2807c2798cadc6f371a2d6f2d647936b82936ba4b19a16f599689814ac4de20cc7cd05a3452d9286b345037abd23850f22a56bba707b1d9cf299ed3ea21943882669735f69d25f240f87f3b34cd794b0c6353681006aac5ad75cf46bc6464579bf5b715ac741cd1cc06cdca6e8d579f2ff839e263c94588ccd268b1d375e5df5bfc8b7a89fd72cfbf9bf5400efef53186b50497d942963eedcd6a7426784f38f8808c50f867d22c10fa4d7dedb4f5354fe1eb1484c9f645397582838f1c78076891c5e1e44959b5c74e28d7bcc3f6acee4e5393a5ce24e97cdbe1b22ae853c567068acee03cdb3157a3ef657"
+            },
+            Test {
+                input: "7c7953d81c8d208fd1c97681d48f49dd003456de60475b84070ef4847c333b74575b1fc8d2a186964485a3b8634feaa3595aaa1a2f4595a7d6b6153563dee31bbac443c8a33eed6d5d956a980a68366c2527b550ee950250dfb691eacbd5d56ae14b970668be174c89df2fea43ae52f13142639c884fd62a3683c0c3792f0f24ab1318bcb27e21f4737fab62c77ea38bc8fd1cf41f7dab64c13febe7152bf5bb7ab5a78f5346d43cc741cb6f72b7b8980f268b68bf62abdfb1577a52438fe14b591498cc95f071228460c7c5d5ceb4a7bde588e7f21c",
+                output_str: "7c0247b191c924335d843b81614c0f1a6a9ab1adb6c286922397d8c1b26220a35c13c7151e35ff9b3653a086da339ea1f05881f414e7a16c61b1453287f924c48ea933995000a9c9b0ebd5e8bef2c92820ccf9bb6cb0f465aac124b5e794fdbcc60584b05cc3bad06d41cf9dd5d3d3b7fe1cef634de558b6642e591bc2f69abeae61ef5da27bedf291d2a4106b3da946fb57328e827c8d4ee1c3665af79f96cc290f924348c30205d75b01bb05aa9dfc317cfddeeb7e3764589c003e2aa1ddf60a3c98adde4517e40d08cf80646205ec9fc6e9a3e1b64b2ead561957c3e2710dff720bd7e5841481d9e1a048d1c76a3e1a08bf010428c8fd2a6f2dca4fde7c8cf59c826e6df246cde77d5823dd1e0c0759af8356e89ed4c03276a37ebba73dc196e7915b57baade13a7a276aaa4456e23e4454d44260d9eadd748d4e7e1857b6d2d9c301af6118270859acc43603c79a2f6d698871fd5384daf43b16fee4ece1146ed54e1ca28eaaf2d94306383609bfb26d6634df00198e0d19500215e178d77329f7504af80dc6b727ea7791305fb38fddb1cef7f626a49ac6e34c3a6ed630f9310f890392704a2cde00cc850ff7ce9f0e1f0cb4b1d0c161ca3b812309cb3c9e9d071024d61e5265a71e7adc58a3d47a567f5b19f9e13fdcdcd34f3deb12da3151fe817e5844f5fce12805b064895671f0c3767af5a3d203d095be306d4a26"
+            },
+            Test {
+                input: "7a6a4f4fdc59a1d223381ae5af498d74b7252ecf59e389e49130c7eaee626e7bd9897effd92017f4ccde66b0440462cdedfd352d8153e6a4c8d7a0812f701cc737b5178c2556f07111200eb627dbc299caa792dfa58f35935299fa3a3519e9b03166dffa159103ffa35e8577f7c0a86c6b46fe13db8e2cdd9dcfba85bdddcce0a7a8e155f81f712d8e9fe646153d3d22c811bd39f830433b2213dd46301941b59293fd0a33e2b63adbd95239bc01315c46fdb678875b3c81e053a40f581cfbec24a1404b1671a1b88a6d06120229518fb13a74ca0ac5ae",
+                output_str: "73f5edf85cbe959cdfbeabbe2a96a1812134ec9d3ccb72d6039d4fcdef0b57bb72a782b76963c97ae0c2713ca657b9424851dc903cc0488a169538a0db3ec58e67c4eea1c18abdb2036c79381e76f5c9f6cf1f830e0dad77d2eb90f120efba42b20b15b8c8ce8532c5b668464ad4986a281e75e4fb2cbc59abf886a8540622c2458fefd190908a09fcd7f16b6e5bcc7e950917794fed485c82ceef7fe0fe4665e0922406ae1f8d34e5f77bfc0af8b4c881bf9f76c78a233898d120981be96f67d135723407ed252432928c7f2580fb80000cb51e3ee8db02d4ef4fcdbabb704db0cdb9e31fbe76930d285702d91a74db806daccc01a15c0129a7f7d4712668ed633462a6a036a9ec2c4a7e4aacd4d62df9da1fe959db9acd0fb6f01a75f95cd9768f408aab1760edad70e936eec344e9506a586b9d42db99ef828e58d281128fb0eac1185be704cc9d16e359ee3bc1361a776de4803132822f99f7e477764c9408b045745150ab8a7481d266995c91eaca7a9497f4ca1848828fb5ed127b7a4a5fa0f23614165a8e4de1e619a40d4e55ac28075ab2ff1bd42bee19f2f9d63630cac85eeca329a0a1877e848fb2a64176411a7fcc2dd63d6ca19452780bbe4eab208b0fa7b25f21f17be1cf7c5415a04fcab687b7d4ba2f657e39d5efc17f36a1a0e3de4610788ecc43cbe70ba2ddc33abf4c335940dd53891fb6dce20dd039ac"
+            },
+            Test {
+                input: "d9faa14cebe9b7de551b6c0765409a33938562013b5e8e0e1e0a6418df7399d0a6a771fb81c3ca9bd3bb8e2951b0bc792525a294ebd1083688806fe5e7f1e17fd4e3a41d00c89e8fcf4a363caedb1acb558e3d562f1302b3d83bb886ed27b76033798131dab05b4217381eaaa7ba15ec820bb5c13b516dd640eaec5a27d05fdfca0f35b3a5312146806b4c0275bcd0aaa3b2017f346975db566f9b4d137f4ee10644c2a2da66deeca5342e236495c3c6280528bfd32e90af4cd9bb908f34012b52b4bc56d48cc8a6b59bab014988eabd12e1a0a1c2e170e7",
+                output_str: "9f303deccea9369400c533ce2e162818957e18f65c05a675404cf8637fdb57f3251fdc2844ca194ed97cd021416e764e072598106e9d97d420087087dcf5f8acf1047a7b4518e683e5ac6df1ef1ba7ec7a418f12e386dfb7a4a5edd9898cae54d645ab3193982f4363da670f1fbc7aaa1194a03bb76391a78dae7e4fff733a6f19393e9c4cc5eb3f5503d8b1cefeeb7038b0565f29d6cd4460090fc63e3c4dbc7d5d3d107f8e905b21cc9b9ef3c535aa0d8ebcf787631744f80a05caca3e50968a05f85e9cb0d775dafcc714fd6d93c8b110e58f9ad1f8077cc80427515fc5c0cf081de5fd4cfe6ea6dd2f33a2df212918a3f86bbb8aba45d808bbc2cad8dd09e7b9af1c33b0e58b988268db39118b2b2090eabadec0b84fd836db6944e8e27b5f4f3b2876077d52b4648885ef55dfff266c7264c46ef5a3cb63588d1a86c82d19449e0c93d968619ca4d33bcadcb21e6787a5e41f0d4e95e2b47e422fcfe5bd7ebc65a3023479330e989b3edc8320edc868fb122df078470b0373732e187110d3964b6e7757e84f177106c2bfac5bcc43a13dc40ba8ad5c1e772c58df0f32ff0f10348686cf0662f2f30d41ba48b121e1a146c70e6131e13080cd8b63ab79869af74e64b9899855c81d20f753f22c67f1e4de2450740944cdf4fdeded59927f92a9568db95e5b8515c07bf4e9adf952d4ad498f3dc19a2205640a8378a0fd5f"
+            },
+            Test {
+                input: "2d8427433d0c61f2d96cfe80cf1e932265a191365c3b61aaa3d6dcc039f6ba2ad52a6a8cc30fc10f705e6b7705105977fa496c1c708a277a124304f1fc40911e7441d1b5e77b951aad7b01fd5db1b377d165b05bbf898042e39660caf8b279fe5229d1a8db86c0999ed65e53d01ccbc4b43173ccf992b3a14586f6ba42f5fe30afa8ae40c5df29966f9346da5f8b35f16a1de3ab6de0f477d8d8660918060e88b9b9e9ca6a4207033b87a812dbf5544d39e4882010f82b6ce005f8e8ff6fe3c3806bc2b73c2b83afb704345629304f9f86358712e9fae3ca3e",
+                output_str: "1cc30597732904c49c0f6eaf777f82b1c33b4cf00fa720c7db8473139266e7304d81999f322ae6803736d242e7408dbb8955d8f1c0b14c6f7678cacdf2f3cc2a17208033e8c70bc5141a072f41e759ad8eedff745df0162c2ea877a7d673bc63d80c0f1db765f9f5cdeb2eff214411f95ad7c3c41f6afec798e001d31ae22432a54badc751f7f713b4a3693267be3cdd3a1dde1a5e638143a2fae59a2a359e197cf4e5e1d933dad9f99773f164173e3e818987f19d122aab725af24497ca116ec201b2482f0539ec454292df4d018e286247f8c857b53816e9623d580d69faef60009fe72f25b4609e8dad73a06c006280edb0137a25d5462368b18b8f37525c2c74ffeb4a7942683b86aca6fb1d773e9c92311c4e197c5466ce90cf01c661ec2d928ee0d35a2fcf0ef1a87fa7d298747e44dbaa4c90c655348b8c2771f378fbaf0702ef9cb4b42cd5b26016d8f5fac1b79a49f8022a180f04f8988b5895822404d346a03622a5df8ad2e3f6841ab14644f6074a72dcda253d7c9423df9fc15d98f49e3b2a1df2011ceaa61bb7dceb3860b9b66df3926a1e79e73ef6c4429aa9f344adce7d9a7451ad97d0c9653b916b029c4971e6756fba775f191751416c3b0587c2fc5043f38d2b6205804c47da3e85a99b47f1aaf42d9c709f21bea94b8ca7340fbb8b262de6c47b79de5222afee7b1c994ed526ad4d5641136f5227a5bb"
+            },
+            Test {
+                input: "5e19d97887fcaac0387e22c6f803c34a3dacd2604172433f7a8a7a526ca4a2a1271ecfc5d5d7be5ac0d85d921095350dfc65997d443c21c8094e0a3fefd2961bcb94aed03291ae310ccda75d8ace4bc7d89e7d3e5d1650bda5d668b8b50bfc8e608e184f4d3a9a2badc4ff5f07e0c0bc8a9f2e0b2a26fd6d8c550008faaab75fd71af2a424bec9a7cd9d83fad4c8e9319115656a8717d3b523a68ff8004258b9990ed362308461804ba3e3a7e92d8f2ffae5c2fba55ba5a3c27c0a2f71bd711d2fe1799c2adb31b200035481e9ee5c4adf2ab9c0fa50b23975cf",
+                output_str: "6d96d224006dfbe8eec28892fd2bf888ff543501f2f8ae5b6beb67713173c88671e4b3804d695730fdd0cb04ffd873b0e401103dfae8f014ffb0ea382333e33985d1037403029f0c642323183ac8668907de791bdb0bf7112fd2c8ba5d3b933273b51082810c7515c78173dab93c7afc48b0a76d5488b76ca0e5da2226b669a2efa56f0a2041cc4a60212b2b4f4b02749b211856839868ccc0a935db1f7305ef356024fc78795690b69cbea01ec0b5aa8b3c4ac2d1815176b57062dc4742defa68081f21384fc875339f40985e85debf3ae9ef80cfca746375492614fe5e76a96e506403fe2cf5bcb43ae6e4e697e86237e825bdb16087eb32d3dbccf2af2b624acb4a960e0781e7c686b0b3a8a0e4beb1f904e0d84b00038788a02ce66baa59ef185e2678598013c60208e5ceb50b701bdd2694a24837f786931027ac0d64a229400b5783bf29ab39df9aeced0cc8b9d6fea52de3e9220575b4f3af6e2df155a20d87ff3f5ecdc0437cf7a8a648a0be9c81f0ec3457bba5d5948149c3ff2411053549ac24dffc65b54bb89b227499e35226fd9e1a85ebf5dd534852921beb63bf850edb495f9dc1876c6a481e9b774e6d4368974bd5a7ba7a16e90d078bd651f128ca7ac160eec05cb8f3ae3cee4bf998579b84418d7a70da95e65e4da9933ef8e399359d6d1993e5d9753cfd1b10737f6930ff0cba3510d3bd9cf78f5f79dd"
+            },
+            Test {
+                input: "c8e976ab4638909387ce3b8d4e510c3230e5690e02c45093b1d297910abc481e56eea0f296f98379dfc9080af69e73b2399d1c143bee80ae1328162ce1ba7f6a8374679b20aacd380eb4e61382c99998704d62701afa914f9a2705cdb065885f50d086c3eb5753700c387118bb142f3e6da1e988dfb31ac75d7368931e45d1391a274b22f83ceb072f9bcabc0b216685bfd789f5023971024b1878a205442522f9ea7d8797a4102a3df41703768251fd5e017c85d1200a464118aa35654e7ca39f3c375b8ef8cbe7534dbc64bc20befb417cf60ec92f63d9ee7397",
+                output_str: "e0335cbfa877da0ddd79072bd7f46ea6313144e633ba2c207cbd6948237cc32a39db06f951a1a4b9b0b91011158d38938adc1e42408a2d8a95c3eac579c922943155624f6318e12be7eb6a83679508e0910fb6e85a84998f0fbe06b087efc6ec91eee277b48d289dd6e12c820d0909e206750c82995db86031e71b0d005ce898f1cf7c782f10b8ced5370cf27b74c6822910b653bbdd328ae5a4921478a4072b8c7c89b446e057f6dc4692186cac39cf08e3c3f0c9457ff44da73b88ce131a1e2b4c6a235dd464e4777b069d39a9ee2a5877e07e8669b0d610513102b00f8e2a7ec210c403f2e398eff22e193a66376d0d08ab3013aea4d508ee88edd361fda5aa4e17ba899632cb7222eddd5b320af686c80f2777d94fa2a3428a47ae7340054d2dec1c42569a5eee01759846fd10af9d2ad2ae9f6fadff825d184eaf7e8ab9d7c7c64ae07cd5a95f2b24cc3857bb239f5c0824ea7ca0c84cccd9601580ea7a4c8937008617468b9122b466624d51af29ae1b66d14c332f2535bd7c3603de07a0b25c6a260e9e70ebd2da622acbca660d425de2e44b7e6242a83077bd24025abd5f0f2f21743f80d9a6f1552c3957b220088d861f3e25823548bdcb448d19b3cfa14fc8f11ceac5bb262364f100655d5099d564041f113503aec817bb03ccb9a6e02196706fbb836c28421afe0ab276772150fd0677ace7655ea6214f61d2a6"
+            },
+            Test {
+                input: "7145fa124b7429a1fc2231237a949ba7201bcc1822d3272de005b682398196c25f7e5cc2f289fbf44415f699cb7fe6757791b1443410234ae061edf623359e2b4e32c19bf88450432dd01caa5eb16a1dc378f391ca5e3c4e5f356728bddd4975db7c890da8bbc84cc73ff244394d0d48954978765e4a00b593f70f2ca082673a261ed88dbcef1127728d8cd89bc2c597e9102ced6010f65fa75a14ebe467fa57ce3bd4948b6867d74a9df5c0ec6f530cbf2ee61ce6f06bc8f2864dff5583776b31df8c7ffcb61428a56bf7bd37188b4a5123bbf338393af46eda85e6",
+                output_str: "74b8e6a2245e18432db073b046fa0d6f63c85a05b9fb3b3098c8f2aaad938cec8a8232ac2cc4cd7ea85a29bbb4a2d03311cfa7f1ed8107da574e659358408c60b1cdae6a4ba6f3091574dff998c97ca31e410b4132013afae543076baca1989e7b5da17e654e664c856a00d7de43eb3a2c5b8e347ea3b18a94d534c0448671fe2c360034550f145f911acb7c245a99fe37ca167eb8ae0ff5e9d0b65f255d24de4239ba87c2e8b757192020b3a28d53861d29c845d4e4a21604ed2d5dc8e4c107cd47501847b50ce2452a31685012c5949e0cb630088178aaa5c9b0eaa6394e00096cdafdc781833f37c64ee2955db09f1c3b3767a0f0928863567513d5b02a3d24e66a79ea590d5dbef5e8b5d9953ed9f72610c0d4f5ead67b3421e90710138e09bb15959dfe9ae408afa9acffca19dd083bdf508d8fba9f75a18f6229a9850de36653a0a39987781eae3f740e2ce387c004d47811e3f8b5f8da9ecafe90c5af4ace449ff7af57b271b0c3059ae42180a1746eb3aaba944dba5bf3946907a18b1d94df4819872a24deedda3af7a3787ab6b3d5f128d0c3ccab6ad0c34371bb76daa321e36f6ff935fd58b590858f894b54bf9997df8b73939919af342d6593f31f76c3251ab3812e27f00f3aae0c0535a8cbf9c6a9d20e26e619d6899eca8a46526d7205a3f2f3971c60e432ce438f40c2cbef0f2ad7253b18ad53c3bd8f108b"
+            },
+            Test {
+                input: "7fdfadcc9d29bad23ae038c6c65cda1aef757221b8872ed3d75ff8df7da0627d266e224e812c39f7983e4558bfd0a1f2bef3feb56ba09120ef762917b9c093867948547aee98600d10d87b20106878a8d22c64378bf634f7f75900c03986b077b0bf8b740a82447b61b99fee5376c5eb6680ec9e3088f0bdd0c56883413d60c1357d3c811950e5890e7600103c916341b80c743c6a852b7b4fb60c3ba21f3bc15b8382437a68454779cf3cd7f9f90ccc8ef28d0b706535b1e4108eb5627bb45d719cb046839aee311ca1abdc8319e050d67972cb35a6b1601b25dbf487",
+                output_str: "10b27d45e1e91c3568b990f306d4d0338380c4a24c543db7905ad8c20b9c469a79e50f7fe705c03d2d1cff9e2c35fce1e6e2035d3f464b6d2861eed223c32e960bb223f21193cd4734f36422c1de6f0f81791d6a5e9db7ba8c2ca1f2b7fef2f94c53928695913471b5e1b02b75fb9b0da1feb46520f3e8558e03427bf371180ebacc91f3989f849b4eab233c529006ee02050d85b548344c09cc7a6c6c40fce5c55348e1beb801482ba70d6cc5a24b3b0c9a3258b0934c3a41fbf07ef50460e2bda507711954c83ffb91cf2b2827d5fcc6dae70df5882689c573f159a9b45694458d0fb8a5000b109bea868160fca781f50db7b5ee56ae55bae1fbeabdc155ec46c0eb16314851fe0446ac2bf171d99fbcfbe2adfbae4a6387b42fe41c5ee8e2ad1819d7f80bb1b4ec2dafcd1d06c2c9750a600ee6627f62089b2ee59ea461e0dcf47188d1a8dc80b0294479c7eb03953c425d6eb3cac6ffc34e484a35127b605cabfa59712141c4fa0840fb520a1d0a8db4b298d24de2a7246f28e036b511db91794e35b75daebcb3b8833794b764f936200e7784348ae50b95363c027f3af85762f3b8e6f31b7c2d8bd18814a723c0de517f7b3937af574a3fb5f52de8a10a2055e8eb4281d383797df4b8d5dd5266c5d438a10de4bad00e4c0b252110cf368707aa2fe785f518cc2f3da5221634b52118348f231aae0712de096d70a43929"
+            },
+            Test {
+                input: "988638219fd3095421f826f56e4f09e356296b628c3ce6930c9f2e758fd1a80c8273f2f61e4daae65c4f110d3e7ca0965ac7d24e34c0dc4ba2d6ff0bf5bbe93b3585f354d7543cb542a1aa54674d375077f2d360a8f4d42f3db131c3b7ab7306267ba107659864a90c8c909460a73621d1f5d9d3fd95beb19b23db1cb6c0d0fba91d36891529b8bd8263caa1bab56a4affaed44962df096d8d5b1eb845ef31188b3e10f1af811a13f156beb7a288aae593ebd1471b624aa1a7c6adf01e2200b3d72d88a3aed3100c88231e41efc376906f0b580dc895f080fda5741db1cb",
+                output_str: "69304677315720d586605521e24d32745dfab082d2bc23a3165c419831c19468a088d972ac672d7baab907005a0ae3910d4f06f0bc5adf6aaf9e1d8cd7cb85dd166d0fb9703cdc7d45dafac4805612137d4720fb3fce90d69864403e6c456fbd87677312ed7cad9a28f7a98753265294f4820fa50868cfea157eba50dc5763e223238fb2032dbc6dc00c3710b6976f16034a9d851cd1baddec6071cadf10c8f9fa123fc0eb81ecaf4c16b8d52a6c1ffe330d114d71ceade28bb0422855aa1e7e838a93523315bd0f8384361a58529a2264d66d65806659c49b7f80d95474a7965a0733d3da4fe317c5ae6180746bd8dc70589f97b15e0fef29d34d6be4416acb3f9eba2f3e34f8e636a6b111dfd4aceb2c9de051b942ef021c78e0671f771058c4b59d34991dd2efc6943c6e0156cc0e3fead10968f77bf4da82b9fd3ab73b43e2890bc8aeb02d7178faeb2fe1a0a194b1581f6322d817aff2de7daa96f4a725ebbd8c9fc9c815d0a8e9fac425f278f121084ad98af9bb119235fffdf1751ab6a805fa80f43a5682c2fd5bf9241fca866de6b5efd36e692313f51fa8dd64b52dc2fc33c56687417c942680676143a459068401690df9213e18604058e74011b111f1410531fbed32567af7a0319b5a4a717f580d16d9e9341e78f717e27258a84a2cdbbb9ca118fd0f81568639f40176a1754c743b4b5e377dbb0175d160b414"
+            },
+            Test {
+                input: "5aab62756d307a669d146aba988d9074c5a159b3de85151a819b117ca1ff6597f6156e80fdd28c9c3176835164d37da7da11d94e09add770b68a6e081cd22ca0c004bfe7cd283bf43a588da91f509b27a6584c474a4a2f3ee0f1f56447379240a5ab1fb77fdca49b305f07ba86b62756fb9efb4fc225c86845f026ea542076b91a0bc2cdd136e122c659be259d98e5841df4c2f60330d4d8cdee7bf1a0a244524eecc68ff2aef5bf0069c9e87a11c6e519de1a4062a10c83837388f7ef58598a3846f49d499682b683c4a062b421594fafbc1383c943ba83bdef515efcf10d",
+                output_str: "b32e9585694532b1018b05b9dfdb23b8924025786f5733769b4913b73b0fc35513d4c0fa1a1a5019db5fc807abadcd4589b4c5658a854fc919105a5f08799f7cba3b8dfe72de84027b341cb1946d6a4a907d6ffbc15b6a00805abe25047476b99d53a6aabe9c758b3bf4476dfefef2e366617a1407853b0d0278df42fb7003bb1610da2ad52422a0eccc74818ebb4df264d0adb9623b9ee0c5371e9f0e73d7fd31a2b41f9da8c9955310166fcae6be9aa75d3f7c532f1502beacfcd81a034b5d4a87647a5b9e2c49b7bf055a0f4bc3f555fef5147bb7b9bd75772878fddcffd58ff2b09a61d6067c0f3498efbb5fcb736813f798e213102e47a3dd61a6bf99db2834db63befda6e290ea953a8b96fa37650df510082294891c86892215850a34af1ee0659694431da636c9bdc854ab98fc796c28bd6272c9c5df1d199ce9f55bb575786ebcd6851dac97924aafb102491bf4b80351afd26ef027c745f98607c19acf96b66ecfacd4c512bcc9a8e609de5ffcde0df0e77760d8d44f12301336247f53cbed8894831765d12221c902127b65dd549e6c32124e0ca555586fca8043097b9ae3d9bcf899fa06ee5d0a17ec0a2e657e37cf5d4a55cf4c99e9f10691602412d27f9b8db5c4c2644fc822e11833b32168ac89f2d591748d12b527fd5eab2291f201579a48aa9c370979dc2265b873ad65266e98ff668579b0f4274c73f9"
+            },
+            Test {
+                input: "47b8216aa0fbb5d67966f2e82c17c07aa2d6327e96fcd83e3de7333689f3ee79994a1bf45082c4d725ed8d41205cb5bcdf5c341f77facb1da46a5b9b2cbc49eadf786bcd881f371a95fa17df73f606519aea0ff79d5a11427b98ee7f13a5c00637e2854134691059839121fea9abe2cd1bcbbbf27c74caf3678e05bfb1c949897ea01f56ffa4dafbe8644611685c617a3206c7a7036e4ac816799f693dafe7f19f303ce4eba09d21e03610201bfc665b72400a547a1e00fa9b7ad8d84f84b34aef118515e74def11b9188bd1e1f97d9a12c30132ec2806339bdadacda2fd8b78",
+                output_str: "e6bbddc5b154abab888f4e00c2bfc18a200db6ded8ebad70ece03d10d123c52d4b5124cdfde2d5a803b8be98c646e29f64f2bdd55492531b2741c6040fc51f7df18106d9aae62f1930bab26fd5167d516c4e4afd3035d6afddd06daa59b56be3f188cbc11529909f6ca0618c321349b1b918c1cee491c8d7996f10b02e0a085ce790648c586710d4916a528398fac1e1fa71971ec85b203b83721aa006d7026c2647cec53296e80ee3fbb6b880bd296d6b9dffdf40c5537551eb0dde86e85a72fd280888c08d67a9839ea61849b47fb010540baa15530495cc8bf941f82b4b3114f6ae055c852b0978ecaa67108aeceb12e78c339071ca058fa4a534558899d71ed36c2164de0c92612f07cf465f92c0a1987f7462ad303de358dc9c9929ac205f366fe564c0b32b1e4d65ef4e0b45b2aaea6a93c5626ed40c597b54a2074f255fc6c33f7de535b5041f32085274ebde9d7ace9b458e7e7cc47193428a8873560c561230b03a72d993100b73fdc24231a39c227b05630b328645349e0025ef02002c34e6a7ef07ac5f7e299cfe0ecccf01e1dfbdac9bbc95b09b2ea505d8e74c85b9bc8e939363f3f062260711c44c132e1f3663123ec0b0a253de7db1dc2a08481571f64bac3fcd9eac737bdb42aa4d392ddf9547126191ddcb2f88a5705bec9be7c8d88e9521ef7bf9753155f6f3a75acd4c9c913785cbff81761da8dd73b8"
+            },
+            Test {
+                input: "8cff1f67fe53c098896d9136389bd8881816ccab34862bb67a656e3d98896f3ce6ffd4da73975809fcdf9666760d6e561c55238b205d8049c1cedeef374d1735daa533147bfa960b2cce4a4f254176bb4d1bd1e89654432b8dbe1a135c42115b394b024856a2a83dc85d6782be4b444239567ccec4b184d4548eae3ff6a192f343292ba2e32a0f267f31cc26719eb85245d415fb897ac2da433ee91a99424c9d7f1766a44171d1651001c38fc79294accc68ceb5665d36218454d3ba169ae058a831338c17743603f81ee173bfc0927464f9bd728dee94c6aeab7aae6ee3a627e8",
+                output_str: "f40b4a6a7d88482c5ba65d17038d68184e1aad676d3403003017a4348a7e3abfe89804ef65d96ea5a467caa9387020719184528944aad358960b66a0e78f2e4c19f244c82cb0d10bd1df49cfb89c24fbce8af1dc6b13dc61f40116ed3d1b51b80acf08a7a9badc6318da75eb4cabbf4798923d639c2c3c24778660089384de33f0ee7f957c78d4bf8d74ee1e3ea5e330c350584c319298166cdaffe0c7ace6a50d1551b30fa386a0ed5c20da31dc35fe2ddb7ff030aef1c0f2ecb0c1915554722ddd5a38df758e321048fc4643fdfaf54ae558f9b40eb38dbe516256e8d97701022b68e1f0983a14d7dbefb59dac5073062de8698beb9c94dae0a49fd51a661fa6aa84fe1088eb4e0f964953625a898b03993ecb248efd5e66380667c2ed185fc568ae58e15b5a57abfd84966094ee5c85284f3248c92e1300db80cd6ae08662412d01503d598a1fcdb0ef8ca773eadace543b867bade24efb25518e59e27fc921d8db6d3ac286bd1aba53d48983df63d493f95b88610cbcf6de2130ad63fb9860a839c3f98f5532b90225d1adad79b478f5c9d836435a9c9c0ebe229fa494b5f4253da92c7382ab388c4f052911e9ff28cc43415c8a82065433d8cdab9152cc13191f1729ea95693b4bbebc3b03f298ef6b3739a0f34a545198ff5d2b4292aa8d6a04271463df95145c99ec769167761690c97361984a665b0d5c2169added2"
+            },
+            Test {
+                input: "eacd07971cff9b9939903f8c1d8cbb5d4db1b548a85d04e037514a583604e787f32992bf2111b97ac5e8a938233552731321522ab5e8583561260b7d13ebeef785b23a41fd8576a6da764a8ed6d822d4957a545d5244756c18aa80e1aad4d1f9c20d259dee1711e2cc8fd013169fb7cc4ce38b362f8e0936ae9198b7e838dcea4f7a5b9429bb3f6bbcf2dc92565e3676c1c5e6eb3dd2a0f86aa23edd3d0891f197447692794b3dfa269611ad97f72b795602b4fdb198f3fd3eb41b415064256e345e8d8c51c555dc8a21904a9b0f1ad0effab7786aac2da3b196507e9f33ca356427",
+                output_str: "92951eaa72195331acdd63572fe112e0df4b43ca1b67ba5c9184da5667a8439e3afd8784461010eb80178b07f278c0bd52582cef5b4d869d77e764342651ace52f1f5dbb5316a36cbe2d6fa455403a8ff0480a5df002396b8e444b9005a9a97d301529f5faef77c0fc04c3b01c7c4907f197927904bc56da2f850a0767e91c5b77d8a41cafcbdd5cc768e220e844786093ce425bcb3bf6cf3fe9cccbf6a5cb84d46aed8beb079ac0f12f68836a71d8c9d738f9be5a8311299eec2ae86ab774d0d8345c6fa7a341223a43dbb85ad5274806b23a3bbe312723bed548f4c64353ee2875a44a8a37153dafbe98e96efaa402e7a68bca09eda8a744c3bb8fcdaedd7ec54ca4066b69b4828afe6285b6909bc2ae96cd62f3a5238987279f206c2593fd2bf4d5a643484a5155fff290253650387c7bdc0b3fd749eb1a84f7a11790afcdd3fc72fae3bbb1c55596584b7246e77d0712562aeaff1c5316a698db9aa3524dc4af4aa4619c5f9cbbe41aa1ff2a0bad12f17ecf7c90e6fbc20ebf374d6335ef245bf449e3ee5870651587727d35bbed64885a8d375e43cc350e398c3d5de83ce92354c08e16a6ac69af10efaec2f0268cb7f998ceb45db988b193c8d35e89a387de6c212a2d2d5a9ffec3d4dff92d66992563c85e4e707730bdb669783357e5ed038acea7d8214313fc027733d51b2d21f47666dab6c6f3e50a335e83c72abd"
+            },
+            Test {
+                input: "23ac4e9a42c6ef45c3336ce6dfc2ff7de8884cd23dc912fef0f7756c09d335c189f3ad3a23697abda851a81881a0c8ccafc980ab2c702564c2be15fe4c4b9f10dfb2248d0d0cb2e2887fd4598a1d4acda897944a2ffc580ff92719c95cf2aa42dc584674cb5a9bc5765b9d6ddf5789791d15f8dd925aa12bffafbce60827b490bb7df3dda6f2a143c8bf96abc903d83d59a791e2d62814a89b8080a28060568cf24a80ae61179fe84e0ffad00388178cb6a617d37efd54cc01970a4a41d1a8d3ddce46edbba4ab7c90ad565398d376f431189ce8c1c33e132feae6a8cd17a61c630012",
+                output_str: "9107bc54f9ae29bd282c37cf4be15d2edc4b5a20fcd8c131620cee6c9326af25896bd25550cc3b46c19bb58d825a7156a4aac0ae72e38601aa6aaedc4ddc578d145ae8a0af4e630914b49fcd39c41924a19ed6e52ec150d1bdfbfe2717b9b46d6be9bd6378761f167c1133ee31981f9b681d674e267b3a01b0f455f9a0c86b7e6bb3ededc2dd86c8ef6f6bf736ba9cfc4a20e602779f0cc626e0f3513807c8bc71546dd1e0e5210a6abdbdb284f90eaebfae970cee9eb8c58a5f0f197feb3292aa8ee814df5d86d6b1f43ad787e82ab6d1c01cf44f3b32522609cc51967fa9d2417a8b91461b41a5390bdaee3763e152a2db2e8b7842a73f1e05a05f7a7d19fc88f576b049f87e85835ea4dbed141ac1321b47aedbfd285b6488b7613206e483559a8b0725d3091a04f10736ea1920fe234658aec2a5fd0f85f50bed9eea3e5513ee3b45f0caee09a1ca3dd8e96ebb408ec6a31f07acec024097c20038a6db8b5a10396c6f3532d8b356bd664a9c3c153d2248f9d8587d21ad3adb20d06c020f5aea40e96c776202a17740f59bac12195b49e19abb87f693ba0b1b414c4c83dd7474fb212f0f8015d0019d33250bb890079278e027f0191b1a92fc40004050c4e88d1cd3469b656a2f6d1ab9e49118b18701fa85a5b1497f1fd0d3c999567f99d05cd8f20dbc05333f547598615fee2452861af0cde27acc4d763074de840004"
+            },
+            Test {
+                input: "0172df732282c9d488669c358e3492260cbe91c95cfbc1e3fea6c4b0ec129b45f242ace09f152fc6234e1bee8aab8cd56e8b486e1dcba9c05407c2f95da8d8f1c0af78ee2ed82a3a79ec0cb0709396ee62aadb84f8a4ee8a7ccca3c1ee84e302a09ea802204afecf04097e67d0f8e8a9d2651126c0a598a37081e42d168b0ae8a71951c524259e4e2054e535b779679bdade566fe55700858618e626b4a0faf895bcce9011504a49e05fd56127eae3d1f8917afb548ecadabda1020111fec9314c413498a360b08640549a22cb23c731ace743252a8227a0d2689d4c6001606678dfb921",
+                output_str: "02d21b8fee4bb59b4d39d88df91b675762640994d3a300bd7259a3e97ded831112d27339fc4f59c7f17dabeed310ee901d829a2193421c4d828df1248a68f6ab928ee87afd727ddc2766de071103b144040f9ef22592599a0fa6cedc2fcd9a774bef862d2d51c8e2538d1dece789a6756a1f9034c0949c3ff13190a141f3dd4f015a89de643d65e5ec4ab25300739892a81911e3c48d8a58239203c7e828e8867230e46bb8befd018e9ace92061e2baa09b0fb8c0cfa7fd5024cc65826aa96bdda6e21ecb7d0d77fe651cc25ec260c1c41f4d0dfa82963a2eeef0ac0c6123d9726a02396a0612e8ba6cd4988c132e7cab1b5097174b6bca798c7b04e5f7175a3a5bfaa9d23dfcf5e531557be9ba6f4b5d806287bcdf1cb5034ff94f709544e81d856cd8a1380774c5361710460d52cdfeae9af4af3e9daf7e6b679a6b881a378a1254de7105396db24497373430c36d24bd49425e7613faf651747217efc4e24a761cb4694a2ab3e0b43a8a4cda5ebc9d7299b27eb600122c7ef54703e48f51db2a5a8f3eb59a2c174df966ad728df0bc2e94418775e0186d3a527f86547980c8998b32f0365d9e430d33a92cf081a1525892fccf3d8fb4db1e0a728a856f2e2cc8ec4a08feff53db85c6620cc8b57106097a96b668f97c3bde8cfdc9600419b46ea24839d27a574bf63147a97b2b48cee1c6fda32f3b945e36fc03eab485b4b"
+            },
+            Test {
+                input: "3875b9240cf3e0a8b59c658540f26a701cf188496e2c2174788b126fd29402d6a75453ba0635284d08835f40051a2a9683dc92afb9383719191231170379ba6f4adc816fecbb0f9c446b785bf520796841e58878b73c58d3ebb097ce4761fdeabe15de2f319dfbaf1742cdeb389559c788131a6793e193856661376c81ce9568da19aa6925b47ffd77a43c7a0e758c37d69254909ff0fbd415ef8eb937bcd49f91468b49974c07dc819abd67395db0e05874ff83dddab895344abd0e7111b2df9e58d76d85ad98106b36295826be04d435615595605e4b4bb824b33c4afeb5e7bb0d19f909",
+                output_str: "76919b60d28a57717ec190fc9990e32020e6436828d90d8a2f4a7ad21f18a4f5f1ca753adcb0aa010d40334d1e58b8bd165b0151e631925055f4800dc01d466d11e88ae945545365b7f6072b36e11cb6f15da6ba3b53e12473beed09c5aa275cad795e03838aebf74a6b1a3371344c1e3104cde3c768026963de2acc8935f5162d1d09c966b5fe2943cc723e8007559c0537126400f1a4c3d9004df88126a23f9051630de9fcac524bf4a109cccf5cd7f7972b64fcb5a8e5a78a85ee82fe553ab90754cd12ec77e2e3cc09aa1f172963da44d29fc7f95f0c7c1207bdc858fe8b9785eab55b6ee33612863fcfd1668a2fb13715f7910968708f22a9a88d97f84ef4212551d8fcb05992670aafc9ef5cc34f0843246241c9ee011470131e0e6b56c9ef6a0e38423943ba502ec9d08c39f70797bd85f6d9207684022cadc282eed833b43ce450445075013f1b3270492aa6e412cce8e9d9534c0a380b45cad9328610ef3facea7ff5199f1e4d0342163b16961b0f98e46e8615ae2cd74d92e2df30a3df00bbba2ae43a67f51ec52cdb37e00d979ace6af3afa34a58b8cfc07ddc3c98fbe4a5e18539d03acfa18152f4cd32cbd84ac30a99c325ebd57ef2870f36c711900cc23539be7c19dc94f75457bdff28b9b5df876b5576cc37fb30b291dbf44904b36c3d96747dcd92a1550cf9323f358d15471fdfd35c2f4c4b104cc91fba"
+            },
+            Test {
+                input: "747cc1a59fefba94a9c75ba866c30dc5c1cb0c0f8e9361d98484956dd5d1a40f6184afbe3dac9f76028d1caeccfbf69199c6ce2b4c092a3f4d2a56fe5a33a00757f4d7dee5dfb0524311a97ae0668a47971b95766e2f6dd48c3f57841f91f04a00ad5ea70f2d479a2620dc5cd78eaab3a3b011719b7e78d19ddf70d9423798af77517ebc55392fcd01fc600d8d466b9e7a7a85bf33f9cc5419e9bd874ddfd60981150ddaf8d7febaa4374f0872a5628d318000311e2f5655365ad4d407c20e5c04df17a222e7deec79c5ab1116d8572f91cd06e1ccc7ced53736fc867fd49ecebe6bf8082e8a",
+                output_str: "72a343df2c1854005653e1ec9c8f9492af9ef7facf46df729ad910fa3a8b830971d22d5e017ecd515c0e972197c87968fd05d59c570634a3864dfea159229746a967a2847f0f4e3c48dbdb21ebfa400e18bf289a2b146758eaee64aa200287f7f55e57817ece0470c35531d35be824ad7e825e7a1fca07ce5325de6e27d6c6bf1602ec1069117e230ed9a0873d6538881992fdbce93a4e12013a56f4d22f5846b4e04bd15e9ae9590c703ee7ae346b860d1b4b181a963c1dcd36ad485aa484ce534138789c2874ab5888b70e278e30534acdf0d9798a44e1701d9447b5d6fd212344603a269a9d2e0437304f5153fbeb7bb5a1e437b63014ed6f01d4f6135ef189ee290e30c25dc2f63b7d8cf19e9d7959eb2f61703842e0c89ea487441b9c17fa6800a63c411f1d3ff4c35f1e89bb820d60b25cb1ad71e6583390e753934759a5467680405b1c9b6e391d6ddc4510ff24496559fe2604c038a5df6638fd7f7880e0847b880c1628f47bef49689d0c31c4867baf6fca08fea898056dcb1716c95341aca367bcd9bb372a93d2fce947b5cab707e744f15fbb85230fe7f86a9ef7c36069ca79d781d1cc76193d423229e51ce0612a2d61680d35cfd5aa482739442f94d205d72080bec7a259b23b8d9b4f76f2a75235cc3bbd6738fd870905fa21bfe1315b0c678d7db5f4df36f5d43d04c11f3bce3fb71b3b7ae410ad51cde033"
+            },
+            Test {
+                input: "57af971fccaec97435dc2ec9ef0429bcedc6b647729ea168858a6e49ac1071e706f4a5a645ca14e8c7746d65511620682c906c8b86ec901f3dded4167b3f00b06cbfac6aee3728051b3e5ff10b4f9ed8bd0b8da94303c833755b3ca3aeddf0b54bc8d6632138b5d25bab03d17b3458a9d782108006f5bb7de75b5c0ba854b423d8bb801e701e99dc4feaad59bc1c7112453b04d33ea3635639fb802c73c2b71d58a56bbd671b18fe34ed2e3dca38827d63fdb1d4fb3285405004b2b3e26081a8ff08cd6d2b08f8e7b7e90a2ab1ed7a41b1d0128522c2f8bff56a7fe67969422ce839a9d4608f03",
+                output_str: "ad4dd99aa71dbdeabf22fc7c82bb839f910a22e4cebf8317899d0af87279ebb321c442dfb9083c4676c16506c4006f18e8bf84ea9024b1deee4abe6f90dbe0effcebf4cb7b94d8a8b107c5bc3198277bef87c9760ae2bea86ac50c39a666ab09f276f2fa4c1eb5b8c37adc3b4c9de4bdc28074ff4b997518b44fe49b0d4e4f83cfe9e12ef7389625766a54bea82db3fb57276f47c418bdd5f20c8146c792dcb8e42c7abf09331f599318265776cbb19c65bac6dc4a683956c052ae5cea02f1e4ea690f9e5d3bf3a06a726f0efb6dab5350753ffa7adc477e9ae454c5e18f9d64edef0157d1f01fa78bf281468f14d79c39405d2b5b604c0ee116731c52c2432488c45a3e56d3f999855631381b5ef3c99a0352c16b92812a4889c1b8a72c84273a90abf29c7ead82f2e7c6de67e7369dc02fb0f1d62bb8d245030a6d26e930476171547f33b9c9dbcd542f04c97b0a278d24e2bfeea0209fa83d634afe65ec9e7a5550774ededffa36250dc5a400ae5fd6696f20e5fc6afb15f54c7240a24cf11bf16730b8e676f948304d3eabf315e95b723ffbde6d931ecf3be6c69d8cc82f31d1f499bbad8ada9654630e7185bf6c1d882dd700f7f1b1abbf384f58994d55c9e831aca847b8f654b070f424267685103bb339a4cd43df94894e912b64acb15aac65fd496424fdf02be7a96e161cb6a0034997ddc918f6fb604d6dd55b4d92"
+            },
+            Test {
+                input: "04e16dedc1227902baaf332d3d08923601bdd64f573faa1bb7201918cfe16b1e10151dae875da0c0d63c59c3dd050c4c6a874011b018421afc4623ab0381831b2da2a8ba42c96e4f70864ac44e106f94311051e74c77c1291bf5db9539e69567bf6a11cf6932bbbad33f8946bf5814c066d851633d1a513510039b349939bfd42b858c21827c8ff05f1d09b1b0765dc78a135b5ca4dfba0801bcaddfa175623c8b647eacfb4444b85a44f73890607d06d507a4f8393658788669f6ef4deb58d08c50ca0756d5e2f49d1a7ad73e0f0b3d3b5f090acf622b1878c59133e4a848e05153592ea81c6fbf",
+                output_str: "7623aea16ed0ac8af23a7911be015d44f93f3329ad1c0023bb9a6e486477d9cf5307b358527bf479fdaa473fe60cdce59c33c4d1db930057438cacb4006d2e6c327b3fb033be384ff07eb40a44ae4d39ea9794c29c9f3a91f679ef4690c41422b193929654d00d44d06fce9b35e5feea5c20cc02fd104a74764f3bbff273086023af4afb3a29f9f9836c17c5a883bfa0fc4d8fcc9808febd82df88f7dfc3f715c8b07db1f2b61403cb6f4f7b18f898fef9741e016ca0cb3a4b8f54f57db2f2bb63289aa38a7a9febde32089e4b479d9cf184f7d1c418b648cfe7e6079f7dc1cc35f22e31e620704736b44fe1e3a677caff61fd956883e6f6cb278284a05bf2b4cd9b832de2058fab356052c55b03d245baad53b86414441010767abea201e26f270649ea35b0479a66adb9439c57a77e84b754a7e328e4aed0618742cd49aef0af116462f3a5b24343e141fc51f6b9ff376a30989b17bf4ca9dc2acebd4f22d8eab082e62fff99cfc55ca5e7c4b86613356f1cf05a9a3e8fd79123fb19627a75810d3af44213dfda590245fb22b48e8ec5f58ee1d51beee4d6be0bdf7e8d18aeb37995d602e1ea1fc25d0d47d64d8a88b273fa8cc649c017a63f34c140a1d801f2558c8639fbeaacd1d961893e111450b85eca907cb3b66027587fe9b39d635d01c4c369589b9d8907d54a9b73fde7ffced9fd443b18892f29fdefd7b3e717b5"
+            },
+            Test {
+                input: "7c815c384eee0f288ece27cced52a01603127b079c007378bc5d1e6c5e9e6d1c735723acbbd5801ac49854b2b569d4472d33f40bbb8882956245c366dc3582d71696a97a4e19557e41e54dee482a14229005f93afd2c4a7d8614d10a97a9dfa07f7cd946fa45263063ddd29db8f9e34db60daa32684f0072ea2a9426ecebfa5239fb67f29c18cbaa2af6ed4bf4283936823ac1790164fec5457a9cba7c767ca59392d94cab7448f50eb34e9a93a80027471ce59736f099c886dea1ab4cba4d89f5fc7ae2f21ccd27f611eca4626b2d08dc22382e92c1efb2f6afdc8fdc3d2172604f5035c46b8197d3",
+                output_str: "a2cd7ae2955e2c2cfdcc374ad99e46f29fce072e2c085e0f02281a4a85a822a2424546410466299cca501ba5a86c12085320d2d0116196cd31e67e175bfab909e279846c8fa2cda475b0c9d604942d6332f3ed46e81d3dca880527debabe55bcae22c98ec42822bd1874561e7f8e8cc8092dc461577f2ae548580faab59afdfebf359847dee5271c2e972c12d13424a50a9b3dc3de5fa6f5b190f3dc060481118a595a8859ecdac8c57fb16fd4db9802c7bf344a68a0a91ca8629dd0a8fbb26fba0e21c4d953626f66c0b33d30c2569d73bbef7ed708212b2f66ddb9aeac459a11c9862cb5674885619d240babe380bbf23564f6d946d03aa544e348943a488c0fd223b36db5b0efbbe5c4e1253c3ff6c058aa95a80925523749bd228d89bf99f5cc681237fdcc8c872f652dae6306a20d9422818a8de2fa68c5a334efe828a20a48cbc49eb6d7ed779b00df50751446d0c850ff1f096fc50a03a8c407b8362ce03690d2d5699c70313b4f2d39e18abe998ee73de38308dcbaca27b8f6cbb3305b35c98b620a811c94aae44b5dfa2f8664fb678fb1d73dddf9fc27cf693db9d5cf3b46c185b72c33e3bd0f6ffc01108c8a65772acfc13defaf21596f2c9b9512f369588f6f8767ff61436ac67eca3de25d6c5a9746afb3b3464a49f3a583740c432ed806bfd16eab27d59a12975d7d09f7eccd67c2527333fa95509f7209dfcc"
+            },
+            Test {
+                input: "e29d505158dbdd937d9e3d2145658ee6f5992a2fc790f4f608d9cdb44a091d5b94b88e81fac4fdf5c49442f13b911c55886469629551189eaff62488f1a479b7db11a1560e198ddccccf50159093425ff7f1cb8d1d1246d0978764087d6bac257026b090efae8cec5f22b6f21c59ace1ac7386f5b8837ca6a12b6fbf5534dd0560ef05ca78104d3b943ddb220feaec89aa5e692a00f822a2ab9a2fe60350d75e7be16ff2526dc643872502d01f42f188abed0a6e9a6f5fd0d1ce7d5755c9ffa66b0af0b20bd806f08e06156690d81ac811778ca3dac2c249b96002017fce93e507e3b953acf99964b847",
+                output_str: "a74b8704cca1f4234742a5c8ad6b138e58d56281c98d95f76bfc0a0ae309d3dc227543f9aee711c85021b89f259d002188f4e753dddc4340dca27b84445afa007a1e502a1903a857583796bb124ddfd64b5c91b69cd9b230f27dfa5d22a09b07fca1d860dcf316c22e57da3589fb0f07ecf671dcb150913ce8606da9ce39a5857b8382853056a5930f25e3647015b77b2df4954314f1f8b1c774de0bcd1842cad3bfcaf5dae8ab9d77290ddd2112ab060f5b017630c318a1a3df5c15e6f8aa348ee3f3c171c4e8b98cb4a2956fa240eb289561e7ca30eeaa9cf79683db7a2b0f28b3b1bf30bd5a62c96ecc8bd74d1f2d131295597c668838a8d3b20ce1a4ee4d1103de547ac21f6442df2ca10181319c76ae5827fd60eaba7c788cb369591e429b5dbbcd95049bfee2a5829ffa0417772db1bbfac2eaf112b9712a02c1ece830e17b22696aa6688e08bc705ea7f7010684d7006bc0a017bbaab1d6119b1b589b326f1936c82c470245298f2167d884398ed408814323d369bd1126031dfeb56a160f90359054400db3b3d267d42ffda5bb710643721871dd4de52446004af00ba55706c93beaf01f8d77664af27aad65c6d61fae24e65feb4310afe6ca5322ee4dd2a55ca5fd7e651ac8d3118c0fddae4b2e42862aaccd8cd2134340ddd760bc7918a461b16ecabb601861b58edee6e78ac3ff75055997aba8c0c57878aba5a7"
+            },
+            Test {
+                input: "d85588696f576e65eca0155f395f0cfacd83f36a99111ed5768df2d116d2121e32357ba4f54ede927f189f297d3a97fad4e9a0f5b41d8d89dd7fe20156799c2b7b6bf9c957ba0d6763f5c3bc5129747bbb53652b49290cff1c87e2cdf2c4b95d8aaee09bc8fbfa6883e62d237885810491bfc101f1d8c636e3d0ede838ad05c207a3df4fad76452979eb99f29afaecedd1c63b8d36cf378454a1bb67a741c77ac6b6b3f95f4f02b64dabc15438613ea49750df42ee90101f115aa9abb9ff64324dde9dabbb01054e1bd6b4bcdc7930a44c2300d87ca78c06924d0323ad7887e46c90e8c4d100acd9eed21e",
+                output_str: "4e12a03995768c80408869a5c45b174783ea2fb5e4c153a2c014a3fb8ab968d74c9b835d9c4c5fc304b5e68cf9aa72c2adfc2de961cc9a90e1d515a3234bb79da1d5fa330c03deff46d304f0f0378324be4fec285758b2de3788e71edcd05754366c71b783a26d105a48bbf51c4f4e769bdd19ca477d80fa55695a04b06a0970b98be48ef1e861f17b9540e63f54b6156fc2996b2d2ca69326e0cb7a4a5761b39fe089017322bf23b7b5ddba1490541843bf703508f5512117370253248f23f30dccf27061b8f81c1090cc8ed866263fb50ad6f3a027efbdaad7760eafcec0928ba40173a50c61596b75aa4d72986a8bacba61dadda139374d17843735136c8dc0e14c2ebcbc9eb110a682cb77a72e790c68e11848431441ff70cbbc513a9d389d349a63aad6a948a42dd798f1a576df57ed0613fff5f569ce5d24061a386b2a5b4b1fde6e3359ce4125241628b9a882ccfd34f266bd8b7806392d52dc8cced80c52ecb6321cf3b3c911d206809faf8fda3f918f93ff507089ca4bd647ad4b5498f0ffcc7563fe5db7bcd613b84edf4a95a4f8d29e3abe0c39c8a76b6fb5db51db09a21a48d3e2c0786b6a13351715f8dca25ef288c46631b25d55a7473e5059d6a16661f948d8a7c1b4d7a21b531f915fc5a18305b6fdaadbc1f201c9a09de221ada6de8baedfa4614e578156137fbf43896cb61ce38ef386fb68d55311c63c"
+            },
+            Test {
+                input: "3a12f8508b40c32c74492b66323375dcfe49184c78f73179f3314b79e63376b8ac683f5a51f1534bd729b02b04d002f55cbd8e8fc9b5ec1ea6bbe6a0d0e7431518e6ba45d124035f9d3dce0a8bb7bf1430a9f657e0b4ea9f20eb20c786a58181a1e20a96f1628f8728a13bdf7a4b4b32fc8aa7054cc4881ae7fa19afa65c6c3ee1b3ade3192af42054a8a911b8ec1826865d46d93f1e7c5e2b7813c92a506e53886f3d4701bb93d2a681ad109c845904bb861af8af0646b6e399b38b614051d34f6842563a0f37ec00cb3d865fc5d746c4987de2a65071100883a2a9c7a2bfe1e2dd603d9ea24dc7c5fd06be",
+                output_str: "8bb1e121fc89ea0f3d79ea823d876eaa74b6ccfab369e7e4783cbcd3701875f1be59b0f8b48c2587e7001b6e7ed1821e2649069e84201583b2562e5945af5cf734e2f0c6090dc8281969cc95c861ecaeecb1cda78e8fe119b60b05c54484bac951b7784ed025fb878e29215916c5886b85b24bb2521feebec3b8766ba14fe47ee0e81dad68b238905377afdbd55e41364a12181d46d2e272bbf1fbf41a83c29ed88361435396614a23730d84684d3f5a622a233ff1ad5583fa707db008e3eed5a9716219ebf3571fb1ce9842d4a37b519767b7392f008193de676f0cd192cd6d0cf651ee5f8331b0982f150a7dcc264c1465177ab98cc590bca81e981ad2e98e47d2d855c0a74895970a96994700a5d55cbbaea2472c4160da0ef3aede987a99065948adc558e7cb9a952495f70cede70ce0e3deccb798eb58941f38c4b13c28b2e5ca4fe3a7cf3c973eb3391b705b9e9e7689e264f878396f438c393eb49e70d6a2bb0a6a92f80fdc2c2f70afbb2a1df1ec4634bc0cfdc9d1239182dfcffd30096e11fc4a32bb44cf510a44d35ec3cbfc354e088e0b53932d0de4df83a963d902971392b74d95c475d26184559f6f9f5f91502a07011b9070f8e9be5f5d1e599634e3bced756a49ac7cb273396f7acdffb3be1e441e8d8ed0588d0931353736dc1d9e889650b503a4fdbf5df7b5708d4218404306b0e11aa08067b7dbe63e8c"
+            },
+            Test {
+                input: "1861edce46fa5ad17e1ff1deae084dec580f97d0a67885dfe834b9dfac1ae076742ce9e267512ca51f6df5a455af0c5fd6abf94acea103a3370c354485a7846fb84f3ac7c2904b5b2fbf227002ce512133bb7e1c4e50057bfd1e44db33c7cdb969a99e284b184f50a14b068a1fc5009d9b298dbe92239572a7627aac02abe8f3e3b473417f36d4d2505d16b7577f4526c9d94a270a2dfe450d06da8f6fa956879a0a55cfe99e742ea555ea477ba3e9b44ccd508c375423611af92e55345dc215779b2d5119eba49c71d49b9fe3f1569fa24e5ca3e332d042422a8b8158d3ec66a80012976f31ffdf305f0c9c5e",
+                output_str: "1887576149594f7fcd27145b5f535219bbc4313e62e7abb6393d6015e8e45b48a211300f8303fb9bf370fe0a117d268624bb741e0bc343487015872e14f84b1ec1e2faeb828f521ece9e7e5efb281dfef05d86bd8eb0b51cf4c46d94ee0afc72da29c3d77eaee07e24035a68792e8eab1e0b96282e1d95b1b9d36b09d6a2e0edd37227b0d29f9e490f1d6156dfce1554e69a49b7660d288ccb6faef9a40f656a90a825a07c5ee0730926cee14ff2694a3bd105d889c88a8ca1d271727dd0fcc0ddd1ca2ee955d02cf8cda7f9e3a00b4362c69ac631523345dabd396354ad862458736d1befc4bc35ef4775f02f017ba2eb9fff9229292432ab5603ba20342e627d380824050ff61c23b5e789df2e835fd56c65febd001ee6960c782b627f90a7087ee24d32a85d0d780a8911945f3719c5ceeb9c7024dcb112c0fcdd72237040c5e964ca57ee504849e3015c200c44ca3a0eec097bf718f6959c4d3e39455976f98db5fd84f01eacbc1b2b57b6483c9e3d58ef76e18f8fbfa341e6399a3d986834e315a2762d239dbb6d1efbd60ba4ee974523d2ec7a9f0a171484d3f09d59019fcbb6a480abebfc06a21dc5af8fbf1b5388278cf84311e56329a6fc3a9426517c3cc581c8c8eada1c656e568bf108f66287fb66a405eb307eda530c18db2cdee78d8de9dcb8e93f195f54086f875935f7736c7c85eaac106f00d28d6753843c"
+            },
+            Test {
+                input: "08d0ffde3a6e4ef65608ea672e4830c12943d7187ccff08f4941cfc13e545f3b9c7ad5eebbe2b01642b486caf855c2c73f58c1e4e3391da8e2d63d96e15fd84953ae5c231911b00ad6050cd7aafdaac9b0f663ae6aab45519d0f5391a541707d479034e73a6ad805ae3598096af078f1393301493d663dd71f83869ca27ba508b7e91e81e128c1716dc3acfe3084b2201e04cf8006617eecf1b640474a5d45cfde9f4d3ef92d6d055b909892194d8a8218db6d8203a84261d200d71473d7488f3427416b6896c137d455f231071cacbc86e0415ab88aec841d96b7b8af41e05bb461a40645bf176601f1e760de5f",
+                output_str: "ea520b7cea0750c8f1ae4d7e5c80e95140d5a980d68f48807e0408a0d17dd084575191ec17a8d5b3d7a458774c453124509aee866183dfca7636d743b6b5798c4d62951d7db5640d1f4467d8703e08411270f3493241aef38fb757f00f0ee6a66c732f138294076de25f0811e8e1baf602e9f38cf92e96acf630ebeccd62c2837dc0f361c014698b3ccf586d372bb0591aafe68d138e1fbf05d205a6124b0ae5f483bbb429eb1bd517c799fbd2b9a154fdb7f687dd320106793d95d2acecfcb4811c627b3287490116c5f5a3082b0c2bb3b703fb2bd92b65e1cc07c61e1ad67c0f5b45c33c981e56cebd6c12d00d9d33c5dac18a41c1025ad24798de28518e5faa6ceca295cd13254367f04cac72fe0a0fe87214103fbdcd9af3fde362d6b7c0997b86cddab824210d1896deb7c75a3eb92be415f450cd62caa1fe4d7a9da2e8b57f2c31999f81ca8a22936684133ddde9fbec522c92b928191220e75f8fd20c29a1da662455fe7b94a2292006052b354db4f03375acb65044c2fdaeb977ca8e81318d2ea95c3981ce76dd9292678bc5f05351d2b4a4a410dec6790dcfa90ab7d9f8d7fe71b1a1e22bfc3ef06f21c7c99f01e11060abd9122dd3ffa6f0c2b402d15c6d4e8f8524a5ae6f1248b6878170f8b4a7d95c85b04587066e340156d80b20e708f5470801f4a5f46a74dee3332fb0adf0472ccd592b2462eae969ac5140"
+            },
+            Test {
+                input: "d782abb72a5be3392757be02d3e45be6e2099d6f000d042c8a543f50ed6ebc055a7f133b0dd8e9bc348536edcaae2e12ec18e8837df7a1b3c87ec46d50c241dee820fd586197552dc20beea50f445a07a38f1768a39e2b2ff05dddedf751f1def612d2e4d810daa3a0cc904516f9a43af660315385178a529e51f8aae141808c8bc5d7b60cac26bb984ac1890d0436ef780426c547e94a7b08f01acbfc4a3825eae04f520a9016f2fb8bf5165ed12736fc71e36a49a73614739eaa3ec834069b1b40f1350c2b3ab885c02c640b9f7686ed5f99527e41cfcd796fe4c256c9173186c226169ff257954ebda81c0e5f99",
+                output_str: "aa38a2aa24d83c0055c05a4d8e5fd6e538ddecddbc6876d816900f4329a5e6d00a25b14ca626f3c9185590a151e438cec7164bd7135bf60afb78aa0c4148febb606c50a0449360952c1bd6c4654804102521315e457afdfa185565d96b6b230a4b36e0dbf215b19fb9b0bb3cfd6a8cc2e4abd6a1a50d978ebb5d351f7a65d39855e9ae57d7343e8ff7eb6fe7974791edf14861f30a428cfa9fa08e3ec4c4f1c6c5cf29a06d777459aecc379bf17e89a54b753fcbf3846835cee9fa834cb294ae3699893adc7de63d96f1f7cb60739e7d672a9d70078f9903f6617ead83ec5847424ebdb89b9a07762887f3a4ce8b7a839f0ffdee21822ddf92a73e85f112d2a6e023c620056e97e3435ccc172e768a195ba50f0238ad3a474fddad6ecd5b90262170dd026826f69cc2ace1d7d9aaba9f14c73c6f114ed5e5f75679679b7a2ecc81432bcba993c4e1caad6db7d9908b56e1404ee5080641a4d261d488457a1da7d5e1f09bfe9db23e3cd4be23b8fa84c93011958d57588a06d8df433428aa13cefd6ec348a52e0076564f0dc849058a601137835f90478b41bd58d24ed9b5e4ee5940a0963bb4fd7a2f5817be1903ab7d960f58ef88a310675ac0452ac6d1ee0cd65e2114865c4adf78b983eb7e894f28a716abbc766a1bab1858641c8cba3a18ba55584a1fdc2f80a61c36a9a56cd0289257ca0402ed99bc680aadcb29287119"
+            },
+            Test {
+                input: "5fce8109a358570e40983e1184e541833bb9091e280f258cfb144387b05d190e431cb19baa67273ba0c58abe91308e1844dcd0b3678baa42f335f2fa05267a0240b3c718a5942b3b3e3bfa98a55c25a1466e8d7a603722cb2bbf03afa54cd769a99f310735ee5a05dae2c22d397bd95635f58c48a67f90e1b73aafcd3f82117f0166657838691005b18da6f341d6e90fc1cdb352b30fae45d348294e501b63252de14740f2b85ae5299ddec3172de8b6d0ba219a20a23bb5e10ff434d39db3f583305e9f5c039d98569e377b75a70ab837d1df269b8a4b566f40bb91b577455fd3c356c914fa06b9a7ce24c7317a172d",
+                output_str: "42db17a940111f1a93b0d583f6173991252286bc5098e136d27196697ae45b878767e17aa8e826dcde186cd76f2024e6772a0dec4c4a8db71959d75cfef0f20cbccd85f15ab5960c0ccda5f14ba0f02958752a0494d4b50e2cc67c554196bfc061f651440c6812cf5319639f93df1fe51d1511df6a3a6aa6538f46ea2d00a3a0f64b25cc9ee8ad05e321649987c36387e2d31da77edc1afa9632d77ee2d4ed54992bd51490a34dd743dcec567de957d55505d1d8dd43be3309f25ae61275203bd9743f3027b9f34b34db7504c2d7fd1aa99b936e7284f9e252df2e3359d868c0c83ab140e14c01b4b650d99ac6dc54ab35dd825116ea96c5fe88822b2d7182fbe9b3f3cfbedee129ef0814c171a207fc9793e1eb72edcd605c3e3b1534106093aa550bc8cff8de3c5d7152f18c87e161da0fc90594161f03b0ff9f9edd41f360db7347b067d8fe1e901d78a77f1ec44e33ed7aadd463c7d676e50b03a92b5417628cf986d5f93197333bfeb5d7b6a7c7863707b7ec032e3f5c62ca6a02938313140e62479842f4cf68a54a14ae0ab35538025920f317039169636f35f02a8e05c344e15492ea02164c62392b0795d4889f7ab68ac969b3b096c21cfe179833ba5fb857751c4713fc928b4623db593c9458aa36ba3b3693e07c3c5c84470f77e5cbdfd9770877a0999dcf8ff1ae27f51b65aaef9754e8a71739ac00be0f9458e0"
+            },
+            Test {
+                input: "6172f1971a6e1e4e6170afbad95d5fec99bf69b24b674bc17dd78011615e502de6f56b86b1a71d3f4348087218ac7b7d09302993be272e4a591968aef18a1262d665610d1070ee91cc8da36e1f841a69a7a682c580e836941d21d909a3afc1f0b963e1ca5ab193e124a1a53df1c587470e5881fb54dae1b0d840f0c8f9d1b04c645ba1041c7d8dbf22030a623aa15638b3d99a2c400ff76f3252079af88d2b37f35ee66c1ad7801a28d3d388ac450b97d5f0f79e4541755356b3b1a5696b023f39ab7ab5f28df4202936bc97393b93bc915cb159ea1bd7a0a414cb4b7a1ac3af68f50d79f0c9c7314e750f7d02faa58bfa",
+                output_str: "82f8c16b8487e008284598fed9c5670c86fe35c8dea51ac59d38722829c94094bb2766aa4cda3139a15dd2ac0309253ec1a15b2969f84899637d3e2a5d55ed1e87561a546a2a7c190008bcf3bec233ebd1dd55242d7fac3a522c6016e62670f66edb6290afe801630e2bccabb450e4d44a9bd8f63d4b04e9f280a2a0972ab229351906f5f32de714867e8f04d276488f2aa5e62db8b634287404a73723abb7e152107a6da60f0c7efaa953db706398a09835e5edd99393db5a162fe3e564298395fcdaae8fa7e7a9081b8e14fa0e99e433e0d44326dc2e9e33378ea719ef780d303589f0a63841b5d5d74ec6e2bb073b55287a6419bc6af759d13f8c8875c372c12d392d7f80608412eb9a92a786048bf9a6f03d11c48f48b96fbe8bba329268242a5463c49b112ad71b8ec42a9a7f272f25819509e5c7a10d9c9f1a386e034be2a89ae28917cf014156211c795d9d6efb267d8f2bc48b5aa767cf8269a6e349701e77ef69f03fbb56c8e2a0c90905f1fda649b75d716c67894e932c63b13911c80339a1df4b7ae2035c7572bbb599e66e7cd9cf447f4f1f1deb63f64508ebe19485db3eb98607f3c87dea60faa331310fb4ba5730ce4024e07b4b134286472bc7b6c816c3f680618941f96539b81df82cd15edd426206f363a9e487c9fadbbb9db90da8f2d73e940c515a7b4ffa07443d35caa0c89ee9e511d66c2c8fe2f0ff"
+            },
+            Test {
+                input: "5668ecd99dfbe215c4118398ac9c9eaf1a1433fab4ccdd3968064752b625ea944731f75d48a27d047d67547f14dd0ffaa55fa5e29f7af0d161d85eafc4f2029b717c918eab9d304543290bdba7158b68020c0ba4e079bc95b5bc0fc044a992b94b4ccd3bd66d0eabb5dbbab904d62e00752c4e3b0091d773bcf4c14b4377da3efff824b1cb2fa01b32d1e46c909e626ed2dae920f4c7dbeb635bc754facbd8d49beba3f23c1c41ccbfcd0ee0c114e69737f5597c0bf1d859f0c767e18002ae8e39c26261ffde2920d3d0baf0e906138696cfe5b7e32b600f45df3aaa39932f3a7df95b60fa8712a2271fcaf3911ce7b511b1",
+                output_str: "706ca15167517d46c47844d044d0fc94cac5d23b90bdb64ce0a2df052ab37c967e57a476fa23c4d3c160c47371cbadc07a48d6a7c0e0b8ce8b337cac62e74e10b68c6fbb109b03547ce998780b605429d6e3061334c702b218c1d6686e3e8c7fcc2c4dec034b9fe68572b45e58de9661216d6a232d13a0eddda45892a4abab666cb528694de50a50d1368be99d257bc8c245429fe55000d3c9cc861fe9228e6ebfb7ddc53148b530e2ffe153b8f40007ed321b4464c0bd5de00c9791073b199ad57f6c242f7cb772ff05a06d010d156ad35dd0ed74c9593855576b1c7a4360770aa88bbf56b65395b163471e4057d27b59b554eeccd9ab8f24f457e400150c5f83b55d703620d68ecd7a01a9b3fec468b75c0f8bbbb08388318d50d38becdcd30f8644a2ebd11fd8e1d103af5f9b64d92bec64fddeffc73d9932871ccd1dc62515f0efa438393109c638f5c11405fd923d784b217f3417bec855a7ca290253cdd902802ebf400015cc2af646aef63684abb39bb98aa598ab767ac4df96cdf631d0500bc61dc822f2c54d761f0c926e023310ac11f3748e8a75564fbdb7039cdd3a42b601339be64bbda4b3f70899700fbda55d1337f5e33f5b00df97e6ca218d212eb771ecfe27b265a8ee8ac9d9f34baf279c49b318ebfba497ce77233cac4a9146ef5df7b93672a553a3ec46dafe8b7f93f233161fb91f5bca89db4d5f2c42"
+            },
+            Test {
+                input: "03d625488354df30e3f875a68edfcf340e8366a8e1ab67f9d5c5486a96829dfac0578289082b2a62117e1cf418b43b90e0adc881fc6ae8105c888e9ecd21aea1c9ae1a4038dfd17378fed71d02ae492087d7cdcd98f746855227967cb1ab4714261ee3bead3f4db118329d3ebef4bc48a875c19ba763966da0ebea800e01b2f50b00e9dd4caca6dcb314d00184ef71ea2391d760c950710db4a70f9212ffc54861f9dc752ce18867b8ad0c48df8466ef7231e7ac567f0eb55099e622ebb86cb237520190a61c66ad34f1f4e289cb3282ae3eaac6152ed24d2c92bae5a7658252a53c49b7b02dfe54fdb2e90074b6cf310ac661",
+                output_str: "a90a149c4b7ba649888f90721e9ff91cc3589e2094b07909959c9a15ff010c610824f7a49ad3ca2864089e93ad7075c1966033ab55e9263871ddd56943d568fe0867221034994b74a3f855544e77e313a29efba367f309243db8a3027eb4da5371439cf39c21eb57823e1e6c73c0707356b68828aac6c8fd05f222f4c58b33cea1aa6344dc33fa88d9a5becc263b7cbf00045378910814c77c2224e56d913d2cbdc48ea6700de0e0306b499a3888f535274069e7ed493c12d46d23b7344cdc11b3433e39ed9cfaea6787704ffd63bee0072ba60f526fb52daddb41ec7e8216ac2a79bbe27e315a2e2824e1dd0bc2943f92393550aa6dc75f1c9755e5d8f811cedbc2139805d5599c1e1f6d4f56aad38e91ffb529a4820f260d752a93d7be57bc2f75234fa615ac72afec7619e0f26071d8a3c90f1fb486497d5af0ee45fd9d0b4aa0e07201b9e5f277e73d48edfbf75df8c3f1a635a733591615c392ce37738851d2ae847c6eb9ab5d91dcda7e953041cc6cf02f0e6604e8ae5756de528645feaa0e8f1c5f6f0c53abb72f84d0397a39a7fa3c7e8bc72b237e0d8b81c91ed18e09273ca20b763d34b779bb79d95c3749aaa703de53fd7fcfb361e2d3e13068fa076021c1373ce99dda0ddf931d2bedd095a3f95e41a0b09c56d01253f29558348d6f841908984e3096a7a0da6de77a5db124aa442edc394126c2f67b1b4a0dee"
+            },
+            Test {
+                input: "2edc282ffb90b97118dd03aaa03b145f363905e3cbd2d50ecd692b37bf000185c651d3e9726c690d3773ec1e48510e42b17742b0b0377e7de6b8f55e00a8a4db4740cee6db0830529dd19617501dc1e9359aa3bcf147e0a76b3ab70c4984c13e339e6806bb35e683af8527093670859f3d8a0fc7d493bcba6bb12b5f65e71e705ca5d6c948d66ed3d730b26db395b3447737c26fad089aa0ad0e306cb28bf0acf106f89af3745f0ec72d534968cca543cd2ca50c94b1456743254e358c1317c07a07bf2b0eca438a709367fafc89a57239028fc5fecfd53b8ef958ef10ee0608b7f5cb9923ad97058ec067700cc746c127a61ee3",
+                output_str: "fcd5fef0de750c6be7615bcb850676e9e83299c522bdc14fbac162f927b0aa4ea6dd76e43b1500c72be0d569566b57054b9340216904d518ecdb25ef39a62891290a1034f262a5e2c0fb37333bbd24323730cfd40fc161edc37eeb7c69769d3ab1f1454560ca78fb96cf133689ef8e75f57c2442e2cbae4f5c648666bfc7fa5da87e7c0dd4816292dfd56b2bcb383b3ff971185b724430f9596f3509c767e159873614b1d4ec45fa8586ec2321b791560785e5e3ce13ad5e8e1550a3290175acf2d78cdd17c0ea205ed7c1396bf9dc0844168ba3a66b4cb01c22629c80577de68d72edb44b419b13a2db6d67877d9cc0a0201c14dad69f25c88c3418ac45ea0d7ada58a02bb7dd0c276dfab29164e1844bad901acb6374ab75e21bfe2f3591b2c8f111a4606c8c52d85b4c073fdbbf25fc81758214ca172fbfe1c6b14476532f35f981c312739ce435f7ad3d0785dcd648e2a5391b64525a8785f3e06446c6bc1e09bfa19c7ce52651bfe1a2e355cd7c1c9ced6540d33194a2212b2a8768e7347042b560f68b4e22e42ed8f51c38375f9fa45c133a90d4f6f17cd5bf19dc9e1035df78f7e0077411bfd0fda23e6759388afc45485bf271c8fdb316a32b898c3d6dcc0738b3aa043acd1848fb7c6fe86a844fc764953d392569520e78fa11bcd6b0af3be8e7bcb0006f56881889cdde27870fe7c9e703f57b6cbe0d6372f2322b"
+            },
+            Test {
+                input: "90b28a6aa1fe533915bcb8e81ed6cacdc10962b7ff82474f845eeb86977600cf70b07ba8e3796141ee340e3fce842a38a50afbe90301a3bdcc591f2e7d9de53e495525560b908c892439990a2ca2679c5539ffdf636777ad9c1cdef809cda9e8dcdb451abb9e9c17efa4379abd24b182bd981cafc792640a183b61694301d04c5b3eaad694a6bd4cc06ef5da8fa23b4fa2a64559c5a68397930079d250c51bcf00e2b16a6c49171433b0aadfd80231276560b80458dd77089b7a1bbcc9e7e4b9f881eacd6c92c4318348a13f4914eb27115a1cfc5d16d7fd94954c3532efaca2cab025103b2d02c6fd71da3a77f417d7932685888a",
+                output_str: "d4c1f39098d123b0dd88504ff6ab424e31f5d3726efbf86500ce730bae87ec671c97f768f9593c8411b57e306b0cb394f33b866493bbfc3f089fa4e875858fbce814debb905fa7249f7dbe737f5f6725cf76d2a50b319d96bfcd55e03a6e923b01003e6d5976a66aa5250c337c9c4c402b9733c8f626789fb23ff1043494a73960297ca9110d23def1d72b601f6c42cf83938003b3a386cdded4a70b24975c958597894fd6e2c412cdc6e32ea7f398242f84d4f4bd469dee9ad10b717ebaa26f2481224f47135219231279c36867751a476af60ac4af8f151f301cacf5d7890d62a135b44149cc7405208212b7547ec0617abf96a7741eb2e08d18aaa17357b4f2ddab92257e893cfcb91bdd73dff3f8e6c28fdf38dc89094c719e69508af7abee4d1403e0f139348632a45708aab27d4403f5d5b85a81ac72ede9e2448f1fb87571cca3631bda9f9d0dc060000b03450fbc7d98af74f0b0a8a1bbdeed01c4c8300b05e05cf7af7824b246666eb53119fcfaad3c7aaeefe0274a55abc01abf0a38189e46cd3ce56f0a4db8e9b498eec68e03db7fdc9177230dfc72f45a41a7064f42f3c527a5e5473b2f68d1c8ba960bd3b458be2bef2c3623b38a66266eacea3cc93c09f4cf566327e78ec39ce5541e48142fef380af5161ed9c63724fa16384f574b1d1cbc3f1c852028cb9a8d1f411d6ac119e11e6202e566b49341d40d19"
+            },
+            Test {
+                input: "2969447d175490f2aa9bb055014dbef2e6854c95f8d60950bfe8c0be8de254c26b2d31b9e4de9c68c9adf49e4ee9b1c2850967f29f5d08738483b417bb96b2a56f0c8aca632b552059c59aac3f61f7b45c966b75f1d9931ff4e596406378cee91aaa726a3a84c33f37e9cdbe626b5745a0b06064a8a8d56e53aaf102d23dd9df0a3fdf7a638509a6761a33fa42fa8ddbd8e16159c93008b53765019c3f0e9f10b144ce2ac57f5d7297f9c9949e4ff68b70d339f87501ce8550b772f32c6da8ad2ce2100a895d8b08fa1eead7c376b407709703c510b50f87e73e43f8e7348f87c3832a547ef2bbe5799abedcf5e1f372ea809233f006",
+                output_str: "d6fc1e61d2bc27ca5dd5acd290c2831070e66c38f03d2dc91184aa9eaeaf03a28e009a1ae1c775f4274b3ae6b5491c9b0c838cf90d185fe94c49ef46ababa62d6ed1f550d83466efc6b97789ca36ad1a6a3e6703a5da9764e47f29c8096e3d317fc7aff0b79b1c278610afe3f5e7fa7fd52fd36cc9e7000da809346281eeba1ee9bb06aad61f3e02cf4a5bb7b211e2437ed21437fae78378f28b14184b7de7e80e845837a483c0c6df8e233687f71f0f9745d585411f103356a0c474f9238403e40960f63a3418199325ea6e8eada31c94f78cff1b83a2efa4e49045e0ce34a5c61025399328cd7f79a1e4cc792d8ae9f1aa954235b515158be5f4064b889c14a3a83ab59cf26945dbbf70f3a5f3bdbe8674546d6df384c40d56b286d309a114871bc18e144d2334c88c32f141f6dfa70859a9ff7d4996bd3faba0299794e861db8be8a324822c4b1dfbfa70f8d9149c3dc01e0e556dc744c98fc2f92c8600c856bd174759af467d6618c4347366ce04d06a0ee4feb9a27b79bed01beb7dee41859c1306939d55b0e319dd2e0e001f6174361cb804cd3ac3332b8d8a1d8204d5255f81faa0bdc29ae71693586c987e35c81e314a3848b03cf7b37eaee2ad6ed4736e1f20a098ddaec612aee17294313da16453d7901cf80fc729962206ad4820b00e8ef0d999857832256e5b784e8a89dfddd38f6e15de081a82e19a2a05d417"
+            },
+            Test {
+                input: "721645633a44a2c78b19024eaecf58575ab23c27190833c26875dc0f0d50b46aea9c343d82ea7d5b3e50ec700545c615daeaea64726a0f05607576dcd396d812b03fb6551c641087856d050b10e6a4d5577b82a98afb89cee8594c9dc19e79feff0382fcfd127f1b803a4b9946f4ac9a4378e1e6e041b1389a53e3450cd32d9d2941b0cbabdb50da8ea2513145164c3ab6bcbd251c448d2d4b087ac57a59c2285d564f16da4ed5e607ed979592146ffb0ef3f3db308fb342df5eb5924a48256fc763141a278814c82d6d6348577545870ae3a83c7230ac02a1540fe1798f7ef09e335a865a2ae0949b21e4f748fb8a51f44750e213a8fb",
+                output_str: "f61115ae2fd5442877d08e39a57df8d4a5f117d57c2688617a8da64f9482f5a817e0d3dfe41a9cff331f4d5e3240da38e43b7b87925fe378512cd83172fc3cc2396a8acdbf5010ca576603581bf7df6d7529423709b30db81620b9f660b5aa82ea6c98656da27b4709da85d364ec015c2eaaf2aadeda2c040badfab16f7c2ae39da6a1691057301b7c3252884cd9ee079e68857d6d3b7f4f85556140db03421f09e98b80a8422500a349b5c0d8ffb25433a4121b7682f8517500930e5f2766c687846553c9f76de38a0ee41f76d3a22696b95774bd5eb747f6445d8044147ee38b127892f4b0b1932470b454f8f1bb697a2f6659ab13f3e2003c97d292a7878e12ce47aa9619fcfe2135d8890710b2733df40fc75dad57b99042e4f54aea9332ed52cab8ffde5195eda05368b09e9fd55731da20012a7d255aaa33d74e22917e58bd546ee90947a16044b14dfffab05916c382d1f038b63d2f20dc09c117c8724a4db3970b7cb143b1522d010881fe6663410db3400db33b62a6e70dfd48c2fe773054e1494944b60fc5d3bc803027c4b12e6a230fe41ca4d072f3628d20782cd7de4e98a29df083fef503e46eefa787f8b0e9b1e7c884b9122977532bd71fb63120c1069156516d265fe3559b18965e968b9bbd653484866847e76262d0ccbee8fb0314a8c40b8c35725337ca4a241592e47d5b8981d3212c62ae7e25f27495"
+            },
+            Test {
+                input: "6b860d39725a14b498bb714574b4d37ca787404768f64c648b1751b353ac92bac2c3a28ea909fdf0423336401a02e63ec24325300d823b6864bb701f9d7c7a1f8ec9d0ae3584aa6dd62ea1997cd831b4babd9a4da50932d4efda745c61e4130890e156aee6113716daf95764222a91187db2effea49d5d0596102d619bd26a616bbfda8335505fbb0d90b4c180d1a2335b91538e1668f9f9642790b4e55f9cab0fe2bdd2935d001ee6419abab5457880d0dbff20ed8758f4c20fe759efb33141cf0e892587fe8187e5fbc57786b7e8b089612c936dfc03d27efbbe7c8673f1606bd51d5ff386f4a7ab68edf59f385eb1291f117bfe717399",
+                output_str: "3bbf30faf9241c9e3e27ec2c17ab24aa3673799371528cb98a6d9b91e553553680505d7cd6590377ab54e5dc7d7c72035300af651ab0ea52aba9fe1d490ee5c95b146138f61f957c5cec8d4633175c99a00590ddb987d2e032547d99c691b32c12d7392742a5ae47d03b5a08a544548bbec45b9580de1cecb7b9f06a88614daa116d7200dc8e81ef3c7c5a716044133d2a66ffbfa35e1668fed9c1045da77df92564f60087d173f71b75f040bc6cc149234659c1213beef18c53cdefef2ff466a2f16823d7659e04ad61f6b23ddca8bf35af892bfb8a952df4ed254ffac52cf71f4c872ef15ef11fae9967fc8f1c218e7caba5382936f4cbbdf7f41aa2a239bcf36fe158b7d771becf8981ddaaac31f744d949396623cb3bb754189fb5e78dd94171c1bd6ad3953dda6d4dacd3b57d37b1b73fab0d2caa0b5b3f6a2c9f324f4b93c912991e50f8872bc276451969ff379aaefc3c710de16128136ae0d1268d106bbce2aa4d2db0c5edb171dff104df4f7d49fe017c82083dd1e9f7dee489bb38ce091c222c3a0898f17a0da1d4b2830c7b7c3c372fdf2a4e9cd7b468107513d6e3adcc91f662218a7364a7340966a4d692cf394443203dce8b33503aee6c1259bbcf36351af93ef01764be4863759ed0abca9e59ca6004f2e5738af7efc7be8f9a1e106551b77aefbff9dbe99ed5abb12207cf38f7fb9ba77d776fa0df3bfaac"
+            },
+            Test {
+                input: "6a01830af3889a25183244decb508bd01253d5b508ab490d3124afbf42626b2e70894e9b562b288d0a2450cfacf14a0ddae5c04716e5a0082c33981f6037d23d5e045ee1ef2283fb8b6378a914c5d9441627a722c282ff452e25a7ea608d69cee4393a0725d17963d0342684f255496d8a18c2961145315130549311fc07f0312fb78e6077334f87eaa873bee8aa95698996eb21375eb2b4ef53c14401207deb4568398e5dd9a7cf97e8c9663e23334b46912f8344c19efcf8c2ba6f04325f1a27e062b62a58d0766fc6db4d2c6a1928604b0175d872d16b7908ebc041761187cc785526c2a3873feac3a642bb39f5351550af9770c328af7b",
+                output_str: "32ffbc063291bd2c957dcdc76632dd1bce0dbfcac549228d277d81b6abba904d43330ef8081e164d8fcaf520e12b388c40168295a63d365b57a7694d4c50812b99c86e036116a07f0164b7088537688d4baf1e0fcdc84c6da8d92789466a606f1ee25ce7461fa65df04bdebc24a3a4bac3b02b469c8e85f53d9481dbe244dc67b8bce84cc7175113d4d7b2413601e9140b7802d9fb712938e9c5034ceea753b7c77c08bc1c03d511ed0b4d5007bbac38ee76b675b73aef8623ca9ccd579e28bae7d695be25fbdb673f3401a75d5a57d142034a7bee554ed30cc7f03cbb363c10a54f818937ae468f5845ada4f9a2a1bf6887105879da745aae64d87f26f489a622370405ada3d3688697db8f04557736c51725aca02e4b76f6a9e88dc6d52d5a63806bba1bd687faac522d7b5b0a8d6073283659056e784320822eaf70666180adfdba2675b4ead6f6b2ef826e7598bbd8c1956a15c1864d249368900d82498297c3e77a19ebe20a111d13fc03ca88d9332f919ea4ad15be8e397aba0a4e2ba85f3fa5999eb553780f0d2f35d76a63b0106406fc3b4550476572e1464c986870027849ada0f164b48b839ecd3ca9afeadee3f63aa6ca06c635990922995db0bb99a4ac4b7f3aac52069f3130660ae0f074fbaa1d103a086b59aee4da3188cca3227670fd43597abfc1a2f6cfa67fa24ef0b20b4aade9ce8e68cab34111d10464"
+            },
+            Test {
+                input: "b3c5e74b69933c2533106c563b4ca20238f2b6e675e8681e34a389894785bdade59652d4a73d80a5c85bd454fd1e9ffdad1c3815f5038e9ef432aac5c3c4fe840cc370cf86580a6011778bbedaf511a51b56d1a2eb68394aa299e26da9ada6a2f39b9faff7fba457689b9c1a577b2a1e505fdf75c7a0a64b1df81b3a356001bf0df4e02a1fc59f651c9d585ec6224bb279c6beba2966e8882d68376081b987468e7aed1ef90ebd090ae825795cdca1b4f09a979c8dfc21a48d8a53cdbb26c4db547fc06efe2f9850edd2685a4661cb4911f165d4b63ef25b87d0a96d3dff6ab0758999aad214d07bd4f133a6734fde445fe474711b69a98f7e2b",
+                output_str: "ba2b1cec1bbb46ea19af7a869fdc73cb3791708defdf530dc9999e9510fcb02aef571b3c5e7258d86dc80edb53b71644110b9e82c239ff17ef523840e6af4d597d814d4e5ec2ea98e451c05318402d5bff6e6e573565ab640e00bf6f8c3646b3f6656047c60ed43393af7f2d8df8915a0f6f44d69fe193dd5617fe39bda638e4ddda771b0e771318a53adecbdbff07d6cfeaa04a837034c6ea0e70c8fc244304804e0e890f31f951007a2f897bf3f00221b63ea3dd8d9d1dd3608596ef7817190d56d36eb99266f83b7f1a2080f7a5405cde86017948bf977c6cc78565b3eec570b36fc06566909951f31cad6094f296f759e858bf7aa9298b2f4f7f5c3167c145ec126c40f6e5dccd87c82489400ff8b9b79b19e472596618eed3fbc6fe5545bb3276ed710ca128a3c2fa9b831fa6fa3b126380c4baed23d9186fac830891f98c81d401a6513e139f6546f065e8af6e1a9595218a025d8292176f8acc4acaee6308c08db5215fc0064d7279ff6165033e0946fb7c10bf5dec2d26950b2abdf71ae2b5bab856386a25117214d5830b7d5e250fdf200cc5eea0085648fa2aab6eec363da41afd82e14eda957ea3ab7c65100f4a8071aca6f1891b5465b7c46caa9612ccb0875369cec4bcf9d99be35e03ae57c83fc80903afe25ecf23d016cf6989eda5b900efcf59c529fd299cf155a1310b239cd364301f520d16c74e270d0d"
+            },
+            Test {
+                input: "83af34279ccb5430febec07a81950d30f4b66f484826afee7456f0071a51e1bbc55570b5cc7ec6f9309c17bf5befdd7c6ba6e968cf218a2b34bd5cf927ab846e38a40bbd81759e9e33381016a755f699df35d660007b5eadf292feefb735207ebf70b5bd17834f7bfa0e16cb219ad4af524ab1ea37334aa66435e5d397fc0a065c411ebbce32c240b90476d307ce802ec82c1c49bc1bec48c0675ec2a6c6f3ed3e5b741d13437095707c565e10d8a20b8c20468ff9514fcf31b4249cd82dcee58c0a2af538b291a87e3390d737191a07484a5d3f3fb8c8f15ce056e5e5f8febe5e1fb59d6740980aa06ca8a0c20f5712b4cde5d032e92ab89f0ae1",
+                output_str: "481cf76e2ed1a1eb74050e9632a3bce4913d2d516e251816a2d55706314d6483b955b87b0a6ee013f248e2ab4517b800e23c8ad85926c36eabab1f2c36625d0492c7f001760e3715eba80aa912f5e3e1a7918d1ede2fa7fdcbbae23ff75adb2bd88527bce6f02fef73175487781f26c7c7dbfd04143b70d636217abf7ef69364b8b7c493c64434dd1ccb523e5cbcc81211a64fefa9f41ffdb38d9d8d5e0a9e51be38dcce5225652cab5a0ef8d8ee7dd175b929aba19480299176d7122ce1a763345a091aeb8c5df8ab37cd4d96c3230e8ea847c1d28986d3398dea80f2c48c3b4406524bcd4850dc02621b470ac7df27372d95822795e8a2d81aaccd72f535110fa01fdf0cabd7d848960603b80758406ffa78fb6c68db4fdf40c146318c2d296cd1a5bd7c1e11ea967b72792a3a7fbac9089588d3fb555f122f7afb499aa3b3c43e07bd3d8f9fe980213c174d37db9fbc8ecd318cc207689766a327614ed6b01bb0a5a2cf04f5b54edd97be72e5f894328ee86a1c9d2ffb65c9fd0fea4ba865d0ea4f16def67ce1d6d42095c1c8488376a4326396fe3448484754153b2d4a94c442bde7cf67e8b9994e958d3cc17d5b0fd7a4f203024ec29cebf40b549f2936cc6c196ab83ec8c4585d28e31d3ecf5bb59ab24b2cc6908e51a9bcd5bbcfa92c02e61b08ca7e3aaaed73c450909c8b9bdb422ccab0a86c5a5c3c10a634b17332"
+            },
+            Test {
+                input: "a7ed84749ccc56bb1dfba57119d279d412b8a986886d810f067af349e8749e9ea746a60b03742636c464fc1ee233acc52c1983914692b64309edfdf29f1ab912ec3e8da074d3f1d231511f5756f0b6eead3e89a6a88fe330a10face267bffbfc3e3090c7fd9a850561f363ad75ea881e7244f80ff55802d5ef7a1a4e7b89fcfa80f16df54d1b056ee637e6964b9e0ffd15b6196bdd7db270c56b47251485348e49813b4eb9ed122a01b3ea45ad5e1a929df61d5c0f3e77e1fdc356b63883a60e9cbb9fc3e00c2f32dbd469659883f690c6772e335f617bc33f161d6f6984252ee12e62b6000ac5231e0c9bc65be223d8dfd94c5004a101af9fd6c0fb",
+                output_str: "47929c7d0c4db7f9ebaef5ea93bbc7b255c8e249edf893257c7aeb996cc8eeab1a6ca4520f4d4257144cd5a9a850a372bd00dcca339c4781479e976b7508688dc63783ca9ec7a9fb8196721c8c24aff5bf9385453e9b85a1f7fc75a029e09d45910dc24f1304d1e51ec702e79dc731b6120596bf3df30dc0f756834ac0bb94f99243eac8910015d10dc618252a77d8b900c4141cff2461c408c19b978d1b58e690815c0c07b901137a45f045abbd85428acf51410135eb27128ec6725062665d1e6a6b8ebad3b81d36770b0cd14303b9264d25dfee14b27798e22b46a77adf456fdafeb6d597f7e3152aad40e29ab7e7808a4e46f43e18856518ce6d716062029024afe0ef0a7f3783f755977f8b10eec658aabc20b2ee0e8d3ade73e2a7e78e4cec3c09ada3089247c678238580891ada460d60da297a4eb7ddba67d117e21e7461bce7cfc7573352696b4643d6d9c9ec97eb431f6159ac438479bc6547ba04552748171f4aeaaa2ef0dd7eccb4abdb2e07ab536f0183516b1dcbf0e12fd134f9ad85b854afdcce14c1c52d0bf1ee1e52a12fdd63632d9df1b78e7899b03527da8597124ae3c8797e6832138508ab89069bf692a9e5d102ca20807a4bd5033d7bf7c918998d3d52b240b8449d12b402ee7f50b211f597f1bd39b69a4dff9a0e6dbe347ac1137b3631dd15f97217a5bfe2c6579bc3c44f8789ded23efec51a64"
+            },
+            Test {
+                input: "a6fe30dcfcda1a329e82ab50e32b5f50eb25c873c5d2305860a835aecee6264aa36a47429922c4b8b3afd00da16035830edb897831c4e7b00f2c23fc0b15fdc30d85fb70c30c431c638e1a25b51caf1d7e8b050b7f89bfb30f59f0f20fecff3d639abc4255b3868fc45dd81e47eb12ab40f2aac735df5d1dc1ad997cefc4d836b854cee9ac02900036f3867fe0d84afff37bde3308c2206c62c4743375094108877c73b87b2546fe05ea137bedfc06a2796274099a0d554da8f7d7223a48cbf31b7decaa1ebc8b145763e3673168c1b1b715c1cd99ecd3ddb238b06049885ecad9347c2436dff32c771f34a38587a44a82c5d3d137a03caa27e66c8ff6",
+                output_str: "401a2897fca682a6949d88f939ecf943140eca42f90d86d2dc301efea2dbd4c03998d686dcec124334f0c5ba7674f25cdbf36fb9480e8db2111ba4e78221d1855893a526f97535936aac3d88d8908786bf5a9334eee1a4d9b346a95573993db7c9c7a75ce692df5118963083b778865396501845e12e4ddde82035b03a6c43697cdb2b1c5c4eb24d0d484acb105549290b9fcd5c8b4ee31d4eb542a2c9637d8e34687b18ab2dcf92a826877f9f1766ecbc43e3879e481c4b6ad994586f110818a20b6f93c8ced8c1fbc0b54572714ef722e83046a93ce23d118e494969d5bd1a9e9c744c5a56d193d2bc7054a4a0bb22987aa2ca672e69c2b733c860f292c4f218557b7b921c4367b611e1d7fe30cf454eebf09990c5acd7b43a174a92e0b8d8180dfd409261274ff09f55013a7f58242d29330426bd4d8ef8365e4de86469c436fc0fdc3b858eee3e29c2ed6f650266a7b34d2a0e5ed438e60891df92fe6b950d95bb99f90344fc5ef5b210692059e9f859a476a3aff4bb478f5dda80629e236afd3742e35f46046bdf1522590562c8337c39fd38b8f57cedd49198f8242d951330fc4d0bdf5413345bb7315eeb67e4b1d561d185fadf23c0979b036d885391643d7514b3fabcd16382ccc49e6b7c0707b90ac0f86176dcf9d7f1dcd270374d2ab8e1e9fafb7dec0f952fbd4456c9e7fcda80cf0a46ce98af6e9b588a370741"
+            },
+            Test {
+                input: "83167ff53704c3aa19e9fb3303539759c46dd4091a52ddae9ad86408b69335989e61414bc20ab4d01220e35241eff5c9522b079fba597674c8d716fe441e566110b6211531ceccf8fd06bc8e511d00785e57788ed9a1c5c73524f01830d2e1148c92d0edc97113e3b7b5cd3049627abdb8b39dd4d6890e0ee91993f92b03354a88f52251c546e64434d9c3d74544f23fb93e5a2d2f1fb15545b4e1367c97335b0291944c8b730ad3d4789273fa44fb98d78a36c3c3764abeeac7c569c1e43a352e5b770c3504f87090dee075a1c4c85c0c39cf421bdcc615f9eff6cb4fe6468004aece5f30e1ecc6db22ad9939bb2b0ccc96521dfbf4ae008b5b46bc006e",
+                output_str: "8e756b09ee1679dfb957aebc5b55ccca4414aead58229106040a1a58f4768d241a0869a3a7d682dd937fb13352f635ec3d57838469ba6ab93a9dc86ef3598f53e044fea98301971a2182a1725c32bf5529fce04665c9f2c1275d484543e038e964d855e1d91983ea34f7d66e19e27b6f59b23e9690c291432793167a5e8a9b44aeb9ecbaa500e2616ac32af6b6acfb6c2b4a485be4fe5072bd1f0e08ae343bf0c5cb241111f894bfd4be6a26dbc7ed352d71744bd9a4d51f149ac4ea5ad323b063d93e56ae12b81d88eb083024d3d164c0fd7b4bce8a800f69cb7c66594d7ab20818dc79f01853fee81b345210cdf2964c3a25a0934ece6b13029b5fdc3b780cd85a46e54495328f0baa63078b3948172443b57d8571a82c717a4d93a6fd9ada3a1efc41f3697600d02fcb555eef1d5162b346d892eabc60251b048979f49e3855fd5a49520a60d099ed2f5a5c8764875a4ea242407856b5dc393ba1e71fd04c53181572ad90e0184934d7b65e0ea56a8521a284e6a5b98bc704ad92e658a8b4c64cf67157ac0673159b9e2a9ea9d94c6fb3e5bd963dfcaad484cf06be75e3f23a11287b82bc6618b6eda760d29d1d8400c41ec3b42a24ec1e070bce0eec7dc6c6f19e2a6ba7faab72dd81f31814a18ce984c7aae6d9caaa800318418f56871c8cfd8778faa7dad3426849e10b041d6190eb445410f5f5e476068579fedc5869"
+            },
+            Test {
+                input: "3a3a819c48efde2ad914fbf00e18ab6bc4f14513ab27d0c178a188b61431e7f5623cb66b23346775d386b50e982c493adbbfc54b9a3cd383382336a1a0b2150a15358f336d03ae18f666c7573d55c4fd181c29e6ccfde63ea35f0adf5885cfc0a3d84a2b2e4dd24496db789e663170cef74798aa1bbcd4574ea0bba40489d764b2f83aadc66b148b4a0cd95246c127d5871c4f11418690a5ddf01246a0c80a43c70088b6183639dcfda4125bd113a8f49ee23ed306faac576c3fb0c1e256671d817fc2534a52f5b439f72e424de376f4c565cca82307dd9ef76da5b7c4eb7e085172e328807c02d011ffbf33785378d79dc266f6a5be6bb0e4a92eceebaeb1",
+                output_str: "8a5199b4a7e133e264a86202720655894d48cff344a928cf8347f48379cef347dfc5bcffab99b27b1f89aa2735e23d30088ffa03b9edb02b9635470ab9f1038985d55f9ca774572dd006470ea65145469609f9fa0831bf1ffd842dc24acade27bd9816e3b5bf2876cb112232a0eb4475f1dff9f5c713d9ffd4ccb89ae5607fe35731df06317949eef646e9591cf3be53add6b7dd2b6096e2b3fb06e662ec8b2d77422daad9463cd155204acdbd38e319613f39f99b6dfb35ca9365160066db19835888c2241ff9a731a4acbb5663727aac34a401247fbaa7499e7d5ee5b69d31025e63d04c35c798bca1262d5673a9cf0930b5ad89bd485599dc184528da4790f088ebd170b635d9581632d2ff90db79665ced430089af13c9f21f6d443a818064f17aec9e9c5457001fa8dc6afbadbe3138f388d89d0e6f22f66671255b210754ed63d81dce75ce8f189b534e6d6b3539aa51e837c42df9df59c71e6171cd4902fe1bdc73fb1775b5c754a1ed4ea7f3105fc543ee0418dad256f3f6118ea77114a16c15355b42877a1db2a7df0e155ae1d8670abcec3450f4e2eec9838f895423ef63d261138baaf5d9f104cb5a957aea06c0b9b8c78b0d441796dc0350ddeabb78a33b6f1f9e68ede3d1805c7b7e2cfd54e0fad62f0d8ca67a775dc4546af9096f2edb221db42843d65327861282dc946a0ba01a11863ab2d1dfd16e3973d4"
+            }
+        ];
+
+        let mut sh = Box::new(Sha3::new(Sha3Mode::Shake256));
+
+        test_hash(&mut *sh, &test_cases[..]);
+    }
+}
diff --git a/third_party/rust-crypto/src/simd.rs b/third_party/rust-crypto/src/simd.rs
new file mode 100644
index 0000000..53f6d20
--- /dev/null
+++ b/third_party/rust-crypto/src/simd.rs
@@ -0,0 +1,121 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use self::fake::*;
+
+pub trait SimdExt {
+    fn simd_eq(self, rhs: Self) -> Self;
+}
+
+impl SimdExt for fake::u32x4 {
+    fn simd_eq(self, rhs: Self) -> Self {
+        if self == rhs {
+            fake::u32x4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff)
+        } else {
+            fake::u32x4(0, 0, 0, 0)
+        }
+    }
+}
+
+mod fake {
+    use std::ops::{Add, BitAnd, BitOr, BitXor, Shl, Shr, Sub};
+
+    #[derive(Clone, Copy, PartialEq, Eq)]
+    #[allow(non_camel_case_types)]
+    pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
+
+    impl Add for u32x4 {
+        type Output = u32x4;
+
+        fn add(self, rhs: u32x4) -> u32x4 {
+            u32x4(
+                self.0.wrapping_add(rhs.0),
+                self.1.wrapping_add(rhs.1),
+                self.2.wrapping_add(rhs.2),
+                self.3.wrapping_add(rhs.3))
+        }
+    }
+
+    impl Sub for u32x4 {
+        type Output = u32x4;
+
+        fn sub(self, rhs: u32x4) -> u32x4 {
+            u32x4(
+                self.0.wrapping_sub(rhs.0),
+                self.1.wrapping_sub(rhs.1),
+                self.2.wrapping_sub(rhs.2),
+                self.3.wrapping_sub(rhs.3))
+        }
+    }
+
+    impl BitAnd for u32x4 {
+        type Output = u32x4;
+
+        fn bitand(self, rhs: u32x4) -> u32x4 {
+            u32x4(self.0 & rhs.0, self.1 & rhs.1, self.2 & rhs.2, self.3 & rhs.3)
+        }
+    }
+
+    impl BitOr for u32x4 {
+        type Output = u32x4;
+
+        fn bitor(self, rhs: u32x4) -> u32x4 {
+            u32x4(self.0 | rhs.0, self.1 | rhs.1, self.2 | rhs.2, self.3 | rhs.3)
+        }
+    }
+
+    impl BitXor for u32x4 {
+        type Output = u32x4;
+
+        fn bitxor(self, rhs: u32x4) -> u32x4 {
+            u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
+        }
+    }
+
+    impl Shl<usize> for u32x4 {
+        type Output = u32x4;
+
+        fn shl(self, amt: usize) -> u32x4 {
+            u32x4(self.0 << amt, self.1 << amt, self.2 << amt, self.3 << amt)
+        }
+    }
+
+    impl Shl<u32x4> for u32x4 {
+        type Output = u32x4;
+
+        fn shl(self, rhs: u32x4) -> u32x4 {
+            u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3)
+        }
+    }
+
+    impl Shr<usize> for u32x4 {
+        type Output = u32x4;
+
+        fn shr(self, amt: usize) -> u32x4 {
+            u32x4(self.0 >> amt, self.1 >> amt, self.2 >> amt, self.3 >> amt)
+        }
+    }
+
+    impl Shr<u32x4> for u32x4 {
+        type Output = u32x4;
+
+        fn shr(self, rhs: u32x4) -> u32x4 {
+            u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3)
+        }
+    }
+
+    #[derive(Clone, Copy)]
+    #[allow(non_camel_case_types)]
+    pub struct u64x2(pub u64, pub u64);
+
+    impl Add for u64x2 {
+        type Output = u64x2;
+
+        fn add(self, rhs: u64x2) -> u64x2 {
+            u64x2(self.0.wrapping_add(rhs.0), self.1.wrapping_add(rhs.1))
+        }
+    }
+}
diff --git a/third_party/rust-crypto/src/sosemanuk.rs b/third_party/rust-crypto/src/sosemanuk.rs
new file mode 100644
index 0000000..c3847eb
--- /dev/null
+++ b/third_party/rust-crypto/src/sosemanuk.rs
@@ -0,0 +1,2515 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+use buffer::{BufferResult, RefReadBuffer, RefWriteBuffer};
+use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher, SymmetricCipherError};
+use cryptoutil::{read_u32_le, symm_enc_or_dec, write_u32v_le};
+
+use cryptoutil::copy_memory;
+
+
+const ALPHA_MUL_TABLE : [u32; 256] =
+[
+    0x00000000, 0xE19FCF13, 0x6B973726, 0x8A08F835,
+    0xD6876E4C, 0x3718A15F, 0xBD10596A, 0x5C8F9679,
+    0x05A7DC98, 0xE438138B, 0x6E30EBBE, 0x8FAF24AD,
+    0xD320B2D4, 0x32BF7DC7, 0xB8B785F2, 0x59284AE1,
+    0x0AE71199, 0xEB78DE8A, 0x617026BF, 0x80EFE9AC,
+    0xDC607FD5, 0x3DFFB0C6, 0xB7F748F3, 0x566887E0,
+    0x0F40CD01, 0xEEDF0212, 0x64D7FA27, 0x85483534,
+    0xD9C7A34D, 0x38586C5E, 0xB250946B, 0x53CF5B78,
+    0x1467229B, 0xF5F8ED88, 0x7FF015BD, 0x9E6FDAAE,
+    0xC2E04CD7, 0x237F83C4, 0xA9777BF1, 0x48E8B4E2,
+    0x11C0FE03, 0xF05F3110, 0x7A57C925, 0x9BC80636,
+    0xC747904F, 0x26D85F5C, 0xACD0A769, 0x4D4F687A,
+    0x1E803302, 0xFF1FFC11, 0x75170424, 0x9488CB37,
+    0xC8075D4E, 0x2998925D, 0xA3906A68, 0x420FA57B,
+    0x1B27EF9A, 0xFAB82089, 0x70B0D8BC, 0x912F17AF,
+    0xCDA081D6, 0x2C3F4EC5, 0xA637B6F0, 0x47A879E3,
+    0x28CE449F, 0xC9518B8C, 0x435973B9, 0xA2C6BCAA,
+    0xFE492AD3, 0x1FD6E5C0, 0x95DE1DF5, 0x7441D2E6,
+    0x2D699807, 0xCCF65714, 0x46FEAF21, 0xA7616032,
+    0xFBEEF64B, 0x1A713958, 0x9079C16D, 0x71E60E7E,
+    0x22295506, 0xC3B69A15, 0x49BE6220, 0xA821AD33,
+    0xF4AE3B4A, 0x1531F459, 0x9F390C6C, 0x7EA6C37F,
+    0x278E899E, 0xC611468D, 0x4C19BEB8, 0xAD8671AB,
+    0xF109E7D2, 0x109628C1, 0x9A9ED0F4, 0x7B011FE7,
+    0x3CA96604, 0xDD36A917, 0x573E5122, 0xB6A19E31,
+    0xEA2E0848, 0x0BB1C75B, 0x81B93F6E, 0x6026F07D,
+    0x390EBA9C, 0xD891758F, 0x52998DBA, 0xB30642A9,
+    0xEF89D4D0, 0x0E161BC3, 0x841EE3F6, 0x65812CE5,
+    0x364E779D, 0xD7D1B88E, 0x5DD940BB, 0xBC468FA8,
+    0xE0C919D1, 0x0156D6C2, 0x8B5E2EF7, 0x6AC1E1E4,
+    0x33E9AB05, 0xD2766416, 0x587E9C23, 0xB9E15330,
+    0xE56EC549, 0x04F10A5A, 0x8EF9F26F, 0x6F663D7C,
+    0x50358897, 0xB1AA4784, 0x3BA2BFB1, 0xDA3D70A2,
+    0x86B2E6DB, 0x672D29C8, 0xED25D1FD, 0x0CBA1EEE,
+    0x5592540F, 0xB40D9B1C, 0x3E056329, 0xDF9AAC3A,
+    0x83153A43, 0x628AF550, 0xE8820D65, 0x091DC276,
+    0x5AD2990E, 0xBB4D561D, 0x3145AE28, 0xD0DA613B,
+    0x8C55F742, 0x6DCA3851, 0xE7C2C064, 0x065D0F77,
+    0x5F754596, 0xBEEA8A85, 0x34E272B0, 0xD57DBDA3,
+    0x89F22BDA, 0x686DE4C9, 0xE2651CFC, 0x03FAD3EF,
+    0x4452AA0C, 0xA5CD651F, 0x2FC59D2A, 0xCE5A5239,
+    0x92D5C440, 0x734A0B53, 0xF942F366, 0x18DD3C75,
+    0x41F57694, 0xA06AB987, 0x2A6241B2, 0xCBFD8EA1,
+    0x977218D8, 0x76EDD7CB, 0xFCE52FFE, 0x1D7AE0ED,
+    0x4EB5BB95, 0xAF2A7486, 0x25228CB3, 0xC4BD43A0,
+    0x9832D5D9, 0x79AD1ACA, 0xF3A5E2FF, 0x123A2DEC,
+    0x4B12670D, 0xAA8DA81E, 0x2085502B, 0xC11A9F38,
+    0x9D950941, 0x7C0AC652, 0xF6023E67, 0x179DF174,
+    0x78FBCC08, 0x9964031B, 0x136CFB2E, 0xF2F3343D,
+    0xAE7CA244, 0x4FE36D57, 0xC5EB9562, 0x24745A71,
+    0x7D5C1090, 0x9CC3DF83, 0x16CB27B6, 0xF754E8A5,
+    0xABDB7EDC, 0x4A44B1CF, 0xC04C49FA, 0x21D386E9,
+    0x721CDD91, 0x93831282, 0x198BEAB7, 0xF81425A4,
+    0xA49BB3DD, 0x45047CCE, 0xCF0C84FB, 0x2E934BE8,
+    0x77BB0109, 0x9624CE1A, 0x1C2C362F, 0xFDB3F93C,
+    0xA13C6F45, 0x40A3A056, 0xCAAB5863, 0x2B349770,
+    0x6C9CEE93, 0x8D032180, 0x070BD9B5, 0xE69416A6,
+    0xBA1B80DF, 0x5B844FCC, 0xD18CB7F9, 0x301378EA,
+    0x693B320B, 0x88A4FD18, 0x02AC052D, 0xE333CA3E,
+    0xBFBC5C47, 0x5E239354, 0xD42B6B61, 0x35B4A472,
+    0x667BFF0A, 0x87E43019, 0x0DECC82C, 0xEC73073F,
+    0xB0FC9146, 0x51635E55, 0xDB6BA660, 0x3AF46973,
+    0x63DC2392, 0x8243EC81, 0x084B14B4, 0xE9D4DBA7,
+    0xB55B4DDE, 0x54C482CD, 0xDECC7AF8, 0x3F53B5EB
+];
+
+const ALPHA_DIV_TABLE : [u32; 256] =
+[
+    0x00000000, 0x180F40CD, 0x301E8033, 0x2811C0FE,
+    0x603CA966, 0x7833E9AB, 0x50222955, 0x482D6998,
+    0xC078FBCC, 0xD877BB01, 0xF0667BFF, 0xE8693B32,
+    0xA04452AA, 0xB84B1267, 0x905AD299, 0x88559254,
+    0x29F05F31, 0x31FF1FFC, 0x19EEDF02, 0x01E19FCF,
+    0x49CCF657, 0x51C3B69A, 0x79D27664, 0x61DD36A9,
+    0xE988A4FD, 0xF187E430, 0xD99624CE, 0xC1996403,
+    0x89B40D9B, 0x91BB4D56, 0xB9AA8DA8, 0xA1A5CD65,
+    0x5249BE62, 0x4A46FEAF, 0x62573E51, 0x7A587E9C,
+    0x32751704, 0x2A7A57C9, 0x026B9737, 0x1A64D7FA,
+    0x923145AE, 0x8A3E0563, 0xA22FC59D, 0xBA208550,
+    0xF20DECC8, 0xEA02AC05, 0xC2136CFB, 0xDA1C2C36,
+    0x7BB9E153, 0x63B6A19E, 0x4BA76160, 0x53A821AD,
+    0x1B854835, 0x038A08F8, 0x2B9BC806, 0x339488CB,
+    0xBBC11A9F, 0xA3CE5A52, 0x8BDF9AAC, 0x93D0DA61,
+    0xDBFDB3F9, 0xC3F2F334, 0xEBE333CA, 0xF3EC7307,
+    0xA492D5C4, 0xBC9D9509, 0x948C55F7, 0x8C83153A,
+    0xC4AE7CA2, 0xDCA13C6F, 0xF4B0FC91, 0xECBFBC5C,
+    0x64EA2E08, 0x7CE56EC5, 0x54F4AE3B, 0x4CFBEEF6,
+    0x04D6876E, 0x1CD9C7A3, 0x34C8075D, 0x2CC74790,
+    0x8D628AF5, 0x956DCA38, 0xBD7C0AC6, 0xA5734A0B,
+    0xED5E2393, 0xF551635E, 0xDD40A3A0, 0xC54FE36D,
+    0x4D1A7139, 0x551531F4, 0x7D04F10A, 0x650BB1C7,
+    0x2D26D85F, 0x35299892, 0x1D38586C, 0x053718A1,
+    0xF6DB6BA6, 0xEED42B6B, 0xC6C5EB95, 0xDECAAB58,
+    0x96E7C2C0, 0x8EE8820D, 0xA6F942F3, 0xBEF6023E,
+    0x36A3906A, 0x2EACD0A7, 0x06BD1059, 0x1EB25094,
+    0x569F390C, 0x4E9079C1, 0x6681B93F, 0x7E8EF9F2,
+    0xDF2B3497, 0xC724745A, 0xEF35B4A4, 0xF73AF469,
+    0xBF179DF1, 0xA718DD3C, 0x8F091DC2, 0x97065D0F,
+    0x1F53CF5B, 0x075C8F96, 0x2F4D4F68, 0x37420FA5,
+    0x7F6F663D, 0x676026F0, 0x4F71E60E, 0x577EA6C3,
+    0xE18D0321, 0xF98243EC, 0xD1938312, 0xC99CC3DF,
+    0x81B1AA47, 0x99BEEA8A, 0xB1AF2A74, 0xA9A06AB9,
+    0x21F5F8ED, 0x39FAB820, 0x11EB78DE, 0x09E43813,
+    0x41C9518B, 0x59C61146, 0x71D7D1B8, 0x69D89175,
+    0xC87D5C10, 0xD0721CDD, 0xF863DC23, 0xE06C9CEE,
+    0xA841F576, 0xB04EB5BB, 0x985F7545, 0x80503588,
+    0x0805A7DC, 0x100AE711, 0x381B27EF, 0x20146722,
+    0x68390EBA, 0x70364E77, 0x58278E89, 0x4028CE44,
+    0xB3C4BD43, 0xABCBFD8E, 0x83DA3D70, 0x9BD57DBD,
+    0xD3F81425, 0xCBF754E8, 0xE3E69416, 0xFBE9D4DB,
+    0x73BC468F, 0x6BB30642, 0x43A2C6BC, 0x5BAD8671,
+    0x1380EFE9, 0x0B8FAF24, 0x239E6FDA, 0x3B912F17,
+    0x9A34E272, 0x823BA2BF, 0xAA2A6241, 0xB225228C,
+    0xFA084B14, 0xE2070BD9, 0xCA16CB27, 0xD2198BEA,
+    0x5A4C19BE, 0x42435973, 0x6A52998D, 0x725DD940,
+    0x3A70B0D8, 0x227FF015, 0x0A6E30EB, 0x12617026,
+    0x451FD6E5, 0x5D109628, 0x750156D6, 0x6D0E161B,
+    0x25237F83, 0x3D2C3F4E, 0x153DFFB0, 0x0D32BF7D,
+    0x85672D29, 0x9D686DE4, 0xB579AD1A, 0xAD76EDD7,
+    0xE55B844F, 0xFD54C482, 0xD545047C, 0xCD4A44B1,
+    0x6CEF89D4, 0x74E0C919, 0x5CF109E7, 0x44FE492A,
+    0x0CD320B2, 0x14DC607F, 0x3CCDA081, 0x24C2E04C,
+    0xAC977218, 0xB49832D5, 0x9C89F22B, 0x8486B2E6,
+    0xCCABDB7E, 0xD4A49BB3, 0xFCB55B4D, 0xE4BA1B80,
+    0x17566887, 0x0F59284A, 0x2748E8B4, 0x3F47A879,
+    0x776AC1E1, 0x6F65812C, 0x477441D2, 0x5F7B011F,
+    0xD72E934B, 0xCF21D386, 0xE7301378, 0xFF3F53B5,
+    0xB7123A2D, 0xAF1D7AE0, 0x870CBA1E, 0x9F03FAD3,
+    0x3EA637B6, 0x26A9777B, 0x0EB8B785, 0x16B7F748,
+    0x5E9A9ED0, 0x4695DE1D, 0x6E841EE3, 0x768B5E2E,
+    0xFEDECC7A, 0xE6D18CB7, 0xCEC04C49, 0xD6CF0C84,
+    0x9EE2651C, 0x86ED25D1, 0xAEFCE52F, 0xB6F3A5E2
+];
+
+
+#[derive(Copy)]
+pub struct Sosemanuk {
+    lfsr: [u32; 10],
+    fsm_r: [u32; 2],
+    subkeys: [u32; 100],
+    output: [u8; 80],
+    offset: u32
+}
+
+impl Clone for Sosemanuk { fn clone(&self) -> Sosemanuk { *self } }
+
+impl Sosemanuk {
+    pub fn new(key: &[u8], nonce: &[u8]) -> Sosemanuk {
+        let mut sosemanuk = Sosemanuk { lfsr: [0; 10], fsm_r: [0; 2], subkeys: [0; 100], output: [0; 80], offset: 80 };
+
+        assert!(key.len() <= 32);
+        assert!(nonce.len() <= 16);
+
+        key_setup(&key, &mut sosemanuk.subkeys);
+        iv_setup(&nonce, &mut sosemanuk.subkeys, &mut sosemanuk.lfsr, &mut sosemanuk.fsm_r);
+
+        sosemanuk
+    }
+
+    fn advance_state(&mut self) {
+        let mut s0 = self.lfsr[0];
+        let mut s1 = self.lfsr[1];
+        let mut s2 = self.lfsr[2];
+        let mut s3 = self.lfsr[3];
+        let mut s4 = self.lfsr[4];
+        let mut s5 = self.lfsr[5];
+        let mut s6 = self.lfsr[6];
+        let mut s7 = self.lfsr[7];
+        let mut s8 = self.lfsr[8];
+        let mut s9 = self.lfsr[9];
+        let mut r1 = self.fsm_r[0];
+        let mut r2 = self.fsm_r[1];
+        let mut f0 : u32;
+        let mut f1 : u32;
+        let mut f2 : u32;
+        let mut f3 : u32;
+        let mut f4 : u32;
+        let mut v0 : u32;
+        let mut v1 : u32;
+        let mut v2 : u32;
+        let mut v3 : u32;
+        let mut tt : u32;
+
+        let ref mul_alpha = ALPHA_MUL_TABLE;
+        let ref div_alpha = ALPHA_DIV_TABLE;
+
+        tt = r1;
+        //r1 = r2 + (s1 ^ ((r1 & 0x01) != 0 ? s8 : 0));
+        r1 = r2.wrapping_add(s1 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s8
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v0 = s0;
+        s0 = ((s0 << 8) ^ mul_alpha[s0 as usize >> 24])
+            ^ ((s3 >> 8) ^ div_alpha[s3 as usize & 0xFF]) ^ s9;
+        f0 = s9.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s2 ^ ((r1 & 0x01) != 0 ? s9 : 0));
+        r1 = r2.wrapping_add(s2 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s9
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v1 = s1;
+        s1 = ((s1 << 8) ^ mul_alpha[s1 as usize >> 24])
+            ^ ((s4 >> 8) ^ div_alpha[s4 as usize & 0xFF]) ^ s0;
+        f1 = s0.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s3 ^ ((r1 & 0x01) != 0 ? s0 : 0));
+        r1 = r2.wrapping_add(s3 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s0
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v2 = s2;
+        s2 = ((s2 << 8) ^ mul_alpha[s2 as usize >> 24])
+            ^ ((s5 >> 8) ^ div_alpha[s5 as usize & 0xFF]) ^ s1;
+        f2 = s1.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s4 ^ ((r1 & 0x01) != 0 ? s1 : 0));
+        r1 = r2.wrapping_add(s4 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s1
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v3 = s3;
+        s3 = ((s3 << 8) ^ mul_alpha[s3 as usize >> 24])
+            ^ ((s6 >> 8) ^ div_alpha[s6 as usize & 0xFF]) ^ s2;
+        f3 = s2.wrapping_add(r1) ^ r2;
+
+        /*
+         * Apply the third S-box (number 2) on (f3, f2, f1, f0).
+         */
+        f4 = f0;
+        f0 &= f2;
+        f0 ^= f3;
+        f2 ^= f1;
+        f2 ^= f0;
+        f3 |= f4;
+        f3 ^= f1;
+        f4 ^= f2;
+        f1 = f3;
+        f3 |= f4;
+        f3 ^= f0;
+        f0 &= f1;
+        f4 ^= f0;
+        f1 ^= f3;
+        f1 ^= f4;
+        f4 = !f4;
+
+        /*
+         * S-box result is in (f2, f3, f1, f4).
+         */
+        let sbox_res = [(f2 ^ v0), (f3 ^ v1), (f1 ^ v2), (f4 ^ v3)];
+        write_u32v_le(&mut self.output[0..16], &sbox_res);
+
+        tt = r1;
+        //r1 = r2 + (s5 ^ ((r1 & 0x01) != 0 ? s2 : 0));
+        r1 = r2.wrapping_add(s5 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s2
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v0 = s4;
+        s4 = ((s4 << 8) ^ mul_alpha[s4 as usize >> 24])
+            ^ ((s7 >> 8) ^ div_alpha[s7 as usize & 0xFF]) ^ s3;
+        f0 = s3.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s6 ^ ((r1 & 0x01) != 0 ? s3 : 0));
+        r1 = r2.wrapping_add(s6 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s3
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v1 = s5;
+        s5 = ((s5 << 8) ^ mul_alpha[s5 as usize >> 24])
+            ^ ((s8 >> 8) ^ div_alpha[s8 as usize & 0xFF]) ^ s4;
+        f1 = s4.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s7 ^ ((r1 & 0x01) != 0 ? s4 : 0));
+        r1 = r2.wrapping_add(s7 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s4
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v2 = s6;
+        s6 = ((s6 << 8) ^ mul_alpha[s6 as usize >> 24])
+            ^ ((s9 >> 8) ^ div_alpha[s9 as usize & 0xFF]) ^ s5;
+        f2 = s5.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s8 ^ ((r1 & 0x01) != 0 ? s5 : 0));
+        r1 = r2.wrapping_add(s8 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s5
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v3 = s7;
+        s7 = ((s7 << 8) ^ mul_alpha[s7 as usize >> 24])
+            ^ ((s0 >> 8) ^ div_alpha[s0 as usize & 0xFF]) ^ s6;
+        f3 = s6.wrapping_add(r1) ^ r2;
+
+        /*
+         * Apply the third S-box (number 2) on (f3, f2, f1, f0).
+         */
+        f4 = f0;
+        f0 &= f2;
+        f0 ^= f3;
+        f2 ^= f1;
+        f2 ^= f0;
+        f3 |= f4;
+        f3 ^= f1;
+        f4 ^= f2;
+        f1 = f3;
+        f3 |= f4;
+        f3 ^= f0;
+        f0 &= f1;
+        f4 ^= f0;
+        f1 ^= f3;
+        f1 ^= f4;
+        f4 = !f4;
+
+        /*
+         * S-box result is in (f2, f3, f1, f4).
+         */
+        let sbox_res = [(f2 ^ v0), (f3 ^ v1), (f1 ^ v2), (f4 ^ v3)];
+        write_u32v_le(&mut self.output[16..32], &sbox_res);
+
+        tt = r1;
+        //r1 = r2 + (s9 ^ ((r1 & 0x01) != 0 ? s6 : 0));
+        r1 = r2.wrapping_add(s9 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s6
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v0 = s8;
+        s8 = ((s8 << 8) ^ mul_alpha[s8 as usize >> 24])
+            ^ ((s1 >> 8) ^ div_alpha[s1 as usize & 0xFF]) ^ s7;
+        f0 = s7.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s0 ^ ((r1 & 0x01) != 0 ? s7 : 0));
+        r1 = r2.wrapping_add(s0 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s7
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v1 = s9;
+        s9 = ((s9 << 8) ^ mul_alpha[s9 as usize >> 24])
+            ^ ((s2 >> 8) ^ div_alpha[s2 as usize & 0xFF]) ^ s8;
+        f1 = s8.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s1 ^ ((r1 & 0x01) != 0 ? s8 : 0));
+        r1 = r2.wrapping_add(s1 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s8
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v2 = s0;
+        s0 = ((s0 << 8) ^ mul_alpha[s0 as usize >> 24])
+            ^ ((s3 >> 8) ^ div_alpha[s3 as usize & 0xFF]) ^ s9;
+        f2 = s9.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s2 ^ ((r1 & 0x01) != 0 ? s9 : 0));
+        r1 = r2.wrapping_add(s2 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s9
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v3 = s1;
+        s1 = ((s1 << 8) ^ mul_alpha[s1 as usize >> 24])
+            ^ ((s4 >> 8) ^ div_alpha[s4 as usize & 0xFF]) ^ s0;
+        f3 = s0.wrapping_add(r1) ^ r2;
+
+        /*
+         * Apply the third S-box (number 2) on (f3, f2, f1, f0).
+         */
+        f4 = f0;
+        f0 &= f2;
+        f0 ^= f3;
+        f2 ^= f1;
+        f2 ^= f0;
+        f3 |= f4;
+        f3 ^= f1;
+        f4 ^= f2;
+        f1 = f3;
+        f3 |= f4;
+        f3 ^= f0;
+        f0 &= f1;
+        f4 ^= f0;
+        f1 ^= f3;
+        f1 ^= f4;
+        f4 = !f4;
+
+        /*
+         * S-box result is in (f2, f3, f1, f4).
+         */
+        let sbox_res = [(f2 ^ v0), (f3 ^ v1), (f1 ^ v2), (f4 ^ v3)];
+        write_u32v_le(&mut self.output[32..48], &sbox_res);
+
+        tt = r1;
+        //r1 = r2 + (s3 ^ ((r1 & 0x01) != 0 ? s0 : 0));
+        r1 = r2.wrapping_add(s3 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s0
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v0 = s2;
+        s2 = ((s2 << 8) ^ mul_alpha[s2 as usize >> 24])
+            ^ ((s5 >> 8) ^ div_alpha[s5 as usize & 0xFF]) ^ s1;
+        f0 = s1.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s4 ^ ((r1 & 0x01) != 0 ? s1 : 0));
+        r1 = r2.wrapping_add(s4 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s1
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v1 = s3;
+        s3 = ((s3 << 8) ^ mul_alpha[s3 as usize >> 24])
+            ^ ((s6 >> 8) ^ div_alpha[s6 as usize & 0xFF]) ^ s2;
+        f1 = s2.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s5 ^ ((r1 & 0x01) != 0 ? s2 : 0));
+        r1 = r2.wrapping_add(s5 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s2
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v2 = s4;
+        s4 = ((s4 << 8) ^ mul_alpha[s4 as usize >> 24])
+            ^ ((s7 >> 8) ^ div_alpha[s7 as usize & 0xFF]) ^ s3;
+        f2 = s3.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s6 ^ ((r1 & 0x01) != 0 ? s3 : 0));
+        r1 = r2.wrapping_add(s6 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s3
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v3 = s5;
+        s5 = ((s5 << 8) ^ mul_alpha[s5 as usize >> 24])
+            ^ ((s8 >> 8) ^ div_alpha[s8 as usize & 0xFF]) ^ s4;
+        f3 = s4.wrapping_add(r1) ^ r2;
+
+        /*
+         * Apply the third S-box (number 2) on (f3, f2, f1, f0).
+         */
+        f4 = f0;
+        f0 &= f2;
+        f0 ^= f3;
+        f2 ^= f1;
+        f2 ^= f0;
+        f3 |= f4;
+        f3 ^= f1;
+        f4 ^= f2;
+        f1 = f3;
+        f3 |= f4;
+        f3 ^= f0;
+        f0 &= f1;
+        f4 ^= f0;
+        f1 ^= f3;
+        f1 ^= f4;
+        f4 = !f4;
+
+        /*
+         * S-box result is in (f2, f3, f1, f4).
+         */
+        let sbox_res = [(f2 ^ v0), (f3 ^ v1), (f1 ^ v2), (f4 ^ v3)];
+        write_u32v_le(&mut self.output[48..64], &sbox_res);
+
+        tt = r1;
+        //r1 = r2 + (s7 ^ ((r1 & 0x01) != 0 ? s4 : 0));
+        r1 = r2.wrapping_add(s7 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s4
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v0 = s6;
+        s6 = ((s6 << 8) ^ mul_alpha[s6 as usize >> 24])
+            ^ ((s9 >> 8) ^ div_alpha[s9 as usize & 0xFF]) ^ s5;
+        f0 = s5.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s8 ^ ((r1 & 0x01) != 0 ? s5 : 0));
+        r1 = r2.wrapping_add(s8 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s5
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v1 = s7;
+        s7 = ((s7 << 8) ^ mul_alpha[s7 as usize >> 24])
+            ^ ((s0 >> 8) ^ div_alpha[s0 as usize & 0xFF]) ^ s6;
+        f1 = s6.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s9 ^ ((r1 & 0x01) != 0 ? s6 : 0));
+        r1 = r2.wrapping_add(s9 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s6
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v2 = s8;
+        s8 = ((s8 << 8) ^ mul_alpha[s8 as usize >> 24])
+            ^ ((s1 >> 8) ^ div_alpha[s1 as usize & 0xFF]) ^ s7;
+        f2 = s7.wrapping_add(r1) ^ r2;
+
+        tt = r1;
+        //r1 = r2 + (s0 ^ ((r1 & 0x01) != 0 ? s7 : 0));
+        r1 = r2.wrapping_add(s0 ^ match r1 & 0x01 {
+            0 => 0,
+            _ => s7
+        });
+        r2 = tt.wrapping_mul(0x54655307).rotate_left(7);
+        v3 = s9;
+        s9 = ((s9 << 8) ^ mul_alpha[s9 as usize >> 24])
+            ^ ( ( s2 >> 8) ^ div_alpha[s2 as usize & 0xFF]) ^ s8;
+        f3 = s8.wrapping_add(r1) ^ r2;
+
+        /*
+         * Apply the third S-box (number 2) on (f3, f2, f1, f0).
+         */
+        f4 = f0;
+        f0 &= f2;
+        f0 ^= f3;
+        f2 ^= f1;
+        f2 ^= f0;
+        f3 |= f4;
+        f3 ^= f1;
+        f4 ^= f2;
+        f1 = f3;
+        f3 |= f4;
+        f3 ^= f0;
+        f0 &= f1;
+        f4 ^= f0;
+        f1 ^= f3;
+        f1 ^= f4;
+        f4 = !f4;
+
+        /*
+         * S-box result is in (f2, f3, f1, f4).
+         */
+        let sbox_res = [(f2 ^ v0), (f3 ^ v1), (f1 ^ v2), (f4 ^ v3)];
+        write_u32v_le(&mut self.output[64..80], &sbox_res);
+
+        self.lfsr[0] = s0;
+        self.lfsr[1] = s1;
+        self.lfsr[2] = s2;
+        self.lfsr[3] = s3;
+        self.lfsr[4] = s4;
+        self.lfsr[5] = s5;
+        self.lfsr[6] = s6;
+        self.lfsr[7] = s7;
+        self.lfsr[8] = s8;
+        self.lfsr[9] = s9;
+        self.fsm_r[0] = r1;
+        self.fsm_r[1] = r2;
+        self.offset = 0;
+    }
+
+    fn next(&mut self) -> u8 {
+        if self.offset == 80 {
+            self.advance_state();
+        }
+        let ret = self.output[self.offset as usize];
+        self.offset += 1;
+        ret
+    }
+}
+
+
+fn key_setup(key : &[u8], subkeys : &mut[u32; 100]) {
+    let mut full_key : [u8; 32] = [0; 32];
+    if key.len() < 32 {
+        copy_memory(&key, &mut full_key[0..key.len()]);
+        full_key[key.len()] = 0x01;
+    } else {
+        copy_memory(&key[0..32], &mut full_key[0..32]);
+    }
+
+    let mut w0 = read_u32_le(&full_key[0..4]);
+    let mut w1 = read_u32_le(&full_key[4..8]);
+    let mut w2 = read_u32_le(&full_key[8..12]);
+    let mut w3 = read_u32_le(&full_key[12..16]);
+    let mut w4 = read_u32_le(&full_key[16..20]);
+    let mut w5 = read_u32_le(&full_key[20..24]);
+    let mut w6 = read_u32_le(&full_key[24..28]);
+    let mut w7 = read_u32_le(&full_key[28..32]);
+    let mut r0 : u32;
+    let mut r1 : u32;
+    let mut r2 : u32;
+    let mut r3 : u32;
+    let mut r4 : u32;
+    let mut tt : u32;
+    let mut i = 0;
+
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (0));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (0 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (0 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (0 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r4 = r0;
+    r0 |= r3;
+    r3 ^= r1;
+    r1 &= r4;
+    r4 ^= r2;
+    r2 ^= r3;
+    r3 &= r0;
+    r4 |= r1;
+    r3 ^= r4;
+    r0 ^= r1;
+    r4 &= r0;
+    r1 ^= r3;
+    r4 ^= r2;
+    r1 |= r0;
+    r1 ^= r2;
+    r0 ^= r3;
+    r2 = r1;
+    r1 |= r3;
+    r1 ^= r0;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r4; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (4));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (4 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (4 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (4 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r4 = r0;
+    r0 &= r2;
+    r0 ^= r3;
+    r2 ^= r1;
+    r2 ^= r0;
+    r3 |= r4;
+    r3 ^= r1;
+    r4 ^= r2;
+    r1 = r3;
+    r3 |= r4;
+    r3 ^= r0;
+    r0 &= r1;
+    r4 ^= r0;
+    r1 ^= r3;
+    r1 ^= r4;
+    r4 = !r4;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (8));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (8 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (8 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (8 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r0 = !r0;
+    r2 = !r2;
+    r4 = r0;
+    r0 &= r1;
+    r2 ^= r0;
+    r0 |= r3;
+    r3 ^= r2;
+    r1 ^= r0;
+    r0 ^= r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r2 |= r0;
+    r2 &= r4;
+    r0 ^= r1;
+    r1 &= r2;
+    r1 ^= r0;
+    r0 &= r2;
+    r0 ^= r4;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (12));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (12 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (12 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (12 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r3 ^= r0;
+    r4 = r1;
+    r1 &= r3;
+    r4 ^= r2;
+    r1 ^= r0;
+    r0 |= r3;
+    r0 ^= r4;
+    r4 ^= r3;
+    r3 ^= r2;
+    r2 |= r1;
+    r2 ^= r4;
+    r4 = !r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r1 ^= r4;
+    r3 |= r0;
+    r1 ^= r3;
+    r4 ^= r3;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r0; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (16));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (16 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (16 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (16 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r4 = r1;
+    r1 |= r2;
+    r1 ^= r3;
+    r4 ^= r2;
+    r2 ^= r1;
+    r3 |= r4;
+    r3 &= r0;
+    r4 ^= r2;
+    r3 ^= r1;
+    r1 |= r4;
+    r1 ^= r0;
+    r0 |= r4;
+    r0 ^= r2;
+    r1 ^= r4;
+    r2 ^= r1;
+    r1 &= r0;
+    r1 ^= r4;
+    r2 = !r2;
+    r2 |= r0;
+    r4 ^= r2;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r0; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (20));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (20 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (20 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (20 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r2 = !r2;
+    r4 = r3;
+    r3 &= r0;
+    r0 ^= r4;
+    r3 ^= r2;
+    r2 |= r4;
+    r1 ^= r3;
+    r2 ^= r0;
+    r0 |= r1;
+    r2 ^= r1;
+    r4 ^= r0;
+    r0 |= r3;
+    r0 ^= r2;
+    r4 ^= r3;
+    r4 ^= r0;
+    r3 = !r3;
+    r2 &= r4;
+    r2 ^= r3;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r2; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (24));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (24 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (24 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (24 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r0 ^= r1;
+    r1 ^= r3;
+    r3 = !r3;
+    r4 = r1;
+    r1 &= r0;
+    r2 ^= r3;
+    r1 ^= r2;
+    r2 |= r4;
+    r4 ^= r3;
+    r3 &= r1;
+    r3 ^= r0;
+    r4 ^= r1;
+    r4 ^= r2;
+    r2 ^= r0;
+    r0 &= r3;
+    r2 = !r2;
+    r0 ^= r4;
+    r4 |= r3;
+    r2 ^= r4;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r2; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (28));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (28 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (28 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (28 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r1 ^= r3;
+    r3 = !r3;
+    r2 ^= r3;
+    r3 ^= r0;
+    r4 = r1;
+    r1 &= r3;
+    r1 ^= r2;
+    r4 ^= r3;
+    r0 ^= r4;
+    r2 &= r4;
+    r2 ^= r0;
+    r0 &= r1;
+    r3 ^= r0;
+    r4 |= r1;
+    r4 ^= r0;
+    r0 |= r3;
+    r0 ^= r2;
+    r2 &= r3;
+    r0 = !r0;
+    r4 ^= r2;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r3; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (32));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (32 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (32 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (32 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r4 = r0;
+    r0 |= r3;
+    r3 ^= r1;
+    r1 &= r4;
+    r4 ^= r2;
+    r2 ^= r3;
+    r3 &= r0;
+    r4 |= r1;
+    r3 ^= r4;
+    r0 ^= r1;
+    r4 &= r0;
+    r1 ^= r3;
+    r4 ^= r2;
+    r1 |= r0;
+    r1 ^= r2;
+    r0 ^= r3;
+    r2 = r1;
+    r1 |= r3;
+    r1 ^= r0;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r4; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (36));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (36 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (36 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (36 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r4 = r0;
+    r0 &= r2;
+    r0 ^= r3;
+    r2 ^= r1;
+    r2 ^= r0;
+    r3 |= r4;
+    r3 ^= r1;
+    r4 ^= r2;
+    r1 = r3;
+    r3 |= r4;
+    r3 ^= r0;
+    r0 &= r1;
+    r4 ^= r0;
+    r1 ^= r3;
+    r1 ^= r4;
+    r4 = !r4;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (40));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (40 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (40 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (40 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r0 = !r0;
+    r2 = !r2;
+    r4 = r0;
+    r0 &= r1;
+    r2 ^= r0;
+    r0 |= r3;
+    r3 ^= r2;
+    r1 ^= r0;
+    r0 ^= r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r2 |= r0;
+    r2 &= r4;
+    r0 ^= r1;
+    r1 &= r2;
+    r1 ^= r0;
+    r0 &= r2;
+    r0 ^= r4;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (44));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (44 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (44 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (44 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r3 ^= r0;
+    r4 = r1;
+    r1 &= r3;
+    r4 ^= r2;
+    r1 ^= r0;
+    r0 |= r3;
+    r0 ^= r4;
+    r4 ^= r3;
+    r3 ^= r2;
+    r2 |= r1;
+    r2 ^= r4;
+    r4 = !r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r1 ^= r4;
+    r3 |= r0;
+    r1 ^= r3;
+    r4 ^= r3;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r0; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (48));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (48 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (48 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (48 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r4 = r1;
+    r1 |= r2;
+    r1 ^= r3;
+    r4 ^= r2;
+    r2 ^= r1;
+    r3 |= r4;
+    r3 &= r0;
+    r4 ^= r2;
+    r3 ^= r1;
+    r1 |= r4;
+    r1 ^= r0;
+    r0 |= r4;
+    r0 ^= r2;
+    r1 ^= r4;
+    r2 ^= r1;
+    r1 &= r0;
+    r1 ^= r4;
+    r2 = !r2;
+    r2 |= r0;
+    r4 ^= r2;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r0; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (52));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (52 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (52 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (52 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r2 = !r2;
+    r4 = r3;
+    r3 &= r0;
+    r0 ^= r4;
+    r3 ^= r2;
+    r2 |= r4;
+    r1 ^= r3;
+    r2 ^= r0;
+    r0 |= r1;
+    r2 ^= r1;
+    r4 ^= r0;
+    r0 |= r3;
+    r0 ^= r2;
+    r4 ^= r3;
+    r4 ^= r0;
+    r3 = !r3;
+    r2 &= r4;
+    r2 ^= r3;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r2; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (56));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (56 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (56 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (56 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r0 ^= r1;
+    r1 ^= r3;
+    r3 = !r3;
+    r4 = r1;
+    r1 &= r0;
+    r2 ^= r3;
+    r1 ^= r2;
+    r2 |= r4;
+    r4 ^= r3;
+    r3 &= r1;
+    r3 ^= r0;
+    r4 ^= r1;
+    r4 ^= r2;
+    r2 ^= r0;
+    r0 &= r3;
+    r2 = !r2;
+    r0 ^= r4;
+    r4 |= r3;
+    r2 ^= r4;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r2; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (60));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (60 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (60 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (60 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r1 ^= r3;
+    r3 = !r3;
+    r2 ^= r3;
+    r3 ^= r0;
+    r4 = r1;
+    r1 &= r3;
+    r1 ^= r2;
+    r4 ^= r3;
+    r0 ^= r4;
+    r2 &= r4;
+    r2 ^= r0;
+    r0 &= r1;
+    r3 ^= r0;
+    r4 |= r1;
+    r4 ^= r0;
+    r0 |= r3;
+    r0 ^= r2;
+    r2 &= r3;
+    r0 = !r0;
+    r4 ^= r2;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r3; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (64));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (64 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (64 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (64 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r4 = r0;
+    r0 |= r3;
+    r3 ^= r1;
+    r1 &= r4;
+    r4 ^= r2;
+    r2 ^= r3;
+    r3 &= r0;
+    r4 |= r1;
+    r3 ^= r4;
+    r0 ^= r1;
+    r4 &= r0;
+    r1 ^= r3;
+    r4 ^= r2;
+    r1 |= r0;
+    r1 ^= r2;
+    r0 ^= r3;
+    r2 = r1;
+    r1 |= r3;
+    r1 ^= r0;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r4; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (68));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (68 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (68 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (68 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r4 = r0;
+    r0 &= r2;
+    r0 ^= r3;
+    r2 ^= r1;
+    r2 ^= r0;
+    r3 |= r4;
+    r3 ^= r1;
+    r4 ^= r2;
+    r1 = r3;
+    r3 |= r4;
+    r3 ^= r0;
+    r0 &= r1;
+    r4 ^= r0;
+    r1 ^= r3;
+    r1 ^= r4;
+    r4 = !r4;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (72));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (72 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (72 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (72 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r0 = !r0;
+    r2 = !r2;
+    r4 = r0;
+    r0 &= r1;
+    r2 ^= r0;
+    r0 |= r3;
+    r3 ^= r2;
+    r1 ^= r0;
+    r0 ^= r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r2 |= r0;
+    r2 &= r4;
+    r0 ^= r1;
+    r1 &= r2;
+    r1 ^= r0;
+    r0 &= r2;
+    r0 ^= r4;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (76));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (76 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (76 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (76 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r3 ^= r0;
+    r4 = r1;
+    r1 &= r3;
+    r4 ^= r2;
+    r1 ^= r0;
+    r0 |= r3;
+    r0 ^= r4;
+    r4 ^= r3;
+    r3 ^= r2;
+    r2 |= r1;
+    r2 ^= r4;
+    r4 = !r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r1 ^= r4;
+    r3 |= r0;
+    r1 ^= r3;
+    r4 ^= r3;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r0; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (80));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (80 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (80 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (80 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r4 = r1;
+    r1 |= r2;
+    r1 ^= r3;
+    r4 ^= r2;
+    r2 ^= r1;
+    r3 |= r4;
+    r3 &= r0;
+    r4 ^= r2;
+    r3 ^= r1;
+    r1 |= r4;
+    r1 ^= r0;
+    r0 |= r4;
+    r0 ^= r2;
+    r1 ^= r4;
+    r2 ^= r1;
+    r1 &= r0;
+    r1 ^= r4;
+    r2 = !r2;
+    r2 |= r0;
+    r4 ^= r2;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r0; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (84));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (84 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (84 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (84 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r2 = !r2;
+    r4 = r3;
+    r3 &= r0;
+    r0 ^= r4;
+    r3 ^= r2;
+    r2 |= r4;
+    r1 ^= r3;
+    r2 ^= r0;
+    r0 |= r1;
+    r2 ^= r1;
+    r4 ^= r0;
+    r0 |= r3;
+    r0 ^= r2;
+    r4 ^= r3;
+    r4 ^= r0;
+    r3 = !r3;
+    r2 &= r4;
+    r2 ^= r3;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r2; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (88));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (88 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (88 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (88 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r0 ^= r1;
+    r1 ^= r3;
+    r3 = !r3;
+    r4 = r1;
+    r1 &= r0;
+    r2 ^= r3;
+    r1 ^= r2;
+    r2 |= r4;
+    r4 ^= r3;
+    r3 &= r1;
+    r3 ^= r0;
+    r4 ^= r1;
+    r4 ^= r2;
+    r2 ^= r0;
+    r0 &= r3;
+    r2 = !r2;
+    r0 ^= r4;
+    r4 |= r3;
+    r2 ^= r4;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r2; i+=1;
+    tt = w4 ^ w7 ^ w1 ^ w3 ^ (0x9E3779B9 ^ (92));
+    w4 = tt.rotate_left(11);
+    tt = w5 ^ w0 ^ w2 ^ w4 ^ (0x9E3779B9 ^ (92 + 1));
+    w5 = tt.rotate_left(11);
+    tt = w6 ^ w1 ^ w3 ^ w5 ^ (0x9E3779B9 ^ (92 + 2));
+    w6 = tt.rotate_left(11);
+    tt = w7 ^ w2 ^ w4 ^ w6 ^ (0x9E3779B9 ^ (92 + 3));
+    w7 = tt.rotate_left(11);
+    r0 = w4;
+    r1 = w5;
+    r2 = w6;
+    r3 = w7;
+    r1 ^= r3;
+    r3 = !r3;
+    r2 ^= r3;
+    r3 ^= r0;
+    r4 = r1;
+    r1 &= r3;
+    r1 ^= r2;
+    r4 ^= r3;
+    r0 ^= r4;
+    r2 &= r4;
+    r2 ^= r0;
+    r0 &= r1;
+    r3 ^= r0;
+    r4 |= r1;
+    r4 ^= r0;
+    r0 |= r3;
+    r0 ^= r2;
+    r2 &= r3;
+    r0 = !r0;
+    r4 ^= r2;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r4; i+=1;
+    subkeys[i] = r0; i+=1;
+    subkeys[i] = r3; i+=1;
+    tt = w0 ^ w3 ^ w5 ^ w7 ^ (0x9E3779B9 ^ (96));
+    w0 = tt.rotate_left(11);
+    tt = w1 ^ w4 ^ w6 ^ w0 ^ (0x9E3779B9 ^ (96 + 1));
+    w1 = tt.rotate_left(11);
+    tt = w2 ^ w5 ^ w7 ^ w1 ^ (0x9E3779B9 ^ (96 + 2));
+    w2 = tt.rotate_left(11);
+    tt = w3 ^ w6 ^ w0 ^ w2 ^ (0x9E3779B9 ^ (96 + 3));
+    w3 = tt.rotate_left(11);
+    r0 = w0;
+    r1 = w1;
+    r2 = w2;
+    r3 = w3;
+    r4 = r0;
+    r0 |= r3;
+    r3 ^= r1;
+    r1 &= r4;
+    r4 ^= r2;
+    r2 ^= r3;
+    r3 &= r0;
+    r4 |= r1;
+    r3 ^= r4;
+    r0 ^= r1;
+    r4 &= r0;
+    r1 ^= r3;
+    r4 ^= r2;
+    r1 |= r0;
+    r1 ^= r2;
+    r0 ^= r3;
+    r2 = r1;
+    r1 |= r3;
+    r1 ^= r0;
+    subkeys[i] = r1; i+=1;
+    subkeys[i] = r2; i+=1;
+    subkeys[i] = r3; i+=1;
+    subkeys[i] = r4;
+}
+
+fn iv_setup(iv : &[u8], subkeys : &mut[u32; 100], lfsr : &mut[u32; 10], fsm_r : &mut[u32; 2]) {
+    let mut nonce : [u8; 16] = [0; 16];
+    if iv.len() < 16 {
+        copy_memory(&iv, &mut nonce[0..iv.len()]);
+    } else {
+        copy_memory(&iv[0..16], &mut nonce[0..16]);
+    }
+
+    let mut r0 : u32;
+    let mut r1 : u32;
+    let mut r2 : u32;
+    let mut r3 : u32;
+    let mut r4 : u32;
+    r0 = read_u32_le(&nonce[0..4]);
+    r1 = read_u32_le(&nonce[4..8]);
+    r2 = read_u32_le(&nonce[8..12]);
+    r3 = read_u32_le(&nonce[12..16]);
+
+    r0 ^= subkeys[0];
+    r1 ^= subkeys[0 + 1];
+    r2 ^= subkeys[0 + 2];
+    r3 ^= subkeys[0 + 3];
+    r3 ^= r0;
+    r4 = r1;
+    r1 &= r3;
+    r4 ^= r2;
+    r1 ^= r0;
+    r0 |= r3;
+    r0 ^= r4;
+    r4 ^= r3;
+    r3 ^= r2;
+    r2 |= r1;
+    r2 ^= r4;
+    r4 = !r4;
+    r4 |= r1;
+    r1 ^= r3;
+    r1 ^= r4;
+    r3 |= r0;
+    r1 ^= r3;
+    r4 ^= r3;
+    r1 = r1.rotate_left(13);
+    r2 = r2.rotate_left(3);
+    r4 = r4 ^ r1 ^ r2;
+    r0 = r0 ^ r2 ^ (r1 << 3);
+    r4 = r4.rotate_left(1);
+    r0 = r0.rotate_left(7);
+    r1 = r1 ^ r4 ^ r0;
+    r2 = r2 ^ r0 ^ (r4 << 7);
+    r1 = r1.rotate_left(5);
+    r2 = r2.rotate_left(22);
+    r1 ^= subkeys[4];
+    r4 ^= subkeys[4 + 1];
+    r2 ^= subkeys[4 + 2];
+    r0 ^= subkeys[4 + 3];
+    r1 = !r1;
+    r2 = !r2;
+    r3 = r1;
+    r1 &= r4;
+    r2 ^= r1;
+    r1 |= r0;
+    r0 ^= r2;
+    r4 ^= r1;
+    r1 ^= r3;
+    r3 |= r4;
+    r4 ^= r0;
+    r2 |= r1;
+    r2 &= r3;
+    r1 ^= r4;
+    r4 &= r2;
+    r4 ^= r1;
+    r1 &= r2;
+    r1 ^= r3;
+    r2 = r2.rotate_left(13);
+    r0 = r0.rotate_left(3);
+    r1 = r1 ^ r2 ^ r0;
+    r4 = r4 ^ r0 ^ (r2 << 3);
+    r1 = r1.rotate_left(1);
+    r4 = r4.rotate_left(7);
+    r2 = r2 ^ r1 ^ r4;
+    r0 = r0 ^ r4 ^ (r1 << 7);
+    r2 = r2.rotate_left(5);
+    r0 = r0.rotate_left(22);
+    r2 ^= subkeys[8];
+    r1 ^= subkeys[8 + 1];
+    r0 ^= subkeys[8 + 2];
+    r4 ^= subkeys[8 + 3];
+    r3 = r2;
+    r2 &= r0;
+    r2 ^= r4;
+    r0 ^= r1;
+    r0 ^= r2;
+    r4 |= r3;
+    r4 ^= r1;
+    r3 ^= r0;
+    r1 = r4;
+    r4 |= r3;
+    r4 ^= r2;
+    r2 &= r1;
+    r3 ^= r2;
+    r1 ^= r4;
+    r1 ^= r3;
+    r3 = !r3;
+    r0 = r0.rotate_left(13);
+    r1 = r1.rotate_left(3);
+    r4 = r4 ^ r0 ^ r1;
+    r3 = r3 ^ r1 ^ (r0 << 3);
+    r4 = r4.rotate_left(1);
+    r3 = r3.rotate_left(7);
+    r0 = r0 ^ r4 ^ r3;
+    r1 = r1 ^ r3 ^ (r4 << 7);
+    r0 = r0.rotate_left(5);
+    r1 = r1.rotate_left(22);
+    r0 ^= subkeys[12];
+    r4 ^= subkeys[12 + 1];
+    r1 ^= subkeys[12 + 2];
+    r3 ^= subkeys[12 + 3];
+    r2 = r0;
+    r0 |= r3;
+    r3 ^= r4;
+    r4 &= r2;
+    r2 ^= r1;
+    r1 ^= r3;
+    r3 &= r0;
+    r2 |= r4;
+    r3 ^= r2;
+    r0 ^= r4;
+    r2 &= r0;
+    r4 ^= r3;
+    r2 ^= r1;
+    r4 |= r0;
+    r4 ^= r1;
+    r0 ^= r3;
+    r1 = r4;
+    r4 |= r3;
+    r4 ^= r0;
+    r4 = r4.rotate_left(13);
+    r3 = r3.rotate_left(3);
+    r1 = r1 ^ r4 ^ r3;
+    r2 = r2 ^ r3 ^ (r4 << 3);
+    r1 = r1.rotate_left(1);
+    r2 = r2.rotate_left(7);
+    r4 = r4 ^ r1 ^ r2;
+    r3 = r3 ^ r2 ^ (r1 << 7);
+    r4 = r4.rotate_left(5);
+    r3 = r3.rotate_left(22);
+    r4 ^= subkeys[16];
+    r1 ^= subkeys[16 + 1];
+    r3 ^= subkeys[16 + 2];
+    r2 ^= subkeys[16 + 3];
+    r1 ^= r2;
+    r2 = !r2;
+    r3 ^= r2;
+    r2 ^= r4;
+    r0 = r1;
+    r1 &= r2;
+    r1 ^= r3;
+    r0 ^= r2;
+    r4 ^= r0;
+    r3 &= r0;
+    r3 ^= r4;
+    r4 &= r1;
+    r2 ^= r4;
+    r0 |= r1;
+    r0 ^= r4;
+    r4 |= r2;
+    r4 ^= r3;
+    r3 &= r2;
+    r4 = !r4;
+    r0 ^= r3;
+    r1 = r1.rotate_left(13);
+    r4 = r4.rotate_left(3);
+    r0 = r0 ^ r1 ^ r4;
+    r2 = r2 ^ r4 ^ (r1 << 3);
+    r0 = r0.rotate_left(1);
+    r2 = r2.rotate_left(7);
+    r1 = r1 ^ r0 ^ r2;
+    r4 = r4 ^ r2 ^ (r0 << 7);
+    r1 = r1.rotate_left(5);
+    r4 = r4.rotate_left(22);
+    r1 ^= subkeys[20];
+    r0 ^= subkeys[20 + 1];
+    r4 ^= subkeys[20 + 2];
+    r2 ^= subkeys[20 + 3];
+    r1 ^= r0;
+    r0 ^= r2;
+    r2 = !r2;
+    r3 = r0;
+    r0 &= r1;
+    r4 ^= r2;
+    r0 ^= r4;
+    r4 |= r3;
+    r3 ^= r2;
+    r2 &= r0;
+    r2 ^= r1;
+    r3 ^= r0;
+    r3 ^= r4;
+    r4 ^= r1;
+    r1 &= r2;
+    r4 = !r4;
+    r1 ^= r3;
+    r3 |= r2;
+    r4 ^= r3;
+    r0 = r0.rotate_left(13);
+    r1 = r1.rotate_left(3);
+    r2 = r2 ^ r0 ^ r1;
+    r4 = r4 ^ r1 ^ (r0 << 3);
+    r2 = r2.rotate_left(1);
+    r4 = r4.rotate_left(7);
+    r0 = r0 ^ r2 ^ r4;
+    r1 = r1 ^ r4 ^ (r2 << 7);
+    r0 = r0.rotate_left(5);
+    r1 = r1.rotate_left(22);
+    r0 ^= subkeys[24];
+    r2 ^= subkeys[24 + 1];
+    r1 ^= subkeys[24 + 2];
+    r4 ^= subkeys[24 + 3];
+    r1 = !r1;
+    r3 = r4;
+    r4 &= r0;
+    r0 ^= r3;
+    r4 ^= r1;
+    r1 |= r3;
+    r2 ^= r4;
+    r1 ^= r0;
+    r0 |= r2;
+    r1 ^= r2;
+    r3 ^= r0;
+    r0 |= r4;
+    r0 ^= r1;
+    r3 ^= r4;
+    r3 ^= r0;
+    r4 = !r4;
+    r1 &= r3;
+    r1 ^= r4;
+    r0 = r0.rotate_left(13);
+    r3 = r3.rotate_left(3);
+    r2 = r2 ^ r0 ^ r3;
+    r1 = r1 ^ r3 ^ (r0 << 3);
+    r2 = r2.rotate_left(1);
+    r1 = r1.rotate_left(7);
+    r0 = r0 ^ r2 ^ r1;
+    r3 = r3 ^ r1 ^ (r2 << 7);
+    r0 = r0.rotate_left(5);
+    r3 = r3.rotate_left(22);
+    r0 ^= subkeys[28];
+    r2 ^= subkeys[28 + 1];
+    r3 ^= subkeys[28 + 2];
+    r1 ^= subkeys[28 + 3];
+    r4 = r2;
+    r2 |= r3;
+    r2 ^= r1;
+    r4 ^= r3;
+    r3 ^= r2;
+    r1 |= r4;
+    r1 &= r0;
+    r4 ^= r3;
+    r1 ^= r2;
+    r2 |= r4;
+    r2 ^= r0;
+    r0 |= r4;
+    r0 ^= r3;
+    r2 ^= r4;
+    r3 ^= r2;
+    r2 &= r0;
+    r2 ^= r4;
+    r3 = !r3;
+    r3 |= r0;
+    r4 ^= r3;
+    r4 = r4.rotate_left(13);
+    r2 = r2.rotate_left(3);
+    r1 = r1 ^ r4 ^ r2;
+    r0 = r0 ^ r2 ^ (r4 << 3);
+    r1 = r1.rotate_left(1);
+    r0 = r0.rotate_left(7);
+    r4 = r4 ^ r1 ^ r0;
+    r2 = r2 ^ r0 ^ (r1 << 7);
+    r4 = r4.rotate_left(5);
+    r2 = r2.rotate_left(22);
+    r4 ^= subkeys[32];
+    r1 ^= subkeys[32 + 1];
+    r2 ^= subkeys[32 + 2];
+    r0 ^= subkeys[32 + 3];
+    r0 ^= r4;
+    r3 = r1;
+    r1 &= r0;
+    r3 ^= r2;
+    r1 ^= r4;
+    r4 |= r0;
+    r4 ^= r3;
+    r3 ^= r0;
+    r0 ^= r2;
+    r2 |= r1;
+    r2 ^= r3;
+    r3 = !r3;
+    r3 |= r1;
+    r1 ^= r0;
+    r1 ^= r3;
+    r0 |= r4;
+    r1 ^= r0;
+    r3 ^= r0;
+    r1 = r1.rotate_left(13);
+    r2 = r2.rotate_left(3);
+    r3 = r3 ^ r1 ^ r2;
+    r4 = r4 ^ r2 ^ (r1 << 3);
+    r3 = r3.rotate_left(1);
+    r4 = r4.rotate_left(7);
+    r1 = r1 ^ r3 ^ r4;
+    r2 = r2 ^ r4 ^ (r3 << 7);
+    r1 = r1.rotate_left(5);
+    r2 = r2.rotate_left(22);
+    r1 ^= subkeys[36];
+    r3 ^= subkeys[36 + 1];
+    r2 ^= subkeys[36 + 2];
+    r4 ^= subkeys[36 + 3];
+    r1 = !r1;
+    r2 = !r2;
+    r0 = r1;
+    r1 &= r3;
+    r2 ^= r1;
+    r1 |= r4;
+    r4 ^= r2;
+    r3 ^= r1;
+    r1 ^= r0;
+    r0 |= r3;
+    r3 ^= r4;
+    r2 |= r1;
+    r2 &= r0;
+    r1 ^= r3;
+    r3 &= r2;
+    r3 ^= r1;
+    r1 &= r2;
+    r1 ^= r0;
+    r2 = r2.rotate_left(13);
+    r4 = r4.rotate_left(3);
+    r1 = r1 ^ r2 ^ r4;
+    r3 = r3 ^ r4 ^ (r2 << 3);
+    r1 = r1.rotate_left(1);
+    r3 = r3.rotate_left(7);
+    r2 = r2 ^ r1 ^ r3;
+    r4 = r4 ^ r3 ^ (r1 << 7);
+    r2 = r2.rotate_left(5);
+    r4 = r4.rotate_left(22);
+    r2 ^= subkeys[40];
+    r1 ^= subkeys[40 + 1];
+    r4 ^= subkeys[40 + 2];
+    r3 ^= subkeys[40 + 3];
+    r0 = r2;
+    r2 &= r4;
+    r2 ^= r3;
+    r4 ^= r1;
+    r4 ^= r2;
+    r3 |= r0;
+    r3 ^= r1;
+    r0 ^= r4;
+    r1 = r3;
+    r3 |= r0;
+    r3 ^= r2;
+    r2 &= r1;
+    r0 ^= r2;
+    r1 ^= r3;
+    r1 ^= r0;
+    r0 = !r0;
+    r4 = r4.rotate_left(13);
+    r1 = r1.rotate_left(3);
+    r3 = r3 ^ r4 ^ r1;
+    r0 = r0 ^ r1 ^ (r4 << 3);
+    r3 = r3.rotate_left(1);
+    r0 = r0.rotate_left(7);
+    r4 = r4 ^ r3 ^ r0;
+    r1 = r1 ^ r0 ^ (r3 << 7);
+    r4 = r4.rotate_left(5);
+    r1 = r1.rotate_left(22);
+    r4 ^= subkeys[44];
+    r3 ^= subkeys[44 + 1];
+    r1 ^= subkeys[44 + 2];
+    r0 ^= subkeys[44 + 3];
+    r2 = r4;
+    r4 |= r0;
+    r0 ^= r3;
+    r3 &= r2;
+    r2 ^= r1;
+    r1 ^= r0;
+    r0 &= r4;
+    r2 |= r3;
+    r0 ^= r2;
+    r4 ^= r3;
+    r2 &= r4;
+    r3 ^= r0;
+    r2 ^= r1;
+    r3 |= r4;
+    r3 ^= r1;
+    r4 ^= r0;
+    r1 = r3;
+    r3 |= r0;
+    r3 ^= r4;
+    r3 = r3.rotate_left(13);
+    r0 = r0.rotate_left(3);
+    r1 = r1 ^ r3 ^ r0;
+    r2 = r2 ^ r0 ^ (r3 << 3);
+    r1 = r1.rotate_left(1);
+    r2 = r2.rotate_left(7);
+    r3 = r3 ^ r1 ^ r2;
+    r0 = r0 ^ r2 ^ (r1 << 7);
+    r3 = r3.rotate_left(5);
+    r0 = r0.rotate_left(22);
+    lfsr[9] = r3;
+    lfsr[8] = r1;
+    lfsr[7] = r0;
+    lfsr[6] = r2;
+    r3 ^= subkeys[48];
+    r1 ^= subkeys[48 + 1];
+    r0 ^= subkeys[48 + 2];
+    r2 ^= subkeys[48 + 3];
+    r1 ^= r2;
+    r2 = !r2;
+    r0 ^= r2;
+    r2 ^= r3;
+    r4 = r1;
+    r1 &= r2;
+    r1 ^= r0;
+    r4 ^= r2;
+    r3 ^= r4;
+    r0 &= r4;
+    r0 ^= r3;
+    r3 &= r1;
+    r2 ^= r3;
+    r4 |= r1;
+    r4 ^= r3;
+    r3 |= r2;
+    r3 ^= r0;
+    r0 &= r2;
+    r3 = !r3;
+    r4 ^= r0;
+    r1 = r1.rotate_left(13);
+    r3 = r3.rotate_left(3);
+    r4 = r4 ^ r1 ^ r3;
+    r2 = r2 ^ r3 ^ (r1 << 3);
+    r4 = r4.rotate_left(1);
+    r2 = r2.rotate_left(7);
+    r1 = r1 ^ r4 ^ r2;
+    r3 = r3 ^ r2 ^ (r4 << 7);
+    r1 = r1.rotate_left(5);
+    r3 = r3.rotate_left(22);
+    r1 ^= subkeys[52];
+    r4 ^= subkeys[52 + 1];
+    r3 ^= subkeys[52 + 2];
+    r2 ^= subkeys[52 + 3];
+    r1 ^= r4;
+    r4 ^= r2;
+    r2 = !r2;
+    r0 = r4;
+    r4 &= r1;
+    r3 ^= r2;
+    r4 ^= r3;
+    r3 |= r0;
+    r0 ^= r2;
+    r2 &= r4;
+    r2 ^= r1;
+    r0 ^= r4;
+    r0 ^= r3;
+    r3 ^= r1;
+    r1 &= r2;
+    r3 = !r3;
+    r1 ^= r0;
+    r0 |= r2;
+    r3 ^= r0;
+    r4 = r4.rotate_left(13);
+    r1 = r1.rotate_left(3);
+    r2 = r2 ^ r4 ^ r1;
+    r3 = r3 ^ r1 ^ (r4 << 3);
+    r2 = r2.rotate_left(1);
+    r3 = r3.rotate_left(7);
+    r4 = r4 ^ r2 ^ r3;
+    r1 = r1 ^ r3 ^ (r2 << 7);
+    r4 = r4.rotate_left(5);
+    r1 = r1.rotate_left(22);
+    r4 ^= subkeys[56];
+    r2 ^= subkeys[56 + 1];
+    r1 ^= subkeys[56 + 2];
+    r3 ^= subkeys[56 + 3];
+    r1 = !r1;
+    r0 = r3;
+    r3 &= r4;
+    r4 ^= r0;
+    r3 ^= r1;
+    r1 |= r0;
+    r2 ^= r3;
+    r1 ^= r4;
+    r4 |= r2;
+    r1 ^= r2;
+    r0 ^= r4;
+    r4 |= r3;
+    r4 ^= r1;
+    r0 ^= r3;
+    r0 ^= r4;
+    r3 = !r3;
+    r1 &= r0;
+    r1 ^= r3;
+    r4 = r4.rotate_left(13);
+    r0 = r0.rotate_left(3);
+    r2 = r2 ^ r4 ^ r0;
+    r1 = r1 ^ r0 ^ (r4 << 3);
+    r2 = r2.rotate_left(1);
+    r1 = r1.rotate_left(7);
+    r4 = r4 ^ r2 ^ r1;
+    r0 = r0 ^ r1 ^ (r2 << 7);
+    r4 = r4.rotate_left(5);
+    r0 = r0.rotate_left(22);
+    r4 ^= subkeys[60];
+    r2 ^= subkeys[60 + 1];
+    r0 ^= subkeys[60 + 2];
+    r1 ^= subkeys[60 + 3];
+    r3 = r2;
+    r2 |= r0;
+    r2 ^= r1;
+    r3 ^= r0;
+    r0 ^= r2;
+    r1 |= r3;
+    r1 &= r4;
+    r3 ^= r0;
+    r1 ^= r2;
+    r2 |= r3;
+    r2 ^= r4;
+    r4 |= r3;
+    r4 ^= r0;
+    r2 ^= r3;
+    r0 ^= r2;
+    r2 &= r4;
+    r2 ^= r3;
+    r0 = !r0;
+    r0 |= r4;
+    r3 ^= r0;
+    r3 = r3.rotate_left(13);
+    r2 = r2.rotate_left(3);
+    r1 = r1 ^ r3 ^ r2;
+    r4 = r4 ^ r2 ^ (r3 << 3);
+    r1 = r1.rotate_left(1);
+    r4 = r4.rotate_left(7);
+    r3 = r3 ^ r1 ^ r4;
+    r2 = r2 ^ r4 ^ (r1 << 7);
+    r3 = r3.rotate_left(5);
+    r2 = r2.rotate_left(22);
+    r3 ^= subkeys[64];
+    r1 ^= subkeys[64 + 1];
+    r2 ^= subkeys[64 + 2];
+    r4 ^= subkeys[64 + 3];
+    r4 ^= r3;
+    r0 = r1;
+    r1 &= r4;
+    r0 ^= r2;
+    r1 ^= r3;
+    r3 |= r4;
+    r3 ^= r0;
+    r0 ^= r4;
+    r4 ^= r2;
+    r2 |= r1;
+    r2 ^= r0;
+    r0 = !r0;
+    r0 |= r1;
+    r1 ^= r4;
+    r1 ^= r0;
+    r4 |= r3;
+    r1 ^= r4;
+    r0 ^= r4;
+    r1 = r1.rotate_left(13);
+    r2 = r2.rotate_left(3);
+    r0 = r0 ^ r1 ^ r2;
+    r3 = r3 ^ r2 ^ (r1 << 3);
+    r0 = r0.rotate_left(1);
+    r3 = r3.rotate_left(7);
+    r1 = r1 ^ r0 ^ r3;
+    r2 = r2 ^ r3 ^ (r0 << 7);
+    r1 = r1.rotate_left(5);
+    r2 = r2.rotate_left(22);
+    r1 ^= subkeys[68];
+    r0 ^= subkeys[68 + 1];
+    r2 ^= subkeys[68 + 2];
+    r3 ^= subkeys[68 + 3];
+    r1 = !r1;
+    r2 = !r2;
+    r4 = r1;
+    r1 &= r0;
+    r2 ^= r1;
+    r1 |= r3;
+    r3 ^= r2;
+    r0 ^= r1;
+    r1 ^= r4;
+    r4 |= r0;
+    r0 ^= r3;
+    r2 |= r1;
+    r2 &= r4;
+    r1 ^= r0;
+    r0 &= r2;
+    r0 ^= r1;
+    r1 &= r2;
+    r1 ^= r4;
+    r2 = r2.rotate_left(13);
+    r3 = r3.rotate_left(3);
+    r1 = r1 ^ r2 ^ r3;
+    r0 = r0 ^ r3 ^ (r2 << 3);
+    r1 = r1.rotate_left(1);
+    r0 = r0.rotate_left(7);
+    r2 = r2 ^ r1 ^ r0;
+    r3 = r3 ^ r0 ^ (r1 << 7);
+    r2 = r2.rotate_left(5);
+    r3 = r3.rotate_left(22);
+    fsm_r[0] = r2;
+    lfsr[4] = r1;
+    fsm_r[1] = r3;
+    lfsr[5] = r0;
+    r2 ^= subkeys[72];
+    r1 ^= subkeys[72 + 1];
+    r3 ^= subkeys[72 + 2];
+    r0 ^= subkeys[72 + 3];
+    r4 = r2;
+    r2 &= r3;
+    r2 ^= r0;
+    r3 ^= r1;
+    r3 ^= r2;
+    r0 |= r4;
+    r0 ^= r1;
+    r4 ^= r3;
+    r1 = r0;
+    r0 |= r4;
+    r0 ^= r2;
+    r2 &= r1;
+    r4 ^= r2;
+    r1 ^= r0;
+    r1 ^= r4;
+    r4 = !r4;
+    r3 = r3.rotate_left(13);
+    r1 = r1.rotate_left(3);
+    r0 = r0 ^ r3 ^ r1;
+    r4 = r4 ^ r1 ^ (r3 << 3);
+    r0 = r0.rotate_left(1);
+    r4 = r4.rotate_left(7);
+    r3 = r3 ^ r0 ^ r4;
+    r1 = r1 ^ r4 ^ (r0 << 7);
+    r3 = r3.rotate_left(5);
+    r1 = r1.rotate_left(22);
+    r3 ^= subkeys[76];
+    r0 ^= subkeys[76 + 1];
+    r1 ^= subkeys[76 + 2];
+    r4 ^= subkeys[76 + 3];
+    r2 = r3;
+    r3 |= r4;
+    r4 ^= r0;
+    r0 &= r2;
+    r2 ^= r1;
+    r1 ^= r4;
+    r4 &= r3;
+    r2 |= r0;
+    r4 ^= r2;
+    r3 ^= r0;
+    r2 &= r3;
+    r0 ^= r4;
+    r2 ^= r1;
+    r0 |= r3;
+    r0 ^= r1;
+    r3 ^= r4;
+    r1 = r0;
+    r0 |= r4;
+    r0 ^= r3;
+    r0 = r0.rotate_left(13);
+    r4 = r4.rotate_left(3);
+    r1 = r1 ^ r0 ^ r4;
+    r2 = r2 ^ r4 ^ (r0 << 3);
+    r1 = r1.rotate_left(1);
+    r2 = r2.rotate_left(7);
+    r0 = r0 ^ r1 ^ r2;
+    r4 = r4 ^ r2 ^ (r1 << 7);
+    r0 = r0.rotate_left(5);
+    r4 = r4.rotate_left(22);
+    r0 ^= subkeys[80];
+    r1 ^= subkeys[80 + 1];
+    r4 ^= subkeys[80 + 2];
+    r2 ^= subkeys[80 + 3];
+    r1 ^= r2;
+    r2 = !r2;
+    r4 ^= r2;
+    r2 ^= r0;
+    r3 = r1;
+    r1 &= r2;
+    r1 ^= r4;
+    r3 ^= r2;
+    r0 ^= r3;
+    r4 &= r3;
+    r4 ^= r0;
+    r0 &= r1;
+    r2 ^= r0;
+    r3 |= r1;
+    r3 ^= r0;
+    r0 |= r2;
+    r0 ^= r4;
+    r4 &= r2;
+    r0 = !r0;
+    r3 ^= r4;
+    r1 = r1.rotate_left(13);
+    r0 = r0.rotate_left(3);
+    r3 = r3 ^ r1 ^ r0;
+    r2 = r2 ^ r0 ^ (r1 << 3);
+    r3 = r3.rotate_left(1);
+    r2 = r2.rotate_left(7);
+    r1 = r1 ^ r3 ^ r2;
+    r0 = r0 ^ r2 ^ (r3 << 7);
+    r1 = r1.rotate_left(5);
+    r0 = r0.rotate_left(22);
+    r1 ^= subkeys[84];
+    r3 ^= subkeys[84 + 1];
+    r0 ^= subkeys[84 + 2];
+    r2 ^= subkeys[84 + 3];
+    r1 ^= r3;
+    r3 ^= r2;
+    r2 = !r2;
+    r4 = r3;
+    r3 &= r1;
+    r0 ^= r2;
+    r3 ^= r0;
+    r0 |= r4;
+    r4 ^= r2;
+    r2 &= r3;
+    r2 ^= r1;
+    r4 ^= r3;
+    r4 ^= r0;
+    r0 ^= r1;
+    r1 &= r2;
+    r0 = !r0;
+    r1 ^= r4;
+    r4 |= r2;
+    r0 ^= r4;
+    r3 = r3.rotate_left(13);
+    r1 = r1.rotate_left(3);
+    r2 = r2 ^ r3 ^ r1;
+    r0 = r0 ^ r1 ^ (r3 << 3);
+    r2 = r2.rotate_left(1);
+    r0 = r0.rotate_left(7);
+    r3 = r3 ^ r2 ^ r0;
+    r1 = r1 ^ r0 ^ (r2 << 7);
+    r3 = r3.rotate_left(5);
+    r1 = r1.rotate_left(22);
+    r3 ^= subkeys[88];
+    r2 ^= subkeys[88 + 1];
+    r1 ^= subkeys[88 + 2];
+    r0 ^= subkeys[88 + 3];
+    r1 = !r1;
+    r4 = r0;
+    r0 &= r3;
+    r3 ^= r4;
+    r0 ^= r1;
+    r1 |= r4;
+    r2 ^= r0;
+    r1 ^= r3;
+    r3 |= r2;
+    r1 ^= r2;
+    r4 ^= r3;
+    r3 |= r0;
+    r3 ^= r1;
+    r4 ^= r0;
+    r4 ^= r3;
+    r0 = !r0;
+    r1 &= r4;
+    r1 ^= r0;
+    r3 = r3.rotate_left(13);
+    r4 = r4.rotate_left(3);
+    r2 = r2 ^ r3 ^ r4;
+    r1 = r1 ^ r4 ^ (r3 << 3);
+    r2 = r2.rotate_left(1);
+    r1 = r1.rotate_left(7);
+    r3 = r3 ^ r2 ^ r1;
+    r4 = r4 ^ r1 ^ (r2 << 7);
+    r3 = r3.rotate_left(5);
+    r4 = r4.rotate_left(22);
+    r3 ^= subkeys[92];
+    r2 ^= subkeys[92 + 1];
+    r4 ^= subkeys[92 + 2];
+    r1 ^= subkeys[92 + 3];
+    r0 = r2;
+    r2 |= r4;
+    r2 ^= r1;
+    r0 ^= r4;
+    r4 ^= r2;
+    r1 |= r0;
+    r1 &= r3;
+    r0 ^= r4;
+    r1 ^= r2;
+    r2 |= r0;
+    r2 ^= r3;
+    r3 |= r0;
+    r3 ^= r4;
+    r2 ^= r0;
+    r4 ^= r2;
+    r2 &= r3;
+    r2 ^= r0;
+    r4 = !r4;
+    r4 |= r3;
+    r0 ^= r4;
+    r0 = r0.rotate_left(13);
+    r2 = r2.rotate_left(3);
+    r1 = r1 ^ r0 ^ r2;
+    r3 = r3 ^ r2 ^ (r0 << 3);
+    r1 = r1.rotate_left(1);
+    r3 = r3.rotate_left(7);
+    r0 = r0 ^ r1 ^ r3;
+    r2 = r2 ^ r3 ^ (r1 << 7);
+    r0 = r0.rotate_left(5);
+    r2 = r2.rotate_left(22);
+    r0 ^= subkeys[96];
+    r1 ^= subkeys[96 + 1];
+    r2 ^= subkeys[96 + 2];
+    r3 ^= subkeys[96 + 3];
+    lfsr[3] = r0;
+    lfsr[2] = r1;
+    lfsr[1] = r2;
+    lfsr[0] = r3;
+}
+
+
+impl SynchronousStreamCipher for Sosemanuk {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        assert!(input.len() == output.len());
+        for (x, y) in input.iter().zip(output.iter_mut()) {
+            *y = *x ^ self.next();
+        }
+    }
+}
+
+impl Encryptor for Sosemanuk {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl Decryptor for Sosemanuk {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+
+#[cfg(test)]
+mod test {
+    use sosemanuk::Sosemanuk;
+    use symmetriccipher::SynchronousStreamCipher;
+    use serialize::hex::{FromHex};
+
+    // Vectors from http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/sosemanuk/unverified.test-vectors?rev=108&view=markup
+
+    #[test]
+    fn test_sosemanuk_ecrypt_set_1_vector_0() {
+        let key = "8000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap();
+        let nonce = "00000000000000000000000000000000".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "1782FABFF497A0E89E16E1BCF22F0FE8AA8C566D293AA35B2425E4F26E31C3E7701C08A0D614AF3D3861A7DFF7D6A38A0EFE84A29FADF68D390A3D15B75C972D";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+
+    #[test]
+    fn test_sosemanuk_ecrypt_set_2_vector_63() {
+        let key = "3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F".from_hex().unwrap();
+        let nonce = "00000000000000000000000000000000".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "7D755F30A2B747A50D7D28147EDF0B3E3FAB6856A7373C7306C00D1D4076969354D7AB4343C0115E7839502C5C699ED06DB119968AEBFD08D8B968A7161D613F";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+
+    #[test]
+    fn test_sosemanuk_ecrypt_set_2_vector_90() {
+        let key = "5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A".from_hex().unwrap();
+        let nonce = "00000000000000000000000000000000".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "F5D7D72686322D1751AFD16A1DD98282D2B9A1EE0C305DF52F86AE1B831E90C22E2DE089CEE656A992736385D9135B823B3611098674BF820986A4342B89ABF7";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+
+    #[test]
+    fn test_sosemanuk_ecrypt_set_3_vector_135() {
+        let key = "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4".from_hex().unwrap();
+        let nonce = "00000000000000000000000000000000".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "9D7EE5A10BBB0756D66B8DAA5AE08F41B05C9E7C6B13532EAA81F224282B61C66DEEE5AF6251DB26C49B865C5AD4250AE89787FC86C35409CF2986CF820293AA";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+
+    #[test]
+    fn test_sosemanuk_ecrypt_set_3_vector_207() {
+        let key = "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE".from_hex().unwrap();
+        let nonce = "00000000000000000000000000000000".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "F028923659C6C0A17065E013368D93EBCF2F4FD892B6E27E104EF0A2605708EA26336AE966D5058BC144F7954FE2FC3C258F00734AA5BEC8281814B746197084";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+
+    #[test]
+    fn test_sosemanuk_ecrypt_set_6_vector_3() {
+        let key = "0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C".from_hex().unwrap();
+        let nonce = "288FF65DC42B92F960C72E95FC63CA31".from_hex().unwrap();
+
+        let input = [0u8; 64];
+        let expected_output_hex = "1FC4F2E266B21C24FDDB3492D40A3FA6DE32CDF13908511E84420ABDFA1D3B0FEC600F83409C57CBE0394B90CDB1D759243EFD8B8E2AB7BC453A8D8A3515183E";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 64];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+
+    // From TEST_VECTOR_128.txt from reference C implementation
+
+    #[test]
+    fn test_sosemanuk_vector128_test1() {
+        let key = "A7C083FEB7".from_hex().unwrap();
+        let nonce = "00112233445566778899AABBCCDDEEFF".from_hex().unwrap();
+
+        let input = [0u8; 160];
+        let expected_output_hex = "FE81D2162C9A100D04895C454A77515BBE6A431A935CB90E2221EBB7EF502328943539492EFF6310C871054C2889CC728F82E86B1AFFF4334B6127A13A155C75151630BD482EB673FF5DB477FA6C53EBE1A4EC38C23C5400C315455D93A2ACED9598604727FA340D5F2A8BD757B77833F74BD2BC049313C80616B4A06268AE350DB92EEC4FA56C171374A67A80C006D0EAD048CE7B640F17D3D5A62D1F251C21";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 160];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+
+    #[test]
+    fn test_sosemanuk_vector128_test2() {
+        let key = "00112233445566778899AABBCCDDEEFF".from_hex().unwrap();
+        let nonce = "8899AABBCCDDEEFF0011223344556677".from_hex().unwrap();
+
+        let input = [0u8; 160];
+        let expected_output_hex = "FA61DBEB71178131A77C714BD2EABF4E1394207A25698AA1308F2F063A0F760604CF67569BA59A3DFAD7F00145C78D29C5FFE5F964950486424451952C84039D234D9C37EECBBCA1EBFB0DD16EA1194A6AFC1A460E33E33FE8D55C48977079C687810D74FEDDEE1B3986218FB1E1C1765E4DF64D7F6911C19A270C59C74B24461717F86CE3B11808FACD4F2E714168DA44CF6360D54DDA2241BCB79401A4EDCC";
+        let expected_output = expected_output_hex.from_hex().unwrap();
+
+        let mut output = [0u8; 160];
+
+        let mut sosemanuk = Sosemanuk::new(key.as_ref(), nonce.as_ref());
+        sosemanuk.process(&input, &mut output);
+        let expected: &[u8] = expected_output.as_ref();
+        assert!(output.as_ref() == expected);
+    }
+}
+
+#[cfg(all(test, feature = "with-bench"))]
+mod bench {
+    use test::Bencher;
+    use symmetriccipher::SynchronousStreamCipher;
+    use sosemanuk::Sosemanuk;
+
+    #[bench]
+    pub fn sosemanuk_10(bh: & mut Bencher) {
+        let mut sosemanuk = Sosemanuk::new(&[0; 32], &[0; 16]);
+        let input = [1u8; 10];
+        let mut output = [0u8; 10];
+        bh.iter( || {
+            sosemanuk.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn sosemanuk_1k(bh: & mut Bencher) {
+        let mut sosemanuk = Sosemanuk::new(&[0; 32], &[0; 16]);
+        let input = [1u8; 1024];
+        let mut output = [0u8; 1024];
+        bh.iter( || {
+            sosemanuk.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+
+    #[bench]
+    pub fn sosemanuk_64k(bh: & mut Bencher) {
+        let mut sosemanuk = Sosemanuk::new(&[0; 32], &[0; 16]);
+        let input = [1u8; 65536];
+        let mut output = [0u8; 65536];
+        bh.iter( || {
+            sosemanuk.process(&input, &mut output);
+        });
+        bh.bytes = input.len() as u64;
+    }
+}
diff --git a/third_party/rust-crypto/src/step_by.rs b/third_party/rust-crypto/src/step_by.rs
new file mode 100644
index 0000000..ac12d4b
--- /dev/null
+++ b/third_party/rust-crypto/src/step_by.rs
@@ -0,0 +1,50 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// This module just implements a simple verison of step_by() since
+/// the function from the standard library is currently unstable.
+/// This should be removed once that function becomes stable.
+
+use std::ops::{Add, Range};
+
+#[derive(Clone)]
+pub struct StepUp<T> {
+    next: T,
+    end: T,
+    ammount: T
+}
+
+impl <T> Iterator for StepUp<T> where
+        T: Add<T, Output = T> + PartialOrd + Copy {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        if self.next < self.end {
+            let n = self.next;
+            self.next = self.next + self.ammount;
+            Some(n)
+        } else {
+            None
+        }
+    }
+}
+
+pub trait RangeExt<T> {
+    fn step_up(self, ammount: T) -> StepUp<T>;
+}
+
+impl <T> RangeExt<T> for Range<T> where
+        T: Add<T, Output = T> + PartialOrd + Copy {
+    fn step_up(self, ammount: T) -> StepUp<T> {
+        StepUp {
+            next: self.start,
+            end: self.end,
+            ammount: ammount
+        }
+    }
+}
+
diff --git a/third_party/rust-crypto/src/symmetriccipher.rs b/third_party/rust-crypto/src/symmetriccipher.rs
new file mode 100644
index 0000000..0837a94
--- /dev/null
+++ b/third_party/rust-crypto/src/symmetriccipher.rs
@@ -0,0 +1,71 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::prelude::v1::*;
+use buffer::{BufferResult, RefReadBuffer, RefWriteBuffer};
+use cryptoutil::symm_enc_or_dec;
+
+pub trait BlockEncryptor {
+    fn block_size(&self) -> usize;
+    fn encrypt_block(&self, input: &[u8], output: &mut [u8]);
+}
+
+pub trait BlockEncryptorX8 {
+    fn block_size(&self) -> usize;
+    fn encrypt_block_x8(&self, input: &[u8], output: &mut [u8]);
+}
+
+pub trait BlockDecryptor {
+    fn block_size(&self) -> usize;
+    fn decrypt_block(&self, input: &[u8], output: &mut [u8]);
+}
+
+pub trait BlockDecryptorX8 {
+    fn block_size(&self) -> usize;
+    fn decrypt_block_x8(&self, input: &[u8], output: &mut [u8]);
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum SymmetricCipherError {
+    InvalidLength,
+    InvalidPadding
+}
+
+pub trait Encryptor {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, eof: bool)
+        -> Result<BufferResult, SymmetricCipherError>;
+}
+
+pub trait Decryptor {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, eof: bool)
+        -> Result<BufferResult, SymmetricCipherError>;
+}
+
+pub trait SynchronousStreamCipher {
+    fn process(&mut self, input: &[u8], output: &mut [u8]);
+}
+
+// TODO - Its a bit unclear to me why this is necessary
+impl SynchronousStreamCipher for Box<SynchronousStreamCipher + 'static> {
+    fn process(&mut self, input: &[u8], output: &mut [u8]) {
+        let me = &mut **self;
+        me.process(input, output);
+    }
+}
+
+impl Encryptor for Box<SynchronousStreamCipher + 'static> {
+    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
+
+impl Decryptor for Box<SynchronousStreamCipher + 'static> {
+    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
+            -> Result<BufferResult, SymmetricCipherError> {
+        symm_enc_or_dec(self, input, output)
+    }
+}
diff --git a/third_party/rust-crypto/src/util.rs b/third_party/rust-crypto/src/util.rs
new file mode 100644
index 0000000..ac938aa
--- /dev/null
+++ b/third_party/rust-crypto/src/util.rs
@@ -0,0 +1,80 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use sgx_trts::libc;
+
+//#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+extern {
+    pub fn rust_crypto_util_supports_aesni() -> u32;
+}
+
+//#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub fn supports_aesni() -> bool {
+    unsafe {
+        rust_crypto_util_supports_aesni() != 0
+    }
+}
+
+extern {
+    pub fn rust_crypto_util_fixed_time_eq_asm(
+            lhsp: *const u8,
+            rhsp: *const u8,
+            count: libc::size_t) -> u32;
+    pub fn rust_crypto_util_secure_memset(
+            dst: *mut u8,
+            val: libc::uint8_t,
+            count: libc::size_t);
+}
+
+pub fn secure_memset(dst: &mut [u8], val: u8) {
+    unsafe {
+        rust_crypto_util_secure_memset(
+            dst.as_mut_ptr(),
+            val,
+            dst.len() as libc::size_t);
+    }
+}
+
+/// Compare two vectors using a fixed number of operations. If the two vectors are not of equal
+/// length, the function returns false immediately.
+pub fn fixed_time_eq(lhs: &[u8], rhs: &[u8]) -> bool {
+    if lhs.len() != rhs.len() {
+        false
+    } else {
+        let count = lhs.len() as libc::size_t;
+
+        unsafe {
+            let lhsp = lhs.get_unchecked(0);
+            let rhsp = rhs.get_unchecked(0);
+            rust_crypto_util_fixed_time_eq_asm(lhsp, rhsp, count) == 0
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use util::fixed_time_eq;
+
+    #[test]
+    pub fn test_fixed_time_eq() {
+        let a = [0, 1, 2];
+        let b = [0, 1, 2];
+        let c = [0, 1, 9];
+        let d = [9, 1, 2];
+        let e = [2, 1, 0];
+        let f = [2, 2, 2];
+        let g = [0, 0, 0];
+
+        assert!(fixed_time_eq(&a, &a));
+        assert!(fixed_time_eq(&a, &b));
+
+        assert!(!fixed_time_eq(&a, &c));
+        assert!(!fixed_time_eq(&a, &d));
+        assert!(!fixed_time_eq(&a, &e));
+        assert!(!fixed_time_eq(&a, &f));
+        assert!(!fixed_time_eq(&a, &g));
+    }
+}
diff --git a/third_party/rust-crypto/src/util_helpers.asm b/third_party/rust-crypto/src/util_helpers.asm
new file mode 100644
index 0000000..6e181cd
--- /dev/null
+++ b/third_party/rust-crypto/src/util_helpers.asm
@@ -0,0 +1,126 @@
+ifndef X64
+.686p
+.XMM
+.model flat, C
+endif
+
+.code
+
+rust_crypto_util_supports_aesni PROC public
+  ; Return false since the AES-NI function have not been
+  ; converted to assembly
+  xor eax, eax
+  ret
+rust_crypto_util_supports_aesni ENDP
+
+; The rust_crypto_util_fixed_time_eq_asm for X86-64
+ifdef X64
+rust_crypto_util_fixed_time_eq_asm PROC public lhs:QWORD, rhs:QWORD, count:QWORD
+  ; lhs is in RCX
+  ; rhs is in RDX
+  ; count is in R8
+
+  ; set the return value initially to 0
+  xor eax, eax
+
+  test r8, r8
+  jz DONE
+
+  BEGIN:
+
+  mov r10b, [rcx]
+  xor r10b, [rdx]
+  or al, r10b
+
+  inc rcx
+  inc rdx
+  dec r8
+  jnz BEGIN
+
+  DONE:
+
+  ret
+rust_crypto_util_fixed_time_eq_asm ENDP
+endif
+
+; The rust_crypto_util_fixed_time_eq_asm for X86 (32-bit)
+ifndef X64
+rust_crypto_util_fixed_time_eq_asm PROC public lhs:DWORD, rhs:DWORD, count:DWORD
+  push ebx
+  push esi
+
+  mov ecx, lhs
+  mov edx, rhs
+  mov esi, count
+
+  xor eax, eax
+
+  test esi, esi
+  jz DONE
+
+  BEGIN:
+
+  mov bl, [ecx]
+  xor bl, [edx]
+  or al, bl
+
+  inc ecx
+  inc edx
+  dec esi
+  jnz BEGIN
+
+  DONE:
+
+  pop esi
+  pop ebx
+
+  ret
+rust_crypto_util_fixed_time_eq_asm ENDP
+endif
+
+ifdef X64
+rust_crypto_util_secure_memset PROC public dst:QWORD, val:BYTE, count:QWORD
+  ; dst is in RCX
+  ; val is in RDX
+  ; count is in R8
+
+  test r8, r8
+  jz DONE
+
+  BEGIN:
+
+  mov [rcx], dl
+  inc rcx
+  dec r8
+  jnz BEGIN
+
+  DONE:
+
+  ret
+rust_crypto_util_secure_memset ENDP
+endif
+
+ifndef X64
+rust_crypto_util_secure_memset PROC public dst:DWORD, val:BYTE, count:DWORD
+  mov eax, dst
+  mov cl, val
+  mov edx, count
+
+  test edx, edx
+  jz DONE
+
+  BEGIN:
+
+  mov [eax], cl
+  inc eax
+  dec edx
+  jnz BEGIN
+
+  DONE:
+
+  ret
+rust_crypto_util_secure_memset ENDP
+endif
+
+end
+
diff --git a/third_party/rust-crypto/src/util_helpers.c b/third_party/rust-crypto/src/util_helpers.c
new file mode 100644
index 0000000..20b5fdd
--- /dev/null
+++ b/third_party/rust-crypto/src/util_helpers.c
@@ -0,0 +1,52 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+uint32_t rust_crypto_util_supports_aesni() {
+    uint32_t flags;
+    asm(
+        "mov $1, %%eax; cpuid;"
+        : "=c" (flags) // output
+        : // input
+        : "eax", "ebx", "edx" // clobbers
+    );
+    return flags & 0x02000000;
+}
+
+uint32_t rust_crypto_util_fixed_time_eq_asm(uint8_t* lhsp, uint8_t* rhsp, size_t count) {
+    if (count == 0) {
+        return 1;
+    }
+    uint8_t result = 0;
+    asm(
+        " \
+            1: \
+            \
+            mov (%1), %%cl; \
+            xor (%2), %%cl; \
+            or %%cl, %0; \
+            \
+            inc %1; \
+            inc %2; \
+            dec %3; \
+            jnz 1b; \
+        "
+        : "+&r" (result), "+&r" (lhsp), "+&r" (rhsp), "+&r" (count) // all input and output
+        : // input
+        : "cl", "cc" // clobbers
+    );
+
+    return result;
+}
+
+void rust_crypto_util_secure_memset(uint8_t* dst, uint8_t val, size_t count) {
+    memset(dst, val, count);
+    asm volatile("" : : "g" (dst) : "memory");
+}
+
diff --git a/third_party/rust-crypto/src/whirlpool.rs b/third_party/rust-crypto/src/whirlpool.rs
new file mode 100644
index 0000000..749f6d7
--- /dev/null
+++ b/third_party/rust-crypto/src/whirlpool.rs
@@ -0,0 +1,812 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+An implementation of the Whirlpool cryptographic hash algorithm.
+
+This is the algorithm recommended by NESSIE (New European Schemes for Signatures,
+Integrity and Encryption; an European research project).
+
+The constants used by Whirlpool were changed twice (2001 and 2003) - this module
+only implements the most recent standard. The two older Whirlpool implementations
+(sometimes called Whirlpool-0 (pre 2001) and Whirlpool-T (pre 2003)) were not used
+much anyway (both have never been recommended by NESSIE).
+
+For details see <http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html>.
+
+# Usage
+
+```rust
+use self::crypto::whirlpool::Whirlpool;
+use self::crypto::digest::Digest;
+
+let mut hasher = Whirlpool::new();
+hasher.input_str("Hello Whirlpool");
+let result = hasher.result_str();
+
+assert_eq!(result,
+    concat!("8eaccdc136903c458ea0b1376be2a5fc",
+            "9dc5b8ce8892a3b4f43366e2610c206c",
+            "a373816495e63db0fff2ff25f75aa716",
+            "2f332c9f518c3036456502a8414d300a"));
+```
+*/
+
+use std::mem::uninitialized;
+use cryptoutil::{write_u64_be, FixedBuffer64, FixedBuffer};
+use digest::Digest;
+
+#[derive(Clone, Copy)]
+pub struct Whirlpool {
+    bit_length: [u8; 32],
+    buffer: FixedBuffer64,
+    hash: [u64; 8],
+    finalized: bool,
+}
+
+impl Whirlpool {
+    pub fn new() -> Whirlpool {
+        Whirlpool{
+            bit_length: [0; 32],
+            buffer: FixedBuffer64::new(),
+            hash: [0; 8],
+            finalized: false,
+        }
+    }
+}
+
+impl Digest for Whirlpool {
+    fn input(&mut self, source: &[u8]) {
+        assert!(!self.finalized);
+
+        // (byte length * 8) = (bit lenght) converted in a 72 bit uint
+        let len = source.len() as u64;
+        let len_bits = [
+            ((len >> (56 + 5))       ) as u8,
+            ((len >> (48 + 5)) & 0xff) as u8,
+            ((len >> (40 + 5)) & 0xff) as u8,
+            ((len >> (32 + 5)) & 0xff) as u8,
+            ((len >> (24 + 5)) & 0xff) as u8,
+            ((len >> (16 + 5)) & 0xff) as u8,
+            ((len >> ( 8 + 5)) & 0xff) as u8,
+            ((len >> ( 0 + 5)) & 0xff) as u8,
+            ((len << 3) & 0xff) as u8,
+        ];
+
+        // adds the 72 bit len_bits to the 256 bit self.bit_length
+        let mut carry = false;
+        for i in 0..32 {
+            let mut x = self.bit_length[self.bit_length.len() - i - 1] as u16;
+            
+            if i < len_bits.len() {
+                x += len_bits[len_bits.len() - i - 1] as u16;
+            } else if !carry {
+                break;
+            }
+
+            if carry {
+                x += 1;
+            }
+            
+            carry = x > 0xff;
+            let pos = self.bit_length.len() -i - 1;
+            self.bit_length[pos] = (x & 0xff) as u8;
+        }
+
+        // process the data itself
+        let hash = &mut self.hash;
+        self.buffer.input(source, |b| { process_buffer(hash, b); });
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        if !self.finalized {
+            self.finalized = true;
+
+            // padding
+            assert!(self.buffer.remaining() >= 1);
+            let hash = &mut self.hash;
+            self.buffer.input(&[0b10000000], |b| { process_buffer(hash, b); });
+
+            if self.buffer.remaining() < self.bit_length.len() {
+                let size = self.buffer.size();
+                self.buffer.zero_until(size);
+                process_buffer(hash, self.buffer.full_buffer());
+            }
+
+            // length
+            self.buffer.zero_until(32);
+            self.buffer.input(&self.bit_length, |b| { process_buffer(hash, b); });
+            assert!(self.buffer.position() == 0);
+        }
+
+        // done!
+        write_u64_be(&mut out[0..8], self.hash[0]);
+        write_u64_be(&mut out[8..16], self.hash[1]);
+        write_u64_be(&mut out[16..24], self.hash[2]);
+        write_u64_be(&mut out[24..32], self.hash[3]);
+        write_u64_be(&mut out[32..40], self.hash[4]);
+        write_u64_be(&mut out[40..48], self.hash[5]);
+        write_u64_be(&mut out[48..56], self.hash[6]);
+        write_u64_be(&mut out[56..64], self.hash[7]);
+    }
+
+    fn reset(&mut self) {
+        self.bit_length = [0; 32];
+        self.buffer.reset();
+        self.finalized = false;
+        self.hash = [0; 8];    
+    }
+
+    fn output_bits(&self) -> usize {
+        512
+    }
+
+    fn block_size(&self) -> usize {
+        512
+    }
+}
+
+fn process_buffer(hash: &mut[u64; 8], buffer: &[u8]) {
+    let mut k: [u64; 8] = unsafe { uninitialized() };
+    let mut block: [u64; 8] = unsafe { uninitialized() };
+    let mut state: [u64; 8] = unsafe { uninitialized() };
+    let mut l: [u64; 8] = unsafe { uninitialized() };
+
+    for i in 0..8 {
+        block[i] =
+            ((buffer[i * 8 + 0] as u64) << 56) ^
+            ((buffer[i * 8 + 1] as u64) << 48) ^
+            ((buffer[i * 8 + 2] as u64) << 40) ^
+            ((buffer[i * 8 + 3] as u64) << 32) ^
+            ((buffer[i * 8 + 4] as u64) << 24) ^
+            ((buffer[i * 8 + 5] as u64) << 16) ^
+            ((buffer[i * 8 + 6] as u64) <<  8) ^
+            ((buffer[i * 8 + 7] as u64)      );
+        k[i] = hash[i];
+        state[i] = block[i] ^ k[i];
+    }
+
+    for r in 1..(R + 1) /* [1, R] */ {
+        for i in 0..8 {
+            l[i] =
+                C0[((k[(0 + i) % 8] >> 56)       ) as usize] ^
+                C1[((k[(7 + i) % 8] >> 48) & 0xff) as usize] ^
+                C2[((k[(6 + i) % 8] >> 40) & 0xff) as usize] ^
+                C3[((k[(5 + i) % 8] >> 32) & 0xff) as usize] ^
+                C4[((k[(4 + i) % 8] >> 24) & 0xff) as usize] ^
+                C5[((k[(3 + i) % 8] >> 16) & 0xff) as usize] ^
+                C6[((k[(2 + i) % 8] >>  8) & 0xff) as usize] ^
+                C7[((k[(1 + i) % 8]      ) & 0xff) as usize] ^
+                if i == 0 { RC[r] } else { 0 };
+        }
+        k = l;
+        for i in 0..8 {
+            l[i] =
+                C0[((state[(0 + i) % 8] >> 56)       ) as usize] ^
+                C1[((state[(7 + i) % 8] >> 48) & 0xff) as usize] ^
+                C2[((state[(6 + i) % 8] >> 40) & 0xff) as usize] ^
+                C3[((state[(5 + i) % 8] >> 32) & 0xff) as usize] ^
+                C4[((state[(4 + i) % 8] >> 24) & 0xff) as usize] ^
+                C5[((state[(3 + i) % 8] >> 16) & 0xff) as usize] ^
+                C6[((state[(2 + i) % 8] >>  8) & 0xff) as usize] ^
+                C7[((state[(1 + i) % 8]      ) & 0xff) as usize] ^
+                k[i];
+        }
+        state = l;
+    }
+
+    for i in 0..8 {
+        hash[i] ^= state[i] ^ block[i];
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use digest::Digest;
+    use std::ascii::AsciiExt;
+
+    static TESTS: [(&'static str, &'static str); 18] = [
+        ("", "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3"),
+        ("\0", "4D9444C212955963D425A410176FCCFB74161E6839692B4C11FDE2ED6EB559EFE0560C39A7B61D5A8BCABD6817A3135AF80F342A4942CCAAE745ABDDFB6AFED0"),
+        ("\0\0", "8BDC9D4471D0DABD8812098B8CBDF5090BEDDB3D582917A61E176E3D22529D753FED9A37990CA18583855EFBC4F26E88F62002F67722EB05F74C7EA5E07013F5"),
+        ("\0\0\0", "86AABFD4A83C3551CC0A63185616ACB41CDFA96118F1FFB28376B41067EFA25FB6C889662435BFC11A4F0936BE6BCC2C3E905C4686DB06159C40E4DD67DD983F"),
+        ("\0\0\0\0", "4ED6B52E915F09A803677C3131F7B34655D32817505D89A8CC07ED073CA3FEDDDD4A57CC53696027E824AB9822630087657C6FC6A28836CF1F252ED204BCA576"),
+        ("\0\0\0\0\0", "4A1D1D8380F38896B6FC5788C559F92727ACFD4DFA7081C72302B17E1ED437B30A24CFD75A16FD71B6BF5AA7AE5C7084594E3003A0B71584DC993681F902DF6F"),
+        ("\0\0\0\0\0\0", "A2A379B0900A3C51809F4216AA3347FEC486D50EC7376553349C5CF2A767049A87BF1AC4642185144924259ECF6B5C3B48B55A20565DE289361E8AE5EAFC5802"),
+        ("\0\0\0\0\0\0\0", "23EB3E26A1543558672F29E196304CD778EA459CC8E38D199DE0CC748BD32D58090FADB39E7C7B6954322DE990556D001BA457061C4367C6FA5D6961F1046E2F"),
+        ("\0\0\0\0\0\0\0\0", "7207BE34FEE657189AF2748358F46C23175C1DCDD6741A9BDB139AEB255B618B711775FC258AC0FA53C350305862415EA121C65BF9E2FAE06CBD81355D928AD7"),
+        ("\0\0\0\0\0\0\0\0\0", "FEF7D0BE035D1860E95644864B199C3A94EB23AB7920134B73239A320EB7CAE450092BC4BA8B9809E20C33937C37C52B52CA90241657FFD0816420C01F4FADA8"),
+        ("\0\0\0\0\0\0\0\0\0\0", "CAAFB557AEF0FAE9F20BCCCDA7F3DC769C478A70508F4F2D180303598276934C410BD3D17627159A9C55B5265B516BA7F3EEF67FBB08D9F22E585BC45964C4D1"),
+        ("\0\0\0\0\0\0\0\0\0\0\0", "8FE2B488CA099DB8E421768E1E7E0193FFAA3000E8281403795575FE7D03BD87298C4F64B1C4311093E43DE4D80049645782EE268C3653C7A5C13DA3773D5564"),
+        ("a", "8ACA2602792AEC6F11A67206531FB7D7F0DFF59413145E6973C45001D0087B42D11BC645413AEFF63A42391A39145A591A92200D560195E53B478584FDAE231A"),
+        ("abc", "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5"),
+        ("message digest", "378C84A4126E2DC6E56DCC7458377AAC838D00032230F53CE1F5700C0FFB4D3B8421557659EF55C106B4B52AC5A4AAA692ED920052838F3362E86DBD37A8903E"),
+        ("abcdefghijklmnopqrstuvwxyz", "F1D754662636FFE92C82EBB9212A484A8D38631EAD4238F5442EE13B8054E41B08BF2A9251C30B6A0B8AAE86177AB4A6F68F673E7207865D5D9819A3DBA4EB3B"),
+        ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "DC37E008CF9EE69BF11F00ED9ABA26901DD7C28CDEC066CC6AF42E40F82F3A1E08EBA26629129D8FB7CB57211B9281A65517CC879D7B962142C65F5A7AF01467"),
+        ("012345678901234567890123456789012345678901234567890123456789012", "6B315FB4EB6A7DDEF9EA173BAAB307ED257F21B7D86DCB85EE03A7CF417A872627DBCCF67E3D018D4D8F61668B416875C5EE21CAF7E158E4B1ECA73D60048701"),
+    ];
+
+    #[test]
+    fn whirlpool_static_test() {
+        let mut d = Whirlpool::new();
+        for tuple in TESTS.iter() {
+            let (s, hash) = *tuple;
+            d.input_str(s);
+            let result = d.result_str().to_ascii_lowercase();
+            println!("{:?}", s);
+            assert!(result == hash.to_ascii_lowercase());
+            d.reset();
+        }
+    }
+
+    #[test]
+    fn whirlpool_1000000a_test() {
+        let mut d = Whirlpool::new();
+        let mut s = String::new();
+        for _ in 0..50000 {
+            s.push_str("aaaaaaaaaa");
+            d.input_str("aaaaaaaaaa");
+        }
+        d.input_str(s.as_ref());
+
+        println!("{:?}", d.result_str().to_ascii_uppercase());
+        assert!(s.len() == 500000);
+        assert!(d.result_str().to_ascii_uppercase() == "0C99005BEB57EFF50A7CF005560DDF5D29057FD86B20BFD62DECA0F1CCEA4AF51FC15490EDDC47AF32BB2B66C34FF9AD8C6008AD677F77126953B226E4ED8B01");
+    }
+}
+
+static R: usize = 10;
+
+static RC: [u64; 11 /* R + 1 */] = [
+    0x0000000000000000,
+    0x1823c6e887b8014f,
+    0x36a6d2f5796f9152,
+    0x60bc9b8ea30c7b35,
+    0x1de0d7c22e4bfe57,
+    0x157737e59ff04ada,
+    0x58c9290ab1a06b85,
+    0xbd5d10f4cb3e0567,
+    0xe427418ba77d95d8,
+    0xfbee7c66dd17479e,
+    0xca2dbf07ad5a8333,
+];
+
+static C0: [u64; 256] = [
+    0x18186018c07830d8, 0x23238c2305af4626, 0xc6c63fc67ef991b8, 0xe8e887e8136fcdfb,
+    0x878726874ca113cb, 0xb8b8dab8a9626d11, 0x0101040108050209, 0x4f4f214f426e9e0d,
+    0x3636d836adee6c9b, 0xa6a6a2a6590451ff, 0xd2d26fd2debdb90c, 0xf5f5f3f5fb06f70e,
+    0x7979f979ef80f296, 0x6f6fa16f5fcede30, 0x91917e91fcef3f6d, 0x52525552aa07a4f8,
+    0x60609d6027fdc047, 0xbcbccabc89766535, 0x9b9b569baccd2b37, 0x8e8e028e048c018a,
+    0xa3a3b6a371155bd2, 0x0c0c300c603c186c, 0x7b7bf17bff8af684, 0x3535d435b5e16a80,
+    0x1d1d741de8693af5, 0xe0e0a7e05347ddb3, 0xd7d77bd7f6acb321, 0xc2c22fc25eed999c,
+    0x2e2eb82e6d965c43, 0x4b4b314b627a9629, 0xfefedffea321e15d, 0x575741578216aed5,
+    0x15155415a8412abd, 0x7777c1779fb6eee8, 0x3737dc37a5eb6e92, 0xe5e5b3e57b56d79e,
+    0x9f9f469f8cd92313, 0xf0f0e7f0d317fd23, 0x4a4a354a6a7f9420, 0xdada4fda9e95a944,
+    0x58587d58fa25b0a2, 0xc9c903c906ca8fcf, 0x2929a429558d527c, 0x0a0a280a5022145a,
+    0xb1b1feb1e14f7f50, 0xa0a0baa0691a5dc9, 0x6b6bb16b7fdad614, 0x85852e855cab17d9,
+    0xbdbdcebd8173673c, 0x5d5d695dd234ba8f, 0x1010401080502090, 0xf4f4f7f4f303f507,
+    0xcbcb0bcb16c08bdd, 0x3e3ef83eedc67cd3, 0x0505140528110a2d, 0x676781671fe6ce78,
+    0xe4e4b7e47353d597, 0x27279c2725bb4e02, 0x4141194132588273, 0x8b8b168b2c9d0ba7,
+    0xa7a7a6a7510153f6, 0x7d7de97dcf94fab2, 0x95956e95dcfb3749, 0xd8d847d88e9fad56,
+    0xfbfbcbfb8b30eb70, 0xeeee9fee2371c1cd, 0x7c7ced7cc791f8bb, 0x6666856617e3cc71,
+    0xdddd53dda68ea77b, 0x17175c17b84b2eaf, 0x4747014702468e45, 0x9e9e429e84dc211a,
+    0xcaca0fca1ec589d4, 0x2d2db42d75995a58, 0xbfbfc6bf9179632e, 0x07071c07381b0e3f,
+    0xadad8ead012347ac, 0x5a5a755aea2fb4b0, 0x838336836cb51bef, 0x3333cc3385ff66b6,
+    0x636391633ff2c65c, 0x02020802100a0412, 0xaaaa92aa39384993, 0x7171d971afa8e2de,
+    0xc8c807c80ecf8dc6, 0x19196419c87d32d1, 0x494939497270923b, 0xd9d943d9869aaf5f,
+    0xf2f2eff2c31df931, 0xe3e3abe34b48dba8, 0x5b5b715be22ab6b9, 0x88881a8834920dbc,
+    0x9a9a529aa4c8293e, 0x262698262dbe4c0b, 0x3232c8328dfa64bf, 0xb0b0fab0e94a7d59,
+    0xe9e983e91b6acff2, 0x0f0f3c0f78331e77, 0xd5d573d5e6a6b733, 0x80803a8074ba1df4,
+    0xbebec2be997c6127, 0xcdcd13cd26de87eb, 0x3434d034bde46889, 0x48483d487a759032,
+    0xffffdbffab24e354, 0x7a7af57af78ff48d, 0x90907a90f4ea3d64, 0x5f5f615fc23ebe9d,
+    0x202080201da0403d, 0x6868bd6867d5d00f, 0x1a1a681ad07234ca, 0xaeae82ae192c41b7,
+    0xb4b4eab4c95e757d, 0x54544d549a19a8ce, 0x93937693ece53b7f, 0x222288220daa442f,
+    0x64648d6407e9c863, 0xf1f1e3f1db12ff2a, 0x7373d173bfa2e6cc, 0x12124812905a2482,
+    0x40401d403a5d807a, 0x0808200840281048, 0xc3c32bc356e89b95, 0xecec97ec337bc5df,
+    0xdbdb4bdb9690ab4d, 0xa1a1bea1611f5fc0, 0x8d8d0e8d1c830791, 0x3d3df43df5c97ac8,
+    0x97976697ccf1335b, 0x0000000000000000, 0xcfcf1bcf36d483f9, 0x2b2bac2b4587566e,
+    0x7676c57697b3ece1, 0x8282328264b019e6, 0xd6d67fd6fea9b128, 0x1b1b6c1bd87736c3,
+    0xb5b5eeb5c15b7774, 0xafaf86af112943be, 0x6a6ab56a77dfd41d, 0x50505d50ba0da0ea,
+    0x45450945124c8a57, 0xf3f3ebf3cb18fb38, 0x3030c0309df060ad, 0xefef9bef2b74c3c4,
+    0x3f3ffc3fe5c37eda, 0x55554955921caac7, 0xa2a2b2a2791059db, 0xeaea8fea0365c9e9,
+    0x656589650fecca6a, 0xbabad2bab9686903, 0x2f2fbc2f65935e4a, 0xc0c027c04ee79d8e,
+    0xdede5fdebe81a160, 0x1c1c701ce06c38fc, 0xfdfdd3fdbb2ee746, 0x4d4d294d52649a1f,
+    0x92927292e4e03976, 0x7575c9758fbceafa, 0x06061806301e0c36, 0x8a8a128a249809ae,
+    0xb2b2f2b2f940794b, 0xe6e6bfe66359d185, 0x0e0e380e70361c7e, 0x1f1f7c1ff8633ee7,
+    0x6262956237f7c455, 0xd4d477d4eea3b53a, 0xa8a89aa829324d81, 0x96966296c4f43152,
+    0xf9f9c3f99b3aef62, 0xc5c533c566f697a3, 0x2525942535b14a10, 0x59597959f220b2ab,
+    0x84842a8454ae15d0, 0x7272d572b7a7e4c5, 0x3939e439d5dd72ec, 0x4c4c2d4c5a619816,
+    0x5e5e655eca3bbc94, 0x7878fd78e785f09f, 0x3838e038ddd870e5, 0x8c8c0a8c14860598,
+    0xd1d163d1c6b2bf17, 0xa5a5aea5410b57e4, 0xe2e2afe2434dd9a1, 0x616199612ff8c24e,
+    0xb3b3f6b3f1457b42, 0x2121842115a54234, 0x9c9c4a9c94d62508, 0x1e1e781ef0663cee,
+    0x4343114322528661, 0xc7c73bc776fc93b1, 0xfcfcd7fcb32be54f, 0x0404100420140824,
+    0x51515951b208a2e3, 0x99995e99bcc72f25, 0x6d6da96d4fc4da22, 0x0d0d340d68391a65,
+    0xfafacffa8335e979, 0xdfdf5bdfb684a369, 0x7e7ee57ed79bfca9, 0x242490243db44819,
+    0x3b3bec3bc5d776fe, 0xabab96ab313d4b9a, 0xcece1fce3ed181f0, 0x1111441188552299,
+    0x8f8f068f0c890383, 0x4e4e254e4a6b9c04, 0xb7b7e6b7d1517366, 0xebeb8beb0b60cbe0,
+    0x3c3cf03cfdcc78c1, 0x81813e817cbf1ffd, 0x94946a94d4fe3540, 0xf7f7fbf7eb0cf31c,
+    0xb9b9deb9a1676f18, 0x13134c13985f268b, 0x2c2cb02c7d9c5851, 0xd3d36bd3d6b8bb05,
+    0xe7e7bbe76b5cd38c, 0x6e6ea56e57cbdc39, 0xc4c437c46ef395aa, 0x03030c03180f061b,
+    0x565645568a13acdc, 0x44440d441a49885e, 0x7f7fe17fdf9efea0, 0xa9a99ea921374f88,
+    0x2a2aa82a4d825467, 0xbbbbd6bbb16d6b0a, 0xc1c123c146e29f87, 0x53535153a202a6f1,
+    0xdcdc57dcae8ba572, 0x0b0b2c0b58271653, 0x9d9d4e9d9cd32701, 0x6c6cad6c47c1d82b,
+    0x3131c43195f562a4, 0x7474cd7487b9e8f3, 0xf6f6fff6e309f115, 0x464605460a438c4c,
+    0xacac8aac092645a5, 0x89891e893c970fb5, 0x14145014a04428b4, 0xe1e1a3e15b42dfba,
+    0x16165816b04e2ca6, 0x3a3ae83acdd274f7, 0x6969b9696fd0d206, 0x09092409482d1241,
+    0x7070dd70a7ade0d7, 0xb6b6e2b6d954716f, 0xd0d067d0ceb7bd1e, 0xeded93ed3b7ec7d6,
+    0xcccc17cc2edb85e2, 0x424215422a578468, 0x98985a98b4c22d2c, 0xa4a4aaa4490e55ed,
+    0x2828a0285d885075, 0x5c5c6d5cda31b886, 0xf8f8c7f8933fed6b, 0x8686228644a411c2,
+];
+
+static C1: [u64; 256] = [
+    0xd818186018c07830, 0x2623238c2305af46, 0xb8c6c63fc67ef991, 0xfbe8e887e8136fcd,
+    0xcb878726874ca113, 0x11b8b8dab8a9626d, 0x0901010401080502, 0x0d4f4f214f426e9e,
+    0x9b3636d836adee6c, 0xffa6a6a2a6590451, 0x0cd2d26fd2debdb9, 0x0ef5f5f3f5fb06f7,
+    0x967979f979ef80f2, 0x306f6fa16f5fcede, 0x6d91917e91fcef3f, 0xf852525552aa07a4,
+    0x4760609d6027fdc0, 0x35bcbccabc897665, 0x379b9b569baccd2b, 0x8a8e8e028e048c01,
+    0xd2a3a3b6a371155b, 0x6c0c0c300c603c18, 0x847b7bf17bff8af6, 0x803535d435b5e16a,
+    0xf51d1d741de8693a, 0xb3e0e0a7e05347dd, 0x21d7d77bd7f6acb3, 0x9cc2c22fc25eed99,
+    0x432e2eb82e6d965c, 0x294b4b314b627a96, 0x5dfefedffea321e1, 0xd5575741578216ae,
+    0xbd15155415a8412a, 0xe87777c1779fb6ee, 0x923737dc37a5eb6e, 0x9ee5e5b3e57b56d7,
+    0x139f9f469f8cd923, 0x23f0f0e7f0d317fd, 0x204a4a354a6a7f94, 0x44dada4fda9e95a9,
+    0xa258587d58fa25b0, 0xcfc9c903c906ca8f, 0x7c2929a429558d52, 0x5a0a0a280a502214,
+    0x50b1b1feb1e14f7f, 0xc9a0a0baa0691a5d, 0x146b6bb16b7fdad6, 0xd985852e855cab17,
+    0x3cbdbdcebd817367, 0x8f5d5d695dd234ba, 0x9010104010805020, 0x07f4f4f7f4f303f5,
+    0xddcbcb0bcb16c08b, 0xd33e3ef83eedc67c, 0x2d0505140528110a, 0x78676781671fe6ce,
+    0x97e4e4b7e47353d5, 0x0227279c2725bb4e, 0x7341411941325882, 0xa78b8b168b2c9d0b,
+    0xf6a7a7a6a7510153, 0xb27d7de97dcf94fa, 0x4995956e95dcfb37, 0x56d8d847d88e9fad,
+    0x70fbfbcbfb8b30eb, 0xcdeeee9fee2371c1, 0xbb7c7ced7cc791f8, 0x716666856617e3cc,
+    0x7bdddd53dda68ea7, 0xaf17175c17b84b2e, 0x454747014702468e, 0x1a9e9e429e84dc21,
+    0xd4caca0fca1ec589, 0x582d2db42d75995a, 0x2ebfbfc6bf917963, 0x3f07071c07381b0e,
+    0xacadad8ead012347, 0xb05a5a755aea2fb4, 0xef838336836cb51b, 0xb63333cc3385ff66,
+    0x5c636391633ff2c6, 0x1202020802100a04, 0x93aaaa92aa393849, 0xde7171d971afa8e2,
+    0xc6c8c807c80ecf8d, 0xd119196419c87d32, 0x3b49493949727092, 0x5fd9d943d9869aaf,
+    0x31f2f2eff2c31df9, 0xa8e3e3abe34b48db, 0xb95b5b715be22ab6, 0xbc88881a8834920d,
+    0x3e9a9a529aa4c829, 0x0b262698262dbe4c, 0xbf3232c8328dfa64, 0x59b0b0fab0e94a7d,
+    0xf2e9e983e91b6acf, 0x770f0f3c0f78331e, 0x33d5d573d5e6a6b7, 0xf480803a8074ba1d,
+    0x27bebec2be997c61, 0xebcdcd13cd26de87, 0x893434d034bde468, 0x3248483d487a7590,
+    0x54ffffdbffab24e3, 0x8d7a7af57af78ff4, 0x6490907a90f4ea3d, 0x9d5f5f615fc23ebe,
+    0x3d202080201da040, 0x0f6868bd6867d5d0, 0xca1a1a681ad07234, 0xb7aeae82ae192c41,
+    0x7db4b4eab4c95e75, 0xce54544d549a19a8, 0x7f93937693ece53b, 0x2f222288220daa44,
+    0x6364648d6407e9c8, 0x2af1f1e3f1db12ff, 0xcc7373d173bfa2e6, 0x8212124812905a24,
+    0x7a40401d403a5d80, 0x4808082008402810, 0x95c3c32bc356e89b, 0xdfecec97ec337bc5,
+    0x4ddbdb4bdb9690ab, 0xc0a1a1bea1611f5f, 0x918d8d0e8d1c8307, 0xc83d3df43df5c97a,
+    0x5b97976697ccf133, 0x0000000000000000, 0xf9cfcf1bcf36d483, 0x6e2b2bac2b458756,
+    0xe17676c57697b3ec, 0xe68282328264b019, 0x28d6d67fd6fea9b1, 0xc31b1b6c1bd87736,
+    0x74b5b5eeb5c15b77, 0xbeafaf86af112943, 0x1d6a6ab56a77dfd4, 0xea50505d50ba0da0,
+    0x5745450945124c8a, 0x38f3f3ebf3cb18fb, 0xad3030c0309df060, 0xc4efef9bef2b74c3,
+    0xda3f3ffc3fe5c37e, 0xc755554955921caa, 0xdba2a2b2a2791059, 0xe9eaea8fea0365c9,
+    0x6a656589650fecca, 0x03babad2bab96869, 0x4a2f2fbc2f65935e, 0x8ec0c027c04ee79d,
+    0x60dede5fdebe81a1, 0xfc1c1c701ce06c38, 0x46fdfdd3fdbb2ee7, 0x1f4d4d294d52649a,
+    0x7692927292e4e039, 0xfa7575c9758fbcea, 0x3606061806301e0c, 0xae8a8a128a249809,
+    0x4bb2b2f2b2f94079, 0x85e6e6bfe66359d1, 0x7e0e0e380e70361c, 0xe71f1f7c1ff8633e,
+    0x556262956237f7c4, 0x3ad4d477d4eea3b5, 0x81a8a89aa829324d, 0x5296966296c4f431,
+    0x62f9f9c3f99b3aef, 0xa3c5c533c566f697, 0x102525942535b14a, 0xab59597959f220b2,
+    0xd084842a8454ae15, 0xc57272d572b7a7e4, 0xec3939e439d5dd72, 0x164c4c2d4c5a6198,
+    0x945e5e655eca3bbc, 0x9f7878fd78e785f0, 0xe53838e038ddd870, 0x988c8c0a8c148605,
+    0x17d1d163d1c6b2bf, 0xe4a5a5aea5410b57, 0xa1e2e2afe2434dd9, 0x4e616199612ff8c2,
+    0x42b3b3f6b3f1457b, 0x342121842115a542, 0x089c9c4a9c94d625, 0xee1e1e781ef0663c,
+    0x6143431143225286, 0xb1c7c73bc776fc93, 0x4ffcfcd7fcb32be5, 0x2404041004201408,
+    0xe351515951b208a2, 0x2599995e99bcc72f, 0x226d6da96d4fc4da, 0x650d0d340d68391a,
+    0x79fafacffa8335e9, 0x69dfdf5bdfb684a3, 0xa97e7ee57ed79bfc, 0x19242490243db448,
+    0xfe3b3bec3bc5d776, 0x9aabab96ab313d4b, 0xf0cece1fce3ed181, 0x9911114411885522,
+    0x838f8f068f0c8903, 0x044e4e254e4a6b9c, 0x66b7b7e6b7d15173, 0xe0ebeb8beb0b60cb,
+    0xc13c3cf03cfdcc78, 0xfd81813e817cbf1f, 0x4094946a94d4fe35, 0x1cf7f7fbf7eb0cf3,
+    0x18b9b9deb9a1676f, 0x8b13134c13985f26, 0x512c2cb02c7d9c58, 0x05d3d36bd3d6b8bb,
+    0x8ce7e7bbe76b5cd3, 0x396e6ea56e57cbdc, 0xaac4c437c46ef395, 0x1b03030c03180f06,
+    0xdc565645568a13ac, 0x5e44440d441a4988, 0xa07f7fe17fdf9efe, 0x88a9a99ea921374f,
+    0x672a2aa82a4d8254, 0x0abbbbd6bbb16d6b, 0x87c1c123c146e29f, 0xf153535153a202a6,
+    0x72dcdc57dcae8ba5, 0x530b0b2c0b582716, 0x019d9d4e9d9cd327, 0x2b6c6cad6c47c1d8,
+    0xa43131c43195f562, 0xf37474cd7487b9e8, 0x15f6f6fff6e309f1, 0x4c464605460a438c,
+    0xa5acac8aac092645, 0xb589891e893c970f, 0xb414145014a04428, 0xbae1e1a3e15b42df,
+    0xa616165816b04e2c, 0xf73a3ae83acdd274, 0x066969b9696fd0d2, 0x4109092409482d12,
+    0xd77070dd70a7ade0, 0x6fb6b6e2b6d95471, 0x1ed0d067d0ceb7bd, 0xd6eded93ed3b7ec7,
+    0xe2cccc17cc2edb85, 0x68424215422a5784, 0x2c98985a98b4c22d, 0xeda4a4aaa4490e55,
+    0x752828a0285d8850, 0x865c5c6d5cda31b8, 0x6bf8f8c7f8933fed, 0xc28686228644a411,
+];
+
+static C2: [u64; 256] = [
+    0x30d818186018c078, 0x462623238c2305af, 0x91b8c6c63fc67ef9, 0xcdfbe8e887e8136f,
+    0x13cb878726874ca1, 0x6d11b8b8dab8a962, 0x0209010104010805, 0x9e0d4f4f214f426e,
+    0x6c9b3636d836adee, 0x51ffa6a6a2a65904, 0xb90cd2d26fd2debd, 0xf70ef5f5f3f5fb06,
+    0xf2967979f979ef80, 0xde306f6fa16f5fce, 0x3f6d91917e91fcef, 0xa4f852525552aa07,
+    0xc04760609d6027fd, 0x6535bcbccabc8976, 0x2b379b9b569baccd, 0x018a8e8e028e048c,
+    0x5bd2a3a3b6a37115, 0x186c0c0c300c603c, 0xf6847b7bf17bff8a, 0x6a803535d435b5e1,
+    0x3af51d1d741de869, 0xddb3e0e0a7e05347, 0xb321d7d77bd7f6ac, 0x999cc2c22fc25eed,
+    0x5c432e2eb82e6d96, 0x96294b4b314b627a, 0xe15dfefedffea321, 0xaed5575741578216,
+    0x2abd15155415a841, 0xeee87777c1779fb6, 0x6e923737dc37a5eb, 0xd79ee5e5b3e57b56,
+    0x23139f9f469f8cd9, 0xfd23f0f0e7f0d317, 0x94204a4a354a6a7f, 0xa944dada4fda9e95,
+    0xb0a258587d58fa25, 0x8fcfc9c903c906ca, 0x527c2929a429558d, 0x145a0a0a280a5022,
+    0x7f50b1b1feb1e14f, 0x5dc9a0a0baa0691a, 0xd6146b6bb16b7fda, 0x17d985852e855cab,
+    0x673cbdbdcebd8173, 0xba8f5d5d695dd234, 0x2090101040108050, 0xf507f4f4f7f4f303,
+    0x8bddcbcb0bcb16c0, 0x7cd33e3ef83eedc6, 0x0a2d050514052811, 0xce78676781671fe6,
+    0xd597e4e4b7e47353, 0x4e0227279c2725bb, 0x8273414119413258, 0x0ba78b8b168b2c9d,
+    0x53f6a7a7a6a75101, 0xfab27d7de97dcf94, 0x374995956e95dcfb, 0xad56d8d847d88e9f,
+    0xeb70fbfbcbfb8b30, 0xc1cdeeee9fee2371, 0xf8bb7c7ced7cc791, 0xcc716666856617e3,
+    0xa77bdddd53dda68e, 0x2eaf17175c17b84b, 0x8e45474701470246, 0x211a9e9e429e84dc,
+    0x89d4caca0fca1ec5, 0x5a582d2db42d7599, 0x632ebfbfc6bf9179, 0x0e3f07071c07381b,
+    0x47acadad8ead0123, 0xb4b05a5a755aea2f, 0x1bef838336836cb5, 0x66b63333cc3385ff,
+    0xc65c636391633ff2, 0x041202020802100a, 0x4993aaaa92aa3938, 0xe2de7171d971afa8,
+    0x8dc6c8c807c80ecf, 0x32d119196419c87d, 0x923b494939497270, 0xaf5fd9d943d9869a,
+    0xf931f2f2eff2c31d, 0xdba8e3e3abe34b48, 0xb6b95b5b715be22a, 0x0dbc88881a883492,
+    0x293e9a9a529aa4c8, 0x4c0b262698262dbe, 0x64bf3232c8328dfa, 0x7d59b0b0fab0e94a,
+    0xcff2e9e983e91b6a, 0x1e770f0f3c0f7833, 0xb733d5d573d5e6a6, 0x1df480803a8074ba,
+    0x6127bebec2be997c, 0x87ebcdcd13cd26de, 0x68893434d034bde4, 0x903248483d487a75,
+    0xe354ffffdbffab24, 0xf48d7a7af57af78f, 0x3d6490907a90f4ea, 0xbe9d5f5f615fc23e,
+    0x403d202080201da0, 0xd00f6868bd6867d5, 0x34ca1a1a681ad072, 0x41b7aeae82ae192c,
+    0x757db4b4eab4c95e, 0xa8ce54544d549a19, 0x3b7f93937693ece5, 0x442f222288220daa,
+    0xc86364648d6407e9, 0xff2af1f1e3f1db12, 0xe6cc7373d173bfa2, 0x248212124812905a,
+    0x807a40401d403a5d, 0x1048080820084028, 0x9b95c3c32bc356e8, 0xc5dfecec97ec337b,
+    0xab4ddbdb4bdb9690, 0x5fc0a1a1bea1611f, 0x07918d8d0e8d1c83, 0x7ac83d3df43df5c9,
+    0x335b97976697ccf1, 0x0000000000000000, 0x83f9cfcf1bcf36d4, 0x566e2b2bac2b4587,
+    0xece17676c57697b3, 0x19e68282328264b0, 0xb128d6d67fd6fea9, 0x36c31b1b6c1bd877,
+    0x7774b5b5eeb5c15b, 0x43beafaf86af1129, 0xd41d6a6ab56a77df, 0xa0ea50505d50ba0d,
+    0x8a5745450945124c, 0xfb38f3f3ebf3cb18, 0x60ad3030c0309df0, 0xc3c4efef9bef2b74,
+    0x7eda3f3ffc3fe5c3, 0xaac755554955921c, 0x59dba2a2b2a27910, 0xc9e9eaea8fea0365,
+    0xca6a656589650fec, 0x6903babad2bab968, 0x5e4a2f2fbc2f6593, 0x9d8ec0c027c04ee7,
+    0xa160dede5fdebe81, 0x38fc1c1c701ce06c, 0xe746fdfdd3fdbb2e, 0x9a1f4d4d294d5264,
+    0x397692927292e4e0, 0xeafa7575c9758fbc, 0x0c3606061806301e, 0x09ae8a8a128a2498,
+    0x794bb2b2f2b2f940, 0xd185e6e6bfe66359, 0x1c7e0e0e380e7036, 0x3ee71f1f7c1ff863,
+    0xc4556262956237f7, 0xb53ad4d477d4eea3, 0x4d81a8a89aa82932, 0x315296966296c4f4,
+    0xef62f9f9c3f99b3a, 0x97a3c5c533c566f6, 0x4a102525942535b1, 0xb2ab59597959f220,
+    0x15d084842a8454ae, 0xe4c57272d572b7a7, 0x72ec3939e439d5dd, 0x98164c4c2d4c5a61,
+    0xbc945e5e655eca3b, 0xf09f7878fd78e785, 0x70e53838e038ddd8, 0x05988c8c0a8c1486,
+    0xbf17d1d163d1c6b2, 0x57e4a5a5aea5410b, 0xd9a1e2e2afe2434d, 0xc24e616199612ff8,
+    0x7b42b3b3f6b3f145, 0x42342121842115a5, 0x25089c9c4a9c94d6, 0x3cee1e1e781ef066,
+    0x8661434311432252, 0x93b1c7c73bc776fc, 0xe54ffcfcd7fcb32b, 0x0824040410042014,
+    0xa2e351515951b208, 0x2f2599995e99bcc7, 0xda226d6da96d4fc4, 0x1a650d0d340d6839,
+    0xe979fafacffa8335, 0xa369dfdf5bdfb684, 0xfca97e7ee57ed79b, 0x4819242490243db4,
+    0x76fe3b3bec3bc5d7, 0x4b9aabab96ab313d, 0x81f0cece1fce3ed1, 0x2299111144118855,
+    0x03838f8f068f0c89, 0x9c044e4e254e4a6b, 0x7366b7b7e6b7d151, 0xcbe0ebeb8beb0b60,
+    0x78c13c3cf03cfdcc, 0x1ffd81813e817cbf, 0x354094946a94d4fe, 0xf31cf7f7fbf7eb0c,
+    0x6f18b9b9deb9a167, 0x268b13134c13985f, 0x58512c2cb02c7d9c, 0xbb05d3d36bd3d6b8,
+    0xd38ce7e7bbe76b5c, 0xdc396e6ea56e57cb, 0x95aac4c437c46ef3, 0x061b03030c03180f,
+    0xacdc565645568a13, 0x885e44440d441a49, 0xfea07f7fe17fdf9e, 0x4f88a9a99ea92137,
+    0x54672a2aa82a4d82, 0x6b0abbbbd6bbb16d, 0x9f87c1c123c146e2, 0xa6f153535153a202,
+    0xa572dcdc57dcae8b, 0x16530b0b2c0b5827, 0x27019d9d4e9d9cd3, 0xd82b6c6cad6c47c1,
+    0x62a43131c43195f5, 0xe8f37474cd7487b9, 0xf115f6f6fff6e309, 0x8c4c464605460a43,
+    0x45a5acac8aac0926, 0x0fb589891e893c97, 0x28b414145014a044, 0xdfbae1e1a3e15b42,
+    0x2ca616165816b04e, 0x74f73a3ae83acdd2, 0xd2066969b9696fd0, 0x124109092409482d,
+    0xe0d77070dd70a7ad, 0x716fb6b6e2b6d954, 0xbd1ed0d067d0ceb7, 0xc7d6eded93ed3b7e,
+    0x85e2cccc17cc2edb, 0x8468424215422a57, 0x2d2c98985a98b4c2, 0x55eda4a4aaa4490e,
+    0x50752828a0285d88, 0xb8865c5c6d5cda31, 0xed6bf8f8c7f8933f, 0x11c28686228644a4,
+];
+
+static C3: [u64; 256] = [
+    0x7830d818186018c0, 0xaf462623238c2305, 0xf991b8c6c63fc67e, 0x6fcdfbe8e887e813,
+    0xa113cb878726874c, 0x626d11b8b8dab8a9, 0x0502090101040108, 0x6e9e0d4f4f214f42,
+    0xee6c9b3636d836ad, 0x0451ffa6a6a2a659, 0xbdb90cd2d26fd2de, 0x06f70ef5f5f3f5fb,
+    0x80f2967979f979ef, 0xcede306f6fa16f5f, 0xef3f6d91917e91fc, 0x07a4f852525552aa,
+    0xfdc04760609d6027, 0x766535bcbccabc89, 0xcd2b379b9b569bac, 0x8c018a8e8e028e04,
+    0x155bd2a3a3b6a371, 0x3c186c0c0c300c60, 0x8af6847b7bf17bff, 0xe16a803535d435b5,
+    0x693af51d1d741de8, 0x47ddb3e0e0a7e053, 0xacb321d7d77bd7f6, 0xed999cc2c22fc25e,
+    0x965c432e2eb82e6d, 0x7a96294b4b314b62, 0x21e15dfefedffea3, 0x16aed55757415782,
+    0x412abd15155415a8, 0xb6eee87777c1779f, 0xeb6e923737dc37a5, 0x56d79ee5e5b3e57b,
+    0xd923139f9f469f8c, 0x17fd23f0f0e7f0d3, 0x7f94204a4a354a6a, 0x95a944dada4fda9e,
+    0x25b0a258587d58fa, 0xca8fcfc9c903c906, 0x8d527c2929a42955, 0x22145a0a0a280a50,
+    0x4f7f50b1b1feb1e1, 0x1a5dc9a0a0baa069, 0xdad6146b6bb16b7f, 0xab17d985852e855c,
+    0x73673cbdbdcebd81, 0x34ba8f5d5d695dd2, 0x5020901010401080, 0x03f507f4f4f7f4f3,
+    0xc08bddcbcb0bcb16, 0xc67cd33e3ef83eed, 0x110a2d0505140528, 0xe6ce78676781671f,
+    0x53d597e4e4b7e473, 0xbb4e0227279c2725, 0x5882734141194132, 0x9d0ba78b8b168b2c,
+    0x0153f6a7a7a6a751, 0x94fab27d7de97dcf, 0xfb374995956e95dc, 0x9fad56d8d847d88e,
+    0x30eb70fbfbcbfb8b, 0x71c1cdeeee9fee23, 0x91f8bb7c7ced7cc7, 0xe3cc716666856617,
+    0x8ea77bdddd53dda6, 0x4b2eaf17175c17b8, 0x468e454747014702, 0xdc211a9e9e429e84,
+    0xc589d4caca0fca1e, 0x995a582d2db42d75, 0x79632ebfbfc6bf91, 0x1b0e3f07071c0738,
+    0x2347acadad8ead01, 0x2fb4b05a5a755aea, 0xb51bef838336836c, 0xff66b63333cc3385,
+    0xf2c65c636391633f, 0x0a04120202080210, 0x384993aaaa92aa39, 0xa8e2de7171d971af,
+    0xcf8dc6c8c807c80e, 0x7d32d119196419c8, 0x70923b4949394972, 0x9aaf5fd9d943d986,
+    0x1df931f2f2eff2c3, 0x48dba8e3e3abe34b, 0x2ab6b95b5b715be2, 0x920dbc88881a8834,
+    0xc8293e9a9a529aa4, 0xbe4c0b262698262d, 0xfa64bf3232c8328d, 0x4a7d59b0b0fab0e9,
+    0x6acff2e9e983e91b, 0x331e770f0f3c0f78, 0xa6b733d5d573d5e6, 0xba1df480803a8074,
+    0x7c6127bebec2be99, 0xde87ebcdcd13cd26, 0xe468893434d034bd, 0x75903248483d487a,
+    0x24e354ffffdbffab, 0x8ff48d7a7af57af7, 0xea3d6490907a90f4, 0x3ebe9d5f5f615fc2,
+    0xa0403d202080201d, 0xd5d00f6868bd6867, 0x7234ca1a1a681ad0, 0x2c41b7aeae82ae19,
+    0x5e757db4b4eab4c9, 0x19a8ce54544d549a, 0xe53b7f93937693ec, 0xaa442f222288220d,
+    0xe9c86364648d6407, 0x12ff2af1f1e3f1db, 0xa2e6cc7373d173bf, 0x5a24821212481290,
+    0x5d807a40401d403a, 0x2810480808200840, 0xe89b95c3c32bc356, 0x7bc5dfecec97ec33,
+    0x90ab4ddbdb4bdb96, 0x1f5fc0a1a1bea161, 0x8307918d8d0e8d1c, 0xc97ac83d3df43df5,
+    0xf1335b97976697cc, 0x0000000000000000, 0xd483f9cfcf1bcf36, 0x87566e2b2bac2b45,
+    0xb3ece17676c57697, 0xb019e68282328264, 0xa9b128d6d67fd6fe, 0x7736c31b1b6c1bd8,
+    0x5b7774b5b5eeb5c1, 0x2943beafaf86af11, 0xdfd41d6a6ab56a77, 0x0da0ea50505d50ba,
+    0x4c8a574545094512, 0x18fb38f3f3ebf3cb, 0xf060ad3030c0309d, 0x74c3c4efef9bef2b,
+    0xc37eda3f3ffc3fe5, 0x1caac75555495592, 0x1059dba2a2b2a279, 0x65c9e9eaea8fea03,
+    0xecca6a656589650f, 0x686903babad2bab9, 0x935e4a2f2fbc2f65, 0xe79d8ec0c027c04e,
+    0x81a160dede5fdebe, 0x6c38fc1c1c701ce0, 0x2ee746fdfdd3fdbb, 0x649a1f4d4d294d52,
+    0xe0397692927292e4, 0xbceafa7575c9758f, 0x1e0c360606180630, 0x9809ae8a8a128a24,
+    0x40794bb2b2f2b2f9, 0x59d185e6e6bfe663, 0x361c7e0e0e380e70, 0x633ee71f1f7c1ff8,
+    0xf7c4556262956237, 0xa3b53ad4d477d4ee, 0x324d81a8a89aa829, 0xf4315296966296c4,
+    0x3aef62f9f9c3f99b, 0xf697a3c5c533c566, 0xb14a102525942535, 0x20b2ab59597959f2,
+    0xae15d084842a8454, 0xa7e4c57272d572b7, 0xdd72ec3939e439d5, 0x6198164c4c2d4c5a,
+    0x3bbc945e5e655eca, 0x85f09f7878fd78e7, 0xd870e53838e038dd, 0x8605988c8c0a8c14,
+    0xb2bf17d1d163d1c6, 0x0b57e4a5a5aea541, 0x4dd9a1e2e2afe243, 0xf8c24e616199612f,
+    0x457b42b3b3f6b3f1, 0xa542342121842115, 0xd625089c9c4a9c94, 0x663cee1e1e781ef0,
+    0x5286614343114322, 0xfc93b1c7c73bc776, 0x2be54ffcfcd7fcb3, 0x1408240404100420,
+    0x08a2e351515951b2, 0xc72f2599995e99bc, 0xc4da226d6da96d4f, 0x391a650d0d340d68,
+    0x35e979fafacffa83, 0x84a369dfdf5bdfb6, 0x9bfca97e7ee57ed7, 0xb44819242490243d,
+    0xd776fe3b3bec3bc5, 0x3d4b9aabab96ab31, 0xd181f0cece1fce3e, 0x5522991111441188,
+    0x8903838f8f068f0c, 0x6b9c044e4e254e4a, 0x517366b7b7e6b7d1, 0x60cbe0ebeb8beb0b,
+    0xcc78c13c3cf03cfd, 0xbf1ffd81813e817c, 0xfe354094946a94d4, 0x0cf31cf7f7fbf7eb,
+    0x676f18b9b9deb9a1, 0x5f268b13134c1398, 0x9c58512c2cb02c7d, 0xb8bb05d3d36bd3d6,
+    0x5cd38ce7e7bbe76b, 0xcbdc396e6ea56e57, 0xf395aac4c437c46e, 0x0f061b03030c0318,
+    0x13acdc565645568a, 0x49885e44440d441a, 0x9efea07f7fe17fdf, 0x374f88a9a99ea921,
+    0x8254672a2aa82a4d, 0x6d6b0abbbbd6bbb1, 0xe29f87c1c123c146, 0x02a6f153535153a2,
+    0x8ba572dcdc57dcae, 0x2716530b0b2c0b58, 0xd327019d9d4e9d9c, 0xc1d82b6c6cad6c47,
+    0xf562a43131c43195, 0xb9e8f37474cd7487, 0x09f115f6f6fff6e3, 0x438c4c464605460a,
+    0x2645a5acac8aac09, 0x970fb589891e893c, 0x4428b414145014a0, 0x42dfbae1e1a3e15b,
+    0x4e2ca616165816b0, 0xd274f73a3ae83acd, 0xd0d2066969b9696f, 0x2d12410909240948,
+    0xade0d77070dd70a7, 0x54716fb6b6e2b6d9, 0xb7bd1ed0d067d0ce, 0x7ec7d6eded93ed3b,
+    0xdb85e2cccc17cc2e, 0x578468424215422a, 0xc22d2c98985a98b4, 0x0e55eda4a4aaa449,
+    0x8850752828a0285d, 0x31b8865c5c6d5cda, 0x3fed6bf8f8c7f893, 0xa411c28686228644,
+];
+
+static C4: [u64; 256] = [
+    0xc07830d818186018, 0x05af462623238c23, 0x7ef991b8c6c63fc6, 0x136fcdfbe8e887e8,
+    0x4ca113cb87872687, 0xa9626d11b8b8dab8, 0x0805020901010401, 0x426e9e0d4f4f214f,
+    0xadee6c9b3636d836, 0x590451ffa6a6a2a6, 0xdebdb90cd2d26fd2, 0xfb06f70ef5f5f3f5,
+    0xef80f2967979f979, 0x5fcede306f6fa16f, 0xfcef3f6d91917e91, 0xaa07a4f852525552,
+    0x27fdc04760609d60, 0x89766535bcbccabc, 0xaccd2b379b9b569b, 0x048c018a8e8e028e,
+    0x71155bd2a3a3b6a3, 0x603c186c0c0c300c, 0xff8af6847b7bf17b, 0xb5e16a803535d435,
+    0xe8693af51d1d741d, 0x5347ddb3e0e0a7e0, 0xf6acb321d7d77bd7, 0x5eed999cc2c22fc2,
+    0x6d965c432e2eb82e, 0x627a96294b4b314b, 0xa321e15dfefedffe, 0x8216aed557574157,
+    0xa8412abd15155415, 0x9fb6eee87777c177, 0xa5eb6e923737dc37, 0x7b56d79ee5e5b3e5,
+    0x8cd923139f9f469f, 0xd317fd23f0f0e7f0, 0x6a7f94204a4a354a, 0x9e95a944dada4fda,
+    0xfa25b0a258587d58, 0x06ca8fcfc9c903c9, 0x558d527c2929a429, 0x5022145a0a0a280a,
+    0xe14f7f50b1b1feb1, 0x691a5dc9a0a0baa0, 0x7fdad6146b6bb16b, 0x5cab17d985852e85,
+    0x8173673cbdbdcebd, 0xd234ba8f5d5d695d, 0x8050209010104010, 0xf303f507f4f4f7f4,
+    0x16c08bddcbcb0bcb, 0xedc67cd33e3ef83e, 0x28110a2d05051405, 0x1fe6ce7867678167,
+    0x7353d597e4e4b7e4, 0x25bb4e0227279c27, 0x3258827341411941, 0x2c9d0ba78b8b168b,
+    0x510153f6a7a7a6a7, 0xcf94fab27d7de97d, 0xdcfb374995956e95, 0x8e9fad56d8d847d8,
+    0x8b30eb70fbfbcbfb, 0x2371c1cdeeee9fee, 0xc791f8bb7c7ced7c, 0x17e3cc7166668566,
+    0xa68ea77bdddd53dd, 0xb84b2eaf17175c17, 0x02468e4547470147, 0x84dc211a9e9e429e,
+    0x1ec589d4caca0fca, 0x75995a582d2db42d, 0x9179632ebfbfc6bf, 0x381b0e3f07071c07,
+    0x012347acadad8ead, 0xea2fb4b05a5a755a, 0x6cb51bef83833683, 0x85ff66b63333cc33,
+    0x3ff2c65c63639163, 0x100a041202020802, 0x39384993aaaa92aa, 0xafa8e2de7171d971,
+    0x0ecf8dc6c8c807c8, 0xc87d32d119196419, 0x7270923b49493949, 0x869aaf5fd9d943d9,
+    0xc31df931f2f2eff2, 0x4b48dba8e3e3abe3, 0xe22ab6b95b5b715b, 0x34920dbc88881a88,
+    0xa4c8293e9a9a529a, 0x2dbe4c0b26269826, 0x8dfa64bf3232c832, 0xe94a7d59b0b0fab0,
+    0x1b6acff2e9e983e9, 0x78331e770f0f3c0f, 0xe6a6b733d5d573d5, 0x74ba1df480803a80,
+    0x997c6127bebec2be, 0x26de87ebcdcd13cd, 0xbde468893434d034, 0x7a75903248483d48,
+    0xab24e354ffffdbff, 0xf78ff48d7a7af57a, 0xf4ea3d6490907a90, 0xc23ebe9d5f5f615f,
+    0x1da0403d20208020, 0x67d5d00f6868bd68, 0xd07234ca1a1a681a, 0x192c41b7aeae82ae,
+    0xc95e757db4b4eab4, 0x9a19a8ce54544d54, 0xece53b7f93937693, 0x0daa442f22228822,
+    0x07e9c86364648d64, 0xdb12ff2af1f1e3f1, 0xbfa2e6cc7373d173, 0x905a248212124812,
+    0x3a5d807a40401d40, 0x4028104808082008, 0x56e89b95c3c32bc3, 0x337bc5dfecec97ec,
+    0x9690ab4ddbdb4bdb, 0x611f5fc0a1a1bea1, 0x1c8307918d8d0e8d, 0xf5c97ac83d3df43d,
+    0xccf1335b97976697, 0x0000000000000000, 0x36d483f9cfcf1bcf, 0x4587566e2b2bac2b,
+    0x97b3ece17676c576, 0x64b019e682823282, 0xfea9b128d6d67fd6, 0xd87736c31b1b6c1b,
+    0xc15b7774b5b5eeb5, 0x112943beafaf86af, 0x77dfd41d6a6ab56a, 0xba0da0ea50505d50,
+    0x124c8a5745450945, 0xcb18fb38f3f3ebf3, 0x9df060ad3030c030, 0x2b74c3c4efef9bef,
+    0xe5c37eda3f3ffc3f, 0x921caac755554955, 0x791059dba2a2b2a2, 0x0365c9e9eaea8fea,
+    0x0fecca6a65658965, 0xb9686903babad2ba, 0x65935e4a2f2fbc2f, 0x4ee79d8ec0c027c0,
+    0xbe81a160dede5fde, 0xe06c38fc1c1c701c, 0xbb2ee746fdfdd3fd, 0x52649a1f4d4d294d,
+    0xe4e0397692927292, 0x8fbceafa7575c975, 0x301e0c3606061806, 0x249809ae8a8a128a,
+    0xf940794bb2b2f2b2, 0x6359d185e6e6bfe6, 0x70361c7e0e0e380e, 0xf8633ee71f1f7c1f,
+    0x37f7c45562629562, 0xeea3b53ad4d477d4, 0x29324d81a8a89aa8, 0xc4f4315296966296,
+    0x9b3aef62f9f9c3f9, 0x66f697a3c5c533c5, 0x35b14a1025259425, 0xf220b2ab59597959,
+    0x54ae15d084842a84, 0xb7a7e4c57272d572, 0xd5dd72ec3939e439, 0x5a6198164c4c2d4c,
+    0xca3bbc945e5e655e, 0xe785f09f7878fd78, 0xddd870e53838e038, 0x148605988c8c0a8c,
+    0xc6b2bf17d1d163d1, 0x410b57e4a5a5aea5, 0x434dd9a1e2e2afe2, 0x2ff8c24e61619961,
+    0xf1457b42b3b3f6b3, 0x15a5423421218421, 0x94d625089c9c4a9c, 0xf0663cee1e1e781e,
+    0x2252866143431143, 0x76fc93b1c7c73bc7, 0xb32be54ffcfcd7fc, 0x2014082404041004,
+    0xb208a2e351515951, 0xbcc72f2599995e99, 0x4fc4da226d6da96d, 0x68391a650d0d340d,
+    0x8335e979fafacffa, 0xb684a369dfdf5bdf, 0xd79bfca97e7ee57e, 0x3db4481924249024,
+    0xc5d776fe3b3bec3b, 0x313d4b9aabab96ab, 0x3ed181f0cece1fce, 0x8855229911114411,
+    0x0c8903838f8f068f, 0x4a6b9c044e4e254e, 0xd1517366b7b7e6b7, 0x0b60cbe0ebeb8beb,
+    0xfdcc78c13c3cf03c, 0x7cbf1ffd81813e81, 0xd4fe354094946a94, 0xeb0cf31cf7f7fbf7,
+    0xa1676f18b9b9deb9, 0x985f268b13134c13, 0x7d9c58512c2cb02c, 0xd6b8bb05d3d36bd3,
+    0x6b5cd38ce7e7bbe7, 0x57cbdc396e6ea56e, 0x6ef395aac4c437c4, 0x180f061b03030c03,
+    0x8a13acdc56564556, 0x1a49885e44440d44, 0xdf9efea07f7fe17f, 0x21374f88a9a99ea9,
+    0x4d8254672a2aa82a, 0xb16d6b0abbbbd6bb, 0x46e29f87c1c123c1, 0xa202a6f153535153,
+    0xae8ba572dcdc57dc, 0x582716530b0b2c0b, 0x9cd327019d9d4e9d, 0x47c1d82b6c6cad6c,
+    0x95f562a43131c431, 0x87b9e8f37474cd74, 0xe309f115f6f6fff6, 0x0a438c4c46460546,
+    0x092645a5acac8aac, 0x3c970fb589891e89, 0xa04428b414145014, 0x5b42dfbae1e1a3e1,
+    0xb04e2ca616165816, 0xcdd274f73a3ae83a, 0x6fd0d2066969b969, 0x482d124109092409,
+    0xa7ade0d77070dd70, 0xd954716fb6b6e2b6, 0xceb7bd1ed0d067d0, 0x3b7ec7d6eded93ed,
+    0x2edb85e2cccc17cc, 0x2a57846842421542, 0xb4c22d2c98985a98, 0x490e55eda4a4aaa4,
+    0x5d8850752828a028, 0xda31b8865c5c6d5c, 0x933fed6bf8f8c7f8, 0x44a411c286862286,
+];
+
+static C5: [u64; 256] = [
+    0x18c07830d8181860, 0x2305af462623238c, 0xc67ef991b8c6c63f, 0xe8136fcdfbe8e887,
+    0x874ca113cb878726, 0xb8a9626d11b8b8da, 0x0108050209010104, 0x4f426e9e0d4f4f21,
+    0x36adee6c9b3636d8, 0xa6590451ffa6a6a2, 0xd2debdb90cd2d26f, 0xf5fb06f70ef5f5f3,
+    0x79ef80f2967979f9, 0x6f5fcede306f6fa1, 0x91fcef3f6d91917e, 0x52aa07a4f8525255,
+    0x6027fdc04760609d, 0xbc89766535bcbcca, 0x9baccd2b379b9b56, 0x8e048c018a8e8e02,
+    0xa371155bd2a3a3b6, 0x0c603c186c0c0c30, 0x7bff8af6847b7bf1, 0x35b5e16a803535d4,
+    0x1de8693af51d1d74, 0xe05347ddb3e0e0a7, 0xd7f6acb321d7d77b, 0xc25eed999cc2c22f,
+    0x2e6d965c432e2eb8, 0x4b627a96294b4b31, 0xfea321e15dfefedf, 0x578216aed5575741,
+    0x15a8412abd151554, 0x779fb6eee87777c1, 0x37a5eb6e923737dc, 0xe57b56d79ee5e5b3,
+    0x9f8cd923139f9f46, 0xf0d317fd23f0f0e7, 0x4a6a7f94204a4a35, 0xda9e95a944dada4f,
+    0x58fa25b0a258587d, 0xc906ca8fcfc9c903, 0x29558d527c2929a4, 0x0a5022145a0a0a28,
+    0xb1e14f7f50b1b1fe, 0xa0691a5dc9a0a0ba, 0x6b7fdad6146b6bb1, 0x855cab17d985852e,
+    0xbd8173673cbdbdce, 0x5dd234ba8f5d5d69, 0x1080502090101040, 0xf4f303f507f4f4f7,
+    0xcb16c08bddcbcb0b, 0x3eedc67cd33e3ef8, 0x0528110a2d050514, 0x671fe6ce78676781,
+    0xe47353d597e4e4b7, 0x2725bb4e0227279c, 0x4132588273414119, 0x8b2c9d0ba78b8b16,
+    0xa7510153f6a7a7a6, 0x7dcf94fab27d7de9, 0x95dcfb374995956e, 0xd88e9fad56d8d847,
+    0xfb8b30eb70fbfbcb, 0xee2371c1cdeeee9f, 0x7cc791f8bb7c7ced, 0x6617e3cc71666685,
+    0xdda68ea77bdddd53, 0x17b84b2eaf17175c, 0x4702468e45474701, 0x9e84dc211a9e9e42,
+    0xca1ec589d4caca0f, 0x2d75995a582d2db4, 0xbf9179632ebfbfc6, 0x07381b0e3f07071c,
+    0xad012347acadad8e, 0x5aea2fb4b05a5a75, 0x836cb51bef838336, 0x3385ff66b63333cc,
+    0x633ff2c65c636391, 0x02100a0412020208, 0xaa39384993aaaa92, 0x71afa8e2de7171d9,
+    0xc80ecf8dc6c8c807, 0x19c87d32d1191964, 0x497270923b494939, 0xd9869aaf5fd9d943,
+    0xf2c31df931f2f2ef, 0xe34b48dba8e3e3ab, 0x5be22ab6b95b5b71, 0x8834920dbc88881a,
+    0x9aa4c8293e9a9a52, 0x262dbe4c0b262698, 0x328dfa64bf3232c8, 0xb0e94a7d59b0b0fa,
+    0xe91b6acff2e9e983, 0x0f78331e770f0f3c, 0xd5e6a6b733d5d573, 0x8074ba1df480803a,
+    0xbe997c6127bebec2, 0xcd26de87ebcdcd13, 0x34bde468893434d0, 0x487a75903248483d,
+    0xffab24e354ffffdb, 0x7af78ff48d7a7af5, 0x90f4ea3d6490907a, 0x5fc23ebe9d5f5f61,
+    0x201da0403d202080, 0x6867d5d00f6868bd, 0x1ad07234ca1a1a68, 0xae192c41b7aeae82,
+    0xb4c95e757db4b4ea, 0x549a19a8ce54544d, 0x93ece53b7f939376, 0x220daa442f222288,
+    0x6407e9c86364648d, 0xf1db12ff2af1f1e3, 0x73bfa2e6cc7373d1, 0x12905a2482121248,
+    0x403a5d807a40401d, 0x0840281048080820, 0xc356e89b95c3c32b, 0xec337bc5dfecec97,
+    0xdb9690ab4ddbdb4b, 0xa1611f5fc0a1a1be, 0x8d1c8307918d8d0e, 0x3df5c97ac83d3df4,
+    0x97ccf1335b979766, 0x0000000000000000, 0xcf36d483f9cfcf1b, 0x2b4587566e2b2bac,
+    0x7697b3ece17676c5, 0x8264b019e6828232, 0xd6fea9b128d6d67f, 0x1bd87736c31b1b6c,
+    0xb5c15b7774b5b5ee, 0xaf112943beafaf86, 0x6a77dfd41d6a6ab5, 0x50ba0da0ea50505d,
+    0x45124c8a57454509, 0xf3cb18fb38f3f3eb, 0x309df060ad3030c0, 0xef2b74c3c4efef9b,
+    0x3fe5c37eda3f3ffc, 0x55921caac7555549, 0xa2791059dba2a2b2, 0xea0365c9e9eaea8f,
+    0x650fecca6a656589, 0xbab9686903babad2, 0x2f65935e4a2f2fbc, 0xc04ee79d8ec0c027,
+    0xdebe81a160dede5f, 0x1ce06c38fc1c1c70, 0xfdbb2ee746fdfdd3, 0x4d52649a1f4d4d29,
+    0x92e4e03976929272, 0x758fbceafa7575c9, 0x06301e0c36060618, 0x8a249809ae8a8a12,
+    0xb2f940794bb2b2f2, 0xe66359d185e6e6bf, 0x0e70361c7e0e0e38, 0x1ff8633ee71f1f7c,
+    0x6237f7c455626295, 0xd4eea3b53ad4d477, 0xa829324d81a8a89a, 0x96c4f43152969662,
+    0xf99b3aef62f9f9c3, 0xc566f697a3c5c533, 0x2535b14a10252594, 0x59f220b2ab595979,
+    0x8454ae15d084842a, 0x72b7a7e4c57272d5, 0x39d5dd72ec3939e4, 0x4c5a6198164c4c2d,
+    0x5eca3bbc945e5e65, 0x78e785f09f7878fd, 0x38ddd870e53838e0, 0x8c148605988c8c0a,
+    0xd1c6b2bf17d1d163, 0xa5410b57e4a5a5ae, 0xe2434dd9a1e2e2af, 0x612ff8c24e616199,
+    0xb3f1457b42b3b3f6, 0x2115a54234212184, 0x9c94d625089c9c4a, 0x1ef0663cee1e1e78,
+    0x4322528661434311, 0xc776fc93b1c7c73b, 0xfcb32be54ffcfcd7, 0x0420140824040410,
+    0x51b208a2e3515159, 0x99bcc72f2599995e, 0x6d4fc4da226d6da9, 0x0d68391a650d0d34,
+    0xfa8335e979fafacf, 0xdfb684a369dfdf5b, 0x7ed79bfca97e7ee5, 0x243db44819242490,
+    0x3bc5d776fe3b3bec, 0xab313d4b9aabab96, 0xce3ed181f0cece1f, 0x1188552299111144,
+    0x8f0c8903838f8f06, 0x4e4a6b9c044e4e25, 0xb7d1517366b7b7e6, 0xeb0b60cbe0ebeb8b,
+    0x3cfdcc78c13c3cf0, 0x817cbf1ffd81813e, 0x94d4fe354094946a, 0xf7eb0cf31cf7f7fb,
+    0xb9a1676f18b9b9de, 0x13985f268b13134c, 0x2c7d9c58512c2cb0, 0xd3d6b8bb05d3d36b,
+    0xe76b5cd38ce7e7bb, 0x6e57cbdc396e6ea5, 0xc46ef395aac4c437, 0x03180f061b03030c,
+    0x568a13acdc565645, 0x441a49885e44440d, 0x7fdf9efea07f7fe1, 0xa921374f88a9a99e,
+    0x2a4d8254672a2aa8, 0xbbb16d6b0abbbbd6, 0xc146e29f87c1c123, 0x53a202a6f1535351,
+    0xdcae8ba572dcdc57, 0x0b582716530b0b2c, 0x9d9cd327019d9d4e, 0x6c47c1d82b6c6cad,
+    0x3195f562a43131c4, 0x7487b9e8f37474cd, 0xf6e309f115f6f6ff, 0x460a438c4c464605,
+    0xac092645a5acac8a, 0x893c970fb589891e, 0x14a04428b4141450, 0xe15b42dfbae1e1a3,
+    0x16b04e2ca6161658, 0x3acdd274f73a3ae8, 0x696fd0d2066969b9, 0x09482d1241090924,
+    0x70a7ade0d77070dd, 0xb6d954716fb6b6e2, 0xd0ceb7bd1ed0d067, 0xed3b7ec7d6eded93,
+    0xcc2edb85e2cccc17, 0x422a578468424215, 0x98b4c22d2c98985a, 0xa4490e55eda4a4aa,
+    0x285d8850752828a0, 0x5cda31b8865c5c6d, 0xf8933fed6bf8f8c7, 0x8644a411c2868622,
+];
+
+static C6: [u64; 256] = [
+    0x6018c07830d81818, 0x8c2305af46262323, 0x3fc67ef991b8c6c6, 0x87e8136fcdfbe8e8,
+    0x26874ca113cb8787, 0xdab8a9626d11b8b8, 0x0401080502090101, 0x214f426e9e0d4f4f,
+    0xd836adee6c9b3636, 0xa2a6590451ffa6a6, 0x6fd2debdb90cd2d2, 0xf3f5fb06f70ef5f5,
+    0xf979ef80f2967979, 0xa16f5fcede306f6f, 0x7e91fcef3f6d9191, 0x5552aa07a4f85252,
+    0x9d6027fdc0476060, 0xcabc89766535bcbc, 0x569baccd2b379b9b, 0x028e048c018a8e8e,
+    0xb6a371155bd2a3a3, 0x300c603c186c0c0c, 0xf17bff8af6847b7b, 0xd435b5e16a803535,
+    0x741de8693af51d1d, 0xa7e05347ddb3e0e0, 0x7bd7f6acb321d7d7, 0x2fc25eed999cc2c2,
+    0xb82e6d965c432e2e, 0x314b627a96294b4b, 0xdffea321e15dfefe, 0x41578216aed55757,
+    0x5415a8412abd1515, 0xc1779fb6eee87777, 0xdc37a5eb6e923737, 0xb3e57b56d79ee5e5,
+    0x469f8cd923139f9f, 0xe7f0d317fd23f0f0, 0x354a6a7f94204a4a, 0x4fda9e95a944dada,
+    0x7d58fa25b0a25858, 0x03c906ca8fcfc9c9, 0xa429558d527c2929, 0x280a5022145a0a0a,
+    0xfeb1e14f7f50b1b1, 0xbaa0691a5dc9a0a0, 0xb16b7fdad6146b6b, 0x2e855cab17d98585,
+    0xcebd8173673cbdbd, 0x695dd234ba8f5d5d, 0x4010805020901010, 0xf7f4f303f507f4f4,
+    0x0bcb16c08bddcbcb, 0xf83eedc67cd33e3e, 0x140528110a2d0505, 0x81671fe6ce786767,
+    0xb7e47353d597e4e4, 0x9c2725bb4e022727, 0x1941325882734141, 0x168b2c9d0ba78b8b,
+    0xa6a7510153f6a7a7, 0xe97dcf94fab27d7d, 0x6e95dcfb37499595, 0x47d88e9fad56d8d8,
+    0xcbfb8b30eb70fbfb, 0x9fee2371c1cdeeee, 0xed7cc791f8bb7c7c, 0x856617e3cc716666,
+    0x53dda68ea77bdddd, 0x5c17b84b2eaf1717, 0x014702468e454747, 0x429e84dc211a9e9e,
+    0x0fca1ec589d4caca, 0xb42d75995a582d2d, 0xc6bf9179632ebfbf, 0x1c07381b0e3f0707,
+    0x8ead012347acadad, 0x755aea2fb4b05a5a, 0x36836cb51bef8383, 0xcc3385ff66b63333,
+    0x91633ff2c65c6363, 0x0802100a04120202, 0x92aa39384993aaaa, 0xd971afa8e2de7171,
+    0x07c80ecf8dc6c8c8, 0x6419c87d32d11919, 0x39497270923b4949, 0x43d9869aaf5fd9d9,
+    0xeff2c31df931f2f2, 0xabe34b48dba8e3e3, 0x715be22ab6b95b5b, 0x1a8834920dbc8888,
+    0x529aa4c8293e9a9a, 0x98262dbe4c0b2626, 0xc8328dfa64bf3232, 0xfab0e94a7d59b0b0,
+    0x83e91b6acff2e9e9, 0x3c0f78331e770f0f, 0x73d5e6a6b733d5d5, 0x3a8074ba1df48080,
+    0xc2be997c6127bebe, 0x13cd26de87ebcdcd, 0xd034bde468893434, 0x3d487a7590324848,
+    0xdbffab24e354ffff, 0xf57af78ff48d7a7a, 0x7a90f4ea3d649090, 0x615fc23ebe9d5f5f,
+    0x80201da0403d2020, 0xbd6867d5d00f6868, 0x681ad07234ca1a1a, 0x82ae192c41b7aeae,
+    0xeab4c95e757db4b4, 0x4d549a19a8ce5454, 0x7693ece53b7f9393, 0x88220daa442f2222,
+    0x8d6407e9c8636464, 0xe3f1db12ff2af1f1, 0xd173bfa2e6cc7373, 0x4812905a24821212,
+    0x1d403a5d807a4040, 0x2008402810480808, 0x2bc356e89b95c3c3, 0x97ec337bc5dfecec,
+    0x4bdb9690ab4ddbdb, 0xbea1611f5fc0a1a1, 0x0e8d1c8307918d8d, 0xf43df5c97ac83d3d,
+    0x6697ccf1335b9797, 0x0000000000000000, 0x1bcf36d483f9cfcf, 0xac2b4587566e2b2b,
+    0xc57697b3ece17676, 0x328264b019e68282, 0x7fd6fea9b128d6d6, 0x6c1bd87736c31b1b,
+    0xeeb5c15b7774b5b5, 0x86af112943beafaf, 0xb56a77dfd41d6a6a, 0x5d50ba0da0ea5050,
+    0x0945124c8a574545, 0xebf3cb18fb38f3f3, 0xc0309df060ad3030, 0x9bef2b74c3c4efef,
+    0xfc3fe5c37eda3f3f, 0x4955921caac75555, 0xb2a2791059dba2a2, 0x8fea0365c9e9eaea,
+    0x89650fecca6a6565, 0xd2bab9686903baba, 0xbc2f65935e4a2f2f, 0x27c04ee79d8ec0c0,
+    0x5fdebe81a160dede, 0x701ce06c38fc1c1c, 0xd3fdbb2ee746fdfd, 0x294d52649a1f4d4d,
+    0x7292e4e039769292, 0xc9758fbceafa7575, 0x1806301e0c360606, 0x128a249809ae8a8a,
+    0xf2b2f940794bb2b2, 0xbfe66359d185e6e6, 0x380e70361c7e0e0e, 0x7c1ff8633ee71f1f,
+    0x956237f7c4556262, 0x77d4eea3b53ad4d4, 0x9aa829324d81a8a8, 0x6296c4f431529696,
+    0xc3f99b3aef62f9f9, 0x33c566f697a3c5c5, 0x942535b14a102525, 0x7959f220b2ab5959,
+    0x2a8454ae15d08484, 0xd572b7a7e4c57272, 0xe439d5dd72ec3939, 0x2d4c5a6198164c4c,
+    0x655eca3bbc945e5e, 0xfd78e785f09f7878, 0xe038ddd870e53838, 0x0a8c148605988c8c,
+    0x63d1c6b2bf17d1d1, 0xaea5410b57e4a5a5, 0xafe2434dd9a1e2e2, 0x99612ff8c24e6161,
+    0xf6b3f1457b42b3b3, 0x842115a542342121, 0x4a9c94d625089c9c, 0x781ef0663cee1e1e,
+    0x1143225286614343, 0x3bc776fc93b1c7c7, 0xd7fcb32be54ffcfc, 0x1004201408240404,
+    0x5951b208a2e35151, 0x5e99bcc72f259999, 0xa96d4fc4da226d6d, 0x340d68391a650d0d,
+    0xcffa8335e979fafa, 0x5bdfb684a369dfdf, 0xe57ed79bfca97e7e, 0x90243db448192424,
+    0xec3bc5d776fe3b3b, 0x96ab313d4b9aabab, 0x1fce3ed181f0cece, 0x4411885522991111,
+    0x068f0c8903838f8f, 0x254e4a6b9c044e4e, 0xe6b7d1517366b7b7, 0x8beb0b60cbe0ebeb,
+    0xf03cfdcc78c13c3c, 0x3e817cbf1ffd8181, 0x6a94d4fe35409494, 0xfbf7eb0cf31cf7f7,
+    0xdeb9a1676f18b9b9, 0x4c13985f268b1313, 0xb02c7d9c58512c2c, 0x6bd3d6b8bb05d3d3,
+    0xbbe76b5cd38ce7e7, 0xa56e57cbdc396e6e, 0x37c46ef395aac4c4, 0x0c03180f061b0303,
+    0x45568a13acdc5656, 0x0d441a49885e4444, 0xe17fdf9efea07f7f, 0x9ea921374f88a9a9,
+    0xa82a4d8254672a2a, 0xd6bbb16d6b0abbbb, 0x23c146e29f87c1c1, 0x5153a202a6f15353,
+    0x57dcae8ba572dcdc, 0x2c0b582716530b0b, 0x4e9d9cd327019d9d, 0xad6c47c1d82b6c6c,
+    0xc43195f562a43131, 0xcd7487b9e8f37474, 0xfff6e309f115f6f6, 0x05460a438c4c4646,
+    0x8aac092645a5acac, 0x1e893c970fb58989, 0x5014a04428b41414, 0xa3e15b42dfbae1e1,
+    0x5816b04e2ca61616, 0xe83acdd274f73a3a, 0xb9696fd0d2066969, 0x2409482d12410909,
+    0xdd70a7ade0d77070, 0xe2b6d954716fb6b6, 0x67d0ceb7bd1ed0d0, 0x93ed3b7ec7d6eded,
+    0x17cc2edb85e2cccc, 0x15422a5784684242, 0x5a98b4c22d2c9898, 0xaaa4490e55eda4a4,
+    0xa0285d8850752828, 0x6d5cda31b8865c5c, 0xc7f8933fed6bf8f8, 0x228644a411c28686,
+];
+
+static C7: [u64; 256] = [
+    0x186018c07830d818, 0x238c2305af462623, 0xc63fc67ef991b8c6, 0xe887e8136fcdfbe8,
+    0x8726874ca113cb87, 0xb8dab8a9626d11b8, 0x0104010805020901, 0x4f214f426e9e0d4f,
+    0x36d836adee6c9b36, 0xa6a2a6590451ffa6, 0xd26fd2debdb90cd2, 0xf5f3f5fb06f70ef5,
+    0x79f979ef80f29679, 0x6fa16f5fcede306f, 0x917e91fcef3f6d91, 0x525552aa07a4f852,
+    0x609d6027fdc04760, 0xbccabc89766535bc, 0x9b569baccd2b379b, 0x8e028e048c018a8e,
+    0xa3b6a371155bd2a3, 0x0c300c603c186c0c, 0x7bf17bff8af6847b, 0x35d435b5e16a8035,
+    0x1d741de8693af51d, 0xe0a7e05347ddb3e0, 0xd77bd7f6acb321d7, 0xc22fc25eed999cc2,
+    0x2eb82e6d965c432e, 0x4b314b627a96294b, 0xfedffea321e15dfe, 0x5741578216aed557,
+    0x155415a8412abd15, 0x77c1779fb6eee877, 0x37dc37a5eb6e9237, 0xe5b3e57b56d79ee5,
+    0x9f469f8cd923139f, 0xf0e7f0d317fd23f0, 0x4a354a6a7f94204a, 0xda4fda9e95a944da,
+    0x587d58fa25b0a258, 0xc903c906ca8fcfc9, 0x29a429558d527c29, 0x0a280a5022145a0a,
+    0xb1feb1e14f7f50b1, 0xa0baa0691a5dc9a0, 0x6bb16b7fdad6146b, 0x852e855cab17d985,
+    0xbdcebd8173673cbd, 0x5d695dd234ba8f5d, 0x1040108050209010, 0xf4f7f4f303f507f4,
+    0xcb0bcb16c08bddcb, 0x3ef83eedc67cd33e, 0x05140528110a2d05, 0x6781671fe6ce7867,
+    0xe4b7e47353d597e4, 0x279c2725bb4e0227, 0x4119413258827341, 0x8b168b2c9d0ba78b,
+    0xa7a6a7510153f6a7, 0x7de97dcf94fab27d, 0x956e95dcfb374995, 0xd847d88e9fad56d8,
+    0xfbcbfb8b30eb70fb, 0xee9fee2371c1cdee, 0x7ced7cc791f8bb7c, 0x66856617e3cc7166,
+    0xdd53dda68ea77bdd, 0x175c17b84b2eaf17, 0x47014702468e4547, 0x9e429e84dc211a9e,
+    0xca0fca1ec589d4ca, 0x2db42d75995a582d, 0xbfc6bf9179632ebf, 0x071c07381b0e3f07,
+    0xad8ead012347acad, 0x5a755aea2fb4b05a, 0x8336836cb51bef83, 0x33cc3385ff66b633,
+    0x6391633ff2c65c63, 0x020802100a041202, 0xaa92aa39384993aa, 0x71d971afa8e2de71,
+    0xc807c80ecf8dc6c8, 0x196419c87d32d119, 0x4939497270923b49, 0xd943d9869aaf5fd9,
+    0xf2eff2c31df931f2, 0xe3abe34b48dba8e3, 0x5b715be22ab6b95b, 0x881a8834920dbc88,
+    0x9a529aa4c8293e9a, 0x2698262dbe4c0b26, 0x32c8328dfa64bf32, 0xb0fab0e94a7d59b0,
+    0xe983e91b6acff2e9, 0x0f3c0f78331e770f, 0xd573d5e6a6b733d5, 0x803a8074ba1df480,
+    0xbec2be997c6127be, 0xcd13cd26de87ebcd, 0x34d034bde4688934, 0x483d487a75903248,
+    0xffdbffab24e354ff, 0x7af57af78ff48d7a, 0x907a90f4ea3d6490, 0x5f615fc23ebe9d5f,
+    0x2080201da0403d20, 0x68bd6867d5d00f68, 0x1a681ad07234ca1a, 0xae82ae192c41b7ae,
+    0xb4eab4c95e757db4, 0x544d549a19a8ce54, 0x937693ece53b7f93, 0x2288220daa442f22,
+    0x648d6407e9c86364, 0xf1e3f1db12ff2af1, 0x73d173bfa2e6cc73, 0x124812905a248212,
+    0x401d403a5d807a40, 0x0820084028104808, 0xc32bc356e89b95c3, 0xec97ec337bc5dfec,
+    0xdb4bdb9690ab4ddb, 0xa1bea1611f5fc0a1, 0x8d0e8d1c8307918d, 0x3df43df5c97ac83d,
+    0x976697ccf1335b97, 0x0000000000000000, 0xcf1bcf36d483f9cf, 0x2bac2b4587566e2b,
+    0x76c57697b3ece176, 0x82328264b019e682, 0xd67fd6fea9b128d6, 0x1b6c1bd87736c31b,
+    0xb5eeb5c15b7774b5, 0xaf86af112943beaf, 0x6ab56a77dfd41d6a, 0x505d50ba0da0ea50,
+    0x450945124c8a5745, 0xf3ebf3cb18fb38f3, 0x30c0309df060ad30, 0xef9bef2b74c3c4ef,
+    0x3ffc3fe5c37eda3f, 0x554955921caac755, 0xa2b2a2791059dba2, 0xea8fea0365c9e9ea,
+    0x6589650fecca6a65, 0xbad2bab9686903ba, 0x2fbc2f65935e4a2f, 0xc027c04ee79d8ec0,
+    0xde5fdebe81a160de, 0x1c701ce06c38fc1c, 0xfdd3fdbb2ee746fd, 0x4d294d52649a1f4d,
+    0x927292e4e0397692, 0x75c9758fbceafa75, 0x061806301e0c3606, 0x8a128a249809ae8a,
+    0xb2f2b2f940794bb2, 0xe6bfe66359d185e6, 0x0e380e70361c7e0e, 0x1f7c1ff8633ee71f,
+    0x62956237f7c45562, 0xd477d4eea3b53ad4, 0xa89aa829324d81a8, 0x966296c4f4315296,
+    0xf9c3f99b3aef62f9, 0xc533c566f697a3c5, 0x25942535b14a1025, 0x597959f220b2ab59,
+    0x842a8454ae15d084, 0x72d572b7a7e4c572, 0x39e439d5dd72ec39, 0x4c2d4c5a6198164c,
+    0x5e655eca3bbc945e, 0x78fd78e785f09f78, 0x38e038ddd870e538, 0x8c0a8c148605988c,
+    0xd163d1c6b2bf17d1, 0xa5aea5410b57e4a5, 0xe2afe2434dd9a1e2, 0x6199612ff8c24e61,
+    0xb3f6b3f1457b42b3, 0x21842115a5423421, 0x9c4a9c94d625089c, 0x1e781ef0663cee1e,
+    0x4311432252866143, 0xc73bc776fc93b1c7, 0xfcd7fcb32be54ffc, 0x0410042014082404,
+    0x515951b208a2e351, 0x995e99bcc72f2599, 0x6da96d4fc4da226d, 0x0d340d68391a650d,
+    0xfacffa8335e979fa, 0xdf5bdfb684a369df, 0x7ee57ed79bfca97e, 0x2490243db4481924,
+    0x3bec3bc5d776fe3b, 0xab96ab313d4b9aab, 0xce1fce3ed181f0ce, 0x1144118855229911,
+    0x8f068f0c8903838f, 0x4e254e4a6b9c044e, 0xb7e6b7d1517366b7, 0xeb8beb0b60cbe0eb,
+    0x3cf03cfdcc78c13c, 0x813e817cbf1ffd81, 0x946a94d4fe354094, 0xf7fbf7eb0cf31cf7,
+    0xb9deb9a1676f18b9, 0x134c13985f268b13, 0x2cb02c7d9c58512c, 0xd36bd3d6b8bb05d3,
+    0xe7bbe76b5cd38ce7, 0x6ea56e57cbdc396e, 0xc437c46ef395aac4, 0x030c03180f061b03,
+    0x5645568a13acdc56, 0x440d441a49885e44, 0x7fe17fdf9efea07f, 0xa99ea921374f88a9,
+    0x2aa82a4d8254672a, 0xbbd6bbb16d6b0abb, 0xc123c146e29f87c1, 0x535153a202a6f153,
+    0xdc57dcae8ba572dc, 0x0b2c0b582716530b, 0x9d4e9d9cd327019d, 0x6cad6c47c1d82b6c,
+    0x31c43195f562a431, 0x74cd7487b9e8f374, 0xf6fff6e309f115f6, 0x4605460a438c4c46,
+    0xac8aac092645a5ac, 0x891e893c970fb589, 0x145014a04428b414, 0xe1a3e15b42dfbae1,
+    0x165816b04e2ca616, 0x3ae83acdd274f73a, 0x69b9696fd0d20669, 0x092409482d124109,
+    0x70dd70a7ade0d770, 0xb6e2b6d954716fb6, 0xd067d0ceb7bd1ed0, 0xed93ed3b7ec7d6ed,
+    0xcc17cc2edb85e2cc, 0x4215422a57846842, 0x985a98b4c22d2c98, 0xa4aaa4490e55eda4,
+    0x28a0285d88507528, 0x5c6d5cda31b8865c, 0xf8c7f8933fed6bf8, 0x86228644a411c286,
+];
diff --git a/third_party/rust-crypto/x86_64-unknown-linux-sgx.json b/third_party/rust-crypto/x86_64-unknown-linux-sgx.json
new file mode 100644
index 0000000..6cbb524
--- /dev/null
+++ b/third_party/rust-crypto/x86_64-unknown-linux-sgx.json
@@ -0,0 +1,31 @@
+{
+  "arch": "x86_64",
+  "cpu": "x86-64",
+  "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
+  "dynamic-linking": true,
+  "env": "sgx",
+  "exe-allocation-crate": "alloc_system",
+  "executables": true,
+  "has-elf-tls": true,
+  "has-rpath": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-unknown-linux-gnu",
+  "max-atomic-width": 64,
+  "os": "linux",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relro-level": "full",
+  "stack-probes": true,
+  "target-c-int-width": "32",
+  "target-endian": "little",
+  "target-family": "unix",
+  "target-pointer-width": "64",
+  "vendor": "unknown"
+}
diff --git a/third_party/rust-fnv/.gitignore b/third_party/rust-fnv/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/third_party/rust-fnv/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/third_party/rust-fnv/.travis.yml b/third_party/rust-fnv/.travis.yml
new file mode 100644
index 0000000..9c58f03
--- /dev/null
+++ b/third_party/rust-fnv/.travis.yml
@@ -0,0 +1,8 @@
+language: rust
+rust:
+  - nightly
+  - beta
+  - stable
+
+notifications:
+  webhooks: http://build.servo.org:54856/travis
diff --git a/third_party/rust-fnv/Cargo.toml b/third_party/rust-fnv/Cargo.toml
new file mode 100644
index 0000000..f89509c
--- /dev/null
+++ b/third_party/rust-fnv/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "fnv"
+version = "1.0.6"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+description = "Fowler–Noll–Vo hash function"
+license = "Apache-2.0 / MIT"
+readme = "README.md"
+repository = "https://github.com/servo/rust-fnv"
+documentation = "https://doc.servo.org/fnv/"
+
+[target.'cfg(not(target_env = "sgx"))'.dependencies]
+sgx_tstd = { path = "../../sgx_tstd" }
+
+[lib]
+name = "fnv"
+path = "lib.rs"
diff --git a/third_party/rust-fnv/LICENSE-APACHE b/third_party/rust-fnv/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/third_party/rust-fnv/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust-fnv/LICENSE-MIT b/third_party/rust-fnv/LICENSE-MIT
new file mode 100644
index 0000000..bc976a2
--- /dev/null
+++ b/third_party/rust-fnv/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017 Contributors
+
+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/third_party/rust-fnv/README.md b/third_party/rust-fnv/README.md
new file mode 100644
index 0000000..6a4c4ae
--- /dev/null
+++ b/third_party/rust-fnv/README.md
@@ -0,0 +1,81 @@
+# rust-fnv
+
+An implementation of the [Fowler–Noll–Vo hash function][chongo].
+
+### [Read the documentation](https://doc.servo.org/fnv/)
+
+
+## About
+
+The FNV hash function is a custom `Hasher` implementation that is more
+efficient for smaller hash keys.
+
+[The Rust FAQ states that][faq] while the default `Hasher` implementation,
+SipHash, is good in many cases, it is notably slower than other algorithms
+with short keys, such as when you have a map of integers to other values.
+In cases like these, [FNV is demonstrably faster][graphs].
+
+Its disadvantages are that it performs badly on larger inputs, and
+provides no protection against collision attacks, where a malicious user
+can craft specific keys designed to slow a hasher down. Thus, it is
+important to profile your program to ensure that you are using small hash
+keys, and be certain that your program could not be exposed to malicious
+inputs (including being a networked server).
+
+The Rust compiler itself uses FNV, as it is not worried about
+denial-of-service attacks, and can assume that its inputs are going to be
+small—a perfect use case for FNV.
+
+
+## Usage
+
+To include this crate in your program, add the following to your `Cargo.toml`:
+
+```toml
+[dependencies]
+fnv = "1.0.3"
+```
+
+
+## Using FNV in a HashMap
+
+The `FnvHashMap` type alias is the easiest way to use the standard library’s
+`HashMap` with FNV.
+
+```rust
+use fnv::FnvHashMap;
+
+let mut map = FnvHashMap::default();
+map.insert(1, "one");
+map.insert(2, "two");
+
+map = FnvHashMap::with_capacity_and_hasher(10, Default::default());
+map.insert(1, "one");
+map.insert(2, "two");
+```
+
+Note, the standard library’s `HashMap::new` and `HashMap::with_capacity`
+are only implemented for the `RandomState` hasher, so using `Default` to
+get the hasher is the next best option.
+
+
+## Using FNV in a HashSet
+
+Similarly, `FnvHashSet` is a type alias for the standard library’s `HashSet`
+with FNV.
+
+```rust
+use fnv::FnvHashSet;
+
+let mut set = FnvHashSet::default();
+set.insert(1);
+set.insert(2);
+
+set = FnvHashSet::with_capacity_and_hasher(10, Default::default());
+set.insert(1);
+set.insert(2);
+```
+
+[chongo]: http://www.isthe.com/chongo/tech/comp/fnv/index.html
+[faq]: https://www.rust-lang.org/en-US/faq.html#why-are-rusts-hashmaps-slow
+[graphs]: http://cglab.ca/~abeinges/blah/hash-rs/
diff --git a/third_party/rust-fnv/Xargo.toml b/third_party/rust-fnv/Xargo.toml
new file mode 100644
index 0000000..48ad024
--- /dev/null
+++ b/third_party/rust-fnv/Xargo.toml
@@ -0,0 +1,20 @@
+[dependencies]
+alloc = {}
+panic_unwind = {}
+panic_abort = {}
+
+[dependencies.std]
+path = "../../xargo/sgx_tstd"
+stage = 1
+
+[dependencies.sgx_rand]
+path = "../../xargo/sgx_rand"
+stage = 2
+
+[dependencies.sgx_serialize]
+path = "../../xargo/sgx_serialize"
+stage = 2
+
+[dependencies.sgx_tunittest]
+path = "../../xargo/sgx_tunittest"
+stage = 2
\ No newline at end of file
diff --git a/third_party/rust-fnv/lib.rs b/third_party/rust-fnv/lib.rs
new file mode 100644
index 0000000..f84d238
--- /dev/null
+++ b/third_party/rust-fnv/lib.rs
@@ -0,0 +1,353 @@
+//! An implementation of the [Fowler–Noll–Vo hash function][chongo].
+//!
+//! ## About
+//!
+//! The FNV hash function is a custom `Hasher` implementation that is more
+//! efficient for smaller hash keys.
+//!
+//! [The Rust FAQ states that][faq] while the default `Hasher` implementation,
+//! SipHash, is good in many cases, it is notably slower than other algorithms
+//! with short keys, such as when you have a map of integers to other values.
+//! In cases like these, [FNV is demonstrably faster][graphs].
+//!
+//! Its disadvantages are that it performs badly on larger inputs, and
+//! provides no protection against collision attacks, where a malicious user
+//! can craft specific keys designed to slow a hasher down. Thus, it is
+//! important to profile your program to ensure that you are using small hash
+//! keys, and be certain that your program could not be exposed to malicious
+//! inputs (including being a networked server).
+//!
+//! The Rust compiler itself uses FNV, as it is not worried about
+//! denial-of-service attacks, and can assume that its inputs are going to be
+//! small—a perfect use case for FNV.
+//!
+//!
+//! ## Using FNV in a `HashMap`
+//!
+//! The `FnvHashMap` type alias is the easiest way to use the standard library’s
+//! `HashMap` with FNV.
+//!
+//! ```rust
+//! use fnv::FnvHashMap;
+//!
+//! let mut map = FnvHashMap::default();
+//! map.insert(1, "one");
+//! map.insert(2, "two");
+//!
+//! map = FnvHashMap::with_capacity_and_hasher(10, Default::default());
+//! map.insert(1, "one");
+//! map.insert(2, "two");
+//! ```
+//!
+//! Note, the standard library’s `HashMap::new` and `HashMap::with_capacity`
+//! are only implemented for the `RandomState` hasher, so using `Default` to
+//! get the hasher is the next best option.
+//!
+//! ## Using FNV in a `HashSet`
+//!
+//! Similarly, `FnvHashSet` is a type alias for the standard library’s `HashSet`
+//! with FNV.
+//!
+//! ```rust
+//! use fnv::FnvHashSet;
+//!
+//! let mut set = FnvHashSet::default();
+//! set.insert(1);
+//! set.insert(2);
+//!
+//! set = FnvHashSet::with_capacity_and_hasher(10, Default::default());
+//! set.insert(1);
+//! set.insert(2);
+//! ```
+//!
+//! [chongo]: http://www.isthe.com/chongo/tech/comp/fnv/index.html
+//! [faq]: https://www.rust-lang.org/en-US/faq.html#why-are-rusts-hashmaps-slow
+//! [graphs]: http://cglab.ca/~abeinges/blah/hash-rs/
+#![cfg_attr(not(target_env = "sgx"), no_std)]
+#![feature(rustc_attrs)]
+#![feature(rustc_private)]
+#[cfg(not(target_env = "sgx"))]
+extern crate sgx_tstd as std;
+
+use std::default::Default;
+use std::hash::{Hasher, BuildHasherDefault};
+use std::collections::{HashMap, HashSet};
+
+/// An implementation of the Fowler–Noll–Vo hash function.
+///
+/// See the [crate documentation](index.html) for more details.
+#[allow(missing_copy_implementations)]
+pub struct FnvHasher(u64);
+
+impl Default for FnvHasher {
+
+    #[inline]
+    fn default() -> FnvHasher {
+        FnvHasher(0xcbf29ce484222325)
+    }
+}
+
+impl FnvHasher {
+    /// Create an FNV hasher starting with a state corresponding
+    /// to the hash `key`.
+    #[inline]
+    pub fn with_key(key: u64) -> FnvHasher {
+        FnvHasher(key)
+    }
+}
+
+impl Hasher for FnvHasher {
+    #[inline]
+    fn finish(&self) -> u64 {
+        self.0
+    }
+
+    #[inline]
+    fn write(&mut self, bytes: &[u8]) {
+        let FnvHasher(mut hash) = *self;
+
+        for byte in bytes.iter() {
+            hash = hash ^ (*byte as u64);
+            hash = hash.wrapping_mul(0x100000001b3);
+        }
+
+        *self = FnvHasher(hash);
+    }
+}
+
+/// A builder for default FNV hashers.
+pub type FnvBuildHasher = BuildHasherDefault<FnvHasher>;
+
+/// A `HashMap` using a default FNV hasher.
+pub type FnvHashMap<K, V> = HashMap<K, V, FnvBuildHasher>;
+
+/// A `HashSet` using a default FNV hasher.
+pub type FnvHashSet<T> = HashSet<T, FnvBuildHasher>;
+
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::hash::Hasher;
+
+    fn fnv1a(bytes: &[u8]) -> u64 {
+        let mut hasher = FnvHasher::default();
+        hasher.write(bytes);
+        hasher.finish()
+    }
+
+    fn repeat_10(bytes: &[u8]) -> Vec<u8> {
+        (0..10).flat_map(|_| bytes.iter().cloned()).collect()
+    }
+
+    fn repeat_500(bytes: &[u8]) -> Vec<u8> {
+        (0..500).flat_map(|_| bytes.iter().cloned()).collect()
+    }
+
+    #[test]
+    fn basic_tests() {
+        assert_eq!(fnv1a(b""), 0xcbf29ce484222325);
+        assert_eq!(fnv1a(b"a"), 0xaf63dc4c8601ec8c);
+        assert_eq!(fnv1a(b"b"), 0xaf63df4c8601f1a5);
+        assert_eq!(fnv1a(b"c"), 0xaf63de4c8601eff2);
+        assert_eq!(fnv1a(b"d"), 0xaf63d94c8601e773);
+        assert_eq!(fnv1a(b"e"), 0xaf63d84c8601e5c0);
+        assert_eq!(fnv1a(b"f"), 0xaf63db4c8601ead9);
+        assert_eq!(fnv1a(b"fo"), 0x08985907b541d342);
+        assert_eq!(fnv1a(b"foo"), 0xdcb27518fed9d577);
+        assert_eq!(fnv1a(b"foob"), 0xdd120e790c2512af);
+        assert_eq!(fnv1a(b"fooba"), 0xcac165afa2fef40a);
+        assert_eq!(fnv1a(b"foobar"), 0x85944171f73967e8);
+        assert_eq!(fnv1a(b"\0"), 0xaf63bd4c8601b7df);
+        assert_eq!(fnv1a(b"a\0"), 0x089be207b544f1e4);
+        assert_eq!(fnv1a(b"b\0"), 0x08a61407b54d9b5f);
+        assert_eq!(fnv1a(b"c\0"), 0x08a2ae07b54ab836);
+        assert_eq!(fnv1a(b"d\0"), 0x0891b007b53c4869);
+        assert_eq!(fnv1a(b"e\0"), 0x088e4a07b5396540);
+        assert_eq!(fnv1a(b"f\0"), 0x08987c07b5420ebb);
+        assert_eq!(fnv1a(b"fo\0"), 0xdcb28a18fed9f926);
+        assert_eq!(fnv1a(b"foo\0"), 0xdd1270790c25b935);
+        assert_eq!(fnv1a(b"foob\0"), 0xcac146afa2febf5d);
+        assert_eq!(fnv1a(b"fooba\0"), 0x8593d371f738acfe);
+        assert_eq!(fnv1a(b"foobar\0"), 0x34531ca7168b8f38);
+        assert_eq!(fnv1a(b"ch"), 0x08a25607b54a22ae);
+        assert_eq!(fnv1a(b"cho"), 0xf5faf0190cf90df3);
+        assert_eq!(fnv1a(b"chon"), 0xf27397910b3221c7);
+        assert_eq!(fnv1a(b"chong"), 0x2c8c2b76062f22e0);
+        assert_eq!(fnv1a(b"chongo"), 0xe150688c8217b8fd);
+        assert_eq!(fnv1a(b"chongo "), 0xf35a83c10e4f1f87);
+        assert_eq!(fnv1a(b"chongo w"), 0xd1edd10b507344d0);
+        assert_eq!(fnv1a(b"chongo wa"), 0x2a5ee739b3ddb8c3);
+        assert_eq!(fnv1a(b"chongo was"), 0xdcfb970ca1c0d310);
+        assert_eq!(fnv1a(b"chongo was "), 0x4054da76daa6da90);
+        assert_eq!(fnv1a(b"chongo was h"), 0xf70a2ff589861368);
+        assert_eq!(fnv1a(b"chongo was he"), 0x4c628b38aed25f17);
+        assert_eq!(fnv1a(b"chongo was her"), 0x9dd1f6510f78189f);
+        assert_eq!(fnv1a(b"chongo was here"), 0xa3de85bd491270ce);
+        assert_eq!(fnv1a(b"chongo was here!"), 0x858e2fa32a55e61d);
+        assert_eq!(fnv1a(b"chongo was here!\n"), 0x46810940eff5f915);
+        assert_eq!(fnv1a(b"ch\0"), 0xf5fadd190cf8edaa);
+        assert_eq!(fnv1a(b"cho\0"), 0xf273ed910b32b3e9);
+        assert_eq!(fnv1a(b"chon\0"), 0x2c8c5276062f6525);
+        assert_eq!(fnv1a(b"chong\0"), 0xe150b98c821842a0);
+        assert_eq!(fnv1a(b"chongo\0"), 0xf35aa3c10e4f55e7);
+        assert_eq!(fnv1a(b"chongo \0"), 0xd1ed680b50729265);
+        assert_eq!(fnv1a(b"chongo w\0"), 0x2a5f0639b3dded70);
+        assert_eq!(fnv1a(b"chongo wa\0"), 0xdcfbaa0ca1c0f359);
+        assert_eq!(fnv1a(b"chongo was\0"), 0x4054ba76daa6a430);
+        assert_eq!(fnv1a(b"chongo was \0"), 0xf709c7f5898562b0);
+        assert_eq!(fnv1a(b"chongo was h\0"), 0x4c62e638aed2f9b8);
+        assert_eq!(fnv1a(b"chongo was he\0"), 0x9dd1a8510f779415);
+        assert_eq!(fnv1a(b"chongo was her\0"), 0xa3de2abd4911d62d);
+        assert_eq!(fnv1a(b"chongo was here\0"), 0x858e0ea32a55ae0a);
+        assert_eq!(fnv1a(b"chongo was here!\0"), 0x46810f40eff60347);
+        assert_eq!(fnv1a(b"chongo was here!\n\0"), 0xc33bce57bef63eaf);
+        assert_eq!(fnv1a(b"cu"), 0x08a24307b54a0265);
+        assert_eq!(fnv1a(b"cur"), 0xf5b9fd190cc18d15);
+        assert_eq!(fnv1a(b"curd"), 0x4c968290ace35703);
+        assert_eq!(fnv1a(b"curds"), 0x07174bd5c64d9350);
+        assert_eq!(fnv1a(b"curds "), 0x5a294c3ff5d18750);
+        assert_eq!(fnv1a(b"curds a"), 0x05b3c1aeb308b843);
+        assert_eq!(fnv1a(b"curds an"), 0xb92a48da37d0f477);
+        assert_eq!(fnv1a(b"curds and"), 0x73cdddccd80ebc49);
+        assert_eq!(fnv1a(b"curds and "), 0xd58c4c13210a266b);
+        assert_eq!(fnv1a(b"curds and w"), 0xe78b6081243ec194);
+        assert_eq!(fnv1a(b"curds and wh"), 0xb096f77096a39f34);
+        assert_eq!(fnv1a(b"curds and whe"), 0xb425c54ff807b6a3);
+        assert_eq!(fnv1a(b"curds and whey"), 0x23e520e2751bb46e);
+        assert_eq!(fnv1a(b"curds and whey\n"), 0x1a0b44ccfe1385ec);
+        assert_eq!(fnv1a(b"cu\0"), 0xf5ba4b190cc2119f);
+        assert_eq!(fnv1a(b"cur\0"), 0x4c962690ace2baaf);
+        assert_eq!(fnv1a(b"curd\0"), 0x0716ded5c64cda19);
+        assert_eq!(fnv1a(b"curds\0"), 0x5a292c3ff5d150f0);
+        assert_eq!(fnv1a(b"curds \0"), 0x05b3e0aeb308ecf0);
+        assert_eq!(fnv1a(b"curds a\0"), 0xb92a5eda37d119d9);
+        assert_eq!(fnv1a(b"curds an\0"), 0x73ce41ccd80f6635);
+        assert_eq!(fnv1a(b"curds and\0"), 0xd58c2c132109f00b);
+        assert_eq!(fnv1a(b"curds and \0"), 0xe78baf81243f47d1);
+        assert_eq!(fnv1a(b"curds and w\0"), 0xb0968f7096a2ee7c);
+        assert_eq!(fnv1a(b"curds and wh\0"), 0xb425a84ff807855c);
+        assert_eq!(fnv1a(b"curds and whe\0"), 0x23e4e9e2751b56f9);
+        assert_eq!(fnv1a(b"curds and whey\0"), 0x1a0b4eccfe1396ea);
+        assert_eq!(fnv1a(b"curds and whey\n\0"), 0x54abd453bb2c9004);
+        assert_eq!(fnv1a(b"hi"), 0x08ba5f07b55ec3da);
+        assert_eq!(fnv1a(b"hi\0"), 0x337354193006cb6e);
+        assert_eq!(fnv1a(b"hello"), 0xa430d84680aabd0b);
+        assert_eq!(fnv1a(b"hello\0"), 0xa9bc8acca21f39b1);
+        assert_eq!(fnv1a(b"\xff\x00\x00\x01"), 0x6961196491cc682d);
+        assert_eq!(fnv1a(b"\x01\x00\x00\xff"), 0xad2bb1774799dfe9);
+        assert_eq!(fnv1a(b"\xff\x00\x00\x02"), 0x6961166491cc6314);
+        assert_eq!(fnv1a(b"\x02\x00\x00\xff"), 0x8d1bb3904a3b1236);
+        assert_eq!(fnv1a(b"\xff\x00\x00\x03"), 0x6961176491cc64c7);
+        assert_eq!(fnv1a(b"\x03\x00\x00\xff"), 0xed205d87f40434c7);
+        assert_eq!(fnv1a(b"\xff\x00\x00\x04"), 0x6961146491cc5fae);
+        assert_eq!(fnv1a(b"\x04\x00\x00\xff"), 0xcd3baf5e44f8ad9c);
+        assert_eq!(fnv1a(b"\x40\x51\x4e\x44"), 0xe3b36596127cd6d8);
+        assert_eq!(fnv1a(b"\x44\x4e\x51\x40"), 0xf77f1072c8e8a646);
+        assert_eq!(fnv1a(b"\x40\x51\x4e\x4a"), 0xe3b36396127cd372);
+        assert_eq!(fnv1a(b"\x4a\x4e\x51\x40"), 0x6067dce9932ad458);
+        assert_eq!(fnv1a(b"\x40\x51\x4e\x54"), 0xe3b37596127cf208);
+        assert_eq!(fnv1a(b"\x54\x4e\x51\x40"), 0x4b7b10fa9fe83936);
+        assert_eq!(fnv1a(b"127.0.0.1"), 0xaabafe7104d914be);
+        assert_eq!(fnv1a(b"127.0.0.1\0"), 0xf4d3180b3cde3eda);
+        assert_eq!(fnv1a(b"127.0.0.2"), 0xaabafd7104d9130b);
+        assert_eq!(fnv1a(b"127.0.0.2\0"), 0xf4cfb20b3cdb5bb1);
+        assert_eq!(fnv1a(b"127.0.0.3"), 0xaabafc7104d91158);
+        assert_eq!(fnv1a(b"127.0.0.3\0"), 0xf4cc4c0b3cd87888);
+        assert_eq!(fnv1a(b"64.81.78.68"), 0xe729bac5d2a8d3a7);
+        assert_eq!(fnv1a(b"64.81.78.68\0"), 0x74bc0524f4dfa4c5);
+        assert_eq!(fnv1a(b"64.81.78.74"), 0xe72630c5d2a5b352);
+        assert_eq!(fnv1a(b"64.81.78.74\0"), 0x6b983224ef8fb456);
+        assert_eq!(fnv1a(b"64.81.78.84"), 0xe73042c5d2ae266d);
+        assert_eq!(fnv1a(b"64.81.78.84\0"), 0x8527e324fdeb4b37);
+        assert_eq!(fnv1a(b"feedface"), 0x0a83c86fee952abc);
+        assert_eq!(fnv1a(b"feedface\0"), 0x7318523267779d74);
+        assert_eq!(fnv1a(b"feedfacedaffdeed"), 0x3e66d3d56b8caca1);
+        assert_eq!(fnv1a(b"feedfacedaffdeed\0"), 0x956694a5c0095593);
+        assert_eq!(fnv1a(b"feedfacedeadbeef"), 0xcac54572bb1a6fc8);
+        assert_eq!(fnv1a(b"feedfacedeadbeef\0"), 0xa7a4c9f3edebf0d8);
+        assert_eq!(fnv1a(b"line 1\nline 2\nline 3"), 0x7829851fac17b143);
+        assert_eq!(fnv1a(b"chongo <Landon Curt Noll> /\\../\\"), 0x2c8f4c9af81bcf06);
+        assert_eq!(fnv1a(b"chongo <Landon Curt Noll> /\\../\\\0"), 0xd34e31539740c732);
+        assert_eq!(fnv1a(b"chongo (Landon Curt Noll) /\\../\\"), 0x3605a2ac253d2db1);
+        assert_eq!(fnv1a(b"chongo (Landon Curt Noll) /\\../\\\0"), 0x08c11b8346f4a3c3);
+        assert_eq!(fnv1a(b"http://antwrp.gsfc.nasa.gov/apod/astropix.html"), 0x6be396289ce8a6da);
+        assert_eq!(fnv1a(b"http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash"), 0xd9b957fb7fe794c5);
+        assert_eq!(fnv1a(b"http://epod.usra.edu/"), 0x05be33da04560a93);
+        assert_eq!(fnv1a(b"http://exoplanet.eu/"), 0x0957f1577ba9747c);
+        assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/cam3/"), 0xda2cc3acc24fba57);
+        assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/cams/HMcam/"), 0x74136f185b29e7f0);
+        assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/deformation.html"), 0xb2f2b4590edb93b2);
+        assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/images.html"), 0xb3608fce8b86ae04);
+        assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/maps.html"), 0x4a3a865079359063);
+        assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/volcanowatch/current_issue.html"), 0x5b3a7ef496880a50);
+        assert_eq!(fnv1a(b"http://neo.jpl.nasa.gov/risk/"), 0x48fae3163854c23b);
+        assert_eq!(fnv1a(b"http://norvig.com/21-days.html"), 0x07aaa640476e0b9a);
+        assert_eq!(fnv1a(b"http://primes.utm.edu/curios/home.php"), 0x2f653656383a687d);
+        assert_eq!(fnv1a(b"http://slashdot.org/"), 0xa1031f8e7599d79c);
+        assert_eq!(fnv1a(b"http://tux.wr.usgs.gov/Maps/155.25-19.5.html"), 0xa31908178ff92477);
+        assert_eq!(fnv1a(b"http://volcano.wr.usgs.gov/kilaueastatus.php"), 0x097edf3c14c3fb83);
+        assert_eq!(fnv1a(b"http://www.avo.alaska.edu/activity/Redoubt.php"), 0xb51ca83feaa0971b);
+        assert_eq!(fnv1a(b"http://www.dilbert.com/fast/"), 0xdd3c0d96d784f2e9);
+        assert_eq!(fnv1a(b"http://www.fourmilab.ch/gravitation/orbits/"), 0x86cd26a9ea767d78);
+        assert_eq!(fnv1a(b"http://www.fpoa.net/"), 0xe6b215ff54a30c18);
+        assert_eq!(fnv1a(b"http://www.ioccc.org/index.html"), 0xec5b06a1c5531093);
+        assert_eq!(fnv1a(b"http://www.isthe.com/cgi-bin/number.cgi"), 0x45665a929f9ec5e5);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/bio.html"), 0x8c7609b4a9f10907);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/index.html"), 0x89aac3a491f0d729);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/src/calc/lucas-calc"), 0x32ce6b26e0f4a403);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/astro/venus2004.html"), 0x614ab44e02b53e01);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/astro/vita.html"), 0xfa6472eb6eef3290);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/c/expert.html"), 0x9e5d75eb1948eb6a);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/calc/index.html"), 0xb6d12ad4a8671852);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/fnv/index.html"), 0x88826f56eba07af1);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/number/howhigh.html"), 0x44535bf2645bc0fd);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/number/number.html"), 0x169388ffc21e3728);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/prime/mersenne.html"), 0xf68aac9e396d8224);
+        assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/prime/mersenne.html#largest"), 0x8e87d7e7472b3883);
+        assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/corpspeak.cgi"), 0x295c26caa8b423de);
+        assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/haiku.cgi"), 0x322c814292e72176);
+        assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/rand-none.cgi"), 0x8a06550eb8af7268);
+        assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/randdist.cgi"), 0xef86d60e661bcf71);
+        assert_eq!(fnv1a(b"http://www.lavarnd.org/index.html"), 0x9e5426c87f30ee54);
+        assert_eq!(fnv1a(b"http://www.lavarnd.org/what/nist-test.html"), 0xf1ea8aa826fd047e);
+        assert_eq!(fnv1a(b"http://www.macosxhints.com/"), 0x0babaf9a642cb769);
+        assert_eq!(fnv1a(b"http://www.mellis.com/"), 0x4b3341d4068d012e);
+        assert_eq!(fnv1a(b"http://www.nature.nps.gov/air/webcams/parks/havoso2alert/havoalert.cfm"), 0xd15605cbc30a335c);
+        assert_eq!(fnv1a(b"http://www.nature.nps.gov/air/webcams/parks/havoso2alert/timelines_24.cfm"), 0x5b21060aed8412e5);
+        assert_eq!(fnv1a(b"http://www.paulnoll.com/"), 0x45e2cda1ce6f4227);
+        assert_eq!(fnv1a(b"http://www.pepysdiary.com/"), 0x50ae3745033ad7d4);
+        assert_eq!(fnv1a(b"http://www.sciencenews.org/index/home/activity/view"), 0xaa4588ced46bf414);
+        assert_eq!(fnv1a(b"http://www.skyandtelescope.com/"), 0xc1b0056c4a95467e);
+        assert_eq!(fnv1a(b"http://www.sput.nl/~rob/sirius.html"), 0x56576a71de8b4089);
+        assert_eq!(fnv1a(b"http://www.systemexperts.com/"), 0xbf20965fa6dc927e);
+        assert_eq!(fnv1a(b"http://www.tq-international.com/phpBB3/index.php"), 0x569f8383c2040882);
+        assert_eq!(fnv1a(b"http://www.travelquesttours.com/index.htm"), 0xe1e772fba08feca0);
+        assert_eq!(fnv1a(b"http://www.wunderground.com/global/stations/89606.html"), 0x4ced94af97138ac4);
+        assert_eq!(fnv1a(&repeat_10(b"21701")), 0xc4112ffb337a82fb);
+        assert_eq!(fnv1a(&repeat_10(b"M21701")), 0xd64a4fd41de38b7d);
+        assert_eq!(fnv1a(&repeat_10(b"2^21701-1")), 0x4cfc32329edebcbb);
+        assert_eq!(fnv1a(&repeat_10(b"\x54\xc5")), 0x0803564445050395);
+        assert_eq!(fnv1a(&repeat_10(b"\xc5\x54")), 0xaa1574ecf4642ffd);
+        assert_eq!(fnv1a(&repeat_10(b"23209")), 0x694bc4e54cc315f9);
+        assert_eq!(fnv1a(&repeat_10(b"M23209")), 0xa3d7cb273b011721);
+        assert_eq!(fnv1a(&repeat_10(b"2^23209-1")), 0x577c2f8b6115bfa5);
+        assert_eq!(fnv1a(&repeat_10(b"\x5a\xa9")), 0xb7ec8c1a769fb4c1);
+        assert_eq!(fnv1a(&repeat_10(b"\xa9\x5a")), 0x5d5cfce63359ab19);
+        assert_eq!(fnv1a(&repeat_10(b"391581216093")), 0x33b96c3cd65b5f71);
+        assert_eq!(fnv1a(&repeat_10(b"391581*2^216093-1")), 0xd845097780602bb9);
+        assert_eq!(fnv1a(&repeat_10(b"\x05\xf9\x9d\x03\x4c\x81")), 0x84d47645d02da3d5);
+        assert_eq!(fnv1a(&repeat_10(b"FEDCBA9876543210")), 0x83544f33b58773a5);
+        assert_eq!(fnv1a(&repeat_10(b"\xfe\xdc\xba\x98\x76\x54\x32\x10")), 0x9175cbb2160836c5);
+        assert_eq!(fnv1a(&repeat_10(b"EFCDAB8967452301")), 0xc71b3bc175e72bc5);
+        assert_eq!(fnv1a(&repeat_10(b"\xef\xcd\xab\x89\x67\x45\x23\x01")), 0x636806ac222ec985);
+        assert_eq!(fnv1a(&repeat_10(b"0123456789ABCDEF")), 0xb6ef0e6950f52ed5);
+        assert_eq!(fnv1a(&repeat_10(b"\x01\x23\x45\x67\x89\xab\xcd\xef")), 0xead3d8a0f3dfdaa5);
+        assert_eq!(fnv1a(&repeat_10(b"1032547698BADCFE")), 0x922908fe9a861ba5);
+        assert_eq!(fnv1a(&repeat_10(b"\x10\x32\x54\x76\x98\xba\xdc\xfe")), 0x6d4821de275fd5c5);
+        assert_eq!(fnv1a(&repeat_500(b"\x00")), 0x1fe3fce62bd816b5);
+        assert_eq!(fnv1a(&repeat_500(b"\x07")), 0xc23e9fccd6f70591);
+        assert_eq!(fnv1a(&repeat_500(b"~")), 0xc1af12bdfe16b5b5);
+        assert_eq!(fnv1a(&repeat_500(b"\x7f")), 0x39e9f18f2f85e221);
+    }
+}
diff --git a/third_party/rust-fnv/x86_64-unknown-linux-sgx.json b/third_party/rust-fnv/x86_64-unknown-linux-sgx.json
new file mode 100644
index 0000000..6cbb524
--- /dev/null
+++ b/third_party/rust-fnv/x86_64-unknown-linux-sgx.json
@@ -0,0 +1,31 @@
+{
+  "arch": "x86_64",
+  "cpu": "x86-64",
+  "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
+  "dynamic-linking": true,
+  "env": "sgx",
+  "exe-allocation-crate": "alloc_system",
+  "executables": true,
+  "has-elf-tls": true,
+  "has-rpath": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-unknown-linux-gnu",
+  "max-atomic-width": 64,
+  "os": "linux",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relro-level": "full",
+  "stack-probes": true,
+  "target-c-int-width": "32",
+  "target-endian": "little",
+  "target-family": "unix",
+  "target-pointer-width": "64",
+  "vendor": "unknown"
+}
diff --git a/third_party/rust-threshold-secret-sharing/Cargo.toml b/third_party/rust-threshold-secret-sharing/Cargo.toml
index f014e46..9792b83 100644
--- a/third_party/rust-threshold-secret-sharing/Cargo.toml
+++ b/third_party/rust-threshold-secret-sharing/Cargo.toml
@@ -26,9 +26,9 @@
 
 [target.'cfg(not(target_env = "sgx"))'.dependencies]
 sgx_tstd = { path = "../../sgx_tstd" }
+sgx_rand = { path = "../../sgx_rand" }
 
 [dependencies]
-sgx_rand = { path = "../../sgx_rand" }
 primal = { version = "0.2", optional = true }
 
 [dev-dependencies]
diff --git a/third_party/rust-threshold-secret-sharing/src/fields/fft.rs b/third_party/rust-threshold-secret-sharing/src/fields/fft.rs
index 31a4132..a48157a 100644
--- a/third_party/rust-threshold-secret-sharing/src/fields/fft.rs
+++ b/third_party/rust-threshold-secret-sharing/src/fields/fft.rs
@@ -114,7 +114,7 @@
 
 fn fft3_in_place_compute<F: Field>(zp: &F, data: &mut [F::U], omega: F::U) {
     let mut step = 1;
-    let big_omega = zp.qpow(omega, (data.len() as u32 / 3));
+    let big_omega = zp.qpow(omega, data.len() as u32 / 3);
     let big_omega_sq = zp.mul(big_omega, big_omega);
     while step < data.len() {
         let jump = 3 * step;
diff --git a/third_party/rust-threshold-secret-sharing/src/fields/mod.rs b/third_party/rust-threshold-secret-sharing/src/fields/mod.rs
index ac913d7..5b02e16 100644
--- a/third_party/rust-threshold-secret-sharing/src/fields/mod.rs
+++ b/third_party/rust-threshold-secret-sharing/src/fields/mod.rs
@@ -95,6 +95,7 @@
     }
 }
 
+#[allow(unused_macros)]
 macro_rules! all_fields_test {
     ($field:ty) => {
         #[test] fn test_convert() { ::fields::test::test_convert::<$field>(); }
diff --git a/third_party/rust-threshold-secret-sharing/src/fields/montgomery.rs b/third_party/rust-threshold-secret-sharing/src/fields/montgomery.rs
index 6b8cd59..decd744 100644
--- a/third_party/rust-threshold-secret-sharing/src/fields/montgomery.rs
+++ b/third_party/rust-threshold-secret-sharing/src/fields/montgomery.rs
@@ -58,7 +58,7 @@
     fn redc(&self, a: u64) -> Value {
         let m: u64 = (a as u32).wrapping_mul(self.n_quote) as u64;
         let t: u32 = ((a + m * (self.n as u64)) >> 32) as u32;
-        Value((if t >= (self.n) { t - (self.n) } else { t }))
+        Value(if t >= (self.n) { t - self.n } else { t })
     }
 }
 
diff --git a/third_party/rust-threshold-secret-sharing/src/lib.rs b/third_party/rust-threshold-secret-sharing/src/lib.rs
index ed9d9f4..5ca69f9 100644
--- a/third_party/rust-threshold-secret-sharing/src/lib.rs
+++ b/third_party/rust-threshold-secret-sharing/src/lib.rs
@@ -12,12 +12,18 @@
 //! traditional Shamir sharing and its packet (or ramp) variant.
 //! For now, secrets and shares are fixed as prime field elements
 //! represented by `i64` values.
-#![no_std]
 
-extern crate sgx_rand as rand;
+#![cfg_attr(not(target_env = "sgx"), no_std)]
+#![cfg_attr(target_env = "sgx", feature(rustc_private))]
+
+#![feature(slice_concat_ext)]
+
+#[cfg(not(target_env = "sgx"))]
 #[macro_use]
 extern crate sgx_tstd as std;
 
+extern crate sgx_rand as rand;
+
 mod fields;
 mod numtheory;
 pub use numtheory::positivise;
diff --git a/third_party/serde-rs/json/Cargo.toml b/third_party/serde-rs/json/Cargo.toml
index 828e6a8..64ba101 100644
--- a/third_party/serde-rs/json/Cargo.toml
+++ b/third_party/serde-rs/json/Cargo.toml
@@ -20,9 +20,9 @@
 
 [dependencies]
 serde = { version = "1.0", path = "../serde/serde" }
-num-traits = { version = "0.1.32", path = "../../num/traits" }
+num-traits = { path = "../../num/traits" }
 linked-hash-map = { version = "0.5", path = "../../linked-hash-map", optional = true }
-itoa = { version = "0.3", path = "../../itoa" }
+itoa = { version = "0.4", path = "../../itoa" }
 dtoa = { version = "0.4", path = "../../dtoa" }
 
 [dev-dependencies]