UNPKG

micro-key-producer

Version:

Produces secure keys and passwords. Supports SSH, PGP, BLS, OTP, and many others

125 lines 4.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HDKey = exports.HARDENED_OFFSET = exports.MASTER_SECRET = void 0; /*! micro-key-producer - MIT License (c) 2024 Paul Miller (paulmillr.com) */ const ed25519_1 = require("@noble/curves/ed25519"); const _assert_1 = require("@noble/hashes/_assert"); const hmac_1 = require("@noble/hashes/hmac"); const ripemd160_1 = require("@noble/hashes/ripemd160"); const sha256_1 = require("@noble/hashes/sha256"); const sha512_1 = require("@noble/hashes/sha512"); const utils_1 = require("@noble/hashes/utils"); exports.MASTER_SECRET = (0, utils_1.utf8ToBytes)('ed25519 seed'); exports.HARDENED_OFFSET = 0x80000000; const ZERO = new Uint8Array([0]); function ensureBytes(b, ...lengths) { if (typeof b === 'string') b = (0, utils_1.hexToBytes)(b); (0, _assert_1.abytes)(b, ...lengths); return b; } const hash160 = (data) => (0, ripemd160_1.ripemd160)((0, sha256_1.sha256)(data)); const fromU32 = (data) => (0, utils_1.createView)(data).getUint32(0, false); const toU32 = (n) => { if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) { throw new Error(`Invalid number=${n}. Should be from 0 to 2 ** 32 - 1`); } const buf = new Uint8Array(4); (0, utils_1.createView)(buf).setUint32(0, n, false); return buf; }; class HDKey { get publicKeyRaw() { return ed25519_1.ed25519.getPublicKey(this.privateKey); } get publicKey() { return (0, utils_1.concatBytes)(ZERO, this.publicKeyRaw); } get pubHash() { return hash160(this.publicKey); } get fingerprint() { return fromU32(this.pubHash); } get fingerprintHex() { return (0, utils_1.bytesToHex)(toU32(this.fingerprint)); } get parentFingerprintHex() { return (0, utils_1.bytesToHex)(toU32(this.parentFingerprint)); } static fromMasterSeed(seed) { seed = ensureBytes(seed); if (8 * seed.length < 128 || 8 * seed.length > 512) { throw new Error(`HDKey: wrong seed length=${seed.length}. Should be between 128 and 512 bits; 256 bits is advised)`); } const I = (0, hmac_1.hmac)(sha512_1.sha512, exports.MASTER_SECRET, seed); return new HDKey({ privateKey: I.slice(0, 32), chainCode: I.slice(32), }); } constructor(opt) { this.depth = 0; this.index = 0; this.parentFingerprint = 0; if (!opt || typeof opt !== 'object') throw new Error('HDKey.constructor must not be called directly'); (0, _assert_1.abytes)(opt.privateKey, 32); (0, _assert_1.abytes)(opt.chainCode, 32); this.depth = opt.depth || 0; this.index = opt.index || 0; this.parentFingerprint = opt.parentFingerprint || 0; if (!this.depth) { if (this.parentFingerprint || this.index) throw new Error('HDKey: zero depth with non-zero index/parent fingerprint'); } this.chainCode = opt.chainCode; this.privateKey = opt.privateKey; } derive(path, forceHardened = false) { if (!/^[mM]'?/.test(path)) throw new Error('Path must start with "m" or "M"'); if (/^[mM]'?$/.test(path)) return this; const parts = path.replace(/^[mM]'?\//, '').split('/'); // tslint:disable-next-line let child = this; for (const c of parts) { const m = /^(\d+)('?)$/.exec(c); if (!m || m.length !== 3) throw new Error(`Invalid child index: ${c}`); let idx = +m[1]; if (!Number.isSafeInteger(idx) || idx >= exports.HARDENED_OFFSET) throw new Error('Invalid index'); // hardened key if (forceHardened || m[2] === "'") idx += exports.HARDENED_OFFSET; child = child.deriveChild(idx); } return child; } deriveChild(index) { if (index < exports.HARDENED_OFFSET) throw new Error(`Non-hardened child derivation not possible for Ed25519 (index=${index})`); // Hardened child: 0x00 || ser256(kpar) || ser32(index) const data = (0, utils_1.concatBytes)(ZERO, this.privateKey, toU32(index)); const I = (0, hmac_1.hmac)(sha512_1.sha512, this.chainCode, data); return new HDKey({ chainCode: I.slice(32), depth: this.depth + 1, parentFingerprint: this.fingerprint, index, privateKey: I.slice(0, 32), }); } sign(message) { return ed25519_1.ed25519.sign(message, this.privateKey); } verify(message, signature) { signature = ensureBytes(signature, 64); return ed25519_1.ed25519.verify(signature, message, this.publicKeyRaw); } } exports.HDKey = HDKey; exports.default = HDKey; //# sourceMappingURL=slip10.js.map