Snap for 8249732 from 1319627187e18db41095e680e6d8eaba75753fdd to tm-release

Change-Id: I4228cde3b496d4f4a4b4528a65b071ed582c8931
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index a2c6e68..832d476 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "ffa04fcb81f39755f636c75c9b7aa06533c0ae75"
+    "sha1": "e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4"
   }
 }
diff --git a/Android.bp b/Android.bp
index 27d6b4c..9e1253a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -43,7 +43,7 @@
     host_supported: true,
     crate_name: "ahash",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.7.4",
+    cargo_pkg_version: "0.7.6",
     srcs: ["src/lib.rs"],
     edition: "2018",
     arch: {
diff --git a/Cargo.toml b/Cargo.toml
index d39374c..b412f79 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,10 +13,10 @@
 [package]
 edition = "2018"
 name = "ahash"
-version = "0.7.4"
+version = "0.7.6"
 authors = ["Tom Kaitchuck <Tom.Kaitchuck@gmail.com>"]
 build = "./build.rs"
-exclude = ["/smhasher"]
+exclude = ["/smhasher", "/benchmark_tools"]
 description = "A non-cryptographic hash function using AES-NI for high performance"
 documentation = "https://docs.rs/ahash"
 readme = "README.md"
@@ -98,16 +98,15 @@
 optional = true
 
 [target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.getrandom]
-version = "0.2.0"
-
-[target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.once_cell]
-version = "1.5.2"
-features = ["unstable", "alloc"]
-default-features = false
+version = "0.2.3"
 
 [target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.serde]
 version = "1.0.117"
 optional = true
+[target."cfg(not(all(target_arch = \"arm\", target_os = \"none\")))".dependencies.once_cell]
+version = "1.8"
+features = ["alloc"]
+default-features = false
 [target."cfg(not(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\")))".dependencies.const-random]
 version = "0.1.12"
 optional = true
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 1b3e831..4b56472 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "ahash"
-version = "0.7.4"
+version = "0.7.6"
 authors = ["Tom Kaitchuck <Tom.Kaitchuck@gmail.com>"]
 license = "MIT OR Apache-2.0"
 description = "A non-cryptographic hash function using AES-NI for high performance"
@@ -11,7 +11,7 @@
 edition = "2018"
 readme = "README.md"
 build = "./build.rs"
-exclude = ["/smhasher"]
+exclude = ["/smhasher", "/benchmark_tools"]
 
 [lib]
 name = "ahash"
@@ -65,8 +65,7 @@
 version_check = "0.9"
 
 [target.'cfg(any(target_os = "linux", target_os = "android", target_os = "windows", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly", target_os = "solaris", target_os = "illumos", target_os = "fuchsia", target_os = "redox", target_os = "cloudabi", target_os = "haiku", target_os = "vxworks", target_os = "emscripten", target_os = "wasi"))'.dependencies]
-once_cell = { version = "1.5.2", default-features = false, features = ["unstable", "alloc"] }
-getrandom = { version = "0.2.0" }
+getrandom = { version = "0.2.3" }
 const-random = { version = "0.1.12", optional = true }
 serde = { version = "1.0.117", optional = true }
 
@@ -74,6 +73,9 @@
 const-random = { version = "0.1.12", optional = true }
 serde = { version = "1.0.117", optional = true }
 
+[target.'cfg(not(all(target_arch = "arm", target_os = "none")))'.dependencies]
+once_cell = { version = "1.8", default-features = false, features = ["alloc"] }
+
 [dev-dependencies]
 no-panic = "0.1.10"
 criterion = {version =  "0.3.2"}
diff --git a/METADATA b/METADATA
index 7738498..7ee2368 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/ahash/ahash-0.7.4.crate"
+    value: "https://static.crates.io/crates/ahash/ahash-0.7.6.crate"
   }
-  version: "0.7.4"
+  version: "0.7.6"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2021
-    month: 6
-    day: 14
+    year: 2022
+    month: 2
+    day: 28
   }
 }
diff --git a/build.rs b/build.rs
index 118c250..8be4964 100644
--- a/build.rs
+++ b/build.rs
@@ -7,6 +7,7 @@
     if let Some(channel) = version_check::Channel::read() {
         if channel.supports_features() {
             println!("cargo:rustc-cfg=feature=\"specialize\"");
+            println!("cargo:rustc-cfg=feature=\"stdsimd\"");
         }
     }
     let os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set");
