@bsv/sdk 1.6.15 → 1.6.16

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 (54) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js +1 -1
  3. package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
  4. package/dist/cjs/src/primitives/Point.js +123 -6
  5. package/dist/cjs/src/primitives/Point.js.map +1 -1
  6. package/dist/cjs/src/primitives/PrivateKey.js +19 -2
  7. package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
  8. package/dist/cjs/src/primitives/PublicKey.js +19 -2
  9. package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
  10. package/dist/cjs/src/wallet/CachedKeyDeriver.js +12 -1
  11. package/dist/cjs/src/wallet/CachedKeyDeriver.js.map +1 -1
  12. package/dist/cjs/src/wallet/KeyDeriver.js +8 -5
  13. package/dist/cjs/src/wallet/KeyDeriver.js.map +1 -1
  14. package/dist/cjs/src/wallet/ProtoWallet.js +5 -2
  15. package/dist/cjs/src/wallet/ProtoWallet.js.map +1 -1
  16. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  17. package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js +2 -2
  18. package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
  19. package/dist/esm/src/primitives/Point.js +123 -6
  20. package/dist/esm/src/primitives/Point.js.map +1 -1
  21. package/dist/esm/src/primitives/PrivateKey.js +19 -2
  22. package/dist/esm/src/primitives/PrivateKey.js.map +1 -1
  23. package/dist/esm/src/primitives/PublicKey.js +19 -2
  24. package/dist/esm/src/primitives/PublicKey.js.map +1 -1
  25. package/dist/esm/src/wallet/CachedKeyDeriver.js +20 -1
  26. package/dist/esm/src/wallet/CachedKeyDeriver.js.map +1 -1
  27. package/dist/esm/src/wallet/KeyDeriver.js +11 -5
  28. package/dist/esm/src/wallet/KeyDeriver.js.map +1 -1
  29. package/dist/esm/src/wallet/ProtoWallet.js +2 -2
  30. package/dist/esm/src/wallet/ProtoWallet.js.map +1 -1
  31. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  32. package/dist/types/src/auth/certificates/__tests/CompletedProtoWallet.d.ts.map +1 -1
  33. package/dist/types/src/primitives/Point.d.ts.map +1 -1
  34. package/dist/types/src/primitives/PrivateKey.d.ts +3 -1
  35. package/dist/types/src/primitives/PrivateKey.d.ts.map +1 -1
  36. package/dist/types/src/primitives/PublicKey.d.ts +3 -1
  37. package/dist/types/src/primitives/PublicKey.d.ts.map +1 -1
  38. package/dist/types/src/wallet/CachedKeyDeriver.d.ts +10 -2
  39. package/dist/types/src/wallet/CachedKeyDeriver.d.ts.map +1 -1
  40. package/dist/types/src/wallet/KeyDeriver.d.ts +5 -2
  41. package/dist/types/src/wallet/KeyDeriver.d.ts.map +1 -1
  42. package/dist/types/src/wallet/ProtoWallet.d.ts.map +1 -1
  43. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  44. package/dist/umd/bundle.js +1 -1
  45. package/docs/reference/primitives.md +14 -6
  46. package/docs/reference/wallet.md +25 -6
  47. package/package.json +1 -1
  48. package/src/auth/certificates/__tests/CompletedProtoWallet.ts +3 -2
  49. package/src/primitives/Point.ts +152 -5
  50. package/src/primitives/PrivateKey.ts +22 -2
  51. package/src/primitives/PublicKey.ts +22 -2
  52. package/src/wallet/CachedKeyDeriver.ts +32 -8
  53. package/src/wallet/KeyDeriver.ts +22 -6
  54. package/src/wallet/ProtoWallet.ts +3 -2
@@ -2396,7 +2396,7 @@ export default class PrivateKey extends BigNumber {
2396
2396
  toHex(): string
2397
2397
  toString(base: number | "hex" = "hex", padding: number = 64): string
2398
2398
  deriveSharedSecret(key: PublicKey): Point
2399
- deriveChild(publicKey: PublicKey, invoiceNumber: string): PrivateKey
2399
+ deriveChild(publicKey: PublicKey, invoiceNumber: string, cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void), retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined))): PrivateKey
2400
2400
  toKeyShares(threshold: number, totalShares: number): KeyShares
