# HG changeset patch # User alfadur # Date 1560701786 -10800 # Node ID bcb98009ad398be30dd8136fdd5d861c2939500b # Parent 7416f6319de903fe9d36cedc822fb0846f931302 avoid allocation in hash comparison diff -r 7416f6319de9 -r bcb98009ad39 rust/hedgewars-server/src/handlers.rs --- a/rust/hedgewars-server/src/handlers.rs Sun Jun 16 13:27:14 2019 +0200 +++ b/rust/hedgewars-server/src/handlers.rs Sun Jun 16 19:16:26 2019 +0300 @@ -1,5 +1,10 @@ use mio; -use std::{collections::HashMap, io, io::Write}; +use std::{ + cmp::PartialEq, + collections::HashMap, + fmt::{Formatter, LowerHex}, + iter::Iterator, +}; use self::{ actions::{Destination, DestinationGroup, PendingMessage}, @@ -28,8 +33,6 @@ mod inlobby; mod inroom; -use std::fmt::{Formatter, LowerHex}; - #[derive(PartialEq, Debug)] pub struct Sha1Digest([u8; 20]); @@ -48,6 +51,35 @@ } } +impl PartialEq<&str> for Sha1Digest { + fn eq(&self, other: &&str) -> bool { + if other.len() != self.0.len() * 2 { + false + } else { + #[inline] + fn convert(c: u8) -> u8 { + if c > b'9' { + c.overflowing_sub(b'a').0.saturating_add(10) + } else { + c.overflowing_sub(b'0').0 + } + } + + other + .as_bytes() + .chunks_exact(2) + .zip(&self.0) + .all(|(chars, byte)| { + if let [hi, lo] = chars { + convert(*lo) == byte & 0x0f && convert(*hi) == (byte & 0xf0) >> 4 + } else { + unreachable!() + } + }) + } + } +} + #[derive(Debug)] pub struct AccountInfo { pub is_registered: bool, @@ -411,3 +443,18 @@ } } } + +#[cfg(test)] +mod test { + use super::Sha1Digest; + + #[test] + fn hash_cmp_test() { + let hash = Sha1Digest([ + 0x37, 0xC4, 0x9F, 0x5C, 0xC3, 0xC9, 0xDB, 0xFC, 0x54, 0xAC, 0x22, 0x04, 0xF6, 0x12, + 0x9A, 0xED, 0x69, 0xB1, 0xC4, 0x5C, + ]); + + assert_eq!(hash, &format!("{:x}", hash)[..]); + } +} diff -r 7416f6319de9 -r bcb98009ad39 rust/hedgewars-server/src/server/database.rs --- a/rust/hedgewars-server/src/server/database.rs Sun Jun 16 13:27:14 2019 +0200 +++ b/rust/hedgewars-server/src/server/database.rs Sun Jun 16 19:16:26 2019 +0300 @@ -69,7 +69,7 @@ let server_hash = get_hash(protocol, &password, &server_salt, &client_salt); password.replace_range(.., "🦔🦔🦔🦔🦔🦔🦔🦔"); - if password_hash == format!("{:x}", client_hash) { + if client_hash == password_hash { Ok(Some(AccountInfo { is_registered: true, is_admin: is_admin == 1,