UNPKG

@stricahq/bip32ed25519

Version:

Pure javascript implementation of Bip32Ed25519, used for Cardano blockchain key pair.

114 lines (113 loc) 4.45 kB
"use strict"; /* eslint-disable no-bitwise */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const buffer_1 = require("buffer"); const bn_js_1 = __importDefault(require("bn.js")); const pbkdf2_1 = require("pbkdf2"); const Bip32PublicKey_1 = __importDefault(require("./Bip32PublicKey")); const PrivateKey_1 = __importDefault(require("./PrivateKey")); const utils_1 = require("./utils"); const EDDSA = require("./ed25519e"); const eddsa = new EDDSA(); class Bip32PrivateKey { constructor(xprv) { this.xprv = xprv; } static fromEntropy(entropy) { return new Promise((resolve, reject) => { pbkdf2_1.pbkdf2("", entropy, 4096, 96, "sha512", (err, xprv) => { if (err) { reject(err); } // The lowest three bits of the first octet are cleared // 248 or 0xf8 or 0b11111000 xprv[0] &= 0b11111000; // the highest bit of the last octet is cleared // 31 or 0x1f or 0b00011111 // AND the third highest bit is cleared too xprv[31] &= 0b00011111; // and the second highest bit of the last octet is set // 64 or 0x40 or 0b01000000 xprv[31] |= 0b01000000; resolve(new Bip32PrivateKey(xprv)); }); }); } derive(index) { const kl = this.xprv.slice(0, 32); const kr = this.xprv.slice(32, 64); const cc = this.xprv.slice(64, 96); let z; let i; if (index < utils_1.HARDENED_OFFSET) { const data = buffer_1.Buffer.allocUnsafe(1 + 32 + 4); data.writeUInt32LE(index, 1 + 32); const keyPair = eddsa.keyFromSecret(kl.toString("hex")); const vk = buffer_1.Buffer.from(keyPair.pubBytes()); vk.copy(data, 1); data[0] = 0x02; z = utils_1.hmac512(cc, data); data[0] = 0x03; i = utils_1.hmac512(cc, data); } else { const data = buffer_1.Buffer.allocUnsafe(1 + 64 + 4); data.writeUInt32LE(index, 1 + 64); kl.copy(data, 1); kr.copy(data, 1 + 32); data[0] = 0x00; z = utils_1.hmac512(cc, data); data[0] = 0x01; i = utils_1.hmac512(cc, data); } const chainCode = i.slice(32, 64); const zl = z.slice(0, 32); const zr = z.slice(32, 64); const left = new bn_js_1.default(kl, 16, "le") .add(new bn_js_1.default(zl.slice(0, 28), 16, "le").mul(new bn_js_1.default(8))) .toArrayLike(buffer_1.Buffer, "le", 32); let right = new bn_js_1.default(kr, 16, "le") .add(new bn_js_1.default(zr, 16, "le")) .toArrayLike(buffer_1.Buffer, "le") .slice(0, 32); if (right.length !== 32) { right = buffer_1.Buffer.from(right.toString("hex").padEnd(32, "0"), "hex"); } const xprv = buffer_1.Buffer.concat([left, right, chainCode]); return new Bip32PrivateKey(xprv); } deriveHardened(index) { return this.derive(index + utils_1.HARDENED_OFFSET); } derivePath(path) { const splitPath = path.split("/"); // @ts-ignore return splitPath.reduce((hdkey, indexStr, i) => { if (i === 0 && indexStr === "m") { return hdkey; } if (indexStr.slice(-1) === `'`) { const index = parseInt(indexStr.slice(0, -1), 10); return hdkey.deriveHardened(index); } const index = parseInt(indexStr, 10); return hdkey.derive(index); }, this); } toBip32PublicKey() { const keyPair = eddsa.keyFromSecret(this.xprv.slice(0, 32).toString("hex")); const vk = buffer_1.Buffer.from(keyPair.pubBytes()); return new Bip32PublicKey_1.default(buffer_1.Buffer.concat([vk, this.xprv.slice(64, 96)])); } toBytes() { return this.xprv; } toPrivateKey() { const keyPair = eddsa.keyFromSecret(this.xprv.slice(0, 64)); return new PrivateKey_1.default(buffer_1.Buffer.from(keyPair.privBytes())); } } exports.default = Bip32PrivateKey;