diff --git a/patches/0001-Use-dev-urandom-instead-of-getrandom.patch b/patches/0001-Use-dev-urandom-instead-of-getrandom.patch
index fba802c..c5f4df3 100644
--- a/patches/0001-Use-dev-urandom-instead-of-getrandom.patch
+++ b/patches/0001-Use-dev-urandom-instead-of-getrandom.patch
@@ -17,12 +17,12 @@
 Change-Id: Ie81a1f3a893d578348db11aee114d1a8f2d9fac5
 ---
 diff --git a/src/random_state.rs b/src/random_state.rs
-index f394cd0..d8280b7 100644
+index c3628bf..835467c 100644
 --- a/src/random_state.rs
 +++ b/src/random_state.rs
-@@ -34,6 +34,15 @@ use crate::aes_hash::*;
- #[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
- use crate::fallback_hash::*;
+@@ -48,6 +48,15 @@ use crate::fallback_hash::*;
+ #[cfg(not(all(target_arch = "arm", target_os = "none")))]
+ static RAND_SOURCE: OnceBox<Box<dyn RandomSource + Send + Sync>> = OnceBox::new();
  
 +#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
 +fn read_urandom(dest: &mut [u8]) -> Result<(), std::io::Error> {
@@ -33,28 +33,17 @@
 +    f.read_exact(dest)
 +}
 +
- #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
- static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new();
+ /// A supplier of Randomness used for different hashers.
+ /// See [RandomState.set_random_source].
+ pub trait RandomSource {
+@@ -98,7 +107,9 @@ impl RandomSource for DefaultRandomSource {
  
-@@ -59,7 +68,9 @@ pub(crate) fn seeds() -> [u64; 4] {
-     {
          SEEDS.get_or_init(|| {
              let mut result: [u8; 64] = [0; 64];
 -            getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
 +            if read_urandom(&mut result).is_err() {
-+                getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.")
++                getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
 +            }
              Box::new(result.convert())
-         })[1]
+         })
      }
-@@ -107,7 +118,9 @@ impl RandomState {
-         {
-             let seeds = SEEDS.get_or_init(|| {
-                 let mut result: [u8; 64] = [0; 64];
--                getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
-+                if read_urandom(&mut result).is_err() {
-+                    getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.")
-+                }
-                 Box::new(result.convert())
-             });
-             RandomState::from_keys(seeds[0], seeds[1])
diff --git a/src/aes_hash.rs b/src/aes_hash.rs
index 3698c4e..1c98582 100644
--- a/src/aes_hash.rs
+++ b/src/aes_hash.rs
@@ -230,13 +230,13 @@
 impl Hasher for AHasherU64 {
     #[inline]
     fn finish(&self) -> u64 {
-        let rot = (self.pad & 64) as u32;
+        let rot = (self.pad & 63) as u32;
         self.buffer.rotate_left(rot)
     }
 
     #[inline]
     fn write(&mut self, _bytes: &[u8]) {
-        unreachable!("This should never be called")
+        unreachable!("Specialized hasher was called with a different type of object")
     }
 
     #[inline]
@@ -261,12 +261,12 @@
 
     #[inline]
     fn write_u128(&mut self, _i: u128) {
-        unreachable!("This should never be called")
+        unreachable!("Specialized hasher was called with a different type of object")
     }
 
     #[inline]
     fn write_usize(&mut self, _i: usize) {
-        unimplemented!()
+        unreachable!("Specialized hasher was called with a different type of object")
     }
 }
 
diff --git a/src/convert.rs b/src/convert.rs
index 1bacb82..4c0a00e 100644
--- a/src/convert.rs
+++ b/src/convert.rs
@@ -8,13 +8,7 @@
             #[inline(always)]
             fn convert(self) -> $b {
                 unsafe {
-                    let mut result: $b = core::mem::zeroed();
-                    core::ptr::copy_nonoverlapping(
-                        &self as *const $a as *const u8,
-                        &mut result as *mut $b as *mut u8,
-                        core::mem::size_of::<$b>(),
-                    );
-                    return result;
+                    core::mem::transmute::<$a, $b>(self)
                 }
             }
         }
@@ -22,13 +16,7 @@
             #[inline(always)]
             fn convert(self) -> $a {
                 unsafe {
-                    let mut result: $a = core::mem::zeroed();
-                    core::ptr::copy_nonoverlapping(
-                        &self as *const $b as *const u8,
-                        &mut result as *mut $a as *mut u8,
-                        core::mem::size_of::<$a>(),
-                    );
-                    return result;
+                    core::mem::transmute::<$b, $a>(self)
                 }
             }
         }
diff --git a/src/fallback_hash.rs b/src/fallback_hash.rs
index 372debc..aad9efc 100644
--- a/src/fallback_hash.rs
+++ b/src/fallback_hash.rs
@@ -233,13 +233,13 @@
 impl Hasher for AHasherU64 {
     #[inline]
     fn finish(&self) -> u64 {
-        let rot = (self.pad & 64) as u32;
+        let rot = (self.pad & 63) as u32;
         self.buffer.rotate_left(rot)
     }
 
     #[inline]
     fn write(&mut self, _bytes: &[u8]) {
-        unreachable!("This should never be called")
+        unreachable!("Specialized hasher was called with a different type of object")
     }
 
     #[inline]
@@ -264,12 +264,12 @@
 
     #[inline]
     fn write_u128(&mut self, _i: u128) {
-        unreachable!("This should never be called")
+        unreachable!("Specialized hasher was called with a different type of object")
     }
 
     #[inline]
     fn write_usize(&mut self, _i: usize) {
-        unimplemented!()
+        unreachable!("Specialized hasher was called with a different type of object")
     }
 }
 
diff --git a/src/hash_quality_test.rs b/src/hash_quality_test.rs
index 837924d..4cd3156 100644
--- a/src/hash_quality_test.rs
+++ b/src/hash_quality_test.rs
@@ -316,6 +316,16 @@
     }
 }
 
