farmhashjs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +216 -0
- package/README.md +108 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +548 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/index.ts +632 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* farmhashjs - Pure JavaScript implementation of Google's FarmHash
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025 Crisp IM SAS
|
|
5
|
+
* Licensed under the Apache-2.0 License
|
|
6
|
+
*
|
|
7
|
+
* This module provides both legacy-compatible and modern stable hash functions:
|
|
8
|
+
*
|
|
9
|
+
* Legacy (v3.x compatible):
|
|
10
|
+
* - legacyHash64(): Compatible with farmhash v3.3.1 hash64()
|
|
11
|
+
* - legacyHash32(): Compatible with farmhash v3.3.1 hash32()
|
|
12
|
+
*
|
|
13
|
+
* Modern (stable fingerprints):
|
|
14
|
+
* - fingerprint64(): Stable 64-bit hash (same as farmhash fingerprint64)
|
|
15
|
+
* - fingerprint32(): Stable 32-bit hash (same as farmhash fingerprint32)
|
|
16
|
+
*
|
|
17
|
+
* The difference is that legacy functions apply a "DebugTweak" transformation
|
|
18
|
+
* that was present in farmhash v3.x (compiled with FARMHASH_DEBUG=1).
|
|
19
|
+
* Modern fingerprint functions are guaranteed stable across all platforms.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**************************************************************************
|
|
23
|
+
* 64-BIT CONSTANTS
|
|
24
|
+
***************************************************************************/
|
|
25
|
+
|
|
26
|
+
const k0 = 0xc3a5c85c97cb3127n;
|
|
27
|
+
const k1 = 0xb492b66fbe98f273n;
|
|
28
|
+
const k2 = 0x9ae16a3b2f90404fn;
|
|
29
|
+
|
|
30
|
+
/**************************************************************************
|
|
31
|
+
* 32-BIT CONSTANTS
|
|
32
|
+
***************************************************************************/
|
|
33
|
+
|
|
34
|
+
const c1_32 = 0xcc9e2d51;
|
|
35
|
+
const c2_32 = 0x1b873593;
|
|
36
|
+
|
|
37
|
+
/**************************************************************************
|
|
38
|
+
* 64-BIT HELPER FUNCTIONS
|
|
39
|
+
***************************************************************************/
|
|
40
|
+
|
|
41
|
+
function fetch64(buf: Buffer, offset: number): bigint {
|
|
42
|
+
return buf.readBigUInt64LE(offset);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function fetch32(buf: Buffer, offset: number): bigint {
|
|
46
|
+
return BigInt(buf.readUInt32LE(offset));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function fetch32AsNumber(buf: Buffer, offset: number): number {
|
|
50
|
+
return buf.readUInt32LE(offset);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function rotate64(val: bigint, shift: number): bigint {
|
|
54
|
+
shift = shift & 63;
|
|
55
|
+
return ((val >> BigInt(shift)) | (val << BigInt(64 - shift))) & 0xFFFFFFFFFFFFFFFFn;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function rotate32(val: number, shift: number): number {
|
|
59
|
+
shift = shift & 31;
|
|
60
|
+
return ((val >>> shift) | (val << (32 - shift))) >>> 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function bswap64(x: bigint): bigint {
|
|
64
|
+
const b0 = (x >> 0n) & 0xFFn;
|
|
65
|
+
const b1 = (x >> 8n) & 0xFFn;
|
|
66
|
+
const b2 = (x >> 16n) & 0xFFn;
|
|
67
|
+
const b3 = (x >> 24n) & 0xFFn;
|
|
68
|
+
const b4 = (x >> 32n) & 0xFFn;
|
|
69
|
+
const b5 = (x >> 40n) & 0xFFn;
|
|
70
|
+
const b6 = (x >> 48n) & 0xFFn;
|
|
71
|
+
const b7 = (x >> 56n) & 0xFFn;
|
|
72
|
+
return (b0 << 56n) | (b1 << 48n) | (b2 << 40n) | (b3 << 32n) |
|
|
73
|
+
(b4 << 24n) | (b5 << 16n) | (b6 << 8n) | b7;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function bswap32(x: number): number {
|
|
77
|
+
return (((x & 0xFF) << 24) |
|
|
78
|
+
((x & 0xFF00) << 8) |
|
|
79
|
+
((x >> 8) & 0xFF00) |
|
|
80
|
+
((x >> 24) & 0xFF)) >>> 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function shiftMix(val: bigint): bigint {
|
|
84
|
+
return (val ^ (val >> 47n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function hashLen16Mul(u: bigint, v: bigint, mul: bigint): bigint {
|
|
88
|
+
let a = ((u ^ v) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
89
|
+
a = (a ^ (a >> 47n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
90
|
+
let b = ((v ^ a) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
91
|
+
b = (b ^ (b >> 47n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
92
|
+
b = (b * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
93
|
+
return b;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**************************************************************************
|
|
97
|
+
* 32-BIT HELPER FUNCTIONS
|
|
98
|
+
***************************************************************************/
|
|
99
|
+
|
|
100
|
+
function fmix(h: number): number {
|
|
101
|
+
h = (h ^ (h >>> 16)) >>> 0;
|
|
102
|
+
h = Math.imul(h, 0x85ebca6b) >>> 0;
|
|
103
|
+
h = (h ^ (h >>> 13)) >>> 0;
|
|
104
|
+
h = Math.imul(h, 0xc2b2ae35) >>> 0;
|
|
105
|
+
h = (h ^ (h >>> 16)) >>> 0;
|
|
106
|
+
return h;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function mur(a: number, h: number): number {
|
|
110
|
+
a = Math.imul(a, c1_32) >>> 0;
|
|
111
|
+
a = rotate32(a, 17);
|
|
112
|
+
a = Math.imul(a, c2_32) >>> 0;
|
|
113
|
+
h = (h ^ a) >>> 0;
|
|
114
|
+
h = rotate32(h, 19);
|
|
115
|
+
return (Math.imul(h, 5) + 0xe6546b64) >>> 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**************************************************************************
|
|
119
|
+
* 64-BIT HASH LENGTH FUNCTIONS
|
|
120
|
+
***************************************************************************/
|
|
121
|
+
|
|
122
|
+
function hashLen0to16(buf: Buffer, len: number): bigint {
|
|
123
|
+
if (len >= 8) {
|
|
124
|
+
const mul = k2 + BigInt(len) * 2n;
|
|
125
|
+
const a = (fetch64(buf, 0) + k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
126
|
+
const b = fetch64(buf, len - 8);
|
|
127
|
+
const c = (rotate64(b, 37) * mul + a) & 0xFFFFFFFFFFFFFFFFn;
|
|
128
|
+
const d = ((rotate64(a, 25) + b) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
129
|
+
return hashLen16Mul(c, d, mul);
|
|
130
|
+
}
|
|
131
|
+
if (len >= 4) {
|
|
132
|
+
const mul = k2 + BigInt(len) * 2n;
|
|
133
|
+
const a = fetch32(buf, 0);
|
|
134
|
+
return hashLen16Mul(BigInt(len) + (a << 3n), fetch32(buf, len - 4), mul);
|
|
135
|
+
}
|
|
136
|
+
if (len > 0) {
|
|
137
|
+
const a = buf[0];
|
|
138
|
+
const b = buf[len >> 1];
|
|
139
|
+
const c = buf[len - 1];
|
|
140
|
+
const y = BigInt(a) + (BigInt(b) << 8n);
|
|
141
|
+
const z = BigInt(len) + (BigInt(c) << 2n);
|
|
142
|
+
return (shiftMix(((y * k2) ^ (z * k0)) & 0xFFFFFFFFFFFFFFFFn) * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
143
|
+
}
|
|
144
|
+
return k2;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function hashLen17to32(buf: Buffer, len: number): bigint {
|
|
148
|
+
const mul = k2 + BigInt(len) * 2n;
|
|
149
|
+
const a = (fetch64(buf, 0) * k1) & 0xFFFFFFFFFFFFFFFFn;
|
|
150
|
+
const b = fetch64(buf, 8);
|
|
151
|
+
const c = (fetch64(buf, len - 8) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
152
|
+
const d = (fetch64(buf, len - 16) * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
153
|
+
return hashLen16Mul(
|
|
154
|
+
(rotate64((a + b) & 0xFFFFFFFFFFFFFFFFn, 43) + rotate64(c, 30) + d) & 0xFFFFFFFFFFFFFFFFn,
|
|
155
|
+
(a + rotate64((b + k2) & 0xFFFFFFFFFFFFFFFFn, 18) + c) & 0xFFFFFFFFFFFFFFFFn,
|
|
156
|
+
mul
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function xoH32(buf: Buffer, offset: number, mul: bigint, seed0: bigint = 0n, seed1: bigint = 0n): bigint {
|
|
161
|
+
const a = (fetch64(buf, offset) * k1) & 0xFFFFFFFFFFFFFFFFn;
|
|
162
|
+
const b = fetch64(buf, offset + 8);
|
|
163
|
+
const c = (fetch64(buf, offset + 24) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
164
|
+
const d = (fetch64(buf, offset + 16) * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
165
|
+
const u = (rotate64((a + b) & 0xFFFFFFFFFFFFFFFFn, 43) + rotate64(c, 30) + d + seed0) & 0xFFFFFFFFFFFFFFFFn;
|
|
166
|
+
const v = (a + rotate64((b + k2) & 0xFFFFFFFFFFFFFFFFn, 18) + c + seed1) & 0xFFFFFFFFFFFFFFFFn;
|
|
167
|
+
const a2 = shiftMix(((u ^ v) * mul) & 0xFFFFFFFFFFFFFFFFn);
|
|
168
|
+
const b2 = shiftMix(((v ^ a2) * mul) & 0xFFFFFFFFFFFFFFFFn);
|
|
169
|
+
return b2;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function hashLen33to64(buf: Buffer, len: number): bigint {
|
|
173
|
+
const mul0 = k2 - 30n;
|
|
174
|
+
const mul1 = k2 - 30n + 2n * BigInt(len);
|
|
175
|
+
const h0 = xoH32(buf, 0, mul0);
|
|
176
|
+
const h1 = xoH32(buf, len - 32, mul1);
|
|
177
|
+
return ((((h1 * mul1) & 0xFFFFFFFFFFFFFFFFn) + h0) * mul1) & 0xFFFFFFFFFFFFFFFFn;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function hashLen65to96(buf: Buffer, len: number): bigint {
|
|
181
|
+
const mul0 = k2 - 114n;
|
|
182
|
+
const mul1 = k2 - 114n + 2n * BigInt(len);
|
|
183
|
+
const h0 = xoH32(buf, 0, mul0);
|
|
184
|
+
const h1 = xoH32(buf, 32, mul1);
|
|
185
|
+
const h2 = xoH32(buf, len - 32, mul1, h0, h1);
|
|
186
|
+
return (((h2 * 9n) + (h0 >> 17n) + (h1 >> 21n)) * mul1) & 0xFFFFFFFFFFFFFFFFn;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function weakHashLen32WithSeeds(buf: Buffer, offset: number, a: bigint, b: bigint): [bigint, bigint] {
|
|
190
|
+
const w = fetch64(buf, offset);
|
|
191
|
+
const x = fetch64(buf, offset + 8);
|
|
192
|
+
const y = fetch64(buf, offset + 16);
|
|
193
|
+
const z = fetch64(buf, offset + 24);
|
|
194
|
+
a = (a + w) & 0xFFFFFFFFFFFFFFFFn;
|
|
195
|
+
b = rotate64((b + a + z) & 0xFFFFFFFFFFFFFFFFn, 21);
|
|
196
|
+
const c = a;
|
|
197
|
+
a = (a + x) & 0xFFFFFFFFFFFFFFFFn;
|
|
198
|
+
a = (a + y) & 0xFFFFFFFFFFFFFFFFn;
|
|
199
|
+
b = (b + rotate64(a, 44)) & 0xFFFFFFFFFFFFFFFFn;
|
|
200
|
+
return [(a + z) & 0xFFFFFFFFFFFFFFFFn, (b + c) & 0xFFFFFFFFFFFFFFFFn];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**************************************************************************
|
|
204
|
+
* FARMHASH NA (64+ bytes, used by fingerprint64)
|
|
205
|
+
***************************************************************************/
|
|
206
|
+
|
|
207
|
+
function naHash64(buf: Buffer, len: number): bigint {
|
|
208
|
+
const seed = 81n;
|
|
209
|
+
|
|
210
|
+
let x = seed;
|
|
211
|
+
let y = (seed * k1 + 113n) & 0xFFFFFFFFFFFFFFFFn;
|
|
212
|
+
let z = (shiftMix((y * k2 + 113n) & 0xFFFFFFFFFFFFFFFFn) * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
213
|
+
let v: [bigint, bigint] = [0n, 0n];
|
|
214
|
+
let w: [bigint, bigint] = [0n, 0n];
|
|
215
|
+
x = (x * k2 + fetch64(buf, 0)) & 0xFFFFFFFFFFFFFFFFn;
|
|
216
|
+
|
|
217
|
+
const endIdx = Math.floor((len - 1) / 64) * 64;
|
|
218
|
+
const last64 = endIdx + ((len - 1) & 63) - 63;
|
|
219
|
+
|
|
220
|
+
let idx = 0;
|
|
221
|
+
do {
|
|
222
|
+
x = (rotate64((x + y + v[0] + fetch64(buf, idx + 8)) & 0xFFFFFFFFFFFFFFFFn, 37) * k1) & 0xFFFFFFFFFFFFFFFFn;
|
|
223
|
+
y = (rotate64((y + v[1] + fetch64(buf, idx + 48)) & 0xFFFFFFFFFFFFFFFFn, 42) * k1) & 0xFFFFFFFFFFFFFFFFn;
|
|
224
|
+
x = (x ^ w[1]) & 0xFFFFFFFFFFFFFFFFn;
|
|
225
|
+
y = (y + v[0] + fetch64(buf, idx + 40)) & 0xFFFFFFFFFFFFFFFFn;
|
|
226
|
+
z = (rotate64((z + w[0]) & 0xFFFFFFFFFFFFFFFFn, 33) * k1) & 0xFFFFFFFFFFFFFFFFn;
|
|
227
|
+
v = weakHashLen32WithSeeds(buf, idx, (v[1] * k1) & 0xFFFFFFFFFFFFFFFFn, (x + w[0]) & 0xFFFFFFFFFFFFFFFFn);
|
|
228
|
+
w = weakHashLen32WithSeeds(buf, idx + 32, (z + w[1]) & 0xFFFFFFFFFFFFFFFFn, (y + fetch64(buf, idx + 16)) & 0xFFFFFFFFFFFFFFFFn);
|
|
229
|
+
[z, x] = [x, z];
|
|
230
|
+
idx += 64;
|
|
231
|
+
} while (idx !== endIdx);
|
|
232
|
+
|
|
233
|
+
const mul = k1 + ((z & 0xFFn) << 1n);
|
|
234
|
+
idx = last64;
|
|
235
|
+
w[0] = (w[0] + (BigInt(len - 1) & 63n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
236
|
+
v[0] = (v[0] + w[0]) & 0xFFFFFFFFFFFFFFFFn;
|
|
237
|
+
w[0] = (w[0] + v[0]) & 0xFFFFFFFFFFFFFFFFn;
|
|
238
|
+
|
|
239
|
+
x = (rotate64((x + y + v[0] + fetch64(buf, idx + 8)) & 0xFFFFFFFFFFFFFFFFn, 37) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
240
|
+
y = (rotate64((y + v[1] + fetch64(buf, idx + 48)) & 0xFFFFFFFFFFFFFFFFn, 42) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
241
|
+
x = (x ^ (w[1] * 9n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
242
|
+
y = (y + (v[0] * 9n) + fetch64(buf, idx + 40)) & 0xFFFFFFFFFFFFFFFFn;
|
|
243
|
+
z = (rotate64((z + w[0]) & 0xFFFFFFFFFFFFFFFFn, 33) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
244
|
+
v = weakHashLen32WithSeeds(buf, idx, (v[1] * mul) & 0xFFFFFFFFFFFFFFFFn, (x + w[0]) & 0xFFFFFFFFFFFFFFFFn);
|
|
245
|
+
w = weakHashLen32WithSeeds(buf, idx + 32, (z + w[1]) & 0xFFFFFFFFFFFFFFFFn, (y + fetch64(buf, idx + 16)) & 0xFFFFFFFFFFFFFFFFn);
|
|
246
|
+
[z, x] = [x, z];
|
|
247
|
+
|
|
248
|
+
return hashLen16Mul(
|
|
249
|
+
(hashLen16Mul(v[0], w[0], mul) + (shiftMix(y) * k0) + z) & 0xFFFFFFFFFFFFFFFFn,
|
|
250
|
+
(hashLen16Mul(v[1], w[1], mul) + x) & 0xFFFFFFFFFFFFFFFFn,
|
|
251
|
+
mul
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**************************************************************************
|
|
256
|
+
* FARMHASH UO (>256 bytes, used by legacy hash64)
|
|
257
|
+
***************************************************************************/
|
|
258
|
+
|
|
259
|
+
function uoH(x: bigint, y: bigint, mul: bigint, r: number): bigint {
|
|
260
|
+
let a = ((x ^ y) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
261
|
+
a = (a ^ (a >> 47n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
262
|
+
const b = ((y ^ a) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
263
|
+
return (rotate64(b, r) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function uoHash64WithSeeds(buf: Buffer, len: number, seed0: bigint, seed1: bigint): bigint {
|
|
267
|
+
let x = seed0;
|
|
268
|
+
let y = (seed1 * k2 + 113n) & 0xFFFFFFFFFFFFFFFFn;
|
|
269
|
+
let z = (shiftMix((y * k2) & 0xFFFFFFFFFFFFFFFFn) * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
270
|
+
let v: [bigint, bigint] = [seed0, seed1];
|
|
271
|
+
let w: [bigint, bigint] = [0n, 0n];
|
|
272
|
+
let u = (x - z) & 0xFFFFFFFFFFFFFFFFn;
|
|
273
|
+
x = (x * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
274
|
+
const mul = (k2 + (u & 0x82n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
275
|
+
|
|
276
|
+
const endIdx = Math.floor((len - 1) / 64) * 64;
|
|
277
|
+
const last64 = endIdx + ((len - 1) & 63) - 63;
|
|
278
|
+
|
|
279
|
+
let idx = 0;
|
|
280
|
+
do {
|
|
281
|
+
const a0 = fetch64(buf, idx);
|
|
282
|
+
const a1 = fetch64(buf, idx + 8);
|
|
283
|
+
const a2 = fetch64(buf, idx + 16);
|
|
284
|
+
const a3 = fetch64(buf, idx + 24);
|
|
285
|
+
const a4 = fetch64(buf, idx + 32);
|
|
286
|
+
const a5 = fetch64(buf, idx + 40);
|
|
287
|
+
const a6 = fetch64(buf, idx + 48);
|
|
288
|
+
const a7 = fetch64(buf, idx + 56);
|
|
289
|
+
|
|
290
|
+
x = (x + a0 + a1) & 0xFFFFFFFFFFFFFFFFn;
|
|
291
|
+
y = (y + a2) & 0xFFFFFFFFFFFFFFFFn;
|
|
292
|
+
z = (z + a3) & 0xFFFFFFFFFFFFFFFFn;
|
|
293
|
+
v[0] = (v[0] + a4) & 0xFFFFFFFFFFFFFFFFn;
|
|
294
|
+
v[1] = (v[1] + a5 + a1) & 0xFFFFFFFFFFFFFFFFn;
|
|
295
|
+
w[0] = (w[0] + a6) & 0xFFFFFFFFFFFFFFFFn;
|
|
296
|
+
w[1] = (w[1] + a7) & 0xFFFFFFFFFFFFFFFFn;
|
|
297
|
+
|
|
298
|
+
x = rotate64(x, 26);
|
|
299
|
+
x = (x * 9n) & 0xFFFFFFFFFFFFFFFFn;
|
|
300
|
+
y = rotate64(y, 29);
|
|
301
|
+
z = (z * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
302
|
+
v[0] = rotate64(v[0], 33);
|
|
303
|
+
v[1] = rotate64(v[1], 30);
|
|
304
|
+
w[0] = (w[0] ^ x) & 0xFFFFFFFFFFFFFFFFn;
|
|
305
|
+
w[0] = (w[0] * 9n) & 0xFFFFFFFFFFFFFFFFn;
|
|
306
|
+
z = rotate64(z, 32);
|
|
307
|
+
z = (z + w[1]) & 0xFFFFFFFFFFFFFFFFn;
|
|
308
|
+
w[1] = (w[1] + z) & 0xFFFFFFFFFFFFFFFFn;
|
|
309
|
+
z = (z * 9n) & 0xFFFFFFFFFFFFFFFFn;
|
|
310
|
+
[u, y] = [y, u];
|
|
311
|
+
|
|
312
|
+
z = (z + a0 + a6) & 0xFFFFFFFFFFFFFFFFn;
|
|
313
|
+
v[0] = (v[0] + a2) & 0xFFFFFFFFFFFFFFFFn;
|
|
314
|
+
v[1] = (v[1] + a3) & 0xFFFFFFFFFFFFFFFFn;
|
|
315
|
+
w[0] = (w[0] + a4) & 0xFFFFFFFFFFFFFFFFn;
|
|
316
|
+
w[1] = (w[1] + a5 + a6) & 0xFFFFFFFFFFFFFFFFn;
|
|
317
|
+
x = (x + a1) & 0xFFFFFFFFFFFFFFFFn;
|
|
318
|
+
y = (y + a7) & 0xFFFFFFFFFFFFFFFFn;
|
|
319
|
+
|
|
320
|
+
y = (y + v[0]) & 0xFFFFFFFFFFFFFFFFn;
|
|
321
|
+
v[0] = (v[0] + (x - y)) & 0xFFFFFFFFFFFFFFFFn;
|
|
322
|
+
v[1] = (v[1] + w[0]) & 0xFFFFFFFFFFFFFFFFn;
|
|
323
|
+
w[0] = (w[0] + v[1]) & 0xFFFFFFFFFFFFFFFFn;
|
|
324
|
+
w[1] = (w[1] + (x - y)) & 0xFFFFFFFFFFFFFFFFn;
|
|
325
|
+
x = (x + w[1]) & 0xFFFFFFFFFFFFFFFFn;
|
|
326
|
+
w[1] = rotate64(w[1], 34);
|
|
327
|
+
[u, z] = [z, u];
|
|
328
|
+
idx += 64;
|
|
329
|
+
} while (idx !== endIdx);
|
|
330
|
+
|
|
331
|
+
idx = last64;
|
|
332
|
+
u = (u * 9n) & 0xFFFFFFFFFFFFFFFFn;
|
|
333
|
+
v[1] = rotate64(v[1], 28);
|
|
334
|
+
v[0] = rotate64(v[0], 20);
|
|
335
|
+
w[0] = (w[0] + (BigInt(len - 1) & 63n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
336
|
+
u = (u + y) & 0xFFFFFFFFFFFFFFFFn;
|
|
337
|
+
y = (y + u) & 0xFFFFFFFFFFFFFFFFn;
|
|
338
|
+
|
|
339
|
+
x = (rotate64((y - x + v[0] + fetch64(buf, idx + 8)) & 0xFFFFFFFFFFFFFFFFn, 37) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
340
|
+
y = (rotate64((y ^ v[1] ^ fetch64(buf, idx + 48)) & 0xFFFFFFFFFFFFFFFFn, 42) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
341
|
+
x = (x ^ (w[1] * 9n)) & 0xFFFFFFFFFFFFFFFFn;
|
|
342
|
+
y = (y + v[0] + fetch64(buf, idx + 40)) & 0xFFFFFFFFFFFFFFFFn;
|
|
343
|
+
z = (rotate64((z + w[0]) & 0xFFFFFFFFFFFFFFFFn, 33) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
344
|
+
|
|
345
|
+
v = weakHashLen32WithSeeds(buf, idx, (v[1] * mul) & 0xFFFFFFFFFFFFFFFFn, (x + w[0]) & 0xFFFFFFFFFFFFFFFFn);
|
|
346
|
+
w = weakHashLen32WithSeeds(buf, idx + 32, (z + w[1]) & 0xFFFFFFFFFFFFFFFFn, (y + fetch64(buf, idx + 16)) & 0xFFFFFFFFFFFFFFFFn);
|
|
347
|
+
|
|
348
|
+
return uoH(
|
|
349
|
+
(hashLen16Mul(v[0] + x, w[0] ^ y, mul) + z - u) & 0xFFFFFFFFFFFFFFFFn,
|
|
350
|
+
uoH((v[1] + y) & 0xFFFFFFFFFFFFFFFFn, (w[1] + z) & 0xFFFFFFFFFFFFFFFFn, k2, 30) ^ x,
|
|
351
|
+
k2,
|
|
352
|
+
31
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function uoHash64(buf: Buffer, len: number): bigint {
|
|
357
|
+
return uoHash64WithSeeds(buf, len, 81n, 0n);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**************************************************************************
|
|
361
|
+
* FARMHASH XO (legacy hash64 router)
|
|
362
|
+
***************************************************************************/
|
|
363
|
+
|
|
364
|
+
function xoHash64(buf: Buffer, len: number): bigint {
|
|
365
|
+
if (len <= 16) return hashLen0to16(buf, len);
|
|
366
|
+
if (len <= 32) return hashLen17to32(buf, len);
|
|
367
|
+
if (len <= 64) return hashLen33to64(buf, len);
|
|
368
|
+
if (len <= 96) return hashLen65to96(buf, len);
|
|
369
|
+
if (len <= 256) return naHash64(buf, len);
|
|
370
|
+
return uoHash64(buf, len);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**************************************************************************
|
|
374
|
+
* FARMHASH NA - HashLen33to64 (used by fingerprint64)
|
|
375
|
+
***************************************************************************/
|
|
376
|
+
|
|
377
|
+
function naHashLen33to64(buf: Buffer, len: number): bigint {
|
|
378
|
+
const mul = k2 + BigInt(len) * 2n;
|
|
379
|
+
const a = (fetch64(buf, 0) * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
380
|
+
const b = fetch64(buf, 8);
|
|
381
|
+
const c = (fetch64(buf, len - 8) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
382
|
+
const d = (fetch64(buf, len - 16) * k2) & 0xFFFFFFFFFFFFFFFFn;
|
|
383
|
+
const y = (rotate64((a + b) & 0xFFFFFFFFFFFFFFFFn, 43) + rotate64(c, 30) + d) & 0xFFFFFFFFFFFFFFFFn;
|
|
384
|
+
const z = hashLen16Mul(y, (a + rotate64((b + k2) & 0xFFFFFFFFFFFFFFFFn, 18) + c) & 0xFFFFFFFFFFFFFFFFn, mul);
|
|
385
|
+
const e = (fetch64(buf, 16) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
386
|
+
const f = fetch64(buf, 24);
|
|
387
|
+
const g = ((y + fetch64(buf, len - 32)) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
388
|
+
const h = ((z + fetch64(buf, len - 24)) * mul) & 0xFFFFFFFFFFFFFFFFn;
|
|
389
|
+
return hashLen16Mul(
|
|
390
|
+
(rotate64((e + f) & 0xFFFFFFFFFFFFFFFFn, 43) + rotate64(g, 30) + h) & 0xFFFFFFFFFFFFFFFFn,
|
|
391
|
+
(e + rotate64((f + a) & 0xFFFFFFFFFFFFFFFFn, 18) + g) & 0xFFFFFFFFFFFFFFFFn,
|
|
392
|
+
mul
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**************************************************************************
|
|
397
|
+
* FINGERPRINT64 (farmhashna::Hash64 - stable across all platforms)
|
|
398
|
+
***************************************************************************/
|
|
399
|
+
|
|
400
|
+
function fingerprint64Internal(buf: Buffer, len: number): bigint {
|
|
401
|
+
if (len <= 16) return hashLen0to16(buf, len);
|
|
402
|
+
if (len <= 32) return hashLen17to32(buf, len);
|
|
403
|
+
if (len <= 64) return naHashLen33to64(buf, len);
|
|
404
|
+
return naHash64(buf, len);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**************************************************************************
|
|
408
|
+
* FARMHASH MK (32-bit)
|
|
409
|
+
***************************************************************************/
|
|
410
|
+
|
|
411
|
+
function mkHash32Len0to4(buf: Buffer, len: number, seed: number = 0): number {
|
|
412
|
+
let b = seed;
|
|
413
|
+
let c = 9;
|
|
414
|
+
for (let i = 0; i < len; i++) {
|
|
415
|
+
const v = buf.readInt8(i);
|
|
416
|
+
b = (Math.imul(b, c1_32) + v) >>> 0;
|
|
417
|
+
c = (c ^ b) >>> 0;
|
|
418
|
+
}
|
|
419
|
+
return fmix(mur(b, mur(len, c)));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function mkHash32Len5to12(buf: Buffer, len: number, seed: number = 0): number {
|
|
423
|
+
let a = len;
|
|
424
|
+
let b = len * 5;
|
|
425
|
+
let c = 9;
|
|
426
|
+
let d = (b + seed) >>> 0;
|
|
427
|
+
a = (a + fetch32AsNumber(buf, 0)) >>> 0;
|
|
428
|
+
b = (b + fetch32AsNumber(buf, len - 4)) >>> 0;
|
|
429
|
+
c = (c + fetch32AsNumber(buf, (len >> 1) & 4)) >>> 0;
|
|
430
|
+
return fmix((seed ^ mur(c, mur(b, mur(a, d)))) >>> 0);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function mkHash32Len13to24(buf: Buffer, len: number, seed: number = 0): number {
|
|
434
|
+
const a = fetch32AsNumber(buf, (len >> 1) - 4);
|
|
435
|
+
const b = fetch32AsNumber(buf, 4);
|
|
436
|
+
const c = fetch32AsNumber(buf, len - 8);
|
|
437
|
+
const d = fetch32AsNumber(buf, len >> 1);
|
|
438
|
+
const e = fetch32AsNumber(buf, 0);
|
|
439
|
+
const f = fetch32AsNumber(buf, len - 4);
|
|
440
|
+
let h = (Math.imul(d, c1_32) + len + seed) >>> 0;
|
|
441
|
+
let a2 = (rotate32(a, 12) + f) >>> 0;
|
|
442
|
+
h = (mur(c, h) + a2) >>> 0;
|
|
443
|
+
a2 = (rotate32(a2, 3) + c) >>> 0;
|
|
444
|
+
h = (mur(e, h) + a2) >>> 0;
|
|
445
|
+
a2 = (rotate32(a2 + f, 12) + d) >>> 0;
|
|
446
|
+
h = (mur((b ^ seed) >>> 0, h) + a2) >>> 0;
|
|
447
|
+
return fmix(h);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function mkHash32(buf: Buffer, len: number): number {
|
|
451
|
+
if (len <= 4) return mkHash32Len0to4(buf, len);
|
|
452
|
+
if (len <= 12) return mkHash32Len5to12(buf, len);
|
|
453
|
+
if (len <= 24) return mkHash32Len13to24(buf, len);
|
|
454
|
+
|
|
455
|
+
let h = len;
|
|
456
|
+
let g = Math.imul(c1_32, len) >>> 0;
|
|
457
|
+
let f = g;
|
|
458
|
+
let a0 = (Math.imul(rotate32(Math.imul(fetch32AsNumber(buf, len - 4), c1_32) >>> 0, 17), c2_32)) >>> 0;
|
|
459
|
+
let a1 = (Math.imul(rotate32(Math.imul(fetch32AsNumber(buf, len - 8), c1_32) >>> 0, 17), c2_32)) >>> 0;
|
|
460
|
+
let a2 = (Math.imul(rotate32(Math.imul(fetch32AsNumber(buf, len - 16), c1_32) >>> 0, 17), c2_32)) >>> 0;
|
|
461
|
+
let a3 = (Math.imul(rotate32(Math.imul(fetch32AsNumber(buf, len - 12), c1_32) >>> 0, 17), c2_32)) >>> 0;
|
|
462
|
+
let a4 = (Math.imul(rotate32(Math.imul(fetch32AsNumber(buf, len - 20), c1_32) >>> 0, 17), c2_32)) >>> 0;
|
|
463
|
+
|
|
464
|
+
h = (h ^ a0) >>> 0;
|
|
465
|
+
h = rotate32(h, 19);
|
|
466
|
+
h = (Math.imul(h, 5) + 0xe6546b64) >>> 0;
|
|
467
|
+
h = (h ^ a2) >>> 0;
|
|
468
|
+
h = rotate32(h, 19);
|
|
469
|
+
h = (Math.imul(h, 5) + 0xe6546b64) >>> 0;
|
|
470
|
+
g = (g ^ a1) >>> 0;
|
|
471
|
+
g = rotate32(g, 19);
|
|
472
|
+
g = (Math.imul(g, 5) + 0xe6546b64) >>> 0;
|
|
473
|
+
g = (g ^ a3) >>> 0;
|
|
474
|
+
g = rotate32(g, 19);
|
|
475
|
+
g = (Math.imul(g, 5) + 0xe6546b64) >>> 0;
|
|
476
|
+
f = (f + a4) >>> 0;
|
|
477
|
+
f = (rotate32(f, 19) + 113) >>> 0;
|
|
478
|
+
|
|
479
|
+
let iters = Math.floor((len - 1) / 20);
|
|
480
|
+
let offset = 0;
|
|
481
|
+
|
|
482
|
+
do {
|
|
483
|
+
const a = fetch32AsNumber(buf, offset);
|
|
484
|
+
const b = fetch32AsNumber(buf, offset + 4);
|
|
485
|
+
const c = fetch32AsNumber(buf, offset + 8);
|
|
486
|
+
const d = fetch32AsNumber(buf, offset + 12);
|
|
487
|
+
const e = fetch32AsNumber(buf, offset + 16);
|
|
488
|
+
h = (h + a) >>> 0;
|
|
489
|
+
g = (g + b) >>> 0;
|
|
490
|
+
f = (f + c) >>> 0;
|
|
491
|
+
h = (mur(d, h) + e) >>> 0;
|
|
492
|
+
g = (mur(c, g) + a) >>> 0;
|
|
493
|
+
f = (mur((b + Math.imul(e, c1_32)) >>> 0, f) + d) >>> 0;
|
|
494
|
+
f = (f + g) >>> 0;
|
|
495
|
+
g = (g + f) >>> 0;
|
|
496
|
+
offset += 20;
|
|
497
|
+
} while (--iters !== 0);
|
|
498
|
+
|
|
499
|
+
g = (Math.imul(rotate32(g, 11), c1_32)) >>> 0;
|
|
500
|
+
g = (Math.imul(rotate32(g, 17), c1_32)) >>> 0;
|
|
501
|
+
f = (Math.imul(rotate32(f, 11), c1_32)) >>> 0;
|
|
502
|
+
f = (Math.imul(rotate32(f, 17), c1_32)) >>> 0;
|
|
503
|
+
h = rotate32((h + g) >>> 0, 19);
|
|
504
|
+
h = (Math.imul(h, 5) + 0xe6546b64) >>> 0;
|
|
505
|
+
h = (Math.imul(rotate32(h, 17), c1_32)) >>> 0;
|
|
506
|
+
h = rotate32((h + f) >>> 0, 19);
|
|
507
|
+
h = (Math.imul(h, 5) + 0xe6546b64) >>> 0;
|
|
508
|
+
h = (Math.imul(rotate32(h, 17), c1_32)) >>> 0;
|
|
509
|
+
return h;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**************************************************************************
|
|
513
|
+
* DEBUG TWEAK (applied in farmhash v3.x with FARMHASH_DEBUG=1)
|
|
514
|
+
***************************************************************************/
|
|
515
|
+
|
|
516
|
+
function debugTweak64(x: bigint): bigint {
|
|
517
|
+
const multiplied = (x * k1) & 0xFFFFFFFFFFFFFFFFn;
|
|
518
|
+
const swapped = bswap64(multiplied);
|
|
519
|
+
return (~swapped) & 0xFFFFFFFFFFFFFFFFn;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function debugTweak32(x: number): number {
|
|
523
|
+
const multiplied = Math.imul(x, c1_32) >>> 0;
|
|
524
|
+
const swapped = bswap32(multiplied);
|
|
525
|
+
return (~swapped) >>> 0;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**************************************************************************
|
|
529
|
+
* PUBLIC API - LEGACY (with DebugTweak, compatible with farmhash v3.3.1)
|
|
530
|
+
***************************************************************************/
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Compute a 64-bit hash compatible with farmhash v3.3.1 hash64()
|
|
534
|
+
* @param input - The string to hash
|
|
535
|
+
* @returns The hash as a decimal string
|
|
536
|
+
*/
|
|
537
|
+
export function legacyHash64(input: string): string {
|
|
538
|
+
const buf = Buffer.from(input);
|
|
539
|
+
const rawHash = xoHash64(buf, buf.length);
|
|
540
|
+
return debugTweak64(rawHash).toString();
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Compute a 64-bit hash compatible with farmhash v3.3.1 hash64()
|
|
545
|
+
* @param input - The string to hash
|
|
546
|
+
* @returns The hash as a BigInt
|
|
547
|
+
*/
|
|
548
|
+
export function legacyHash64BigInt(input: string): bigint {
|
|
549
|
+
const buf = Buffer.from(input);
|
|
550
|
+
const rawHash = xoHash64(buf, buf.length);
|
|
551
|
+
return debugTweak64(rawHash);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Compute a 32-bit hash compatible with farmhash v3.3.1 hash32()
|
|
556
|
+
* @param input - The string to hash
|
|
557
|
+
* @returns The hash as a number
|
|
558
|
+
*/
|
|
559
|
+
export function legacyHash32(input: string): number {
|
|
560
|
+
const buf = Buffer.from(input);
|
|
561
|
+
const rawHash = mkHash32(buf, buf.length);
|
|
562
|
+
return debugTweak32(rawHash);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**************************************************************************
|
|
566
|
+
* PUBLIC API - MODERN (stable fingerprints, same as farmhash v5)
|
|
567
|
+
***************************************************************************/
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Compute a stable 64-bit fingerprint hash
|
|
571
|
+
* This is guaranteed stable across all platforms and versions.
|
|
572
|
+
* @param input - The string to hash
|
|
573
|
+
* @returns The hash as a decimal string
|
|
574
|
+
*/
|
|
575
|
+
export function fingerprint64(input: string): string {
|
|
576
|
+
const buf = Buffer.from(input);
|
|
577
|
+
return fingerprint64Internal(buf, buf.length).toString();
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Compute a stable 64-bit fingerprint hash
|
|
582
|
+
* This is guaranteed stable across all platforms and versions.
|
|
583
|
+
* @param input - The string to hash
|
|
584
|
+
* @returns The hash as a BigInt
|
|
585
|
+
*/
|
|
586
|
+
export function fingerprint64BigInt(input: string): bigint {
|
|
587
|
+
const buf = Buffer.from(input);
|
|
588
|
+
return fingerprint64Internal(buf, buf.length);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Compute a stable 32-bit fingerprint hash
|
|
593
|
+
* This is guaranteed stable across all platforms and versions.
|
|
594
|
+
* @param input - The string to hash
|
|
595
|
+
* @returns The hash as a number
|
|
596
|
+
*/
|
|
597
|
+
export function fingerprint32(input: string): number {
|
|
598
|
+
const buf = Buffer.from(input);
|
|
599
|
+
return mkHash32(buf, buf.length);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**************************************************************************
|
|
603
|
+
* ALIASES
|
|
604
|
+
***************************************************************************/
|
|
605
|
+
|
|
606
|
+
/** Alias for fingerprint64 */
|
|
607
|
+
export const hash64 = fingerprint64;
|
|
608
|
+
|
|
609
|
+
/** Alias for fingerprint64BigInt */
|
|
610
|
+
export const hash64BigInt = fingerprint64BigInt;
|
|
611
|
+
|
|
612
|
+
/** Alias for fingerprint32 */
|
|
613
|
+
export const hash32 = fingerprint32;
|
|
614
|
+
|
|
615
|
+
/**************************************************************************
|
|
616
|
+
* DEFAULT EXPORT
|
|
617
|
+
***************************************************************************/
|
|
618
|
+
|
|
619
|
+
export default {
|
|
620
|
+
// Legacy (farmhash v3.3.1 compatible)
|
|
621
|
+
legacyHash64,
|
|
622
|
+
legacyHash64BigInt,
|
|
623
|
+
legacyHash32,
|
|
624
|
+
// Modern stable fingerprints
|
|
625
|
+
fingerprint64,
|
|
626
|
+
fingerprint64BigInt,
|
|
627
|
+
fingerprint32,
|
|
628
|
+
// Aliases
|
|
629
|
+
hash64,
|
|
630
|
+
hash64BigInt,
|
|
631
|
+
hash32
|
|
632
|
+
};
|