jody_hash.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /* Jody Bruchon's fast hashing function
  2. *
  3. * This function was written to generate a fast hash that also has a
  4. * fairly low collision rate. The collision rate is much higher than
  5. * a secure hash algorithm, but the calculation is drastically simpler
  6. * and faster.
  7. *
  8. * Copyright (C) 2014-2017 by Jody Bruchon <jody@jodybruchon.com>
  9. * Released under The MIT License
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include "jody_hash.h"
  14. /* DO NOT modify the shift unless you know what you're doing.
  15. * This shift was decided upon after lots of testing and
  16. * changing it will likely cause lots of hash collisions. */
  17. #ifndef JODY_HASH_SHIFT
  18. #define JODY_HASH_SHIFT 14
  19. #endif
  20. /* The salt value's purpose is to cause each byte in the
  21. * hash_t word to have a positionally dependent variation.
  22. * It is injected into the calculation to prevent a string of
  23. * identical bytes from easily producing an identical hash. */
  24. /* The tail mask table is used for block sizes that are
  25. * indivisible by the width of a hash_t. It is ANDed with the
  26. * final hash_t-sized element to zero out data in the buffer
  27. * that is not part of the data to be hashed. */
  28. /* Set hash parameters based on requested hash width */
  29. #if JODY_HASH_WIDTH == 64
  30. #define JODY_HASH_CONSTANT 0x1f3d5b79U
  31. static const hash_t tail_mask[] = {
  32. 0x0000000000000000,
  33. 0x00000000000000ff,
  34. 0x000000000000ffff,
  35. 0x0000000000ffffff,
  36. 0x00000000ffffffff,
  37. 0x000000ffffffffff,
  38. 0x0000ffffffffffff,
  39. 0x00ffffffffffffff,
  40. 0xffffffffffffffff
  41. };
  42. #endif /* JODY_HASH_WIDTH == 64 */
  43. #if JODY_HASH_WIDTH == 32
  44. #define JODY_HASH_CONSTANT 0x1f3d5b79U
  45. static const hash_t tail_mask[] = {
  46. 0x00000000,
  47. 0x000000ff,
  48. 0x0000ffff,
  49. 0x00ffffff,
  50. 0xffffffff,
  51. };
  52. #endif /* JODY_HASH_WIDTH == 32 */
  53. #if JODY_HASH_WIDTH == 16
  54. #define JODY_HASH_CONSTANT 0x1f5bU
  55. static const hash_t tail_mask[] = {
  56. 0x0000,
  57. 0x00ff,
  58. 0xffff,
  59. };
  60. #endif /* JODY_HASH_WIDTH == 16 */
  61. /* Hash a block of arbitrary size; must be divisible by sizeof(hash_t)
  62. * The first block should pass a start_hash of zero.
  63. * All blocks after the first should pass start_hash as the value
  64. * returned by the last call to this function. This allows hashing
  65. * of any amount of data. If data is not divisible by the size of
  66. * hash_t, it is MANDATORY that the caller provide a data buffer
  67. * which is divisible by sizeof(hash_t). */
  68. extern hash_t jody_block_hash(const hash_t * restrict data,
  69. const hash_t start_hash, const size_t count)
  70. {
  71. hash_t hash = start_hash;
  72. hash_t element;
  73. hash_t partial_salt;
  74. size_t len;
  75. /* Don't bother trying to hash a zero-length block */
  76. if (count == 0) return hash;
  77. len = count / sizeof(hash_t);
  78. for (; len > 0; len--) {
  79. element = *data;
  80. hash += element;
  81. hash += JODY_HASH_CONSTANT;
  82. hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT); /* bit rotate left */
  83. hash ^= element;
  84. hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT);
  85. hash ^= JODY_HASH_CONSTANT;
  86. hash += element;
  87. data++;
  88. }
  89. /* Handle data tail (for blocks indivisible by sizeof(hash_t)) */
  90. len = count & (sizeof(hash_t) - 1);
  91. if (len) {
  92. partial_salt = JODY_HASH_CONSTANT & tail_mask[len];
  93. element = *data & tail_mask[len];
  94. hash += element;
  95. hash += partial_salt;
  96. hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT);
  97. hash ^= element;
  98. hash = (hash << JODY_HASH_SHIFT) | hash >> (sizeof(hash_t) * 8 - JODY_HASH_SHIFT);
  99. hash ^= partial_salt;
  100. hash += element;
  101. }
  102. return hash;
  103. }