+fn test_length_extension<T: Hasher>(hasher: impl Fn(u128, u128) -> T) {
+    for key in 0..256 {
+        let h1 = hasher(key, key);
+        let v1 = hash_with(&[0_u8, 0, 0, 0, 0, 0, 0, 0], h1);
+        let h2 = hasher(key, key);
+        let v2 = hash_with(&[1_u8, 0, 0, 0, 0, 0, 0, 0, 0], h2);
+        assert_ne!(v1, v2);
+    }
+}
+
 #[cfg(test)]
 mod fallback_tests {
     use crate::fallback_hash::*;
@@ -377,10 +387,18 @@
         test_padding_doesnot_collide(|| AHasher::new_with_keys(2, 0));
         test_padding_doesnot_collide(|| AHasher::new_with_keys(2, 2));
     }
+
+    #[test]
+    fn fallback_length_extension() {
+        test_length_extension(|a, b| AHasher::new_with_keys(a, b));
+    }
 }
 
 ///Basic sanity tests of the cypto properties of aHash.
-#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
+#[cfg(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+))]
 #[cfg(test)]
 mod aes_tests {
     use crate::aes_hash::*;
@@ -457,4 +475,9 @@
         test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
         test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
     }
+
+    #[test]
+    fn aes_length_extension() {
+        test_length_extension(|a, b| AHasher::test_with_keys(a, b));
+    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 4ee1ac6..9964a7c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -30,11 +30,15 @@
 #![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)]
 #![cfg_attr(all(not(test), not(feature = "std")), no_std)]
 #![cfg_attr(feature = "specialize", feature(min_specialization))]
+#![cfg_attr(feature = "stdsimd", feature(stdsimd))]
 
 #[macro_use]
 mod convert;
 
-#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
+#[cfg(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+))]
 mod aes_hash;
 mod fallback_hash;
 #[cfg(test)]
@@ -48,10 +52,16 @@
 mod random_state;
 mod specialize;
 
-#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
+#[cfg(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+))]
 pub use crate::aes_hash::AHasher;
 
-#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
+#[cfg(not(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+)))]
 pub use crate::fallback_hash::AHasher;
 pub use crate::random_state::RandomState;
 
diff --git a/src/operations.rs b/src/operations.rs
index 2071d6b..b71fd5a 100644
--- a/src/operations.rs
+++ b/src/operations.rs
@@ -100,6 +100,22 @@
         transmute(_mm_aesenc_si128(value, transmute(xor)))
     }
 }
