@bsv/sdk 1.2.2 → 1.2.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/dist/cjs/src/auth/Certificate.js +1 -1
- package/dist/cjs/src/auth/Certificate.js.map +1 -1
- package/dist/cjs/src/overlay-tools/LookupResolver.js +8 -5
- package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/cjs/src/overlay-tools/OverlayAdminTokenTemplate.js.map +1 -1
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js +2 -1
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/cjs/src/transaction/Beef.js +19 -10
- package/dist/cjs/src/transaction/Beef.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +38 -6
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/src/wallet/CachedKeyDeriver.js.map +1 -1
- package/dist/cjs/src/wallet/KeyDeriver.js.map +1 -1
- package/dist/cjs/src/wallet/ProtoWallet.js.map +1 -1
- package/dist/cjs/src/wallet/WalletClient.js.map +1 -1
- package/dist/cjs/src/wallet/WalletError.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/Certificate.js +1 -1
- package/dist/esm/src/auth/Certificate.js.map +1 -1
- package/dist/esm/src/overlay-tools/LookupResolver.js +8 -5
- package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/esm/src/overlay-tools/OverlayAdminTokenTemplate.js.map +1 -1
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js +2 -1
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/esm/src/transaction/Beef.js +19 -10
- package/dist/esm/src/transaction/Beef.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +38 -6
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/src/wallet/CachedKeyDeriver.js.map +1 -1
- package/dist/esm/src/wallet/KeyDeriver.js.map +1 -1
- package/dist/esm/src/wallet/ProtoWallet.js.map +1 -1
- package/dist/esm/src/wallet/WalletClient.js.map +1 -1
- package/dist/esm/src/wallet/WalletError.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/Certificate.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts +10 -3
- package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/OverlayAdminTokenTemplate.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts.map +1 -1
- package/dist/types/src/transaction/Beef.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/src/wallet/CachedKeyDeriver.d.ts.map +1 -1
- package/dist/types/src/wallet/KeyDeriver.d.ts.map +1 -1
- package/dist/types/src/wallet/ProtoWallet.d.ts.map +1 -1
- package/dist/types/src/wallet/Wallet.interfaces.d.ts +11 -11
- package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -1
- package/dist/types/src/wallet/WalletClient.d.ts.map +1 -1
- package/dist/types/src/wallet/WalletError.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/overlay-tools.md +19 -4
- package/package.json +1 -1
- package/src/auth/Certificate.ts +9 -9
- package/src/auth/index.ts +1 -1
- package/src/overlay-tools/LookupResolver.ts +25 -9
- package/src/overlay-tools/OverlayAdminTokenTemplate.ts +4 -4
- package/src/overlay-tools/SHIPBroadcaster.ts +11 -9
- package/src/overlay-tools/__tests/LookupResolver.test.ts +83 -42
- package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +5 -5
- package/src/overlay-tools/index.ts +1 -1
- package/src/transaction/Beef.ts +33 -48
- package/src/transaction/BeefParty.ts +4 -4
- package/src/transaction/BeefTx.ts +1 -1
- package/src/transaction/Transaction.ts +38 -10
- package/src/transaction/__tests/Transaction.test.ts +133 -4
- package/src/wallet/CachedKeyDeriver.ts +10 -10
- package/src/wallet/KeyDeriver.ts +8 -8
- package/src/wallet/ProtoWallet.ts +176 -176
- package/src/wallet/Wallet.interfaces.ts +19 -19
- package/src/wallet/WalletClient.ts +30 -30
- package/src/wallet/WalletError.ts +2 -2
|
@@ -140,9 +140,9 @@ export default class Transaction {
|
|
|
140
140
|
const validTxids = new Set<string>()
|
|
141
141
|
// All BUMP level 0 hashes are valid.
|
|
142
142
|
for (const bump of BUMPs) {
|
|
143
|
-
for (const n of bump.path[0])
|
|
144
|
-
if (n.hash)
|
|
145
|
-
|
|
143
|
+
for (const n of bump.path[0]) {
|
|
144
|
+
if (n.hash) { validTxids.add(n.hash) }
|
|
145
|
+
}
|
|
146
146
|
}
|
|
147
147
|
// To keep track of which transactions were used.
|
|
148
148
|
const unusedTxTxids = new Set<string>()
|
|
@@ -524,17 +524,47 @@ export default class Transaction {
|
|
|
524
524
|
}
|
|
525
525
|
|
|
526
526
|
// Distribute change among change outputs
|
|
527
|
+
let distributedChange = 0
|
|
527
528
|
if (changeDistribution === 'random') {
|
|
528
|
-
//
|
|
529
|
-
|
|
529
|
+
// Implement Benford's Law distribution for change outputs
|
|
530
|
+
const changeOutputs = this.outputs.filter(out => out.change)
|
|
531
|
+
let changeToUse = change
|
|
532
|
+
|
|
533
|
+
// Helper function to generate a number approximating Benford's Law
|
|
534
|
+
const benfordNumber = (min: number, max: number): number => {
|
|
535
|
+
const d = Math.floor(Math.random() * 9) + 1
|
|
536
|
+
return Math.floor(min + (max - min) * Math.log10(1 + 1 / d) / Math.log10(10))
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const benfordNumbers = Array(changeOutputs.length).fill(1)
|
|
540
|
+
changeToUse -= changeOutputs.length
|
|
541
|
+
distributedChange += changeOutputs.length
|
|
542
|
+
for (let i = 0; i < changeOutputs.length - 1; i++) {
|
|
543
|
+
const portion = benfordNumber(0, changeToUse)
|
|
544
|
+
benfordNumbers[i] += portion
|
|
545
|
+
distributedChange += portion
|
|
546
|
+
changeToUse -= portion
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
for (let i = 0; i < this.outputs.length; i++) {
|
|
550
|
+
if (this.outputs[i].change) {
|
|
551
|
+
const t = benfordNumbers.shift()
|
|
552
|
+
this.outputs[i].satoshis = t
|
|
553
|
+
}
|
|
554
|
+
}
|
|
530
555
|
} else if (changeDistribution === 'equal') {
|
|
531
556
|
const perOutput = Math.floor(change / changeCount)
|
|
532
557
|
for (const out of this.outputs) {
|
|
533
558
|
if (out.change) {
|
|
559
|
+
distributedChange += perOutput
|
|
534
560
|
out.satoshis = perOutput
|
|
535
561
|
}
|
|
536
562
|
}
|
|
537
563
|
}
|
|
564
|
+
// if there's any remaining change, add it to the last output
|
|
565
|
+
if (distributedChange < change) {
|
|
566
|
+
this.outputs[this.outputs.length - 1].satoshis += (change - distributedChange)
|
|
567
|
+
}
|
|
538
568
|
}
|
|
539
569
|
|
|
540
570
|
/**
|
|
@@ -868,13 +898,14 @@ export default class Transaction {
|
|
|
868
898
|
|
|
869
899
|
/**
|
|
870
900
|
* Serializes this transaction, together with its inputs and the respective merkle proofs, into the BEEF (BRC-62) format. This enables efficient verification of its compliance with the rules of SPV.
|
|
871
|
-
*
|
|
901
|
+
*
|
|
872
902
|
* @param allowPartial If true, error will not be thrown if there are any missing sourceTransactions.
|
|
873
903
|
*
|
|
874
904
|
* @returns The serialized BEEF structure
|
|
875
905
|
* @throws Error if there are any missing sourceTransactions unless `allowPartial` is true.
|
|
876
906
|
*/
|
|
877
907
|
toBEEF (allowPartial?: boolean): number[] {
|
|
908
|
+
this.outputs.length
|
|
878
909
|
const writer = new Writer()
|
|
879
910
|
writer.writeUInt32LE(4022206465)
|
|
880
911
|
const BUMPs: MerklePath[] = []
|
|
@@ -919,10 +950,7 @@ export default class Transaction {
|
|
|
919
950
|
if (!hasProof) {
|
|
920
951
|
for (let i = 0; i < tx.inputs.length; i++) {
|
|
921
952
|
const input = tx.inputs[i]
|
|
922
|
-
if (typeof input.sourceTransaction === 'object')
|
|
923
|
-
addPathsAndInputs(input.sourceTransaction)
|
|
924
|
-
else if (!allowPartial)
|
|
925
|
-
throw new Error('A required source transaction is missing!')
|
|
953
|
+
if (typeof input.sourceTransaction === 'object') { addPathsAndInputs(input.sourceTransaction) } else if (!allowPartial) { throw new Error('A required source transaction is missing!') }
|
|
926
954
|
}
|
|
927
955
|
}
|
|
928
956
|
}
|
|
@@ -346,7 +346,7 @@ describe('Transaction', () => {
|
|
|
346
346
|
// 4000 sats in - 1000 sats out - 1033 sats fee = expected 1967 sats change
|
|
347
347
|
expect(spendTx.outputs[1].satoshis).toEqual(1967)
|
|
348
348
|
})
|
|
349
|
-
it('Distributes change among multiple change outputs', async () => {
|
|
349
|
+
it('Distributes change equally among multiple change outputs', async () => {
|
|
350
350
|
const privateKey = new PrivateKey(1)
|
|
351
351
|
const publicKey = new Curve().g.mul(privateKey)
|
|
352
352
|
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
@@ -369,17 +369,146 @@ describe('Transaction', () => {
|
|
|
369
369
|
}, {
|
|
370
370
|
lockingScript: p2pkh.lock(publicKeyHash),
|
|
371
371
|
change: true
|
|
372
|
+
}, {
|
|
373
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
374
|
+
change: true
|
|
375
|
+
}, {
|
|
376
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
377
|
+
change: true
|
|
372
378
|
}], 0)
|
|
373
379
|
expect(spendTx.outputs[1].satoshis).not.toBeDefined()
|
|
374
380
|
expect(spendTx.outputs[2].satoshis).not.toBeDefined()
|
|
381
|
+
expect(spendTx.outputs[3].satoshis).not.toBeDefined()
|
|
382
|
+
expect(spendTx.outputs[4].satoshis).not.toBeDefined()
|
|
375
383
|
await spendTx.fee({
|
|
376
384
|
// Our custom fee model will always charge 1033 sats for a tx.
|
|
377
|
-
computeFee: async () =>
|
|
385
|
+
computeFee: async () => 1032
|
|
378
386
|
})
|
|
379
387
|
// 4000 sats in - 1000 sats out - 1033 sats fee = expected 1967 sats change
|
|
380
388
|
// Divide by 2 (no remainder) = 983 sats per change output
|
|
381
|
-
expect(spendTx.outputs[
|
|
382
|
-
expect(spendTx.outputs[
|
|
389
|
+
expect(spendTx.outputs[0].satoshis).toEqual(1000)
|
|
390
|
+
expect(spendTx.outputs[1].satoshis).toEqual(492)
|
|
391
|
+
expect(spendTx.outputs[2].satoshis).toEqual(492)
|
|
392
|
+
expect(spendTx.outputs[3].satoshis).toEqual(492)
|
|
393
|
+
expect(spendTx.outputs[4].satoshis).toEqual(492)
|
|
394
|
+
})
|
|
395
|
+
it('Distributes change randomly among multiple change outputs', async () => {
|
|
396
|
+
const privateKey = new PrivateKey(1)
|
|
397
|
+
const publicKey = new Curve().g.mul(privateKey)
|
|
398
|
+
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
399
|
+
const p2pkh = new P2PKH()
|
|
400
|
+
const sourceTx = new Transaction(1, [], [{
|
|
401
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
402
|
+
satoshis: 900
|
|
403
|
+
}], 0)
|
|
404
|
+
const spendTx = new Transaction(1, [{
|
|
405
|
+
sourceTransaction: sourceTx,
|
|
406
|
+
sourceOutputIndex: 0,
|
|
407
|
+
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
408
|
+
sequence: 0xffffffff
|
|
409
|
+
}], [{
|
|
410
|
+
satoshis: 1,
|
|
411
|
+
lockingScript: p2pkh.lock(publicKeyHash)
|
|
412
|
+
}, {
|
|
413
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
414
|
+
change: true
|
|
415
|
+
}, {
|
|
416
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
417
|
+
change: true
|
|
418
|
+
}, {
|
|
419
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
420
|
+
change: true
|
|
421
|
+
}, {
|
|
422
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
423
|
+
change: true
|
|
424
|
+
}, {
|
|
425
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
426
|
+
change: true
|
|
427
|
+
}, {
|
|
428
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
429
|
+
change: true
|
|
430
|
+
}], 0)
|
|
431
|
+
expect(spendTx.outputs[1].satoshis).not.toBeDefined()
|
|
432
|
+
expect(spendTx.outputs[2].satoshis).not.toBeDefined()
|
|
433
|
+
expect(spendTx.outputs[3].satoshis).not.toBeDefined()
|
|
434
|
+
expect(spendTx.outputs[4].satoshis).not.toBeDefined()
|
|
435
|
+
expect(spendTx.outputs[5].satoshis).not.toBeDefined()
|
|
436
|
+
expect(spendTx.outputs[6].satoshis).not.toBeDefined()
|
|
437
|
+
await spendTx.fee({
|
|
438
|
+
computeFee: async () => 3
|
|
439
|
+
}, 'random')
|
|
440
|
+
expect(spendTx.outputs[0].satoshis).toEqual(1)
|
|
441
|
+
expect(spendTx.outputs.reduce((a, b) => a + b.satoshis, 0)).toEqual(897)
|
|
442
|
+
})
|
|
443
|
+
it('Distributes change randomly among multiple change outputs, with one set output', async () => {
|
|
444
|
+
const privateKey = new PrivateKey(1)
|
|
445
|
+
const publicKey = new Curve().g.mul(privateKey)
|
|
446
|
+
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
447
|
+
const p2pkh = new P2PKH()
|
|
448
|
+
const sourceTx = new Transaction(1, [], [{
|
|
449
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
450
|
+
satoshis: 9
|
|
451
|
+
}], 0)
|
|
452
|
+
const spendTx = new Transaction(1, [{
|
|
453
|
+
sourceTransaction: sourceTx,
|
|
454
|
+
sourceOutputIndex: 0,
|
|
455
|
+
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
456
|
+
sequence: 0xffffffff
|
|
457
|
+
}], [{
|
|
458
|
+
satoshis: 1,
|
|
459
|
+
lockingScript: p2pkh.lock(publicKeyHash)
|
|
460
|
+
}, {
|
|
461
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
462
|
+
change: true
|
|
463
|
+
}, {
|
|
464
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
465
|
+
change: true
|
|
466
|
+
}, {
|
|
467
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
468
|
+
change: true
|
|
469
|
+
}, {
|
|
470
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
471
|
+
change: true
|
|
472
|
+
}, {
|
|
473
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
474
|
+
change: true
|
|
475
|
+
}, {
|
|
476
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
477
|
+
change: true
|
|
478
|
+
}], 0)
|
|
479
|
+
expect(spendTx.outputs[1].satoshis).not.toBeDefined()
|
|
480
|
+
expect(spendTx.outputs[2].satoshis).not.toBeDefined()
|
|
481
|
+
expect(spendTx.outputs[3].satoshis).not.toBeDefined()
|
|
482
|
+
expect(spendTx.outputs[4].satoshis).not.toBeDefined()
|
|
483
|
+
expect(spendTx.outputs[5].satoshis).not.toBeDefined()
|
|
484
|
+
expect(spendTx.outputs[6].satoshis).not.toBeDefined()
|
|
485
|
+
await spendTx.fee({
|
|
486
|
+
computeFee: async () => 1
|
|
487
|
+
}, 'random')
|
|
488
|
+
expect(spendTx.outputs.reduce((a, b) => a + b.satoshis, 0)).toEqual(8)
|
|
489
|
+
})
|
|
490
|
+
it('Distributes change randomly among multiple change outputs, thinnly spread', async () => {
|
|
491
|
+
const privateKey = new PrivateKey(1)
|
|
492
|
+
const publicKey = new Curve().g.mul(privateKey)
|
|
493
|
+
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
494
|
+
const p2pkh = new P2PKH()
|
|
495
|
+
const sourceTx = new Transaction(1, [], [{
|
|
496
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
497
|
+
satoshis: 46
|
|
498
|
+
}], 0)
|
|
499
|
+
const spendTx = new Transaction(1, [{
|
|
500
|
+
sourceTransaction: sourceTx,
|
|
501
|
+
sourceOutputIndex: 0,
|
|
502
|
+
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
503
|
+
sequence: 0xffffffff
|
|
504
|
+
}], Array(21).fill(null).map(() => ({
|
|
505
|
+
lockingScript: p2pkh.lock(publicKeyHash),
|
|
506
|
+
change: true
|
|
507
|
+
})), 0)
|
|
508
|
+
await spendTx.fee({
|
|
509
|
+
computeFee: async () => 1
|
|
510
|
+
}, 'random')
|
|
511
|
+
expect(spendTx.outputs.reduce((a, b) => a + b.satoshis, 0)).toEqual(45)
|
|
383
512
|
})
|
|
384
513
|
it('Calculates fee for utxo based transaction', async () => {
|
|
385
514
|
const utxos = [ // WoC format utxos
|
|
@@ -17,7 +17,7 @@ export default class CachedKeyDeriver {
|
|
|
17
17
|
* @param {Object} [options] - Optional settings for the cache.
|
|
18
18
|
* @param {number} [options.maxCacheSize=1000] - The maximum number of entries to store in the cache.
|
|
19
19
|
*/
|
|
20
|
-
constructor(rootKey: PrivateKey | 'anyone', options?: { maxCacheSize?: number }) {
|
|
20
|
+
constructor (rootKey: PrivateKey | 'anyone', options?: { maxCacheSize?: number }) {
|
|
21
21
|
this.keyDeriver = new KeyDeriver(rootKey)
|
|
22
22
|
this.cache = new Map<string, any>()
|
|
23
23
|
this.maxCacheSize = options?.maxCacheSize || 1000
|
|
@@ -32,7 +32,7 @@ export default class CachedKeyDeriver {
|
|
|
32
32
|
* @param {boolean} [forSelf=false] - Whether deriving for self.
|
|
33
33
|
* @returns {PublicKey} - The derived public key.
|
|
34
34
|
*/
|
|
35
|
-
derivePublicKey(
|
|
35
|
+
derivePublicKey (
|
|
36
36
|
protocolID: [0 | 1 | 2, string],
|
|
37
37
|
keyID: string,
|
|
38
38
|
counterparty: PublicKey | string | 'self' | 'anyone',
|
|
@@ -56,7 +56,7 @@ export default class CachedKeyDeriver {
|
|
|
56
56
|
* @param {PublicKey | string | 'self' | 'anyone'} counterparty - The counterparty's public key or a predefined value ('self' or 'anyone').
|
|
57
57
|
* @returns {PrivateKey} - The derived private key.
|
|
58
58
|
*/
|
|
59
|
-
derivePrivateKey(
|
|
59
|
+
derivePrivateKey (
|
|
60
60
|
protocolID: [0 | 1 | 2, string],
|
|
61
61
|
keyID: string,
|
|
62
62
|
counterparty: PublicKey | string | 'self' | 'anyone'
|
|
@@ -80,7 +80,7 @@ export default class CachedKeyDeriver {
|
|
|
80
80
|
* @returns {SymmetricKey} - The derived symmetric key.
|
|
81
81
|
* @throws {Error} - Throws an error if attempting to derive a symmetric key for 'anyone'.
|
|
82
82
|
*/
|
|
83
|
-
deriveSymmetricKey(
|
|
83
|
+
deriveSymmetricKey (
|
|
84
84
|
protocolID: [0 | 1 | 2, string],
|
|
85
85
|
keyID: string,
|
|
86
86
|
counterparty: PublicKey | string | 'self' | 'anyone'
|
|
@@ -102,7 +102,7 @@ export default class CachedKeyDeriver {
|
|
|
102
102
|
* @returns {number[]} - The shared secret as a number array.
|
|
103
103
|
* @throws {Error} - Throws an error if attempting to reveal a shared secret for 'self'.
|
|
104
104
|
*/
|
|
105
|
-
revealCounterpartySecret(counterparty: PublicKey | string | 'self' | 'anyone'): number[] {
|
|
105
|
+
revealCounterpartySecret (counterparty: PublicKey | string | 'self' | 'anyone'): number[] {
|
|
106
106
|
const cacheKey = this.generateCacheKey('revealCounterpartySecret', counterparty)
|
|
107
107
|
if (this.cache.has(cacheKey)) {
|
|
108
108
|
return this.cacheGet(cacheKey)
|
|
@@ -121,7 +121,7 @@ export default class CachedKeyDeriver {
|
|
|
121
121
|
* @param {string} keyID - The key identifier.
|
|
122
122
|
* @returns {number[]} - The specific key association as a number array.
|
|
123
123
|
*/
|
|
124
|
-
revealSpecificSecret(
|
|
124
|
+
revealSpecificSecret (
|
|
125
125
|
counterparty: PublicKey | string | 'self' | 'anyone',
|
|
126
126
|
protocolID: [0 | 1 | 2, string],
|
|
127
127
|
keyID: string
|
|
@@ -142,7 +142,7 @@ export default class CachedKeyDeriver {
|
|
|
142
142
|
* @param {...any} args - The arguments passed to the method.
|
|
143
143
|
* @returns {string} - The generated cache key.
|
|
144
144
|
*/
|
|
145
|
-
private generateCacheKey(methodName: string, ...args: any[]): string {
|
|
145
|
+
private generateCacheKey (methodName: string, ...args: any[]): string {
|
|
146
146
|
const serializedArgs = args.map((arg) => this.serializeArgument(arg)).join('|')
|
|
147
147
|
return `${methodName}|${serializedArgs}`
|
|
148
148
|
}
|
|
@@ -152,7 +152,7 @@ export default class CachedKeyDeriver {
|
|
|
152
152
|
* @param {any} arg - The argument to serialize.
|
|
153
153
|
* @returns {string} - The serialized argument.
|
|
154
154
|
*/
|
|
155
|
-
private serializeArgument(arg: any): string {
|
|
155
|
+
private serializeArgument (arg: any): string {
|
|
156
156
|
if (arg instanceof PublicKey || arg instanceof PrivateKey) {
|
|
157
157
|
return arg.toString()
|
|
158
158
|
} else if (Array.isArray(arg)) {
|
|
@@ -169,7 +169,7 @@ export default class CachedKeyDeriver {
|
|
|
169
169
|
* @param {string} cacheKey - The key of the cached item.
|
|
170
170
|
* @returns {any} - The cached value.
|
|
171
171
|
*/
|
|
172
|
-
private cacheGet(cacheKey: string): any {
|
|
172
|
+
private cacheGet (cacheKey: string): any {
|
|
173
173
|
const value = this.cache.get(cacheKey)
|
|
174
174
|
// Update the entry to reflect recent use
|
|
175
175
|
this.cache.delete(cacheKey)
|
|
@@ -182,7 +182,7 @@ export default class CachedKeyDeriver {
|
|
|
182
182
|
* @param {string} cacheKey - The key of the item to cache.
|
|
183
183
|
* @param {any} value - The value to cache.
|
|
184
184
|
*/
|
|
185
|
-
private cacheSet(cacheKey: string, value: any): void {
|
|
185
|
+
private cacheSet (cacheKey: string, value: any): void {
|
|
186
186
|
if (this.cache.size >= this.maxCacheSize) {
|
|
187
187
|
// Evict the least recently used item (first item in Map)
|
|
188
188
|
const firstKey = this.cache.keys().next().value
|
package/src/wallet/KeyDeriver.ts
CHANGED
|
@@ -11,7 +11,7 @@ export default class KeyDeriver {
|
|
|
11
11
|
* Initializes the KeyDeriver instance with a root private key.
|
|
12
12
|
* @param {PrivateKey | 'anyone'} rootKey - The root private key or the string 'anyone'.
|
|
13
13
|
*/
|
|
14
|
-
constructor(rootKey: PrivateKey | 'anyone') {
|
|
14
|
+
constructor (rootKey: PrivateKey | 'anyone') {
|
|
15
15
|
if (rootKey === 'anyone') {
|
|
16
16
|
this.rootKey = new PrivateKey(1)
|
|
17
17
|
} else {
|
|
@@ -27,7 +27,7 @@ export default class KeyDeriver {
|
|
|
27
27
|
* @param {boolean} [forSelf=false] - Whether deriving for self.
|
|
28
28
|
* @returns {PublicKey} - The derived public key.
|
|
29
29
|
*/
|
|
30
|
-
derivePublicKey(protocolID: [0 | 1 | 2, string], keyID: string, counterparty: PublicKey | string | 'self' | 'anyone', forSelf: boolean = false): PublicKey {
|
|
30
|
+
derivePublicKey (protocolID: [0 | 1 | 2, string], keyID: string, counterparty: PublicKey | string | 'self' | 'anyone', forSelf: boolean = false): PublicKey {
|
|
31
31
|
counterparty = this.normalizeCounterparty(counterparty)
|
|
32
32
|
if (forSelf) {
|
|
33
33
|
return this.rootKey.deriveChild(counterparty, this.computeInvoiceNumber(protocolID, keyID)).toPublicKey()
|
|
@@ -43,7 +43,7 @@ export default class KeyDeriver {
|
|
|
43
43
|
* @param {PublicKey | string | 'self' | 'anyone'} counterparty - The counterparty's public key or a predefined value ('self' or 'anyone').
|
|
44
44
|
* @returns {PrivateKey} - The derived private key.
|
|
45
45
|
*/
|
|
46
|
-
derivePrivateKey(protocolID: [0 | 1 | 2, string], keyID: string, counterparty: PublicKey | string | 'self' | 'anyone'): PrivateKey {
|
|
46
|
+
derivePrivateKey (protocolID: [0 | 1 | 2, string], keyID: string, counterparty: PublicKey | string | 'self' | 'anyone'): PrivateKey {
|
|
47
47
|
counterparty = this.normalizeCounterparty(counterparty)
|
|
48
48
|
return this.rootKey.deriveChild(counterparty, this.computeInvoiceNumber(protocolID, keyID))
|
|
49
49
|
}
|
|
@@ -57,7 +57,7 @@ export default class KeyDeriver {
|
|
|
57
57
|
* @returns {SymmetricKey} - The derived symmetric key.
|
|
58
58
|
* @throws {Error} - Throws an error if attempting to derive a symmetric key for 'anyone'.
|
|
59
59
|
*/
|
|
60
|
-
deriveSymmetricKey(protocolID: [0 | 1 | 2, string], keyID: string, counterparty: PublicKey | string | 'self' | 'anyone'): SymmetricKey {
|
|
60
|
+
deriveSymmetricKey (protocolID: [0 | 1 | 2, string], keyID: string, counterparty: PublicKey | string | 'self' | 'anyone'): SymmetricKey {
|
|
61
61
|
if (counterparty === 'anyone') {
|
|
62
62
|
throw new Error(
|
|
63
63
|
'Symmetric keys (such as encryption keys or HMAC keys) should not be derivable by everyone, because messages would be decryptable by anyone who knows the identity public key of the user, and HMACs would be similarly forgeable.'
|
|
@@ -76,7 +76,7 @@ export default class KeyDeriver {
|
|
|
76
76
|
* @returns {number[]} - The shared secret as a number array.
|
|
77
77
|
* @throws {Error} - Throws an error if attempting to reveal a shared secret for 'self'.
|
|
78
78
|
*/
|
|
79
|
-
revealCounterpartySecret(counterparty: PublicKey | string | 'self' | 'anyone'): number[] {
|
|
79
|
+
revealCounterpartySecret (counterparty: PublicKey | string | 'self' | 'anyone'): number[] {
|
|
80
80
|
if (counterparty === 'self') {
|
|
81
81
|
throw new Error('Counterparty secrets cannot be revealed for counterparty=self.')
|
|
82
82
|
}
|
|
@@ -101,7 +101,7 @@ export default class KeyDeriver {
|
|
|
101
101
|
* @param {string} keyID - The key identifier.
|
|
102
102
|
* @returns {number[]} - The specific key association as a number array.
|
|
103
103
|
*/
|
|
104
|
-
revealSpecificSecret(counterparty: PublicKey | string | 'self' | 'anyone', protocolID: [0 | 1 | 2, string], keyID: string): number[] {
|
|
104
|
+
revealSpecificSecret (counterparty: PublicKey | string | 'self' | 'anyone', protocolID: [0 | 1 | 2, string], keyID: string): number[] {
|
|
105
105
|
counterparty = this.normalizeCounterparty(counterparty)
|
|
106
106
|
const sharedSecret = this.rootKey.deriveSharedSecret(counterparty)
|
|
107
107
|
const invoiceNumberBin = Utils.toArray(this.computeInvoiceNumber(protocolID, keyID), 'utf8')
|
|
@@ -114,7 +114,7 @@ export default class KeyDeriver {
|
|
|
114
114
|
* @returns {PublicKey} - The normalized counterparty public key.
|
|
115
115
|
* @throws {Error} - Throws an error if the counterparty is invalid.
|
|
116
116
|
*/
|
|
117
|
-
private normalizeCounterparty(counterparty: PublicKey | string | 'self' | 'anyone'): PublicKey {
|
|
117
|
+
private normalizeCounterparty (counterparty: PublicKey | string | 'self' | 'anyone'): PublicKey {
|
|
118
118
|
if (!counterparty) {
|
|
119
119
|
throw new Error('counterparty must be self, anyone or a public key!')
|
|
120
120
|
} else if (counterparty === 'self') {
|
|
@@ -135,7 +135,7 @@ export default class KeyDeriver {
|
|
|
135
135
|
* @returns {string} - The computed invoice number.
|
|
136
136
|
* @throws {Error} - Throws an error if protocol ID or key ID are invalid.
|
|
137
137
|
*/
|
|
138
|
-
private computeInvoiceNumber(protocolID: [0 | 1 | 2, string], keyID: string): string {
|
|
138
|
+
private computeInvoiceNumber (protocolID: [0 | 1 | 2, string], keyID: string): string {
|
|
139
139
|
const securityLevel = protocolID[0]
|
|
140
140
|
if (!Number.isInteger(securityLevel) || securityLevel < 0 || securityLevel > 2) {
|
|
141
141
|
throw new Error('Protocol security level must be 0, 1, or 2')
|