@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.
@@ -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>>;
@@ -1 +1,2 @@
1
1
  export * from "./exports";
2
+ export * from "./pbkdf2";
@@ -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 salt = password => {
26
- return new TextEncoder().encode(`mnemonic${password.normalize("NFKD")}`);
27
- };
28
- const entropyToSeedSubstrate = (entropy, password) => {
29
- return pbkdf2.pbkdf2(sha512.sha512, entropy, salt(password ?? ""), {
30
- c: 2048,
31
- dkLen: 32
32
- });
33
- };
34
- const entropyToSeedClassic = (entropy, password) => {
35
- const mnemonic = entropyToMnemonic(entropy);
36
- return pbkdf2.pbkdf2(sha512.sha512, mnemonic.normalize("NFKD"), salt(password ?? ""), {
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 salt = password => {
26
- return new TextEncoder().encode(`mnemonic${password.normalize("NFKD")}`);
27
- };
28
- const entropyToSeedSubstrate = (entropy, password) => {
29
- return pbkdf2.pbkdf2(sha512.sha512, entropy, salt(password ?? ""), {
30
- c: 2048,
31
- dkLen: 32
32
- });
33
- };
34
- const entropyToSeedClassic = (entropy, password) => {
35
- const mnemonic = entropyToMnemonic(entropy);
36
- return pbkdf2.pbkdf2(sha512.sha512, mnemonic.normalize("NFKD"), salt(password ?? ""), {
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 { HDKD, secretFromSeed, getPublicKey } from 'micro-sr25519';
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 salt = password => {
25
- return new TextEncoder().encode(`mnemonic${password.normalize("NFKD")}`);
26
- };
27
- const entropyToSeedSubstrate = (entropy, password) => {
28
- return pbkdf2(sha512, entropy, salt(password ?? ""), {
29
- c: 2048,
30
- dkLen: 32
31
- });
32
- };
33
- const entropyToSeedClassic = (entropy, password) => {
34
- const mnemonic = entropyToMnemonic(entropy);
35
- return pbkdf2(sha512, mnemonic.normalize("NFKD"), salt(password ?? ""), {
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.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/tsconfig": "0.0.2",
40
- "@talismn/eslint-config": "0.0.3"
39
+ "@talismn/eslint-config": "0.0.3",
40
+ "@talismn/tsconfig": "0.0.2"
41
41
  },
42
42
  "preconstruct": {
43
43
  "entrypoints": [