@hkdigital/lib-core 0.4.56 → 0.4.57
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/util/checksum/README.md +267 -0
- package/dist/util/checksum/blockCrc32.d.ts +44 -0
- package/dist/util/checksum/blockCrc32.js +174 -0
- package/dist/util/checksum/bufferCrc32.d.ts +11 -0
- package/dist/util/checksum/bufferCrc32.js +69 -0
- package/dist/util/checksum/crcTables.d.ts +31 -0
- package/dist/util/checksum/crcTables.js +79 -0
- package/dist/util/checksum/stringCrc32.d.ts +12 -0
- package/dist/util/checksum/stringCrc32.js +33 -0
- package/dist/util/checksum/typedef.d.ts +10 -0
- package/dist/util/checksum/typedef.js +11 -0
- package/dist/util/checksum.d.ts +4 -0
- package/dist/util/checksum.js +23 -0
- package/package.json +1 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# CRC32 Checksum Utilities
|
|
2
|
+
|
|
3
|
+
Fast, modular CRC32 implementation with support for strings, buffers, and
|
|
4
|
+
large file processing.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Standard CRC32**: IEEE 802.3 compatible (ZIP, PNG, Ethernet)
|
|
9
|
+
- **CRC32C variant**: Castagnoli polynomial for improved performance
|
|
10
|
+
- **Buffer support**: ArrayBuffer, DataView, Uint8Array
|
|
11
|
+
- **Block processing**: Custom format for large files
|
|
12
|
+
- **Zero dependencies**: Pure JavaScript implementation
|
|
13
|
+
- **TypeScript ready**: Full JSDoc type annotations
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import { stringToCrc32 } from './stringCrc32.js';
|
|
19
|
+
import { bufferToCrc32 } from './bufferCrc32.js';
|
|
20
|
+
import { bufferToBlockCrc32 } from './blockCrc32.js';
|
|
21
|
+
import { CRC32, CRC32C } from './crcTables.js';
|
|
22
|
+
|
|
23
|
+
// String checksums (IEEE 802.3 standard)
|
|
24
|
+
const crc = stringToCrc32('hello world');
|
|
25
|
+
console.log(crc); // 222957957 (0xd4a1185)
|
|
26
|
+
|
|
27
|
+
// Standard test vector verification
|
|
28
|
+
console.log(stringToCrc32('123456789')); // 3421780262 (0xcbf43926)
|
|
29
|
+
console.log(stringToCrc32('123456789', CRC32C)); // 3808858755 (0xe3069283)
|
|
30
|
+
|
|
31
|
+
// Buffer checksums (standard)
|
|
32
|
+
const buffer = new TextEncoder().encode('hello world');
|
|
33
|
+
const bufferCrc = bufferToCrc32(buffer);
|
|
34
|
+
console.log(bufferCrc); // 222957957 (same as string)
|
|
35
|
+
|
|
36
|
+
// Large file processing (custom format)
|
|
37
|
+
const result = bufferToBlockCrc32(buffer, 1024);
|
|
38
|
+
console.log(result.checksumList); // [222957957]
|
|
39
|
+
console.log(result.toBase58()); // Base58-encoded result
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Module Overview
|
|
43
|
+
|
|
44
|
+
### `crcTables.js`
|
|
45
|
+
Shared CRC table generation and constants.
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
import { getCrcTable, CRC32, CRC32C } from './crcTables.js';
|
|
49
|
+
|
|
50
|
+
const table = getCrcTable(CRC32); // Get lookup table
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `stringCrc32.js`
|
|
54
|
+
String to CRC32 conversion.
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
import { stringToCrc32, CRC32, CRC32C } from './stringCrc32.js';
|
|
58
|
+
|
|
59
|
+
const crc = stringToCrc32('text', CRC32); // Standard CRC32
|
|
60
|
+
const crcC = stringToCrc32('text', CRC32C); // CRC32C variant
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### `bufferCrc32.js`
|
|
64
|
+
Standard buffer CRC32 - compatible with external tools.
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
import { bufferToCrc32 } from './bufferCrc32.js';
|
|
68
|
+
|
|
69
|
+
// Works with all buffer types
|
|
70
|
+
const arrayBuffer = new ArrayBuffer(100);
|
|
71
|
+
const uint8Array = new Uint8Array(100);
|
|
72
|
+
const dataView = new DataView(arrayBuffer);
|
|
73
|
+
|
|
74
|
+
const crc1 = bufferToCrc32(arrayBuffer);
|
|
75
|
+
const crc2 = bufferToCrc32(uint8Array, 10, 50); // Offset & length
|
|
76
|
+
const crc3 = bufferToCrc32(dataView);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `blockCrc32.js`
|
|
80
|
+
Custom block-based processing for large files.
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
import {
|
|
84
|
+
bufferToBlockCrc32,
|
|
85
|
+
blockCrc32Iterator,
|
|
86
|
+
bufferChecksumEquals,
|
|
87
|
+
optimalBlockSize
|
|
88
|
+
} from './blockCrc32.js';
|
|
89
|
+
|
|
90
|
+
// Process large buffer in blocks
|
|
91
|
+
const result = bufferToBlockCrc32(largeBuffer);
|
|
92
|
+
console.log(result.checksumList); // Array of CRC32 values
|
|
93
|
+
console.log(result.toBase58()); // Concatenated Base58 string
|
|
94
|
+
|
|
95
|
+
// Stream processing
|
|
96
|
+
for (const block of blockCrc32Iterator(buffer, 1024)) {
|
|
97
|
+
console.log(`Block at ${block.offset}: ${block.toBase58()}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Verification
|
|
101
|
+
const isValid = bufferChecksumEquals(buffer, expectedChecksum);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## CRC32 Variants
|
|
105
|
+
|
|
106
|
+
### CRC32 (IEEE 802.3)
|
|
107
|
+
- **Use case**: General purpose, file integrity
|
|
108
|
+
- **Compatible with**: ZIP files, PNG images, Ethernet frames
|
|
109
|
+
- **Polynomial**: `0xEDB88320` (reversed)
|
|
110
|
+
- **Standard test**: `"123456789"` → `0xcbf43926` ✅
|
|
111
|
+
|
|
112
|
+
### CRC32C (Castagnoli)
|
|
113
|
+
- **Use case**: High-performance applications
|
|
114
|
+
- **Compatible with**: iSCSI, SCTP, certain databases
|
|
115
|
+
- **Polynomial**: `0x82f63b78` (reversed)
|
|
116
|
+
- **Standard test**: `"123456789"` → `0xe3069283` ✅
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
import { CRC32, CRC32C } from './crcTables.js';
|
|
120
|
+
|
|
121
|
+
// All functions accept variant parameter
|
|
122
|
+
stringToCrc32('data', CRC32); // Default
|
|
123
|
+
stringToCrc32('data', CRC32C); // Castagnoli
|
|
124
|
+
|
|
125
|
+
// Verify against standard test vectors
|
|
126
|
+
console.assert(stringToCrc32('123456789', CRC32) === 0xcbf43926);
|
|
127
|
+
console.assert(stringToCrc32('123456789', CRC32C) === 0xe3069283);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Block Processing Details
|
|
131
|
+
|
|
132
|
+
### Standard vs Block Format
|
|
133
|
+
|
|
134
|
+
**Standard CRC32** (compatible):
|
|
135
|
+
```
|
|
136
|
+
Input: [large file data]
|
|
137
|
+
Output: 222957957 (single 32-bit value)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Block CRC32** (proprietary):
|
|
141
|
+
```
|
|
142
|
+
Input: [large file data split into blocks]
|
|
143
|
+
Block 1: 222957957 → Base58 encoded
|
|
144
|
+
Block 2: 891347246 → Base58 encoded
|
|
145
|
+
Block 3: 234567890 → Base58 encoded
|
|
146
|
+
Output: [concatenated Base58 string]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Block Size Selection
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
// Automatic sizing
|
|
153
|
+
const blockSize = optimalBlockSize(buffer);
|
|
154
|
+
|
|
155
|
+
// Manual sizing
|
|
156
|
+
const result = bufferToBlockCrc32(buffer, 65536); // 64KB blocks
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Size Guidelines:**
|
|
160
|
+
- **Small files** (< 100KB): Single block
|
|
161
|
+
- **Medium files** (100KB - 2MB): 100KB blocks
|
|
162
|
+
- **Large files** (> 2MB): Adaptive sizing (max 20 blocks)
|
|
163
|
+
|
|
164
|
+
### Use Cases
|
|
165
|
+
|
|
166
|
+
**Standard CRC32:**
|
|
167
|
+
- File integrity verification
|
|
168
|
+
- Compatibility with external tools
|
|
169
|
+
- Single checksum for entire data
|
|
170
|
+
|
|
171
|
+
**Block CRC32:**
|
|
172
|
+
- Large file streaming
|
|
173
|
+
- Partial corruption detection
|
|
174
|
+
- Progress tracking during transfer
|
|
175
|
+
- Resume capability for interrupted uploads
|
|
176
|
+
|
|
177
|
+
## Error Handling
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
// Invalid CRC variant
|
|
181
|
+
getCrcTable('invalid'); // throws "Invalid variant [invalid]"
|
|
182
|
+
|
|
183
|
+
// Unsupported buffer type
|
|
184
|
+
bufferToCrc32('string'); // throws "Unsupported buffer type"
|
|
185
|
+
|
|
186
|
+
// All functions validate inputs and provide clear error messages
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Standards Compliance
|
|
190
|
+
|
|
191
|
+
✅ **Verified Implementation**: Both CRC32 and CRC32C pass standard test vectors
|
|
192
|
+
- CRC32 IEEE 802.3: `"123456789"` → `0xcbf43926`
|
|
193
|
+
- CRC32C Castagnoli: `"123456789"` → `0xe3069283`
|
|
194
|
+
|
|
195
|
+
✅ **Full Compatibility**:
|
|
196
|
+
- ZIP/PNG/Ethernet frames (CRC32)
|
|
197
|
+
- iSCSI/SCTP protocols (CRC32C)
|
|
198
|
+
|
|
199
|
+
## Performance Notes
|
|
200
|
+
|
|
201
|
+
- **Table caching**: CRC tables generated once per variant
|
|
202
|
+
- **Memory efficient**: Block processing doesn't load entire files
|
|
203
|
+
- **Browser compatible**: Works in all modern browsers
|
|
204
|
+
- **Standards compliant**: Verified against authoritative test vectors
|
|
205
|
+
- **No dependencies**: Pure JavaScript implementation
|
|
206
|
+
|
|
207
|
+
## Testing
|
|
208
|
+
|
|
209
|
+
Run tests for all modules:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
pnpm test:file src/lib/util/checksum/
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Run specific test files:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
pnpm test:file src/lib/util/checksum/stringCrc32.test.js
|
|
219
|
+
pnpm test:file src/lib/util/checksum/bufferCrc32.test.js
|
|
220
|
+
pnpm test:file src/lib/util/checksum/blockCrc32.test.js
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## TypeScript Support
|
|
224
|
+
|
|
225
|
+
All modules include comprehensive JSDoc type annotations:
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
/**
|
|
229
|
+
* @param {string} str - String to calculate checksum for
|
|
230
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
231
|
+
* @returns {number} Unsigned 32-bit CRC32 value
|
|
232
|
+
*/
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Migration Guide
|
|
236
|
+
|
|
237
|
+
### From Original Implementation
|
|
238
|
+
|
|
239
|
+
**Old:**
|
|
240
|
+
```javascript
|
|
241
|
+
import { stringToCrc32 } from './crc32.js';
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**New:**
|
|
245
|
+
```javascript
|
|
246
|
+
import { stringToCrc32 } from './stringCrc32.js';
|
|
247
|
+
// Same API, no changes needed
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Adding Block Processing
|
|
251
|
+
|
|
252
|
+
**Before:**
|
|
253
|
+
```javascript
|
|
254
|
+
// Single CRC32 for entire file
|
|
255
|
+
const crc = bufferToCrc32(largeFile);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**After:**
|
|
259
|
+
```javascript
|
|
260
|
+
// Block-based processing
|
|
261
|
+
const result = bufferToBlockCrc32(largeFile);
|
|
262
|
+
const checksum = result.toBase58(); // Custom format
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
Part of HKdigital library core utilities.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate block-based CRC32 for buffer
|
|
3
|
+
*
|
|
4
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to process
|
|
5
|
+
* @param {number} [blockSize] - Block size (auto-calculated if not provided)
|
|
6
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
7
|
+
*
|
|
8
|
+
* @returns {object} Block checksum result
|
|
9
|
+
*/
|
|
10
|
+
export function bufferToBlockCrc32(buffer: ArrayBuffer | DataView | Uint8Array, blockSize?: number, variant?: import("./crcTables.js").CrcVariant): object;
|
|
11
|
+
/**
|
|
12
|
+
* Iterate over buffer blocks and yield CRC32 for each
|
|
13
|
+
*
|
|
14
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to process
|
|
15
|
+
* @param {number} [blockSize] - Block size
|
|
16
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
17
|
+
*
|
|
18
|
+
* @yields {object} Block checksum with value and encoding methods
|
|
19
|
+
*/
|
|
20
|
+
export function blockCrc32Iterator(buffer: ArrayBuffer | DataView | Uint8Array, blockSize?: number, variant?: import("./crcTables.js").CrcVariant): Generator<{
|
|
21
|
+
value: number;
|
|
22
|
+
offset: number;
|
|
23
|
+
size: number;
|
|
24
|
+
toBase58: () => string;
|
|
25
|
+
}, void, unknown>;
|
|
26
|
+
/**
|
|
27
|
+
* Check if buffer checksum matches expected value
|
|
28
|
+
*
|
|
29
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to verify
|
|
30
|
+
* @param {string} expectedChecksum - Expected Base58 checksum string
|
|
31
|
+
* @param {number} [blockSize] - Block size
|
|
32
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
33
|
+
*
|
|
34
|
+
* @returns {boolean} True if checksums match
|
|
35
|
+
*/
|
|
36
|
+
export function bufferChecksumEquals(buffer: ArrayBuffer | DataView | Uint8Array, expectedChecksum: string, blockSize?: number, variant?: import("./crcTables.js").CrcVariant): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Calculate optimal block size for buffer
|
|
39
|
+
*
|
|
40
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to analyze
|
|
41
|
+
*
|
|
42
|
+
* @returns {number} Optimal block size
|
|
43
|
+
*/
|
|
44
|
+
export function optimalBlockSize(buffer: ArrayBuffer | DataView | Uint8Array): number;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom block-based CRC32 calculation
|
|
3
|
+
*
|
|
4
|
+
* Splits large buffers into blocks and concatenates individual CRC32 values.
|
|
5
|
+
* Creates proprietary checksum format for efficient large file processing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { base58fromNumber } from '../bases.js';
|
|
9
|
+
|
|
10
|
+
import { bufferToCrc32 } from './bufferCrc32.js';
|
|
11
|
+
import { CRC32 } from './crcTables.js';
|
|
12
|
+
|
|
13
|
+
/* ---------------------------------------------------------------- Constants */
|
|
14
|
+
|
|
15
|
+
/** @type {number} */
|
|
16
|
+
const MIN_BUFFER_BLOCK_SIZE = 100000;
|
|
17
|
+
|
|
18
|
+
/** @type {number} */
|
|
19
|
+
const MAX_BUFFER_BLOCKS = 20;
|
|
20
|
+
|
|
21
|
+
/** @type {number} */
|
|
22
|
+
const OPTIMAL_BLOCK_SIZE_FACTOR = 0.95;
|
|
23
|
+
|
|
24
|
+
/* ---------------------------------------------------------------- Functions */
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Calculate block-based CRC32 for buffer
|
|
28
|
+
*
|
|
29
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to process
|
|
30
|
+
* @param {number} [blockSize] - Block size (auto-calculated if not provided)
|
|
31
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
32
|
+
*
|
|
33
|
+
* @returns {object} Block checksum result
|
|
34
|
+
*/
|
|
35
|
+
export function bufferToBlockCrc32(buffer, blockSize, variant = CRC32) {
|
|
36
|
+
if (!blockSize) {
|
|
37
|
+
blockSize = optimalBlockSize(buffer);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** @type {number[]} */
|
|
41
|
+
const checksumList = [];
|
|
42
|
+
|
|
43
|
+
for (const block of blockCrc32Iterator(buffer, blockSize, variant)) {
|
|
44
|
+
checksumList.push(block.value);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
checksumList,
|
|
49
|
+
blockSize,
|
|
50
|
+
toBase58: () => checksumsToBase58(checksumList)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Iterate over buffer blocks and yield CRC32 for each
|
|
56
|
+
*
|
|
57
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to process
|
|
58
|
+
* @param {number} [blockSize] - Block size
|
|
59
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
60
|
+
*
|
|
61
|
+
* @yields {object} Block checksum with value and encoding methods
|
|
62
|
+
*/
|
|
63
|
+
export function* blockCrc32Iterator(buffer, blockSize, variant = CRC32) {
|
|
64
|
+
if (!blockSize) {
|
|
65
|
+
blockSize = optimalBlockSize(buffer);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const bufferLength = getBufferLength(buffer);
|
|
69
|
+
|
|
70
|
+
for (let offset = 0; offset < bufferLength; offset += blockSize) {
|
|
71
|
+
const currentBlockSize = Math.min(blockSize, bufferLength - offset);
|
|
72
|
+
|
|
73
|
+
/** @type {number} */
|
|
74
|
+
const value = bufferToCrc32(buffer, offset, currentBlockSize, variant);
|
|
75
|
+
|
|
76
|
+
yield {
|
|
77
|
+
value,
|
|
78
|
+
offset,
|
|
79
|
+
size: currentBlockSize,
|
|
80
|
+
toBase58: () => base58fromNumber(value)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if buffer checksum matches expected value
|
|
87
|
+
*
|
|
88
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to verify
|
|
89
|
+
* @param {string} expectedChecksum - Expected Base58 checksum string
|
|
90
|
+
* @param {number} [blockSize] - Block size
|
|
91
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
92
|
+
*
|
|
93
|
+
* @returns {boolean} True if checksums match
|
|
94
|
+
*/
|
|
95
|
+
export function bufferChecksumEquals(
|
|
96
|
+
buffer,
|
|
97
|
+
expectedChecksum,
|
|
98
|
+
blockSize,
|
|
99
|
+
variant = CRC32
|
|
100
|
+
) {
|
|
101
|
+
if (!blockSize) {
|
|
102
|
+
blockSize = optimalBlockSize(buffer);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** @type {string} */
|
|
106
|
+
let remaining = expectedChecksum;
|
|
107
|
+
|
|
108
|
+
for (const block of blockCrc32Iterator(buffer, blockSize, variant)) {
|
|
109
|
+
const blockChecksum = block.toBase58();
|
|
110
|
+
|
|
111
|
+
if (!remaining.startsWith(blockChecksum)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
remaining = remaining.slice(blockChecksum.length);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return remaining.length === 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Calculate optimal block size for buffer
|
|
123
|
+
*
|
|
124
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to analyze
|
|
125
|
+
*
|
|
126
|
+
* @returns {number} Optimal block size
|
|
127
|
+
*/
|
|
128
|
+
export function optimalBlockSize(buffer) {
|
|
129
|
+
/** @type {number} */
|
|
130
|
+
const bufferByteLength = getBufferLength(buffer);
|
|
131
|
+
|
|
132
|
+
if (bufferByteLength < MIN_BUFFER_BLOCK_SIZE) {
|
|
133
|
+
return bufferByteLength;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** @type {number} */
|
|
137
|
+
let blockSize = bufferByteLength / MAX_BUFFER_BLOCKS;
|
|
138
|
+
|
|
139
|
+
if (blockSize < MIN_BUFFER_BLOCK_SIZE) {
|
|
140
|
+
return MIN_BUFFER_BLOCK_SIZE;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return Math.ceil(
|
|
144
|
+
blockSize * OPTIMAL_BLOCK_SIZE_FACTOR +
|
|
145
|
+
MIN_BUFFER_BLOCK_SIZE * (1 - OPTIMAL_BLOCK_SIZE_FACTOR)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* ------------------------------------------------------- Internal functions */
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get buffer length safely for different buffer types
|
|
153
|
+
*
|
|
154
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to measure
|
|
155
|
+
*
|
|
156
|
+
* @returns {number} Buffer length in bytes
|
|
157
|
+
*/
|
|
158
|
+
function getBufferLength(buffer) {
|
|
159
|
+
if (buffer instanceof ArrayBuffer || buffer instanceof DataView) {
|
|
160
|
+
return buffer.byteLength;
|
|
161
|
+
}
|
|
162
|
+
return buffer.length;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Convert checksum array to concatenated Base58 string
|
|
167
|
+
*
|
|
168
|
+
* @param {number[]} checksumList - Array of CRC32 values
|
|
169
|
+
*
|
|
170
|
+
* @returns {string} Concatenated Base58 string
|
|
171
|
+
*/
|
|
172
|
+
function checksumsToBase58(checksumList) {
|
|
173
|
+
return checksumList.map(crc => base58fromNumber(crc)).join('');
|
|
174
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate standard CRC32 for buffer
|
|
3
|
+
*
|
|
4
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to checksum
|
|
5
|
+
* @param {number} [byteOffset=0] - Start offset in buffer
|
|
6
|
+
* @param {number} [byteLength] - Number of bytes to process
|
|
7
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
8
|
+
*
|
|
9
|
+
* @returns {number} Unsigned 32-bit CRC32 value
|
|
10
|
+
*/
|
|
11
|
+
export function bufferToCrc32(buffer: ArrayBuffer | DataView | Uint8Array, byteOffset?: number, byteLength?: number, variant?: import("./crcTables.js").CrcVariant): number;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard buffer CRC32 calculation
|
|
3
|
+
*
|
|
4
|
+
* Implements IEEE 802.3 CRC32 over entire buffer.
|
|
5
|
+
* Compatible with ZIP, PNG, and other standard formats.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getCrcTable, CRC32 } from './crcTables.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Calculate standard CRC32 for buffer
|
|
12
|
+
*
|
|
13
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Buffer to checksum
|
|
14
|
+
* @param {number} [byteOffset=0] - Start offset in buffer
|
|
15
|
+
* @param {number} [byteLength] - Number of bytes to process
|
|
16
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
17
|
+
*
|
|
18
|
+
* @returns {number} Unsigned 32-bit CRC32 value
|
|
19
|
+
*/
|
|
20
|
+
export function bufferToCrc32(buffer, byteOffset = 0, byteLength, variant = CRC32) {
|
|
21
|
+
const table = getCrcTable(variant);
|
|
22
|
+
|
|
23
|
+
/** @type {DataView} */
|
|
24
|
+
const dataView = createDataView(buffer, byteOffset, byteLength);
|
|
25
|
+
|
|
26
|
+
/** @type {number} */
|
|
27
|
+
let crc = 0 ^ (-1);
|
|
28
|
+
|
|
29
|
+
for (let j = 0; j < dataView.byteLength; j = j + 1) {
|
|
30
|
+
crc = (crc >>> 8) ^ table[(crc ^ dataView.getUint8(j)) & 0xFF];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (crc ^ (-1)) >>> 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* ------------------------------------------------------- Internal functions */
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create DataView from various buffer types
|
|
40
|
+
*
|
|
41
|
+
* @param {ArrayBuffer|DataView|Uint8Array} buffer - Input buffer
|
|
42
|
+
* @param {number} [byteOffset=0] - Start offset
|
|
43
|
+
* @param {number} [byteLength] - Length to use
|
|
44
|
+
*
|
|
45
|
+
* @returns {DataView} DataView for the buffer
|
|
46
|
+
*/
|
|
47
|
+
function createDataView(buffer, byteOffset = 0, byteLength) {
|
|
48
|
+
if (buffer instanceof DataView) {
|
|
49
|
+
return new DataView(
|
|
50
|
+
buffer.buffer,
|
|
51
|
+
buffer.byteOffset + byteOffset,
|
|
52
|
+
byteLength ?? (buffer.byteLength - byteOffset)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (buffer instanceof ArrayBuffer) {
|
|
57
|
+
return new DataView(buffer, byteOffset, byteLength);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (buffer instanceof Uint8Array) {
|
|
61
|
+
return new DataView(
|
|
62
|
+
buffer.buffer,
|
|
63
|
+
buffer.byteOffset + byteOffset,
|
|
64
|
+
byteLength ?? (buffer.byteLength - byteOffset)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
throw new Error('Unsupported buffer type');
|
|
69
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get CRC lookup table for specified variant
|
|
3
|
+
*
|
|
4
|
+
* @param {CrcVariant} [variant=CRC32] - CRC variant
|
|
5
|
+
*
|
|
6
|
+
* @returns {CrcTable} The CRC lookup table
|
|
7
|
+
*/
|
|
8
|
+
export function getCrcTable(variant?: CrcVariant): CrcTable;
|
|
9
|
+
/**
|
|
10
|
+
* Shared CRC table generation and constants
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {import('./typedef').CrcVariant} CrcVariant
|
|
14
|
+
* Valid CRC32 variant types
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {import('./typedef').CrcTable} CrcTable
|
|
18
|
+
* Lookup table for CRC calculations - array of 256 numbers
|
|
19
|
+
*/
|
|
20
|
+
/** @type {CrcVariant} */
|
|
21
|
+
export const CRC32: CrcVariant;
|
|
22
|
+
/** @type {CrcVariant} */
|
|
23
|
+
export const CRC32C: CrcVariant;
|
|
24
|
+
/**
|
|
25
|
+
* Valid CRC32 variant types
|
|
26
|
+
*/
|
|
27
|
+
export type CrcVariant = import("./typedef").CrcVariant;
|
|
28
|
+
/**
|
|
29
|
+
* Lookup table for CRC calculations - array of 256 numbers
|
|
30
|
+
*/
|
|
31
|
+
export type CrcTable = import("./typedef").CrcTable;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CRC table generation and constants
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import('./typedef').CrcVariant} CrcVariant
|
|
7
|
+
* Valid CRC32 variant types
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {import('./typedef').CrcTable} CrcTable
|
|
12
|
+
* Lookup table for CRC calculations - array of 256 numbers
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* ---------------------------------------------------------------- Constants */
|
|
16
|
+
|
|
17
|
+
/** @type {CrcVariant} */
|
|
18
|
+
export const CRC32 = 'crc32';
|
|
19
|
+
|
|
20
|
+
/** @type {CrcVariant} */
|
|
21
|
+
export const CRC32C = 'crc32c';
|
|
22
|
+
|
|
23
|
+
/** @type {Record<CrcVariant, number>} */
|
|
24
|
+
const START_POLYNOMIALS = {
|
|
25
|
+
[CRC32]: 0xEDB88320,
|
|
26
|
+
[CRC32C]: 0x82f63b78
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** @type {Record<CrcVariant, CrcTable>} */
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
const crcTables = {};
|
|
32
|
+
|
|
33
|
+
/* ---------------------------------------------------------------- Functions */
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get CRC lookup table for specified variant
|
|
37
|
+
*
|
|
38
|
+
* @param {CrcVariant} [variant=CRC32] - CRC variant
|
|
39
|
+
*
|
|
40
|
+
* @returns {CrcTable} The CRC lookup table
|
|
41
|
+
*/
|
|
42
|
+
export function getCrcTable(variant = CRC32) {
|
|
43
|
+
return crcTables[variant] || (crcTables[variant] = makeCRCTable(variant));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ---------------------------------------------------------------- Internals */
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create CRC lookup table for specified variant
|
|
50
|
+
*
|
|
51
|
+
* @param {CrcVariant} variant - CRC variant to create table for
|
|
52
|
+
*
|
|
53
|
+
* @returns {CrcTable} The generated CRC lookup table
|
|
54
|
+
*/
|
|
55
|
+
function makeCRCTable(variant) {
|
|
56
|
+
/** @type {number} */
|
|
57
|
+
let c;
|
|
58
|
+
|
|
59
|
+
/** @type {CrcTable} */
|
|
60
|
+
const crcTable = [];
|
|
61
|
+
|
|
62
|
+
/** @type {number} */
|
|
63
|
+
const startPolynomial = START_POLYNOMIALS[variant];
|
|
64
|
+
|
|
65
|
+
if (!startPolynomial) {
|
|
66
|
+
throw new Error(`Invalid variant [${variant}]`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (let n = 0; n < 256; n = n + 1) {
|
|
70
|
+
c = n;
|
|
71
|
+
|
|
72
|
+
for (let k = 0; k < 8; k = k + 1) {
|
|
73
|
+
c = ((c & 1) ? (startPolynomial ^ (c >>> 1)) : (c >>> 1));
|
|
74
|
+
}
|
|
75
|
+
crcTable[n] = c;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return crcTable;
|
|
79
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate CRC32 hash for string input
|
|
3
|
+
*
|
|
4
|
+
* @param {string} str - String to calculate checksum for
|
|
5
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
6
|
+
*
|
|
7
|
+
* @returns {number} Unsigned 32-bit CRC32 value
|
|
8
|
+
*/
|
|
9
|
+
export function stringToCrc32(str: string, variant?: import("./crcTables.js").CrcVariant): number;
|
|
10
|
+
import { CRC32 } from './crcTables.js';
|
|
11
|
+
import { CRC32C } from './crcTables.js';
|
|
12
|
+
export { CRC32, CRC32C };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String CRC32 calculation utility
|
|
3
|
+
*
|
|
4
|
+
* Calculates CRC32 checksums for strings using standard IEEE 802.3 algorithm.
|
|
5
|
+
* CRC32 is fast but not cryptographically secure.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getCrcTable, CRC32, CRC32C } from './crcTables.js';
|
|
9
|
+
|
|
10
|
+
/* ------------------------------------------------------------------ Exports */
|
|
11
|
+
|
|
12
|
+
export { CRC32, CRC32C };
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Calculate CRC32 hash for string input
|
|
16
|
+
*
|
|
17
|
+
* @param {string} str - String to calculate checksum for
|
|
18
|
+
* @param {import('./crcTables.js').CrcVariant} [variant=CRC32] - CRC variant
|
|
19
|
+
*
|
|
20
|
+
* @returns {number} Unsigned 32-bit CRC32 value
|
|
21
|
+
*/
|
|
22
|
+
export function stringToCrc32(str, variant = CRC32) {
|
|
23
|
+
const table = getCrcTable(variant);
|
|
24
|
+
|
|
25
|
+
/** @type {number} */
|
|
26
|
+
let crc = 0 ^ (-1);
|
|
27
|
+
|
|
28
|
+
for (let j = 0; j < str.length; j = j + 1) {
|
|
29
|
+
crc = (crc >>> 8) ^ table[(crc ^ str.charCodeAt(j)) & 0xFF];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (crc ^ (-1)) >>> 0;
|
|
33
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { bufferToCrc32 } from "./checksum/bufferCrc32.js";
|
|
2
|
+
export { getCrcTable } from "./checksum/crcTables.js";
|
|
3
|
+
export { stringToCrc32, CRC32, CRC32C } from "./checksum/stringCrc32.js";
|
|
4
|
+
export { bufferToBlockCrc32, blockCrc32Iterator, bufferChecksumEquals, optimalBlockSize } from "./checksum/blockCrc32.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checksum utilities - CRC32 calculations
|
|
3
|
+
*
|
|
4
|
+
* Exports the main public-facing functions from the checksum module.
|
|
5
|
+
* Provides both standard IEEE 802.3 CRC32 and custom block-based processing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// String CRC32 calculations
|
|
9
|
+
export { stringToCrc32, CRC32, CRC32C } from './checksum/stringCrc32.js';
|
|
10
|
+
|
|
11
|
+
// Standard buffer CRC32 (IEEE 802.3 compatible)
|
|
12
|
+
export { bufferToCrc32 } from './checksum/bufferCrc32.js';
|
|
13
|
+
|
|
14
|
+
// Custom block-based CRC32 for large files
|
|
15
|
+
export {
|
|
16
|
+
bufferToBlockCrc32,
|
|
17
|
+
blockCrc32Iterator,
|
|
18
|
+
bufferChecksumEquals,
|
|
19
|
+
optimalBlockSize
|
|
20
|
+
} from './checksum/blockCrc32.js';
|
|
21
|
+
|
|
22
|
+
// CRC table utilities (for advanced use)
|
|
23
|
+
export { getCrcTable } from './checksum/crcTables.js';
|