@fulmenhq/tsfulmen 0.1.13 → 0.1.14
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 +14 -8
- package/dist/fulhash/index.d.ts +64 -12
- package/dist/fulhash/index.js +292 -53
- package/dist/fulhash/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pathfinder/index.js +250 -53
- package/dist/pathfinder/index.js.map +1 -1
- package/package.json +3 -2
- package/schemas/crucible-ts/taxonomy/library/fulhash/algorithms/v1.0.0/algorithms.yaml +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,23 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
## [0.1.
|
|
10
|
+
## [0.1.14] - 2025-11-28
|
|
11
11
|
|
|
12
12
|
### Added
|
|
13
13
|
|
|
14
|
-
- **
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
14
|
+
- **Unified Hashing Stack** (`@fulmenhq/tsfulmen/fulhash`) - Consolidated hashing implementations on `hash-wasm`
|
|
15
|
+
- Added support for **CRC32** and **CRC32C** algorithms (block and streaming)
|
|
16
|
+
- Implemented `multiHash()` for efficient single-pass multi-algorithm hashing
|
|
17
|
+
- Implemented `verify()` for checksum validation
|
|
18
|
+
- Benchmarked performance: XXH3-128 (~5GB/s), SHA-256 (~2GB/s), CRC (~1.2GB/s)
|
|
19
|
+
- Added comprehensive tests for streaming, concurrency, and encoding handling
|
|
19
20
|
|
|
20
21
|
### Changed
|
|
21
22
|
|
|
22
|
-
- **Crucible SSOT** - Updated to v0.2.
|
|
23
|
+
- **Crucible SSOT** - Updated to v0.2.20 (syncs latest fulhash types)
|
|
24
|
+
- **Dependency Cleanup** - Removed `crc-32` and `fast-crc32c` in favor of `hash-wasm` consolidation
|
|
25
|
+
- **Bug Fixes**:
|
|
26
|
+
- Fixed `Digest.parse` to support 8-char CRC checksums
|
|
27
|
+
- Fixed XXH3 encoding handling for non-UTF8 inputs
|
|
28
|
+
- Improved `MultiHashResult` typing and deduplication
|
|
23
29
|
|
|
24
30
|
---
|
|
25
31
|
|
|
26
|
-
## [0.1.
|
|
32
|
+
## [0.1.13] - 2025-11-20
|
|
27
33
|
|
|
28
34
|
### Fixed
|
|
29
35
|
|
package/dist/fulhash/index.d.ts
CHANGED
|
@@ -1,28 +1,80 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* FulHash Types
|
|
3
|
+
* Code generated by scripts/codegen/generate-fulhash-types.ts; DO NOT EDIT.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Supported hashing algorithms for FulHash
|
|
3
7
|
*/
|
|
4
8
|
declare enum Algorithm {
|
|
9
|
+
/**
|
|
10
|
+
* XXH3 (128-bit)
|
|
11
|
+
* Fast non-cryptographic hash (default). Excellent collision resistance, extremely high throughput (50GB/s+).
|
|
12
|
+
*/
|
|
5
13
|
XXH3_128 = "xxh3-128",
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
/**
|
|
15
|
+
* SHA-256
|
|
16
|
+
* Cryptographic security standard. Resistant to intentional collisions. Use for security verification.
|
|
17
|
+
*/
|
|
18
|
+
SHA256 = "sha256",
|
|
19
|
+
/**
|
|
20
|
+
* CRC-32 (IEEE)
|
|
21
|
+
* 32-bit Cyclic Redundancy Check. Standard for GZIP/ZIP/PNG legacy format interoperability.
|
|
22
|
+
*/
|
|
23
|
+
CRC32 = "crc32",
|
|
24
|
+
/**
|
|
25
|
+
* CRC-32C (Castagnoli)
|
|
26
|
+
* 32-bit CRC (Castagnoli). HW accelerated (SSE4.2/ARMv8). Use for cloud storage (GCS, AWS) and networking.
|
|
27
|
+
*/
|
|
28
|
+
CRC32C = "crc32c"
|
|
11
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Standard digest payload returned by FulHash helpers
|
|
32
|
+
*/
|
|
12
33
|
interface Digest$1 {
|
|
13
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Hash algorithm identifier
|
|
36
|
+
*/
|
|
37
|
+
algorithm: "xxh3-128" | "crc32" | "crc32c" | "sha256";
|
|
38
|
+
/**
|
|
39
|
+
* Lowercase hexadecimal representation of the digest
|
|
40
|
+
*/
|
|
14
41
|
hex: string;
|
|
15
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Canonical string representation '<algorithm>:<hex>'
|
|
44
|
+
*/
|
|
16
45
|
formatted: string;
|
|
46
|
+
/**
|
|
47
|
+
* Raw digest bytes (optional)
|
|
48
|
+
*/
|
|
49
|
+
bytes?: number[];
|
|
17
50
|
}
|
|
18
|
-
|
|
51
|
+
|
|
52
|
+
interface HashOptions {
|
|
19
53
|
algorithm?: Algorithm;
|
|
54
|
+
encoding?: BufferEncoding;
|
|
20
55
|
}
|
|
21
56
|
interface StreamHasher {
|
|
22
57
|
update(data: string | Uint8Array): StreamHasher;
|
|
23
58
|
digest(): Digest$1;
|
|
24
59
|
reset(): StreamHasher;
|
|
25
60
|
}
|
|
61
|
+
interface StreamHasherOptions {
|
|
62
|
+
algorithm?: Algorithm;
|
|
63
|
+
}
|
|
64
|
+
type MultiHashResult = Partial<Record<Algorithm, Digest$1>>;
|
|
65
|
+
|
|
66
|
+
type HashInput = string | Uint8Array | AsyncIterable<string | Uint8Array>;
|
|
67
|
+
/**
|
|
68
|
+
* Compute multiple hashes in a single pass over the data.
|
|
69
|
+
* Useful for generating checksums for multiple algorithms (e.g. SHA256 + XXH3)
|
|
70
|
+
* without reading the stream multiple times.
|
|
71
|
+
*/
|
|
72
|
+
declare function multiHash(input: HashInput, algorithms: Algorithm[], encoding?: BufferEncoding): Promise<MultiHashResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Verify data against a formatted checksum (e.g. "sha256:abc...").
|
|
75
|
+
* Automatically selects the algorithm from the checksum prefix.
|
|
76
|
+
*/
|
|
77
|
+
declare function verify(input: HashInput, checksum: string, encoding?: BufferEncoding): Promise<boolean>;
|
|
26
78
|
|
|
27
79
|
/**
|
|
28
80
|
* Digest implementation - immutable hash result container
|
|
@@ -34,7 +86,7 @@ declare class Digest implements Digest$1 {
|
|
|
34
86
|
readonly hex: string;
|
|
35
87
|
readonly formatted: string;
|
|
36
88
|
constructor(algorithm: Algorithm, bytes: Uint8Array);
|
|
37
|
-
get bytes():
|
|
89
|
+
get bytes(): number[];
|
|
38
90
|
toJSON(): object;
|
|
39
91
|
toString(): string;
|
|
40
92
|
static parse(formatted: string): Digest;
|
|
@@ -74,9 +126,9 @@ declare function createStreamHasher(options?: StreamHasherOptions): Promise<Stre
|
|
|
74
126
|
/**
|
|
75
127
|
* FulHash - Consistent hashing API for Fulmen ecosystem
|
|
76
128
|
*
|
|
77
|
-
* Provides block and streaming hashing with
|
|
129
|
+
* Provides block and streaming hashing with XXH3-128, SHA-256, CRC32, and CRC32C algorithms.
|
|
78
130
|
* Cross-language compatible with gofulmen and pyfulmen.
|
|
79
131
|
*/
|
|
80
132
|
declare const VERSION = "1.0.0";
|
|
81
133
|
|
|
82
|
-
export { Algorithm, Digest, DigestStateError, FulHashError, type HashOptions, InvalidChecksumError, InvalidChecksumFormatError, type StreamHasher, type StreamHasherOptions, UnsupportedAlgorithmError, VERSION, createStreamHasher, hash, hashBytes, hashString };
|
|
134
|
+
export { Algorithm, Digest, DigestStateError, FulHashError, type HashInput, type HashOptions, InvalidChecksumError, InvalidChecksumFormatError, type StreamHasher, type StreamHasherOptions, UnsupportedAlgorithmError, VERSION, createStreamHasher, hash, hashBytes, hashString, multiHash, verify };
|
package/dist/fulhash/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { crc32, xxhash128, createXXHash128, createCRC32 } from 'hash-wasm';
|
|
1
2
|
import { createHash } from 'crypto';
|
|
2
|
-
import { xxhash128, createXXHash128 } from 'hash-wasm';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -11,6 +11,20 @@ var __export = (target, all) => {
|
|
|
11
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
// src/crucible/fulhash/types.ts
|
|
15
|
+
var Algorithm;
|
|
16
|
+
var init_types = __esm({
|
|
17
|
+
"src/crucible/fulhash/types.ts"() {
|
|
18
|
+
Algorithm = /* @__PURE__ */ ((Algorithm2) => {
|
|
19
|
+
Algorithm2["XXH3_128"] = "xxh3-128";
|
|
20
|
+
Algorithm2["SHA256"] = "sha256";
|
|
21
|
+
Algorithm2["CRC32"] = "crc32";
|
|
22
|
+
Algorithm2["CRC32C"] = "crc32c";
|
|
23
|
+
return Algorithm2;
|
|
24
|
+
})(Algorithm || {});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
14
28
|
// src/fulhash/errors.ts
|
|
15
29
|
var FulHashError, UnsupportedAlgorithmError, InvalidChecksumError, InvalidChecksumFormatError, DigestStateError;
|
|
16
30
|
var init_errors = __esm({
|
|
@@ -54,24 +68,70 @@ var init_errors = __esm({
|
|
|
54
68
|
};
|
|
55
69
|
}
|
|
56
70
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
function hexToBytes(hex) {
|
|
72
|
+
const bytes = new Uint8Array(4);
|
|
73
|
+
for (let i = 0; i < 4; i++) {
|
|
74
|
+
bytes[i] = Number.parseInt(hex.substr(i * 2, 2), 16);
|
|
75
|
+
}
|
|
76
|
+
return bytes;
|
|
77
|
+
}
|
|
78
|
+
async function hashBytes(data) {
|
|
79
|
+
const hex = await crc32(data);
|
|
80
|
+
return hexToBytes(hex);
|
|
81
|
+
}
|
|
82
|
+
async function hashString(str, encoding = "utf8") {
|
|
83
|
+
if (encoding !== "utf8") {
|
|
84
|
+
const buf = Buffer.from(str, encoding);
|
|
85
|
+
const hex2 = await crc32(buf);
|
|
86
|
+
return hexToBytes(hex2);
|
|
87
|
+
}
|
|
88
|
+
const hex = await crc32(str);
|
|
89
|
+
return hexToBytes(hex);
|
|
90
|
+
}
|
|
91
|
+
async function createHasher() {
|
|
92
|
+
const hasher = await createCRC32();
|
|
93
|
+
return hasher;
|
|
94
|
+
}
|
|
95
|
+
var init_crc32 = __esm({
|
|
96
|
+
"src/fulhash/algorithms/crc32.ts"() {
|
|
67
97
|
}
|
|
68
98
|
});
|
|
69
|
-
function
|
|
99
|
+
function hexToBytes2(hex) {
|
|
100
|
+
const bytes = new Uint8Array(4);
|
|
101
|
+
for (let i = 0; i < 4; i++) {
|
|
102
|
+
bytes[i] = Number.parseInt(hex.substr(i * 2, 2), 16);
|
|
103
|
+
}
|
|
104
|
+
return bytes;
|
|
105
|
+
}
|
|
106
|
+
async function hashBytes2(data) {
|
|
107
|
+
const hex = await crc32(data, CRC32C_POLYNOMIAL);
|
|
108
|
+
return hexToBytes2(hex);
|
|
109
|
+
}
|
|
110
|
+
async function hashString2(str, encoding = "utf8") {
|
|
111
|
+
if (encoding !== "utf8") {
|
|
112
|
+
const buf = Buffer.from(str, encoding);
|
|
113
|
+
const hex2 = await crc32(buf, CRC32C_POLYNOMIAL);
|
|
114
|
+
return hexToBytes2(hex2);
|
|
115
|
+
}
|
|
116
|
+
const hex = await crc32(str, CRC32C_POLYNOMIAL);
|
|
117
|
+
return hexToBytes2(hex);
|
|
118
|
+
}
|
|
119
|
+
async function createHasher2() {
|
|
120
|
+
const hasher = await createCRC32(CRC32C_POLYNOMIAL);
|
|
121
|
+
return hasher;
|
|
122
|
+
}
|
|
123
|
+
var CRC32C_POLYNOMIAL;
|
|
124
|
+
var init_crc32c = __esm({
|
|
125
|
+
"src/fulhash/algorithms/crc32c.ts"() {
|
|
126
|
+
CRC32C_POLYNOMIAL = 2197175160;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
function hashBytes3(data) {
|
|
70
130
|
const hash2 = createHash("sha256");
|
|
71
131
|
hash2.update(data);
|
|
72
132
|
return new Uint8Array(hash2.digest());
|
|
73
133
|
}
|
|
74
|
-
function
|
|
134
|
+
function hashString3(str, encoding = "utf8") {
|
|
75
135
|
const hash2 = createHash("sha256");
|
|
76
136
|
hash2.update(str, encoding);
|
|
77
137
|
return new Uint8Array(hash2.digest());
|
|
@@ -80,25 +140,25 @@ var init_sha256 = __esm({
|
|
|
80
140
|
"src/fulhash/algorithms/sha256.ts"() {
|
|
81
141
|
}
|
|
82
142
|
});
|
|
83
|
-
function
|
|
143
|
+
function hexToBytes3(hex) {
|
|
84
144
|
const bytes = new Uint8Array(16);
|
|
85
145
|
for (let i = 0; i < 16; i++) {
|
|
86
146
|
bytes[i] = Number.parseInt(hex.substr(i * 2, 2), 16);
|
|
87
147
|
}
|
|
88
148
|
return bytes;
|
|
89
149
|
}
|
|
90
|
-
async function
|
|
150
|
+
async function hashBytes4(data) {
|
|
91
151
|
const hex = await xxhash128(data);
|
|
92
|
-
return
|
|
152
|
+
return hexToBytes3(hex);
|
|
93
153
|
}
|
|
94
|
-
async function
|
|
154
|
+
async function hashString4(str, encoding = "utf8") {
|
|
95
155
|
if (encoding !== "utf8") {
|
|
96
156
|
throw new FulHashError(
|
|
97
157
|
"XXH3-128 only supports UTF-8 encoding. Use utf8 encoding or convert data to Uint8Array."
|
|
98
158
|
);
|
|
99
159
|
}
|
|
100
160
|
const hex = await xxhash128(str);
|
|
101
|
-
return
|
|
161
|
+
return hexToBytes3(hex);
|
|
102
162
|
}
|
|
103
163
|
var init_xxh3 = __esm({
|
|
104
164
|
"src/fulhash/algorithms/xxh3.ts"() {
|
|
@@ -110,43 +170,66 @@ var init_xxh3 = __esm({
|
|
|
110
170
|
var hash_exports = {};
|
|
111
171
|
__export(hash_exports, {
|
|
112
172
|
hash: () => hash,
|
|
113
|
-
hashBytes: () =>
|
|
114
|
-
hashString: () =>
|
|
173
|
+
hashBytes: () => hashBytes5,
|
|
174
|
+
hashString: () => hashString5
|
|
115
175
|
});
|
|
116
176
|
async function hash(input, options) {
|
|
117
177
|
const algorithm = options?.algorithm ?? "xxh3-128" /* XXH3_128 */;
|
|
118
178
|
const encoding = options?.encoding ?? "utf8";
|
|
119
179
|
let bytes;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
180
|
+
switch (algorithm) {
|
|
181
|
+
case "sha256" /* SHA256 */:
|
|
182
|
+
if (typeof input === "string") {
|
|
183
|
+
bytes = hashString3(input, encoding);
|
|
184
|
+
} else {
|
|
185
|
+
bytes = hashBytes3(input);
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
case "xxh3-128" /* XXH3_128 */:
|
|
189
|
+
if (typeof input === "string") {
|
|
190
|
+
if (encoding !== "utf8") {
|
|
191
|
+
bytes = await hashBytes4(Buffer.from(input, encoding));
|
|
192
|
+
} else {
|
|
193
|
+
bytes = await hashString4(input, "utf8");
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
bytes = await hashBytes4(input);
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
case "crc32" /* CRC32 */:
|
|
200
|
+
if (typeof input === "string") {
|
|
201
|
+
bytes = await hashString(input, encoding);
|
|
202
|
+
} else {
|
|
203
|
+
bytes = await hashBytes(input);
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
case "crc32c" /* CRC32C */:
|
|
207
|
+
if (typeof input === "string") {
|
|
208
|
+
bytes = await hashString2(input, encoding);
|
|
209
|
+
} else {
|
|
210
|
+
bytes = await hashBytes2(input);
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
default:
|
|
214
|
+
throw new UnsupportedAlgorithmError(algorithm, Object.values(Algorithm));
|
|
134
215
|
}
|
|
135
216
|
return new Digest(algorithm, bytes);
|
|
136
217
|
}
|
|
137
|
-
async function
|
|
218
|
+
async function hashString5(str, options) {
|
|
138
219
|
return hash(str, options);
|
|
139
220
|
}
|
|
140
|
-
async function
|
|
221
|
+
async function hashBytes5(data, options) {
|
|
141
222
|
return hash(data, options);
|
|
142
223
|
}
|
|
143
224
|
var init_hash = __esm({
|
|
144
225
|
"src/fulhash/hash.ts"() {
|
|
226
|
+
init_types();
|
|
227
|
+
init_crc32();
|
|
228
|
+
init_crc32c();
|
|
145
229
|
init_sha256();
|
|
146
230
|
init_xxh3();
|
|
147
231
|
init_digest();
|
|
148
232
|
init_errors();
|
|
149
|
-
init_types();
|
|
150
233
|
}
|
|
151
234
|
});
|
|
152
235
|
|
|
@@ -154,8 +237,8 @@ var init_hash = __esm({
|
|
|
154
237
|
var Digest;
|
|
155
238
|
var init_digest = __esm({
|
|
156
239
|
"src/fulhash/digest.ts"() {
|
|
157
|
-
init_errors();
|
|
158
240
|
init_types();
|
|
241
|
+
init_errors();
|
|
159
242
|
Digest = class _Digest {
|
|
160
243
|
algorithm;
|
|
161
244
|
_bytes;
|
|
@@ -169,7 +252,7 @@ var init_digest = __esm({
|
|
|
169
252
|
Object.freeze(this);
|
|
170
253
|
}
|
|
171
254
|
get bytes() {
|
|
172
|
-
return
|
|
255
|
+
return Array.from(this._bytes);
|
|
173
256
|
}
|
|
174
257
|
toJSON() {
|
|
175
258
|
return {
|
|
@@ -199,7 +282,21 @@ var init_digest = __esm({
|
|
|
199
282
|
"hex must contain only lowercase hexadecimal characters"
|
|
200
283
|
);
|
|
201
284
|
}
|
|
202
|
-
|
|
285
|
+
let expectedLength;
|
|
286
|
+
switch (algorithm) {
|
|
287
|
+
case "xxh3-128" /* XXH3_128 */:
|
|
288
|
+
expectedLength = 32;
|
|
289
|
+
break;
|
|
290
|
+
case "sha256" /* SHA256 */:
|
|
291
|
+
expectedLength = 64;
|
|
292
|
+
break;
|
|
293
|
+
case "crc32" /* CRC32 */:
|
|
294
|
+
case "crc32c" /* CRC32C */:
|
|
295
|
+
expectedLength = 8;
|
|
296
|
+
break;
|
|
297
|
+
default:
|
|
298
|
+
throw new UnsupportedAlgorithmError(algorithm, Object.values(Algorithm));
|
|
299
|
+
}
|
|
203
300
|
if (hex.length !== expectedLength) {
|
|
204
301
|
throw new InvalidChecksumError(
|
|
205
302
|
formatted,
|
|
@@ -232,14 +329,17 @@ var init_digest = __esm({
|
|
|
232
329
|
});
|
|
233
330
|
|
|
234
331
|
// src/fulhash/index.ts
|
|
332
|
+
init_types();
|
|
333
|
+
|
|
334
|
+
// src/fulhash/convenience.ts
|
|
235
335
|
init_digest();
|
|
236
|
-
init_errors();
|
|
237
|
-
init_hash();
|
|
238
336
|
|
|
239
337
|
// src/fulhash/stream.ts
|
|
338
|
+
init_types();
|
|
339
|
+
init_crc32();
|
|
340
|
+
init_crc32c();
|
|
240
341
|
init_digest();
|
|
241
342
|
init_errors();
|
|
242
|
-
init_types();
|
|
243
343
|
|
|
244
344
|
// src/fulhash/wasm-loader.ts
|
|
245
345
|
init_errors();
|
|
@@ -260,7 +360,7 @@ async function initializeWasm() {
|
|
|
260
360
|
});
|
|
261
361
|
return initPromise;
|
|
262
362
|
}
|
|
263
|
-
async function
|
|
363
|
+
async function createHasher3() {
|
|
264
364
|
if (!isWasmReady) {
|
|
265
365
|
throw new FulHashError("WASM not initialized. Call initializeWasm() first.");
|
|
266
366
|
}
|
|
@@ -268,6 +368,15 @@ async function createHasher() {
|
|
|
268
368
|
}
|
|
269
369
|
|
|
270
370
|
// src/fulhash/stream.ts
|
|
371
|
+
function intToBytes(crc) {
|
|
372
|
+
const bytes = new Uint8Array(4);
|
|
373
|
+
const unsigned = crc >>> 0;
|
|
374
|
+
bytes[0] = unsigned >>> 24 & 255;
|
|
375
|
+
bytes[1] = unsigned >>> 16 & 255;
|
|
376
|
+
bytes[2] = unsigned >>> 8 & 255;
|
|
377
|
+
bytes[3] = unsigned & 255;
|
|
378
|
+
return bytes;
|
|
379
|
+
}
|
|
271
380
|
var BaseStreamHasher = class {
|
|
272
381
|
state = "initial" /* INITIAL */;
|
|
273
382
|
algorithm;
|
|
@@ -352,23 +461,153 @@ var XXH3StreamHasher = class extends BaseStreamHasher {
|
|
|
352
461
|
return this;
|
|
353
462
|
}
|
|
354
463
|
};
|
|
464
|
+
var CRC32StreamHasher = class extends BaseStreamHasher {
|
|
465
|
+
hasher = null;
|
|
466
|
+
constructor() {
|
|
467
|
+
super("crc32" /* CRC32 */);
|
|
468
|
+
}
|
|
469
|
+
async init() {
|
|
470
|
+
this.hasher = await createHasher();
|
|
471
|
+
this.hasher.init();
|
|
472
|
+
}
|
|
473
|
+
update(data) {
|
|
474
|
+
this.ensureNotFinalized();
|
|
475
|
+
this.markUpdating();
|
|
476
|
+
if (!this.hasher) {
|
|
477
|
+
throw new Error("Hasher not initialized");
|
|
478
|
+
}
|
|
479
|
+
if (typeof data === "string") {
|
|
480
|
+
const encoder = new TextEncoder();
|
|
481
|
+
this.hasher.update(encoder.encode(data));
|
|
482
|
+
} else {
|
|
483
|
+
this.hasher.update(data);
|
|
484
|
+
}
|
|
485
|
+
return this;
|
|
486
|
+
}
|
|
487
|
+
digest() {
|
|
488
|
+
this.ensureUpdating();
|
|
489
|
+
this.markFinalized();
|
|
490
|
+
if (!this.hasher) throw new Error("Hasher not initialized");
|
|
491
|
+
const hex = this.hasher.digest();
|
|
492
|
+
const bytes = intToBytes(parseInt(hex, 16));
|
|
493
|
+
return new Digest(this.algorithm, bytes);
|
|
494
|
+
}
|
|
495
|
+
reset() {
|
|
496
|
+
if (!this.hasher) throw new Error("Hasher not initialized");
|
|
497
|
+
this.hasher.init();
|
|
498
|
+
this.markInitial();
|
|
499
|
+
return this;
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
var CRC32CStreamHasher = class extends BaseStreamHasher {
|
|
503
|
+
hasher = null;
|
|
504
|
+
constructor() {
|
|
505
|
+
super("crc32c" /* CRC32C */);
|
|
506
|
+
}
|
|
507
|
+
async init() {
|
|
508
|
+
this.hasher = await createHasher2();
|
|
509
|
+
this.hasher.init();
|
|
510
|
+
}
|
|
511
|
+
update(data) {
|
|
512
|
+
this.ensureNotFinalized();
|
|
513
|
+
this.markUpdating();
|
|
514
|
+
if (!this.hasher) throw new Error("Hasher not initialized");
|
|
515
|
+
if (typeof data === "string") {
|
|
516
|
+
const encoder = new TextEncoder();
|
|
517
|
+
this.hasher.update(encoder.encode(data));
|
|
518
|
+
} else {
|
|
519
|
+
this.hasher.update(data);
|
|
520
|
+
}
|
|
521
|
+
return this;
|
|
522
|
+
}
|
|
523
|
+
digest() {
|
|
524
|
+
this.ensureUpdating();
|
|
525
|
+
this.markFinalized();
|
|
526
|
+
if (!this.hasher) throw new Error("Hasher not initialized");
|
|
527
|
+
const hex = this.hasher.digest();
|
|
528
|
+
const bytes = intToBytes(parseInt(hex, 16));
|
|
529
|
+
return new Digest(this.algorithm, bytes);
|
|
530
|
+
}
|
|
531
|
+
reset() {
|
|
532
|
+
if (!this.hasher) throw new Error("Hasher not initialized");
|
|
533
|
+
this.hasher.init();
|
|
534
|
+
this.markInitial();
|
|
535
|
+
return this;
|
|
536
|
+
}
|
|
537
|
+
};
|
|
355
538
|
async function createStreamHasher(options = {}) {
|
|
356
539
|
const algorithm = options.algorithm ?? "xxh3-128" /* XXH3_128 */;
|
|
357
|
-
|
|
358
|
-
|
|
540
|
+
switch (algorithm) {
|
|
541
|
+
case "sha256" /* SHA256 */:
|
|
542
|
+
return new SHA256StreamHasher();
|
|
543
|
+
case "xxh3-128" /* XXH3_128 */: {
|
|
544
|
+
await initializeWasm();
|
|
545
|
+
const wasmHasher = await createHasher3();
|
|
546
|
+
return new XXH3StreamHasher(wasmHasher);
|
|
547
|
+
}
|
|
548
|
+
case "crc32" /* CRC32 */: {
|
|
549
|
+
const hasher = new CRC32StreamHasher();
|
|
550
|
+
await hasher.init();
|
|
551
|
+
return hasher;
|
|
552
|
+
}
|
|
553
|
+
case "crc32c" /* CRC32C */: {
|
|
554
|
+
const hasher = new CRC32CStreamHasher();
|
|
555
|
+
await hasher.init();
|
|
556
|
+
return hasher;
|
|
557
|
+
}
|
|
558
|
+
default:
|
|
559
|
+
throw new UnsupportedAlgorithmError(algorithm, Object.values(Algorithm));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/fulhash/convenience.ts
|
|
564
|
+
async function multiHash(input, algorithms, encoding = "utf8") {
|
|
565
|
+
const uniqueAlgorithms = [...new Set(algorithms)];
|
|
566
|
+
const hashers = await Promise.all(
|
|
567
|
+
uniqueAlgorithms.map((algo) => createStreamHasher({ algorithm: algo }))
|
|
568
|
+
);
|
|
569
|
+
if (typeof input === "string") {
|
|
570
|
+
if (encoding !== "utf8") {
|
|
571
|
+
const buf = Buffer.from(input, encoding);
|
|
572
|
+
for (const hasher of hashers) {
|
|
573
|
+
hasher.update(buf);
|
|
574
|
+
}
|
|
575
|
+
} else {
|
|
576
|
+
for (const hasher of hashers) {
|
|
577
|
+
hasher.update(input);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
} else if (input instanceof Uint8Array) {
|
|
581
|
+
for (const hasher of hashers) {
|
|
582
|
+
hasher.update(input);
|
|
583
|
+
}
|
|
584
|
+
} else {
|
|
585
|
+
for await (const chunk of input) {
|
|
586
|
+
for (const hasher of hashers) {
|
|
587
|
+
hasher.update(chunk);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
359
590
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
return new XXH3StreamHasher(wasmHasher);
|
|
591
|
+
const result = {};
|
|
592
|
+
for (let i = 0; i < uniqueAlgorithms.length; i++) {
|
|
593
|
+
result[uniqueAlgorithms[i]] = hashers[i].digest();
|
|
364
594
|
}
|
|
365
|
-
|
|
595
|
+
return result;
|
|
596
|
+
}
|
|
597
|
+
async function verify(input, checksum, encoding = "utf8") {
|
|
598
|
+
const expected = Digest.parse(checksum);
|
|
599
|
+
const result = await multiHash(input, [expected.algorithm], encoding);
|
|
600
|
+
const actual = result[expected.algorithm];
|
|
601
|
+
if (!actual) return false;
|
|
602
|
+
return actual.algorithm === expected.algorithm && actual.hex === expected.hex;
|
|
366
603
|
}
|
|
367
604
|
|
|
368
605
|
// src/fulhash/index.ts
|
|
369
|
-
|
|
606
|
+
init_digest();
|
|
607
|
+
init_errors();
|
|
608
|
+
init_hash();
|
|
370
609
|
var VERSION = "1.0.0";
|
|
371
610
|
|
|
372
|
-
export { Algorithm, Digest, DigestStateError, FulHashError, InvalidChecksumError, InvalidChecksumFormatError, UnsupportedAlgorithmError, VERSION, createStreamHasher, hash,
|
|
611
|
+
export { Algorithm, Digest, DigestStateError, FulHashError, InvalidChecksumError, InvalidChecksumFormatError, UnsupportedAlgorithmError, VERSION, createStreamHasher, hash, hashBytes5 as hashBytes, hashString5 as hashString, multiHash, verify };
|
|
373
612
|
//# sourceMappingURL=index.js.map
|
|
374
613
|
//# sourceMappingURL=index.js.map
|