From 62138fd9a43a2d5ce6a90f31ab13a1ea0be8b2de Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Tue, 1 Aug 2023 23:27:47 +0200 Subject: [PATCH] First commit. The hashes and their inverses. --- .gitignore | 2 ++ Cargo.toml | 8 +++++ src/lib.rs | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a6c0ab3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "bit_mixers" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8526767 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,101 @@ +/// 32-bit bijective bit mixer. +/// +/// https://github.com/skeeto/hash-prospector +pub fn mix32(mut n: u32) -> u32 { + n ^= n >> 16; + n = n.wrapping_mul(0x21f0aaad); + n ^= n >> 15; + n = n.wrapping_mul(0xd35a2d97); + n ^= n >> 15; + + n +} + +/// Inverse of `mix32()`. +pub fn mix32_inv(mut n: u32) -> u32 { + n ^= (n >> 15) ^ (n >> 30); + n = n.wrapping_mul(0x37132227); + n ^= (n >> 15) ^ (n >> 30); + n = n.wrapping_mul(0x333c4925); + n ^= n >> 16; + + n +} + +/// 64-bit bijective bit mixer. +/// +/// http://zimbry.blogspot.ch/2011/09/better-bit-mixing-improving-on.html +pub fn mix64(mut n: u64) -> u64 { + n ^= n >> 31; + n = n.wrapping_mul(0x7fb5d329728ea185); + n ^= n >> 27; + n = n.wrapping_mul(0x81dadef4bc2dd44d); + n ^= n >> 33; + + n +} + +/// Inverse of `mix64()`. +pub fn mix64_inv(mut n: u64) -> u64 { + n ^= n >> 33; + n = n.wrapping_mul(0x4d6dff26c61d8485); + n ^= (n >> 27) ^ (n >> 54); + n = n.wrapping_mul(0x4c5ff4596f4a2f4d); + n ^= (n >> 31) ^ (n >> 62); + + n +} + +#[cfg(test)] +mod tests { + use super::*; + + // fn compute_multiplicative_inverse_32(a: u32) -> u32 { + // assert!(a & 1 == 1); + // let mut x = a; + // // Overkill iteration count. + // for _ in 0..100 { + // // x += x - a * x * x; + // x = x.wrapping_add(x.wrapping_sub(a.wrapping_mul(x).wrapping_mul(x))); + // } + + // x + // } + + // fn compute_multiplicative_inverse_64(a: u64) -> u64 { + // assert!(a & 1 == 1); + // let mut x = a; + // // Overkill iteration count. + // for _ in 0..100 { + // // x += x - a * x * x; + // x = x.wrapping_add(x.wrapping_sub(a.wrapping_mul(x).wrapping_mul(x))); + // } + + // x + // } + + // #[test] + // fn get_inverse() { + // // Panic, to print the result. + // panic!("0x{:x}", compute_multiplicative_inverse_32(0x21f0aaad)); + // panic!("0x{:x}", compute_multiplicative_inverse_32(0xd35a2d97)); + // } + + #[test] + fn mix32_invertability() { + for i in 0..9999999u32 { + let n = mix32(mix32(mix32(i))); + assert_eq!(n, mix32_inv(mix32(n))); + assert_eq!(n, mix32(mix32_inv(n))); + } + } + + #[test] + fn mix64_invertability() { + for i in 0..9999999u64 { + let n = mix64(mix64(mix64(i))); + assert_eq!(n, mix64_inv(mix64(n))); + assert_eq!(n, mix64(mix64_inv(n))); + } + } +}