Last active
May 8, 2023 15:36
-
-
Save RoccoDev/8fa130f1946f89702f799f89b8469bc9 to your computer and use it in GitHub Desktop.
Minecraft SHA-1 complement hash calculation in Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (C) 2019 RoccoDev | |
// Licensed under the MIT license. | |
// <https://opensource.org/licenses/MIT> | |
// Bench results: | |
// First hash: 152ms | |
// Second hash: 1ms | |
// Third hash: 0ms | |
extern crate crypto; // Tested with 0.2.36 | |
extern crate num_bigint; // Tested with 0.2 | |
extern crate rustc_serialize; // Tested with ^0.3 | |
extern crate regex; // Tested with 1 | |
use regex::Regex; | |
use crypto::digest::Digest; | |
use crypto::sha1::Sha1; | |
use std::iter; | |
use rustc_serialize::hex::ToHex; | |
const LEADING_ZERO_REGEX: &str = r#"^0+"#; | |
fn calc_hash(name: &str) -> String { | |
let mut hasher = Sha1::new(); | |
hasher.input_str(name); | |
let mut hex: Vec<u8> = iter::repeat(0).take((hasher.output_bits() + 7)/8).collect(); | |
hasher.result(&mut hex); | |
let negative = (hex[0] & 0x80) == 0x80; | |
let regex = Regex::new(LEADING_ZERO_REGEX).unwrap(); | |
if negative { | |
two_complement(&mut hex); | |
format!("-{}", regex.replace(hex.as_slice().to_hex().as_str(), "").to_string()) | |
} | |
else { | |
regex.replace(hex.as_slice().to_hex().as_str(), "").to_string() | |
} | |
} | |
fn two_complement(bytes: &mut Vec<u8>) { | |
let mut carry = true; | |
for i in (0..bytes.len()).rev() { | |
bytes[i] = !bytes[i] & 0xff; | |
if carry { | |
carry = bytes[i] == 0xff; | |
bytes[i] = bytes[i] + 1; | |
} | |
} | |
} | |
mod tests { | |
#[test] | |
pub fn calc_hashes() { | |
assert_eq!("-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1", crate::calc_hash("jeb_")); | |
assert_eq!("4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48", crate::calc_hash("Notch")); | |
assert_eq!("88e16a1019277b15d58faf0541e11910eb756f6", crate::calc_hash("simon")); | |
} | |
} |
Does this still work? For me it says:
function or associated item not found in 'Sha1'
refering toSha1::digest()
Im using rust-crypto 0.2.36 and num-bigint 0.4
Is the Digest
trait in scope?
This might be better...
fn notchian_digest(mut array: [u8; 20]) -> String {
let mut hex;
if array[0] & 0b1000_0000 != 0 {
hex = String::with_capacity(41);
hex.push('-');
array[0] &= 0b0111_1111;
} else {
hex = String::with_capacity(40);
}
for byte in array {
write!(&mut hex, "{:X} ", byte)
.expect("failed to write hex?");
}
hex
}
and with the hasher
use sha1::Digest;
use sha1::Sha1;
use sha1::digest::generic_array::GenericArray;
fn notchian_hash(plaintext: impl AsRef<[u8]>) -> String {
let mut hasher = sha1::Sha1::default();
hasher.update(plaintext.as_ref());
let mut alloc = [0u8; 20];
sha1::Digest::finalize_into(hasher, GenericArray::from_mut_slice(&mut alloc));
notchian_digest(alloc)
}
Another example (no regex needed):
use sha1::{Digest, Sha1};
pub fn calc_hash(name: &str) -> String {
let mut hash: [u8; 20] = Sha1::new().chain_update(name).finalize().into();
let negative = (hash[0] & 0x80) == 0x80;
// Digest is 20 bytes, so 40 hex digits plus the minus sign if necessary.
let mut hex = String::with_capacity(40 + negative as usize);
if negative {
hex.push('-');
// two's complement
let mut carry = true;
for b in hash.iter_mut().rev() {
(*b, carry) = (!*b).overflowing_add(carry as u8);
}
}
hex.extend(
hash.into_iter()
// extract hex digits
.flat_map(|x| [x >> 4, x & 0xf])
// skip leading zeroes
.skip_while(|&x| x == 0)
.map(|x| char::from_digit(x as u32, 16).expect("x is always valid base16")),
);
hex
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_cases() {
let pairs = &[
("Notch", "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48"),
("jeb_", "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1"),
("simon", "88e16a1019277b15d58faf0541e11910eb756f6"),
];
for (input, output) in pairs {
assert_eq!(&calc_hash(input), output);
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Does this still work? For me it says:
function or associated item not found in 'Sha1'
refering toSha1::digest()
Im using rust-crypto 0.2.36 and num-bigint 0.4