@metamask/key-tree
An interface over SLIP-10, BIP-32, and BIP-44 key derivation paths.
This library was audited by Cure53 in February 2023. The audit report can be found here (PDF).
Installation
yarn add @metamask/key-tree
or
npm install @metamask/key-tree
Usage
This package is designed to accommodate the creation of keys for any level of a SLIP-10 or BIP-44 path.
Recall that a BIP-44 HD tree path consists of the following nodes (and depths):
m / 44' / coin_type' / account' / change / address_index
0 / 1 / 2 / 3 / 4 / 5
Where m
is the "master" or seed node, coin_type
indicates the protocol for which deeper keys are intended,
and address_index
usually furnishes key pairs intended for user addresses / accounts.
For details, refer to the BIP-44 specification.
For the authoritative list of protocol coin_type
indices, see SLIP-44.
The SLIP-10 interface provides a more generic way for deriving keys, which is not constrained to the BIP-44 path
nodes. Currently only Secp256k1 and Ed25519 are supported for SLIP-10, but NIST P-256 may be added if there is
sufficient demand for it.
This package exports a few classes intended to facilitate the creation of keys in contexts with different privileges.
They are used as follows.
import { BIP44CoinTypeNode } from '@metamask/key-tree';
const coinType = 60;
const secretRecoveryPhrase = getSecretRecoveryPhrase();
const coinTypeNode = await BIP44CoinTypeNode.fromDerivationPath([
`bip39:${secretRecoveryPhrase}`,
`bip32:44'`,
`bip32:${coinType}'`,
]);
stream.write(coinTypeNode.toJSON());
import { getBIP44AddressKeyDeriver } from '@metamask/key-tree';
const coinTypeNode = await getCoinTypeNode();
const addressKeyDeriver = getBIP44AddressKeyDeriver(coinTypeNode);
const addressKey0 = await addressKeyDeriver(0);
const addressKey1 = await addressKeyDeriver(1);
const addressKey2 = await addressKeyDeriver(2, true);
You can derive SLIP-10 keys as follows.
import { SLIP10Node } from '@metamask/key-tree';
const node = await SLIP10Node.fromDerivationPath({
curve: 'secp256k1',
derivationPath: [`bip39:${secretRecoveryPhrase}`, `slip10:0'`],
});
const ed25519Node = await SLIP10Node.fromDerivationPath({
curve: 'ed25519',
derivationPath: [`bip39:${secretRecoveryPhrase}`, `slip10:0'`],
});
const childNode = await node.derive([`slip10:1'`, `slip10:2'`]);
The SLIP10Node
class supports both bip32:
and slip10:
paths. While BIP-32 and SLIP-10 are mostly compatible with
each other, there are some differences:
- Ed25519 is only supported by SLIP-10, so you must use
slip10:
paths when deriving Ed25519 keys. - Key derivation errors (i.e., invalid keys being derived) are handled slightly different. While the chance of
encountering such an error is extremely low, it is possible.
If you require full compatibility with one or the other, you can choose between the bip32:
and slip10:
path types.
There are other ways of deriving keys in addition to the above example.
See the docstrings in the BIP44Node, BIP44CoinTypeNode and
SLIP10Node files for details.
Internals
This package also has methods for deriving arbitrary SLIP-10 and BIP-32 keys, and generating seeds from BIP-39
secret recovery phrases.
These methods do not constitute a safe key derivation API, and their use is strongly discouraged.
Nevertheless, since those methods were the main exports of this package prior to version 3.0.0
, consumers can
still access them by importing @metamask/key-tree/derivation
.
Security
This package is rigorously tested against reference implementations and the SLIP-10 and BIP-32 specifications.
See the reference implementation tests for details.
Further Reading