Socket
Socket
Sign inDemoInstall

@metamask/key-tree

Package Overview
Dependencies
Maintainers
7
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@metamask/key-tree - npm Package Compare versions

Comparing version 2.0.1 to 3.0.0

dist/BIP44CoinTypeNode.d.ts

34

CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file.

@@ -10,6 +9,17 @@

## [3.0.0]
### Changed
- **BREAKING:** Refactor package API ([#25](https://github.com/MetaMask/key-tree/pull/25))
- The new API is designed to make it harder to derive incorrect keys.
- The previous exports of this package can no longer be accessed from the main entry file.
- For the new API, please see [the README](https://github.com/MetaMask/key-tree/blob/1743ef1bb2ca4603c6e2861b975bf2b4d60a0dbc/README.md).
- **BREAKING:** Bump minimum Node.js version to >=12.0.0 ([#20](https://github.com/MetaMask/key-tree/pull/20))
### Security
- Add reference implementation tests ([#25](https://github.com/MetaMask/key-tree/pull/25))
- The key derivation of this package is now tested against the BIP-32 specification and [`ethereumjs-wallet`](https://github.com/ethereumjs/ethereumjs-wallet) and [`@metamask/eth-hd-keyring`](https://github.com/MetaMask/eth-hd-keyring).
- The key derivation was found to be sound.
## [2.0.1] - 2021-02-27
### Fixed
- Correctly type `deriveKeyFromPath` `parentKey` param as optional ([#14](https://github.com/MetaMask/key-tree/pull/14))

@@ -19,15 +29,15 @@ - Only accept lowercase BIP-39 seed phrases in `deriveKeyFromPath` ([#15](https://github.com/MetaMask/key-tree/pull/15))

## [2.0.0] - 2021-02-25
### Changed
- **(BREAKING)** Add input validation to `deriveKeyFromPath` ([#3](https://github.com/MetaMask/key-tree/pull/3), [#4](https://github.com/MetaMask/key-tree/pull/4))
- **(BREAKING)** Change `deriveKeyFromPath` parameter order ([#3](https://github.com/MetaMask/key-tree/pull/3))
- **BREAKING:** Add input validation to `deriveKeyFromPath` ([#3](https://github.com/MetaMask/key-tree/pull/3), [#4](https://github.com/MetaMask/key-tree/pull/4))
- **BREAKING:** Change `deriveKeyFromPath` parameter order ([#3](https://github.com/MetaMask/key-tree/pull/3))
- Migrate to TypeScript, update types ([#10](https://github.com/MetaMask/key-tree/pull/10))
## [1.0.0] - 2020-09-03
### Added
- Initial release.
Initial release.
[Unreleased]:https://github.com/MetaMask/key-tree/compare/v2.0.0...HEAD
[2.0.0]:https://github.com/MetaMask/key-tree/compare/v1.0.0...v2.0.0
[1.0.0]:https://github.com/MetaMask/key-tree/compare/a29b75...v1.0.0
[Unreleased]: https://github.com/MetaMask/key-tree/compare/v3.0.0...HEAD
[3.0.0]: https://github.com/MetaMask/key-tree/compare/v2.0.1...v3.0.0
[2.0.1]: https://github.com/MetaMask/key-tree/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/MetaMask/key-tree/compare/v1.0.0...v2.0.0
[1.0.0]: https://github.com/MetaMask/key-tree/releases/tag/v1.0.0
/// <reference types="node" />
export declare function privateKeyToEthAddress(keyBuffer: Buffer): Buffer;
export declare function bip32PathToMultipath(bip32Path: string): string;
/**
* Converts a BIP-32 private key to an Ethereum address.
*
* **WARNING:** Only validates that the key is non-zero and of the correct
* length. It is the consumer's responsibility to ensure that the specified
* key is a valid BIP-44 Ethereum `address_index` key.
*
* @param key - The `address_index` key buffer to convert to an Ethereum
* address.
* @returns The Ethereum address corresponding to the given key.
*/
export declare function privateKeyToEthAddress(key: Buffer): Buffer;
/**
* @param pathPart
* @param parentKey
*/
export declare function deriveChildKey(pathPart: string, parentKey: Buffer): Buffer;

@@ -6,39 +6,65 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.deriveChildKey = exports.bip32PathToMultipath = exports.privateKeyToEthAddress = void 0;
// node
exports.deriveChildKey = exports.privateKeyToEthAddress = void 0;
const crypto_1 = __importDefault(require("crypto"));
const assert_1 = __importDefault(require("assert"));
// npm
const secp256k1_1 = __importDefault(require("secp256k1"));
const keccak_1 = __importDefault(require("keccak"));
const constants_1 = require("../constants");
const utils_1 = require("../utils");
const HARDENED_OFFSET = 0x80000000;
function privateKeyToEthAddress(keyBuffer) {
const privateKey = keyBuffer.slice(0, 32);
const publicKey = secp256k1_1.default.publicKeyCreate(privateKey, false).slice(1);
return keccak(publicKey).slice(-20);
/**
* Converts a BIP-32 private key to an Ethereum address.
*
* **WARNING:** Only validates that the key is non-zero and of the correct
* length. It is the consumer's responsibility to ensure that the specified
* key is a valid BIP-44 Ethereum `address_index` key.
*
* @param key - The `address_index` key buffer to convert to an Ethereum
* address.
* @returns The Ethereum address corresponding to the given key.
*/
function privateKeyToEthAddress(key) {
if (!Buffer.isBuffer(key) || !utils_1.isValidBufferKey(key)) {
throw new Error('Invalid key: The key must be a 64-byte, non-zero Buffer.');
}
const privateKey = key.slice(0, 32);
const publicKey = secp256k1_1.default
.publicKeyCreate(new Uint8Array(privateKey), false)
.slice(1);
return keccak(Buffer.from(publicKey)).slice(-20);
}
exports.privateKeyToEthAddress = privateKeyToEthAddress;
function keccak(a, bits = '256') {
return keccak_1.default(`keccak${bits}`).update(a).digest();
/**
* @param data
* @param keccakBits
*/
function keccak(data, keccakBits = '256') {
return keccak_1.default(`keccak${keccakBits}`).update(data).digest();
}
function bip32PathToMultipath(bip32Path) {
let pathParts = bip32Path.trim().split('/');
// strip "m" noop
if (pathParts[0].toLowerCase() === 'm') {
pathParts = pathParts.slice(1);
/**
* @param pathPart
* @param parentKey
*/
function deriveChildKey(pathPart, parentKey) {
if (!parentKey) {
throw new Error('Invalid parameters: Must specify a parent key.');
}
const multipath = pathParts.map((part) => `bip32:${part}`).join('/');
return multipath;
}
exports.bip32PathToMultipath = bip32PathToMultipath;
function deriveChildKey(pathPart, parentKey) {
if (parentKey.length !== constants_1.BUFFER_KEY_LENGTH) {
throw new Error('Invalid parent key: Must be 64 bytes long.');
}
const isHardened = pathPart.includes(`'`);
const indexPart = pathPart.split(`'`)[0];
const childIndex = parseInt(indexPart, 10);
assert_1.default(childIndex < HARDENED_OFFSET, 'Invalid index');
assert_1.default(Boolean(parentKey), 'Must provide parentKey');
assert_1.default(parentKey.length === 64, 'Parent key invalid length');
if (!/^\d+$/u.test(indexPart) ||
!Number.isInteger(childIndex) ||
childIndex < 0 ||
childIndex >= HARDENED_OFFSET) {
throw new Error(`Invalid BIP-32 index: The index must be a non-negative decimal integer less than ${HARDENED_OFFSET}.`);
}
const parentPrivateKey = parentKey.slice(0, 32);
const parentExtraEntropy = parentKey.slice(32);
const secretExtension = deriveSecretExtension({ parentPrivateKey, childIndex, isHardened });
const secretExtension = deriveSecretExtension({
parentPrivateKey,
childIndex,
isHardened,
});
const { privateKey, extraEntropy } = generateKey({

@@ -53,3 +79,9 @@ parentPrivateKey,

// the bip32 secret extension is created from the parent private or public key and the child index
function deriveSecretExtension({ parentPrivateKey, childIndex, isHardened }) {
/**
* @param options
* @param options.parentPrivateKey
* @param options.childIndex
* @param options.isHardened
*/
function deriveSecretExtension({ parentPrivateKey, childIndex, isHardened, }) {
if (isHardened) {

@@ -66,13 +98,22 @@ // Hardened child

indexBuffer.writeUInt32BE(childIndex, 0);
const parentPublicKey = secp256k1_1.default.publicKeyCreate(parentPrivateKey, true);
const parentPublicKey = secp256k1_1.default.publicKeyCreate(new Uint8Array(parentPrivateKey), true);
return Buffer.concat([parentPublicKey, indexBuffer]);
}
function generateKey({ parentPrivateKey, parentExtraEntropy, secretExtension }) {
const entropy = crypto_1.default.createHmac('sha512', parentExtraEntropy).update(secretExtension).digest();
/**
* @param options
* @param options.parentPrivateKey
* @param options.parentExtraEntropy
* @param options.secretExtension
*/
function generateKey({ parentPrivateKey, parentExtraEntropy, secretExtension, }) {
const entropy = crypto_1.default
.createHmac('sha512', parentExtraEntropy)
.update(secretExtension)
.digest();
const keyMaterial = entropy.slice(0, 32);
// extraEntropy is also called "chaincode"
const extraEntropy = entropy.slice(32);
const privateKey = secp256k1_1.default.privateKeyTweakAdd(parentPrivateKey, keyMaterial);
const privateKey = secp256k1_1.default.privateKeyTweakAdd(new Uint8Array(parentPrivateKey), new Uint8Array(keyMaterial));
return { privateKey, extraEntropy };
}
//# sourceMappingURL=bip32.js.map
/// <reference types="node" />
export declare function bip39MnemonicToMultipath(mnemonic: string): string;
import { BIP39Node } from '../constants';
/**
* @param mnemonic
*/
export declare function bip39MnemonicToMultipath(mnemonic: string): BIP39Node;
/**
* @param pathPart
* @param _parentKey
*/
export declare function deriveChildKey(pathPart: string, _parentKey?: never): Buffer;
/**
* @param seed - The cryptographic seed bytes.
* @returns The bytes of the corresponding BIP-39 master key.
*/
export declare function createBip39KeyFromSeed(seed: Buffer): Buffer;

@@ -6,6 +6,11 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.deriveChildKey = exports.bip39MnemonicToMultipath = void 0;
exports.createBip39KeyFromSeed = exports.deriveChildKey = exports.bip39MnemonicToMultipath = void 0;
const crypto_1 = __importDefault(require("crypto"));
const bip39_1 = __importDefault(require("bip39"));
const bip39_1 = require("bip39");
// This magic constant is analogous to a salt, and is consistent across all
// major BIP-32 implementations.
const ROOT_BASE_SECRET = Buffer.from('Bitcoin seed', 'utf8');
/**
* @param mnemonic
*/
function bip39MnemonicToMultipath(mnemonic) {

@@ -16,9 +21,18 @@ return `bip39:${mnemonic.toLowerCase().trim()}`;

// this creates a child key using bip39, ignoring the parent key
/**
* @param pathPart
* @param _parentKey
*/
function deriveChildKey(pathPart, _parentKey) {
const mnemonic = pathPart;
const seedBuffer = bip39_1.default.mnemonicToSeed(mnemonic);
const entropy = crypto_1.default.createHmac('sha512', ROOT_BASE_SECRET).update(seedBuffer).digest();
return entropy;
return createBip39KeyFromSeed(bip39_1.mnemonicToSeedSync(pathPart));
}
exports.deriveChildKey = deriveChildKey;
/**
* @param seed - The cryptographic seed bytes.
* @returns The bytes of the corresponding BIP-39 master key.
*/
function createBip39KeyFromSeed(seed) {
return crypto_1.default.createHmac('sha512', ROOT_BASE_SECRET).update(seed).digest();
}
exports.createBip39KeyFromSeed = createBip39KeyFromSeed;
//# sourceMappingURL=bip39.js.map
/// <reference types="node" />
export { BIP44Node, BIP44NodeInterface, JsonBIP44Node } from './BIP44Node';
export { BIP44CoinTypeNode, BIP44CoinTypeNodeInterface, BIP_44_COIN_TYPE_DEPTH, CoinTypeHDPathTuple, deriveBIP44AddressKey, getBIP44AddressKeyDeriver, JsonBIP44CoinTypeNode, } from './BIP44CoinTypeNode';
export { MIN_BIP_44_DEPTH, MAX_BIP_44_DEPTH, BIP44Depth, BIP44PurposeNodeToken, BIP32Node, BIP39Node, } from './constants';
/**
* Converts the given BIP-39 mnemonic to a cryptographic seed.
* @param mnemonic - The BIP-39 mnemonic.
* @returns The cryptographic seed corresponding to the given mnemonic.
* The {@link Buffer} accessible to `@metamask/key-tree`, re-exported in case
* of module resolution issues.
*/
export declare function mnemonicToSeed(mnemonic: string): Buffer;
/**
* ethereum default seed path: "m/44'/60'/0'/0/{account_index}"
* multipath: "bip32:44'/bip32:60'/bip32:0'/bip32:0/bip32:{account_index}"
*
* m: { privateKey, chainCode } = sha512Hmac("Bitcoin seed", masterSeed)
* 44': { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [0x00, parentKey.privateKey, index + HARDENED_OFFSET])
* 60': { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [0x00, parentKey.privateKey, index + HARDENED_OFFSET])
* 0': { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [0x00, parentKey.privateKey, index + HARDENED_OFFSET])
* 0: { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [parentKey.publicKey, index])
* 0: { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [parentKey.publicKey, index])
*/
/**
* Takes a full or partial HD path string and returns the key corresponding to
* the given path, with the following constraints:
*
* - If the path starts with a BIP-32 segment, a parent key must be provided.
* - If the path starts with a BIP-39 segment, a parent key may NOT be provided.
* - The path cannot exceed 5 BIP-32 segments in length, optionally preceded by
* a single BIP-39 segment.
*
* WARNING: It is the consumer's responsibility to ensure that the path is valid
* relative to its parent key.
*
* @param pathSegment - A full or partial HD path, e.g.:
* bip39:SEED_PHRASE/bip32:44'/bip32:60'/bip32:0'/bip32:0/bip32:0
*
* BIP-39 seed phrases must be lowercase, space-delimited, and 12-24 words long.
*
* @param parentKey - The parent key of the given path segment, if any.
* @returns The derived key.
*/
export declare function deriveKeyFromPath(pathSegment: string, parentKey?: Buffer): Buffer;
export declare const PackageBuffer: typeof Buffer;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deriveKeyFromPath = exports.mnemonicToSeed = void 0;
const bip39_1 = __importDefault(require("bip39"));
const derivers_1 = require("./derivers");
exports.PackageBuffer = exports.BIP44PurposeNodeToken = exports.MAX_BIP_44_DEPTH = exports.MIN_BIP_44_DEPTH = exports.getBIP44AddressKeyDeriver = exports.deriveBIP44AddressKey = exports.BIP_44_COIN_TYPE_DEPTH = exports.BIP44CoinTypeNode = exports.BIP44Node = void 0;
var BIP44Node_1 = require("./BIP44Node");
Object.defineProperty(exports, "BIP44Node", { enumerable: true, get: function () { return BIP44Node_1.BIP44Node; } });
var BIP44CoinTypeNode_1 = require("./BIP44CoinTypeNode");
Object.defineProperty(exports, "BIP44CoinTypeNode", { enumerable: true, get: function () { return BIP44CoinTypeNode_1.BIP44CoinTypeNode; } });
Object.defineProperty(exports, "BIP_44_COIN_TYPE_DEPTH", { enumerable: true, get: function () { return BIP44CoinTypeNode_1.BIP_44_COIN_TYPE_DEPTH; } });
Object.defineProperty(exports, "deriveBIP44AddressKey", { enumerable: true, get: function () { return BIP44CoinTypeNode_1.deriveBIP44AddressKey; } });
Object.defineProperty(exports, "getBIP44AddressKeyDeriver", { enumerable: true, get: function () { return BIP44CoinTypeNode_1.getBIP44AddressKeyDeriver; } });
var constants_1 = require("./constants");
Object.defineProperty(exports, "MIN_BIP_44_DEPTH", { enumerable: true, get: function () { return constants_1.MIN_BIP_44_DEPTH; } });
Object.defineProperty(exports, "MAX_BIP_44_DEPTH", { enumerable: true, get: function () { return constants_1.MAX_BIP_44_DEPTH; } });
Object.defineProperty(exports, "BIP44PurposeNodeToken", { enumerable: true, get: function () { return constants_1.BIP44PurposeNodeToken; } });
/**
* Converts the given BIP-39 mnemonic to a cryptographic seed.
* @param mnemonic - The BIP-39 mnemonic.
* @returns The cryptographic seed corresponding to the given mnemonic.
* The {@link Buffer} accessible to `@metamask/key-tree`, re-exported in case
* of module resolution issues.
*/
function mnemonicToSeed(mnemonic) {
return bip39_1.default.mnemonicToSeed(mnemonic);
}
exports.mnemonicToSeed = mnemonicToSeed;
/**
* ethereum default seed path: "m/44'/60'/0'/0/{account_index}"
* multipath: "bip32:44'/bip32:60'/bip32:0'/bip32:0/bip32:{account_index}"
*
* m: { privateKey, chainCode } = sha512Hmac("Bitcoin seed", masterSeed)
* 44': { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [0x00, parentKey.privateKey, index + HARDENED_OFFSET])
* 60': { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [0x00, parentKey.privateKey, index + HARDENED_OFFSET])
* 0': { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [0x00, parentKey.privateKey, index + HARDENED_OFFSET])
* 0: { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [parentKey.publicKey, index])
* 0: { privateKey, chainCode } = parentKey.privateKey + sha512Hmac(parentKey.chainCode, [parentKey.publicKey, index])
*/
/**
* Takes a full or partial HD path string and returns the key corresponding to
* the given path, with the following constraints:
*
* - If the path starts with a BIP-32 segment, a parent key must be provided.
* - If the path starts with a BIP-39 segment, a parent key may NOT be provided.
* - The path cannot exceed 5 BIP-32 segments in length, optionally preceded by
* a single BIP-39 segment.
*
* WARNING: It is the consumer's responsibility to ensure that the path is valid
* relative to its parent key.
*
* @param pathSegment - A full or partial HD path, e.g.:
* bip39:SEED_PHRASE/bip32:44'/bip32:60'/bip32:0'/bip32:0/bip32:0
*
* BIP-39 seed phrases must be lowercase, space-delimited, and 12-24 words long.
*
* @param parentKey - The parent key of the given path segment, if any.
* @returns The derived key.
*/
function deriveKeyFromPath(pathSegment, parentKey) {
validateDeriveKeyParams(pathSegment, parentKey);
let key = parentKey;
// derive through each part of path
pathSegment.split('/').forEach((path) => {
const [pathType, pathValue] = path.split(':');
if (!(hasDeriver(pathType))) {
throw new Error(`Unknown derivation type "${pathType}"`);
}
const deriver = derivers_1.derivers[pathType];
const childKey = deriver.deriveChildKey(pathValue, key);
// continue deriving from child key
key = childKey;
});
return key;
}
exports.deriveKeyFromPath = deriveKeyFromPath;
function hasDeriver(pathType) {
return pathType in derivers_1.derivers;
}
/**
* e.g.
* - bip32:0
* - bip32:0'
*/
const BIP_32_PATH_REGEX = /^bip32:\d+'?$/u;
/**
* bip39:<SPACE_DELMITED_SEED_PHRASE>
*
* The seed phrase must consist of 12 <= 24 words.
*/
const BIP_39_PATH_REGEX = /^bip39:([a-z]+){1}( [a-z]+){11,23}$/u;
/**
* e.g.
* - bip32:44'/bip32:60'/bip32:0'/bip32:0/bip32:0
* - bip39:<SPACE_DELMITED_SEED_PHRASE>/bip32:44'/bip32:60'/bip32:0'/bip32:0/bip32:0
*/
const MULTI_PATH_REGEX = /^(bip39:([a-z]+){1}( [a-z]+){11,23}\/)?(bip32:\d+'?\/){0,4}(bip32:\d+'?)$/u;
function validateDeriveKeyParams(pathSegment, parentKey) {
// The path segment must be one of the following:
// - A lone BIP-32 path segment
// - A lone BIP-39 path segment
// - A multipath
if (!(BIP_32_PATH_REGEX.test(pathSegment) ||
BIP_39_PATH_REGEX.test(pathSegment) ||
MULTI_PATH_REGEX.test(pathSegment))) {
throw new Error('Invalid HD path segment. Ensure that the HD path segment is correctly formatted.');
}
// BIP-39 segments can only initiate HD paths
if (BIP_39_PATH_REGEX.test(pathSegment) && parentKey) {
throw new Error('May not specify parent key and BIP-39 path segment.');
}
// BIP-32 segments cannot initiate HD paths
if (!pathSegment.startsWith('bip39') && !parentKey) {
throw new Error('Must specify parent key if the first path of the path segment is not BIP-39.');
}
// The parent key must be a Buffer
if (parentKey && !Buffer.isBuffer(parentKey)) {
throw new Error('Parent key must be a Buffer if specified.');
}
}
exports.PackageBuffer = Buffer;
//# sourceMappingURL=index.js.map
{
"name": "@metamask/key-tree",
"version": "2.0.1",
"version": "3.0.0",
"description": "An interface over BIP-32 and BIP-39 key derivation paths.",
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/key-tree.git"
},
"license": "MIT",
"author": "kumavis",
"main": "dist/index.js",

@@ -11,28 +17,59 @@ "files": [

"build": "tsc --project .",
"lint": "eslint . --ext ts,js,json",
"lint:fix": "yarn lint --fix",
"test": "yarn build && node ./test/index.js",
"test:nobuild": "node ./test/index.js",
"prepublishOnly": "yarn lint && yarn test"
"build:clean": "rimraf dist && yarn build",
"lint": "yarn lint:eslint && yarn lint:misc --check",
"lint:eslint": "eslint . --cache --ext js,ts",
"lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write",
"lint:misc": "prettier '**/*.json' '**/*.md' '!CHANGELOG.md' '**/*.yml' --ignore-path .gitignore",
"prepublishOnly": "yarn build:clean && yarn lint && yarn test",
"setup": "yarn install && yarn allow-scripts",
"test": "jest",
"test:watch": "jest --watch"
},
"author": "kumavis",
"license": "MIT",
"dependencies": {
"bip39": "^2.5.0",
"ethereumjs-util": "^5.2.0",
"keccak": "^1.4.0",
"secp256k1": "^3.5.0"
"bip39": "^3.0.4",
"keccak": "^3.0.2",
"secp256k1": "^4.0.2"
},
"devDependencies": {
"@metamask/eslint-config": "^5.0.0",
"@lavamoat/allow-scripts": "^1.0.6",
"@metamask/auto-changelog": "^2.5.0",
"@metamask/eslint-config": "^8.0.0",
"@metamask/eslint-config-jest": "^8.0.0",
"@metamask/eslint-config-nodejs": "^8.0.0",
"@metamask/eslint-config-typescript": "^8.0.0",
"@types/jest": "^27.0.2",
"@types/keccak": "^3.0.1",
"@typescript-eslint/eslint-plugin": "^4.15.2",
"@typescript-eslint/parser": "^4.15.2",
"eslint": "^7.20.0",
"@types/secp256k1": "^4.0.3",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^7.23.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-json": "^2.1.2",
"eslint-plugin-jest": "^24.3.4",
"eslint-plugin-jsdoc": "^36.1.1",
"eslint-plugin-node": "^11.1.0",
"tape": "^4.9.1",
"typescript": "4.1.5"
"eslint-plugin-prettier": "^4.0.0",
"eth-hd-keyring": "^3.6.0",
"ethereumjs-wallet": "^1.0.2",
"jest": "^27.2.5",
"prettier": "^2.4.1",
"prettier-plugin-packagejson": "^2.2.13",
"rimraf": "^3.0.2",
"ts-jest": "^27.0.6",
"typescript": "4.3.5"
},
"engines": {
"node": ">=12.0.0"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"lavamoat": {
"allowScripts": {
"@lavamoat/preinstall-always-fail": false,
"keccak": true,
"secp256k1": true
}
}
}
# @metamask/key-tree
```text
yarn add @metamask/key-tree
An interface over [BIP-44] key derivation paths.
## 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 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].
This package exports two classes intended to facilitate the creation of keys in contexts with different privileges.
They are used as follows.
```typescript
import { BIP44CoinTypeNode } from '@metamask/key-tree';
// Per SLIP-44, Ethereum has a coin_type of 60.
// Ethereum is only used by way of example.
const coinType = 60;
// Imagine that this takes place in some privileged context with access to
// the user's mnemonic.
const mnemonic = getMnemonic();
const coinTypeNode = new BIP44CoinTypeNode([
`bip39:${mnemonic}`,
`bip32:44'`, // By BIP-44, the "purpose" node must be "44'"
`bip32:${coinType}'`,
]);
// Imagine that this is some Node.js stream, but it could be anything that
// can transmit JSON messages, such as window.postMessage.
stream.write(coinTypeNode.toJSON());
//===============================
// Then, on the receiving end...
//===============================
import { getBIP44AddressKeyDeriver } from '@metamask/key-tree';
// Get the node sent from the privileged context.
// It will have the following shape:
// {
// key, // A Base64 string of the coin_type key
// depth, // The number 2, which is the depth of coin_type nodes
// coin_type, // In this case, the number 60
// path, // For visualization only. In this case: m / 44' / 60'
// }
const coinTypeNode = await getCoinTypeNode();
// Get an address key deriver for the coin_type node.
// In this case, its path will be: m / 44' / 60' / 0' / 0 / address_index
const addressKeyDeriver = getBIP44AddressKeyDeriver(coinTypeNode);
// These are Node.js Buffer representations of the extended private keys for
// the respective addresses.
// m / 44' / 60' / 0' / 0 / 0
const addressKey0 = addressKeyDeriver(0);
// m / 44' / 60' / 0' / 0 / 1
const addressKey1 = addressKeyDeriver(1);
// Now, the extended private keys can be used to derive the corresponding public
// keys and protocol addresses.
```
An interface over BIP-32 and BIP-39 key derivation paths.
There are other ways of deriving keys in addition to the above example.
See the docstrings in the [BIP44Node](./src/BIP44Node.ts) and [BIP44CoinTypeNode](./src/BIP44CoinTypeNode.ts) files for details.
## References
### Internals
- Bitcoin: [BIP-0032](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
- Bitcoin: [BIP-0039](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)
- Bitcoin: [BIP-0044](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
- SatoshiLabs: [SLIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
This package also has methods for deriving arbitrary BIP-32 keys, and generating seeds from BIP-39 mnemonics.
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 [BIP-32] specification.
See the [reference implementation tests](./test/reference-implementations.test.ts) for details.
## Further Reading
- [BIP-32]
- [BIP-39]
- [BIP-44]
- [SLIP-44]
- Network Working Group: ["Key Derivation Functions and their Uses"](https://trac.tools.ietf.org/html/draft-irtf-cfrg-kdf-uses-00)
[bip-32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
[bip-39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
[bip-44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
[slip-44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc