Skip to content

Instantly share code, notes, and snippets.

@roccodev
Last active May 31, 2025 23:07
Show Gist options
  • Save roccodev/8fa130f1946f89702f799f89b8469bc9 to your computer and use it in GitHub Desktop.
Save roccodev/8fa130f1946f89702f799f89b8469bc9 to your computer and use it in GitHub Desktop.
Minecraft SHA-1 complement hash calculation in Rust
// 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"));
}
}
@flavianz
Copy link

num-bigint

Thanks man

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment