@talismn/crypto 0.1.1 → 0.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/declarations/src/derivation/common.d.ts +2 -2
- package/dist/declarations/src/derivation/deriveEcdsa.d.ts +1 -1
- package/dist/declarations/src/derivation/deriveEd25519.d.ts +1 -1
- package/dist/declarations/src/derivation/deriveEthereum.d.ts +1 -1
- package/dist/declarations/src/derivation/deriveSolana.d.ts +1 -1
- package/dist/declarations/src/derivation/utils.d.ts +3 -3
- package/dist/declarations/src/hashing/index.d.ts +2 -2
- package/dist/declarations/src/mnemonic/index.d.ts +3 -3
- package/dist/declarations/src/utils/index.d.ts +1 -0
- package/dist/declarations/src/utils/pbkdf2.d.ts +1 -0
- package/dist/talismn-crypto.cjs.dev.js +38 -28
- package/dist/talismn-crypto.cjs.prod.js +38 -28
- package/dist/talismn-crypto.esm.js +39 -30
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type DerivationDescriptor = [type: "hard" | "soft", code: string];
|
|
2
2
|
export declare const parseSubstrateDerivations: (derivationsStr: string) => DerivationDescriptor[];
|
|
3
|
-
export declare const createChainCode: (code: string) => Uint8Array
|
|
4
|
-
export declare const deriveSubstrateSecretKey: (seed: Uint8Array, derivationPath: string, prefix: string) => Uint8Array
|
|
3
|
+
export declare const createChainCode: (code: string) => Uint8Array<ArrayBuffer>;
|
|
4
|
+
export declare const deriveSubstrateSecretKey: (seed: Uint8Array, derivationPath: string, prefix: string) => Uint8Array<ArrayBufferLike>;
|
|
5
5
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Keypair } from "../types";
|
|
2
2
|
export declare const deriveEcdsa: (seed: Uint8Array, derivationPath: string) => Keypair;
|
|
3
|
-
export declare const getPublicKeyEcdsa: (secretKey: Uint8Array) => Uint8Array
|
|
3
|
+
export declare const getPublicKeyEcdsa: (secretKey: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Keypair } from "../types";
|
|
2
2
|
export declare const deriveEd25519: (seed: Uint8Array, derivationPath: string) => Keypair;
|
|
3
|
-
export declare const getPublicKeyEd25519: (secretKey: Uint8Array) => Uint8Array
|
|
3
|
+
export declare const getPublicKeyEd25519: (secretKey: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Keypair } from "../types";
|
|
2
2
|
export declare const deriveEthereum: (seed: Uint8Array, derivationPath: string) => Keypair;
|
|
3
|
-
export declare const getPublicKeyEthereum: (secretKey: Uint8Array) => Uint8Array
|
|
3
|
+
export declare const getPublicKeyEthereum: (secretKey: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Keypair } from "../types";
|
|
2
2
|
export declare const deriveSolana: (seed: Uint8Array, derivationPath: string) => Keypair;
|
|
3
|
-
export declare const getPublicKeySolana: (secretKey: Uint8Array) => Uint8Array
|
|
3
|
+
export declare const getPublicKeySolana: (secretKey: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { KeypairCurve } from "../types";
|
|
2
2
|
export declare const deriveKeypair: (seed: Uint8Array, derivationPath: string, curve: KeypairCurve) => import("../types").Keypair;
|
|
3
3
|
export declare const getPublicKeyFromSecret: (secretKey: Uint8Array, curve: KeypairCurve) => Uint8Array;
|
|
4
|
-
export declare const addressFromSuri: (suri: string, type: KeypairCurve) => string
|
|
4
|
+
export declare const addressFromSuri: (suri: string, type: KeypairCurve) => Promise<string>;
|
|
5
5
|
/**
|
|
6
6
|
* @dev we only expect suri to contain a mnemonic and derivation path.
|
|
7
7
|
* for other cases see https://polkadot.js.org/docs/keyring/start/suri/
|
|
@@ -12,5 +12,5 @@ export declare const parseSuri: (suri: string) => {
|
|
|
12
12
|
password: string | undefined;
|
|
13
13
|
};
|
|
14
14
|
export declare const removeHexPrefix: (secretKey: string) => string;
|
|
15
|
-
export declare const parseSecretKey: (secretKey: string, curve: KeypairCurve) => Uint8Array
|
|
16
|
-
export declare const isValidDerivationPath: (derivationPath: string, curve: KeypairCurve) => boolean
|
|
15
|
+
export declare const parseSecretKey: (secretKey: string, curve: KeypairCurve) => Uint8Array<ArrayBufferLike>;
|
|
16
|
+
export declare const isValidDerivationPath: (derivationPath: string, curve: KeypairCurve) => Promise<boolean>;
|
|
@@ -4,6 +4,6 @@ export declare const blake3: {
|
|
|
4
4
|
blockLen: number;
|
|
5
5
|
create(opts: Object): import("@noble/hashes/utils").HashXOF<import("@noble/hashes/utils").HashXOF<import("@noble/hashes/utils").HashXOF<any>>>;
|
|
6
6
|
};
|
|
7
|
-
export declare const blake2b256: (msg: Uint8Array) => Uint8Array
|
|
8
|
-
export declare const blake2b512: (msg: Uint8Array) => Uint8Array
|
|
7
|
+
export declare const blake2b256: (msg: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
8
|
+
export declare const blake2b512: (msg: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
9
9
|
export declare const getSafeHash: (bytes: Uint8Array) => string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { KeypairCurve } from "../types";
|
|
2
|
-
export declare const mnemonicToEntropy: (mnemonic: string) => Uint8Array
|
|
2
|
+
export declare const mnemonicToEntropy: (mnemonic: string) => Uint8Array<ArrayBufferLike>;
|
|
3
3
|
export declare const entropyToMnemonic: (entropy: Uint8Array) => string;
|
|
4
|
-
export declare const entropyToSeed: (entropy: Uint8Array, curve: KeypairCurve, password?: string) => Uint8Array
|
|
4
|
+
export declare const entropyToSeed: (entropy: Uint8Array, curve: KeypairCurve, password?: string) => Promise<Uint8Array<ArrayBuffer>>;
|
|
5
5
|
export declare const isValidMnemonic: (mnemonic: string) => boolean;
|
|
6
6
|
export declare const generateMnemonic: (words: 12 | 24) => string;
|
|
7
7
|
export declare const DEV_MNEMONIC_POLKADOT = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
|
|
8
8
|
export declare const DEV_MNEMONIC_ETHEREUM = "test test test test test test test test test test test junk";
|
|
9
|
-
export declare const getDevSeed: (curve: KeypairCurve) => Uint8Array
|
|
9
|
+
export declare const getDevSeed: (curve: KeypairCurve) => Promise<Uint8Array<ArrayBufferLike>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const pbkdf2: (hash: "SHA-256" | "SHA-512", entropy: Uint8Array, salt: Uint8Array, iterations: number, outputLenBytes: number) => Promise<Uint8Array<ArrayBuffer>>;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var pbkdf2 = require('@noble/hashes/pbkdf2');
|
|
4
|
-
var sha512 = require('@noble/hashes/sha512');
|
|
5
3
|
var bip39 = require('@scure/bip39');
|
|
6
4
|
var english = require('@scure/bip39/wordlists/english');
|
|
7
5
|
var base = require('@scure/base');
|
|
@@ -14,30 +12,41 @@ var scaleTs = require('scale-ts');
|
|
|
14
12
|
var ed25519 = require('@noble/curves/ed25519');
|
|
15
13
|
var bip32 = require('@scure/bip32');
|
|
16
14
|
var hmac = require('@noble/hashes/hmac');
|
|
15
|
+
var sha512 = require('@noble/hashes/sha512');
|
|
17
16
|
var microSr25519 = require('micro-sr25519');
|
|
18
17
|
|
|
18
|
+
const pbkdf2 = async (hash, entropy, salt, iterations, outputLenBytes) => {
|
|
19
|
+
// NOTE: react-native-quick-crypto (our `global.crypto` polyfill on Talisman Mobile) doesn't support `crypto.subtle.deriveKey`.
|
|
20
|
+
// But, we can work around this by using `crypto.subtle.deriveBits` and `crypto.subtle.importKey`, which when used together
|
|
21
|
+
// can provide the same functionality as `crypto.subtle.deriveKey`.
|
|
22
|
+
const keyMaterial = await crypto.subtle.importKey("raw", entropy, "PBKDF2", false, ["deriveBits"]);
|
|
23
|
+
const derivedBits = await crypto.subtle.deriveBits({
|
|
24
|
+
name: "PBKDF2",
|
|
25
|
+
salt,
|
|
26
|
+
iterations,
|
|
27
|
+
hash
|
|
28
|
+
}, keyMaterial, outputLenBytes * 8);
|
|
29
|
+
return new Uint8Array(derivedBits);
|
|
30
|
+
};
|
|
31
|
+
|
|
19
32
|
const mnemonicToEntropy = mnemonic => {
|
|
20
33
|
return bip39.mnemonicToEntropy(mnemonic, english.wordlist);
|
|
21
34
|
};
|
|
22
35
|
const entropyToMnemonic = entropy => {
|
|
23
36
|
return bip39.entropyToMnemonic(entropy, english.wordlist);
|
|
24
37
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
c: 2048,
|
|
38
|
-
dkLen: 64
|
|
39
|
-
});
|
|
40
|
-
};
|
|
38
|
+
const entropyToSeedSubstrate = async (entropy, password) => await pbkdf2("SHA-512", entropy, mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
39
|
+
// 2048 iterations
|
|
40
|
+
32 // 32 bytes (32 * 8 == 256 bits)
|
|
41
|
+
);
|
|
42
|
+
const entropyToSeedClassic = async (entropy, password) => await pbkdf2("SHA-512", encodeNormalized(entropyToMnemonic(entropy)), mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
43
|
+
// 2048 iterations
|
|
44
|
+
64 // 64 bytes (64 * 8 == 512 bits)
|
|
45
|
+
);
|
|
46
|
+
const mnemonicPasswordToSalt = password => encodeNormalized(`mnemonic${password}`);
|
|
47
|
+
|
|
48
|
+
/** Normalizes a UTF-8 string using `NFKD` form, then encodes it into bytes */
|
|
49
|
+
const encodeNormalized = utf8 => new TextEncoder().encode(utf8.normalize("NFKD"));
|
|
41
50
|
const getSeedDerivationType = curve => {
|
|
42
51
|
switch (curve) {
|
|
43
52
|
case "sr25519":
|
|
@@ -52,13 +61,13 @@ const getSeedDerivationType = curve => {
|
|
|
52
61
|
|
|
53
62
|
// when deriving keys from a mnemonic, we usually dont want a password here.
|
|
54
63
|
// a password provided here would be used as a 25th mnemonic word.
|
|
55
|
-
const entropyToSeed = (entropy, curve, password) => {
|
|
64
|
+
const entropyToSeed = async (entropy, curve, password) => {
|
|
56
65
|
const type = getSeedDerivationType(curve);
|
|
57
66
|
switch (type) {
|
|
58
67
|
case "classic":
|
|
59
|
-
return entropyToSeedClassic(entropy, password);
|
|
68
|
+
return await entropyToSeedClassic(entropy, password);
|
|
60
69
|
case "substrate":
|
|
61
|
-
return entropyToSeedSubstrate(entropy, password);
|
|
70
|
+
return await entropyToSeedSubstrate(entropy, password);
|
|
62
71
|
}
|
|
63
72
|
};
|
|
64
73
|
const isValidMnemonic = mnemonic => {
|
|
@@ -81,21 +90,21 @@ const DEV_MNEMONIC_ETHEREUM = "test test test test test test test test test test
|
|
|
81
90
|
|
|
82
91
|
// keep dev seeds in cache as we will reuse them to validate multiple derivation paths
|
|
83
92
|
const DEV_SEED_CACHE = new Map();
|
|
84
|
-
const getDevSeed = curve => {
|
|
93
|
+
const getDevSeed = async curve => {
|
|
85
94
|
const type = getSeedDerivationType(curve);
|
|
86
95
|
if (!DEV_SEED_CACHE.has(type)) {
|
|
87
96
|
switch (type) {
|
|
88
97
|
case "classic":
|
|
89
98
|
{
|
|
90
99
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_ETHEREUM);
|
|
91
|
-
const seed = entropyToSeedClassic(entropy); // 80ms
|
|
100
|
+
const seed = await entropyToSeedClassic(entropy); // 80ms
|
|
92
101
|
DEV_SEED_CACHE.set(type, seed);
|
|
93
102
|
break;
|
|
94
103
|
}
|
|
95
104
|
case "substrate":
|
|
96
105
|
{
|
|
97
106
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_POLKADOT);
|
|
98
|
-
const seed = entropyToSeedSubstrate(entropy); // 80ms
|
|
107
|
+
const seed = await entropyToSeedSubstrate(entropy); // 80ms
|
|
99
108
|
DEV_SEED_CACHE.set(type, seed);
|
|
100
109
|
break;
|
|
101
110
|
}
|
|
@@ -459,14 +468,14 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
459
468
|
return getPublicKeySolana(secretKey);
|
|
460
469
|
}
|
|
461
470
|
};
|
|
462
|
-
const addressFromSuri = (suri, type) => {
|
|
471
|
+
const addressFromSuri = async (suri, type) => {
|
|
463
472
|
const {
|
|
464
473
|
mnemonic,
|
|
465
474
|
derivationPath,
|
|
466
475
|
password
|
|
467
476
|
} = parseSuri(suri);
|
|
468
477
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
469
|
-
const seed = entropyToSeed(entropy, type, password); // ~80ms
|
|
478
|
+
const seed = await entropyToSeed(entropy, type, password); // ~80ms
|
|
470
479
|
const {
|
|
471
480
|
secretKey
|
|
472
481
|
} = deriveKeypair(seed, derivationPath, type);
|
|
@@ -516,9 +525,9 @@ const parseSecretKey = (secretKey, curve) => {
|
|
|
516
525
|
};
|
|
517
526
|
|
|
518
527
|
// @dev: didn't find a reliable source of information on which characters are valid => assume it s valid if a keypair can be generated from it
|
|
519
|
-
const isValidDerivationPath = (derivationPath, curve) => {
|
|
528
|
+
const isValidDerivationPath = async (derivationPath, curve) => {
|
|
520
529
|
try {
|
|
521
|
-
deriveKeypair(getDevSeed(curve), derivationPath, curve);
|
|
530
|
+
deriveKeypair(await getDevSeed(curve), derivationPath, curve);
|
|
522
531
|
return true;
|
|
523
532
|
} catch (err) {
|
|
524
533
|
return false;
|
|
@@ -591,6 +600,7 @@ exports.mnemonicToEntropy = mnemonicToEntropy;
|
|
|
591
600
|
exports.normalizeAddress = normalizeAddress;
|
|
592
601
|
exports.parseSecretKey = parseSecretKey;
|
|
593
602
|
exports.parseSuri = parseSuri;
|
|
603
|
+
exports.pbkdf2 = pbkdf2;
|
|
594
604
|
exports.platformFromAddress = platformFromAddress;
|
|
595
605
|
exports.platformFromCurve = platformFromCurve;
|
|
596
606
|
exports.platformFromEncoding = platformFromEncoding;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var pbkdf2 = require('@noble/hashes/pbkdf2');
|
|
4
|
-
var sha512 = require('@noble/hashes/sha512');
|
|
5
3
|
var bip39 = require('@scure/bip39');
|
|
6
4
|
var english = require('@scure/bip39/wordlists/english');
|
|
7
5
|
var base = require('@scure/base');
|
|
@@ -14,30 +12,41 @@ var scaleTs = require('scale-ts');
|
|
|
14
12
|
var ed25519 = require('@noble/curves/ed25519');
|
|
15
13
|
var bip32 = require('@scure/bip32');
|
|
16
14
|
var hmac = require('@noble/hashes/hmac');
|
|
15
|
+
var sha512 = require('@noble/hashes/sha512');
|
|
17
16
|
var microSr25519 = require('micro-sr25519');
|
|
18
17
|
|
|
18
|
+
const pbkdf2 = async (hash, entropy, salt, iterations, outputLenBytes) => {
|
|
19
|
+
// NOTE: react-native-quick-crypto (our `global.crypto` polyfill on Talisman Mobile) doesn't support `crypto.subtle.deriveKey`.
|
|
20
|
+
// But, we can work around this by using `crypto.subtle.deriveBits` and `crypto.subtle.importKey`, which when used together
|
|
21
|
+
// can provide the same functionality as `crypto.subtle.deriveKey`.
|
|
22
|
+
const keyMaterial = await crypto.subtle.importKey("raw", entropy, "PBKDF2", false, ["deriveBits"]);
|
|
23
|
+
const derivedBits = await crypto.subtle.deriveBits({
|
|
24
|
+
name: "PBKDF2",
|
|
25
|
+
salt,
|
|
26
|
+
iterations,
|
|
27
|
+
hash
|
|
28
|
+
}, keyMaterial, outputLenBytes * 8);
|
|
29
|
+
return new Uint8Array(derivedBits);
|
|
30
|
+
};
|
|
31
|
+
|
|
19
32
|
const mnemonicToEntropy = mnemonic => {
|
|
20
33
|
return bip39.mnemonicToEntropy(mnemonic, english.wordlist);
|
|
21
34
|
};
|
|
22
35
|
const entropyToMnemonic = entropy => {
|
|
23
36
|
return bip39.entropyToMnemonic(entropy, english.wordlist);
|
|
24
37
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
c: 2048,
|
|
38
|
-
dkLen: 64
|
|
39
|
-
});
|
|
40
|
-
};
|
|
38
|
+
const entropyToSeedSubstrate = async (entropy, password) => await pbkdf2("SHA-512", entropy, mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
39
|
+
// 2048 iterations
|
|
40
|
+
32 // 32 bytes (32 * 8 == 256 bits)
|
|
41
|
+
);
|
|
42
|
+
const entropyToSeedClassic = async (entropy, password) => await pbkdf2("SHA-512", encodeNormalized(entropyToMnemonic(entropy)), mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
43
|
+
// 2048 iterations
|
|
44
|
+
64 // 64 bytes (64 * 8 == 512 bits)
|
|
45
|
+
);
|
|
46
|
+
const mnemonicPasswordToSalt = password => encodeNormalized(`mnemonic${password}`);
|
|
47
|
+
|
|
48
|
+
/** Normalizes a UTF-8 string using `NFKD` form, then encodes it into bytes */
|
|
49
|
+
const encodeNormalized = utf8 => new TextEncoder().encode(utf8.normalize("NFKD"));
|
|
41
50
|
const getSeedDerivationType = curve => {
|
|
42
51
|
switch (curve) {
|
|
43
52
|
case "sr25519":
|
|
@@ -52,13 +61,13 @@ const getSeedDerivationType = curve => {
|
|
|
52
61
|
|
|
53
62
|
// when deriving keys from a mnemonic, we usually dont want a password here.
|
|
54
63
|
// a password provided here would be used as a 25th mnemonic word.
|
|
55
|
-
const entropyToSeed = (entropy, curve, password) => {
|
|
64
|
+
const entropyToSeed = async (entropy, curve, password) => {
|
|
56
65
|
const type = getSeedDerivationType(curve);
|
|
57
66
|
switch (type) {
|
|
58
67
|
case "classic":
|
|
59
|
-
return entropyToSeedClassic(entropy, password);
|
|
68
|
+
return await entropyToSeedClassic(entropy, password);
|
|
60
69
|
case "substrate":
|
|
61
|
-
return entropyToSeedSubstrate(entropy, password);
|
|
70
|
+
return await entropyToSeedSubstrate(entropy, password);
|
|
62
71
|
}
|
|
63
72
|
};
|
|
64
73
|
const isValidMnemonic = mnemonic => {
|
|
@@ -81,21 +90,21 @@ const DEV_MNEMONIC_ETHEREUM = "test test test test test test test test test test
|
|
|
81
90
|
|
|
82
91
|
// keep dev seeds in cache as we will reuse them to validate multiple derivation paths
|
|
83
92
|
const DEV_SEED_CACHE = new Map();
|
|
84
|
-
const getDevSeed = curve => {
|
|
93
|
+
const getDevSeed = async curve => {
|
|
85
94
|
const type = getSeedDerivationType(curve);
|
|
86
95
|
if (!DEV_SEED_CACHE.has(type)) {
|
|
87
96
|
switch (type) {
|
|
88
97
|
case "classic":
|
|
89
98
|
{
|
|
90
99
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_ETHEREUM);
|
|
91
|
-
const seed = entropyToSeedClassic(entropy); // 80ms
|
|
100
|
+
const seed = await entropyToSeedClassic(entropy); // 80ms
|
|
92
101
|
DEV_SEED_CACHE.set(type, seed);
|
|
93
102
|
break;
|
|
94
103
|
}
|
|
95
104
|
case "substrate":
|
|
96
105
|
{
|
|
97
106
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_POLKADOT);
|
|
98
|
-
const seed = entropyToSeedSubstrate(entropy); // 80ms
|
|
107
|
+
const seed = await entropyToSeedSubstrate(entropy); // 80ms
|
|
99
108
|
DEV_SEED_CACHE.set(type, seed);
|
|
100
109
|
break;
|
|
101
110
|
}
|
|
@@ -459,14 +468,14 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
459
468
|
return getPublicKeySolana(secretKey);
|
|
460
469
|
}
|
|
461
470
|
};
|
|
462
|
-
const addressFromSuri = (suri, type) => {
|
|
471
|
+
const addressFromSuri = async (suri, type) => {
|
|
463
472
|
const {
|
|
464
473
|
mnemonic,
|
|
465
474
|
derivationPath,
|
|
466
475
|
password
|
|
467
476
|
} = parseSuri(suri);
|
|
468
477
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
469
|
-
const seed = entropyToSeed(entropy, type, password); // ~80ms
|
|
478
|
+
const seed = await entropyToSeed(entropy, type, password); // ~80ms
|
|
470
479
|
const {
|
|
471
480
|
secretKey
|
|
472
481
|
} = deriveKeypair(seed, derivationPath, type);
|
|
@@ -516,9 +525,9 @@ const parseSecretKey = (secretKey, curve) => {
|
|
|
516
525
|
};
|
|
517
526
|
|
|
518
527
|
// @dev: didn't find a reliable source of information on which characters are valid => assume it s valid if a keypair can be generated from it
|
|
519
|
-
const isValidDerivationPath = (derivationPath, curve) => {
|
|
528
|
+
const isValidDerivationPath = async (derivationPath, curve) => {
|
|
520
529
|
try {
|
|
521
|
-
deriveKeypair(getDevSeed(curve), derivationPath, curve);
|
|
530
|
+
deriveKeypair(await getDevSeed(curve), derivationPath, curve);
|
|
522
531
|
return true;
|
|
523
532
|
} catch (err) {
|
|
524
533
|
return false;
|
|
@@ -591,6 +600,7 @@ exports.mnemonicToEntropy = mnemonicToEntropy;
|
|
|
591
600
|
exports.normalizeAddress = normalizeAddress;
|
|
592
601
|
exports.parseSecretKey = parseSecretKey;
|
|
593
602
|
exports.parseSuri = parseSuri;
|
|
603
|
+
exports.pbkdf2 = pbkdf2;
|
|
594
604
|
exports.platformFromAddress = platformFromAddress;
|
|
595
605
|
exports.platformFromCurve = platformFromCurve;
|
|
596
606
|
exports.platformFromEncoding = platformFromEncoding;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { pbkdf2 } from '@noble/hashes/pbkdf2';
|
|
2
|
-
import { sha512 } from '@noble/hashes/sha512';
|
|
3
1
|
import { mnemonicToEntropy as mnemonicToEntropy$1, entropyToMnemonic as entropyToMnemonic$1, validateMnemonic, generateMnemonic as generateMnemonic$1 } from '@scure/bip39';
|
|
4
2
|
import { wordlist } from '@scure/bip39/wordlists/english';
|
|
5
3
|
import { base58, bytesToString, stringToBytes } from '@scure/base';
|
|
@@ -13,7 +11,22 @@ import { Tuple, str, Bytes, u32 } from 'scale-ts';
|
|
|
13
11
|
import { ed25519 } from '@noble/curves/ed25519';
|
|
14
12
|
import { HDKey } from '@scure/bip32';
|
|
15
13
|
import { hmac } from '@noble/hashes/hmac';
|
|
16
|
-
import {
|
|
14
|
+
import { sha512 } from '@noble/hashes/sha512';
|
|
15
|
+
import { getPublicKey, HDKD, secretFromSeed } from 'micro-sr25519';
|
|
16
|
+
|
|
17
|
+
const pbkdf2 = async (hash, entropy, salt, iterations, outputLenBytes) => {
|
|
18
|
+
// NOTE: react-native-quick-crypto (our `global.crypto` polyfill on Talisman Mobile) doesn't support `crypto.subtle.deriveKey`.
|
|
19
|
+
// But, we can work around this by using `crypto.subtle.deriveBits` and `crypto.subtle.importKey`, which when used together
|
|
20
|
+
// can provide the same functionality as `crypto.subtle.deriveKey`.
|
|
21
|
+
const keyMaterial = await crypto.subtle.importKey("raw", entropy, "PBKDF2", false, ["deriveBits"]);
|
|
22
|
+
const derivedBits = await crypto.subtle.deriveBits({
|
|
23
|
+
name: "PBKDF2",
|
|
24
|
+
salt,
|
|
25
|
+
iterations,
|
|
26
|
+
hash
|
|
27
|
+
}, keyMaterial, outputLenBytes * 8);
|
|
28
|
+
return new Uint8Array(derivedBits);
|
|
29
|
+
};
|
|
17
30
|
|
|
18
31
|
const mnemonicToEntropy = mnemonic => {
|
|
19
32
|
return mnemonicToEntropy$1(mnemonic, wordlist);
|
|
@@ -21,22 +34,18 @@ const mnemonicToEntropy = mnemonic => {
|
|
|
21
34
|
const entropyToMnemonic = entropy => {
|
|
22
35
|
return entropyToMnemonic$1(entropy, wordlist);
|
|
23
36
|
};
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
c: 2048,
|
|
37
|
-
dkLen: 64
|
|
38
|
-
});
|
|
39
|
-
};
|
|
37
|
+
const entropyToSeedSubstrate = async (entropy, password) => await pbkdf2("SHA-512", entropy, mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
38
|
+
// 2048 iterations
|
|
39
|
+
32 // 32 bytes (32 * 8 == 256 bits)
|
|
40
|
+
);
|
|
41
|
+
const entropyToSeedClassic = async (entropy, password) => await pbkdf2("SHA-512", encodeNormalized(entropyToMnemonic(entropy)), mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
42
|
+
// 2048 iterations
|
|
43
|
+
64 // 64 bytes (64 * 8 == 512 bits)
|
|
44
|
+
);
|
|
45
|
+
const mnemonicPasswordToSalt = password => encodeNormalized(`mnemonic${password}`);
|
|
46
|
+
|
|
47
|
+
/** Normalizes a UTF-8 string using `NFKD` form, then encodes it into bytes */
|
|
48
|
+
const encodeNormalized = utf8 => new TextEncoder().encode(utf8.normalize("NFKD"));
|
|
40
49
|
const getSeedDerivationType = curve => {
|
|
41
50
|
switch (curve) {
|
|
42
51
|
case "sr25519":
|
|
@@ -51,13 +60,13 @@ const getSeedDerivationType = curve => {
|
|
|
51
60
|
|
|
52
61
|
// when deriving keys from a mnemonic, we usually dont want a password here.
|
|
53
62
|
// a password provided here would be used as a 25th mnemonic word.
|
|
54
|
-
const entropyToSeed = (entropy, curve, password) => {
|
|
63
|
+
const entropyToSeed = async (entropy, curve, password) => {
|
|
55
64
|
const type = getSeedDerivationType(curve);
|
|
56
65
|
switch (type) {
|
|
57
66
|
case "classic":
|
|
58
|
-
return entropyToSeedClassic(entropy, password);
|
|
67
|
+
return await entropyToSeedClassic(entropy, password);
|
|
59
68
|
case "substrate":
|
|
60
|
-
return entropyToSeedSubstrate(entropy, password);
|
|
69
|
+
return await entropyToSeedSubstrate(entropy, password);
|
|
61
70
|
}
|
|
62
71
|
};
|
|
63
72
|
const isValidMnemonic = mnemonic => {
|
|
@@ -80,21 +89,21 @@ const DEV_MNEMONIC_ETHEREUM = "test test test test test test test test test test
|
|
|
80
89
|
|
|
81
90
|
// keep dev seeds in cache as we will reuse them to validate multiple derivation paths
|
|
82
91
|
const DEV_SEED_CACHE = new Map();
|
|
83
|
-
const getDevSeed = curve => {
|
|
92
|
+
const getDevSeed = async curve => {
|
|
84
93
|
const type = getSeedDerivationType(curve);
|
|
85
94
|
if (!DEV_SEED_CACHE.has(type)) {
|
|
86
95
|
switch (type) {
|
|
87
96
|
case "classic":
|
|
88
97
|
{
|
|
89
98
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_ETHEREUM);
|
|
90
|
-
const seed = entropyToSeedClassic(entropy); // 80ms
|
|
99
|
+
const seed = await entropyToSeedClassic(entropy); // 80ms
|
|
91
100
|
DEV_SEED_CACHE.set(type, seed);
|
|
92
101
|
break;
|
|
93
102
|
}
|
|
94
103
|
case "substrate":
|
|
95
104
|
{
|
|
96
105
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_POLKADOT);
|
|
97
|
-
const seed = entropyToSeedSubstrate(entropy); // 80ms
|
|
106
|
+
const seed = await entropyToSeedSubstrate(entropy); // 80ms
|
|
98
107
|
DEV_SEED_CACHE.set(type, seed);
|
|
99
108
|
break;
|
|
100
109
|
}
|
|
@@ -458,14 +467,14 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
458
467
|
return getPublicKeySolana(secretKey);
|
|
459
468
|
}
|
|
460
469
|
};
|
|
461
|
-
const addressFromSuri = (suri, type) => {
|
|
470
|
+
const addressFromSuri = async (suri, type) => {
|
|
462
471
|
const {
|
|
463
472
|
mnemonic,
|
|
464
473
|
derivationPath,
|
|
465
474
|
password
|
|
466
475
|
} = parseSuri(suri);
|
|
467
476
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
468
|
-
const seed = entropyToSeed(entropy, type, password); // ~80ms
|
|
477
|
+
const seed = await entropyToSeed(entropy, type, password); // ~80ms
|
|
469
478
|
const {
|
|
470
479
|
secretKey
|
|
471
480
|
} = deriveKeypair(seed, derivationPath, type);
|
|
@@ -515,9 +524,9 @@ const parseSecretKey = (secretKey, curve) => {
|
|
|
515
524
|
};
|
|
516
525
|
|
|
517
526
|
// @dev: didn't find a reliable source of information on which characters are valid => assume it s valid if a keypair can be generated from it
|
|
518
|
-
const isValidDerivationPath = (derivationPath, curve) => {
|
|
527
|
+
const isValidDerivationPath = async (derivationPath, curve) => {
|
|
519
528
|
try {
|
|
520
|
-
deriveKeypair(getDevSeed(curve), derivationPath, curve);
|
|
529
|
+
deriveKeypair(await getDevSeed(curve), derivationPath, curve);
|
|
521
530
|
return true;
|
|
522
531
|
} catch (err) {
|
|
523
532
|
return false;
|
|
@@ -551,4 +560,4 @@ const platformFromAddress = address => {
|
|
|
551
560
|
return platformFromEncoding(encoding);
|
|
552
561
|
};
|
|
553
562
|
|
|
554
|
-
export { DEV_MNEMONIC_ETHEREUM, DEV_MNEMONIC_POLKADOT, addressEncodingFromCurve, addressFromPublicKey, addressFromSuri, blake2b256, blake2b512, blake3, checksumEthereumAddress, decodeSs58Address, deriveKeypair, detectAddressEncoding, encodeAddressBase58, encodeAddressEthereum, encodeAddressSs58, entropyToMnemonic, entropyToSeed, generateMnemonic, getDevSeed, getPublicKeyFromSecret, getSafeHash, isAddressEqual, isBase58Address, isEthereumAddress, isSs58Address, isValidDerivationPath, isValidMnemonic, mnemonicToEntropy, normalizeAddress, parseSecretKey, parseSuri, platformFromAddress, platformFromCurve, platformFromEncoding, removeHexPrefix };
|
|
563
|
+
export { DEV_MNEMONIC_ETHEREUM, DEV_MNEMONIC_POLKADOT, addressEncodingFromCurve, addressFromPublicKey, addressFromSuri, blake2b256, blake2b512, blake3, checksumEthereumAddress, decodeSs58Address, deriveKeypair, detectAddressEncoding, encodeAddressBase58, encodeAddressEthereum, encodeAddressSs58, entropyToMnemonic, entropyToSeed, generateMnemonic, getDevSeed, getPublicKeyFromSecret, getSafeHash, isAddressEqual, isBase58Address, isEthereumAddress, isSs58Address, isValidDerivationPath, isValidMnemonic, mnemonicToEntropy, normalizeAddress, parseSecretKey, parseSuri, pbkdf2, platformFromAddress, platformFromCurve, platformFromEncoding, removeHexPrefix };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talismn/crypto",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"author": "Talisman",
|
|
5
5
|
"homepage": "https://talisman.xyz",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"jest": "^29.7.0",
|
|
37
37
|
"ts-jest": "^29.2.5",
|
|
38
38
|
"typescript": "^5.6.3",
|
|
39
|
-
"@talismn/
|
|
40
|
-
"@talismn/
|
|
39
|
+
"@talismn/eslint-config": "0.0.3",
|
|
40
|
+
"@talismn/tsconfig": "0.0.2"
|
|
41
41
|
},
|
|
42
42
|
"preconstruct": {
|
|
43
43
|
"entrypoints": [
|