2401
2401
  toBackupShares(threshold: number, totalShares: number): string[]
2402
2402
  static fromBackupShares(shares: string[]): PrivateKey
@@ -2453,9 +2453,9 @@ Returns
2453
2453
  Derives a child key with BRC-42.
2454
2454
 
2455
2455
  ```ts
2456
- deriveChild(publicKey: PublicKey, invoiceNumber: string): PrivateKey
2456
+ deriveChild(publicKey: PublicKey, invoiceNumber: string, cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void), retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined))): PrivateKey
2457
2457
  ```
2458
- See also: [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey)
2458
+ See also: [Point](./primitives.md#class-point), [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey)
2459
2459
 
2460
2460
  Returns
2461
2461
 
@@ -2467,6 +2467,10 @@ Argument Details
2467
2467
  + The public key of the other party
2468
2468
  + **invoiceNumber**
2469
2469
  + The invoice number used to derive the child key
2470
+ + **cacheSharedSecret**
2471
+ + Optional function to cache shared secrets
2472
+ + **retrieveCachedSharedSecret**
2473
+ + Optional function to retrieve shared secrets from the cache
2470
2474
 
2471
2475
  #### Method deriveSharedSecret
2472
2476
 
@@ -2885,7 +2889,7 @@ export default class PublicKey extends Point {
2885
2889
  toDER(enc?: "hex" | undefined): number[] | string
2886
2890
  toHash(enc?: "hex"): number[] | string
2887
2891
  toAddress(prefix: number[] | string = [0]): string
2888
- deriveChild(privateKey: PrivateKey, invoiceNumber: string): PublicKey
2892
+ deriveChild(privateKey: PrivateKey, invoiceNumber: string, cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void), retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined))): PublicKey
2889
2893
  static fromMsgHashAndCompactSignature(msgHash: BigNumber, signature: number[] | string, enc?: "hex" | "base64"): PublicKey
2890
2894
  }
2891
2895
  ```
@@ -2920,9 +2924,9 @@ new PublicKey('abc123', 'def456');
2920
2924
  Derives a child key with BRC-42.
2921
2925
 
2922
2926
  ```ts
2923
- deriveChild(privateKey: PrivateKey, invoiceNumber: string): PublicKey
2927
+ deriveChild(privateKey: PrivateKey, invoiceNumber: string, cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void), retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined))): PublicKey
2924
2928
  ```
2925
- See also: [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey)
2929
+ See also: [Point](./primitives.md#class-point), [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey)
2926
2930
 
2927
2931
  Returns
2928
2932
 
@@ -2934,6 +2938,10 @@ Argument Details
2934
2938
  + The private key of the other party
2935
2939
  + **invoiceNumber**
2936
2940
  + The invoice number used to derive the child key
2941
+ + **cacheSharedSecret**
2942
+ + Optional function to cache shared secrets
2943
+ + **retrieveCachedSharedSecret**
2944
+ + Optional function to retrieve shared secrets from the cache
2937
2945
 
2938
2946
  #### Method deriveSharedSecret
2939
2947
 
@@ -1549,7 +1549,9 @@ This is useful for optimizing performance when the same keys are derived multipl
1549
1549
  It supports configurable cache size with sane defaults and maintains cache entries using LRU (Least Recently Used) eviction policy.
1550
1550
 
1551
1551
  ```ts
