sekant-intercept-js 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 +231 -0
- package/NOTICE +15 -0
- package/README.md +327 -0
- package/dist/sekant-intercept.browser.mjs +15 -0
- package/dist/sekant-intercept.node.mjs +15 -0
- package/package.json +69 -0
- package/src/ahocorasickEngine.mjs +229 -0
- package/src/elfModule.mjs +306 -0
- package/src/hashModule.mjs +284 -0
- package/src/index.js +9 -0
- package/src/interceptCustomModules.mjs +230 -0
- package/src/interceptScanner.mjs +865 -0
- package/src/mathModule.mjs +506 -0
- package/src/peModule.mjs +295 -0
- package/src/performanceInstrumentation.mjs +172 -0
- package/src/sharedUtils.mjs +127 -0
- package/src/stringModule.mjs +43 -0
- package/src/timeModule.mjs +19 -0
- package/src/yaraConditionParser.mjs +1083 -0
- package/src/yaraConditionsMatch.mjs +1373 -0
- package/src/yaraRuleCompiler.mjs +448 -0
- package/src/yaraStringMatch.mjs +449 -0
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Rishi Kant (Sekant Security Inc.)
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* YARA Math Module Implementation
|
|
19
|
+
*
|
|
20
|
+
* Provides mathematical and statistical functions for YARA rules.
|
|
21
|
+
* This implementation matches the official YARA math module API.
|
|
22
|
+
*
|
|
23
|
+
* Supported functions:
|
|
24
|
+
* - entropy(offset, size) : Calculate Shannon entropy
|
|
25
|
+
* - entropy(string) : Calculate Shannon entropy of string
|
|
26
|
+
* - monte_carlo_pi(offset, size) : Monte Carlo estimation of Pi
|
|
27
|
+
* - serial_correlation(offset, size) : Serial correlation coefficient
|
|
28
|
+
* - mean(offset, size) : Arithmetic mean of bytes
|
|
29
|
+
* - deviation(offset, size) : Standard deviation of bytes
|
|
30
|
+
* - min(offset, size) : Minimum byte value
|
|
31
|
+
* - max(offset, size) : Maximum byte value
|
|
32
|
+
* - abs(value) : Absolute value
|
|
33
|
+
* - count(byte, offset, size) : Count occurrences of byte
|
|
34
|
+
* - percentage(byte, offset, size) : Percentage of byte occurrences
|
|
35
|
+
* - mode(offset, size) : Most common byte value
|
|
36
|
+
* - to_number(bool) : Convert boolean to number
|
|
37
|
+
* - in_range(value, lower, upper): Check if value is in range
|
|
38
|
+
*
|
|
39
|
+
* All statistical functions operate on byte values (0-255).
|
|
40
|
+
*
|
|
41
|
+
* @see https://yara.readthedocs.io/en/stable/modules/math.html
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Convert string to Uint8Array
|
|
46
|
+
* @param {string} str
|
|
47
|
+
* @returns {Uint8Array}
|
|
48
|
+
*/
|
|
49
|
+
function stringToBytes(str) {
|
|
50
|
+
const encoder = new TextEncoder();
|
|
51
|
+
return encoder.encode(str);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Calculate Shannon entropy of data
|
|
56
|
+
* Entropy measures the randomness/unpredictability of data
|
|
57
|
+
* @param {Uint8Array} data
|
|
58
|
+
* @returns {number} Entropy value (0 to 8 bits per byte)
|
|
59
|
+
*/
|
|
60
|
+
function calculateEntropy(data) {
|
|
61
|
+
if (data.length === 0) return 0.0;
|
|
62
|
+
|
|
63
|
+
// Count frequency of each byte value (0-255)
|
|
64
|
+
const frequency = new Uint32Array(256);
|
|
65
|
+
for (let i = 0; i < data.length; i++) {
|
|
66
|
+
frequency[data[i]]++;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Calculate entropy
|
|
70
|
+
let entropy = 0.0;
|
|
71
|
+
const length = data.length;
|
|
72
|
+
|
|
73
|
+
for (let i = 0; i < 256; i++) {
|
|
74
|
+
if (frequency[i] > 0) {
|
|
75
|
+
const probability = frequency[i] / length;
|
|
76
|
+
entropy -= probability * Math.log2(probability);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return entropy;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Calculate arithmetic mean of byte values
|
|
85
|
+
* @param {Uint8Array} data
|
|
86
|
+
* @returns {number} Mean value (0 to 255)
|
|
87
|
+
*/
|
|
88
|
+
function calculateMean(data) {
|
|
89
|
+
if (data.length === 0) return 0.0;
|
|
90
|
+
|
|
91
|
+
let sum = 0;
|
|
92
|
+
for (let i = 0; i < data.length; i++) {
|
|
93
|
+
sum += data[i];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return sum / data.length;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Calculate standard deviation of byte values
|
|
101
|
+
* @param {Uint8Array} data
|
|
102
|
+
* @returns {number} Standard deviation
|
|
103
|
+
*/
|
|
104
|
+
function calculateDeviation(data, mean) {
|
|
105
|
+
if (data.length === 0) return 0.0;
|
|
106
|
+
|
|
107
|
+
let sumSquaredDiff = 0;
|
|
108
|
+
|
|
109
|
+
for (let i = 0; i < data.length; i++) {
|
|
110
|
+
const diff = data[i] - mean;
|
|
111
|
+
sumSquaredDiff += diff * diff;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return Math.sqrt(sumSquaredDiff / data.length);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Monte Carlo estimation of Pi using byte pairs as coordinates
|
|
119
|
+
* @param {Uint8Array} data
|
|
120
|
+
* @returns {number} Estimated value of Pi (typically close to 3.14159...)
|
|
121
|
+
*/
|
|
122
|
+
function calculateMonteCarloPI(data) {
|
|
123
|
+
if (data.length < 2) return 0.0;
|
|
124
|
+
|
|
125
|
+
let insideCircle = 0;
|
|
126
|
+
let totalPoints = 0;
|
|
127
|
+
|
|
128
|
+
// Use consecutive byte pairs as (x, y) coordinates
|
|
129
|
+
for (let i = 0; i < data.length - 1; i += 2) {
|
|
130
|
+
// Normalize coordinates to [-1, 1] range
|
|
131
|
+
const x = (data[i] / 255.0) * 2.0 - 1.0;
|
|
132
|
+
const y = (data[i + 1] / 255.0) * 2.0 - 1.0;
|
|
133
|
+
|
|
134
|
+
// Check if point is inside unit circle
|
|
135
|
+
if (x * x + y * y <= 1.0) {
|
|
136
|
+
insideCircle++;
|
|
137
|
+
}
|
|
138
|
+
totalPoints++;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (totalPoints === 0) return 0.0;
|
|
142
|
+
|
|
143
|
+
// Pi ≈ 4 * (points inside circle / total points)
|
|
144
|
+
return (4.0 * insideCircle) / totalPoints;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Calculate serial correlation coefficient
|
|
149
|
+
* Measures correlation between consecutive bytes
|
|
150
|
+
* @param {Uint8Array} data
|
|
151
|
+
* @returns {number} Correlation coefficient (-1 to 1)
|
|
152
|
+
*/
|
|
153
|
+
function calculateSerialCorrelation(data) {
|
|
154
|
+
if (data.length < 2) return 0.0;
|
|
155
|
+
|
|
156
|
+
const mean = calculateMean(data);
|
|
157
|
+
|
|
158
|
+
let numerator = 0;
|
|
159
|
+
let denominator = 0;
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < data.length - 1; i++) {
|
|
162
|
+
numerator += (data[i] - mean) * (data[i + 1] - mean);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (let i = 0; i < data.length; i++) {
|
|
166
|
+
const diff = data[i] - mean;
|
|
167
|
+
denominator += diff * diff;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (denominator === 0) return 0.0;
|
|
171
|
+
|
|
172
|
+
return numerator / denominator;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Find minimum byte value
|
|
177
|
+
* @param {Array<number>} data
|
|
178
|
+
* @returns {number} Minimum value
|
|
179
|
+
*/
|
|
180
|
+
function findMin(...data) {
|
|
181
|
+
if (data.length === 0) throw new Error("No data provided");
|
|
182
|
+
|
|
183
|
+
return Math.min(...data);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Find maximum byte value
|
|
188
|
+
* @param {Array<number>} data
|
|
189
|
+
* @returns {number} Maximum value
|
|
190
|
+
*/
|
|
191
|
+
function findMax(...data) {
|
|
192
|
+
if (data.length === 0) throw new Error("No data provided");
|
|
193
|
+
|
|
194
|
+
return Math.max(...data);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Count occurrences of a specific byte value
|
|
199
|
+
* @param {number} byte - Byte value to count (0-255)
|
|
200
|
+
* @param {Uint8Array} data
|
|
201
|
+
* @returns {number} Count of occurrences
|
|
202
|
+
*/
|
|
203
|
+
function countByte(byte, data) {
|
|
204
|
+
let count = 0;
|
|
205
|
+
for (let i = 0; i < data.length; i++) {
|
|
206
|
+
if (data[i] === byte) {
|
|
207
|
+
count++;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return count;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Calculate percentage of a specific byte value
|
|
215
|
+
* @param {number} byte - Byte value (0-255)
|
|
216
|
+
* @param {Uint8Array} data
|
|
217
|
+
* @returns {number} Percentage (0.0 to 1.0)
|
|
218
|
+
*/
|
|
219
|
+
function percentageByte(byte, data) {
|
|
220
|
+
if (data.length === 0) return 0.0;
|
|
221
|
+
return countByte(byte, data) / data.length;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Find the mode (most common byte value)
|
|
226
|
+
* @param {Uint8Array} data
|
|
227
|
+
* @returns {number} Most common byte value (0-255)
|
|
228
|
+
*/
|
|
229
|
+
function findMode(data) {
|
|
230
|
+
if (data.length === 0) return 0;
|
|
231
|
+
|
|
232
|
+
const frequency = new Uint32Array(256);
|
|
233
|
+
for (let i = 0; i < data.length; i++) {
|
|
234
|
+
frequency[data[i]]++;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
let maxFreq = 0;
|
|
238
|
+
let mode = 0;
|
|
239
|
+
|
|
240
|
+
for (let i = 0; i < 256; i++) {
|
|
241
|
+
if (frequency[i] > maxFreq) {
|
|
242
|
+
maxFreq = frequency[i];
|
|
243
|
+
mode = i;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return mode;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Create a math module instance for a specific data buffer
|
|
252
|
+
* @param {Uint8Array} data - The data to perform mathematical operations on
|
|
253
|
+
* @returns {Object} Math module with all YARA math functions
|
|
254
|
+
*/
|
|
255
|
+
export function createMathModule(data) {
|
|
256
|
+
if (!data || !(data instanceof Uint8Array)) {
|
|
257
|
+
throw new Error("Math module requires a Uint8Array data buffer");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
/**
|
|
262
|
+
* Calculate Shannon entropy
|
|
263
|
+
* Can be called with (offset, size) or (string)
|
|
264
|
+
*/
|
|
265
|
+
entropy: function (...args) {
|
|
266
|
+
if (args.length === 1 && typeof args[0] === "string") {
|
|
267
|
+
// entropy(string)
|
|
268
|
+
const bytes = stringToBytes(args[0]);
|
|
269
|
+
return calculateEntropy(bytes);
|
|
270
|
+
} else if (args.length === 2) {
|
|
271
|
+
// entropy(offset, size)
|
|
272
|
+
const offset = args[0];
|
|
273
|
+
const size = args[1];
|
|
274
|
+
if (offset < 0 || size < 0) {
|
|
275
|
+
throw new Error(`Invalid range: offset=${offset}, size=${size}, data.length=${data.length}`);
|
|
276
|
+
}
|
|
277
|
+
if (offset >= data.length || offset + size > data.length) return 0;
|
|
278
|
+
const slice = data.slice(offset, offset + size);
|
|
279
|
+
if (slice.length === 0) return 0;
|
|
280
|
+
return calculateEntropy(slice);
|
|
281
|
+
} else {
|
|
282
|
+
throw new Error("entropy() requires either (offset, size) or (string)");
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Monte Carlo estimation of Pi
|
|
288
|
+
* Called with (offset, size) or (string)
|
|
289
|
+
*/
|
|
290
|
+
monte_carlo_pi: function (...args) {
|
|
291
|
+
if (args.length === 1 && typeof args[0] === "string") {
|
|
292
|
+
// monte_carlo_pi(string)
|
|
293
|
+
const bytes = stringToBytes(args[0]);
|
|
294
|
+
return calculateMonteCarloPI(bytes);
|
|
295
|
+
} else if (args.length === 2) {
|
|
296
|
+
const [offset, size] = args;
|
|
297
|
+
if (offset < 0 || size < 0) {
|
|
298
|
+
throw new Error(`Invalid range: offset=${offset}, size=${size}, data.length=${data.length}`);
|
|
299
|
+
}
|
|
300
|
+
if (offset >= data.length || offset + size > data.length) return 0;
|
|
301
|
+
const slice = data.slice(offset, offset + size);
|
|
302
|
+
if (slice.length === 0) return 0;
|
|
303
|
+
return calculateMonteCarloPI(slice);
|
|
304
|
+
} else {
|
|
305
|
+
throw new Error("monte_carlo_pi() requires (offset, size)");
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Serial correlation coefficient
|
|
311
|
+
* Called with (offset, size) or (string)
|
|
312
|
+
*/
|
|
313
|
+
serial_correlation: function (...args) {
|
|
314
|
+
if (args.length === 1 && typeof args[0] === "string") {
|
|
315
|
+
// monte_carlo_pi(string)
|
|
316
|
+
const bytes = stringToBytes(args[0]);
|
|
317
|
+
return calculateSerialCorrelation(bytes);
|
|
318
|
+
} else if (args.length === 2) {
|
|
319
|
+
const [offset, size] = args;
|
|
320
|
+
if (offset < 0 || size < 0) {
|
|
321
|
+
throw new Error(`Invalid range: offset=${offset}, size=${size}, data.length=${data.length}`);
|
|
322
|
+
}
|
|
323
|
+
if (offset >= data.length || offset + size > data.length) return 0;
|
|
324
|
+
const slice = data.slice(offset, offset + size);
|
|
325
|
+
if (slice.length === 0) return 0;
|
|
326
|
+
return calculateSerialCorrelation(slice);
|
|
327
|
+
} else {
|
|
328
|
+
throw new Error("serial_correlation() requires (offset, size)");
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Arithmetic mean of bytes
|
|
334
|
+
* Called with (offset, size) or (string)
|
|
335
|
+
*/
|
|
336
|
+
mean: function (...args) {
|
|
337
|
+
if (args.length === 1 && typeof args[0] === "string") {
|
|
338
|
+
// monte_carlo_pi(string)
|
|
339
|
+
const bytes = stringToBytes(args[0]);
|
|
340
|
+
return calculateMean(bytes);
|
|
341
|
+
} else if (args.length === 2) {
|
|
342
|
+
const [offset, size] = args;
|
|
343
|
+
if (offset < 0 || size < 0) {
|
|
344
|
+
throw new Error(`Invalid range: offset=${offset}, size=${size}, data.length=${data.length}`);
|
|
345
|
+
}
|
|
346
|
+
if (offset >= data.length || offset + size > data.length) return 0;
|
|
347
|
+
const slice = data.slice(offset, offset + size);
|
|
348
|
+
if (slice.length === 0) return 0;
|
|
349
|
+
return calculateMean(slice);
|
|
350
|
+
} else {
|
|
351
|
+
throw new Error("mean() requires (offset, size)");
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Standard deviation of bytes
|
|
357
|
+
* Called with (offset, size, mean) or (string)
|
|
358
|
+
*/
|
|
359
|
+
deviation: function (...args) {
|
|
360
|
+
if (args.length === 2 && typeof args[0] === "string") {
|
|
361
|
+
// deviation(string)
|
|
362
|
+
const [str, mean] = args;
|
|
363
|
+
const bytes = stringToBytes(str);
|
|
364
|
+
return calculateDeviation(bytes, mean);
|
|
365
|
+
} else if (args.length === 3) {
|
|
366
|
+
const [offset, size, mean] = args;
|
|
367
|
+
if (offset < 0 || size < 0) {
|
|
368
|
+
throw new Error(`Invalid range: offset=${offset}, size=${size}, data.length=${data.length}`);
|
|
369
|
+
}
|
|
370
|
+
if (offset >= data.length || offset + size > data.length) return 0;
|
|
371
|
+
const slice = data.slice(offset, offset + size);
|
|
372
|
+
if (slice.length === 0) return 0;
|
|
373
|
+
return calculateDeviation(slice, mean);
|
|
374
|
+
} else {
|
|
375
|
+
throw new Error("deviation() requires (offset, size, mean)");
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Minimum byte value
|
|
381
|
+
* Called with (offset, size)
|
|
382
|
+
*/
|
|
383
|
+
min: function (a, b) {
|
|
384
|
+
return findMin(a, b);
|
|
385
|
+
},
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Maximum byte value
|
|
389
|
+
* Called with (offset, size)
|
|
390
|
+
*/
|
|
391
|
+
max: function (a, b) {
|
|
392
|
+
return findMax(a, b);
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Count occurrences of a byte
|
|
397
|
+
* Called with (byte, offset, size)
|
|
398
|
+
*/
|
|
399
|
+
count: function (byte, offset, size) {
|
|
400
|
+
if (byte < 0 || byte > 255) {
|
|
401
|
+
throw new Error(`Invalid byte value: ${byte} (must be 0-255)`);
|
|
402
|
+
}
|
|
403
|
+
if (offset < 0 || size < 0) {
|
|
404
|
+
throw new Error(`Invalid range: offset=${offset}, size=${size}, data.length=${data.length}`);
|
|
405
|
+
}
|
|
406
|
+
const slice = data.slice(offset, offset + size);
|
|
407
|
+
if (slice.length === 0) return 0;
|
|
408
|
+
return countByte(byte, slice);
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Percentage of a byte value
|
|
413
|
+
* Called with (byte, offset, size)
|
|
414
|
+
*/
|
|
415
|
+
percentage: function (byte, offset, size) {
|
|
416
|
+
return this.count(byte, offset, size) / size;
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Most common byte value (mode)
|
|
421
|
+
* Called with (offset, size)
|
|
422
|
+
*/
|
|
423
|
+
mode: function (offset, size) {
|
|
424
|
+
if (offset < 0 || size < 0) {
|
|
425
|
+
throw new Error(`Invalid range: offset=${offset}, size=${size}, data.length=${data.length}`);
|
|
426
|
+
}
|
|
427
|
+
const slice = data.slice(offset, offset + size);
|
|
428
|
+
if (slice.length === 0) return 0;
|
|
429
|
+
return findMode(slice);
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Absolute value
|
|
434
|
+
* Called with (value)
|
|
435
|
+
*/
|
|
436
|
+
abs: function (value) {
|
|
437
|
+
return Math.abs(value);
|
|
438
|
+
},
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Convert boolean to number
|
|
442
|
+
* Called with (bool)
|
|
443
|
+
*/
|
|
444
|
+
to_number: function (bool) {
|
|
445
|
+
return bool ? 1 : 0;
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Check if value is in range
|
|
450
|
+
* Called with (value, lower, upper)
|
|
451
|
+
*/
|
|
452
|
+
in_range: function (value, lower, upper) {
|
|
453
|
+
return value >= lower && value <= upper;
|
|
454
|
+
},
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Standalone math functions that don't require a data buffer
|
|
460
|
+
*/
|
|
461
|
+
export const math = {
|
|
462
|
+
/**
|
|
463
|
+
* Calculate entropy of a string
|
|
464
|
+
* @param {string} str
|
|
465
|
+
* @returns {number} Entropy value
|
|
466
|
+
*/
|
|
467
|
+
entropy: function (str) {
|
|
468
|
+
const bytes = stringToBytes(str);
|
|
469
|
+
return calculateEntropy(bytes);
|
|
470
|
+
},
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Absolute value
|
|
474
|
+
* @param {number} value
|
|
475
|
+
* @returns {number}
|
|
476
|
+
*/
|
|
477
|
+
abs: function (value) {
|
|
478
|
+
return Math.abs(value);
|
|
479
|
+
},
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Convert boolean to number
|
|
483
|
+
* @param {boolean} bool
|
|
484
|
+
* @returns {number} 1 for true, 0 for false
|
|
485
|
+
*/
|
|
486
|
+
to_number: function (bool) {
|
|
487
|
+
return bool ? 1 : 0;
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Check if value is in range [lower, upper]
|
|
492
|
+
* @param {number} value
|
|
493
|
+
* @param {number} lower
|
|
494
|
+
* @param {number} upper
|
|
495
|
+
* @returns {boolean}
|
|
496
|
+
*/
|
|
497
|
+
in_range: function (value, lower, upper) {
|
|
498
|
+
return value >= lower && value <= upper;
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
// Export for convenience
|
|
503
|
+
export default {
|
|
504
|
+
createMathModule,
|
|
505
|
+
math,
|
|
506
|
+
};
|