+
+#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))]
+#[allow(unused)]
+#[inline(always)]
+pub(crate) fn aesenc(value: u128, xor: u128) -> u128 {
+    #[cfg(target_arch = "arm")]
+    use core::arch::arm::*;
+    #[cfg(target_arch = "aarch64")]
+    use core::arch::aarch64::*;
+    use core::mem::transmute;
+    unsafe {
+        let value = transmute(value);
+        transmute(vaesmcq_u8(vaeseq_u8(value, transmute(xor))))
+    }
+}
+
 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
 #[allow(unused)]
 #[inline(always)]
@@ -115,6 +131,21 @@
     }
 }
 
+#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))]
+#[allow(unused)]
+#[inline(always)]
+pub(crate) fn aesdec(value: u128, xor: u128) -> u128 {
+    #[cfg(target_arch = "arm")]
+    use core::arch::arm::*;
+    #[cfg(target_arch = "aarch64")]
+    use core::arch::aarch64::*;
+    use core::mem::transmute;
+    unsafe {
+        let value = transmute(value);
+        transmute(vaesimcq_u8(vaesdq_u8(value, transmute(xor))))
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/src/random_state.rs b/src/random_state.rs
index d8280b7..835467c 100644
--- a/src/random_state.rs
+++ b/src/random_state.rs
@@ -3,14 +3,21 @@
 #[cfg(feature = "specialize")]
 use crate::BuildHasherExt;
 
-#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
+#[cfg(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+))]
 pub use crate::aes_hash::*;
 
-#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
+#[cfg(not(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+)))]
 pub use crate::fallback_hash::*;
 
 #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
 use const_random::const_random;
+use core::any::{Any, TypeId};
 use core::fmt;
 use core::hash::BuildHasher;
 #[cfg(feature = "specialize")]
@@ -22,18 +29,25 @@
 #[cfg(feature = "std")]
 extern crate std as alloc;
 
-
-#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
 use alloc::boxed::Box;
 use core::sync::atomic::{AtomicUsize, Ordering};
-#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
+#[cfg(not(all(target_arch = "arm", target_os = "none")))]
 use once_cell::race::OnceBox;
 
-#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
+#[cfg(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+))]
 use crate::aes_hash::*;
-#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
+#[cfg(not(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+)))]
 use crate::fallback_hash::*;
 
+#[cfg(not(all(target_arch = "arm", target_os = "none")))]
+static RAND_SOURCE: OnceBox<Box<dyn RandomSource + Send + Sync>> = OnceBox::new();
+
 #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
 fn read_urandom(dest: &mut [u8]) -> Result<(), std::io::Error> {
     use std::fs::File;
@@ -43,10 +57,15 @@
     f.read_exact(dest)
 }
 
-#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
-static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new();
+/// A supplier of Randomness used for different hashers.
+/// See [RandomState.set_random_source].
+pub trait RandomSource {
 
-static COUNTER: AtomicUsize = AtomicUsize::new(0);
+    fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2];
+
+    fn gen_hasher_seed(&self) -> usize;
+
+}
 
 pub(crate) const PI: [u64; 4] = [
     0x243f_6a88_85a3_08d3,
@@ -62,30 +81,75 @@
     0x3f84_d5b5_b547_0917,
 ];
 
-#[inline]
-pub(crate) fn seeds() -> [u64; 4] {
+struct DefaultRandomSource {
+    counter: AtomicUsize,
+}
+
+impl DefaultRandomSource {
+    fn new() -> DefaultRandomSource {
+        DefaultRandomSource {
+            counter: AtomicUsize::new(&PI as *const _ as usize),
+        }
+    }
+
+    const fn default() -> DefaultRandomSource {
+        DefaultRandomSource {
+            counter: AtomicUsize::new(PI[3] as usize),
+        }
+    }
+}
+
+impl RandomSource for DefaultRandomSource {
+
     #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
-    {
+    fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] {
+        static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new();
+
         SEEDS.get_or_init(|| {
             let mut result: [u8; 64] = [0; 64];
             if read_urandom(&mut result).is_err() {
-                getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.")
+                getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
             }
             Box::new(result.convert())
-        })[1]
+        })
     }
+
     #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
-    {
-        [
-            const_random!(u64),
-            const_random!(u64),
-            const_random!(u64),
-            const_random!(u64),
-        ]
+    fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] {
+        const RAND: [[u64; 4]; 2] = [
+            [
+                const_random!(u64),
+                const_random!(u64),
+                const_random!(u64),
+                const_random!(u64),
+            ], [
+                const_random!(u64),
+                const_random!(u64),
+                const_random!(u64),
+                const_random!(u64),
+            ]
+        ];
+        &RAND
     }
+
     #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
-    {
-        PI
+    fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] {
+        &[PI, PI2]
+    }
+
+    #[cfg(not(all(target_arch = "arm", target_os = "none")))]
+    fn gen_hasher_seed(&self) -> usize {
+        let stack = self as *const _ as usize;
+        self.counter.fetch_add(stack, Ordering::Relaxed)
+    }
+
+    #[cfg(all(target_arch = "arm", target_os = "none"))]
+    fn gen_hasher_seed(&self) -> usize {
+        let stack = self as *const _ as usize;
+        let previous = self.counter.load(Ordering::Relaxed);
+        let new = previous.wrapping_add(stack);
+        self.counter.store(new, Ordering::Relaxed);
+        new
     }
 }
 
