Skip to content

Commit 6aaefa7

Browse files
author
AJ ONeal
committed
chore: add types and minor changes for type checking
1 parent 48a7387 commit 6aaefa7

File tree

1 file changed

+177
-7
lines changed

1 file changed

+177
-7
lines changed

lib/hdkey.js

Lines changed: 177 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,44 @@
1+
/**
2+
* @typedef HDKey
3+
* @prop {HDCreate} create
4+
* @prop {HDFromSeed} fromMasterSeed
5+
* @prop {HDFromXKey} fromExtendedKey
6+
* @prop {HDFromJSON} fromJSON
7+
* @prop {Number} HARDENED_OFFSET - 0x80000000
8+
*/
9+
10+
/**
11+
* @callback HDCreate
12+
* @param {HDVersions} [versions]
13+
* @returns {hdkey}
14+
*/
15+
16+
/**
17+
* @typedef hdkey
18+
* @prop {Buffer} chainCode - extra 32-bytes of shared entropy for xkeys
19+
* @prop {Number} depth - of hd path - typically 0 is seed, 1-3 hardened, 4-5 are not
20+
* @prop {Buffer} identifier - same bytes as pubKeyHash, but used for id
21+
* @prop {Number} index - the final segment of an HD Path, the index of the wif/addr
22+
* @prop {Number} parentFingerprint - 32-bit int, slice of id, stored in child xkeys
23+
* @prop {Buffer} publicKey
24+
* @prop {HDVersions} versions - magic bytes for base58 prefix
25+
* @prop {HDDerivePath} derive - derive a full hd path from the given root
26+
* @prop {HDDeriveChild} deriveChild - get the next child xkey (in a path segment)
27+
* @prop {HDFingerprint} getFingerprint
28+
* @prop {HDMaybeGetString} getPrivateExtendedKey
29+
* @prop {HDMaybeGetBuffer} getPrivateKey
30+
* @prop {HDGetString} getPublicExtendedKey
31+
* @prop {HDSetBuffer} setPublicKey
32+
* @prop {HDSetBuffer} setPrivateKey
33+
* @prop {HDSign} sign
34+
* @prop {HDVerify} verify
35+
* @prop {HDToJSON} toJSON
36+
* @prop {HDWipePrivates} wipePrivateData - randomizes private key buffer in-place
37+
* @prop {Function} _setPublicKey
38+
*/
39+
40+
/** @type {HDKey} */
41+
//@ts-ignore
142
var HDKey = ("object" === typeof module && exports) || {};
243
(function (window, HDKey) {
344
"use strict";
@@ -15,21 +56,23 @@ var HDKey = ("object" === typeof module && exports) || {};
1556
var BITCOIN_VERSIONS = { private: 0x0488ade4, public: 0x0488b21e };
1657

1758
HDKey.create = function (versions) {
59+
/** @type {hdkey} */
1860
var hdkey = {};
61+
/** @type {Buffer?} */
1962
var _privateKey = null;
2063

2164
hdkey.versions = versions || BITCOIN_VERSIONS;
2265
hdkey.depth = 0;
2366
hdkey.index = 0;
24-
hdkey.publicKey = null;
25-
// note: BIP-32 "Key Identifier" is the same as "Pub Key Hash"
26-
// but used for a different purpose, hence the semantic name
27-
hdkey.identifier = null;
28-
// note: chainCode is public
29-
hdkey.chainCode = null;
67+
//hdkey.publicKey = null;
68+
//hdkey.identifier = null;
69+
//hdkey.chainCode = null;
3070
hdkey.parentFingerprint = 0;
3171

3272
hdkey.getFingerprint = function () {
73+
if (!hdkey.identifier) {
74+
throw new Error("Public key has not been set");
75+
}
3376
return hdkey.identifier.slice(0, 4).readUInt32BE(0);
3477
};
3578

@@ -57,6 +100,9 @@ var HDKey = ("object" === typeof module && exports) || {};
57100
hdkey._setPublicKey(publicKey);
58101
};
59102

103+
/**
104+
* @param {Buffer} publicKey
105+
*/
60106
hdkey._setPublicKey = function (publicKey) {
61107
hdkey.publicKey = Buffer.from(publicKey);
62108
hdkey.identifier = hash160(publicKey);
@@ -78,6 +124,10 @@ var HDKey = ("object" === typeof module && exports) || {};
78124
};
79125

80126
hdkey.getPublicExtendedKey = function () {
127+
if (!hdkey.publicKey) {
128+
throw new Error("Missing public key");
129+
}
130+
81131
return bs58check.encode(
82132
serialize(hdkey, hdkey.versions.public, hdkey.publicKey),
83133
);
@@ -118,7 +168,9 @@ var HDKey = ("object" === typeof module && exports) || {};
118168

119169
if (isHardened) {
120170
// Hardened child
121-
assert(Boolean(_privateKey), "Could not derive hardened child key");
171+
if (!_privateKey) {
172+
throw new Error("Could not derive hardened child key");
173+
}
122174

123175
var pk = _privateKey;
124176
var zb = Buffer.alloc(1, 0);
@@ -186,6 +238,10 @@ var HDKey = ("object" === typeof module && exports) || {};
186238
};
187239

188240
hdkey.sign = function (hash) {
241+
if (!_privateKey) {
242+
throw new Error("Private Key must be set");
243+
}
244+
189245
return Buffer.from(
190246
secp256k1.ecdsaSign(Uint8Array.from(hash), Uint8Array.from(_privateKey))
191247
.signature,
@@ -279,12 +335,21 @@ var HDKey = ("object" === typeof module && exports) || {};
279335
return HDKey.fromExtendedKey(obj.xpriv);
280336
};
281337

338+
/**
339+
* @param {Boolean} assertion
340+
* @param {String} message
341+
*/
282342
function assert(assertion, message) {
283343
if (!assertion) {
284344
throw new Error(message);
285345
}
286346
}
287347

348+
/**
349+
* @param {hdkey} hdkey - TODO attach to hdkey
350+
* @param {Number} version
351+
* @param {Buffer} key
352+
*/
288353
function serialize(hdkey, version, key) {
289354
// => version(4) || depth(1) || fingerprint(4) || index(4) || chain(32) || key(33)
290355
var buffer = Buffer.allocUnsafe(LEN);
@@ -302,6 +367,10 @@ var HDKey = ("object" === typeof module && exports) || {};
302367
return buffer;
303368
}
304369

370+
/**
371+
* @param {Buffer} buf
372+
* @returns {Buffer}
373+
*/
305374
function hash160(buf) {
306375
var sha = crypto.createHash("sha256").update(buf).digest();
307376
return new RIPEMD160().update(sha).digest();
@@ -312,3 +381,104 @@ var HDKey = ("object" === typeof module && exports) || {};
312381
if ("object" === typeof module) {
313382
module.exports = HDKey;
314383
}
384+
385+
// Type Definitions
386+
387+
/**
388+
* @typedef HDVersions
389+
* @prop {Number} private - 32-bit int (encodes to 'xprv' in base58)
390+
* @prop {Number} public - 32-bit int (encodes to 'xpub' in base58)
391+
*/
392+
393+
/**
394+
* @typedef HDJSON
395+
* @prop {String?} xpriv - base58check-encoded extended private key
396+
* @prop {String} xpub - base58check-encoded extended public key
397+
*/
398+
399+
// Function Definitions
400+
401+
/**
402+
* @callback HDDeriveChild
403+
* @param {Number} index - includes HARDENED_OFFSET, if applicable
404+
*/
405+
406+
/**
407+
* @callback HDDerivePath
408+
* @param {String} path
409+
*/
410+
411+
/**
412+
* @callback HDFingerprint
413+
* @returns {Number}
414+
*/
415+
416+
/**
417+
* @callback HDFromXKey
418+
* @param {String} base58key - base58check-encoded xkey
419+
* @param {HDVersions} [versions]
420+
* @param {Boolean} [skipVerification]
421+
* returns {hdkey}
422+
*/
423+
424+
/**
425+
* @callback HDFromJSON
426+
* @param {HDFromJSONOpts} opts
427+
* returns {hdkey}
428+
*
429+
* @typedef HDFromJSONOpts
430+
* @prop {String} xpriv
431+
*/
432+
433+
/**
434+
* @callback HDFromSeed
435+
* @param {Buffer} seedBuffer
436+
* @param {HDVersions} [versions]
437+
*/
438+
439+
/**
440+
* @callback HDGetBuffer
441+
* @returns {Buffer}
442+
*/
443+
444+
/**
445+
* @callback HDGetString
446+
* @returns {String}
447+
*/
448+
449+
/**
450+
* @callback HDMaybeGetBuffer
451+
* @returns {Buffer?}
452+
*/
453+
454+
/**
455+
* @callback HDMaybeGetString
456+
* @returns {String?}
457+
*/
458+
459+
/**
460+
* @callback HDSetBuffer
461+
* @param {Buffer} buf
462+
*/
463+
464+
/**
465+
* @callback HDSign
466+
* @param {Buffer} hash
467+
* @returns {Buffer} - signature
468+
*/
469+
470+
/**
471+
* @callback HDToJSON
472+
* @returns {HDJSON}
473+
*/
474+
475+
/**
476+
* @callback HDVerify
477+
* @param {Buffer} hash
478+
* @param {Buffer} signature
479+
* @returns {Boolean}
480+
*/
481+
482+
/**
483+
* @callback HDWipePrivates
484+
*/

0 commit comments

Comments
 (0)