生成 UUID 的一致哈希

Generate consistent hash of a UUID

我想生成 UUID 字符串的一致散列,例如 dcc549d8-bd0c-49c2-bff8-f6fa80fb7857,最好是 0 到 N 之间的数字。

最好最快的方法是什么?

更新:我正在考虑使用 CRC32。有 pros/cons 吗?

你想要什么样的散列? 'best' 选择可能不是最快的,并且取决于您使用散列的目的。

对于 md5,你可以这样做:

var crypto = require('crypto');

var md5sum = crypto.createHash('md5');
md5sum.update(uuid);
var b64 = md5sum.digest('base64')

如果需要,您可以使用 base64 库将其转换为数字。

节点加密内容,包括可能更适合您的情况的其他哈希算法(md5 速度更快但安全性较低)记录在此处:https://nodejs.org/api/crypto.html

如果思考UUID的本质example。 我会朝那个方向走。

const INIT_NUMBER = 271;

function hash(uuid, N) {
  const x = uuid.split("-").reduce((a,b) => a ^ Number.parseInt(b, 16), INIT_NUMBER) ;
  return arguments.length === 1 ? x : x % N;
}

const a = hash("dcc549d8-bd0c-49c2-bff8-f6fa80fb7857");            
const b = hash("dcc549d8-bd0c-49c2-bff8-f6fa80fb7857", 256);

console.log(a, b);
  
  

如果您使用的是 v4 UUID 生成,除了两个数字之外的所有数字都已经包含伪随机值,您需要做的就是将它们提取为您想要的形式。

来自规范:

4.4.  Algorithms for Creating a UUID from Truly Random or
      Pseudo-Random Numbers

   The version 4 UUID is meant for generating UUIDs from truly-random or
   pseudo-random numbers.

   The algorithm is as follows:

   o  Set the two most significant bits (bits 6 and 7) of the
      clock_seq_hi_and_reserved to zero and one, respectively.

   o  Set the four most significant bits (bits 12 through 15) of the
      time_hi_and_version field to the 4-bit version number from
      Section 4.1.3.

   o  Set all the other bits to randomly (or pseudo-randomly) chosen
      values.

要提取伪随机值,我们只需删除由“-”分隔的第三和第四部分的第一个十六进制字符(包含 4 个最高有效位)并将其转换为您想要的基数。因为 UUID 总是相同的长度,所以我们每次都可以删除相同的索引(14 和 19)。

不幸的是,由于 Javascript 最多只支持 32 位整数,我们需要分别提供 Number.parseInt 组 8 个十六进制字符(32 位),然后添加模数以最小化偏差。

因此,我们的代码将是:

function parseUUID(uuid, N) {
    var pseudorandomBytes = uuid.substring(0, 14) + uuid.substring(15, 19) + uuid.substring(20); // Splice out the bytes which contain metadata
    pseudorandomBytes = pseudorandomBytes.replace(/-/g, ""); // Remove all dashes
    var accumulator = 0; // Accumulate the sums modulo N of every eight hex characters and the remainder
    pseudorandomBytes.match(/.{1,8}/g).forEach(function (a) { accumulator = (accumulator + (Number.parseInt(a, 16) % N)) % N; });
    return accumulator; // Return the result
}