@@ -111,74 +175,59 @@
 }
 
 impl RandomState {
+
+    /// Provides an optional way to manually supply a source of randomness for Hasher keys.
+    ///
+    /// The provided [RandomSource] will be used to be used as a source of randomness by [RandomState] to generate new states.
+    /// If this method is not invoked the standard source of randomness is used as described in the Readme.
+    ///
+    /// The source of randomness can only be set once, and must be set before the first RandomState is created.
+    /// If the source has already been specified `Err` is returned with a `bool` indicating if the set failed because
+    /// method was previously invoked (true) or if the default source is already being used (false).
+    #[cfg(not(all(target_arch = "arm", target_os = "none")))]
+    pub fn set_random_source(source: impl RandomSource + Send + Sync + 'static) -> Result<(), bool> {
+        RAND_SOURCE.set(Box::new(Box::new(source))).map_err(|s| s.as_ref().type_id() != TypeId::of::<&DefaultRandomSource>())
+    }
+
+    #[inline]
+    #[cfg(not(all(target_arch = "arm", target_os = "none")))]
+    fn get_src() -> &'static dyn RandomSource {
+        RAND_SOURCE.get_or_init(|| Box::new(Box::new(DefaultRandomSource::new()))).as_ref()
+    }
+
+    #[inline]
+    #[cfg(all(target_arch = "arm", target_os = "none"))]
+    fn get_src() -> &'static dyn RandomSource {
+        static RAND_SOURCE: DefaultRandomSource = DefaultRandomSource::default();
+        &RAND_SOURCE
+    }
+
     /// Use randomly generated keys
     #[inline]
     pub fn new() -> RandomState {
-        #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
-        {
-            let seeds = SEEDS.get_or_init(|| {
-                let mut result: [u8; 64] = [0; 64];
-                if read_urandom(&mut result).is_err() {
-                    getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.")
-                }
-                Box::new(result.convert())
-            });
-            RandomState::from_keys(seeds[0], seeds[1])
-        }
-        #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
-        {
-            RandomState::from_keys(
-                [
-                    const_random!(u64),
-                    const_random!(u64),
-                    const_random!(u64),
-                    const_random!(u64),
-                ],
-                [
-                    const_random!(u64),
-                    const_random!(u64),
-                    const_random!(u64),
-                    const_random!(u64),
-                ],
-            )
-        }
-        #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
-        {
-            RandomState::from_keys(PI, PI2)
-        }
+        let src = Self::get_src();
+        let fixed = src.get_fixed_seeds();
+        Self::from_keys(&fixed[0], &fixed[1], src.gen_hasher_seed())
     }
 
     /// Allows for supplying seeds, but each time it is called the resulting state will be different.
     /// This is done using a static counter, so it can safely be used with a fixed keys.
     #[inline]
     pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
-        RandomState::from_keys(seeds(), [k0, k1, k2, k3])
+        let src = Self::get_src();
+        let fixed = src.get_fixed_seeds();
+        RandomState::from_keys(&fixed[0], &[k0, k1, k2, k3], src.gen_hasher_seed())
     }
 
-    fn from_keys(a: [u64; 4], b: [u64; 4]) -> RandomState {
-        let [k0, k1, k2, k3] = a;
+    fn from_keys(a: &[u64; 4], b: &[u64; 4], c: usize) -> RandomState {
+        let &[k0, k1, k2, k3] = a;
         let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 });
