@anonympins/fingerprint 0.7.3 → 0.7.5
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/CHANGELOG.md +41 -0
- package/README.md +1 -1
- package/package.json +109 -107
- package/public/fingerprint-anti-bot.zip +0 -0
- package/src/js/dynamic-wasm.js +218 -218
- package/src/js/fingerprint.client.js +329 -88
- package/src/js/fingerprint.client.obfuscated.js +1 -0
- package/src/js/fingerprint.js +486 -231
- package/src/js/fingerprint.worker.js +81 -0
- package/src/js/library.js +6 -2
- package/src/js/pow.solver.js +2 -3
- package/src/js/problem-manager.js +113 -113
- package/src/js/tests/dynamic-wasm.test.js +77 -77
- package/src/js/tests/fingerprint.client.init.test.js +108 -0
- package/src/js/tests/fingerprint.test.js +153 -3
- package/src/js/tests/threatIntel.test.js +40 -1
- package/src/php/Challenge/ChallengeUtils.php +25 -16
- package/src/php/Config/SecurityProfiles.php +5 -0
- package/src/php/FingerprintEngine.php +186 -37
- package/src/php/Tests/ChallengeUtilsTest.php +469 -453
- package/src/php/Tests/RequestUtilsTest.php +1 -1
- package/src/php/Tests/ThreatIntelTest.php +34 -0
- package/src/php/Utils/RequestUtils.php +257 -127
- package/src/php/WordPress/fingerprint-anti-bot.php +1 -1
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +1 -1
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +1 -1
- package/src/php/WordPress/readme.txt +1 -1
package/src/js/dynamic-wasm.js
CHANGED
|
@@ -1,219 +1,219 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
|
|
3
|
-
function encodeULEB128(val) {
|
|
4
|
-
const bytes = [];
|
|
5
|
-
let num = val >>> 0;
|
|
6
|
-
do {
|
|
7
|
-
let byte = num & 0x7f;
|
|
8
|
-
num >>>= 7;
|
|
9
|
-
if (num !== 0) byte |= 0x80;
|
|
10
|
-
bytes.push(byte);
|
|
11
|
-
} while (num !== 0);
|
|
12
|
-
return bytes;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function encodeSLEB128(val) {
|
|
16
|
-
const bytes = [];
|
|
17
|
-
let num = val | 0;
|
|
18
|
-
while (true) {
|
|
19
|
-
let byte = num & 0x7f;
|
|
20
|
-
num >>= 7;
|
|
21
|
-
if ((num === 0 && (byte & 0x40) === 0) || (num === -1 && (byte & 0x40) !== 0)) {
|
|
22
|
-
bytes.push(byte);
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
bytes.push(byte | 0x80);
|
|
26
|
-
}
|
|
27
|
-
return bytes;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function getRandomNonTrivialOpcodes(tempLocal) {
|
|
31
|
-
const insts = [];
|
|
32
|
-
const ops = [
|
|
33
|
-
// local.get tempLocal, i32.const rand, rotl, local.set tempLocal
|
|
34
|
-
() => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x77, 0x21, tempLocal],
|
|
35
|
-
// local.get tempLocal, i32.const rand, rotr, local.set tempLocal
|
|
36
|
-
() => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x78, 0x21, tempLocal],
|
|
37
|
-
// local.get tempLocal, i32.const rand, xor, local.set tempLocal
|
|
38
|
-
() => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(0, 10000)), 0x73, 0x21, tempLocal],
|
|
39
|
-
// local.get tempLocal, popcnt, i32.const rand, mul, local.set tempLocal
|
|
40
|
-
() => [0x20, tempLocal, 0x69, 0x41, ...encodeSLEB128(crypto.randomInt(1, 1001)), 0x6c, 0x21, tempLocal],
|
|
41
|
-
// local.get tempLocal, clz, local.get tempLocal, ctz, add, local.set tempLocal
|
|
42
|
-
() => [0x20, tempLocal, 0x67, 0x20, tempLocal, 0x68, 0x6a, 0x21, tempLocal]
|
|
43
|
-
];
|
|
44
|
-
const count = crypto.randomInt(2, 5);
|
|
45
|
-
for (let i = 0; i < count; i++) {
|
|
46
|
-
const op = ops[crypto.randomInt(0, ops.length)];
|
|
47
|
-
insts.push(...op());
|
|
48
|
-
}
|
|
49
|
-
return insts;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function generatePolymorphicInstructions(stateLocal = 4, tempLocal = 5) {
|
|
53
|
-
const insts = [];
|
|
54
|
-
|
|
55
|
-
// Initialize tempLocal with a random value
|
|
56
|
-
const initVal = crypto.randomInt(-500, 500);
|
|
57
|
-
insts.push(0x41, ...encodeSLEB128(initVal), 0x21, tempLocal);
|
|
58
|
-
|
|
59
|
-
// Initialize stateLocal to 0
|
|
60
|
-
insts.push(0x41, ...encodeSLEB128(0), 0x21, stateLocal);
|
|
61
|
-
|
|
62
|
-
// Loop & Block for state machine
|
|
63
|
-
insts.push(0x03, 0x40); // loop
|
|
64
|
-
insts.push(0x02, 0x40); // block
|
|
65
|
-
|
|
66
|
-
for (let state = 0; state < 3; state++) {
|
|
67
|
-
insts.push(0x20, stateLocal, 0x41, ...encodeSLEB128(state), 0x46); // state == expected
|
|
68
|
-
insts.push(0x04, 0x40); // if
|
|
69
|
-
insts.push(...getRandomNonTrivialOpcodes(tempLocal));
|
|
70
|
-
insts.push(0x41, ...encodeSLEB128(state + 1), 0x21, stateLocal); // transit to state + 1
|
|
71
|
-
insts.push(0x0c, ...encodeULEB128(2)); // br 2 (targets loop start)
|
|
72
|
-
insts.push(0x0b); // end if
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Fallthrough / Default break (targets block depth 0, which exits the loop)
|
|
76
|
-
insts.push(0x0c, ...encodeULEB128(0));
|
|
77
|
-
|
|
78
|
-
// end block
|
|
79
|
-
insts.push(0x0b);
|
|
80
|
-
// end loop
|
|
81
|
-
insts.push(0x0b);
|
|
82
|
-
|
|
83
|
-
return insts;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export class DynamicWasmGenerator {
|
|
87
|
-
/**
|
|
88
|
-
* Generates a unique polymorphic WebAssembly module containing a custom hash function
|
|
89
|
-
* with randomized constants and control flow variables.
|
|
90
|
-
* @param {object} constants - Custom seed, multiplier and adder.
|
|
91
|
-
* @returns {Buffer} Valid WebAssembly binary buffer.
|
|
92
|
-
*/
|
|
93
|
-
static generate(constants) {
|
|
94
|
-
const { seed, multiplier, adder } = constants;
|
|
95
|
-
|
|
96
|
-
const preLoopPoly = generatePolymorphicInstructions(4, 5);
|
|
97
|
-
const midLoopPoly = generatePolymorphicInstructions(4, 5);
|
|
98
|
-
|
|
99
|
-
const inst = [
|
|
100
|
-
0x01, 0x06, 0x7f, // Locals: 1 entry of 6 locals of type i32
|
|
101
|
-
...preLoopPoly,
|
|
102
|
-
// h = seed
|
|
103
|
-
0x41, ...encodeSLEB128(seed),
|
|
104
|
-
0x21, 0x03,
|
|
105
|
-
// i = 0
|
|
106
|
-
0x41, 0x00,
|
|
107
|
-
0x21, 0x02,
|
|
108
|
-
|
|
109
|
-
// block
|
|
110
|
-
0x02, 0x40,
|
|
111
|
-
// loop
|
|
112
|
-
0x03, 0x40,
|
|
113
|
-
|
|
114
|
-
// if i >= len break
|
|
115
|
-
0x20, 0x02,
|
|
116
|
-
0x20, 0x01,
|
|
117
|
-
0x4f,
|
|
118
|
-
0x0d, 0x01,
|
|
119
|
-
|
|
120
|
-
// byte = load8_u(ptr + i)
|
|
121
|
-
0x20, 0x00,
|
|
122
|
-
0x20, 0x02,
|
|
123
|
-
0x6a,
|
|
124
|
-
0x2d, 0x00, 0x00,
|
|
125
|
-
|
|
126
|
-
// h = h ^ byte
|
|
127
|
-
0x20, 0x03,
|
|
128
|
-
0x73,
|
|
129
|
-
|
|
130
|
-
// h = h * multiplier
|
|
131
|
-
0x41, ...encodeSLEB128(multiplier),
|
|
132
|
-
0x6c,
|
|
133
|
-
|
|
134
|
-
// h = h + adder
|
|
135
|
-
0x41, ...encodeSLEB128(adder),
|
|
136
|
-
0x6a,
|
|
137
|
-
|
|
138
|
-
// local.set 3
|
|
139
|
-
0x21, 0x03,
|
|
140
|
-
...midLoopPoly,
|
|
141
|
-
|
|
142
|
-
// i = i + 1
|
|
143
|
-
0x20, 0x02,
|
|
144
|
-
0x41, 0x01,
|
|
145
|
-
0x6a,
|
|
146
|
-
0x21, 0x02,
|
|
147
|
-
|
|
148
|
-
// br 0
|
|
149
|
-
0x0c, 0x00,
|
|
150
|
-
|
|
151
|
-
0x0b, // end loop
|
|
152
|
-
0x0b, // end block
|
|
153
|
-
|
|
154
|
-
// return h
|
|
155
|
-
0x20, 0x03,
|
|
156
|
-
0x0b // end function
|
|
157
|
-
];
|
|
158
|
-
|
|
159
|
-
const funcBody = [
|
|
160
|
-
...encodeULEB128(inst.length),
|
|
161
|
-
...inst
|
|
162
|
-
];
|
|
163
|
-
|
|
164
|
-
const codeSectionPayload = [
|
|
165
|
-
...encodeULEB128(1),
|
|
166
|
-
...funcBody
|
|
167
|
-
];
|
|
168
|
-
|
|
169
|
-
const codeSection = [
|
|
170
|
-
0x0a,
|
|
171
|
-
...encodeULEB128(codeSectionPayload.length),
|
|
172
|
-
...codeSectionPayload
|
|
173
|
-
];
|
|
174
|
-
|
|
175
|
-
const typeSection = [
|
|
176
|
-
0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f
|
|
177
|
-
];
|
|
178
|
-
|
|
179
|
-
const funcSection = [
|
|
180
|
-
0x03, 0x02, 0x01, 0x00
|
|
181
|
-
];
|
|
182
|
-
|
|
183
|
-
const memSection = [
|
|
184
|
-
0x05, 0x03, 0x01, 0x00, 0x01
|
|
185
|
-
];
|
|
186
|
-
|
|
187
|
-
const exportSection = [
|
|
188
|
-
0x07, 0x11, 0x02, 0x04, 0x68, 0x61, 0x73, 0x68, 0x00, 0x00, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00
|
|
189
|
-
];
|
|
190
|
-
|
|
191
|
-
const wasm = [
|
|
192
|
-
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
|
|
193
|
-
...typeSection,
|
|
194
|
-
...funcSection,
|
|
195
|
-
...memSection,
|
|
196
|
-
...exportSection,
|
|
197
|
-
...codeSection
|
|
198
|
-
];
|
|
199
|
-
|
|
200
|
-
return Buffer.from(wasm);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Pure JavaScript fallback equivalent of the custom polymorphic hash.
|
|
205
|
-
* @param {string} str Input string.
|
|
206
|
-
* @param {object} constants Parameters.
|
|
207
|
-
* @returns {number} 32-bit unsigned integer hash.
|
|
208
|
-
*/
|
|
209
|
-
static hashJs(str, constants) {
|
|
210
|
-
const { seed, multiplier, adder } = constants;
|
|
211
|
-
let h = seed | 0;
|
|
212
|
-
for (let i = 0; i < str.length; i++) {
|
|
213
|
-
const byte = str.charCodeAt(i) & 0xff;
|
|
214
|
-
h = h ^ byte;
|
|
215
|
-
h = Math.imul(h, multiplier) + adder;
|
|
216
|
-
}
|
|
217
|
-
return h >>> 0;
|
|
218
|
-
}
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
|
|
3
|
+
function encodeULEB128(val) {
|
|
4
|
+
const bytes = [];
|
|
5
|
+
let num = val >>> 0;
|
|
6
|
+
do {
|
|
7
|
+
let byte = num & 0x7f;
|
|
8
|
+
num >>>= 7;
|
|
9
|
+
if (num !== 0) byte |= 0x80;
|
|
10
|
+
bytes.push(byte);
|
|
11
|
+
} while (num !== 0);
|
|
12
|
+
return bytes;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function encodeSLEB128(val) {
|
|
16
|
+
const bytes = [];
|
|
17
|
+
let num = val | 0;
|
|
18
|
+
while (true) {
|
|
19
|
+
let byte = num & 0x7f;
|
|
20
|
+
num >>= 7;
|
|
21
|
+
if ((num === 0 && (byte & 0x40) === 0) || (num === -1 && (byte & 0x40) !== 0)) {
|
|
22
|
+
bytes.push(byte);
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
bytes.push(byte | 0x80);
|
|
26
|
+
}
|
|
27
|
+
return bytes;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getRandomNonTrivialOpcodes(tempLocal) {
|
|
31
|
+
const insts = [];
|
|
32
|
+
const ops = [
|
|
33
|
+
// local.get tempLocal, i32.const rand, rotl, local.set tempLocal
|
|
34
|
+
() => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x77, 0x21, tempLocal],
|
|
35
|
+
// local.get tempLocal, i32.const rand, rotr, local.set tempLocal
|
|
36
|
+
() => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x78, 0x21, tempLocal],
|
|
37
|
+
// local.get tempLocal, i32.const rand, xor, local.set tempLocal
|
|
38
|
+
() => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(0, 10000)), 0x73, 0x21, tempLocal],
|
|
39
|
+
// local.get tempLocal, popcnt, i32.const rand, mul, local.set tempLocal
|
|
40
|
+
() => [0x20, tempLocal, 0x69, 0x41, ...encodeSLEB128(crypto.randomInt(1, 1001)), 0x6c, 0x21, tempLocal],
|
|
41
|
+
// local.get tempLocal, clz, local.get tempLocal, ctz, add, local.set tempLocal
|
|
42
|
+
() => [0x20, tempLocal, 0x67, 0x20, tempLocal, 0x68, 0x6a, 0x21, tempLocal]
|
|
43
|
+
];
|
|
44
|
+
const count = crypto.randomInt(2, 5);
|
|
45
|
+
for (let i = 0; i < count; i++) {
|
|
46
|
+
const op = ops[crypto.randomInt(0, ops.length)];
|
|
47
|
+
insts.push(...op());
|
|
48
|
+
}
|
|
49
|
+
return insts;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function generatePolymorphicInstructions(stateLocal = 4, tempLocal = 5) {
|
|
53
|
+
const insts = [];
|
|
54
|
+
|
|
55
|
+
// Initialize tempLocal with a random value
|
|
56
|
+
const initVal = crypto.randomInt(-500, 500);
|
|
57
|
+
insts.push(0x41, ...encodeSLEB128(initVal), 0x21, tempLocal);
|
|
58
|
+
|
|
59
|
+
// Initialize stateLocal to 0
|
|
60
|
+
insts.push(0x41, ...encodeSLEB128(0), 0x21, stateLocal);
|
|
61
|
+
|
|
62
|
+
// Loop & Block for state machine
|
|
63
|
+
insts.push(0x03, 0x40); // loop
|
|
64
|
+
insts.push(0x02, 0x40); // block
|
|
65
|
+
|
|
66
|
+
for (let state = 0; state < 3; state++) {
|
|
67
|
+
insts.push(0x20, stateLocal, 0x41, ...encodeSLEB128(state), 0x46); // state == expected
|
|
68
|
+
insts.push(0x04, 0x40); // if
|
|
69
|
+
insts.push(...getRandomNonTrivialOpcodes(tempLocal));
|
|
70
|
+
insts.push(0x41, ...encodeSLEB128(state + 1), 0x21, stateLocal); // transit to state + 1
|
|
71
|
+
insts.push(0x0c, ...encodeULEB128(2)); // br 2 (targets loop start)
|
|
72
|
+
insts.push(0x0b); // end if
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Fallthrough / Default break (targets block depth 0, which exits the loop)
|
|
76
|
+
insts.push(0x0c, ...encodeULEB128(0));
|
|
77
|
+
|
|
78
|
+
// end block
|
|
79
|
+
insts.push(0x0b);
|
|
80
|
+
// end loop
|
|
81
|
+
insts.push(0x0b);
|
|
82
|
+
|
|
83
|
+
return insts;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class DynamicWasmGenerator {
|
|
87
|
+
/**
|
|
88
|
+
* Generates a unique polymorphic WebAssembly module containing a custom hash function
|
|
89
|
+
* with randomized constants and control flow variables.
|
|
90
|
+
* @param {object} constants - Custom seed, multiplier and adder.
|
|
91
|
+
* @returns {Buffer} Valid WebAssembly binary buffer.
|
|
92
|
+
*/
|
|
93
|
+
static generate(constants) {
|
|
94
|
+
const { seed, multiplier, adder } = constants;
|
|
95
|
+
|
|
96
|
+
const preLoopPoly = generatePolymorphicInstructions(4, 5);
|
|
97
|
+
const midLoopPoly = generatePolymorphicInstructions(4, 5);
|
|
98
|
+
|
|
99
|
+
const inst = [
|
|
100
|
+
0x01, 0x06, 0x7f, // Locals: 1 entry of 6 locals of type i32
|
|
101
|
+
...preLoopPoly,
|
|
102
|
+
// h = seed
|
|
103
|
+
0x41, ...encodeSLEB128(seed),
|
|
104
|
+
0x21, 0x03,
|
|
105
|
+
// i = 0
|
|
106
|
+
0x41, 0x00,
|
|
107
|
+
0x21, 0x02,
|
|
108
|
+
|
|
109
|
+
// block
|
|
110
|
+
0x02, 0x40,
|
|
111
|
+
// loop
|
|
112
|
+
0x03, 0x40,
|
|
113
|
+
|
|
114
|
+
// if i >= len break
|
|
115
|
+
0x20, 0x02,
|
|
116
|
+
0x20, 0x01,
|
|
117
|
+
0x4f,
|
|
118
|
+
0x0d, 0x01,
|
|
119
|
+
|
|
120
|
+
// byte = load8_u(ptr + i)
|
|
121
|
+
0x20, 0x00,
|
|
122
|
+
0x20, 0x02,
|
|
123
|
+
0x6a,
|
|
124
|
+
0x2d, 0x00, 0x00,
|
|
125
|
+
|
|
126
|
+
// h = h ^ byte
|
|
127
|
+
0x20, 0x03,
|
|
128
|
+
0x73,
|
|
129
|
+
|
|
130
|
+
// h = h * multiplier
|
|
131
|
+
0x41, ...encodeSLEB128(multiplier),
|
|
132
|
+
0x6c,
|
|
133
|
+
|
|
134
|
+
// h = h + adder
|
|
135
|
+
0x41, ...encodeSLEB128(adder),
|
|
136
|
+
0x6a,
|
|
137
|
+
|
|
138
|
+
// local.set 3
|
|
139
|
+
0x21, 0x03,
|
|
140
|
+
...midLoopPoly,
|
|
141
|
+
|
|
142
|
+
// i = i + 1
|
|
143
|
+
0x20, 0x02,
|
|
144
|
+
0x41, 0x01,
|
|
145
|
+
0x6a,
|
|
146
|
+
0x21, 0x02,
|
|
147
|
+
|
|
148
|
+
// br 0
|
|
149
|
+
0x0c, 0x00,
|
|
150
|
+
|
|
151
|
+
0x0b, // end loop
|
|
152
|
+
0x0b, // end block
|
|
153
|
+
|
|
154
|
+
// return h
|
|
155
|
+
0x20, 0x03,
|
|
156
|
+
0x0b // end function
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
const funcBody = [
|
|
160
|
+
...encodeULEB128(inst.length),
|
|
161
|
+
...inst
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
const codeSectionPayload = [
|
|
165
|
+
...encodeULEB128(1),
|
|
166
|
+
...funcBody
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const codeSection = [
|
|
170
|
+
0x0a,
|
|
171
|
+
...encodeULEB128(codeSectionPayload.length),
|
|
172
|
+
...codeSectionPayload
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
const typeSection = [
|
|
176
|
+
0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
const funcSection = [
|
|
180
|
+
0x03, 0x02, 0x01, 0x00
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
const memSection = [
|
|
184
|
+
0x05, 0x03, 0x01, 0x00, 0x01
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
const exportSection = [
|
|
188
|
+
0x07, 0x11, 0x02, 0x04, 0x68, 0x61, 0x73, 0x68, 0x00, 0x00, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
const wasm = [
|
|
192
|
+
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
|
|
193
|
+
...typeSection,
|
|
194
|
+
...funcSection,
|
|
195
|
+
...memSection,
|
|
196
|
+
...exportSection,
|
|
197
|
+
...codeSection
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
return Buffer.from(wasm);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Pure JavaScript fallback equivalent of the custom polymorphic hash.
|
|
205
|
+
* @param {string} str Input string.
|
|
206
|
+
* @param {object} constants Parameters.
|
|
207
|
+
* @returns {number} 32-bit unsigned integer hash.
|
|
208
|
+
*/
|
|
209
|
+
static hashJs(str, constants) {
|
|
210
|
+
const { seed, multiplier, adder } = constants;
|
|
211
|
+
let h = seed | 0;
|
|
212
|
+
for (let i = 0; i < str.length; i++) {
|
|
213
|
+
const byte = str.charCodeAt(i) & 0xff;
|
|
214
|
+
h = h ^ byte;
|
|
215
|
+
h = Math.imul(h, multiplier) + adder;
|
|
216
|
+
}
|
|
217
|
+
return h >>> 0;
|
|
218
|
+
}
|
|
219
219
|
}
|