@bsv/sdk 1.6.8 → 1.6.10

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