1552
- export default class CachedKeyDeriver {
1552
+ export default class CachedKeyDeriver implements KeyDeriverApi {
1553
+ rootKey: PrivateKey;
1554
+ identityKey: string;
1553
1555
  constructor(rootKey: PrivateKey | "anyone", options?: {
1554
1556
  maxCacheSize?: number;
1555
1557
  })
@@ -1561,7 +1563,7 @@ export default class CachedKeyDeriver {
1561
1563
  }
1562
1564
  ```
1563
1565
 
1564
- See also: [Counterparty](./wallet.md#type-counterparty), [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey), [SymmetricKey](./primitives.md#class-symmetrickey), [WalletProtocol](./wallet.md#type-walletprotocol)
1566
+ See also: [Counterparty](./wallet.md#type-counterparty), [KeyDeriverApi](./wallet.md#interface-keyderiverapi), [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey), [SymmetricKey](./primitives.md#class-symmetrickey), [WalletProtocol](./wallet.md#type-walletprotocol)
1565
1567
 
1566
1568
  #### Constructor
1567
1569
 
@@ -1581,6 +1583,23 @@ Argument Details
1581
1583
  + **options**
1582
1584
  + Optional settings for the cache.
1583
1585
 
1586
+ #### Property identityKey
1587
+
1588
+ The identity of this key deriver which is normally the public key associated with the `rootKey`
1589
+
1590
+ ```ts
1591
+ identityKey: string
1592
+ ```
1593
+
1594
+ #### Property rootKey
1595
+
1596
+ The root key from which all other keys are derived.
1597
+
1598
+ ```ts
1599
+ rootKey: PrivateKey
1600
+ ```
1601
+ See also: [PrivateKey](./primitives.md#class-privatekey)
1602
+
1584
1603
  #### Method derivePrivateKey
1585
1604
 
1586
1605
  Derives a private key based on protocol ID, key ID, and counterparty.
@@ -1955,7 +1974,7 @@ It supports deriving public and private keys, symmetric keys, and revealing key
1955
1974
  export class KeyDeriver implements KeyDeriverApi {
1956
1975
  rootKey: PrivateKey;
1957
1976
  identityKey: string;
1958
- constructor(rootKey: PrivateKey | "anyone")
1977
+ constructor(rootKey: PrivateKey | "anyone", private readonly cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void), private readonly retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined)))
1959
1978
  derivePublicKey(protocolID: WalletProtocol, keyID: string, counterparty: Counterparty, forSelf: boolean = false): PublicKey
1960
1979
  derivePrivateKey(protocolID: WalletProtocol, keyID: string, counterparty: Counterparty): PrivateKey
1961
1980
  deriveSymmetricKey(protocolID: WalletProtocol, keyID: string, counterparty: Counterparty): SymmetricKey
@@ -1964,16 +1983,16 @@ export class KeyDeriver implements KeyDeriverApi {
1964
1983
  }
1965
1984
  ```
1966
1985
 
1967
- See also: [Counterparty](./wallet.md#type-counterparty), [KeyDeriverApi](./wallet.md#interface-keyderiverapi), [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey), [SymmetricKey](./primitives.md#class-symmetrickey), [WalletProtocol](./wallet.md#type-walletprotocol)
1986
+ See also: [Counterparty](./wallet.md#type-counterparty), [KeyDeriverApi](./wallet.md#interface-keyderiverapi), [Point](./primitives.md#class-point), [PrivateKey](./primitives.md#class-privatekey), [PublicKey](./primitives.md#class-publickey), [SymmetricKey](./primitives.md#class-symmetrickey), [WalletProtocol](./wallet.md#type-walletprotocol)
1968
1987
 
1969
1988
  #### Constructor
1970
1989
 
1971
1990
  Initializes the KeyDeriver instance with a root private key.
1972
1991
 
1973
1992
  ```ts
1974
- constructor(rootKey: PrivateKey | "anyone")
1993
+ constructor(rootKey: PrivateKey | "anyone", private readonly cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void), private readonly retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined)))
1975
1994
  ```
1976
- See also: [PrivateKey](./primitives.md#class-privatekey)
1995
+ See also: [Point](./primitives.md#class-point), [PrivateKey](./primitives.md#class-privatekey)
1977
1996
 
1978
1997
  Argument Details
1979
1998
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "1.6.15",
3
+ "version": "1.6.16",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -23,7 +23,8 @@ import {
23
23
  PubKeyHex,
24
24
  AuthenticatedResult,
25
25
  GetNetworkResult,
26
- GetVersionResult
26
+ GetVersionResult,
27
+ CachedKeyDeriver
27
28
  } from '../../../wallet/index.js'
28
29
 
29
30
  // Test Mock wallet which extends ProtoWallet but still implements Wallet interface
@@ -41,7 +42,7 @@ export class CompletedProtoWallet
41
42
  typeof rootKeyOrKeyDeriver === 'string' ||
42
43
  rootKeyOrKeyDeriver instanceof PrivateKey
43
44
  ) {
44
- this.keyDeriver = new KeyDeriver(rootKeyOrKeyDeriver)
45
+ this.keyDeriver = new CachedKeyDeriver(rootKeyOrKeyDeriver)
45
46
  } else {
46
47
  throw new Error('Invalid key deriver provided')
47
48
  }
@@ -576,12 +576,159 @@ export default class Point extends BasePoint {
576
576
  k = new BigNumber(k as number, 16)
577
577
  }
578
578
  k = k as BigNumber
579
- if (this.isInfinity()) {
580
- return this
581
- } else if (this._hasDoubles(k)) {
582
- return this._fixedNafMul(k)
579
+ if (typeof BigInt === 'function') {
580
+ if (this.inf) {
581
+ return this
582
+ }
583
+
584
+ const zero = BigInt(0)
585
+ const one = BigInt(1)
586
+ const two = BigInt(2)
587
+ const three = BigInt(3)
588
+ const four = BigInt(4)
589
+ const eight = BigInt(8)
590
+
591
+ const p = BigInt(
592
+ '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'
593
+ )
594
+ const n = BigInt(
595
+ '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'
596
+ )
597
+
598
+ let kBig = BigInt('0x' + k.toString(16))
599
+ const isNeg = kBig < zero
600
+ if (isNeg) kBig = -kBig
601
+ kBig = ((kBig % n) + n) % n
602
+ if (kBig === zero) {
603
+ return new Point(null, null)
604
+ }
605
+
606
+ if (this.x === null || this.y === null) {
607
+ throw new Error('Point coordinates cannot be null')
608
+ }
609
+
610
+ const Px = BigInt('0x' + this.x.fromRed().toString(16))
611
+ const Py = BigInt('0x' + this.y.fromRed().toString(16))
612
+
613
+ const mod = (a: bigint, m: bigint): bigint => ((a % m) + m) % m
614
+ const modMul = (a: bigint, b: bigint, m: bigint): bigint => mod(a * b, m)
615
+ const modSub = (a: bigint, b: bigint, m: bigint): bigint => mod(a - b, m)
616
+ const modInv = (a: bigint, m: bigint): bigint => {
617
+ let lm = one
618
+ let hm = zero
619
+ let low = mod(a, m)
620
+ let high = m
621
+ while (low > one) {
622
+ const r = high / low
623
+ const nm = hm - lm * r
624
+ const neww = high - low * r
625
+ hm = lm
626
+ lm = nm
627
+ high = low
628
+ low = neww
629
+ }
630
+ return mod(lm, m)
631
+ }
632
+
633
+ interface JacobianPoint {
634
+ X: bigint
635
+ Y: bigint
636
+ Z: bigint
637
+ }
638
+
639
+ const pointDouble = (P: JacobianPoint): JacobianPoint => {
640
+ const { X: X1, Y: Y1, Z: Z1 } = P
641
+ if (Y1 === zero) {
642
+ return { X: zero, Y: one, Z: zero }
643
+ }
644
+
645
+ const Y1sq = modMul(Y1, Y1, p)
646
+ const S = modMul(four, modMul(X1, Y1sq, p), p)
647
+ const M = modMul(three, modMul(X1, X1, p), p)
648
+ const X3 = modSub(modMul(M, M, p), modMul(two, S, p), p)
649
+ const Y3 = modSub(
650
+ modMul(M, modSub(S, X3, p), p),
651
+ modMul(eight, modMul(Y1sq, Y1sq, p), p),
652
+ p
653
+ )
654
+ const Z3 = modMul(two, modMul(Y1, Z1, p), p)
655
+ return { X: X3, Y: Y3, Z: Z3 }
656
+ }
657
+
658
+ const pointAdd = (P: JacobianPoint, Q: JacobianPoint): JacobianPoint => {
659
+ if (P.Z === zero) return Q
660
+ if (Q.Z === zero) return P
661
+
662
+ const Z1Z1 = modMul(P.Z, P.Z, p)
663
+ const Z2Z2 = modMul(Q.Z, Q.Z, p)
664
+ const U1 = modMul(P.X, Z2Z2, p)
665
+ const U2 = modMul(Q.X, Z1Z1, p)
666
+ const S1 = modMul(P.Y, modMul(Z2Z2, Q.Z, p), p)
667
+ const S2 = modMul(Q.Y, modMul(Z1Z1, P.Z, p), p)
668
+
669
+ const H = modSub(U2, U1, p)
670
+ const r = modSub(S2, S1, p)
671
+
672
+ if (H === zero) {
673
+ if (r === zero) {
674
+ return pointDouble(P)
675
+ } else {
676
+ return { X: zero, Y: one, Z: zero }
677
+ }
678
+ }
679
+
680
+ const HH = modMul(H, H, p)
681
+ const HHH = modMul(H, HH, p)
682
+ const V = modMul(U1, HH, p)
683
+
684
+ const X3 = modSub(modSub(modMul(r, r, p), HHH, p), modMul(two, V, p), p)
685
+ const Y3 = modSub(modMul(r, modSub(V, X3, p), p), modMul(S1, HHH, p), p)
686
+ const Z3 = modMul(H, modMul(P.Z, Q.Z, p), p)
687
+
688
+ return { X: X3, Y: Y3, Z: Z3 }
689
+ }
690
+
691
+ const scalarMultiply = (
692
+ kVal: bigint,
693
+ P0: { x: bigint, y: bigint }
694
+ ): JacobianPoint => {
695
+ let N: JacobianPoint = { X: P0.x, Y: P0.y, Z: one }
696
+ let Q: JacobianPoint = { X: zero, Y: one, Z: zero }
697
+ let kk = kVal
698
+ while (kk > zero) {
699
+ if ((kk & one) === one) {
700
+ Q = pointAdd(Q, N)
701
+ }
702
+ N = pointDouble(N)
703
+ kk >>= one
704
+ }
705
+ return Q
706
+ }
707
+
708
+ const R = scalarMultiply(kBig, { x: Px, y: Py })
709
+ if (R.Z === zero) {
710
+ return new Point(null, null)
711
+ }
712
+ const zInv = modInv(R.Z, p)
713
+ const zInv2 = modMul(zInv, zInv, p)
714
+ const xRes = modMul(R.X, zInv2, p)
715
+ const yRes = modMul(R.Y, modMul(zInv2, zInv, p), p)
716
+
717
+ const xBN = new BigNumber(xRes.toString(16), 16)
718
+ const yBN = new BigNumber(yRes.toString(16), 16)
719
+ const result = new Point(xBN, yBN)
720
+ if (isNeg) {
721
+ return result.neg()
722
+ }
723
+ return result
583
724
  } else {
584
- return this._endoWnafMulAdd([this], [k]) as Point
725
+ if (this.isInfinity()) {
726
+ return this
727
+ } else if (this._hasDoubles(k)) {
728
+ return this._fixedNafMul(k)
729
+ } else {
730
+ return this._endoWnafMulAdd([this], [k]) as Point
731
+ }
585
732
  }
586
733
  }
587
734
 
@@ -359,10 +359,30 @@ export default class PrivateKey extends BigNumber {
359
359
  * Derives a child key with BRC-42.
360
360
  * @param publicKey The public key of the other party
361
361
  * @param invoiceNumber The invoice number used to derive the child key
362
+ * @param cacheSharedSecret Optional function to cache shared secrets
363
+ * @param retrieveCachedSharedSecret Optional function to retrieve shared secrets from the cache
362
364
  * @returns The derived child key.
363
365
  */
364
- deriveChild (publicKey: PublicKey, invoiceNumber: string): PrivateKey {
365
- const sharedSecret = this.deriveSharedSecret(publicKey)
366
+ deriveChild (
367
+ publicKey: PublicKey,
368
+ invoiceNumber: string,
369
+ cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void),
370
+ retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined))
371
+ ): PrivateKey {
372
+ let sharedSecret: Point
373
+ if (typeof retrieveCachedSharedSecret === 'function') {
374
+ const retrieved = retrieveCachedSharedSecret(this, publicKey)
375
+ if (typeof retrieved !== 'undefined') {
376
+ sharedSecret = retrieved
377
+ } else {
378
+ sharedSecret = this.deriveSharedSecret(publicKey)
379
+ if (typeof cacheSharedSecret === 'function') {
380
+ cacheSharedSecret(this, publicKey, sharedSecret)
381
+ }
382
+ }
383
+ } else {
384
+ sharedSecret = this.deriveSharedSecret(publicKey)
385
+ }
366
386
  const invoiceNumberBin = toArray(invoiceNumber, 'utf8')
367
387
  const hmac = sha256hmac(sharedSecret.encode(true), invoiceNumberBin)
368
388
  const curve = new Curve()
@@ -202,10 +202,30 @@ export default class PublicKey extends Point {
202
202
  * Derives a child key with BRC-42.
203
203
  * @param privateKey The private key of the other party
204
204
  * @param invoiceNumber The invoice number used to derive the child key
205
+ * @param cacheSharedSecret Optional function to cache shared secrets
206
+ * @param retrieveCachedSharedSecret Optional function to retrieve shared secrets from the cache
205
207
  * @returns The derived child key.
206
208
  */
207
- deriveChild (privateKey: PrivateKey, invoiceNumber: string): PublicKey {
208
- const sharedSecret = this.deriveSharedSecret(privateKey)
209
+ deriveChild (
210
+ privateKey: PrivateKey,
211
+ invoiceNumber: string,
212
+ cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void),
213
+ retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined))
214
+ ): PublicKey {
215
+ let sharedSecret: Point
216
+ if (typeof retrieveCachedSharedSecret === 'function') {
217
+ const retrieved = retrieveCachedSharedSecret(privateKey, this)
218
+ if (typeof retrieved !== 'undefined') {
219
+ sharedSecret = retrieved
220
+ } else {
221
+ sharedSecret = this.deriveSharedSecret(privateKey)
222
+ if (typeof cacheSharedSecret === 'function') {
223
+ cacheSharedSecret(privateKey, this, sharedSecret)
224
+ }
225
+ }
226
+ } else {
227
+ sharedSecret = this.deriveSharedSecret(privateKey)
228
+ }
209
229
  const invoiceNumberBin = toArray(invoiceNumber, 'utf8')
210
230
  const hmac = sha256hmac(sharedSecret.encode(true), invoiceNumberBin)
211
231
  const curve = new Curve()
@@ -1,5 +1,5 @@
1
- import { PrivateKey, PublicKey, SymmetricKey } from '../primitives/index.js'
2
- import { Counterparty, KeyDeriver } from './KeyDeriver.js'
1
+ import { Point, PrivateKey, PublicKey, SymmetricKey } from '../primitives/index.js'
2
+ import { Counterparty, KeyDeriver, KeyDeriverApi } from './KeyDeriver.js'
3
3
  import { WalletProtocol } from './Wallet.interfaces.js'
4
4
 
5
5
  /**
@@ -7,11 +7,21 @@ import { WalletProtocol } from './Wallet.interfaces.js'
7
7
  * This is useful for optimizing performance when the same keys are derived multiple times.
8
8
  * It supports configurable cache size with sane defaults and maintains cache entries using LRU (Least Recently Used) eviction policy.
9
9
  */
10
- export default class CachedKeyDeriver {
10
+ export default class CachedKeyDeriver implements KeyDeriverApi {
11
11
  private readonly keyDeriver: KeyDeriver
12
- private readonly cache: Map<string, PublicKey | PrivateKey | SymmetricKey | number[]>
12
+ private readonly cache: Map<string, PublicKey | PrivateKey | SymmetricKey | Point | number[]>
13
13
  private readonly maxCacheSize: number
14
14
 
15
+ /**
16
+ * The root key from which all other keys are derived.
17
+ */
18
+ rootKey: PrivateKey
19
+
20
+ /**
21
+ * The identity of this key deriver which is normally the public key associated with the `rootKey`
22
+ */
23
+ identityKey: string
24
+
15
25
  /**
16
26
  * Initializes the CachedKeyDeriver instance with a root private key and optional cache settings.
17
27
  * @param {PrivateKey | 'anyone'} rootKey - The root private key or the string 'anyone'.
@@ -22,8 +32,22 @@ export default class CachedKeyDeriver {
22
32
  rootKey: PrivateKey | 'anyone',
23
33
  options?: { maxCacheSize?: number }
24
34
  ) {
25
- this.keyDeriver = new KeyDeriver(rootKey)
26
- this.cache = new Map<string, PublicKey | PrivateKey | SymmetricKey | number[]>()
35
+ if (rootKey === 'anyone') {
36
+ this.rootKey = new PrivateKey(1)
37
+ } else {
38
+ this.rootKey = rootKey
39
+ }
40
+ this.keyDeriver = new KeyDeriver(
41
+ this.rootKey,
42
+ (priv, pub, point) => {
43
+ this.cacheSet(`${priv.toString()}-${pub.toString()}`, point)
44
+ },
45
+ (priv, pub) => {
46
+ return this.cacheGet(`${priv.toString()}-${pub.toString()}`) as Point | undefined
47
+ }
48
+ )
49
+ this.identityKey = this.rootKey.toPublicKey().toString()
50
+ this.cache = new Map<string, PublicKey | PrivateKey | SymmetricKey | Point | number[]>()
27
51
  const maxCacheSize = options?.maxCacheSize
28
52
  this.maxCacheSize = (maxCacheSize != null && !isNaN(maxCacheSize) && maxCacheSize > 0) ? maxCacheSize : 1000
29
53
  }
@@ -237,7 +261,7 @@ export default class CachedKeyDeriver {
237
261
  * @param {string} cacheKey - The key of the cached item.
238
262
  * @returns {any} - The cached value.
239
263
  */
240
- private cacheGet (cacheKey: string): PublicKey | PrivateKey | SymmetricKey | number[] | undefined {
264
+ private cacheGet (cacheKey: string): PublicKey | PrivateKey | SymmetricKey | Point | number[] | undefined {
241
265
  const value = this.cache.get(cacheKey)
242
266
  // Update the entry to reflect recent use
243
267
  this.cache.delete(cacheKey)
@@ -252,7 +276,7 @@ export default class CachedKeyDeriver {
252
276
  * @param {string} cacheKey - The key of the item to cache.
253
277
  * @param {any} value - The value to cache.
254
278
  */
255
- private cacheSet (cacheKey: string, value: PublicKey | PrivateKey | SymmetricKey | number[]): void {
279
+ private cacheSet (cacheKey: string, value: PublicKey | PrivateKey | SymmetricKey | Point | number[]): void {
256
280
  if (this.cache.size >= this.maxCacheSize) {
257
281
  // Evict the least recently used item (first item in Map)
258
282
  const firstKey = this.cache.keys().next().value
@@ -3,7 +3,8 @@ import {
3
3
  PublicKey,
4
4
  SymmetricKey,
5
5
  Hash,
6
- Utils
6
+ Utils,
7
+ Point
7
8
  } from '../primitives/index.js'
8
9
  import { WalletProtocol, PubKeyHex } from './Wallet.interfaces.js'
9
10
 
@@ -92,12 +93,18 @@ export interface KeyDeriverApi {
92
93
  export class KeyDeriver implements KeyDeriverApi {
93
94
  rootKey: PrivateKey
94
95
  identityKey: string
96
+ private readonly anyone: PublicKey
95
97
 
96
98
  /**
97
99
  * Initializes the KeyDeriver instance with a root private key.
98
100
  * @param {PrivateKey | 'anyone'} rootKey - The root private key or the string 'anyone'.
99
101
  */
100
- constructor (rootKey: PrivateKey | 'anyone') {
102
+ constructor (
103
+ rootKey: PrivateKey | 'anyone',
104
+ private readonly cacheSharedSecret?: ((priv: PrivateKey, pub: Point, point: Point) => void),
105
+ private readonly retrieveCachedSharedSecret?: ((priv: PrivateKey, pub: Point) => (Point | undefined))
106
+ ) {
107
+ this.anyone = new PrivateKey(1).toPublicKey()
101
108
  if (rootKey === 'anyone') {
102
109
  this.rootKey = new PrivateKey(1)
103
110
  } else {
@@ -123,12 +130,19 @@ export class KeyDeriver implements KeyDeriverApi {
123
130
  counterparty = this.normalizeCounterparty(counterparty)
124
131
  if (forSelf) {
125
132
  return this.rootKey
126
- .deriveChild(counterparty, this.computeInvoiceNumber(protocolID, keyID))
133
+ .deriveChild(
134
+ counterparty,
135
+ this.computeInvoiceNumber(protocolID, keyID),
136
+ this.cacheSharedSecret,
137
+ this.retrieveCachedSharedSecret
138
+ )
127
139
  .toPublicKey()
128
140
  } else {
129
141
  return counterparty.deriveChild(
130
142
  this.rootKey,
131
- this.computeInvoiceNumber(protocolID, keyID)
143
+ this.computeInvoiceNumber(protocolID, keyID),
144
+ this.cacheSharedSecret,
145
+ this.retrieveCachedSharedSecret
132
146
  )
133
147
  }
134
148
  }
@@ -148,7 +162,9 @@ export class KeyDeriver implements KeyDeriverApi {
148
162
  counterparty = this.normalizeCounterparty(counterparty)
149
163
  return this.rootKey.deriveChild(
150
164
  counterparty,
151
- this.computeInvoiceNumber(protocolID, keyID)
165
+ this.computeInvoiceNumber(protocolID, keyID),
166
+ this.cacheSharedSecret,
167
+ this.retrieveCachedSharedSecret
152
168
  )
153
169
  }
154
170
 
@@ -168,7 +184,7 @@ export class KeyDeriver implements KeyDeriverApi {
168
184
  // If counterparty is 'anyone', we use 1*G as the public key.
169
185
  // This is a publicly derivable key and should only be used in scenarios where public disclosure is intended.
170
186
  if (counterparty === 'anyone') {
171
- counterparty = new PrivateKey(1).toPublicKey()
187
+ counterparty = this.anyone
172
188
  }
173
189
  counterparty = this.normalizeCounterparty(counterparty)
174
190
  const derivedPublicKey = this.derivePublicKey(
@@ -1,4 +1,5 @@
1
1
  import { KeyDeriver, KeyDeriverApi } from './KeyDeriver.js'
2
+ import CachedKeyDeriver from './CachedKeyDeriver.js'
2
3
  import {
3
4
  Hash,
4
5
  ECDSA,
@@ -42,11 +43,11 @@ export class ProtoWallet {
42
43
 
43
44
  constructor (rootKeyOrKeyDeriver?: PrivateKey | 'anyone' | KeyDeriverApi) {
44
45
  if (typeof (rootKeyOrKeyDeriver as KeyDeriver).identityKey !== 'string') {
45
- rootKeyOrKeyDeriver = new KeyDeriver(
46
+ rootKeyOrKeyDeriver = new CachedKeyDeriver(
46
47
  rootKeyOrKeyDeriver as PrivateKey | 'anyone'
47
48
  )
48
49
  }
49
- this.keyDeriver = rootKeyOrKeyDeriver as KeyDeriver
50
+ this.keyDeriver = rootKeyOrKeyDeriver as KeyDeriverApi
50
51
  }
51
52
 
52
53
  async getPublicKey (