@bsv/sdk 1.9.3 → 1.9.4

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.
Files changed (60) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/docs/fast-docs.png +0 -0
  3. package/docs/index.md +49 -44
  4. package/docs/swagger.png +0 -0
  5. package/package.json +1 -1
  6. package/docs/MARKDOWN_VALIDATION_GUIDE.md +0 -175
  7. package/docs/concepts/beef.md +0 -92
  8. package/docs/concepts/chain-tracking.md +0 -134
  9. package/docs/concepts/decentralized-identity.md +0 -221
  10. package/docs/concepts/fees.md +0 -249
  11. package/docs/concepts/identity-certificates.md +0 -307
  12. package/docs/concepts/index.md +0 -77
  13. package/docs/concepts/key-management.md +0 -185
  14. package/docs/concepts/script-templates.md +0 -176
  15. package/docs/concepts/sdk-philosophy.md +0 -80
  16. package/docs/concepts/signatures.md +0 -194
  17. package/docs/concepts/spv-verification.md +0 -118
  18. package/docs/concepts/transaction-encoding.md +0 -167
  19. package/docs/concepts/transaction-structure.md +0 -67
  20. package/docs/concepts/trust-model.md +0 -139
  21. package/docs/concepts/verification.md +0 -250
  22. package/docs/concepts/wallet-integration.md +0 -101
  23. package/docs/guides/development-wallet-setup.md +0 -374
  24. package/docs/guides/direct-transaction-creation.md +0 -147
  25. package/docs/guides/http-client-configuration.md +0 -488
  26. package/docs/guides/index.md +0 -138
  27. package/docs/guides/large-transactions.md +0 -448
  28. package/docs/guides/multisig-transactions.md +0 -792
  29. package/docs/guides/security-best-practices.md +0 -494
  30. package/docs/guides/transaction-batching.md +0 -132
  31. package/docs/guides/transaction-signing-methods.md +0 -419
  32. package/docs/reference/arc-config.md +0 -698
  33. package/docs/reference/brc-100.md +0 -33
  34. package/docs/reference/configuration.md +0 -835
  35. package/docs/reference/debugging.md +0 -705
  36. package/docs/reference/errors.md +0 -597
  37. package/docs/reference/index.md +0 -111
  38. package/docs/reference/network-config.md +0 -914
  39. package/docs/reference/op-codes.md +0 -325
  40. package/docs/reference/transaction-signatures.md +0 -95
  41. package/docs/tutorials/advanced-transaction.md +0 -572
  42. package/docs/tutorials/aes-encryption.md +0 -949
  43. package/docs/tutorials/authfetch-tutorial.md +0 -986
  44. package/docs/tutorials/ecdh-key-exchange.md +0 -549
  45. package/docs/tutorials/elliptic-curve-fundamentals.md +0 -606
  46. package/docs/tutorials/error-handling.md +0 -1216
  47. package/docs/tutorials/first-transaction-low-level.md +0 -205
  48. package/docs/tutorials/first-transaction.md +0 -275
  49. package/docs/tutorials/hashes-and-hmacs.md +0 -788
  50. package/docs/tutorials/identity-management.md +0 -729
  51. package/docs/tutorials/index.md +0 -219
  52. package/docs/tutorials/key-management.md +0 -538
  53. package/docs/tutorials/protowallet-development.md +0 -743
  54. package/docs/tutorials/script-construction.md +0 -690
  55. package/docs/tutorials/spv-merkle-proofs.md +0 -685
  56. package/docs/tutorials/testnet-transactions-low-level.md +0 -359
  57. package/docs/tutorials/transaction-broadcasting.md +0 -538
  58. package/docs/tutorials/transaction-types.md +0 -420
  59. package/docs/tutorials/type-42.md +0 -568
  60. package/docs/tutorials/uhrp-storage.md +0 -599