-
-        let stack_mem_loc = &hasher as *const _ as usize;
-        #[cfg(not(all(target_arch = "arm", target_os = "none")))]
-        {
-            hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
-        }
-        #[cfg(all(target_arch = "arm", target_os = "none"))]
-        {
-            let previous = COUNTER.load(Ordering::Relaxed);
-            let new = previous.wrapping_add(stack_mem_loc);
-            COUNTER.store(new, Ordering::Relaxed);
-            hasher.write_usize(new);
-        }
-        #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
-        hasher.write_usize(&PI as *const _ as usize);
+        hasher.write_usize(c);
         let mix = |k: u64| {
             let mut h = hasher.clone();
             h.write_u64(k);
             h.finish()
         };
-
         RandomState {
             k0: mix(b[0]),
             k1: mix(b[1]),
@@ -190,11 +239,23 @@
     /// Internal. Used by Default.
     #[inline]
     pub(crate) fn with_fixed_keys() -> RandomState {
-        let [k0, k1, k2, k3] = seeds();
+        let [k0, k1, k2, k3] = Self::get_src().get_fixed_seeds()[0];
         RandomState { k0, k1, k2, k3 }
     }
 
+    /// Allows for explicitly setting a seed to used.
+    ///
+    /// Note: This method does not require the provided seed to be strong.
+    #[inline]
+    pub fn with_seed(key: usize) -> RandomState {
+        let fixed = Self::get_src().get_fixed_seeds();
+        RandomState::from_keys(&fixed[0], &fixed[1], key)
+    }
+
     /// Allows for explicitly setting the seeds to used.
+    ///
+    /// Note: This method is robust against 0s being passed for one or more of the parameters
+    /// or the same value being passed for more than one parameter.
     #[inline]
     pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
         RandomState { k0: k0 ^ PI2[0], k1: k1 ^ PI2[1], k2: k2 ^ PI2[2], k3: k3 ^ PI2[3] }
@@ -286,19 +347,19 @@
     #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
     #[test]
     fn test_not_pi() {
-        assert_ne!(PI, seeds());
+        assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]);
     }
 
     #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
     #[test]
     fn test_not_pi_const() {
-        assert_ne!(PI, seeds());
+        assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]);
     }
 
     #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
     #[test]
     fn test_pi() {
-        assert_eq!(PI, seeds());
+        assert_eq!(PI, RandomState::get_src().get_fixed_seeds()[0]);
     }
 
     #[test]
diff --git a/src/specialize.rs b/src/specialize.rs
index 7dddb9a..d94a4ee 100644
--- a/src/specialize.rs
+++ b/src/specialize.rs
@@ -25,9 +25,19 @@
 ///
 /// let hash_builder = RandomState::new();
 /// //...
-/// let value = 17;
+/// let value: u32 = 17;
 /// let hash = u32::get_hash(&value, &hash_builder);
 /// ```
+/// Note that the type used to invoke `get_hash` must be the same a the type of value passed.
+/// For example get a hasher specialized on `[u8]` can invoke:
+/// ```
+/// /// use std::hash::BuildHasher;
+/// # use ahash::RandomState;
+/// # use ahash::CallHasher;
+/// # let hash_builder = RandomState::new();
+/// let bytes: [u8; 4] = [1, 2, 3, 4];
+/// let hash = <[u8]>::get_hash(&bytes, &hash_builder);
+/// ```
 pub trait CallHasher {
     fn get_hash<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64;
 }
diff --git a/tests/bench.rs b/tests/bench.rs
index 16904c0..9e6dccc 100644
--- a/tests/bench.rs
+++ b/tests/bench.rs
@@ -4,22 +4,34 @@
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
 
-#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
+#[cfg(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+))]
 fn aeshash<H: Hash>(b: &H) -> u64 {
     let build_hasher = RandomState::with_seeds(1, 2, 3, 4);
     H::get_hash(b, &build_hasher)
 }
-#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
+#[cfg(not(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+)))]
 fn aeshash<H: Hash>(_b: &H) -> u64 {
     panic!("aes must be enabled")
 }
 
-#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
+#[cfg(not(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+)))]
 fn fallbackhash<H: Hash>(b: &H) -> u64 {
     let build_hasher = RandomState::with_seeds(1, 2, 3, 4);
     H::get_hash(b, &build_hasher)
 }
-#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
+#[cfg(any(
+    all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
+    all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
+))]
 fn fallbackhash<H: Hash>(_b: &H) -> u64 {
     panic!("aes must be disabled")
 }