From WikiChip
$hash Identifier - mIRC
< mirc‎ | identifiers
Revision as of 17:08, 8 January 2018 by Maroonbells (talk | contribs) (Create content for empty page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The $hash identifier calculates a simple hash of the supplied text. Hash is shown as a decimal number in the range from 1 to 2^32-1. You should probably avoid using this hash for reasons explained in the Notes section.

Synopsis

$hash(<text>,<N>)

Switches

None

Parameters

text text string or %variable to be hashed
N Bit length for the returned hash. $hash returns $null if N is not in the range 2-32

Properties

None

Example

//echo -a The hash is $hash(test,32)
returns: The hash is 1702094848

Notes

The 'fakehash' alias below is based on the code posted here: https://forums.mirc.com/ubbthreads.php/topics/98371/Re:_$hash_function#Post98371

$hash uses a hash function that is very weak for several reasons. The weaknesses are more easily seen by showing an alias which mimics $hash output, and showing $hash output in hex. Some weaknesses include:

  • 1. Similar text have similar hash. Strings of 1-3 bytes are most obvious:
//echo -a $base($hash(abc,32),10,16) is $+($base($asc(a),10,16,2),$base($asc(b),10,16,2),$base($asc(c),10,16,2),00)
returns: 61626300 is 61626300
  • 2. When N is greater than 24, the rightmost extra bits above 24 are always zero, making it effectively a 24-bit hash not a 32. Only 2^24 of the values within the range of 0 - 2^32-1 can possibly be hashes. i.e. a 27-bit hash always has the least-significant 3 bits as zero:
//var %i 99999 | while (%i) { var %n $rand(1,99999999) , %bits $rand(25,32) | if ( $right($base($hash(%n,%bits),10,2,%bits) , $calc(%bits -24) )) echo -a this message will never show | dec %i }
  • 3. One of the properties of good hash hash functions is that each changed bit of the input should change close to half the bits in a seemingly-random pattern. Changing 1 bit of the text has minimal change of the bits in the $hash output, often changing just 1 bit. It often takes several additional bytes before the bits set by the first byte are altered.
//echo -a $base($hash(mIRC,32),10,16) / $base($hash(mIRD,32),10,16)
returns: 4952B000 / 4952B100
  • 4. It's easy to create duplicate hashes, especially when the length of the text is a multiple of 3:
//echo -a $base($hash(ABCDEF,32),10,16) / $base($hash(ABDDEE,32),10,16)

Instead of using $hash, you would be better off using other substitutes. For example, if you need it to be a decimal number with a variable number of bits from 1-32, use $crc then convert to decimal then reduce the number of bits:

alias crchash {
  return $calc( $base($crc($1,0),16,10) % 2^$2 )
}

If the hash needs to be crypto-level secure, use 8 bits from $sha1 or $sha512 instead of from $crc.

When the fakehash alias is in a remotes script, you should get the same answers from $fakehash as from $hash:

//var %i 999 | while (%i) { var %text $rand(1,999999999) , %bits $rand(16,24) | if ($hash(%text,%bits) != $fakehash(%text,%bits)) echo -a this should never show: %text %bits | dec %i }
 
alias fakehash {
  if ( ($1 == $null) || ($2 !isnum 2-32) ) return $null
  var %i 1 | var %len $len(%string) | var %x 0 | var %bits $int($2)
  while (%i <= $len($1)) {
    var %y $int($calc( $and(%x,$base(ff000000,16,10)) / 2^24 ))
    var %x = $calc( %x + %y + $asc($mid($1,%i,1)) )
    var %x = $calc( (%x * 256) % (2^32) )
    inc %i
  }
  var %y = $base(%x,10,2,32)
  var %z = $base($left(%y,%bits),2,10)
  if ($mid(%y,$calc(1+%bits))) inc %z
  return $calc( %z % (2^%bits) )
}

Compatibility

Added: mIRC v5.4
Added on: 23 Jun 1998
Note: Unless otherwise stated, this was the date of original functionality.
Further enhancements may have been made in later versions.


See also

[Expand]
v · d · e mIRC identifier list