From e4826c62dfeed52ae0cc82b012cdf77a054a474b Mon Sep 17 00:00:00 2001 From: Artemis Tosini Date: Sat, 13 Jul 2024 21:36:33 +0000 Subject: [PATCH] add nix_hash --- rust/nix_hash/Cargo.lock | 16 ++++++++++ rust/nix_hash/Cargo.toml | 7 +++++ rust/nix_hash/src/main.rs | 64 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 rust/nix_hash/Cargo.lock create mode 100644 rust/nix_hash/Cargo.toml create mode 100644 rust/nix_hash/src/main.rs diff --git a/rust/nix_hash/Cargo.lock b/rust/nix_hash/Cargo.lock new file mode 100644 index 0000000..9690c79 --- /dev/null +++ b/rust/nix_hash/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "nix_hash" +version = "0.1.0" +dependencies = [ + "data-encoding", +] diff --git a/rust/nix_hash/Cargo.toml b/rust/nix_hash/Cargo.toml new file mode 100644 index 0000000..8d163a7 --- /dev/null +++ b/rust/nix_hash/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "nix_hash" +version = "0.1.0" +edition = "2021" + +[dependencies] +data-encoding = "2.6.0" diff --git a/rust/nix_hash/src/main.rs b/rust/nix_hash/src/main.rs new file mode 100644 index 0000000..b197658 --- /dev/null +++ b/rust/nix_hash/src/main.rs @@ -0,0 +1,64 @@ +use data_encoding::BitOrder; + +fn main() -> Result<(), Box> { + let mut binary = data_encoding::HEXLOWER + .decode(b"3a99595f4daedd5f52d646e413ea1c989abb910cd2ea18fd98ccddeab68f0883")?; + + let mut spec = data_encoding::Specification::new(); + spec.symbols.push_str("0123456789abcdfghijklmnpqrsvwxyz"); + spec.bit_order = BitOrder::LeastSignificantFirst; + + println!( + "Found: {}", + spec.encoding()? + .encode(&binary) + .chars() + .rev() + .collect::() + ); + println!("Expected: 10q8iyvfmpfck3yiisnj1j8vp6lq3km17r26sr95zpdf9mgmk69s"); + println!("Found: {}", encode_nix32(&binary)); + + Ok(()) +} + +static NIX32_CHARS: &[u8; 32] = b"0123456789abcdfghijklmnpqrsvwxyz"; + +fn encode_nix32(input: &[u8]) -> String { + let length = if input.len() == 0 { + 0 + } else { + // ceil(input.len() * 8 / 5) + (input.len() * 8 - 1) / 5 + 1 + }; + let mut output = String::with_capacity(length); + + // nix32 hashes feel like they're a bug that stuck + // The output is backwards and bits are grouped + // from the least significant bit in each byte + // instead of the most significant bit. + // e.g. encoding "Meow" gives us: + // Char: M (0x4d) e (0x65) o (0x6f) w (0x77) + // Value: 0 1 0 0 1 1 0 1 | 0 1 1 0 0 1 0 1 | 0 1 1 0 1 1 1 1 | 0 1 1 1 0 1 1 1 + // Out No.: 5 5 5 6 6 6 6 6 | 3 4 4 4 4 4 5 5 | 2 2 2 2 3 3 3 3 | 0 0 1 1 1 1 1 2 + // Out Bit: 2 1 0 4 3 2 1 0 | 0 5 4 3 2 1 4 3 | 3 2 1 0 4 3 2 1 | 1 0 4 3 2 1 0 4 + // + // where "Out No." is the index of the output charater responsible for a given bit, + // and 2**"Out Bit" is the value of a given bit for its output character. + // + // In this example, characters 0 to 6 have values + // 0x01, 0x1b, 0x16, 0x1e, 0x19, 0xa, 0xd. + // Indexing into the alphabet gives us "1vnyrad" + + for char_no in 0..length { + let bit_no = (length - char_no - 1) * 5; + let byte_no = bit_no / 8; + let offset = bit_no % 8; + + let next_byte = input.get(byte_no + 1).unwrap_or(&0); + let value = (input[byte_no] as u16 >> offset) | ((*next_byte as u16) << (8 - offset)); + output.push(NIX32_CHARS[(value & 0x1f) as usize] as char); + } + + output +}