@fuzdev/fuz_util 0.52.1 → 0.53.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/dist/bytes.d.ts +14 -0
- package/dist/bytes.d.ts.map +1 -0
- package/dist/bytes.js +22 -0
- package/dist/hash.d.ts +5 -5
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js +8 -24
- package/dist/hash_blake3.d.ts +15 -0
- package/dist/hash_blake3.d.ts.map +1 -0
- package/dist/hash_blake3.js +17 -0
- package/dist/hex.d.ts +13 -0
- package/dist/hex.d.ts.map +1 -0
- package/dist/hex.js +30 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +7 -1
- package/dist/random.d.ts +9 -0
- package/dist/random.d.ts.map +1 -1
- package/dist/random.js +9 -0
- package/dist/random_alea.d.ts +33 -10
- package/dist/random_alea.d.ts.map +1 -1
- package/dist/random_alea.js +33 -32
- package/dist/random_xoshiro.d.ts +51 -0
- package/dist/random_xoshiro.d.ts.map +1 -0
- package/dist/random_xoshiro.js +92 -0
- package/package.json +15 -8
- package/src/lib/bytes.ts +21 -0
- package/src/lib/hash.ts +9 -28
- package/src/lib/hash_blake3.ts +20 -0
- package/src/lib/hex.ts +32 -0
- package/src/lib/log.ts +6 -1
- package/src/lib/random.ts +10 -0
- package/src/lib/random_alea.ts +37 -12
- package/src/lib/random_xoshiro.ts +124 -0
package/dist/bytes.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary data conversion helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Converts string or binary data to a `Uint8Array`.
|
|
8
|
+
* Strings are UTF-8 encoded. `Uint8Array` inputs are returned as-is.
|
|
9
|
+
*
|
|
10
|
+
* @param data - String or `BufferSource` to convert.
|
|
11
|
+
* @returns `Uint8Array` view of the data.
|
|
12
|
+
*/
|
|
13
|
+
export declare const to_bytes: (data: BufferSource | string) => Uint8Array;
|
|
14
|
+
//# sourceMappingURL=bytes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bytes.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/bytes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,MAAM,YAAY,GAAG,MAAM,KAAG,UAKtD,CAAC"}
|
package/dist/bytes.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary data conversion helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
const encoder = new TextEncoder();
|
|
7
|
+
/**
|
|
8
|
+
* Converts string or binary data to a `Uint8Array`.
|
|
9
|
+
* Strings are UTF-8 encoded. `Uint8Array` inputs are returned as-is.
|
|
10
|
+
*
|
|
11
|
+
* @param data - String or `BufferSource` to convert.
|
|
12
|
+
* @returns `Uint8Array` view of the data.
|
|
13
|
+
*/
|
|
14
|
+
export const to_bytes = (data) => {
|
|
15
|
+
if (typeof data === 'string')
|
|
16
|
+
return encoder.encode(data);
|
|
17
|
+
if (data instanceof Uint8Array)
|
|
18
|
+
return data;
|
|
19
|
+
if (data instanceof ArrayBuffer)
|
|
20
|
+
return new Uint8Array(data);
|
|
21
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
22
|
+
};
|
package/dist/hash.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hash utilities for content comparison and cache invalidation.
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides `hash_sha256` (Web Crypto, async) and `hash_insecure` (DJB2, fast non-cryptographic).
|
|
5
|
+
* For BLAKE3, see `hash_blake3` in `hash_blake3.ts`.
|
|
5
6
|
*
|
|
6
7
|
* @module
|
|
7
8
|
*/
|
|
8
9
|
/**
|
|
9
|
-
* Computes a
|
|
10
|
+
* Computes a SHA-256 hash using Web Crypto API.
|
|
10
11
|
*
|
|
11
12
|
* @param data - String or binary data to hash. Strings are UTF-8 encoded.
|
|
12
|
-
* @
|
|
13
|
-
* @returns Hexadecimal hash string.
|
|
13
|
+
* @returns 64-character hexadecimal hash string.
|
|
14
14
|
*/
|
|
15
|
-
export declare const
|
|
15
|
+
export declare const hash_sha256: (data: BufferSource | string) => Promise<string>;
|
|
16
16
|
/**
|
|
17
17
|
* Computes a fast non-cryptographic hash using DJB2 algorithm.
|
|
18
18
|
* Use for content comparison and cache keys, not security.
|
package/dist/hash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hash.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAU,MAAM,YAAY,GAAG,MAAM,KAAG,OAAO,CAAC,MAAM,CAI7E,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,YAAY,GAAG,MAAM,KAAG,MAkB3D,CAAC"}
|
package/dist/hash.js
CHANGED
|
@@ -1,39 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hash utilities for content comparison and cache invalidation.
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides `hash_sha256` (Web Crypto, async) and `hash_insecure` (DJB2, fast non-cryptographic).
|
|
5
|
+
* For BLAKE3, see `hash_blake3` in `hash_blake3.ts`.
|
|
5
6
|
*
|
|
6
7
|
* @module
|
|
7
8
|
*/
|
|
9
|
+
import { to_hex } from './hex.js';
|
|
8
10
|
const encoder = new TextEncoder();
|
|
9
|
-
// Lazily computed lookup table for byte to hex conversion
|
|
10
|
-
let byte_to_hex;
|
|
11
|
-
const get_byte_to_hex = () => {
|
|
12
|
-
if (byte_to_hex === undefined) {
|
|
13
|
-
byte_to_hex = new Array(256); // 256 possible byte values (0x00-0xff)
|
|
14
|
-
for (let i = 0; i < 256; i++) {
|
|
15
|
-
byte_to_hex[i] = i.toString(16).padStart(2, '0');
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return byte_to_hex;
|
|
19
|
-
};
|
|
20
11
|
/**
|
|
21
|
-
* Computes a
|
|
12
|
+
* Computes a SHA-256 hash using Web Crypto API.
|
|
22
13
|
*
|
|
23
14
|
* @param data - String or binary data to hash. Strings are UTF-8 encoded.
|
|
24
|
-
* @
|
|
25
|
-
* @returns Hexadecimal hash string.
|
|
15
|
+
* @returns 64-character hexadecimal hash string.
|
|
26
16
|
*/
|
|
27
|
-
export const
|
|
17
|
+
export const hash_sha256 = async (data) => {
|
|
28
18
|
const buffer = typeof data === 'string' ? encoder.encode(data) : data;
|
|
29
|
-
const digested = await crypto.subtle.digest(
|
|
30
|
-
|
|
31
|
-
const lookup = get_byte_to_hex();
|
|
32
|
-
let hex = '';
|
|
33
|
-
for (const byte of bytes) {
|
|
34
|
-
hex += lookup[byte];
|
|
35
|
-
}
|
|
36
|
-
return hex;
|
|
19
|
+
const digested = await crypto.subtle.digest('SHA-256', buffer);
|
|
20
|
+
return to_hex(new Uint8Array(digested));
|
|
37
21
|
};
|
|
38
22
|
/**
|
|
39
23
|
* Computes a fast non-cryptographic hash using DJB2 algorithm.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLAKE3 cryptographic hashing via `@fuzdev/blake3_wasm`.
|
|
3
|
+
*
|
|
4
|
+
* Synchronous and fast. Returns hex-encoded 256-bit (32-byte) digests.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Computes a BLAKE3 hash synchronously.
|
|
10
|
+
*
|
|
11
|
+
* @param data - String or binary data to hash. Strings are UTF-8 encoded.
|
|
12
|
+
* @returns 64-character hexadecimal hash string (32 bytes).
|
|
13
|
+
*/
|
|
14
|
+
export declare const hash_blake3: (data: BufferSource | string) => string;
|
|
15
|
+
//# sourceMappingURL=hash_blake3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash_blake3.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hash_blake3.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,YAAY,GAAG,MAAM,KAAG,MAAsC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLAKE3 cryptographic hashing via `@fuzdev/blake3_wasm`.
|
|
3
|
+
*
|
|
4
|
+
* Synchronous and fast. Returns hex-encoded 256-bit (32-byte) digests.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { hash } from '@fuzdev/blake3_wasm';
|
|
9
|
+
import { to_hex } from './hex.js';
|
|
10
|
+
import { to_bytes } from './bytes.js';
|
|
11
|
+
/**
|
|
12
|
+
* Computes a BLAKE3 hash synchronously.
|
|
13
|
+
*
|
|
14
|
+
* @param data - String or binary data to hash. Strings are UTF-8 encoded.
|
|
15
|
+
* @returns 64-character hexadecimal hash string (32 bytes).
|
|
16
|
+
*/
|
|
17
|
+
export const hash_blake3 = (data) => to_hex(hash(to_bytes(data)));
|
package/dist/hex.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hex encoding helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Converts a `Uint8Array` to a lowercase hex string.
|
|
8
|
+
*
|
|
9
|
+
* @param bytes - Binary data to encode.
|
|
10
|
+
* @returns Hex string with two characters per byte.
|
|
11
|
+
*/
|
|
12
|
+
export declare const to_hex: (bytes: Uint8Array) => string;
|
|
13
|
+
//# sourceMappingURL=hex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hex.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hex.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GAAI,OAAO,UAAU,KAAG,MAO1C,CAAC"}
|
package/dist/hex.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hex encoding helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Converts a `Uint8Array` to a lowercase hex string.
|
|
8
|
+
*
|
|
9
|
+
* @param bytes - Binary data to encode.
|
|
10
|
+
* @returns Hex string with two characters per byte.
|
|
11
|
+
*/
|
|
12
|
+
export const to_hex = (bytes) => {
|
|
13
|
+
const lookup = get_byte_to_hex();
|
|
14
|
+
let hex = '';
|
|
15
|
+
for (const byte of bytes) {
|
|
16
|
+
hex += lookup[byte];
|
|
17
|
+
}
|
|
18
|
+
return hex;
|
|
19
|
+
};
|
|
20
|
+
// Lazily computed lookup table for byte to hex conversion
|
|
21
|
+
let byte_to_hex;
|
|
22
|
+
const get_byte_to_hex = () => {
|
|
23
|
+
if (byte_to_hex === undefined) {
|
|
24
|
+
byte_to_hex = new Array(256); // 256 possible byte values (0x00-0xff)
|
|
25
|
+
for (let i = 0; i < 256; i++) {
|
|
26
|
+
byte_to_hex[i] = i.toString(16).padStart(2, '0');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return byte_to_hex;
|
|
30
|
+
};
|
package/dist/log.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/log.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC;AAwBxE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,QAAQ,KAAG,MAAiC,CAAC;AAExF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,QAAQ,GAAG,SAItE,CAAC;AASF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,MAAM;;IAClB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAkBzB;;;;;;;OAOG;gBACS,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;IAiBvD;;OAEG;IACH,IAAI,KAAK,IAAI,QAAQ,CAQpB;IAED;;OAEG;IACH,IAAI,KAAK,CAAC,KAAK,EAAE,QAAQ,EAGxB;IAED;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,OAAO,CAWpB;IAED;;OAEG;IACH,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,EAExB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,UAAU,CAQxB;IAED;;OAEG;IACH,IAAI,OAAO,CAAC,KAAK,EAAE,UAAU,EAE5B;IAED;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,CAMjB;IAED;;;;OAIG;IACH,oBAAoB,IAAI,IAAI;IAM5B;;;;OAIG;IACH,qBAAqB,IAAI,IAAI;IAU7B;;;;OAIG;IACH,sBAAsB,IAAI,IAAI;IA8G9B;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM;IAezD;;;OAGG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAKpC;;;OAGG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAKnC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/log.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC;AAwBxE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,QAAQ,KAAG,MAAiC,CAAC;AAExF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,QAAQ,GAAG,SAItE,CAAC;AASF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,MAAM;;IAClB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAkBzB;;;;;;;OAOG;gBACS,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;IAiBvD;;OAEG;IACH,IAAI,KAAK,IAAI,QAAQ,CAQpB;IAED;;OAEG;IACH,IAAI,KAAK,CAAC,KAAK,EAAE,QAAQ,EAGxB;IAED;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,OAAO,CAWpB;IAED;;OAEG;IACH,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,EAExB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,UAAU,CAQxB;IAED;;OAEG;IACH,IAAI,OAAO,CAAC,KAAK,EAAE,UAAU,EAE5B;IAED;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,CAMjB;IAED;;;;OAIG;IACH,oBAAoB,IAAI,IAAI;IAM5B;;;;OAIG;IACH,qBAAqB,IAAI,IAAI;IAU7B;;;;OAIG;IACH,sBAAsB,IAAI,IAAI;IA8G9B;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM;IAezD;;;OAGG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAKpC;;;OAGG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAKnC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAUnC;;;OAGG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAKpC;;;;;;;;;OASG;IACH,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;CAGlC;AAED,MAAM,WAAW,aAAa;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,QAAQ,CAAC;IAEjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC;IAErB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB"}
|
package/dist/log.js
CHANGED
|
@@ -366,7 +366,13 @@ export class Logger {
|
|
|
366
366
|
info(...args) {
|
|
367
367
|
if (this.#get_cached_level() < LOG_LEVEL_VALUES.info)
|
|
368
368
|
return;
|
|
369
|
-
this
|
|
369
|
+
const prefix = this.#get_info_prefix();
|
|
370
|
+
if (prefix) {
|
|
371
|
+
this.console.log(prefix, ...args);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
this.console.log(...args);
|
|
375
|
+
}
|
|
370
376
|
}
|
|
371
377
|
/**
|
|
372
378
|
* Logs a debug message with `┆debug┆` prefix.
|
package/dist/random.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random helpers that accept an optional `random` parameter,
|
|
3
|
+
* defaulting to `Math.random`. Pass a seeded PRNG for reproducible results:
|
|
4
|
+
*
|
|
5
|
+
* - {@link create_random_xoshiro} — fast, high-quality numeric seeding (recommended)
|
|
6
|
+
* - {@link create_random_alea} — supports string and variadic seeds
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
1
10
|
import type { ArrayElement } from './types.js';
|
|
2
11
|
/**
|
|
3
12
|
* Generates a random `number` between `min` and `max`.
|
package/dist/random.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"random.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/random.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,qBAAoB,KAAG,MACjD,CAAC;AAE9B;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,qBAAoB,KAAG,MAC/B,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,qBAAoB,KAAG,OAAyB,CAAC;AAEhF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,EACvD,KAAK,CAAC,EACN,qBAAoB,KAClB,YAAY,CAAC,CAAC,CAA+C,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,UAAU,KAAK,CAcrF,CAAC"}
|
|
1
|
+
{"version":3,"file":"random.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/random.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,qBAAoB,KAAG,MACjD,CAAC;AAE9B;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,qBAAoB,KAAG,MAC/B,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,qBAAoB,KAAG,OAAyB,CAAC;AAEhF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,EACvD,KAAK,CAAC,EACN,qBAAoB,KAClB,YAAY,CAAC,CAAC,CAA+C,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,UAAU,KAAK,CAcrF,CAAC"}
|
package/dist/random.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random helpers that accept an optional `random` parameter,
|
|
3
|
+
* defaulting to `Math.random`. Pass a seeded PRNG for reproducible results:
|
|
4
|
+
*
|
|
5
|
+
* - {@link create_random_xoshiro} — fast, high-quality numeric seeding (recommended)
|
|
6
|
+
* - {@link create_random_alea} — supports string and variadic seeds
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
1
10
|
/**
|
|
2
11
|
* Generates a random `number` between `min` and `max`.
|
|
3
12
|
*/
|
package/dist/random_alea.d.ts
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Alea: a seedable pseudo-random number generator by Johannes Baagøe.
|
|
3
|
+
* Supports variadic and string seeds (`create_random_alea('my', 3, 'seeds')`).
|
|
4
|
+
* For numeric seeds, prefer `create_random_xoshiro` which is faster with equal quality.
|
|
5
|
+
*
|
|
6
|
+
* DO NOT USE when security matters — use the Web Crypto API (`crypto.getRandomValues`) instead.
|
|
7
|
+
*
|
|
8
|
+
* Alea passes all 11 distribution quality tests at 10M samples,
|
|
9
|
+
* performing on par with `Math.random` (V8's xorshift128+):
|
|
10
|
+
*
|
|
11
|
+
* - mean, variance, chi-squared uniformity, Kolmogorov-Smirnov
|
|
12
|
+
* - lag-1 through lag-8 autocorrelation
|
|
13
|
+
* - runs test, gap test, permutation test (triples)
|
|
14
|
+
* - bit-level frequency (bits 0-7)
|
|
15
|
+
* - 2D serial pairs (25x25 through 200x200 grids)
|
|
16
|
+
* - birthday spacings (Marsaglia parameters)
|
|
17
|
+
*
|
|
18
|
+
* Speed is ~19% slower than `Math.random` (~12.2M ops/sec vs ~15.0M ops/sec).
|
|
19
|
+
*
|
|
20
|
+
* To reproduce:
|
|
21
|
+
*
|
|
22
|
+
* ```bash
|
|
23
|
+
* npm run benchmark_random_quality # distribution tests (N=1M)
|
|
24
|
+
* npm run benchmark_random_quality -- --deep # thorough (N=10M, multi-trial)
|
|
25
|
+
* npm run benchmark_random # speed comparison
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @see https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
export interface RandomAlea {
|
|
2
33
|
(): number;
|
|
3
34
|
uint32: () => number;
|
|
4
35
|
fract53: () => number;
|
|
@@ -9,15 +40,7 @@ export interface Alea {
|
|
|
9
40
|
* Seeded pseudo-random number generator.
|
|
10
41
|
* DO NOT USE when security matters, use webcrypto APIs instead.
|
|
11
42
|
*
|
|
12
|
-
* @see http://baagoe.com/en/RandomMusings/javascript/
|
|
13
43
|
* @see https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
14
44
|
*/
|
|
15
|
-
export declare const create_random_alea: (...seed: Array<unknown>) =>
|
|
16
|
-
type Mash = (data: any) => number;
|
|
17
|
-
/**
|
|
18
|
-
* @source http://baagoe.com/en/RandomMusings/javascript/
|
|
19
|
-
* @copyright Johannes Baagøe <baagoe@baagoe.com>, 2010
|
|
20
|
-
*/
|
|
21
|
-
export declare const masher: () => Mash;
|
|
22
|
-
export {};
|
|
45
|
+
export declare const create_random_alea: (...seed: Array<unknown>) => RandomAlea;
|
|
23
46
|
//# sourceMappingURL=random_alea.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"random_alea.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/random_alea.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"random_alea.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/random_alea.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AA0BH,MAAM,WAAW,UAAU;IAC1B,IAAI,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACtB;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,KAAG,UAqC5D,CAAC"}
|
package/dist/random_alea.js
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Alea: a seedable pseudo-random number generator by Johannes Baagøe.
|
|
3
|
+
* Supports variadic and string seeds (`create_random_alea('my', 3, 'seeds')`).
|
|
4
|
+
* For numeric seeds, prefer `create_random_xoshiro` which is faster with equal quality.
|
|
5
|
+
*
|
|
6
|
+
* DO NOT USE when security matters — use the Web Crypto API (`crypto.getRandomValues`) instead.
|
|
7
|
+
*
|
|
8
|
+
* Alea passes all 11 distribution quality tests at 10M samples,
|
|
9
|
+
* performing on par with `Math.random` (V8's xorshift128+):
|
|
10
|
+
*
|
|
11
|
+
* - mean, variance, chi-squared uniformity, Kolmogorov-Smirnov
|
|
12
|
+
* - lag-1 through lag-8 autocorrelation
|
|
13
|
+
* - runs test, gap test, permutation test (triples)
|
|
14
|
+
* - bit-level frequency (bits 0-7)
|
|
15
|
+
* - 2D serial pairs (25x25 through 200x200 grids)
|
|
16
|
+
* - birthday spacings (Marsaglia parameters)
|
|
17
|
+
*
|
|
18
|
+
* Speed is ~19% slower than `Math.random` (~12.2M ops/sec vs ~15.0M ops/sec).
|
|
19
|
+
*
|
|
20
|
+
* To reproduce:
|
|
21
|
+
*
|
|
22
|
+
* ```bash
|
|
23
|
+
* npm run benchmark_random_quality # distribution tests (N=1M)
|
|
24
|
+
* npm run benchmark_random_quality -- --deep # thorough (N=10M, multi-trial)
|
|
25
|
+
* npm run benchmark_random # speed comparison
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @see https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
30
32
|
/**
|
|
31
33
|
* Seeded pseudo-random number generator.
|
|
32
34
|
* DO NOT USE when security matters, use webcrypto APIs instead.
|
|
33
35
|
*
|
|
34
|
-
* @see http://baagoe.com/en/RandomMusings/javascript/
|
|
35
36
|
* @see https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
36
37
|
*/
|
|
37
38
|
export const create_random_alea = (...seed) => {
|
|
@@ -73,10 +74,10 @@ export const create_random_alea = (...seed) => {
|
|
|
73
74
|
return random;
|
|
74
75
|
};
|
|
75
76
|
/**
|
|
76
|
-
* @source
|
|
77
|
+
* @source https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
77
78
|
* @copyright Johannes Baagøe <baagoe@baagoe.com>, 2010
|
|
78
79
|
*/
|
|
79
|
-
|
|
80
|
+
const masher = () => {
|
|
80
81
|
let n = 0xefc8249d;
|
|
81
82
|
return (data) => {
|
|
82
83
|
const d = data + '';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Xoshiro128**: a seedable pseudo-random number generator by Blackman & Vigna (2018).
|
|
3
|
+
* Recommended for reproducible randomness (testing, simulations, procedural generation).
|
|
4
|
+
*
|
|
5
|
+
* DO NOT USE when security matters — use the Web Crypto API (`crypto.getRandomValues`) instead.
|
|
6
|
+
*
|
|
7
|
+
* Xoshiro128** has a 2^128-1 period and passes BigCrush.
|
|
8
|
+
* It uses pure 32-bit arithmetic (shifts, rotates, XOR, multiply)
|
|
9
|
+
* making it very fast in JavaScript via `Math.imul`.
|
|
10
|
+
*
|
|
11
|
+
* Xoshiro128** passes all 11 distribution quality tests at 10M samples,
|
|
12
|
+
* performing on par with `Math.random` (V8's xorshift128+):
|
|
13
|
+
*
|
|
14
|
+
* - mean, variance, chi-squared uniformity, Kolmogorov-Smirnov
|
|
15
|
+
* - lag-1 through lag-8 autocorrelation
|
|
16
|
+
* - runs test, gap test, permutation test (triples)
|
|
17
|
+
* - bit-level frequency (bits 0-7)
|
|
18
|
+
* - 2D serial pairs (25x25 through 200x200 grids)
|
|
19
|
+
* - birthday spacings (Marsaglia parameters)
|
|
20
|
+
*
|
|
21
|
+
* Speed is near-native (~4% slower than `Math.random`) and ~18% faster than Alea
|
|
22
|
+
* (~14.4M ops/sec vs ~15.0M and ~12.2M respectively).
|
|
23
|
+
*
|
|
24
|
+
* To reproduce:
|
|
25
|
+
*
|
|
26
|
+
* ```bash
|
|
27
|
+
* npm run benchmark_random_quality # distribution tests (N=1M)
|
|
28
|
+
* npm run benchmark_random_quality -- --deep # thorough (N=10M, multi-trial)
|
|
29
|
+
* npm run benchmark_random # speed comparison
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @see https://prng.di.unimi.it/
|
|
33
|
+
* @see https://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
|
|
34
|
+
*
|
|
35
|
+
* @module
|
|
36
|
+
*/
|
|
37
|
+
export interface RandomXoshiro {
|
|
38
|
+
(): number;
|
|
39
|
+
uint32: () => number;
|
|
40
|
+
fract53: () => number;
|
|
41
|
+
version: string;
|
|
42
|
+
seed: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Seeded pseudo-random number generator using the Xoshiro128** algorithm.
|
|
46
|
+
* DO NOT USE when security matters, use webcrypto APIs instead.
|
|
47
|
+
*
|
|
48
|
+
* @see https://prng.di.unimi.it/
|
|
49
|
+
*/
|
|
50
|
+
export declare const create_random_xoshiro: (seed?: number) => RandomXoshiro;
|
|
51
|
+
//# sourceMappingURL=random_xoshiro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random_xoshiro.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/random_xoshiro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAcH,MAAM,WAAW,aAAa;IAC7B,IAAI,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,KAAG,aA8CrD,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Xoshiro128**: a seedable pseudo-random number generator by Blackman & Vigna (2018).
|
|
3
|
+
* Recommended for reproducible randomness (testing, simulations, procedural generation).
|
|
4
|
+
*
|
|
5
|
+
* DO NOT USE when security matters — use the Web Crypto API (`crypto.getRandomValues`) instead.
|
|
6
|
+
*
|
|
7
|
+
* Xoshiro128** has a 2^128-1 period and passes BigCrush.
|
|
8
|
+
* It uses pure 32-bit arithmetic (shifts, rotates, XOR, multiply)
|
|
9
|
+
* making it very fast in JavaScript via `Math.imul`.
|
|
10
|
+
*
|
|
11
|
+
* Xoshiro128** passes all 11 distribution quality tests at 10M samples,
|
|
12
|
+
* performing on par with `Math.random` (V8's xorshift128+):
|
|
13
|
+
*
|
|
14
|
+
* - mean, variance, chi-squared uniformity, Kolmogorov-Smirnov
|
|
15
|
+
* - lag-1 through lag-8 autocorrelation
|
|
16
|
+
* - runs test, gap test, permutation test (triples)
|
|
17
|
+
* - bit-level frequency (bits 0-7)
|
|
18
|
+
* - 2D serial pairs (25x25 through 200x200 grids)
|
|
19
|
+
* - birthday spacings (Marsaglia parameters)
|
|
20
|
+
*
|
|
21
|
+
* Speed is near-native (~4% slower than `Math.random`) and ~18% faster than Alea
|
|
22
|
+
* (~14.4M ops/sec vs ~15.0M and ~12.2M respectively).
|
|
23
|
+
*
|
|
24
|
+
* To reproduce:
|
|
25
|
+
*
|
|
26
|
+
* ```bash
|
|
27
|
+
* npm run benchmark_random_quality # distribution tests (N=1M)
|
|
28
|
+
* npm run benchmark_random_quality -- --deep # thorough (N=10M, multi-trial)
|
|
29
|
+
* npm run benchmark_random # speed comparison
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @see https://prng.di.unimi.it/
|
|
33
|
+
* @see https://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
|
|
34
|
+
*
|
|
35
|
+
* @module
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Seeded pseudo-random number generator using the Xoshiro128** algorithm.
|
|
39
|
+
* DO NOT USE when security matters, use webcrypto APIs instead.
|
|
40
|
+
*
|
|
41
|
+
* @see https://prng.di.unimi.it/
|
|
42
|
+
*/
|
|
43
|
+
export const create_random_xoshiro = (seed) => {
|
|
44
|
+
const actual_seed = seed ?? Date.now();
|
|
45
|
+
let sm_state = actual_seed | 0;
|
|
46
|
+
// expand single seed into 4 state words via SplitMix32
|
|
47
|
+
let r = splitmix32_next(sm_state);
|
|
48
|
+
let s0 = r.value;
|
|
49
|
+
sm_state = r.state;
|
|
50
|
+
r = splitmix32_next(sm_state);
|
|
51
|
+
let s1 = r.value;
|
|
52
|
+
sm_state = r.state;
|
|
53
|
+
r = splitmix32_next(sm_state);
|
|
54
|
+
let s2 = r.value;
|
|
55
|
+
sm_state = r.state;
|
|
56
|
+
r = splitmix32_next(sm_state);
|
|
57
|
+
let s3 = r.value;
|
|
58
|
+
// guard against all-zero state (absorbing fixed point)
|
|
59
|
+
if ((s0 | s1 | s2 | s3) === 0)
|
|
60
|
+
s0 = 1;
|
|
61
|
+
const next_uint32 = () => {
|
|
62
|
+
const result = Math.imul(rotl(Math.imul(s1, 5), 7), 9);
|
|
63
|
+
const t = s1 << 9;
|
|
64
|
+
s2 ^= s0;
|
|
65
|
+
s3 ^= s1;
|
|
66
|
+
s1 ^= s2;
|
|
67
|
+
s0 ^= s3;
|
|
68
|
+
s2 ^= t;
|
|
69
|
+
s3 = rotl(s3, 11);
|
|
70
|
+
return result >>> 0;
|
|
71
|
+
};
|
|
72
|
+
const random = () => next_uint32() / 0x100000000; // 2^32
|
|
73
|
+
random.uint32 = next_uint32;
|
|
74
|
+
random.fract53 = () => {
|
|
75
|
+
return random() + ((random() * 0x200000) | 0) * 1.1102230246251565e-16; // 2^-53
|
|
76
|
+
};
|
|
77
|
+
random.version = 'Xoshiro128** 1.0';
|
|
78
|
+
random.seed = actual_seed;
|
|
79
|
+
return random;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Expands a 32-bit state by one step using the SplitMix32 algorithm,
|
|
83
|
+
* producing the four state words needed by Xoshiro128**.
|
|
84
|
+
*/
|
|
85
|
+
const splitmix32_next = (prev_state) => {
|
|
86
|
+
const next_state = (prev_state + 0x9e3779b9) | 0;
|
|
87
|
+
let z = next_state;
|
|
88
|
+
z = Math.imul(z ^ (z >>> 16), 0x85ebca6b);
|
|
89
|
+
z = Math.imul(z ^ (z >>> 13), 0xc2b2ae35);
|
|
90
|
+
return { value: (z ^ (z >>> 16)) >>> 0, state: next_state };
|
|
91
|
+
};
|
|
92
|
+
const rotl = (x, k) => (x << k) | (x >>> (32 - k));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzdev/fuz_util",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "utility belt for JS",
|
|
5
5
|
"glyph": "🦕",
|
|
6
6
|
"logo": "logo.svg",
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
"benchmark:save": "gro run src/benchmarks/run.ts --save",
|
|
32
32
|
"benchmark_slugify": "gro run src/benchmarks/slugify.benchmark.ts",
|
|
33
33
|
"benchmark_deep_equal": "gro run src/benchmarks/deep_equal.benchmark.ts",
|
|
34
|
-
"benchmark_deep_equal_comparison": "gro run src/benchmarks/deep_equal_comparison.benchmark.ts"
|
|
34
|
+
"benchmark_deep_equal_comparison": "gro run src/benchmarks/deep_equal_comparison.benchmark.ts",
|
|
35
|
+
"benchmark_random": "gro run src/benchmarks/random.benchmark.ts",
|
|
36
|
+
"benchmark_random_quality": "gro run src/benchmarks/random_quality.ts"
|
|
35
37
|
},
|
|
36
38
|
"type": "module",
|
|
37
39
|
"engines": {
|
|
@@ -44,6 +46,7 @@
|
|
|
44
46
|
"web"
|
|
45
47
|
],
|
|
46
48
|
"peerDependencies": {
|
|
49
|
+
"@fuzdev/blake3_wasm": "^0.1.0",
|
|
47
50
|
"@types/estree": "^1",
|
|
48
51
|
"@types/node": "^24",
|
|
49
52
|
"esm-env": "^1.2.2",
|
|
@@ -51,13 +54,16 @@
|
|
|
51
54
|
"zod": "^4.0.14"
|
|
52
55
|
},
|
|
53
56
|
"peerDependenciesMeta": {
|
|
54
|
-
"@
|
|
57
|
+
"@fuzdev/blake3_wasm": {
|
|
55
58
|
"optional": true
|
|
56
59
|
},
|
|
57
|
-
"
|
|
60
|
+
"@types/estree": {
|
|
58
61
|
"optional": true
|
|
59
62
|
},
|
|
60
|
-
"@types/
|
|
63
|
+
"@types/node": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"esm-env": {
|
|
61
67
|
"optional": true
|
|
62
68
|
},
|
|
63
69
|
"svelte": {
|
|
@@ -69,10 +75,11 @@
|
|
|
69
75
|
},
|
|
70
76
|
"devDependencies": {
|
|
71
77
|
"@changesets/changelog-git": "^0.2.1",
|
|
78
|
+
"@fuzdev/blake3_wasm": "^0.1.0",
|
|
72
79
|
"@fuzdev/fuz_code": "^0.45.1",
|
|
73
|
-
"@fuzdev/fuz_css": "^0.
|
|
74
|
-
"@fuzdev/fuz_ui": "^0.
|
|
75
|
-
"@fuzdev/gro": "^0.
|
|
80
|
+
"@fuzdev/fuz_css": "^0.54.0",
|
|
81
|
+
"@fuzdev/fuz_ui": "^0.185.2",
|
|
82
|
+
"@fuzdev/gro": "^0.196.0",
|
|
76
83
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
77
84
|
"@ryanatkn/eslint-config": "^0.9.0",
|
|
78
85
|
"@sveltejs/adapter-static": "^3.0.10",
|
package/src/lib/bytes.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary data conversion helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const encoder = new TextEncoder();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Converts string or binary data to a `Uint8Array`.
|
|
11
|
+
* Strings are UTF-8 encoded. `Uint8Array` inputs are returned as-is.
|
|
12
|
+
*
|
|
13
|
+
* @param data - String or `BufferSource` to convert.
|
|
14
|
+
* @returns `Uint8Array` view of the data.
|
|
15
|
+
*/
|
|
16
|
+
export const to_bytes = (data: BufferSource | string): Uint8Array => {
|
|
17
|
+
if (typeof data === 'string') return encoder.encode(data);
|
|
18
|
+
if (data instanceof Uint8Array) return data;
|
|
19
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
20
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
21
|
+
};
|
package/src/lib/hash.ts
CHANGED
|
@@ -1,45 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hash utilities for content comparison and cache invalidation.
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides `hash_sha256` (Web Crypto, async) and `hash_insecure` (DJB2, fast non-cryptographic).
|
|
5
|
+
* For BLAKE3, see `hash_blake3` in `hash_blake3.ts`.
|
|
5
6
|
*
|
|
6
7
|
* @module
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
import {to_hex} from './hex.js';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
let byte_to_hex: Array<string> | undefined;
|
|
13
|
-
const get_byte_to_hex = (): Array<string> => {
|
|
14
|
-
if (byte_to_hex === undefined) {
|
|
15
|
-
byte_to_hex = new Array(256); // 256 possible byte values (0x00-0xff)
|
|
16
|
-
for (let i = 0; i < 256; i++) {
|
|
17
|
-
byte_to_hex[i] = i.toString(16).padStart(2, '0');
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return byte_to_hex;
|
|
21
|
-
};
|
|
12
|
+
const encoder = new TextEncoder();
|
|
22
13
|
|
|
23
14
|
/**
|
|
24
|
-
* Computes a
|
|
15
|
+
* Computes a SHA-256 hash using Web Crypto API.
|
|
25
16
|
*
|
|
26
17
|
* @param data - String or binary data to hash. Strings are UTF-8 encoded.
|
|
27
|
-
* @
|
|
28
|
-
* @returns Hexadecimal hash string.
|
|
18
|
+
* @returns 64-character hexadecimal hash string.
|
|
29
19
|
*/
|
|
30
|
-
export const
|
|
31
|
-
data: BufferSource | string,
|
|
32
|
-
algorithm: 'SHA-256' | 'SHA-384' | 'SHA-512' = 'SHA-256',
|
|
33
|
-
): Promise<string> => {
|
|
20
|
+
export const hash_sha256 = async (data: BufferSource | string): Promise<string> => {
|
|
34
21
|
const buffer = typeof data === 'string' ? encoder.encode(data) : data;
|
|
35
|
-
const digested = await crypto.subtle.digest(
|
|
36
|
-
|
|
37
|
-
const lookup = get_byte_to_hex();
|
|
38
|
-
let hex = '';
|
|
39
|
-
for (const byte of bytes) {
|
|
40
|
-
hex += lookup[byte];
|
|
41
|
-
}
|
|
42
|
-
return hex;
|
|
22
|
+
const digested = await crypto.subtle.digest('SHA-256', buffer);
|
|
23
|
+
return to_hex(new Uint8Array(digested));
|
|
43
24
|
};
|
|
44
25
|
|
|
45
26
|
/**
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLAKE3 cryptographic hashing via `@fuzdev/blake3_wasm`.
|
|
3
|
+
*
|
|
4
|
+
* Synchronous and fast. Returns hex-encoded 256-bit (32-byte) digests.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {hash} from '@fuzdev/blake3_wasm';
|
|
10
|
+
|
|
11
|
+
import {to_hex} from './hex.js';
|
|
12
|
+
import {to_bytes} from './bytes.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Computes a BLAKE3 hash synchronously.
|
|
16
|
+
*
|
|
17
|
+
* @param data - String or binary data to hash. Strings are UTF-8 encoded.
|
|
18
|
+
* @returns 64-character hexadecimal hash string (32 bytes).
|
|
19
|
+
*/
|
|
20
|
+
export const hash_blake3 = (data: BufferSource | string): string => to_hex(hash(to_bytes(data)));
|
package/src/lib/hex.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hex encoding helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Converts a `Uint8Array` to a lowercase hex string.
|
|
9
|
+
*
|
|
10
|
+
* @param bytes - Binary data to encode.
|
|
11
|
+
* @returns Hex string with two characters per byte.
|
|
12
|
+
*/
|
|
13
|
+
export const to_hex = (bytes: Uint8Array): string => {
|
|
14
|
+
const lookup = get_byte_to_hex();
|
|
15
|
+
let hex = '';
|
|
16
|
+
for (const byte of bytes) {
|
|
17
|
+
hex += lookup[byte];
|
|
18
|
+
}
|
|
19
|
+
return hex;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Lazily computed lookup table for byte to hex conversion
|
|
23
|
+
let byte_to_hex: Array<string> | undefined;
|
|
24
|
+
const get_byte_to_hex = (): Array<string> => {
|
|
25
|
+
if (byte_to_hex === undefined) {
|
|
26
|
+
byte_to_hex = new Array(256); // 256 possible byte values (0x00-0xff)
|
|
27
|
+
for (let i = 0; i < 256; i++) {
|
|
28
|
+
byte_to_hex[i] = i.toString(16).padStart(2, '0');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return byte_to_hex;
|
|
32
|
+
};
|
package/src/lib/log.ts
CHANGED
|
@@ -415,7 +415,12 @@ export class Logger {
|
|
|
415
415
|
*/
|
|
416
416
|
info(...args: Array<unknown>): void {
|
|
417
417
|
if (this.#get_cached_level() < LOG_LEVEL_VALUES.info) return;
|
|
418
|
-
this
|
|
418
|
+
const prefix = this.#get_info_prefix();
|
|
419
|
+
if (prefix) {
|
|
420
|
+
this.console.log(prefix, ...args);
|
|
421
|
+
} else {
|
|
422
|
+
this.console.log(...args);
|
|
423
|
+
}
|
|
419
424
|
}
|
|
420
425
|
|
|
421
426
|
/**
|
package/src/lib/random.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random helpers that accept an optional `random` parameter,
|
|
3
|
+
* defaulting to `Math.random`. Pass a seeded PRNG for reproducible results:
|
|
4
|
+
*
|
|
5
|
+
* - {@link create_random_xoshiro} — fast, high-quality numeric seeding (recommended)
|
|
6
|
+
* - {@link create_random_alea} — supports string and variadic seeds
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
import type {ArrayElement} from './types.js';
|
|
2
12
|
|
|
3
13
|
/**
|
package/src/lib/random_alea.ts
CHANGED
|
@@ -1,10 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Alea: a seedable pseudo-random number generator by Johannes Baagøe.
|
|
3
|
+
* Supports variadic and string seeds (`create_random_alea('my', 3, 'seeds')`).
|
|
4
|
+
* For numeric seeds, prefer `create_random_xoshiro` which is faster with equal quality.
|
|
5
|
+
*
|
|
6
|
+
* DO NOT USE when security matters — use the Web Crypto API (`crypto.getRandomValues`) instead.
|
|
7
|
+
*
|
|
8
|
+
* Alea passes all 11 distribution quality tests at 10M samples,
|
|
9
|
+
* performing on par with `Math.random` (V8's xorshift128+):
|
|
10
|
+
*
|
|
11
|
+
* - mean, variance, chi-squared uniformity, Kolmogorov-Smirnov
|
|
12
|
+
* - lag-1 through lag-8 autocorrelation
|
|
13
|
+
* - runs test, gap test, permutation test (triples)
|
|
14
|
+
* - bit-level frequency (bits 0-7)
|
|
15
|
+
* - 2D serial pairs (25x25 through 200x200 grids)
|
|
16
|
+
* - birthday spacings (Marsaglia parameters)
|
|
17
|
+
*
|
|
18
|
+
* Speed is ~19% slower than `Math.random` (~12.2M ops/sec vs ~15.0M ops/sec).
|
|
19
|
+
*
|
|
20
|
+
* To reproduce:
|
|
21
|
+
*
|
|
22
|
+
* ```bash
|
|
23
|
+
* npm run benchmark_random_quality # distribution tests (N=1M)
|
|
24
|
+
* npm run benchmark_random_quality -- --deep # thorough (N=10M, multi-trial)
|
|
25
|
+
* npm run benchmark_random # speed comparison
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @see https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
5
32
|
|
|
6
|
-
|
|
7
|
-
via https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
33
|
+
/*
|
|
8
34
|
|
|
9
35
|
Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>
|
|
10
36
|
|
|
@@ -28,7 +54,7 @@ THE SOFTWARE.
|
|
|
28
54
|
|
|
29
55
|
*/
|
|
30
56
|
|
|
31
|
-
export interface
|
|
57
|
+
export interface RandomAlea {
|
|
32
58
|
(): number;
|
|
33
59
|
uint32: () => number;
|
|
34
60
|
fract53: () => number;
|
|
@@ -40,10 +66,9 @@ export interface Alea {
|
|
|
40
66
|
* Seeded pseudo-random number generator.
|
|
41
67
|
* DO NOT USE when security matters, use webcrypto APIs instead.
|
|
42
68
|
*
|
|
43
|
-
* @see http://baagoe.com/en/RandomMusings/javascript/
|
|
44
69
|
* @see https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
45
70
|
*/
|
|
46
|
-
export const create_random_alea = (...seed: Array<unknown>):
|
|
71
|
+
export const create_random_alea = (...seed: Array<unknown>): RandomAlea => {
|
|
47
72
|
let s0 = 0;
|
|
48
73
|
let s1 = 0;
|
|
49
74
|
let s2 = 0;
|
|
@@ -65,7 +90,7 @@ export const create_random_alea = (...seed: Array<unknown>): Alea => {
|
|
|
65
90
|
}
|
|
66
91
|
mash = null;
|
|
67
92
|
|
|
68
|
-
const random:
|
|
93
|
+
const random: RandomAlea = (): number => {
|
|
69
94
|
const t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
|
|
70
95
|
s0 = s1;
|
|
71
96
|
s1 = s2;
|
|
@@ -85,10 +110,10 @@ export const create_random_alea = (...seed: Array<unknown>): Alea => {
|
|
|
85
110
|
type Mash = (data: any) => number;
|
|
86
111
|
|
|
87
112
|
/**
|
|
88
|
-
* @source
|
|
113
|
+
* @source https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
|
|
89
114
|
* @copyright Johannes Baagøe <baagoe@baagoe.com>, 2010
|
|
90
115
|
*/
|
|
91
|
-
|
|
116
|
+
const masher = (): Mash => {
|
|
92
117
|
let n = 0xefc8249d;
|
|
93
118
|
return (data) => {
|
|
94
119
|
const d = data + '';
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Xoshiro128**: a seedable pseudo-random number generator by Blackman & Vigna (2018).
|
|
3
|
+
* Recommended for reproducible randomness (testing, simulations, procedural generation).
|
|
4
|
+
*
|
|
5
|
+
* DO NOT USE when security matters — use the Web Crypto API (`crypto.getRandomValues`) instead.
|
|
6
|
+
*
|
|
7
|
+
* Xoshiro128** has a 2^128-1 period and passes BigCrush.
|
|
8
|
+
* It uses pure 32-bit arithmetic (shifts, rotates, XOR, multiply)
|
|
9
|
+
* making it very fast in JavaScript via `Math.imul`.
|
|
10
|
+
*
|
|
11
|
+
* Xoshiro128** passes all 11 distribution quality tests at 10M samples,
|
|
12
|
+
* performing on par with `Math.random` (V8's xorshift128+):
|
|
13
|
+
*
|
|
14
|
+
* - mean, variance, chi-squared uniformity, Kolmogorov-Smirnov
|
|
15
|
+
* - lag-1 through lag-8 autocorrelation
|
|
16
|
+
* - runs test, gap test, permutation test (triples)
|
|
17
|
+
* - bit-level frequency (bits 0-7)
|
|
18
|
+
* - 2D serial pairs (25x25 through 200x200 grids)
|
|
19
|
+
* - birthday spacings (Marsaglia parameters)
|
|
20
|
+
*
|
|
21
|
+
* Speed is near-native (~4% slower than `Math.random`) and ~18% faster than Alea
|
|
22
|
+
* (~14.4M ops/sec vs ~15.0M and ~12.2M respectively).
|
|
23
|
+
*
|
|
24
|
+
* To reproduce:
|
|
25
|
+
*
|
|
26
|
+
* ```bash
|
|
27
|
+
* npm run benchmark_random_quality # distribution tests (N=1M)
|
|
28
|
+
* npm run benchmark_random_quality -- --deep # thorough (N=10M, multi-trial)
|
|
29
|
+
* npm run benchmark_random # speed comparison
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @see https://prng.di.unimi.it/
|
|
33
|
+
* @see https://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
|
|
34
|
+
*
|
|
35
|
+
* @module
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
|
|
40
|
+
Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
|
41
|
+
|
|
42
|
+
To the extent possible under law, the author has dedicated all copyright
|
|
43
|
+
and related and neighboring rights to this software to the public domain
|
|
44
|
+
worldwide. This software is distributed without any warranty.
|
|
45
|
+
|
|
46
|
+
See <https://creativecommons.org/publicdomain/zero/1.0/>.
|
|
47
|
+
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
export interface RandomXoshiro {
|
|
51
|
+
(): number;
|
|
52
|
+
uint32: () => number;
|
|
53
|
+
fract53: () => number;
|
|
54
|
+
version: string;
|
|
55
|
+
seed: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Seeded pseudo-random number generator using the Xoshiro128** algorithm.
|
|
60
|
+
* DO NOT USE when security matters, use webcrypto APIs instead.
|
|
61
|
+
*
|
|
62
|
+
* @see https://prng.di.unimi.it/
|
|
63
|
+
*/
|
|
64
|
+
export const create_random_xoshiro = (seed?: number): RandomXoshiro => {
|
|
65
|
+
const actual_seed = seed ?? Date.now();
|
|
66
|
+
let sm_state = actual_seed | 0;
|
|
67
|
+
|
|
68
|
+
// expand single seed into 4 state words via SplitMix32
|
|
69
|
+
let r = splitmix32_next(sm_state);
|
|
70
|
+
let s0 = r.value;
|
|
71
|
+
sm_state = r.state;
|
|
72
|
+
r = splitmix32_next(sm_state);
|
|
73
|
+
let s1 = r.value;
|
|
74
|
+
sm_state = r.state;
|
|
75
|
+
r = splitmix32_next(sm_state);
|
|
76
|
+
let s2 = r.value;
|
|
77
|
+
sm_state = r.state;
|
|
78
|
+
r = splitmix32_next(sm_state);
|
|
79
|
+
let s3 = r.value;
|
|
80
|
+
|
|
81
|
+
// guard against all-zero state (absorbing fixed point)
|
|
82
|
+
if ((s0 | s1 | s2 | s3) === 0) s0 = 1;
|
|
83
|
+
|
|
84
|
+
const next_uint32 = (): number => {
|
|
85
|
+
const result = Math.imul(rotl(Math.imul(s1, 5), 7), 9);
|
|
86
|
+
const t = s1 << 9;
|
|
87
|
+
|
|
88
|
+
s2 ^= s0;
|
|
89
|
+
s3 ^= s1;
|
|
90
|
+
s1 ^= s2;
|
|
91
|
+
s0 ^= s3;
|
|
92
|
+
s2 ^= t;
|
|
93
|
+
s3 = rotl(s3, 11);
|
|
94
|
+
|
|
95
|
+
return result >>> 0;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const random: RandomXoshiro = (): number => next_uint32() / 0x100000000; // 2^32
|
|
99
|
+
|
|
100
|
+
random.uint32 = next_uint32;
|
|
101
|
+
|
|
102
|
+
random.fract53 = (): number => {
|
|
103
|
+
return random() + ((random() * 0x200000) | 0) * 1.1102230246251565e-16; // 2^-53
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
random.version = 'Xoshiro128** 1.0';
|
|
107
|
+
random.seed = actual_seed;
|
|
108
|
+
|
|
109
|
+
return random;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Expands a 32-bit state by one step using the SplitMix32 algorithm,
|
|
114
|
+
* producing the four state words needed by Xoshiro128**.
|
|
115
|
+
*/
|
|
116
|
+
const splitmix32_next = (prev_state: number): {value: number; state: number} => {
|
|
117
|
+
const next_state = (prev_state + 0x9e3779b9) | 0;
|
|
118
|
+
let z = next_state;
|
|
119
|
+
z = Math.imul(z ^ (z >>> 16), 0x85ebca6b);
|
|
120
|
+
z = Math.imul(z ^ (z >>> 13), 0xc2b2ae35);
|
|
121
|
+
return {value: (z ^ (z >>> 16)) >>> 0, state: next_state};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const rotl = (x: number, k: number): number => (x << k) | (x >>> (32 - k));
|