@bsv/sdk 2.1.1 → 2.1.2
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/identity/ContactsManager.js +44 -6
- package/dist/cjs/src/identity/ContactsManager.js.map +1 -1
- package/dist/cjs/src/identity/IdentityClient.js +106 -37
- package/dist/cjs/src/identity/IdentityClient.js.map +1 -1
- package/dist/cjs/src/overlay-tools/LookupResolver.js +85 -58
- package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/cjs/src/primitives/Hash.js +173 -50
- package/dist/cjs/src/primitives/Hash.js.map +1 -1
- package/dist/cjs/src/primitives/SymmetricKey.js +123 -1
- package/dist/cjs/src/primitives/SymmetricKey.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/identity/ContactsManager.js +44 -6
- package/dist/esm/src/identity/ContactsManager.js.map +1 -1
- package/dist/esm/src/identity/IdentityClient.js +106 -37
- package/dist/esm/src/identity/IdentityClient.js.map +1 -1
- package/dist/esm/src/overlay-tools/LookupResolver.js +85 -58
- package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/esm/src/primitives/Hash.js +177 -50
- package/dist/esm/src/primitives/Hash.js.map +1 -1
- package/dist/esm/src/primitives/SymmetricKey.js +123 -1
- package/dist/esm/src/primitives/SymmetricKey.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/identity/ContactsManager.d.ts +13 -2
- package/dist/types/src/identity/ContactsManager.d.ts.map +1 -1
- package/dist/types/src/identity/IdentityClient.d.ts +50 -24
- package/dist/types/src/identity/IdentityClient.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts +14 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -1
- package/dist/types/src/primitives/Hash.d.ts +21 -16
- package/dist/types/src/primitives/Hash.d.ts.map +1 -1
- package/dist/types/src/primitives/SymmetricKey.d.ts.map +1 -1
- package/dist/types/src/wallet/Wallet.interfaces.d.ts +16 -1
- package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -1
- package/dist/types/src/wallet/WalletClient.d.ts +1 -1
- package/dist/types/src/wallet/WalletClient.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/window.CWI.d.ts +1 -1
- package/dist/types/src/wallet/substrates/window.CWI.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +3 -3
- package/package.json +1 -1
- package/src/identity/ContactsManager.ts +47 -6
- package/src/identity/IdentityClient.ts +137 -53
- package/src/identity/__tests/IdentityClient.additional.test.ts +150 -1
- package/src/identity/__tests/IdentityClient.test.ts +4 -4
- package/src/overlay-tools/LookupResolver.ts +94 -57
- package/src/primitives/Hash.ts +232 -96
- package/src/primitives/SymmetricKey.ts +145 -1
- package/src/primitives/__tests/Hash.additional.test.ts +65 -0
- package/src/primitives/__tests/Hash.test.ts +6 -1
- package/src/wallet/Wallet.interfaces.ts +16 -1
- package/src/wallet/WalletClient.ts +1 -1
- package/src/wallet/substrates/window.CWI.ts +1 -1
package/src/primitives/Hash.ts
CHANGED
|
@@ -349,10 +349,141 @@ function zero8 (word: string): string {
|
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
const BufferCtor =
|
|
353
|
+
typeof globalThis === 'undefined' ? undefined : (globalThis as any).Buffer
|
|
354
|
+
const CAN_USE_BUFFER =
|
|
355
|
+
BufferCtor != null && typeof BufferCtor.from === 'function'
|
|
356
|
+
const HEX_DIGITS = '0123456789abcdef'
|
|
357
|
+
const HEX_BYTE_STRINGS = new Array<string>(256)
|
|
358
|
+
for (let i = 0; i < HEX_BYTE_STRINGS.length; i++) {
|
|
359
|
+
HEX_BYTE_STRINGS[i] = HEX_DIGITS[(i >> 4) & 0xf] + HEX_DIGITS[i & 0xf]
|
|
360
|
+
}
|
|
361
|
+
|
|
352
362
|
function bytesToHex (data: Uint8Array): string {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
363
|
+
if (CAN_USE_BUFFER) {
|
|
364
|
+
return BufferCtor.from(data).toString('hex')
|
|
365
|
+
}
|
|
366
|
+
const out = new Array<string>(data.length)
|
|
367
|
+
for (let i = 0; i < data.length; i++) out[i] = HEX_BYTE_STRINGS[data[i]]
|
|
368
|
+
return out.join('')
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const NODE_CRYPTO = (() => {
|
|
372
|
+
const processLike =
|
|
373
|
+
typeof globalThis === 'undefined' ? undefined : (globalThis as any).process
|
|
374
|
+
const getBuiltinModule = processLike?.getBuiltinModule
|
|
375
|
+
if (typeof getBuiltinModule === 'function') {
|
|
376
|
+
try {
|
|
377
|
+
const crypto = getBuiltinModule.call(processLike, 'node:crypto')
|
|
378
|
+
if (crypto != null) return crypto
|
|
379
|
+
} catch {
|
|
380
|
+
// continue to CommonJS fallback
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
if (typeof require === 'function') {
|
|
386
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
387
|
+
return require('node:crypto')
|
|
388
|
+
}
|
|
389
|
+
} catch {
|
|
390
|
+
// node:crypto is unavailable in this runtime
|
|
391
|
+
}
|
|
392
|
+
return undefined
|
|
393
|
+
})()
|
|
394
|
+
|
|
395
|
+
type HashInput = Uint8Array | number[] | string
|
|
396
|
+
|
|
397
|
+
function toHashBytes (msg: HashInput, enc?: 'hex' | 'utf8'): Uint8Array {
|
|
398
|
+
if (msg instanceof Uint8Array) {
|
|
399
|
+
return msg
|
|
400
|
+
}
|
|
401
|
+
if (Array.isArray(msg)) {
|
|
402
|
+
return new Uint8Array(msg)
|
|
403
|
+
}
|
|
404
|
+
return Uint8Array.from(toArray(msg, enc))
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function toHashKeyBytes (key: HashInput): Uint8Array {
|
|
408
|
+
return typeof key === 'string' ? toHashBytes(key, 'hex') : toHashBytes(key)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
interface FallbackHashLike {
|
|
412
|
+
update: (data: Uint8Array) => unknown
|
|
413
|
+
digest: () => Uint8Array
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function updateNativeOrFallback (
|
|
417
|
+
native: any,
|
|
418
|
+
fallback: FallbackHashLike | undefined,
|
|
419
|
+
data: Uint8Array
|
|
420
|
+
): void {
|
|
421
|
+
if (native != null) {
|
|
422
|
+
native.update(data)
|
|
423
|
+
} else if (fallback != null) {
|
|
424
|
+
fallback.update(data)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function digestNativeOrFallback (
|
|
429
|
+
native: any,
|
|
430
|
+
fallback: FallbackHashLike | undefined
|
|
431
|
+
): number[] {
|
|
432
|
+
if (native != null) return Array.from(native.digest())
|
|
433
|
+
if (fallback != null) return Array.from(fallback.digest())
|
|
434
|
+
return []
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function digestHexNativeOrFallback (
|
|
438
|
+
native: any,
|
|
439
|
+
fallback: FallbackHashLike | undefined
|
|
440
|
+
): string {
|
|
441
|
+
if (native != null) return native.digest('hex')
|
|
442
|
+
if (fallback != null) return bytesToHex(fallback.digest())
|
|
443
|
+
return ''
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function createNodeHash (algorithm: string): any {
|
|
447
|
+
const createHash = NODE_CRYPTO?.createHash
|
|
448
|
+
if (typeof createHash !== 'function') return undefined
|
|
449
|
+
try {
|
|
450
|
+
return createHash(algorithm)
|
|
451
|
+
} catch {
|
|
452
|
+
return undefined
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function createNodeHmac (algorithm: string, keyBytes: Uint8Array): any {
|
|
457
|
+
const createHmac = NODE_CRYPTO?.createHmac
|
|
458
|
+
if (typeof createHmac !== 'function') return undefined
|
|
459
|
+
try {
|
|
460
|
+
return createHmac(algorithm, keyBytes)
|
|
461
|
+
} catch {
|
|
462
|
+
return undefined
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function digestWithNodeHash (
|
|
467
|
+
algorithm: string,
|
|
468
|
+
msg: HashInput,
|
|
469
|
+
enc?: 'hex' | 'utf8'
|
|
470
|
+
): Uint8Array | undefined {
|
|
471
|
+
const hash = createNodeHash(algorithm)
|
|
472
|
+
if (hash == null) return undefined
|
|
473
|
+
hash.update(toHashBytes(msg, enc))
|
|
474
|
+
return hash.digest()
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function digestWithNodeHmac (
|
|
478
|
+
algorithm: string,
|
|
479
|
+
key: HashInput,
|
|
480
|
+
msg: HashInput,
|
|
481
|
+
enc?: 'hex' | 'utf8'
|
|
482
|
+
): Uint8Array | undefined {
|
|
483
|
+
const hmac = createNodeHmac(algorithm, toHashKeyBytes(key))
|
|
484
|
+
if (hmac == null) return undefined
|
|
485
|
+
hmac.update(toHashBytes(msg, enc))
|
|
486
|
+
return hmac.digest()
|
|
356
487
|
}
|
|
357
488
|
|
|
358
489
|
function join32 (msg, start, end, endian): number[] {
|
|
@@ -631,27 +762,27 @@ export class RIPEMD160 extends BaseHash {
|
|
|
631
762
|
* @property k - The round constants used for each round of SHA-256
|
|
632
763
|
*/
|
|
633
764
|
export class SHA256 {
|
|
634
|
-
private readonly h
|
|
765
|
+
private readonly h?: FastSHA256
|
|
766
|
+
private readonly native?: any
|
|
767
|
+
|
|
635
768
|
constructor () {
|
|
636
|
-
this.
|
|
769
|
+
this.native = createNodeHash('sha256')
|
|
770
|
+
if (this.native == null) {
|
|
771
|
+
this.h = new FastSHA256()
|
|
772
|
+
}
|
|
637
773
|
}
|
|
638
774
|
|
|
639
|
-
update (
|
|
640
|
-
|
|
641
|
-
enc?: 'hex' | 'utf8'
|
|
642
|
-
): this {
|
|
643
|
-
const data =
|
|
644
|
-
msg instanceof Uint8Array ? msg : Uint8Array.from(toArray(msg, enc))
|
|
645
|
-
this.h.update(data)
|
|
775
|
+
update (msg: HashInput, enc?: 'hex' | 'utf8'): this {
|
|
776
|
+
updateNativeOrFallback(this.native, this.h, toHashBytes(msg, enc))
|
|
646
777
|
return this
|
|
647
778
|
}
|
|
648
779
|
|
|
649
780
|
digest (): number[] {
|
|
650
|
-
return
|
|
781
|
+
return digestNativeOrFallback(this.native, this.h)
|
|
651
782
|
}
|
|
652
783
|
|
|
653
784
|
digestHex (): string {
|
|
654
|
-
return
|
|
785
|
+
return digestHexNativeOrFallback(this.native, this.h)
|
|
655
786
|
}
|
|
656
787
|
}
|
|
657
788
|
|
|
@@ -755,23 +886,27 @@ export class SHA1 extends BaseHash {
|
|
|
755
886
|
* @property k - The round constants used for each round of SHA-512.
|
|
756
887
|
*/
|
|
757
888
|
export class SHA512 {
|
|
758
|
-
private readonly h
|
|
889
|
+
private readonly h?: FastSHA512
|
|
890
|
+
private readonly native?: any
|
|
891
|
+
|
|
759
892
|
constructor () {
|
|
760
|
-
this.
|
|
893
|
+
this.native = createNodeHash('sha512')
|
|
894
|
+
if (this.native == null) {
|
|
895
|
+
this.h = new FastSHA512()
|
|
896
|
+
}
|
|
761
897
|
}
|
|
762
898
|
|
|
763
|
-
update (msg:
|
|
764
|
-
|
|
765
|
-
this.h.update(data)
|
|
899
|
+
update (msg: HashInput, enc?: 'hex' | 'utf8'): this {
|
|
900
|
+
updateNativeOrFallback(this.native, this.h, toHashBytes(msg, enc))
|
|
766
901
|
return this
|
|
767
902
|
}
|
|
768
903
|
|
|
769
904
|
digest (): number[] {
|
|
770
|
-
return
|
|
905
|
+
return digestNativeOrFallback(this.native, this.h)
|
|
771
906
|
}
|
|
772
907
|
|
|
773
908
|
digestHex (): string {
|
|
774
|
-
return
|
|
909
|
+
return digestHexNativeOrFallback(this.native, this.h)
|
|
775
910
|
}
|
|
776
911
|
}
|
|
777
912
|
|
|
@@ -788,7 +923,8 @@ export class SHA512 {
|
|
|
788
923
|
* @property outSize - The output size of the SHA-256 hash function, in bytes. It's set to 32 bytes.
|
|
789
924
|
*/
|
|
790
925
|
export class SHA256HMAC {
|
|
791
|
-
private readonly h
|
|
926
|
+
private readonly h?: HMAC<FastSHA256>
|
|
927
|
+
private readonly native?: any
|
|
792
928
|
blockSize = 64
|
|
793
929
|
outSize = 32
|
|
794
930
|
|
|
@@ -805,17 +941,12 @@ export class SHA256HMAC {
|
|
|
805
941
|
* @example
|
|
806
942
|
* const myHMAC = new SHA256HMAC('deadbeef');
|
|
807
943
|
*/
|
|
808
|
-
constructor (key:
|
|
809
|
-
const k =
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
key,
|
|
815
|
-
typeof key === 'string' ? 'hex' : undefined
|
|
816
|
-
)
|
|
817
|
-
)
|
|
818
|
-
this.h = new HMAC(sha256Fast, k)
|
|
944
|
+
constructor (key: HashInput) {
|
|
945
|
+
const k = toHashKeyBytes(key)
|
|
946
|
+
this.native = createNodeHmac('sha256', k)
|
|
947
|
+
if (this.native == null) {
|
|
948
|
+
this.h = new HMAC(sha256Fast, k)
|
|
949
|
+
}
|
|
819
950
|
}
|
|
820
951
|
|
|
821
952
|
/**
|
|
@@ -829,10 +960,8 @@ export class SHA256HMAC {
|
|
|
829
960
|
* @example
|
|
830
961
|
* myHMAC.update('deadbeef', 'hex');
|
|
831
962
|
*/
|
|
832
|
-
update (msg:
|
|
833
|
-
|
|
834
|
-
msg instanceof Uint8Array ? msg : Uint8Array.from(toArray(msg, enc))
|
|
835
|
-
this.h.update(data)
|
|
963
|
+
update (msg: HashInput, enc?: 'hex'): this {
|
|
964
|
+
updateNativeOrFallback(this.native, this.h, toHashBytes(msg, enc))
|
|
836
965
|
return this
|
|
837
966
|
}
|
|
838
967
|
|
|
@@ -846,7 +975,7 @@ export class SHA256HMAC {
|
|
|
846
975
|
* let hashedMessage = myHMAC.digest();
|
|
847
976
|
*/
|
|
848
977
|
digest (): number[] {
|
|
849
|
-
return
|
|
978
|
+
return digestNativeOrFallback(this.native, this.h)
|
|
850
979
|
}
|
|
851
980
|
|
|
852
981
|
/**
|
|
@@ -859,7 +988,7 @@ export class SHA256HMAC {
|
|
|
859
988
|
* let hashedMessage = myHMAC.digestHex();
|
|
860
989
|
*/
|
|
861
990
|
digestHex (): string {
|
|
862
|
-
return
|
|
991
|
+
return digestHexNativeOrFallback(this.native, this.h)
|
|
863
992
|
}
|
|
864
993
|
}
|
|
865
994
|
|
|
@@ -922,7 +1051,8 @@ export class SHA1HMAC {
|
|
|
922
1051
|
* @property outSize - The output size of the SHA-512 hash function, in bytes. It's set to 64 bytes.
|
|
923
1052
|
*/
|
|
924
1053
|
export class SHA512HMAC {
|
|
925
|
-
private readonly h
|
|
1054
|
+
private readonly h?: HMAC<FastSHA512>
|
|
1055
|
+
private readonly native?: any
|
|
926
1056
|
blockSize = 128
|
|
927
1057
|
outSize = 32
|
|
928
1058
|
|
|
@@ -939,17 +1069,12 @@ export class SHA512HMAC {
|
|
|
939
1069
|
* @example
|
|
940
1070
|
* const myHMAC = new SHA512HMAC('deadbeef');
|
|
941
1071
|
*/
|
|
942
|
-
constructor (key:
|
|
943
|
-
const k =
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
key,
|
|
949
|
-
typeof key === 'string' ? 'hex' : undefined
|
|
950
|
-
)
|
|
951
|
-
)
|
|
952
|
-
this.h = new HMAC(sha512Fast, k)
|
|
1072
|
+
constructor (key: HashInput) {
|
|
1073
|
+
const k = toHashKeyBytes(key)
|
|
1074
|
+
this.native = createNodeHmac('sha512', k)
|
|
1075
|
+
if (this.native == null) {
|
|
1076
|
+
this.h = new HMAC(sha512Fast, k)
|
|
1077
|
+
}
|
|
953
1078
|
}
|
|
954
1079
|
|
|
955
1080
|
/**
|
|
@@ -963,10 +1088,8 @@ export class SHA512HMAC {
|
|
|
963
1088
|
* @example
|
|
964
1089
|
* myHMAC.update('deadbeef', 'hex');
|
|
965
1090
|
*/
|
|
966
|
-
update (msg:
|
|
967
|
-
|
|
968
|
-
msg instanceof Uint8Array ? msg : Uint8Array.from(toArray(msg, enc))
|
|
969
|
-
this.h.update(data)
|
|
1091
|
+
update (msg: HashInput, enc?: 'hex' | 'utf8'): this {
|
|
1092
|
+
updateNativeOrFallback(this.native, this.h, toHashBytes(msg, enc))
|
|
970
1093
|
return this
|
|
971
1094
|
}
|
|
972
1095
|
|
|
@@ -980,7 +1103,7 @@ export class SHA512HMAC {
|
|
|
980
1103
|
* let hashedMessage = myHMAC.digest();
|
|
981
1104
|
*/
|
|
982
1105
|
digest (): number[] {
|
|
983
|
-
return
|
|
1106
|
+
return digestNativeOrFallback(this.native, this.h)
|
|
984
1107
|
}
|
|
985
1108
|
|
|
986
1109
|
/**
|
|
@@ -993,10 +1116,32 @@ export class SHA512HMAC {
|
|
|
993
1116
|
* let hashedMessage = myHMAC.digestHex();
|
|
994
1117
|
*/
|
|
995
1118
|
digestHex (): string {
|
|
996
|
-
return
|
|
1119
|
+
return digestHexNativeOrFallback(this.native, this.h)
|
|
997
1120
|
}
|
|
998
1121
|
}
|
|
999
1122
|
|
|
1123
|
+
function sha256Bytes (msg: HashInput, enc?: 'hex' | 'utf8'): Uint8Array {
|
|
1124
|
+
const native = digestWithNodeHash('sha256', msg, enc)
|
|
1125
|
+
if (native != null) return native
|
|
1126
|
+
return new FastSHA256().update(toHashBytes(msg, enc)).digest()
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
function sha512Bytes (
|
|
1130
|
+
msg: HashInput,
|
|
1131
|
+
enc?: 'hex' | 'utf8'
|
|
1132
|
+
): Uint8Array {
|
|
1133
|
+
const native = digestWithNodeHash('sha512', msg, enc)
|
|
1134
|
+
if (native != null) return native
|
|
1135
|
+
return new FastSHA512().update(toHashBytes(msg, enc)).digest()
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
function ripemd160Bytes (
|
|
1139
|
+
msg: HashInput,
|
|
1140
|
+
enc?: 'hex' | 'utf8'
|
|
1141
|
+
): Uint8Array | undefined {
|
|
1142
|
+
return digestWithNodeHash('ripemd160', msg, enc)
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1000
1145
|
/**
|
|
1001
1146
|
* Computes RIPEMD160 hash of a given message.
|
|
1002
1147
|
* @function ripemd160
|
|
@@ -1012,6 +1157,8 @@ export const ripemd160 = (
|
|
|
1012
1157
|
msg: number[] | string,
|
|
1013
1158
|
enc?: 'hex' | 'utf8'
|
|
1014
1159
|
): number[] => {
|
|
1160
|
+
const native = ripemd160Bytes(msg, enc)
|
|
1161
|
+
if (native != null) return Array.from(native)
|
|
1015
1162
|
return new RIPEMD160().update(msg, enc).digest()
|
|
1016
1163
|
}
|
|
1017
1164
|
|
|
@@ -1044,11 +1191,8 @@ export const sha1 = (
|
|
|
1044
1191
|
* @example
|
|
1045
1192
|
* const digest = sha256('Hello, world!');
|
|
1046
1193
|
*/
|
|
1047
|
-
export const sha256 = (
|
|
1048
|
-
msg
|
|
1049
|
-
enc?: 'hex' | 'utf8'
|
|
1050
|
-
): number[] => {
|
|
1051
|
-
return new SHA256().update(msg, enc).digest()
|
|
1194
|
+
export const sha256 = (msg: HashInput, enc?: 'hex' | 'utf8'): number[] => {
|
|
1195
|
+
return Array.from(sha256Bytes(msg, enc))
|
|
1052
1196
|
}
|
|
1053
1197
|
|
|
1054
1198
|
/**
|
|
@@ -1062,11 +1206,8 @@ export const sha256 = (
|
|
|
1062
1206
|
* @example
|
|
1063
1207
|
* const digest = sha512('Hello, world!');
|
|
1064
1208
|
*/
|
|
1065
|
-
export const sha512 = (
|
|
1066
|
-
msg
|
|
1067
|
-
enc?: 'hex' | 'utf8'
|
|
1068
|
-
): number[] => {
|
|
1069
|
-
return new SHA512().update(msg, enc).digest()
|
|
1209
|
+
export const sha512 = (msg: HashInput, enc?: 'hex' | 'utf8'): number[] => {
|
|
1210
|
+
return Array.from(sha512Bytes(msg, enc))
|
|
1070
1211
|
}
|
|
1071
1212
|
|
|
1072
1213
|
/**
|
|
@@ -1082,12 +1223,8 @@ export const sha512 = (
|
|
|
1082
1223
|
* @example
|
|
1083
1224
|
* const doubleHash = hash256('Hello, world!');
|
|
1084
1225
|
*/
|
|
1085
|
-
export const hash256 = (
|
|
1086
|
-
msg
|
|
1087
|
-
enc?: 'hex' | 'utf8'
|
|
1088
|
-
): number[] => {
|
|
1089
|
-
const first = new SHA256().update(msg, enc).digest()
|
|
1090
|
-
return new SHA256().update(first).digest()
|
|
1226
|
+
export const hash256 = (msg: HashInput, enc?: 'hex' | 'utf8'): number[] => {
|
|
1227
|
+
return Array.from(sha256Bytes(sha256Bytes(msg, enc)))
|
|
1091
1228
|
}
|
|
1092
1229
|
|
|
1093
1230
|
/**
|
|
@@ -1102,11 +1239,10 @@ export const hash256 = (
|
|
|
1102
1239
|
* @example
|
|
1103
1240
|
* const hash = hash160('Hello, world!');
|
|
1104
1241
|
*/
|
|
1105
|
-
export const hash160 = (
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
)
|
|
1109
|
-
const first = new SHA256().update(msg, enc).digest()
|
|
1242
|
+
export const hash160 = (msg: HashInput, enc?: 'hex' | 'utf8'): number[] => {
|
|
1243
|
+
const first = sha256Bytes(msg, enc)
|
|
1244
|
+
const native = ripemd160Bytes(first)
|
|
1245
|
+
if (native != null) return Array.from(native)
|
|
1110
1246
|
return new RIPEMD160().update(first).digest()
|
|
1111
1247
|
}
|
|
1112
1248
|
|
|
@@ -1123,10 +1259,12 @@ export const hash160 = (
|
|
|
1123
1259
|
* const digest = sha256hmac('deadbeef', 'ffff001d');
|
|
1124
1260
|
*/
|
|
1125
1261
|
export const sha256hmac = (
|
|
1126
|
-
key:
|
|
1127
|
-
msg:
|
|
1262
|
+
key: HashInput,
|
|
1263
|
+
msg: HashInput,
|
|
1128
1264
|
enc?: 'hex'
|
|
1129
1265
|
): number[] => {
|
|
1266
|
+
const native = digestWithNodeHmac('sha256', key, msg, enc)
|
|
1267
|
+
if (native != null) return Array.from(native)
|
|
1130
1268
|
return new SHA256HMAC(key).update(msg, enc).digest()
|
|
1131
1269
|
}
|
|
1132
1270
|
|
|
@@ -1143,10 +1281,12 @@ export const sha256hmac = (
|
|
|
1143
1281
|
* const digest = sha512hmac('deadbeef', 'ffff001d');
|
|
1144
1282
|
*/
|
|
1145
1283
|
export const sha512hmac = (
|
|
1146
|
-
key:
|
|
1147
|
-
msg:
|
|
1284
|
+
key: HashInput,
|
|
1285
|
+
msg: HashInput,
|
|
1148
1286
|
enc?: 'hex'
|
|
1149
1287
|
): number[] => {
|
|
1288
|
+
const native = digestWithNodeHmac('sha512', key, msg, enc)
|
|
1289
|
+
if (native != null) return Array.from(native)
|
|
1150
1290
|
return new SHA512HMAC(key).update(msg, enc).digest()
|
|
1151
1291
|
}
|
|
1152
1292
|
|
|
@@ -1938,20 +2078,16 @@ export function pbkdf2 (
|
|
|
1938
2078
|
if (digest !== 'sha512') {
|
|
1939
2079
|
throw new Error('Only sha512 is supported in this PBKDF2 implementation')
|
|
1940
2080
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
return [...nodeCrypto.pbkdf2Sync(p, s, iterations, keylen, digest)]
|
|
1952
|
-
}
|
|
1953
|
-
} catch {
|
|
1954
|
-
// ignore
|
|
2081
|
+
const pbkdf2Sync = NODE_CRYPTO?.pbkdf2Sync
|
|
2082
|
+
if (typeof pbkdf2Sync === 'function') {
|
|
2083
|
+
const out = pbkdf2Sync(
|
|
2084
|
+
toHashBytes(password),
|
|
2085
|
+
toHashBytes(salt),
|
|
2086
|
+
iterations,
|
|
2087
|
+
keylen,
|
|
2088
|
+
digest
|
|
2089
|
+
)
|
|
2090
|
+
return Array.from(out)
|
|
1955
2091
|
}
|
|
1956
2092
|
const p = Uint8Array.from(password)
|
|
1957
2093
|
const s = Uint8Array.from(salt)
|
|
@@ -3,6 +3,124 @@ import { AESGCM, AESGCMDecrypt } from './AESGCM.js'
|
|
|
3
3
|
import Random from './Random.js'
|
|
4
4
|
import { toArray, encode } from './utils.js'
|
|
5
5
|
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Native AES-GCM fast-path via node:crypto / react-native-quick-crypto
|
|
8
|
+
//
|
|
9
|
+
// Resolved once at module load using the same pattern as Hash.ts. When
|
|
10
|
+
// `node:crypto` (or a compatible shim) is available and exposes
|
|
11
|
+
// `createCipheriv` / `createDecipheriv`, encrypt and decrypt will use it
|
|
12
|
+
// instead of the pure-TS implementation. The pure-TS path remains the
|
|
13
|
+
// unconditional fallback — any error in the native path causes silent
|
|
14
|
+
// re-execution through the pure-TS implementation.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const NODE_CRYPTO_SYM = (() => {
|
|
17
|
+
const processLike =
|
|
18
|
+
typeof globalThis === 'undefined' ? undefined : (globalThis as any).process
|
|
19
|
+
const getBuiltinModule = processLike?.getBuiltinModule
|
|
20
|
+
if (typeof getBuiltinModule === 'function') {
|
|
21
|
+
try {
|
|
22
|
+
const crypto = getBuiltinModule.call(processLike, 'node:crypto')
|
|
23
|
+
if (crypto != null) return crypto
|
|
24
|
+
} catch {
|
|
25
|
+
// continue to CommonJS fallback
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
if (typeof require === 'function') {
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
31
|
+
return require('node:crypto')
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
// node:crypto is unavailable in this runtime
|
|
35
|
+
}
|
|
36
|
+
return undefined
|
|
37
|
+
})()
|
|
38
|
+
|
|
39
|
+
/** True when the runtime provides a usable createCipheriv for aes-256-gcm. */
|
|
40
|
+
const NATIVE_AES_GCM_AVAILABLE: boolean = (() => {
|
|
41
|
+
if (NODE_CRYPTO_SYM == null) return false
|
|
42
|
+
return (
|
|
43
|
+
typeof NODE_CRYPTO_SYM.createCipheriv === 'function' &&
|
|
44
|
+
typeof NODE_CRYPTO_SYM.createDecipheriv === 'function'
|
|
45
|
+
)
|
|
46
|
+
})()
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Encrypt `plaintext` with AES-256-GCM via node:crypto.
|
|
50
|
+
* Returns `iv (32 bytes) || ciphertext || authTag (16 bytes)` — identical
|
|
51
|
+
* layout to the pure-TS AESGCM path used by SymmetricKey.encrypt.
|
|
52
|
+
*
|
|
53
|
+
* Returns `null` on any failure so the caller can fall back to pure-TS.
|
|
54
|
+
*/
|
|
55
|
+
function nativeEncrypt (
|
|
56
|
+
plaintext: Uint8Array,
|
|
57
|
+
iv: Uint8Array,
|
|
58
|
+
key: Uint8Array
|
|
59
|
+
): Uint8Array | null {
|
|
60
|
+
try {
|
|
61
|
+
const cipher = NODE_CRYPTO_SYM.createCipheriv(
|
|
62
|
+
'aes-256-gcm',
|
|
63
|
+
Buffer.from(key.buffer, key.byteOffset, key.byteLength),
|
|
64
|
+
Buffer.from(iv.buffer, iv.byteOffset, iv.byteLength)
|
|
65
|
+
)
|
|
66
|
+
const encrypted: Buffer = Buffer.concat([
|
|
67
|
+
cipher.update(Buffer.from(plaintext.buffer, plaintext.byteOffset, plaintext.byteLength)),
|
|
68
|
+
cipher.final()
|
|
69
|
+
])
|
|
70
|
+
const authTag: Buffer = cipher.getAuthTag() // always 16 bytes for GCM
|
|
71
|
+
|
|
72
|
+
const out = new Uint8Array(iv.length + encrypted.length + authTag.length)
|
|
73
|
+
let offset = 0
|
|
74
|
+
out.set(iv, offset); offset += iv.length
|
|
75
|
+
out.set(encrypted, offset); offset += encrypted.length
|
|
76
|
+
out.set(authTag, offset)
|
|
77
|
+
return out
|
|
78
|
+
} catch {
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Decrypt an `iv || ciphertext || authTag` bundle produced by nativeEncrypt
|
|
85
|
+
* (or by the pure-TS SymmetricKey.encrypt path) using node:crypto.
|
|
86
|
+
*
|
|
87
|
+
* Returns the plaintext on success, `null` on authentication failure, or
|
|
88
|
+
* `undefined` to signal a non-auth error so the caller can fall back.
|
|
89
|
+
*/
|
|
90
|
+
function nativeDecrypt (
|
|
91
|
+
msgBytes: Uint8Array,
|
|
92
|
+
ivLength: number,
|
|
93
|
+
tagLength: number,
|
|
94
|
+
key: Uint8Array
|
|
95
|
+
): Uint8Array | null | undefined {
|
|
96
|
+
try {
|
|
97
|
+
const iv = msgBytes.slice(0, ivLength)
|
|
98
|
+
const tagStart = msgBytes.length - tagLength
|
|
99
|
+
const ciphertext = msgBytes.slice(ivLength, tagStart)
|
|
100
|
+
const messageTag = msgBytes.slice(tagStart)
|
|
101
|
+
|
|
102
|
+
const decipher = NODE_CRYPTO_SYM.createDecipheriv(
|
|
103
|
+
'aes-256-gcm',
|
|
104
|
+
Buffer.from(key.buffer, key.byteOffset, key.byteLength),
|
|
105
|
+
Buffer.from(iv.buffer, iv.byteOffset, iv.byteLength)
|
|
106
|
+
)
|
|
107
|
+
decipher.setAuthTag(Buffer.from(messageTag.buffer, messageTag.byteOffset, messageTag.byteLength))
|
|
108
|
+
|
|
109
|
+
// Decryption authenticates on final(); throws if tag is wrong.
|
|
110
|
+
const decrypted: Buffer = Buffer.concat([
|
|
111
|
+
decipher.update(Buffer.from(ciphertext.buffer, ciphertext.byteOffset, ciphertext.byteLength)),
|
|
112
|
+
decipher.final()
|
|
113
|
+
])
|
|
114
|
+
return new Uint8Array(decrypted.buffer, decrypted.byteOffset, decrypted.byteLength)
|
|
115
|
+
} catch {
|
|
116
|
+
// Node throws "Unsupported state or unable to authenticate data" on auth
|
|
117
|
+
// failure. Treat any error as auth failure so SymmetricKey.decrypt re-throws
|
|
118
|
+
// its own descriptive message — pure-TS fallback would return null in the
|
|
119
|
+
// same scenario.
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
6
124
|
/**
|
|
7
125
|
* `SymmetricKey` is a class that extends the `BigNumber` class and implements symmetric encryption and decryption methods.
|
|
8
126
|
* Symmetric-Key encryption is a form of encryption where the same key is used to encrypt and decrypt the message.
|
|
@@ -45,6 +163,16 @@ export default class SymmetricKey extends BigNumber {
|
|
|
45
163
|
const msgBytes = new Uint8Array(toArray(msg, enc))
|
|
46
164
|
const keyBytes = new Uint8Array(this.toArray('be', 32))
|
|
47
165
|
|
|
166
|
+
// Fast path: native AES-256-GCM via node:crypto / react-native-quick-crypto.
|
|
167
|
+
// Falls back to pure-TS on any failure.
|
|
168
|
+
if (NATIVE_AES_GCM_AVAILABLE) {
|
|
169
|
+
const nativeResult = nativeEncrypt(msgBytes, iv, keyBytes)
|
|
170
|
+
if (nativeResult !== null) {
|
|
171
|
+
return encode(Array.from(nativeResult), enc)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Pure-TS fallback.
|
|
48
176
|
const { result, authenticationTag } = AESGCM(
|
|
49
177
|
msgBytes,
|
|
50
178
|
iv,
|
|
@@ -90,12 +218,28 @@ export default class SymmetricKey extends BigNumber {
|
|
|
90
218
|
throw new Error('Ciphertext too short')
|
|
91
219
|
}
|
|
92
220
|
|
|
221
|
+
const keyBytes = new Uint8Array(this.toArray('be', 32))
|
|
222
|
+
|
|
223
|
+
// Fast path: native AES-256-GCM via node:crypto / react-native-quick-crypto.
|
|
224
|
+
// Falls back to pure-TS on null/undefined return.
|
|
225
|
+
if (NATIVE_AES_GCM_AVAILABLE) {
|
|
226
|
+
const nativeResult = nativeDecrypt(msgBytes, ivLength, tagLength, keyBytes)
|
|
227
|
+
if (nativeResult !== undefined) {
|
|
228
|
+
// nativeResult is Uint8Array on success or null on auth/decryption failure.
|
|
229
|
+
if (nativeResult === null) {
|
|
230
|
+
throw new Error('Decryption failed!')
|
|
231
|
+
}
|
|
232
|
+
return encode(Array.from(nativeResult), enc)
|
|
233
|
+
}
|
|
234
|
+
// undefined means unexpected setup error — fall through to pure-TS.
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Pure-TS fallback.
|
|
93
238
|
const iv = msgBytes.slice(0, ivLength)
|
|
94
239
|
const tagStart = msgBytes.length - tagLength
|
|
95
240
|
const ciphertext = msgBytes.slice(ivLength, tagStart)
|
|
96
241
|
const messageTag = msgBytes.slice(tagStart)
|
|
97
242
|
|
|
98
|
-
const keyBytes = new Uint8Array(this.toArray('be', 32))
|
|
99
243
|
const result = AESGCMDecrypt(
|
|
100
244
|
ciphertext,
|
|
101
245
|
iv,
|