@talismn/crypto 0.1.1 → 0.1.3
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/address/encoding/addressEncodingFromCurve.d.ts +1 -0
- package/dist/declarations/src/address/encoding/bitcoin.d.ts +37 -0
- package/dist/declarations/src/address/encoding/index.d.ts +3 -2
- 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/types/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 +187 -41
- package/dist/talismn-crypto.cjs.prod.js +187 -41
- package/dist/talismn-crypto.esm.js +177 -43
- package/package.json +5 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare const isBitcoinAddress: (address: string) => boolean;
|
|
2
|
+
export declare function isBech32mAddress(address: string): boolean;
|
|
3
|
+
export declare function isBech32Address(address: string): boolean;
|
|
4
|
+
export declare function isBase58CheckAddress(address: string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Converts a Bech32m encoded address to its corresponding data representation.
|
|
7
|
+
* @param address - The Bech32m encoded address.
|
|
8
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
9
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
10
|
+
*/
|
|
11
|
+
export declare function fromBech32m(address: string): {
|
|
12
|
+
version: number;
|
|
13
|
+
prefix: string;
|
|
14
|
+
data: Uint8Array<ArrayBuffer>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Converts a Bech32 encoded address to its corresponding data representation.
|
|
18
|
+
* @param address - The Bech32 encoded address.
|
|
19
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
20
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
21
|
+
*/
|
|
22
|
+
export declare function fromBech32(address: string): {
|
|
23
|
+
version: number;
|
|
24
|
+
prefix: string;
|
|
25
|
+
data: Uint8Array<ArrayBuffer>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Decodes a base58check encoded Bitcoin address and returns the version and hash.
|
|
29
|
+
*
|
|
30
|
+
* @param address - The base58check encoded Bitcoin address to decode.
|
|
31
|
+
* @returns An object containing the version and hash of the decoded address.
|
|
32
|
+
* @throws {TypeError} If the address is too short or too long.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fromBase58Check(address: string): {
|
|
35
|
+
version: number;
|
|
36
|
+
hash: Uint8Array<ArrayBuffer>;
|
|
37
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
export * from "./addressEncodingFromCurve";
|
|
1
2
|
export * from "./base58";
|
|
3
|
+
export * from "./bitcoin";
|
|
4
|
+
export * from "./detectAddressEncoding";
|
|
2
5
|
export * from "./ethereum";
|
|
3
6
|
export * from "./ss58";
|
|
4
|
-
export * from "./addressEncodingFromCurve";
|
|
5
|
-
export * from "./detectAddressEncoding";
|
|
@@ -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,9 +1,9 @@
|
|
|
1
|
-
export type KeypairCurve = "ecdsa" | "ed25519" | "sr25519" | "ethereum" | "solana";
|
|
2
|
-
export type AddressEncoding = "ss58" | "ethereum" | "base58";
|
|
1
|
+
export type KeypairCurve = "ecdsa" | "ed25519" | "sr25519" | "ethereum" | "bitcoin-ed25519" | "bitcoin-ecdsa" | "solana";
|
|
2
|
+
export type AddressEncoding = "ss58" | "ethereum" | "bech32m" | "bech32" | "base58check" | "base58";
|
|
3
3
|
export type Keypair = {
|
|
4
4
|
type: KeypairCurve;
|
|
5
5
|
secretKey: Uint8Array;
|
|
6
6
|
publicKey: Uint8Array;
|
|
7
7
|
address: string;
|
|
8
8
|
};
|
|
9
|
-
export type Platform = "ethereum" | "polkadot" | "solana";
|
|
9
|
+
export type Platform = "ethereum" | "polkadot" | "bitcoin" | "solana";
|
|
@@ -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,10 +1,10 @@
|
|
|
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');
|
|
6
|
+
var bech32 = require('bech32');
|
|
7
|
+
var bs58check = require('bs58check');
|
|
8
8
|
var sha3 = require('@noble/hashes/sha3');
|
|
9
9
|
var utils = require('@noble/hashes/utils');
|
|
10
10
|
var blake2b = require('@noble/hashes/blake2b');
|
|
@@ -14,30 +14,45 @@ var scaleTs = require('scale-ts');
|
|
|
14
14
|
var ed25519 = require('@noble/curves/ed25519');
|
|
15
15
|
var bip32 = require('@scure/bip32');
|
|
16
16
|
var hmac = require('@noble/hashes/hmac');
|
|
17
|
+
var sha512 = require('@noble/hashes/sha512');
|
|
17
18
|
var microSr25519 = require('micro-sr25519');
|
|
18
19
|
|
|
20
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
|
+
|
|
22
|
+
var bs58check__default = /*#__PURE__*/_interopDefault(bs58check);
|
|
23
|
+
|
|
24
|
+
const pbkdf2 = async (hash, entropy, salt, iterations, outputLenBytes) => {
|
|
25
|
+
// NOTE: react-native-quick-crypto (our `global.crypto` polyfill on Talisman Mobile) doesn't support `crypto.subtle.deriveKey`.
|
|
26
|
+
// But, we can work around this by using `crypto.subtle.deriveBits` and `crypto.subtle.importKey`, which when used together
|
|
27
|
+
// can provide the same functionality as `crypto.subtle.deriveKey`.
|
|
28
|
+
const keyMaterial = await crypto.subtle.importKey("raw", entropy, "PBKDF2", false, ["deriveBits"]);
|
|
29
|
+
const derivedBits = await crypto.subtle.deriveBits({
|
|
30
|
+
name: "PBKDF2",
|
|
31
|
+
salt,
|
|
32
|
+
iterations,
|
|
33
|
+
hash
|
|
34
|
+
}, keyMaterial, outputLenBytes * 8);
|
|
35
|
+
return new Uint8Array(derivedBits);
|
|
36
|
+
};
|
|
37
|
+
|
|
19
38
|
const mnemonicToEntropy = mnemonic => {
|
|
20
39
|
return bip39.mnemonicToEntropy(mnemonic, english.wordlist);
|
|
21
40
|
};
|
|
22
41
|
const entropyToMnemonic = entropy => {
|
|
23
42
|
return bip39.entropyToMnemonic(entropy, english.wordlist);
|
|
24
43
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
c: 2048,
|
|
38
|
-
dkLen: 64
|
|
39
|
-
});
|
|
40
|
-
};
|
|
44
|
+
const entropyToSeedSubstrate = async (entropy, password) => await pbkdf2("SHA-512", entropy, mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
45
|
+
// 2048 iterations
|
|
46
|
+
32 // 32 bytes (32 * 8 == 256 bits)
|
|
47
|
+
);
|
|
48
|
+
const entropyToSeedClassic = async (entropy, password) => await pbkdf2("SHA-512", encodeNormalized(entropyToMnemonic(entropy)), mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
49
|
+
// 2048 iterations
|
|
50
|
+
64 // 64 bytes (64 * 8 == 512 bits)
|
|
51
|
+
);
|
|
52
|
+
const mnemonicPasswordToSalt = password => encodeNormalized(`mnemonic${password}`);
|
|
53
|
+
|
|
54
|
+
/** Normalizes a UTF-8 string using `NFKD` form, then encodes it into bytes */
|
|
55
|
+
const encodeNormalized = utf8 => new TextEncoder().encode(utf8.normalize("NFKD"));
|
|
41
56
|
const getSeedDerivationType = curve => {
|
|
42
57
|
switch (curve) {
|
|
43
58
|
case "sr25519":
|
|
@@ -47,18 +62,21 @@ const getSeedDerivationType = curve => {
|
|
|
47
62
|
case "ethereum":
|
|
48
63
|
case "solana":
|
|
49
64
|
return "classic";
|
|
65
|
+
case "bitcoin-ecdsa":
|
|
66
|
+
case "bitcoin-ed25519":
|
|
67
|
+
throw new Error("seed derivation is not implemented for Bitcoin");
|
|
50
68
|
}
|
|
51
69
|
};
|
|
52
70
|
|
|
53
71
|
// when deriving keys from a mnemonic, we usually dont want a password here.
|
|
54
72
|
// a password provided here would be used as a 25th mnemonic word.
|
|
55
|
-
const entropyToSeed = (entropy, curve, password) => {
|
|
73
|
+
const entropyToSeed = async (entropy, curve, password) => {
|
|
56
74
|
const type = getSeedDerivationType(curve);
|
|
57
75
|
switch (type) {
|
|
58
76
|
case "classic":
|
|
59
|
-
return entropyToSeedClassic(entropy, password);
|
|
77
|
+
return await entropyToSeedClassic(entropy, password);
|
|
60
78
|
case "substrate":
|
|
61
|
-
return entropyToSeedSubstrate(entropy, password);
|
|
79
|
+
return await entropyToSeedSubstrate(entropy, password);
|
|
62
80
|
}
|
|
63
81
|
};
|
|
64
82
|
const isValidMnemonic = mnemonic => {
|
|
@@ -81,21 +99,21 @@ const DEV_MNEMONIC_ETHEREUM = "test test test test test test test test test test
|
|
|
81
99
|
|
|
82
100
|
// keep dev seeds in cache as we will reuse them to validate multiple derivation paths
|
|
83
101
|
const DEV_SEED_CACHE = new Map();
|
|
84
|
-
const getDevSeed = curve => {
|
|
102
|
+
const getDevSeed = async curve => {
|
|
85
103
|
const type = getSeedDerivationType(curve);
|
|
86
104
|
if (!DEV_SEED_CACHE.has(type)) {
|
|
87
105
|
switch (type) {
|
|
88
106
|
case "classic":
|
|
89
107
|
{
|
|
90
108
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_ETHEREUM);
|
|
91
|
-
const seed = entropyToSeedClassic(entropy); // 80ms
|
|
109
|
+
const seed = await entropyToSeedClassic(entropy); // 80ms
|
|
92
110
|
DEV_SEED_CACHE.set(type, seed);
|
|
93
111
|
break;
|
|
94
112
|
}
|
|
95
113
|
case "substrate":
|
|
96
114
|
{
|
|
97
115
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_POLKADOT);
|
|
98
|
-
const seed = entropyToSeedSubstrate(entropy); // 80ms
|
|
116
|
+
const seed = await entropyToSeedSubstrate(entropy); // 80ms
|
|
99
117
|
DEV_SEED_CACHE.set(type, seed);
|
|
100
118
|
break;
|
|
101
119
|
}
|
|
@@ -106,6 +124,26 @@ const getDevSeed = curve => {
|
|
|
106
124
|
return DEV_SEED_CACHE.get(type);
|
|
107
125
|
};
|
|
108
126
|
|
|
127
|
+
/** NOTE: Try not to use this too much, it will need to change */
|
|
128
|
+
const addressEncodingFromCurve = curve => {
|
|
129
|
+
switch (curve) {
|
|
130
|
+
case "sr25519":
|
|
131
|
+
case "ed25519":
|
|
132
|
+
case "ecdsa":
|
|
133
|
+
return "ss58";
|
|
134
|
+
case "bitcoin-ecdsa":
|
|
135
|
+
case "bitcoin-ed25519":
|
|
136
|
+
// NOTE: Bitcoin has multiple address formats, so this isn't necessarily correct
|
|
137
|
+
// The format MAY be bech32m, but it might also be bech32 or base58check.
|
|
138
|
+
// bech32m is the most recent format.
|
|
139
|
+
return "bech32m";
|
|
140
|
+
case "ethereum":
|
|
141
|
+
return "ethereum";
|
|
142
|
+
case "solana":
|
|
143
|
+
return "base58";
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
109
147
|
const encodeAddressBase58 = publicKey => {
|
|
110
148
|
return base.base58.encode(publicKey);
|
|
111
149
|
};
|
|
@@ -119,6 +157,94 @@ function isBase58Address(address) {
|
|
|
119
157
|
}
|
|
120
158
|
}
|
|
121
159
|
|
|
160
|
+
const isBitcoinAddress = address => isBech32mAddress(address) || isBech32Address(address) || isBase58CheckAddress(address);
|
|
161
|
+
function isBech32mAddress(address) {
|
|
162
|
+
try {
|
|
163
|
+
fromBech32m(address);
|
|
164
|
+
} catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
function isBech32Address(address) {
|
|
170
|
+
try {
|
|
171
|
+
fromBech32(address);
|
|
172
|
+
} catch {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
function isBase58CheckAddress(address) {
|
|
178
|
+
try {
|
|
179
|
+
fromBase58Check(address);
|
|
180
|
+
} catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Converts a Bech32m encoded address to its corresponding data representation.
|
|
188
|
+
* @param address - The Bech32m encoded address.
|
|
189
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
190
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
191
|
+
*/
|
|
192
|
+
function fromBech32m(address) {
|
|
193
|
+
const result = bech32.bech32m.decode(address);
|
|
194
|
+
const version = result.words[0];
|
|
195
|
+
if (version === 0) throw new TypeError(address + " uses wrong encoding");
|
|
196
|
+
const data = bech32.bech32m.fromWords(result.words.slice(1));
|
|
197
|
+
return {
|
|
198
|
+
version,
|
|
199
|
+
prefix: result.prefix,
|
|
200
|
+
data: Uint8Array.from(data)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Converts a Bech32 encoded address to its corresponding data representation.
|
|
206
|
+
* @param address - The Bech32 encoded address.
|
|
207
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
208
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
209
|
+
*/
|
|
210
|
+
function fromBech32(address) {
|
|
211
|
+
const result = bech32.bech32.decode(address);
|
|
212
|
+
const version = result.words[0];
|
|
213
|
+
if (version !== 0) throw new TypeError(address + " uses wrong encoding");
|
|
214
|
+
const data = bech32.bech32.fromWords(result.words.slice(1));
|
|
215
|
+
return {
|
|
216
|
+
version,
|
|
217
|
+
prefix: result.prefix,
|
|
218
|
+
data: Uint8Array.from(data)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Decodes a base58check encoded Bitcoin address and returns the version and hash.
|
|
224
|
+
*
|
|
225
|
+
* @param address - The base58check encoded Bitcoin address to decode.
|
|
226
|
+
* @returns An object containing the version and hash of the decoded address.
|
|
227
|
+
* @throws {TypeError} If the address is too short or too long.
|
|
228
|
+
*/
|
|
229
|
+
function fromBase58Check(address) {
|
|
230
|
+
const payload = bs58check__default.default.decode(address);
|
|
231
|
+
if (payload.length < 21) throw new TypeError(address + " is too short");
|
|
232
|
+
if (payload.length > 21) throw new TypeError(address + " is too long");
|
|
233
|
+
function readUInt8(buffer, offset) {
|
|
234
|
+
if (offset + 1 > buffer.length) {
|
|
235
|
+
throw new Error("Offset is outside the bounds of Uint8Array");
|
|
236
|
+
}
|
|
237
|
+
const buf = Buffer.from(buffer);
|
|
238
|
+
return buf.readUInt8(offset);
|
|
239
|
+
}
|
|
240
|
+
const version = readUInt8(payload, 0);
|
|
241
|
+
const hash = payload.slice(1);
|
|
242
|
+
return {
|
|
243
|
+
version,
|
|
244
|
+
hash
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
122
248
|
/**
|
|
123
249
|
* Encodes a public key using H160 encoding with Ethereum checksum.
|
|
124
250
|
*/
|
|
@@ -206,23 +332,13 @@ function isSs58Address(address) {
|
|
|
206
332
|
}
|
|
207
333
|
}
|
|
208
334
|
|
|
209
|
-
const addressEncodingFromCurve = curve => {
|
|
210
|
-
switch (curve) {
|
|
211
|
-
case "sr25519":
|
|
212
|
-
case "ed25519":
|
|
213
|
-
case "ecdsa":
|
|
214
|
-
return "ss58";
|
|
215
|
-
case "ethereum":
|
|
216
|
-
return "ethereum";
|
|
217
|
-
case "solana":
|
|
218
|
-
return "base58";
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
|
|
222
335
|
const CACHE$1 = new Map();
|
|
223
336
|
const detectAddressEncodingInner = address => {
|
|
224
337
|
if (isEthereumAddress(address)) return "ethereum";
|
|
225
338
|
if (isSs58Address(address)) return "ss58";
|
|
339
|
+
if (isBech32mAddress(address)) return "bech32m";
|
|
340
|
+
if (isBech32Address(address)) return "bech32";
|
|
341
|
+
if (isBase58CheckAddress(address)) return "base58check";
|
|
226
342
|
if (isBase58Address(address)) return "base58";
|
|
227
343
|
throw new Error(`Unknown address encoding`);
|
|
228
344
|
};
|
|
@@ -237,6 +353,10 @@ const addressFromPublicKey = (publicKey, encoding, options) => {
|
|
|
237
353
|
return encodeAddressSs58(publicKey, options?.ss58Prefix);
|
|
238
354
|
case "ethereum":
|
|
239
355
|
return encodeAddressEthereum(publicKey);
|
|
356
|
+
case "bech32m":
|
|
357
|
+
case "bech32":
|
|
358
|
+
case "base58check":
|
|
359
|
+
throw new Error("addressFromPublicKey is not implemented for Bitcoin");
|
|
240
360
|
case "base58":
|
|
241
361
|
return encodeAddressBase58(publicKey);
|
|
242
362
|
}
|
|
@@ -259,6 +379,9 @@ const normalizeAnyAddress = address => {
|
|
|
259
379
|
switch (detectAddressEncoding(address)) {
|
|
260
380
|
case "ethereum":
|
|
261
381
|
return checksumEthereumAddress(address);
|
|
382
|
+
case "bech32m":
|
|
383
|
+
case "bech32":
|
|
384
|
+
case "base58check":
|
|
262
385
|
case "base58":
|
|
263
386
|
return address;
|
|
264
387
|
case "ss58":
|
|
@@ -439,6 +562,9 @@ const deriveKeypair = (seed, derivationPath, curve) => {
|
|
|
439
562
|
return deriveEd25519(seed, derivationPath);
|
|
440
563
|
case "ecdsa":
|
|
441
564
|
return deriveEcdsa(seed, derivationPath);
|
|
565
|
+
case "bitcoin-ecdsa":
|
|
566
|
+
case "bitcoin-ed25519":
|
|
567
|
+
throw new Error("deriveKeypair is not implemented for Bitcoin");
|
|
442
568
|
case "ethereum":
|
|
443
569
|
return deriveEthereum(seed, derivationPath);
|
|
444
570
|
case "solana":
|
|
@@ -455,18 +581,21 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
455
581
|
return getPublicKeySr25519(secretKey);
|
|
456
582
|
case "ed25519":
|
|
457
583
|
return getPublicKeyEd25519(secretKey);
|
|
584
|
+
case "bitcoin-ecdsa":
|
|
585
|
+
case "bitcoin-ed25519":
|
|
586
|
+
throw new Error("getPublicKeyFromSecret is not implemented for Bitcoin");
|
|
458
587
|
case "solana":
|
|
459
588
|
return getPublicKeySolana(secretKey);
|
|
460
589
|
}
|
|
461
590
|
};
|
|
462
|
-
const addressFromSuri = (suri, type) => {
|
|
591
|
+
const addressFromSuri = async (suri, type) => {
|
|
463
592
|
const {
|
|
464
593
|
mnemonic,
|
|
465
594
|
derivationPath,
|
|
466
595
|
password
|
|
467
596
|
} = parseSuri(suri);
|
|
468
597
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
469
|
-
const seed = entropyToSeed(entropy, type, password); // ~80ms
|
|
598
|
+
const seed = await entropyToSeed(entropy, type, password); // ~80ms
|
|
470
599
|
const {
|
|
471
600
|
secretKey
|
|
472
601
|
} = deriveKeypair(seed, derivationPath, type);
|
|
@@ -510,15 +639,17 @@ const parseSecretKey = (secretKey, curve) => {
|
|
|
510
639
|
case "ed25519":
|
|
511
640
|
case "sr25519":
|
|
512
641
|
case "ecdsa":
|
|
642
|
+
case "bitcoin-ecdsa":
|
|
643
|
+
case "bitcoin-ed25519":
|
|
513
644
|
case "solana":
|
|
514
645
|
throw new Error("Not implemented");
|
|
515
646
|
}
|
|
516
647
|
};
|
|
517
648
|
|
|
518
649
|
// @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) => {
|
|
650
|
+
const isValidDerivationPath = async (derivationPath, curve) => {
|
|
520
651
|
try {
|
|
521
|
-
deriveKeypair(getDevSeed(curve), derivationPath, curve);
|
|
652
|
+
deriveKeypair(await getDevSeed(curve), derivationPath, curve);
|
|
522
653
|
return true;
|
|
523
654
|
} catch (err) {
|
|
524
655
|
return false;
|
|
@@ -533,6 +664,9 @@ const platformFromCurve = curve => {
|
|
|
533
664
|
return "polkadot";
|
|
534
665
|
case "ethereum":
|
|
535
666
|
return "ethereum";
|
|
667
|
+
case "bitcoin-ecdsa":
|
|
668
|
+
case "bitcoin-ed25519":
|
|
669
|
+
return "bitcoin";
|
|
536
670
|
case "solana":
|
|
537
671
|
return "solana";
|
|
538
672
|
}
|
|
@@ -543,6 +677,10 @@ const platformFromEncoding = encoding => {
|
|
|
543
677
|
return "polkadot";
|
|
544
678
|
case "ethereum":
|
|
545
679
|
return "ethereum";
|
|
680
|
+
case "bech32m":
|
|
681
|
+
case "bech32":
|
|
682
|
+
case "base58check":
|
|
683
|
+
return "bitcoin";
|
|
546
684
|
case "base58":
|
|
547
685
|
return "solana";
|
|
548
686
|
}
|
|
@@ -577,12 +715,19 @@ exports.encodeAddressEthereum = encodeAddressEthereum;
|
|
|
577
715
|
exports.encodeAddressSs58 = encodeAddressSs58;
|
|
578
716
|
exports.entropyToMnemonic = entropyToMnemonic;
|
|
579
717
|
exports.entropyToSeed = entropyToSeed;
|
|
718
|
+
exports.fromBase58Check = fromBase58Check;
|
|
719
|
+
exports.fromBech32 = fromBech32;
|
|
720
|
+
exports.fromBech32m = fromBech32m;
|
|
580
721
|
exports.generateMnemonic = generateMnemonic;
|
|
581
722
|
exports.getDevSeed = getDevSeed;
|
|
582
723
|
exports.getPublicKeyFromSecret = getPublicKeyFromSecret;
|
|
583
724
|
exports.getSafeHash = getSafeHash;
|
|
584
725
|
exports.isAddressEqual = isAddressEqual;
|
|
585
726
|
exports.isBase58Address = isBase58Address;
|
|
727
|
+
exports.isBase58CheckAddress = isBase58CheckAddress;
|
|
728
|
+
exports.isBech32Address = isBech32Address;
|
|
729
|
+
exports.isBech32mAddress = isBech32mAddress;
|
|
730
|
+
exports.isBitcoinAddress = isBitcoinAddress;
|
|
586
731
|
exports.isEthereumAddress = isEthereumAddress;
|
|
587
732
|
exports.isSs58Address = isSs58Address;
|
|
588
733
|
exports.isValidDerivationPath = isValidDerivationPath;
|
|
@@ -591,6 +736,7 @@ exports.mnemonicToEntropy = mnemonicToEntropy;
|
|
|
591
736
|
exports.normalizeAddress = normalizeAddress;
|
|
592
737
|
exports.parseSecretKey = parseSecretKey;
|
|
593
738
|
exports.parseSuri = parseSuri;
|
|
739
|
+
exports.pbkdf2 = pbkdf2;
|
|
594
740
|
exports.platformFromAddress = platformFromAddress;
|
|
595
741
|
exports.platformFromCurve = platformFromCurve;
|
|
596
742
|
exports.platformFromEncoding = platformFromEncoding;
|
|
@@ -1,10 +1,10 @@
|
|
|
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');
|
|
6
|
+
var bech32 = require('bech32');
|
|
7
|
+
var bs58check = require('bs58check');
|
|
8
8
|
var sha3 = require('@noble/hashes/sha3');
|
|
9
9
|
var utils = require('@noble/hashes/utils');
|
|
10
10
|
var blake2b = require('@noble/hashes/blake2b');
|
|
@@ -14,30 +14,45 @@ var scaleTs = require('scale-ts');
|
|
|
14
14
|
var ed25519 = require('@noble/curves/ed25519');
|
|
15
15
|
var bip32 = require('@scure/bip32');
|
|
16
16
|
var hmac = require('@noble/hashes/hmac');
|
|
17
|
+
var sha512 = require('@noble/hashes/sha512');
|
|
17
18
|
var microSr25519 = require('micro-sr25519');
|
|
18
19
|
|
|
20
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
|
+
|
|
22
|
+
var bs58check__default = /*#__PURE__*/_interopDefault(bs58check);
|
|
23
|
+
|
|
24
|
+
const pbkdf2 = async (hash, entropy, salt, iterations, outputLenBytes) => {
|
|
25
|
+
// NOTE: react-native-quick-crypto (our `global.crypto` polyfill on Talisman Mobile) doesn't support `crypto.subtle.deriveKey`.
|
|
26
|
+
// But, we can work around this by using `crypto.subtle.deriveBits` and `crypto.subtle.importKey`, which when used together
|
|
27
|
+
// can provide the same functionality as `crypto.subtle.deriveKey`.
|
|
28
|
+
const keyMaterial = await crypto.subtle.importKey("raw", entropy, "PBKDF2", false, ["deriveBits"]);
|
|
29
|
+
const derivedBits = await crypto.subtle.deriveBits({
|
|
30
|
+
name: "PBKDF2",
|
|
31
|
+
salt,
|
|
32
|
+
iterations,
|
|
33
|
+
hash
|
|
34
|
+
}, keyMaterial, outputLenBytes * 8);
|
|
35
|
+
return new Uint8Array(derivedBits);
|
|
36
|
+
};
|
|
37
|
+
|
|
19
38
|
const mnemonicToEntropy = mnemonic => {
|
|
20
39
|
return bip39.mnemonicToEntropy(mnemonic, english.wordlist);
|
|
21
40
|
};
|
|
22
41
|
const entropyToMnemonic = entropy => {
|
|
23
42
|
return bip39.entropyToMnemonic(entropy, english.wordlist);
|
|
24
43
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
c: 2048,
|
|
38
|
-
dkLen: 64
|
|
39
|
-
});
|
|
40
|
-
};
|
|
44
|
+
const entropyToSeedSubstrate = async (entropy, password) => await pbkdf2("SHA-512", entropy, mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
45
|
+
// 2048 iterations
|
|
46
|
+
32 // 32 bytes (32 * 8 == 256 bits)
|
|
47
|
+
);
|
|
48
|
+
const entropyToSeedClassic = async (entropy, password) => await pbkdf2("SHA-512", encodeNormalized(entropyToMnemonic(entropy)), mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
49
|
+
// 2048 iterations
|
|
50
|
+
64 // 64 bytes (64 * 8 == 512 bits)
|
|
51
|
+
);
|
|
52
|
+
const mnemonicPasswordToSalt = password => encodeNormalized(`mnemonic${password}`);
|
|
53
|
+
|
|
54
|
+
/** Normalizes a UTF-8 string using `NFKD` form, then encodes it into bytes */
|
|
55
|
+
const encodeNormalized = utf8 => new TextEncoder().encode(utf8.normalize("NFKD"));
|
|
41
56
|
const getSeedDerivationType = curve => {
|
|
42
57
|
switch (curve) {
|
|
43
58
|
case "sr25519":
|
|
@@ -47,18 +62,21 @@ const getSeedDerivationType = curve => {
|
|
|
47
62
|
case "ethereum":
|
|
48
63
|
case "solana":
|
|
49
64
|
return "classic";
|
|
65
|
+
case "bitcoin-ecdsa":
|
|
66
|
+
case "bitcoin-ed25519":
|
|
67
|
+
throw new Error("seed derivation is not implemented for Bitcoin");
|
|
50
68
|
}
|
|
51
69
|
};
|
|
52
70
|
|
|
53
71
|
// when deriving keys from a mnemonic, we usually dont want a password here.
|
|
54
72
|
// a password provided here would be used as a 25th mnemonic word.
|
|
55
|
-
const entropyToSeed = (entropy, curve, password) => {
|
|
73
|
+
const entropyToSeed = async (entropy, curve, password) => {
|
|
56
74
|
const type = getSeedDerivationType(curve);
|
|
57
75
|
switch (type) {
|
|
58
76
|
case "classic":
|
|
59
|
-
return entropyToSeedClassic(entropy, password);
|
|
77
|
+
return await entropyToSeedClassic(entropy, password);
|
|
60
78
|
case "substrate":
|
|
61
|
-
return entropyToSeedSubstrate(entropy, password);
|
|
79
|
+
return await entropyToSeedSubstrate(entropy, password);
|
|
62
80
|
}
|
|
63
81
|
};
|
|
64
82
|
const isValidMnemonic = mnemonic => {
|
|
@@ -81,21 +99,21 @@ const DEV_MNEMONIC_ETHEREUM = "test test test test test test test test test test
|
|
|
81
99
|
|
|
82
100
|
// keep dev seeds in cache as we will reuse them to validate multiple derivation paths
|
|
83
101
|
const DEV_SEED_CACHE = new Map();
|
|
84
|
-
const getDevSeed = curve => {
|
|
102
|
+
const getDevSeed = async curve => {
|
|
85
103
|
const type = getSeedDerivationType(curve);
|
|
86
104
|
if (!DEV_SEED_CACHE.has(type)) {
|
|
87
105
|
switch (type) {
|
|
88
106
|
case "classic":
|
|
89
107
|
{
|
|
90
108
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_ETHEREUM);
|
|
91
|
-
const seed = entropyToSeedClassic(entropy); // 80ms
|
|
109
|
+
const seed = await entropyToSeedClassic(entropy); // 80ms
|
|
92
110
|
DEV_SEED_CACHE.set(type, seed);
|
|
93
111
|
break;
|
|
94
112
|
}
|
|
95
113
|
case "substrate":
|
|
96
114
|
{
|
|
97
115
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_POLKADOT);
|
|
98
|
-
const seed = entropyToSeedSubstrate(entropy); // 80ms
|
|
116
|
+
const seed = await entropyToSeedSubstrate(entropy); // 80ms
|
|
99
117
|
DEV_SEED_CACHE.set(type, seed);
|
|
100
118
|
break;
|
|
101
119
|
}
|
|
@@ -106,6 +124,26 @@ const getDevSeed = curve => {
|
|
|
106
124
|
return DEV_SEED_CACHE.get(type);
|
|
107
125
|
};
|
|
108
126
|
|
|
127
|
+
/** NOTE: Try not to use this too much, it will need to change */
|
|
128
|
+
const addressEncodingFromCurve = curve => {
|
|
129
|
+
switch (curve) {
|
|
130
|
+
case "sr25519":
|
|
131
|
+
case "ed25519":
|
|
132
|
+
case "ecdsa":
|
|
133
|
+
return "ss58";
|
|
134
|
+
case "bitcoin-ecdsa":
|
|
135
|
+
case "bitcoin-ed25519":
|
|
136
|
+
// NOTE: Bitcoin has multiple address formats, so this isn't necessarily correct
|
|
137
|
+
// The format MAY be bech32m, but it might also be bech32 or base58check.
|
|
138
|
+
// bech32m is the most recent format.
|
|
139
|
+
return "bech32m";
|
|
140
|
+
case "ethereum":
|
|
141
|
+
return "ethereum";
|
|
142
|
+
case "solana":
|
|
143
|
+
return "base58";
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
109
147
|
const encodeAddressBase58 = publicKey => {
|
|
110
148
|
return base.base58.encode(publicKey);
|
|
111
149
|
};
|
|
@@ -119,6 +157,94 @@ function isBase58Address(address) {
|
|
|
119
157
|
}
|
|
120
158
|
}
|
|
121
159
|
|
|
160
|
+
const isBitcoinAddress = address => isBech32mAddress(address) || isBech32Address(address) || isBase58CheckAddress(address);
|
|
161
|
+
function isBech32mAddress(address) {
|
|
162
|
+
try {
|
|
163
|
+
fromBech32m(address);
|
|
164
|
+
} catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
function isBech32Address(address) {
|
|
170
|
+
try {
|
|
171
|
+
fromBech32(address);
|
|
172
|
+
} catch {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
function isBase58CheckAddress(address) {
|
|
178
|
+
try {
|
|
179
|
+
fromBase58Check(address);
|
|
180
|
+
} catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Converts a Bech32m encoded address to its corresponding data representation.
|
|
188
|
+
* @param address - The Bech32m encoded address.
|
|
189
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
190
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
191
|
+
*/
|
|
192
|
+
function fromBech32m(address) {
|
|
193
|
+
const result = bech32.bech32m.decode(address);
|
|
194
|
+
const version = result.words[0];
|
|
195
|
+
if (version === 0) throw new TypeError(address + " uses wrong encoding");
|
|
196
|
+
const data = bech32.bech32m.fromWords(result.words.slice(1));
|
|
197
|
+
return {
|
|
198
|
+
version,
|
|
199
|
+
prefix: result.prefix,
|
|
200
|
+
data: Uint8Array.from(data)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Converts a Bech32 encoded address to its corresponding data representation.
|
|
206
|
+
* @param address - The Bech32 encoded address.
|
|
207
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
208
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
209
|
+
*/
|
|
210
|
+
function fromBech32(address) {
|
|
211
|
+
const result = bech32.bech32.decode(address);
|
|
212
|
+
const version = result.words[0];
|
|
213
|
+
if (version !== 0) throw new TypeError(address + " uses wrong encoding");
|
|
214
|
+
const data = bech32.bech32.fromWords(result.words.slice(1));
|
|
215
|
+
return {
|
|
216
|
+
version,
|
|
217
|
+
prefix: result.prefix,
|
|
218
|
+
data: Uint8Array.from(data)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Decodes a base58check encoded Bitcoin address and returns the version and hash.
|
|
224
|
+
*
|
|
225
|
+
* @param address - The base58check encoded Bitcoin address to decode.
|
|
226
|
+
* @returns An object containing the version and hash of the decoded address.
|
|
227
|
+
* @throws {TypeError} If the address is too short or too long.
|
|
228
|
+
*/
|
|
229
|
+
function fromBase58Check(address) {
|
|
230
|
+
const payload = bs58check__default.default.decode(address);
|
|
231
|
+
if (payload.length < 21) throw new TypeError(address + " is too short");
|
|
232
|
+
if (payload.length > 21) throw new TypeError(address + " is too long");
|
|
233
|
+
function readUInt8(buffer, offset) {
|
|
234
|
+
if (offset + 1 > buffer.length) {
|
|
235
|
+
throw new Error("Offset is outside the bounds of Uint8Array");
|
|
236
|
+
}
|
|
237
|
+
const buf = Buffer.from(buffer);
|
|
238
|
+
return buf.readUInt8(offset);
|
|
239
|
+
}
|
|
240
|
+
const version = readUInt8(payload, 0);
|
|
241
|
+
const hash = payload.slice(1);
|
|
242
|
+
return {
|
|
243
|
+
version,
|
|
244
|
+
hash
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
122
248
|
/**
|
|
123
249
|
* Encodes a public key using H160 encoding with Ethereum checksum.
|
|
124
250
|
*/
|
|
@@ -206,23 +332,13 @@ function isSs58Address(address) {
|
|
|
206
332
|
}
|
|
207
333
|
}
|
|
208
334
|
|
|
209
|
-
const addressEncodingFromCurve = curve => {
|
|
210
|
-
switch (curve) {
|
|
211
|
-
case "sr25519":
|
|
212
|
-
case "ed25519":
|
|
213
|
-
case "ecdsa":
|
|
214
|
-
return "ss58";
|
|
215
|
-
case "ethereum":
|
|
216
|
-
return "ethereum";
|
|
217
|
-
case "solana":
|
|
218
|
-
return "base58";
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
|
|
222
335
|
const CACHE$1 = new Map();
|
|
223
336
|
const detectAddressEncodingInner = address => {
|
|
224
337
|
if (isEthereumAddress(address)) return "ethereum";
|
|
225
338
|
if (isSs58Address(address)) return "ss58";
|
|
339
|
+
if (isBech32mAddress(address)) return "bech32m";
|
|
340
|
+
if (isBech32Address(address)) return "bech32";
|
|
341
|
+
if (isBase58CheckAddress(address)) return "base58check";
|
|
226
342
|
if (isBase58Address(address)) return "base58";
|
|
227
343
|
throw new Error(`Unknown address encoding`);
|
|
228
344
|
};
|
|
@@ -237,6 +353,10 @@ const addressFromPublicKey = (publicKey, encoding, options) => {
|
|
|
237
353
|
return encodeAddressSs58(publicKey, options?.ss58Prefix);
|
|
238
354
|
case "ethereum":
|
|
239
355
|
return encodeAddressEthereum(publicKey);
|
|
356
|
+
case "bech32m":
|
|
357
|
+
case "bech32":
|
|
358
|
+
case "base58check":
|
|
359
|
+
throw new Error("addressFromPublicKey is not implemented for Bitcoin");
|
|
240
360
|
case "base58":
|
|
241
361
|
return encodeAddressBase58(publicKey);
|
|
242
362
|
}
|
|
@@ -259,6 +379,9 @@ const normalizeAnyAddress = address => {
|
|
|
259
379
|
switch (detectAddressEncoding(address)) {
|
|
260
380
|
case "ethereum":
|
|
261
381
|
return checksumEthereumAddress(address);
|
|
382
|
+
case "bech32m":
|
|
383
|
+
case "bech32":
|
|
384
|
+
case "base58check":
|
|
262
385
|
case "base58":
|
|
263
386
|
return address;
|
|
264
387
|
case "ss58":
|
|
@@ -439,6 +562,9 @@ const deriveKeypair = (seed, derivationPath, curve) => {
|
|
|
439
562
|
return deriveEd25519(seed, derivationPath);
|
|
440
563
|
case "ecdsa":
|
|
441
564
|
return deriveEcdsa(seed, derivationPath);
|
|
565
|
+
case "bitcoin-ecdsa":
|
|
566
|
+
case "bitcoin-ed25519":
|
|
567
|
+
throw new Error("deriveKeypair is not implemented for Bitcoin");
|
|
442
568
|
case "ethereum":
|
|
443
569
|
return deriveEthereum(seed, derivationPath);
|
|
444
570
|
case "solana":
|
|
@@ -455,18 +581,21 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
455
581
|
return getPublicKeySr25519(secretKey);
|
|
456
582
|
case "ed25519":
|
|
457
583
|
return getPublicKeyEd25519(secretKey);
|
|
584
|
+
case "bitcoin-ecdsa":
|
|
585
|
+
case "bitcoin-ed25519":
|
|
586
|
+
throw new Error("getPublicKeyFromSecret is not implemented for Bitcoin");
|
|
458
587
|
case "solana":
|
|
459
588
|
return getPublicKeySolana(secretKey);
|
|
460
589
|
}
|
|
461
590
|
};
|
|
462
|
-
const addressFromSuri = (suri, type) => {
|
|
591
|
+
const addressFromSuri = async (suri, type) => {
|
|
463
592
|
const {
|
|
464
593
|
mnemonic,
|
|
465
594
|
derivationPath,
|
|
466
595
|
password
|
|
467
596
|
} = parseSuri(suri);
|
|
468
597
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
469
|
-
const seed = entropyToSeed(entropy, type, password); // ~80ms
|
|
598
|
+
const seed = await entropyToSeed(entropy, type, password); // ~80ms
|
|
470
599
|
const {
|
|
471
600
|
secretKey
|
|
472
601
|
} = deriveKeypair(seed, derivationPath, type);
|
|
@@ -510,15 +639,17 @@ const parseSecretKey = (secretKey, curve) => {
|
|
|
510
639
|
case "ed25519":
|
|
511
640
|
case "sr25519":
|
|
512
641
|
case "ecdsa":
|
|
642
|
+
case "bitcoin-ecdsa":
|
|
643
|
+
case "bitcoin-ed25519":
|
|
513
644
|
case "solana":
|
|
514
645
|
throw new Error("Not implemented");
|
|
515
646
|
}
|
|
516
647
|
};
|
|
517
648
|
|
|
518
649
|
// @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) => {
|
|
650
|
+
const isValidDerivationPath = async (derivationPath, curve) => {
|
|
520
651
|
try {
|
|
521
|
-
deriveKeypair(getDevSeed(curve), derivationPath, curve);
|
|
652
|
+
deriveKeypair(await getDevSeed(curve), derivationPath, curve);
|
|
522
653
|
return true;
|
|
523
654
|
} catch (err) {
|
|
524
655
|
return false;
|
|
@@ -533,6 +664,9 @@ const platformFromCurve = curve => {
|
|
|
533
664
|
return "polkadot";
|
|
534
665
|
case "ethereum":
|
|
535
666
|
return "ethereum";
|
|
667
|
+
case "bitcoin-ecdsa":
|
|
668
|
+
case "bitcoin-ed25519":
|
|
669
|
+
return "bitcoin";
|
|
536
670
|
case "solana":
|
|
537
671
|
return "solana";
|
|
538
672
|
}
|
|
@@ -543,6 +677,10 @@ const platformFromEncoding = encoding => {
|
|
|
543
677
|
return "polkadot";
|
|
544
678
|
case "ethereum":
|
|
545
679
|
return "ethereum";
|
|
680
|
+
case "bech32m":
|
|
681
|
+
case "bech32":
|
|
682
|
+
case "base58check":
|
|
683
|
+
return "bitcoin";
|
|
546
684
|
case "base58":
|
|
547
685
|
return "solana";
|
|
548
686
|
}
|
|
@@ -577,12 +715,19 @@ exports.encodeAddressEthereum = encodeAddressEthereum;
|
|
|
577
715
|
exports.encodeAddressSs58 = encodeAddressSs58;
|
|
578
716
|
exports.entropyToMnemonic = entropyToMnemonic;
|
|
579
717
|
exports.entropyToSeed = entropyToSeed;
|
|
718
|
+
exports.fromBase58Check = fromBase58Check;
|
|
719
|
+
exports.fromBech32 = fromBech32;
|
|
720
|
+
exports.fromBech32m = fromBech32m;
|
|
580
721
|
exports.generateMnemonic = generateMnemonic;
|
|
581
722
|
exports.getDevSeed = getDevSeed;
|
|
582
723
|
exports.getPublicKeyFromSecret = getPublicKeyFromSecret;
|
|
583
724
|
exports.getSafeHash = getSafeHash;
|
|
584
725
|
exports.isAddressEqual = isAddressEqual;
|
|
585
726
|
exports.isBase58Address = isBase58Address;
|
|
727
|
+
exports.isBase58CheckAddress = isBase58CheckAddress;
|
|
728
|
+
exports.isBech32Address = isBech32Address;
|
|
729
|
+
exports.isBech32mAddress = isBech32mAddress;
|
|
730
|
+
exports.isBitcoinAddress = isBitcoinAddress;
|
|
586
731
|
exports.isEthereumAddress = isEthereumAddress;
|
|
587
732
|
exports.isSs58Address = isSs58Address;
|
|
588
733
|
exports.isValidDerivationPath = isValidDerivationPath;
|
|
@@ -591,6 +736,7 @@ exports.mnemonicToEntropy = mnemonicToEntropy;
|
|
|
591
736
|
exports.normalizeAddress = normalizeAddress;
|
|
592
737
|
exports.parseSecretKey = parseSecretKey;
|
|
593
738
|
exports.parseSuri = parseSuri;
|
|
739
|
+
exports.pbkdf2 = pbkdf2;
|
|
594
740
|
exports.platformFromAddress = platformFromAddress;
|
|
595
741
|
exports.platformFromCurve = platformFromCurve;
|
|
596
742
|
exports.platformFromEncoding = platformFromEncoding;
|
|
@@ -1,9 +1,9 @@
|
|
|
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';
|
|
6
4
|
export { bytesToString, stringToBytes } from '@scure/base';
|
|
5
|
+
import { bech32m, bech32 } from 'bech32';
|
|
6
|
+
import bs58check from 'bs58check';
|
|
7
7
|
import { keccak_256 } from '@noble/hashes/sha3';
|
|
8
8
|
import { bytesToHex, randomBytes } from '@noble/hashes/utils';
|
|
9
9
|
import { blake2b } from '@noble/hashes/blake2b';
|
|
@@ -13,7 +13,22 @@ import { Tuple, str, Bytes, u32 } from 'scale-ts';
|
|
|
13
13
|
import { ed25519 } from '@noble/curves/ed25519';
|
|
14
14
|
import { HDKey } from '@scure/bip32';
|
|
15
15
|
import { hmac } from '@noble/hashes/hmac';
|
|
16
|
-
import {
|
|
16
|
+
import { sha512 } from '@noble/hashes/sha512';
|
|
17
|
+
import { getPublicKey, HDKD, secretFromSeed } from 'micro-sr25519';
|
|
18
|
+
|
|
19
|
+
const pbkdf2 = async (hash, entropy, salt, iterations, outputLenBytes) => {
|
|
20
|
+
// NOTE: react-native-quick-crypto (our `global.crypto` polyfill on Talisman Mobile) doesn't support `crypto.subtle.deriveKey`.
|
|
21
|
+
// But, we can work around this by using `crypto.subtle.deriveBits` and `crypto.subtle.importKey`, which when used together
|
|
22
|
+
// can provide the same functionality as `crypto.subtle.deriveKey`.
|
|
23
|
+
const keyMaterial = await crypto.subtle.importKey("raw", entropy, "PBKDF2", false, ["deriveBits"]);
|
|
24
|
+
const derivedBits = await crypto.subtle.deriveBits({
|
|
25
|
+
name: "PBKDF2",
|
|
26
|
+
salt,
|
|
27
|
+
iterations,
|
|
28
|
+
hash
|
|
29
|
+
}, keyMaterial, outputLenBytes * 8);
|
|
30
|
+
return new Uint8Array(derivedBits);
|
|
31
|
+
};
|
|
17
32
|
|
|
18
33
|
const mnemonicToEntropy = mnemonic => {
|
|
19
34
|
return mnemonicToEntropy$1(mnemonic, wordlist);
|
|
@@ -21,22 +36,18 @@ const mnemonicToEntropy = mnemonic => {
|
|
|
21
36
|
const entropyToMnemonic = entropy => {
|
|
22
37
|
return entropyToMnemonic$1(entropy, wordlist);
|
|
23
38
|
};
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
c: 2048,
|
|
37
|
-
dkLen: 64
|
|
38
|
-
});
|
|
39
|
-
};
|
|
39
|
+
const entropyToSeedSubstrate = async (entropy, password) => await pbkdf2("SHA-512", entropy, mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
40
|
+
// 2048 iterations
|
|
41
|
+
32 // 32 bytes (32 * 8 == 256 bits)
|
|
42
|
+
);
|
|
43
|
+
const entropyToSeedClassic = async (entropy, password) => await pbkdf2("SHA-512", encodeNormalized(entropyToMnemonic(entropy)), mnemonicPasswordToSalt(password ?? ""), 2048,
|
|
44
|
+
// 2048 iterations
|
|
45
|
+
64 // 64 bytes (64 * 8 == 512 bits)
|
|
46
|
+
);
|
|
47
|
+
const mnemonicPasswordToSalt = password => encodeNormalized(`mnemonic${password}`);
|
|
48
|
+
|
|
49
|
+
/** Normalizes a UTF-8 string using `NFKD` form, then encodes it into bytes */
|
|
50
|
+
const encodeNormalized = utf8 => new TextEncoder().encode(utf8.normalize("NFKD"));
|
|
40
51
|
const getSeedDerivationType = curve => {
|
|
41
52
|
switch (curve) {
|
|
42
53
|
case "sr25519":
|
|
@@ -46,18 +57,21 @@ const getSeedDerivationType = curve => {
|
|
|
46
57
|
case "ethereum":
|
|
47
58
|
case "solana":
|
|
48
59
|
return "classic";
|
|
60
|
+
case "bitcoin-ecdsa":
|
|
61
|
+
case "bitcoin-ed25519":
|
|
62
|
+
throw new Error("seed derivation is not implemented for Bitcoin");
|
|
49
63
|
}
|
|
50
64
|
};
|
|
51
65
|
|
|
52
66
|
// when deriving keys from a mnemonic, we usually dont want a password here.
|
|
53
67
|
// a password provided here would be used as a 25th mnemonic word.
|
|
54
|
-
const entropyToSeed = (entropy, curve, password) => {
|
|
68
|
+
const entropyToSeed = async (entropy, curve, password) => {
|
|
55
69
|
const type = getSeedDerivationType(curve);
|
|
56
70
|
switch (type) {
|
|
57
71
|
case "classic":
|
|
58
|
-
return entropyToSeedClassic(entropy, password);
|
|
72
|
+
return await entropyToSeedClassic(entropy, password);
|
|
59
73
|
case "substrate":
|
|
60
|
-
return entropyToSeedSubstrate(entropy, password);
|
|
74
|
+
return await entropyToSeedSubstrate(entropy, password);
|
|
61
75
|
}
|
|
62
76
|
};
|
|
63
77
|
const isValidMnemonic = mnemonic => {
|
|
@@ -80,21 +94,21 @@ const DEV_MNEMONIC_ETHEREUM = "test test test test test test test test test test
|
|
|
80
94
|
|
|
81
95
|
// keep dev seeds in cache as we will reuse them to validate multiple derivation paths
|
|
82
96
|
const DEV_SEED_CACHE = new Map();
|
|
83
|
-
const getDevSeed = curve => {
|
|
97
|
+
const getDevSeed = async curve => {
|
|
84
98
|
const type = getSeedDerivationType(curve);
|
|
85
99
|
if (!DEV_SEED_CACHE.has(type)) {
|
|
86
100
|
switch (type) {
|
|
87
101
|
case "classic":
|
|
88
102
|
{
|
|
89
103
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_ETHEREUM);
|
|
90
|
-
const seed = entropyToSeedClassic(entropy); // 80ms
|
|
104
|
+
const seed = await entropyToSeedClassic(entropy); // 80ms
|
|
91
105
|
DEV_SEED_CACHE.set(type, seed);
|
|
92
106
|
break;
|
|
93
107
|
}
|
|
94
108
|
case "substrate":
|
|
95
109
|
{
|
|
96
110
|
const entropy = mnemonicToEntropy(DEV_MNEMONIC_POLKADOT);
|
|
97
|
-
const seed = entropyToSeedSubstrate(entropy); // 80ms
|
|
111
|
+
const seed = await entropyToSeedSubstrate(entropy); // 80ms
|
|
98
112
|
DEV_SEED_CACHE.set(type, seed);
|
|
99
113
|
break;
|
|
100
114
|
}
|
|
@@ -105,6 +119,26 @@ const getDevSeed = curve => {
|
|
|
105
119
|
return DEV_SEED_CACHE.get(type);
|
|
106
120
|
};
|
|
107
121
|
|
|
122
|
+
/** NOTE: Try not to use this too much, it will need to change */
|
|
123
|
+
const addressEncodingFromCurve = curve => {
|
|
124
|
+
switch (curve) {
|
|
125
|
+
case "sr25519":
|
|
126
|
+
case "ed25519":
|
|
127
|
+
case "ecdsa":
|
|
128
|
+
return "ss58";
|
|
129
|
+
case "bitcoin-ecdsa":
|
|
130
|
+
case "bitcoin-ed25519":
|
|
131
|
+
// NOTE: Bitcoin has multiple address formats, so this isn't necessarily correct
|
|
132
|
+
// The format MAY be bech32m, but it might also be bech32 or base58check.
|
|
133
|
+
// bech32m is the most recent format.
|
|
134
|
+
return "bech32m";
|
|
135
|
+
case "ethereum":
|
|
136
|
+
return "ethereum";
|
|
137
|
+
case "solana":
|
|
138
|
+
return "base58";
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
108
142
|
const encodeAddressBase58 = publicKey => {
|
|
109
143
|
return base58.encode(publicKey);
|
|
110
144
|
};
|
|
@@ -118,6 +152,94 @@ function isBase58Address(address) {
|
|
|
118
152
|
}
|
|
119
153
|
}
|
|
120
154
|
|
|
155
|
+
const isBitcoinAddress = address => isBech32mAddress(address) || isBech32Address(address) || isBase58CheckAddress(address);
|
|
156
|
+
function isBech32mAddress(address) {
|
|
157
|
+
try {
|
|
158
|
+
fromBech32m(address);
|
|
159
|
+
} catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
function isBech32Address(address) {
|
|
165
|
+
try {
|
|
166
|
+
fromBech32(address);
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
function isBase58CheckAddress(address) {
|
|
173
|
+
try {
|
|
174
|
+
fromBase58Check(address);
|
|
175
|
+
} catch {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Converts a Bech32m encoded address to its corresponding data representation.
|
|
183
|
+
* @param address - The Bech32m encoded address.
|
|
184
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
185
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
186
|
+
*/
|
|
187
|
+
function fromBech32m(address) {
|
|
188
|
+
const result = bech32m.decode(address);
|
|
189
|
+
const version = result.words[0];
|
|
190
|
+
if (version === 0) throw new TypeError(address + " uses wrong encoding");
|
|
191
|
+
const data = bech32m.fromWords(result.words.slice(1));
|
|
192
|
+
return {
|
|
193
|
+
version,
|
|
194
|
+
prefix: result.prefix,
|
|
195
|
+
data: Uint8Array.from(data)
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Converts a Bech32 encoded address to its corresponding data representation.
|
|
201
|
+
* @param address - The Bech32 encoded address.
|
|
202
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
203
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
204
|
+
*/
|
|
205
|
+
function fromBech32(address) {
|
|
206
|
+
const result = bech32.decode(address);
|
|
207
|
+
const version = result.words[0];
|
|
208
|
+
if (version !== 0) throw new TypeError(address + " uses wrong encoding");
|
|
209
|
+
const data = bech32.fromWords(result.words.slice(1));
|
|
210
|
+
return {
|
|
211
|
+
version,
|
|
212
|
+
prefix: result.prefix,
|
|
213
|
+
data: Uint8Array.from(data)
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Decodes a base58check encoded Bitcoin address and returns the version and hash.
|
|
219
|
+
*
|
|
220
|
+
* @param address - The base58check encoded Bitcoin address to decode.
|
|
221
|
+
* @returns An object containing the version and hash of the decoded address.
|
|
222
|
+
* @throws {TypeError} If the address is too short or too long.
|
|
223
|
+
*/
|
|
224
|
+
function fromBase58Check(address) {
|
|
225
|
+
const payload = bs58check.decode(address);
|
|
226
|
+
if (payload.length < 21) throw new TypeError(address + " is too short");
|
|
227
|
+
if (payload.length > 21) throw new TypeError(address + " is too long");
|
|
228
|
+
function readUInt8(buffer, offset) {
|
|
229
|
+
if (offset + 1 > buffer.length) {
|
|
230
|
+
throw new Error("Offset is outside the bounds of Uint8Array");
|
|
231
|
+
}
|
|
232
|
+
const buf = Buffer.from(buffer);
|
|
233
|
+
return buf.readUInt8(offset);
|
|
234
|
+
}
|
|
235
|
+
const version = readUInt8(payload, 0);
|
|
236
|
+
const hash = payload.slice(1);
|
|
237
|
+
return {
|
|
238
|
+
version,
|
|
239
|
+
hash
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
121
243
|
/**
|
|
122
244
|
* Encodes a public key using H160 encoding with Ethereum checksum.
|
|
123
245
|
*/
|
|
@@ -205,23 +327,13 @@ function isSs58Address(address) {
|
|
|
205
327
|
}
|
|
206
328
|
}
|
|
207
329
|
|
|
208
|
-
const addressEncodingFromCurve = curve => {
|
|
209
|
-
switch (curve) {
|
|
210
|
-
case "sr25519":
|
|
211
|
-
case "ed25519":
|
|
212
|
-
case "ecdsa":
|
|
213
|
-
return "ss58";
|
|
214
|
-
case "ethereum":
|
|
215
|
-
return "ethereum";
|
|
216
|
-
case "solana":
|
|
217
|
-
return "base58";
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
330
|
const CACHE$1 = new Map();
|
|
222
331
|
const detectAddressEncodingInner = address => {
|
|
223
332
|
if (isEthereumAddress(address)) return "ethereum";
|
|
224
333
|
if (isSs58Address(address)) return "ss58";
|
|
334
|
+
if (isBech32mAddress(address)) return "bech32m";
|
|
335
|
+
if (isBech32Address(address)) return "bech32";
|
|
336
|
+
if (isBase58CheckAddress(address)) return "base58check";
|
|
225
337
|
if (isBase58Address(address)) return "base58";
|
|
226
338
|
throw new Error(`Unknown address encoding`);
|
|
227
339
|
};
|
|
@@ -236,6 +348,10 @@ const addressFromPublicKey = (publicKey, encoding, options) => {
|
|
|
236
348
|
return encodeAddressSs58(publicKey, options?.ss58Prefix);
|
|
237
349
|
case "ethereum":
|
|
238
350
|
return encodeAddressEthereum(publicKey);
|
|
351
|
+
case "bech32m":
|
|
352
|
+
case "bech32":
|
|
353
|
+
case "base58check":
|
|
354
|
+
throw new Error("addressFromPublicKey is not implemented for Bitcoin");
|
|
239
355
|
case "base58":
|
|
240
356
|
return encodeAddressBase58(publicKey);
|
|
241
357
|
}
|
|
@@ -258,6 +374,9 @@ const normalizeAnyAddress = address => {
|
|
|
258
374
|
switch (detectAddressEncoding(address)) {
|
|
259
375
|
case "ethereum":
|
|
260
376
|
return checksumEthereumAddress(address);
|
|
377
|
+
case "bech32m":
|
|
378
|
+
case "bech32":
|
|
379
|
+
case "base58check":
|
|
261
380
|
case "base58":
|
|
262
381
|
return address;
|
|
263
382
|
case "ss58":
|
|
@@ -438,6 +557,9 @@ const deriveKeypair = (seed, derivationPath, curve) => {
|
|
|
438
557
|
return deriveEd25519(seed, derivationPath);
|
|
439
558
|
case "ecdsa":
|
|
440
559
|
return deriveEcdsa(seed, derivationPath);
|
|
560
|
+
case "bitcoin-ecdsa":
|
|
561
|
+
case "bitcoin-ed25519":
|
|
562
|
+
throw new Error("deriveKeypair is not implemented for Bitcoin");
|
|
441
563
|
case "ethereum":
|
|
442
564
|
return deriveEthereum(seed, derivationPath);
|
|
443
565
|
case "solana":
|
|
@@ -454,18 +576,21 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
454
576
|
return getPublicKeySr25519(secretKey);
|
|
455
577
|
case "ed25519":
|
|
456
578
|
return getPublicKeyEd25519(secretKey);
|
|
579
|
+
case "bitcoin-ecdsa":
|
|
580
|
+
case "bitcoin-ed25519":
|
|
581
|
+
throw new Error("getPublicKeyFromSecret is not implemented for Bitcoin");
|
|
457
582
|
case "solana":
|
|
458
583
|
return getPublicKeySolana(secretKey);
|
|
459
584
|
}
|
|
460
585
|
};
|
|
461
|
-
const addressFromSuri = (suri, type) => {
|
|
586
|
+
const addressFromSuri = async (suri, type) => {
|
|
462
587
|
const {
|
|
463
588
|
mnemonic,
|
|
464
589
|
derivationPath,
|
|
465
590
|
password
|
|
466
591
|
} = parseSuri(suri);
|
|
467
592
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
468
|
-
const seed = entropyToSeed(entropy, type, password); // ~80ms
|
|
593
|
+
const seed = await entropyToSeed(entropy, type, password); // ~80ms
|
|
469
594
|
const {
|
|
470
595
|
secretKey
|
|
471
596
|
} = deriveKeypair(seed, derivationPath, type);
|
|
@@ -509,15 +634,17 @@ const parseSecretKey = (secretKey, curve) => {
|
|
|
509
634
|
case "ed25519":
|
|
510
635
|
case "sr25519":
|
|
511
636
|
case "ecdsa":
|
|
637
|
+
case "bitcoin-ecdsa":
|
|
638
|
+
case "bitcoin-ed25519":
|
|
512
639
|
case "solana":
|
|
513
640
|
throw new Error("Not implemented");
|
|
514
641
|
}
|
|
515
642
|
};
|
|
516
643
|
|
|
517
644
|
// @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) => {
|
|
645
|
+
const isValidDerivationPath = async (derivationPath, curve) => {
|
|
519
646
|
try {
|
|
520
|
-
deriveKeypair(getDevSeed(curve), derivationPath, curve);
|
|
647
|
+
deriveKeypair(await getDevSeed(curve), derivationPath, curve);
|
|
521
648
|
return true;
|
|
522
649
|
} catch (err) {
|
|
523
650
|
return false;
|
|
@@ -532,6 +659,9 @@ const platformFromCurve = curve => {
|
|
|
532
659
|
return "polkadot";
|
|
533
660
|
case "ethereum":
|
|
534
661
|
return "ethereum";
|
|
662
|
+
case "bitcoin-ecdsa":
|
|
663
|
+
case "bitcoin-ed25519":
|
|
664
|
+
return "bitcoin";
|
|
535
665
|
case "solana":
|
|
536
666
|
return "solana";
|
|
537
667
|
}
|
|
@@ -542,6 +672,10 @@ const platformFromEncoding = encoding => {
|
|
|
542
672
|
return "polkadot";
|
|
543
673
|
case "ethereum":
|
|
544
674
|
return "ethereum";
|
|
675
|
+
case "bech32m":
|
|
676
|
+
case "bech32":
|
|
677
|
+
case "base58check":
|
|
678
|
+
return "bitcoin";
|
|
545
679
|
case "base58":
|
|
546
680
|
return "solana";
|
|
547
681
|
}
|
|
@@ -551,4 +685,4 @@ const platformFromAddress = address => {
|
|
|
551
685
|
return platformFromEncoding(encoding);
|
|
552
686
|
};
|
|
553
687
|
|
|
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 };
|
|
688
|
+
export { DEV_MNEMONIC_ETHEREUM, DEV_MNEMONIC_POLKADOT, addressEncodingFromCurve, addressFromPublicKey, addressFromSuri, blake2b256, blake2b512, blake3, checksumEthereumAddress, decodeSs58Address, deriveKeypair, detectAddressEncoding, encodeAddressBase58, encodeAddressEthereum, encodeAddressSs58, entropyToMnemonic, entropyToSeed, fromBase58Check, fromBech32, fromBech32m, generateMnemonic, getDevSeed, getPublicKeyFromSecret, getSafeHash, isAddressEqual, isBase58Address, isBase58CheckAddress, isBech32Address, isBech32mAddress, isBitcoinAddress, 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.3",
|
|
4
4
|
"author": "Talisman",
|
|
5
5
|
"homepage": "https://talisman.xyz",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
"@scure/base": "1.2.4",
|
|
28
28
|
"@scure/bip32": "1.6.2",
|
|
29
29
|
"@scure/bip39": "1.5.4",
|
|
30
|
+
"bech32": "2.0.0",
|
|
31
|
+
"bs58check": "4.0.0",
|
|
30
32
|
"micro-sr25519": "0.1.3",
|
|
31
33
|
"scale-ts": "1.6.1"
|
|
32
34
|
},
|
|
@@ -36,8 +38,8 @@
|
|
|
36
38
|
"jest": "^29.7.0",
|
|
37
39
|
"ts-jest": "^29.2.5",
|
|
38
40
|
"typescript": "^5.6.3",
|
|
39
|
-
"@talismn/
|
|
40
|
-
"@talismn/
|
|
41
|
+
"@talismn/eslint-config": "0.0.3",
|
|
42
|
+
"@talismn/tsconfig": "0.0.2"
|
|
41
43
|
},
|
|
42
44
|
"preconstruct": {
|
|
43
45
|
"entrypoints": [
|