@@ -1,788 +0,0 @@
1
- # Cryptographic Hashing and HMACs
2
-
3
- **Duration**: 75 minutes
4
- **Prerequisites**: Basic TypeScript knowledge, understanding of cryptographic concepts
5
-
6
- ## Learning Goals
7
-
8
- By completing this tutorial, you will:
9
-
10
- - Understand cryptographic hash functions and their properties
11
- - Master the Hash module classes and helper functions in the BSV TypeScript SDK
12
- - Implement various hash algorithms (SHA-256, SHA-512, SHA-1, RIPEMD-160)
13
- - Create and verify HMACs for message authentication
14
- - Apply Bitcoin-specific hashing patterns (hash256, hash160)
15
- - Build practical applications using hashing for data integrity and authentication
16
- - Understand performance considerations and security best practices
17
-
18
- ## Introduction to Cryptographic Hashing
19
-
20
- Cryptographic hash functions are mathematical algorithms that transform input data of any size into fixed-size output values. They are fundamental to Bitcoin's security architecture, providing:
21
-
22
- - **Data Integrity**: Detect any changes to data
23
- - **Digital Fingerprints**: Unique identifiers for data
24
- - **Proof of Work**: Foundation for Bitcoin's consensus mechanism
25
- - **Address Generation**: Converting public keys to Bitcoin addresses
26
-
27
- The BSV TypeScript SDK provides comprehensive hashing capabilities through the `Hash` module, supporting both class-based and functional approaches.
28
-
29
- ## Setting Up Your Environment
30
-
31
- First, import the necessary modules from the BSV SDK:
32
-
33
- ```typescript
34
- import { Hash, Utils } from '@bsv/sdk'
35
- ```
36
-
37
- The `Hash` module contains:
38
-
39
- - Hash function classes (`SHA256`, `SHA512`, `SHA1`, `RIPEMD160`)
40
- - HMAC classes (`SHA256HMAC`, `SHA512HMAC`, `SHA1HMAC`)
41
- - Helper functions (`sha256`, `sha512`, `hash256`, `hash160`, `sha256hmac`)
42
- - Utility functions for data conversion and encoding
43
-
44
- ## Basic Hash Function Usage
45
-
46
- ### SHA-256 Hashing
47
-
48
- SHA-256 is Bitcoin's primary hash function. Here's how to use it:
49
-
50
- ```typescript
51
- // Method 1: Using the SHA256 class
52
- const sha256Hasher = new Hash.SHA256()
53
- sha256Hasher.update('Message to hash')
54
- const hashedMessage = sha256Hasher.digestHex()
55
- console.log('SHA-256 hash:', hashedMessage)
56
- // Output: f1aa45b0f5f6703468f9b9bc2b9874d4fa6b001a170d0f132aa5a26d00d0c7e5
57
-
58
- // Method 2: Using the helper function
59
- const message = 'Hello, Bitcoin!'
60
- const hashResult = Hash.sha256(Utils.toArray(message, 'utf8'))
61
- console.log('SHA-256 hash (binary):', hashResult)
62
-
63
- // Convert to hex for display
64
- const hashHex = Utils.toHex(hashResult)
65
- console.log('SHA-256 hash (hex):', hashHex)
66
- ```
67
-
68
- ### Working with Different Data Types
69
-
70
- The Hash functions can process various data formats:
71
-
72
- ```typescript
73
- // String input
74
- const stringHash = Hash.sha256(Utils.toArray('Hello World', 'utf8'))
75
-
76
- // Hex string input
77
- const hexHash = Hash.sha256(Utils.toArray('deadbeef', 'hex'))
78
-
79
- // Binary array input
80
- const binaryData = [0x01, 0x02, 0x03, 0x04]
81
- const binaryHash = Hash.sha256(binaryData)
82
-
83
- // JSON data hashing
84
- const jsonData = { name: 'Alice', amount: 100 }
85
- const jsonString = JSON.stringify(jsonData)
86
- const jsonHash = Hash.sha256(Utils.toArray(jsonString, 'utf8'))
87
-
88
- console.log('String hash:', Utils.toHex(stringHash))
89
- console.log('Hex hash:', Utils.toHex(hexHash))
90
- console.log('Binary hash:', Utils.toHex(binaryHash))
91
- console.log('JSON hash:', Utils.toHex(jsonHash))
92
- ```
93
-
94
- ### Other Hash Algorithms
95
-
96
- The SDK supports multiple hash algorithms:
97
-
98
- ```typescript
99
- // SHA-512
100
- const sha512Hasher = new Hash.SHA512()
101
- sha512Hasher.update('Message for SHA-512')
102
- const sha512Result = sha512Hasher.digestHex()
103
- console.log('SHA-512 hash:', sha512Result)
104
-
105
- // SHA-1 (legacy, use with caution)
106
- const sha1Hasher = new Hash.SHA1()
107
- sha1Hasher.update('Message for SHA-1')
108
- const sha1Result = sha1Hasher.digestHex()
109
- console.log('SHA-1 hash:', sha1Result)
110
-
111
- // RIPEMD-160 (used in Bitcoin address generation)
112
- const ripemdHasher = new Hash.RIPEMD160()
113
- ripemdHasher.update('Message for RIPEMD-160')
114
- const ripemdResult = ripemdHasher.digestHex()
115
- console.log('RIPEMD-160 hash:', ripemdResult)
116
-
117
- // Using helper functions
118
- const sha512Helper = Hash.sha512(Utils.toArray('Hello', 'utf8'))
119
- console.log('SHA-512 helper result:', Utils.toHex(sha512Helper))
120
- ```
121
-
122
- ## Bitcoin-Specific Hash Functions
123
-
124
- ### Double SHA-256 (hash256)
125
-
126
- Bitcoin uses double SHA-256 hashing for block headers and transaction IDs:
127
-
128
- ```typescript
129
- // Double SHA-256 using hash256 helper
130
- const message = 'Bitcoin transaction data'
131
- const doubleHash = Hash.hash256(Utils.toArray(message, 'utf8'))
132
- console.log('Double SHA-256 hash:', Utils.toHex(doubleHash))
133
-
134
- // Manual double hashing
135
- const firstHash = Hash.sha256(Utils.toArray(message, 'utf8'))
136
- const secondHash = Hash.sha256(firstHash)
137
- console.log('Manual double hash:', Utils.toHex(secondHash))
138
-
139
- // Both methods produce the same result
140
- console.log('Results match:', Utils.toHex(doubleHash) === Utils.toHex(secondHash))
141
- ```
142
-
143
- ### Hash160 (SHA-256 + RIPEMD-160)
144
-
145
- Used for Bitcoin address generation:
146
-
147
- ```typescript
148
- // Hash160: SHA-256 followed by RIPEMD-160
149
- const publicKeyData = 'compressed_public_key_hex_data'
150
- const hash160Result = Hash.hash160(Utils.toArray(publicKeyData, 'hex'))
151
- console.log('Hash160 result:', Utils.toHex(hash160Result))
152
-
153
- // Manual implementation
154
- const sha256First = Hash.sha256(Utils.toArray(publicKeyData, 'hex'))
155
- const ripemd160Second = new Hash.RIPEMD160().update(sha256First).digest()
156
- console.log('Manual Hash160:', Utils.toHex(ripemd160Second))
157
-
158
- // Results should match
159
- console.log('Hash160 results match:',
160
- Utils.toHex(hash160Result) === Utils.toHex(ripemd160Second))
161
- ```
162
-
163
- ## HMAC Implementation
164
-
165
- HMACs (Hash-based Message Authentication Codes) provide both data integrity and authentication by incorporating a secret key into the hashing process.
166
-
167
- ### Basic HMAC Usage
168
-
169
- ```typescript
170
- // SHA-256 HMAC
171
- const key = 'secret_key'
172
- const message = 'Message to authenticate'
173
-
174
- // Method 1: Using HMAC class
175
- const hmacHasher = new Hash.SHA256HMAC(key)
176
- hmacHasher.update(message)
177
- const hmacResult = hmacHasher.digestHex()
178
- console.log('HMAC-SHA256:', hmacResult)
179
- // Output: b4d897472c73a052733d0796a5f71cf8253bab7d3969811b64f41ff6aa89d86f
180
-
181
- // Method 2: Using helper function
182
- const hmacHelper = Hash.sha256hmac(key, message)
183
- console.log('HMAC helper result:', Utils.toHex(hmacHelper))
184
-
185
- // Both methods produce the same result
186
- console.log('HMAC results match:', hmacResult === Utils.toHex(hmacHelper))
187
- ```
188
-
189
- ### HMAC with Different Algorithms
190
-
191
- ```typescript
192
- // SHA-512 HMAC
193
- const sha512Hmac = new Hash.SHA512HMAC('my_secret_key')
194
- sha512Hmac.update('Data to authenticate')
195
- const sha512HmacResult = sha512Hmac.digestHex()
196
- console.log('HMAC-SHA512:', sha512HmacResult)
197
-
198
- // SHA-1 HMAC (legacy)
199
- const sha1Hmac = new Hash.SHA1HMAC('legacy_key')
200
- sha1Hmac.update('Legacy data')
201
- const sha1HmacResult = sha1Hmac.digestHex()
202
- console.log('HMAC-SHA1:', sha1HmacResult)
203
- ```
204
-
205
- ### HMAC Key Management
206
-
207
- ```typescript
208
- // Strong key generation
209
- function generateHmacKey(): string {
210
- const randomBytes = new Array(32)
211
- for (let i = 0; i < 32; i++) {
212
- randomBytes[i] = Math.floor(Math.random() * 256)
213
- }
214
- return Utils.toHex(randomBytes)
215
- }
216
-
217
- // Key derivation from password
218
- function deriveKeyFromPassword(password: string, salt: string): number[] {
219
- const combined = password + salt
220
- return Hash.sha256(Utils.toArray(combined, 'utf8'))
221
- }
222
-
223
- // Example usage
224
- const strongKey = generateHmacKey()
225
- const derivedKey = deriveKeyFromPassword('user_password', 'random_salt')
226
-
227
- console.log('Strong key:', strongKey)
228
- console.log('Derived key:', Utils.toHex(derivedKey))
229
-
230
- // Use derived key for HMAC
231
- const secureHmac = Hash.sha256hmac(derivedKey, 'sensitive_data')
232
- console.log('Secure HMAC:', Utils.toHex(secureHmac))
233
- ```
234
-
235
- ## Practical Applications
236
-
237
- ### Data Integrity Verification
238
-
239
- ```typescript
240
- class DataIntegrityChecker {
241
- private data: string
242
- private hash: string
243
-
244
- constructor(data: string) {
245
- this.data = data
246
- this.hash = this.calculateHash(data)
247
- }
248
-
249
- private calculateHash(data: string): string {
250
- const hashResult = Hash.sha256(Utils.toArray(data, 'utf8'))
251
- return Utils.toHex(hashResult)
252
- }
253
-
254
- verify(): boolean {
255
- const currentHash = this.calculateHash(this.data)
256
- return currentHash === this.hash
257
- }
258
-
259
- getData(): string {
260
- return this.data
261
- }
262
-
263
- getHash(): string {
264
- return this.hash
265
- }
266
-
267
- // Simulate data corruption
268
- corruptData(): void {
269
- this.data += '_corrupted'
270
- }
271
- }
272
-
273
- // Example usage
274
- const checker = new DataIntegrityChecker('Important document content')
275
- console.log('Original hash:', checker.getHash())
276
- console.log('Data is valid:', checker.verify()) // true
277
-
278
- checker.corruptData()
279
- console.log('After corruption, data is valid:', checker.verify()) // false
280
- ```
281
-
282
- ### Message Authentication System
283
-
284
- ```typescript
285
- class MessageAuthenticator {
286
- private secretKey: string
287
-
288
- constructor(secretKey: string) {
289
- this.secretKey = secretKey
290
- }
291
-
292
- createAuthenticatedMessage(message: string): {
293
- message: string
294
- hmac: string
295
- timestamp: number
296
- } {
297
- const timestamp = Date.now()
298
- const messageWithTimestamp = `${message}:${timestamp}`
299
- const hmac = Hash.sha256hmac(this.secretKey, messageWithTimestamp)
300
-
301
- return {
302
- message,
303
- hmac: Utils.toHex(hmac),
304
- timestamp
305
- }
306
- }
307
-
308
- verifyMessage(authenticatedMessage: {
309
- message: string
310
- hmac: string
311
- timestamp: number
312
- }): boolean {
313
- try {
314
- const messageWithTimestamp = `${authenticatedMessage.message}:${authenticatedMessage.timestamp}`
315
- const expectedHmac = Hash.sha256hmac(this.secretKey, messageWithTimestamp)
316
- const expectedHmacHex = Utils.toHex(expectedHmac)
317
-
318
- // Constant-time comparison to prevent timing attacks
319
- return this.constantTimeCompare(authenticatedMessage.hmac, expectedHmacHex)
320
- } catch (error) {
321
- console.error('Verification error:', error)
322
- return false
323
- }
324
- }
325
-
326
- private constantTimeCompare(a: string, b: string): boolean {
327
- if (a.length !== b.length) {
328
- return false
329
- }
330
-
331
- let result = 0
332
- for (let i = 0; i < a.length; i++) {
333
- result |= a.charCodeAt(i) ^ b.charCodeAt(i)
334
- }
335
-
336
- return result === 0
337
- }
338
- }
339
-
340
- // Example usage
341
- const authenticator = new MessageAuthenticator('super_secret_key_123')
342
-
343
- const authMessage = authenticator.createAuthenticatedMessage('Transfer 100 satoshis to Alice')
344
- console.log('Authenticated message:', authMessage)
345
-
346
- const isValid = authenticator.verifyMessage(authMessage)
347
- console.log('Message is authentic:', isValid) // true
348
-
349
- // Tamper with the message
350
- authMessage.message = 'Transfer 1000 satoshis to Alice'
351
- const isTamperedValid = authenticator.verifyMessage(authMessage)
352
- console.log('Tampered message is authentic:', isTamperedValid) // false
353
- ```
354
-
355
- ### Transaction Metadata Protection
356
-
357
- ```typescript
358
- interface TransactionMetadata {
359
- description: string
360
- category: string
361
- tags: string[]
362
- amount: number
363
- }
364
-
365
- class SecureTransactionMetadata {
366
- private key: number[]
367
-
368
- constructor(password: string) {
369
- // Derive key from password
370
- this.key = Hash.sha256(Utils.toArray(password, 'utf8'))
371
- }
372
-
373
- protectMetadata(metadata: TransactionMetadata): {
374
- data: string
375
- integrity: string
376
- } {
377
- const jsonData = JSON.stringify(metadata)
378
- const dataBytes = Utils.toArray(jsonData, 'utf8')
379
-
380
- // Create integrity hash
381
- const integrity = Hash.sha256hmac(this.key, dataBytes)
382
-
383
- return {
384
- data: Utils.toBase64(dataBytes),
385
- integrity: Utils.toHex(integrity)
386
- }
387
- }
388
-
389
- verifyAndExtract(protectedData: {
390
- data: string
391
- integrity: string
392
- }): TransactionMetadata | null {
393
- try {
394
- const dataBytes = Array.from(Buffer.from(protectedData.data, 'base64'))
395
- const expectedIntegrity = Hash.sha256hmac(this.key, dataBytes)
396
- const expectedIntegrityHex = Utils.toHex(expectedIntegrity)
397
-
398
- if (protectedData.integrity !== expectedIntegrityHex) {
399
- console.error('Integrity check failed')
400
- return null
401
- }
402
-
403
- const jsonString = Utils.toUTF8(dataBytes)
404
- return JSON.parse(jsonString) as TransactionMetadata
405
- } catch (error) {
406
- console.error('Extraction error:', error)
407
- return null
408
- }
409
- }
410
- }
411
-
412
- // Example usage
413
- const metadataProtector = new SecureTransactionMetadata('user_password_123')
414
-
415
- const originalMetadata: TransactionMetadata = {
416
- description: 'Payment for services',
417
- category: 'business',
418
- tags: ['consulting', 'development'],
419
- amount: 100
420
- }
421
-
422
- const protectedData = metadataProtector.protectMetadata(originalMetadata)
423
- console.log('Protected metadata:', protectedData)
424
-
425
- const extracted = metadataProtector.verifyAndExtract(protectedData)
426
- console.log('Extracted metadata:', extracted)
427
- console.log('Metadata matches:', JSON.stringify(originalMetadata) === JSON.stringify(extracted))
428
- ```
429
-
430
- ## Performance Optimization
431
-
432
- ### Batch Hashing
433
-
434
- ```typescript
435
- class BatchHashProcessor {
436
- private hasher: Hash.SHA256
437
-
438
- constructor() {
439
- this.hasher = new Hash.SHA256()
440
- }
441
-
442
- hashMultipleMessages(messages: string[]): string[] {
443
- const results: string[] = []
444
-
445
- for (const message of messages) {
446
- // Reset hasher for each message
447
- this.hasher = new Hash.SHA256()
448
- this.hasher.update(message)
449
- results.push(this.hasher.digestHex())
450
- }
451
-
452
- return results
453
- }
454
-
455
- createMerkleRoot(hashes: string[]): string {
456
- if (hashes.length === 0) {
457
- throw new Error('Cannot create merkle root from empty array')
458
- }
459
-
460
- if (hashes.length === 1) {
461
- return hashes[0]
462
- }
463
-
464
- const nextLevel: string[] = []
465
-
466
- for (let i = 0; i < hashes.length; i += 2) {
467
- const left = hashes[i]
468
- const right = i + 1 < hashes.length ? hashes[i + 1] : left
469
-
470
- const combined = left + right
471
- const combinedBytes = Utils.toArray(combined, 'hex')
472
- const hash = Hash.sha256(combinedBytes)
473
- nextLevel.push(Utils.toHex(hash))
474
- }
475
-
476
- return this.createMerkleRoot(nextLevel)
477
- }
478
- }
479
-
480
- // Performance testing
481
- function performanceTest() {
482
- const processor = new BatchHashProcessor()
483
- const testMessages = Array.from({ length: 1000 }, (_, i) => `Message ${i}`)
484
-
485
- console.time('Batch hashing 1000 messages')
486
- const hashes = processor.hashMultipleMessages(testMessages)
487
- console.timeEnd('Batch hashing 1000 messages')
488
-
489
- console.time('Creating merkle root')
490
- const merkleRoot = processor.createMerkleRoot(hashes)
491
- console.timeEnd('Creating merkle root')
492
-
493
- console.log('Merkle root:', merkleRoot)
494
- console.log('Processed', hashes.length, 'messages')
495
- }
496
-
497
- performanceTest()
498
- ```
499
-
500
- ### Memory-Efficient Streaming
501
-
502
- ```typescript
503
- class StreamingHasher {
504
- private hasher: Hash.SHA256
505
-
506
- constructor() {
507
- this.hasher = new Hash.SHA256()
508
- }
509
-
510
- processLargeData(data: string, chunkSize: number = 1024): string {
511
- for (let i = 0; i < data.length; i += chunkSize) {
512
- const chunk = data.slice(i, i + chunkSize)
513
- this.hasher.update(chunk)
514
- }
515
-
516
- return this.hasher.digestHex()
517
- }
518
-
519
- reset(): void {
520
- this.hasher = new Hash.SHA256()
521
- }
522
- }
523
-
524
- // Example with large data
525
- const streamingHasher = new StreamingHasher()
526
- const largeData = 'A'.repeat(1000000) // 1MB of data
527
- const streamHash = streamingHasher.processLargeData(largeData)
528
- console.log('Streaming hash result:', streamHash)
529
- ```
530
-
531
- ## Security Best Practices
532
-
533
- ### Secure Key Generation and Storage
534
-
535
- ```typescript
536
- class SecureKeyManager {
537
- static generateSecureKey(length: number = 32): number[] {
538
- // In production, use a cryptographically secure random number generator
539
- const key = new Array(length)
540
- for (let i = 0; i < length; i++) {
541
- key[i] = Math.floor(Math.random() * 256)
542
- }
543
- return key
544
- }
545
-
546
- static deriveKeyFromPassword(
547
- password: string,
548
- salt: number[],
549
- iterations: number = 10000
550
- ): number[] {
551
- let derived = Hash.sha256(Utils.toArray(password + Utils.toHex(salt), 'utf8'))
552
-
553
- for (let i = 1; i < iterations; i++) {
554
- derived = Hash.sha256(derived)
555
- }
556
-
557
- return derived
558
- }
559
-
560
- static secureCompare(a: number[], b: number[]): boolean {
561
- if (a.length !== b.length) {
562
- return false
563
- }
564
-
565
- let result = 0
566
- for (let i = 0; i < a.length; i++) {
567
- result |= a[i] ^ b[i]
568
- }
569
-
570
- return result === 0
571
- }
572
-
573
- static clearSensitiveData(data: number[]): void {
574
- for (let i = 0; i < data.length; i++) {
575
- data[i] = 0
576
- }
577
- }
578
- }
579
-
580
- // Example secure usage
581
- const salt = SecureKeyManager.generateSecureKey(16)
582
- const derivedKey = SecureKeyManager.deriveKeyFromPassword('user_password', salt)
583
-
584
- console.log('Salt:', Utils.toHex(salt))
585
- console.log('Derived key:', Utils.toHex(derivedKey))
586
-
587
- // Clear sensitive data when done
588
- SecureKeyManager.clearSensitiveData(derivedKey)
589
- SecureKeyManager.clearSensitiveData(salt)
590
- ```
591
-
592
- ### Input Validation and Error Handling
593
-
594
- ```typescript
595
- class SafeHasher {
596
- static validateInput(input: any): void {
597
- if (input === null || input === undefined) {
598
- throw new Error('Input cannot be null or undefined')
599
- }
600
-
601
- if (typeof input === 'string' && input.length === 0) {
602
- throw new Error('Input string cannot be empty')
603
- }
604
-
605
- if (Array.isArray(input) && input.length === 0) {
606
- throw new Error('Input array cannot be empty')
607
- }
608
- }
609
-
610
- static safeHash(input: string | number[], algorithm: 'sha256' | 'sha512' = 'sha256'): string {
611
- try {
612
- this.validateInput(input)
613
-
614
- let data: number[]
615
- if (typeof input === 'string') {
616
- data = Utils.toArray(input, 'utf8')
617
- } else {
618
- data = input
619
- }
620
-
621
- let result: number[]
622
- switch (algorithm) {
623
- case 'sha256':
624
- result = Hash.sha256(data)
625
- break
626
- case 'sha512':
627
- result = Hash.sha512(data)
628
- break
629
- default:
630
- throw new Error(`Unsupported algorithm: ${algorithm}`)
631
- }
632
-
633
- return Utils.toHex(result)
634
- } catch (error) {
635
- console.error('Hashing error:', error)
636
- throw new Error(`Failed to hash input: ${error instanceof Error ? error.message : 'Unknown error'}`)
637
- }
638
- }
639
-
640
- static safeHmac(key: string | number[], message: string | number[]): string {
641
- try {
642
- this.validateInput(key)
643
- this.validateInput(message)
644
-
645
- const result = Hash.sha256hmac(key, message)
646
- return Utils.toHex(result)
647
- } catch (error) {
648
- console.error('HMAC error:', error)
649
- throw new Error(`Failed to create HMAC: ${error instanceof Error ? error.message : 'Unknown error'}`)
650
- }
651
- }
652
- }
653
-
654
- // Example safe usage
655
- try {
656
- const hash = SafeHasher.safeHash('Valid input')
657
- console.log('Safe hash:', hash)
658
-
659
- const hmac = SafeHasher.safeHmac('secret_key', 'message')
660
- console.log('Safe HMAC:', hmac)
661
- } catch (error) {
662
- console.error('Operation failed:', error)
663
- }
664
- ```
665
-
666
- ## Testing Your Implementation
667
-
668
- ```typescript
669
- // Comprehensive test suite
670
- function runHashTests(): void {
671
- console.log('Running hash function tests...')
672
-
673
- // Test SHA-256 consistency
674
- const testMessage = 'Hello, Bitcoin!'
675
- const hash1 = Hash.sha256(Utils.toArray(testMessage, 'utf8'))
676
- const hash2 = new Hash.SHA256().update(testMessage).digest()
677
-
678
- console.assert(
679
- Utils.toHex(hash1) === Utils.toHex(hash2),
680
- 'SHA-256 methods should produce same result'
681
- )
682
-
683
- // Test HMAC consistency
684
- const key = 'test_key'
685
- const message = 'test_message'
686
- const hmac1 = Hash.sha256hmac(key, message)
687
- const hmac2 = new Hash.SHA256HMAC(key).update(message).digest()
688
-
689
- console.assert(
690
- Utils.toHex(hmac1) === Utils.toHex(hmac2),
691
- 'HMAC methods should produce same result'
692
- )
693
-
694
- // Test Bitcoin-specific functions
695
- const data = 'bitcoin_data'
696
- const hash256Result = Hash.hash256(Utils.toArray(data, 'utf8'))
697
- const manualDouble = Hash.sha256(Hash.sha256(Utils.toArray(data, 'utf8')))
698
-
699
- console.assert(
700
- Utils.toHex(hash256Result) === Utils.toHex(manualDouble),
701
- 'hash256 should equal double SHA-256'
702
- )
703
-
704
- console.log('All tests passed!')
705
- }
706
-
707
- runHashTests()
708
- ```
709
-
710
- ## Troubleshooting Common Issues
711
-
712
- ### Issue 1: Encoding Problems
713
-
714
- ```typescript
715
- // Problem: Incorrect encoding leads to different hashes
716
- // Note: Hash.sha256() requires number[] input, not strings directly
717
- const correctHash = Hash.sha256(Utils.toArray('hello', 'utf8')) // Correct approach
718
-
719
- console.log('Correct hash with proper encoding:', Utils.toHex(correctHash))
720
- console.log('Always use Utils.toArray() for proper encoding')
721
- ```
722
-
723
- ### Issue 2: Key Management
724
-
725
- ```typescript
726
- // Problem: Weak keys or improper key derivation
727
- const weakKey = 'password123' // Weak
728
- const strongKey = SecureKeyManager.generateSecureKey() // Strong
729
-
730
- // Problem: Reusing keys across different purposes
731
- const hmacKey = strongKey
732
- const encryptionKey = strongKey // Wrong: same key for different purposes
733
-
734
- // Solution: Derive different keys for different purposes
735
- const hmacKeyDerived = Hash.sha256(Utils.toArray('hmac:' + Utils.toHex(strongKey), 'utf8'))
736
- const encryptionKeyDerived = Hash.sha256(Utils.toArray('encrypt:' + Utils.toHex(strongKey), 'utf8'))
737
- ```
738
-
739
- ### Issue 3: Performance Problems
740
-
741
- ```typescript
742
- // Problem: Creating new hasher instances unnecessarily
743
- function inefficientHashing(messages: string[]): string[] {
744
- return messages.map(msg => {
745
- const hasher = new Hash.SHA256() // Inefficient: new instance each time
746
- return hasher.update(msg).digestHex()
747
- })
748
- }
749
-
750
- // Solution: Reuse hasher or use helper functions
751
- function efficientHashing(messages: string[]): string[] {
752
- return messages.map(msg => {
753
- return Utils.toHex(Hash.sha256(Utils.toArray(msg, 'utf8'))) // Efficient
754
- })
755
- }
756
- ```
757
-
758
- ## Summary
759
-
760
- This tutorial covered comprehensive usage of cryptographic hashing and HMACs in the BSV TypeScript SDK:
761
-
762
- **Key Concepts Learned:**
763
-
764
- - Hash function fundamentals and Bitcoin-specific applications
765
- - SHA-256, SHA-512, SHA-1, and RIPEMD-160 implementation
766
- - HMAC creation and verification for message authentication
767
- - Bitcoin-specific functions: hash256 (double SHA-256) and hash160
768
- - Performance optimization techniques for batch processing
769
- - Security best practices for key management and validation
770
-
771
- **Practical Applications:**
772
-
773
- - Data integrity verification systems
774
- - Message authentication protocols
775
- - Transaction metadata protection
776
- - Merkle tree construction
777
- - Secure key derivation patterns
778
-
779
- **Security Considerations:**
780
-
781
- - Proper input validation and error handling
782
- - Constant-time comparison to prevent timing attacks
783
- - Secure key generation and storage practices
784
- - Memory management for sensitive data
785
-
786
- The Hash module in the BSV TypeScript SDK provides both low-level control through classes and high-level convenience through helper functions, enabling developers to implement robust cryptographic solutions for Bitcoin applications.
787
-
788
- Continue exploring advanced cryptographic topics with the [ECDH Key Exchange](./ecdh-key-exchange.md) and [AES Symmetric Encryption](./aes-encryption.md) tutorials to build complete cryptographic systems.