@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.
- package/dist/cjs/package.json +1 -1
- package/docs/fast-docs.png +0 -0
- package/docs/index.md +49 -44
- package/docs/swagger.png +0 -0
- package/package.json +1 -1
- package/docs/MARKDOWN_VALIDATION_GUIDE.md +0 -175
- package/docs/concepts/beef.md +0 -92
- package/docs/concepts/chain-tracking.md +0 -134
- package/docs/concepts/decentralized-identity.md +0 -221
- package/docs/concepts/fees.md +0 -249
- package/docs/concepts/identity-certificates.md +0 -307
- package/docs/concepts/index.md +0 -77
- package/docs/concepts/key-management.md +0 -185
- package/docs/concepts/script-templates.md +0 -176
- package/docs/concepts/sdk-philosophy.md +0 -80
- package/docs/concepts/signatures.md +0 -194
- package/docs/concepts/spv-verification.md +0 -118
- package/docs/concepts/transaction-encoding.md +0 -167
- package/docs/concepts/transaction-structure.md +0 -67
- package/docs/concepts/trust-model.md +0 -139
- package/docs/concepts/verification.md +0 -250
- package/docs/concepts/wallet-integration.md +0 -101
- package/docs/guides/development-wallet-setup.md +0 -374
- package/docs/guides/direct-transaction-creation.md +0 -147
- package/docs/guides/http-client-configuration.md +0 -488
- package/docs/guides/index.md +0 -138
- package/docs/guides/large-transactions.md +0 -448
- package/docs/guides/multisig-transactions.md +0 -792
- package/docs/guides/security-best-practices.md +0 -494
- package/docs/guides/transaction-batching.md +0 -132
- package/docs/guides/transaction-signing-methods.md +0 -419
- package/docs/reference/arc-config.md +0 -698
- package/docs/reference/brc-100.md +0 -33
- package/docs/reference/configuration.md +0 -835
- package/docs/reference/debugging.md +0 -705
- package/docs/reference/errors.md +0 -597
- package/docs/reference/index.md +0 -111
- package/docs/reference/network-config.md +0 -914
- package/docs/reference/op-codes.md +0 -325
- package/docs/reference/transaction-signatures.md +0 -95
- package/docs/tutorials/advanced-transaction.md +0 -572
- package/docs/tutorials/aes-encryption.md +0 -949
- package/docs/tutorials/authfetch-tutorial.md +0 -986
- package/docs/tutorials/ecdh-key-exchange.md +0 -549
- package/docs/tutorials/elliptic-curve-fundamentals.md +0 -606
- package/docs/tutorials/error-handling.md +0 -1216
- package/docs/tutorials/first-transaction-low-level.md +0 -205
- package/docs/tutorials/first-transaction.md +0 -275
- package/docs/tutorials/hashes-and-hmacs.md +0 -788
- package/docs/tutorials/identity-management.md +0 -729
- package/docs/tutorials/index.md +0 -219
- package/docs/tutorials/key-management.md +0 -538
- package/docs/tutorials/protowallet-development.md +0 -743
- package/docs/tutorials/script-construction.md +0 -690
- package/docs/tutorials/spv-merkle-proofs.md +0 -685
- package/docs/tutorials/testnet-transactions-low-level.md +0 -359
- package/docs/tutorials/transaction-broadcasting.md +0 -538
- package/docs/tutorials/transaction-types.md +0 -420
- package/docs/tutorials/type-42.md +0 -568
- package/docs/tutorials/uhrp-storage.md +0 -599
|
@@ -1,743 +0,0 @@
|
|
|
1
|
-
# Working with ProtoWallet for Development
|
|
2
|
-
|
|
3
|
-
**Duration**: 45 minutes
|
|
4
|
-
**Prerequisites**: Node.js, basic TypeScript knowledge, completed "Your First BSV Transaction" tutorial
|
|
5
|
-
**Learning Goals**:
|
|
6
|
-
|
|
7
|
-
- Understand ProtoWallet's role in development and testing
|
|
8
|
-
- Implement cryptographic operations without blockchain interaction
|
|
9
|
-
- Use ProtoWallet for key derivation and signing
|
|
10
|
-
- Build development tools and testing frameworks
|
|
11
|
-
|
|
12
|
-
## Introduction
|
|
13
|
-
|
|
14
|
-
ProtoWallet is a lightweight wallet implementation designed for development and testing scenarios. Unlike full wallets, ProtoWallet focuses purely on cryptographic operations without blockchain interaction, making it perfect for:
|
|
15
|
-
|
|
16
|
-
- Development and testing environments
|
|
17
|
-
- Cryptographic operation prototyping
|
|
18
|
-
- Key derivation and signing operations
|
|
19
|
-
- Building wallet-like functionality without full wallet complexity
|
|
20
|
-
|
|
21
|
-
## What You'll Build
|
|
22
|
-
|
|
23
|
-
In this tutorial, you'll create a development toolkit using ProtoWallet that includes:
|
|
24
|
-
|
|
25
|
-
- Key generation and management
|
|
26
|
-
- Message signing and verification
|
|
27
|
-
- Symmetric encryption/decryption
|
|
28
|
-
- HMAC creation and verification
|
|
29
|
-
|
|
30
|
-
## Setting Up ProtoWallet
|
|
31
|
-
|
|
32
|
-
### Basic ProtoWallet Creation
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
import { ProtoWallet, PrivateKey } from '@bsv/sdk'
|
|
36
|
-
|
|
37
|
-
async function createProtoWallet() {
|
|
38
|
-
// Create with a random private key
|
|
39
|
-
const randomWallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
40
|
-
|
|
41
|
-
// Create with a specific private key
|
|
42
|
-
const privateKey = PrivateKey.fromRandom()
|
|
43
|
-
const specificWallet = new ProtoWallet(privateKey)
|
|
44
|
-
|
|
45
|
-
// Create with 'anyone' key (for testing)
|
|
46
|
-
const anyoneWallet = new ProtoWallet('anyone')
|
|
47
|
-
|
|
48
|
-
console.log('ProtoWallet instances created successfully')
|
|
49
|
-
return { randomWallet, specificWallet, anyoneWallet }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
createProtoWallet().catch(console.error)
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Getting Public Keys
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
import { ProtoWallet } from '@bsv/sdk'
|
|
59
|
-
|
|
60
|
-
async function demonstratePublicKeys() {
|
|
61
|
-
const wallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
62
|
-
|
|
63
|
-
// Get identity public key
|
|
64
|
-
const { publicKey: identityKey } = await wallet.getPublicKey({
|
|
65
|
-
identityKey: true
|
|
66
|
-
})
|
|
67
|
-
console.log('Identity Key:', identityKey)
|
|
68
|
-
|
|
69
|
-
// Get derived public key for a protocol
|
|
70
|
-
const { publicKey: protocolKey } = await wallet.getPublicKey({
|
|
71
|
-
protocolID: [1, 'my-app'],
|
|
72
|
-
keyID: 'user-signing-key'
|
|
73
|
-
})
|
|
74
|
-
console.log('Protocol Key:', protocolKey)
|
|
75
|
-
|
|
76
|
-
// Get public key for counterparty communication
|
|
77
|
-
const { publicKey: counterpartyKey } = await wallet.getPublicKey({
|
|
78
|
-
protocolID: [1, 'messaging'],
|
|
79
|
-
keyID: 'chat-key',
|
|
80
|
-
counterparty: identityKey
|
|
81
|
-
})
|
|
82
|
-
console.log('Counterparty Key:', counterpartyKey)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
demonstratePublicKeys().catch(console.error)
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Digital Signatures with ProtoWallet
|
|
89
|
-
|
|
90
|
-
### Creating and Verifying Signatures
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
import { ProtoWallet, Utils } from '@bsv/sdk'
|
|
94
|
-
|
|
95
|
-
async function demonstrateSignatures() {
|
|
96
|
-
const wallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
97
|
-
|
|
98
|
-
// Message to sign
|
|
99
|
-
const message = 'Hello, BSV development!'
|
|
100
|
-
const messageBytes = Utils.toArray(message, 'utf8')
|
|
101
|
-
|
|
102
|
-
// Create signature
|
|
103
|
-
const { signature } = await wallet.createSignature({
|
|
104
|
-
data: messageBytes,
|
|
105
|
-
protocolID: [1, 'document signing'],
|
|
106
|
-
keyID: 'doc-key',
|
|
107
|
-
counterparty: 'self'
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
console.log('Message:', message)
|
|
111
|
-
console.log('Signature:', Utils.toBase64(signature))
|
|
112
|
-
|
|
113
|
-
// Verify signature
|
|
114
|
-
const { valid } = await wallet.verifySignature({
|
|
115
|
-
data: messageBytes,
|
|
116
|
-
signature,
|
|
117
|
-
protocolID: [1, 'document signing'],
|
|
118
|
-
keyID: 'doc-key',
|
|
119
|
-
counterparty: 'self'
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
console.log('Signature valid:', valid)
|
|
123
|
-
|
|
124
|
-
return { message, signature, valid }
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
demonstrateSignatures().catch(console.error)
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Advanced Signature Scenarios
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
import { ProtoWallet, Utils } from '@bsv/sdk'
|
|
134
|
-
|
|
135
|
-
class DocumentSigner {
|
|
136
|
-
private wallet: ProtoWallet
|
|
137
|
-
|
|
138
|
-
constructor() {
|
|
139
|
-
this.wallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async signDocument(content: string, documentId: string): Promise<{
|
|
143
|
-
signature: number[]
|
|
144
|
-
publicKey: string
|
|
145
|
-
timestamp: number
|
|
146
|
-
}> {
|
|
147
|
-
const timestamp = Date.now()
|
|
148
|
-
const documentData = {
|
|
149
|
-
content,
|
|
150
|
-
documentId,
|
|
151
|
-
timestamp
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const dataToSign = Utils.toArray(JSON.stringify(documentData), 'utf8')
|
|
155
|
-
|
|
156
|
-
const { signature } = await this.wallet.createSignature({
|
|
157
|
-
data: dataToSign,
|
|
158
|
-
protocolID: [1, 'document system'],
|
|
159
|
-
keyID: `doc-${documentId}`,
|
|
160
|
-
counterparty: 'self'
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
const { publicKey } = await this.wallet.getPublicKey({
|
|
164
|
-
protocolID: [1, 'document system'],
|
|
165
|
-
keyID: `doc-${documentId}`
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
return { signature, publicKey, timestamp }
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async verifyDocument(
|
|
172
|
-
content: string,
|
|
173
|
-
documentId: string,
|
|
174
|
-
signature: number[],
|
|
175
|
-
timestamp: number
|
|
176
|
-
): Promise<boolean> {
|
|
177
|
-
const documentData = {
|
|
178
|
-
content,
|
|
179
|
-
documentId,
|
|
180
|
-
timestamp
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const dataToVerify = Utils.toArray(JSON.stringify(documentData), 'utf8')
|
|
184
|
-
|
|
185
|
-
const { valid } = await this.wallet.verifySignature({
|
|
186
|
-
data: dataToVerify,
|
|
187
|
-
signature,
|
|
188
|
-
protocolID: [1, 'document system'],
|
|
189
|
-
keyID: `doc-${documentId}`,
|
|
190
|
-
counterparty: 'self'
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
return valid
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async function demonstrateDocumentSigning() {
|
|
198
|
-
const signer = new DocumentSigner()
|
|
199
|
-
|
|
200
|
-
const document = {
|
|
201
|
-
content: 'This is a confidential document requiring digital signature.',
|
|
202
|
-
id: 'contract-2024-001'
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Sign document
|
|
206
|
-
const signatureData = await signer.signDocument(document.content, document.id)
|
|
207
|
-
console.log('Document signed:', {
|
|
208
|
-
documentId: document.id,
|
|
209
|
-
publicKey: signatureData.publicKey,
|
|
210
|
-
timestamp: new Date(signatureData.timestamp).toISOString()
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
// Verify document
|
|
214
|
-
const isValid = await signer.verifyDocument(
|
|
215
|
-
document.content,
|
|
216
|
-
document.id,
|
|
217
|
-
signatureData.signature,
|
|
218
|
-
signatureData.timestamp
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
console.log('Document verification:', isValid ? 'VALID' : 'INVALID')
|
|
222
|
-
|
|
223
|
-
return { signatureData, isValid }
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
demonstrateDocumentSigning().catch(console.error)
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## Encryption and Decryption
|
|
230
|
-
|
|
231
|
-
### Symmetric Encryption
|
|
232
|
-
|
|
233
|
-
```typescript
|
|
234
|
-
import { ProtoWallet, Utils } from '@bsv/sdk'
|
|
235
|
-
|
|
236
|
-
async function demonstrateEncryption() {
|
|
237
|
-
const wallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
238
|
-
|
|
239
|
-
// Data to encrypt
|
|
240
|
-
const secretMessage = 'This is confidential development data'
|
|
241
|
-
const plaintext = Utils.toArray(secretMessage, 'utf8')
|
|
242
|
-
|
|
243
|
-
// Encrypt data
|
|
244
|
-
const { ciphertext } = await wallet.encrypt({
|
|
245
|
-
plaintext,
|
|
246
|
-
protocolID: [1, 'secure storage'],
|
|
247
|
-
keyID: 'data-encryption-key'
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
console.log('Original message:', secretMessage)
|
|
251
|
-
console.log('Encrypted (base64):', Utils.toBase64(ciphertext))
|
|
252
|
-
|
|
253
|
-
// Decrypt data
|
|
254
|
-
const { plaintext: decrypted } = await wallet.decrypt({
|
|
255
|
-
ciphertext,
|
|
256
|
-
protocolID: [1, 'secure storage'],
|
|
257
|
-
keyID: 'data-encryption-key'
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
const decryptedMessage = Utils.toUTF8(decrypted)
|
|
261
|
-
console.log('Decrypted message:', decryptedMessage)
|
|
262
|
-
|
|
263
|
-
return { original: secretMessage, decrypted: decryptedMessage }
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
demonstrateEncryption().catch(console.error)
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Counterparty Encryption
|
|
270
|
-
|
|
271
|
-
```typescript
|
|
272
|
-
import { ProtoWallet, Utils } from '@bsv/sdk'
|
|
273
|
-
|
|
274
|
-
class SecureMessaging {
|
|
275
|
-
private aliceWallet: ProtoWallet
|
|
276
|
-
private bobWallet: ProtoWallet
|
|
277
|
-
private aliceIdentity: string
|
|
278
|
-
private bobIdentity: string
|
|
279
|
-
|
|
280
|
-
constructor() {
|
|
281
|
-
this.aliceWallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
282
|
-
this.bobWallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async initialize() {
|
|
286
|
-
// Get identity keys for both parties
|
|
287
|
-
const aliceKey = await this.aliceWallet.getPublicKey({ identityKey: true })
|
|
288
|
-
const bobKey = await this.bobWallet.getPublicKey({ identityKey: true })
|
|
289
|
-
|
|
290
|
-
this.aliceIdentity = aliceKey.publicKey
|
|
291
|
-
this.bobIdentity = bobKey.publicKey
|
|
292
|
-
|
|
293
|
-
console.log('Alice Identity:', this.aliceIdentity.substring(0, 20) + '...')
|
|
294
|
-
console.log('Bob Identity:', this.bobIdentity.substring(0, 20) + '...')
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
async aliceSendsToBob(message: string): Promise<string> {
|
|
298
|
-
const plaintext = Utils.toArray(message, 'utf8')
|
|
299
|
-
|
|
300
|
-
const { ciphertext } = await this.aliceWallet.encrypt({
|
|
301
|
-
plaintext,
|
|
302
|
-
protocolID: [1, 'secure chat'],
|
|
303
|
-
keyID: 'message-key',
|
|
304
|
-
counterparty: this.bobIdentity
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
console.log('Alice encrypts message for Bob')
|
|
308
|
-
return Utils.toBase64(ciphertext)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async bobReceivesFromAlice(ciphertext: string): Promise<string> {
|
|
312
|
-
const ciphertextBytes = Utils.toArray(ciphertext, 'base64')
|
|
313
|
-
|
|
314
|
-
const { plaintext } = await this.bobWallet.decrypt({
|
|
315
|
-
ciphertext: ciphertextBytes,
|
|
316
|
-
protocolID: [1, 'secure chat'],
|
|
317
|
-
keyID: 'message-key',
|
|
318
|
-
counterparty: this.aliceIdentity
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
const message = Utils.toUTF8(plaintext)
|
|
322
|
-
console.log('Bob decrypts message from Alice')
|
|
323
|
-
return message
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
async function demonstrateSecureMessaging() {
|
|
328
|
-
const messaging = new SecureMessaging()
|
|
329
|
-
await messaging.initialize()
|
|
330
|
-
|
|
331
|
-
const originalMessage = 'Hello Bob, this is a secure message from Alice!'
|
|
332
|
-
|
|
333
|
-
// Alice encrypts and sends
|
|
334
|
-
const encryptedMessage = await messaging.aliceSendsToBob(originalMessage)
|
|
335
|
-
console.log('Encrypted message length:', encryptedMessage.length, 'bytes')
|
|
336
|
-
|
|
337
|
-
// Bob receives and decrypts
|
|
338
|
-
const decryptedMessage = await messaging.bobReceivesFromAlice(encryptedMessage)
|
|
339
|
-
|
|
340
|
-
console.log('Original:', originalMessage)
|
|
341
|
-
console.log('Decrypted:', decryptedMessage)
|
|
342
|
-
console.log('Messages match:', originalMessage === decryptedMessage)
|
|
343
|
-
|
|
344
|
-
return { originalMessage, decryptedMessage }
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
demonstrateSecureMessaging().catch(console.error)
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
## HMAC Operations
|
|
351
|
-
|
|
352
|
-
### Creating and Verifying HMACs
|
|
353
|
-
|
|
354
|
-
```typescript
|
|
355
|
-
import { ProtoWallet, Utils } from '@bsv/sdk'
|
|
356
|
-
|
|
357
|
-
async function demonstrateHMAC() {
|
|
358
|
-
const wallet = new ProtoWallet(PrivateKey.fromRandom())
|
|
359
|
-
|
|
360
|
-
// Data to authenticate
|
|
361
|
-
const data = Utils.toArray('Important data requiring integrity verification', 'utf8')
|
|
362
|
-
|
|
363
|
-
// Create HMAC
|
|
364
|
-
const { hmac } = await wallet.createHmac({
|
|
365
|
-
data,
|
|
366
|
-
protocolID: [1, 'data integrity'],
|
|
367
|
-
keyID: 'hmac-key'
|
|
368
|
-
})
|
|
369
|
-
|
|
370
|
-
console.log('Data:', Utils.toUTF8(data))
|
|
371
|
-
console.log('HMAC:', Utils.toHex(hmac))
|
|
372
|
-
|
|
373
|
-
// Verify HMAC
|
|
374
|
-
const { valid } = await wallet.verifyHmac({
|
|
375
|
-
data,
|
|
376
|
-
hmac,
|
|
377
|
-
protocolID: [1, 'data integrity'],
|
|
378
|
-
keyID: 'hmac-key'
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
console.log('HMAC valid:', valid)
|
|
382
|
-
|
|
383
|
-
// Test with tampered data
|
|
384
|
-
const tamperedData = Utils.toArray('Tampered data requiring integrity verification', 'utf8')
|
|
385
|
-
const { valid: tamperedValid } = await wallet.verifyHmac({
|
|
386
|
-
data: tamperedData,
|
|
387
|
-
hmac,
|
|
388
|
-
protocolID: [1, 'data integrity'],
|
|
389
|
-
keyID: 'hmac-key'
|
|
390
|
-
})
|
|
391
|
-
|
|
392
|
-
console.log('Tampered data HMAC valid:', tamperedValid)
|
|
393
|
-
|
|
394
|
-
return { valid, tamperedValid }
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
demonstrateHMAC().catch(console.error)
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
## Building a Development Toolkit
|
|
401
|
-
|
|
402
|
-
### Complete ProtoWallet Utility Class
|
|
403
|
-
|
|
404
|
-
```typescript
|
|
405
|
-
import { ProtoWallet, PrivateKey, Utils } from '@bsv/sdk'
|
|
406
|
-
|
|
407
|
-
export class DevelopmentWallet {
|
|
408
|
-
private wallet: ProtoWallet
|
|
409
|
-
private identityKey: string | null = null
|
|
410
|
-
|
|
411
|
-
constructor(privateKey?: PrivateKey) {
|
|
412
|
-
this.wallet = new ProtoWallet(privateKey)
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
async getIdentity(): Promise<string> {
|
|
416
|
-
if (!this.identityKey) {
|
|
417
|
-
const { publicKey } = await this.wallet.getPublicKey({ identityKey: true })
|
|
418
|
-
this.identityKey = publicKey
|
|
419
|
-
}
|
|
420
|
-
return this.identityKey
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
async signData(data: string, protocolId: string, keyId: string): Promise<{
|
|
424
|
-
signature: string
|
|
425
|
-
publicKey: string
|
|
426
|
-
data: string
|
|
427
|
-
}> {
|
|
428
|
-
const dataBytes = Utils.toArray(data, 'utf8')
|
|
429
|
-
|
|
430
|
-
const { signature } = await this.wallet.createSignature({
|
|
431
|
-
data: dataBytes,
|
|
432
|
-
protocolID: [1, protocolId],
|
|
433
|
-
keyID: keyId,
|
|
434
|
-
counterparty: 'self'
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
const { publicKey } = await this.wallet.getPublicKey({
|
|
438
|
-
protocolID: [1, protocolId],
|
|
439
|
-
keyID: keyId
|
|
440
|
-
})
|
|
441
|
-
|
|
442
|
-
return {
|
|
443
|
-
signature: Utils.toBase64(signature),
|
|
444
|
-
publicKey,
|
|
445
|
-
data
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
async verifyData(
|
|
450
|
-
data: string,
|
|
451
|
-
signature: string,
|
|
452
|
-
protocolId: string,
|
|
453
|
-
keyId: string
|
|
454
|
-
): Promise<boolean> {
|
|
455
|
-
const dataBytes = Utils.toArray(data, 'utf8')
|
|
456
|
-
const signatureBytes = Utils.toArray(signature, 'base64')
|
|
457
|
-
|
|
458
|
-
const { valid } = await this.wallet.verifySignature({
|
|
459
|
-
data: dataBytes,
|
|
460
|
-
signature: signatureBytes,
|
|
461
|
-
protocolID: [1, protocolId],
|
|
462
|
-
keyID: keyId,
|
|
463
|
-
counterparty: 'self'
|
|
464
|
-
})
|
|
465
|
-
|
|
466
|
-
return valid
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
async encryptForSelf(data: string, protocolId: string, keyId: string): Promise<string> {
|
|
470
|
-
const plaintext = Utils.toArray(data, 'utf8')
|
|
471
|
-
|
|
472
|
-
const { ciphertext } = await this.wallet.encrypt({
|
|
473
|
-
plaintext,
|
|
474
|
-
protocolID: [1, protocolId],
|
|
475
|
-
keyID: keyId
|
|
476
|
-
})
|
|
477
|
-
|
|
478
|
-
return Utils.toBase64(ciphertext)
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
async decryptFromSelf(
|
|
482
|
-
encryptedData: string,
|
|
483
|
-
protocolId: string,
|
|
484
|
-
keyId: string
|
|
485
|
-
): Promise<string> {
|
|
486
|
-
const ciphertext = Utils.toArray(encryptedData, 'base64')
|
|
487
|
-
|
|
488
|
-
const { plaintext } = await this.wallet.decrypt({
|
|
489
|
-
ciphertext,
|
|
490
|
-
protocolID: [1, protocolId],
|
|
491
|
-
keyID: keyId
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
return Utils.toUTF8(plaintext)
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
async createDataIntegrityTag(data: string, protocolId: string, keyId: string): Promise<string> {
|
|
498
|
-
const dataBytes = Utils.toArray(data, 'utf8')
|
|
499
|
-
|
|
500
|
-
const { hmac } = await this.wallet.createHmac({
|
|
501
|
-
data: dataBytes,
|
|
502
|
-
protocolID: [1, protocolId],
|
|
503
|
-
keyID: keyId
|
|
504
|
-
})
|
|
505
|
-
|
|
506
|
-
return Utils.toHex(hmac)
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
async verifyDataIntegrity(
|
|
510
|
-
data: string,
|
|
511
|
-
integrityTag: string,
|
|
512
|
-
protocolId: string,
|
|
513
|
-
keyId: string
|
|
514
|
-
): Promise<boolean> {
|
|
515
|
-
const dataBytes = Utils.toArray(data, 'utf8')
|
|
516
|
-
const hmac = Utils.toArray(integrityTag, 'hex')
|
|
517
|
-
|
|
518
|
-
const { valid } = await this.wallet.verifyHmac({
|
|
519
|
-
data: dataBytes,
|
|
520
|
-
hmac,
|
|
521
|
-
protocolID: [1, protocolId],
|
|
522
|
-
keyID: keyId
|
|
523
|
-
})
|
|
524
|
-
|
|
525
|
-
return valid
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
async function demonstrateDevelopmentToolkit() {
|
|
530
|
-
const devWallet = new DevelopmentWallet()
|
|
531
|
-
|
|
532
|
-
console.log('=== Development Wallet Toolkit Demo ===')
|
|
533
|
-
|
|
534
|
-
// Get identity
|
|
535
|
-
const identity = await devWallet.getIdentity()
|
|
536
|
-
console.log('Wallet Identity:', identity.substring(0, 20) + '...')
|
|
537
|
-
|
|
538
|
-
// Sign and verify data
|
|
539
|
-
const testData = 'Development test data for signing'
|
|
540
|
-
const signatureResult = await devWallet.signData(testData, 'dev-tools', 'test-key')
|
|
541
|
-
console.log('Data signed successfully')
|
|
542
|
-
|
|
543
|
-
const isValid = await devWallet.verifyData(
|
|
544
|
-
testData,
|
|
545
|
-
signatureResult.signature,
|
|
546
|
-
'dev-tools',
|
|
547
|
-
'test-key'
|
|
548
|
-
)
|
|
549
|
-
console.log('Signature verification:', isValid ? 'PASSED' : 'FAILED')
|
|
550
|
-
|
|
551
|
-
// Encrypt and decrypt data
|
|
552
|
-
const secretData = 'Confidential development information'
|
|
553
|
-
const encrypted = await devWallet.encryptForSelf(secretData, 'dev-storage', 'secret-key')
|
|
554
|
-
console.log('Data encrypted successfully')
|
|
555
|
-
|
|
556
|
-
const decrypted = await devWallet.decryptFromSelf(encrypted, 'dev-storage', 'secret-key')
|
|
557
|
-
console.log('Decryption result:', secretData === decrypted ? 'PASSED' : 'FAILED')
|
|
558
|
-
|
|
559
|
-
// Create and verify integrity tag
|
|
560
|
-
const importantData = 'Critical development configuration'
|
|
561
|
-
const integrityTag = await devWallet.createDataIntegrityTag(
|
|
562
|
-
importantData,
|
|
563
|
-
'dev-integrity',
|
|
564
|
-
'config-key'
|
|
565
|
-
)
|
|
566
|
-
console.log('Integrity tag created')
|
|
567
|
-
|
|
568
|
-
const integrityValid = await devWallet.verifyDataIntegrity(
|
|
569
|
-
importantData,
|
|
570
|
-
integrityTag,
|
|
571
|
-
'dev-integrity',
|
|
572
|
-
'config-key'
|
|
573
|
-
)
|
|
574
|
-
console.log('Integrity verification:', integrityValid ? 'PASSED' : 'FAILED')
|
|
575
|
-
|
|
576
|
-
return {
|
|
577
|
-
identity,
|
|
578
|
-
signatureValid: isValid,
|
|
579
|
-
decryptionValid: secretData === decrypted,
|
|
580
|
-
integrityValid
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
demonstrateDevelopmentToolkit().catch(console.error)
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
## Testing Framework Integration
|
|
588
|
-
|
|
589
|
-
### ProtoWallet Test Utilities
|
|
590
|
-
|
|
591
|
-
```typescript
|
|
592
|
-
import { ProtoWallet, PrivateKey, Utils } from '@bsv/sdk'
|
|
593
|
-
|
|
594
|
-
export class ProtoWalletTestUtils {
|
|
595
|
-
static createTestWallet(seed?: string): ProtoWallet {
|
|
596
|
-
if (seed) {
|
|
597
|
-
// Create deterministic wallet for testing
|
|
598
|
-
const hash = Utils.toArray(seed, 'utf8')
|
|
599
|
-
const privateKey = PrivateKey.fromString(Utils.toHex(hash).padEnd(64, '0'))
|
|
600
|
-
return new ProtoWallet(privateKey)
|
|
601
|
-
}
|
|
602
|
-
return new ProtoWallet(PrivateKey.fromRandom())
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
static async createTestIdentities(count: number): Promise<{
|
|
606
|
-
wallets: ProtoWallet[]
|
|
607
|
-
identities: string[]
|
|
608
|
-
}> {
|
|
609
|
-
const wallets: ProtoWallet[] = []
|
|
610
|
-
const identities: string[] = []
|
|
611
|
-
|
|
612
|
-
for (let i = 0; i < count; i++) {
|
|
613
|
-
const wallet = this.createTestWallet(`test-identity-${i}`)
|
|
614
|
-
const { publicKey } = await wallet.getPublicKey({ identityKey: true })
|
|
615
|
-
|
|
616
|
-
wallets.push(wallet)
|
|
617
|
-
identities.push(publicKey)
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
return { wallets, identities }
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
static async testCryptographicRoundTrip(
|
|
624
|
-
wallet: ProtoWallet,
|
|
625
|
-
data: string,
|
|
626
|
-
protocolId: string,
|
|
627
|
-
keyId: string
|
|
628
|
-
): Promise<{
|
|
629
|
-
signatureValid: boolean
|
|
630
|
-
encryptionValid: boolean
|
|
631
|
-
hmacValid: boolean
|
|
632
|
-
}> {
|
|
633
|
-
const dataBytes = Utils.toArray(data, 'utf8')
|
|
634
|
-
|
|
635
|
-
// Test signature round trip
|
|
636
|
-
const { signature } = await wallet.createSignature({
|
|
637
|
-
data: dataBytes,
|
|
638
|
-
protocolID: [1, protocolId],
|
|
639
|
-
keyID: keyId,
|
|
640
|
-
counterparty: 'self'
|
|
641
|
-
})
|
|
642
|
-
|
|
643
|
-
const { valid: signatureValid } = await wallet.verifySignature({
|
|
644
|
-
data: dataBytes,
|
|
645
|
-
signature,
|
|
646
|
-
protocolID: [1, protocolId],
|
|
647
|
-
keyID: keyId,
|
|
648
|
-
counterparty: 'self'
|
|
649
|
-
})
|
|
650
|
-
|
|
651
|
-
// Test encryption round trip
|
|
652
|
-
const { ciphertext } = await wallet.encrypt({
|
|
653
|
-
plaintext: dataBytes,
|
|
654
|
-
protocolID: [1, protocolId],
|
|
655
|
-
keyID: keyId
|
|
656
|
-
})
|
|
657
|
-
|
|
658
|
-
const { plaintext } = await wallet.decrypt({
|
|
659
|
-
ciphertext,
|
|
660
|
-
protocolID: [1, protocolId],
|
|
661
|
-
keyID: keyId
|
|
662
|
-
})
|
|
663
|
-
|
|
664
|
-
const encryptionValid = Utils.toUTF8(plaintext) === data
|
|
665
|
-
|
|
666
|
-
// Test HMAC round trip
|
|
667
|
-
const { hmac } = await wallet.createHmac({
|
|
668
|
-
data: dataBytes,
|
|
669
|
-
protocolID: [1, protocolId],
|
|
670
|
-
keyID: keyId
|
|
671
|
-
})
|
|
672
|
-
|
|
673
|
-
const { valid: hmacValid } = await wallet.verifyHmac({
|
|
674
|
-
data: dataBytes,
|
|
675
|
-
hmac,
|
|
676
|
-
protocolID: [1, protocolId],
|
|
677
|
-
keyID: keyId
|
|
678
|
-
})
|
|
679
|
-
|
|
680
|
-
return { signatureValid, encryptionValid, hmacValid }
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
async function runTestSuite() {
|
|
685
|
-
console.log('=== ProtoWallet Test Suite ===')
|
|
686
|
-
|
|
687
|
-
// Test deterministic wallet creation
|
|
688
|
-
const wallet1 = ProtoWalletTestUtils.createTestWallet('test-seed-123')
|
|
689
|
-
const wallet2 = ProtoWalletTestUtils.createTestWallet('test-seed-123')
|
|
690
|
-
|
|
691
|
-
const identity1 = await wallet1.getPublicKey({ identityKey: true })
|
|
692
|
-
const identity2 = await wallet2.getPublicKey({ identityKey: true })
|
|
693
|
-
|
|
694
|
-
console.log('Deterministic wallet test:',
|
|
695
|
-
identity1.publicKey === identity2.publicKey ? 'PASSED' : 'FAILED')
|
|
696
|
-
|
|
697
|
-
// Test multiple identities
|
|
698
|
-
const { wallets, identities } = await ProtoWalletTestUtils.createTestIdentities(3)
|
|
699
|
-
console.log('Created test identities:', identities.length)
|
|
700
|
-
|
|
701
|
-
// Test cryptographic operations
|
|
702
|
-
const testData = 'Test data for cryptographic operations'
|
|
703
|
-
const results = await ProtoWalletTestUtils.testCryptographicRoundTrip(
|
|
704
|
-
wallets[0],
|
|
705
|
-
testData,
|
|
706
|
-
'test-protocol',
|
|
707
|
-
'test-key'
|
|
708
|
-
)
|
|
709
|
-
|
|
710
|
-
console.log('Cryptographic tests:')
|
|
711
|
-
console.log(' Signature:', results.signatureValid ? 'PASSED' : 'FAILED')
|
|
712
|
-
console.log(' Encryption:', results.encryptionValid ? 'PASSED' : 'FAILED')
|
|
713
|
-
console.log(' HMAC:', results.hmacValid ? 'PASSED' : 'FAILED')
|
|
714
|
-
|
|
715
|
-
return results
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
runTestSuite().catch(console.error)
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
## Conclusion
|
|
722
|
-
|
|
723
|
-
Congratulations! You've successfully built a comprehensive ProtoWallet development framework using the BSV TypeScript SDK. In this tutorial, you've learned how to create, test, and manage prototype wallet implementations for rapid development and testing.
|
|
724
|
-
|
|
725
|
-
### Core Concepts Mastered
|
|
726
|
-
|
|
727
|
-
1. **ProtoWallet Architecture**: Implemented lightweight wallet prototypes for development and testing
|
|
728
|
-
2. **Key Management**: Created deterministic key generation and management systems
|
|
729
|
-
3. **Cryptographic Operations**: Implemented signing, encryption, and HMAC operations
|
|
730
|
-
4. **Protocol Integration**: Built protocol-specific wallet functionality with proper key derivation
|
|
731
|
-
5. **Testing Framework**: Developed comprehensive testing utilities for wallet validation
|
|
732
|
-
|
|
733
|
-
## Next Steps
|
|
734
|
-
|
|
735
|
-
- Learn about [Development Wallet Setup](../guides/development-wallet-setup.md) for production-ready wallet implementation
|
|
736
|
-
- Explore [Key Management](./key-management.md) for advanced cryptographic key handling
|
|
737
|
-
- Understand [Security Best Practices](../guides/security-best-practices.md) for secure wallet development
|
|
738
|
-
|
|
739
|
-
## Additional Resources
|
|
740
|
-
|
|
741
|
-
- [Wallet API Reference](../reference/wallet.md)
|
|
742
|
-
- [Key Management Concepts](../concepts/key-management.md)
|
|
743
|
-
- [BSV Wallet Standards](https://projectbabbage.com/docs/guides/wallet/)
|