35
35
* @prop {HDVersions } versions - magic bytes for base58 prefix
36
36
* @prop {HDDerivePath } derive - derive a full hd path from the given root
37
37
* @prop {HDDeriveChild } deriveChild - get the next child xkey (in a path segment)
38
+ * @prop {HDDeriveChild } _deriveChild - helper
38
39
* @prop {HDFingerprint } getFingerprint
39
40
* @prop {HDMaybeGetString } getPrivateExtendedKey
40
41
* @prop {HDMaybeGetBuffer } getPrivateKey
@@ -323,89 +324,77 @@ var DashHd = ("object" === typeof module && exports) || {};
323
324
let hardened = c . length > 1 && c [ c . length - 1 ] === "'" ;
324
325
let childIndex = parseInt ( c , 10 ) ; // & (HARDENED_OFFSET - 1)
325
326
assert ( childIndex < HARDENED_OFFSET , "Invalid index" ) ;
326
- if ( hardened ) {
327
- childIndex += HARDENED_OFFSET ;
328
- }
329
327
330
- _hdkey = await _hdkey . deriveChild ( childIndex ) ;
328
+ _hdkey = await _hdkey . deriveChild ( childIndex , hardened ) ;
331
329
}
332
330
333
331
return _hdkey ;
334
332
} ;
335
333
334
+ hdkey . deriveChild = async function ( index , hardened ) {
335
+ for ( ; ; ) {
336
+ try {
337
+ //@ts -ignore
338
+ return await hdkey . _deriveChild ( index , hardened ) ;
339
+ } catch ( e ) {
340
+ // In essence:
341
+ // if it couldn't produce a public key, just go on the next one
342
+ //
343
+ // More precisely:
344
+ //
345
+ // throw if IL >= n || (privateKey + IL) === 0
346
+ // In case parse256(IL) >= n or ki == 0,
347
+ // one should proceed with the next value for i
348
+
349
+ // throw if IL >= n || (g**IL + publicKey) is infinity
350
+ // In case parse256(IL) >= n or Ki is the point at infinity,
351
+ // one should proceed with the next value for i
352
+ index += 1 ;
353
+ }
354
+ }
355
+ } ;
356
+
336
357
// IMPORTANT: never allow `await` (or other async) between writing to
337
358
// and accessing these! (otherwise the data will be corrupted)
338
359
// (stored here for performance - no allocations or garbage collection)
339
360
let _indexBuffer = new Uint8Array ( 4 ) ;
340
361
let _indexDv = new DataView ( _indexBuffer . buffer ) ;
341
362
342
- hdkey . deriveChild = async function ( index ) {
343
- let isHardened = index >= HARDENED_OFFSET ;
344
- let offset = 0 ;
345
- _indexDv . setUint32 ( offset , index , BUFFER_BE ) ;
346
-
347
- let data = new Uint8Array ( INDEXED_KEY_SIZE ) ;
348
-
349
- if ( isHardened ) {
350
- // Hardened child
363
+ //@ts -ignore
364
+ hdkey . _deriveChild = async function ( index , hardened ) {
365
+ let seed = new Uint8Array ( INDEXED_KEY_SIZE ) ;
366
+ if ( hardened ) {
351
367
if ( ! _privateKey ) {
352
368
throw new Error ( "Could not derive hardened child key" ) ;
353
369
}
354
-
355
- // data = 0x00 || ser256(kpar) || ser32(index)
356
- data . set ( [ 0 ] , 0 ) ; // 1
357
- data . set ( _privateKey , 1 ) ; // 32
358
- data . set ( _indexBuffer , KEY_SIZE ) ;
370
+ index += HARDENED_OFFSET ;
371
+ seed . set ( [ 0 ] , 0 ) ;
372
+ seed . set ( _privateKey , 1 ) ;
359
373
} else {
360
- // Normal child
361
- // data = serP(point(kpar)) || ser32(index)
362
- // = serP(Kpar) || ser32(index)
363
- data . set ( hdkey . publicKey , 0 ) ;
364
- data . set ( _indexBuffer , KEY_SIZE ) ;
374
+ seed . set ( hdkey . publicKey , 0 ) ;
365
375
}
376
+ _indexDv . setUint32 ( 0 , index , BUFFER_BE ) ;
377
+ seed . set ( _indexBuffer , KEY_SIZE ) ;
366
378
367
- let IBuf = await Utils . sha512hmac ( hdkey . chainCode , data ) ;
368
- let I = new Uint8Array ( IBuf ) ;
379
+ let I = await Utils . sha512hmac ( hdkey . chainCode , seed ) ;
369
380
let IL = I . slice ( 0 , 32 ) ;
370
381
let IR = I . slice ( 32 ) ;
371
382
372
- let hd = DashHd . create ( hdkey . versions ) ;
383
+ let _hdkey = DashHd . create ( hdkey . versions ) ;
384
+ _hdkey . depth = hdkey . depth + 1 ;
385
+ _hdkey . parentFingerprint = hdkey . getFingerprint ( ) ;
386
+ _hdkey . index = index ;
387
+ _hdkey . chainCode = IR ;
373
388
374
- // Private parent key -> private child key
375
389
if ( _privateKey ) {
376
- // ki = parse256(IL) + kpar (mod n)
377
- try {
378
- let privateKeyCopy = new Uint8Array ( _privateKey ) ;
379
- await hd . setPrivateKey (
380
- await Utils . privateKeyTweakAdd ( privateKeyCopy , IL ) ,
381
- ) ;
382
- // throw if IL >= n || (privateKey + IL) === 0
383
- } catch ( err ) {
384
- // In case parse256(IL) >= n or ki == 0, one should proceed with the next value for i
385
- return await hdkey . deriveChild ( index + 1 ) ;
386
- }
387
- // Public parent key -> public child key
390
+ let nextPrivKey = await Utils . privateKeyTweakAdd ( _privateKey , IL ) ;
391
+ await _hdkey . setPrivateKey ( nextPrivKey ) ;
388
392
} else {
389
- // Ki = point(parse256(IL)) + Kpar
390
- // = G*IL + Kpar
391
- try {
392
- let publicKeyCopy = new Uint8Array ( hdkey . publicKey ) ;
393
- await hd . setPublicKey (
394
- await Utils . publicKeyTweakAdd ( publicKeyCopy , IL ) ,
395
- ) ;
396
- // throw if IL >= n || (g**IL + publicKey) is infinity
397
- } catch ( err ) {
398
- // In case parse256(IL) >= n or Ki is the point at infinity, one should proceed with the next value for i
399
- return await hdkey . deriveChild ( index + 1 ) ;
400
- }
393
+ let nextPubKey = await Utils . publicKeyTweakAdd ( hdkey . publicKey , IL ) ;
394
+ await _hdkey . setPublicKey ( nextPubKey ) ;
401
395
}
402
396
403
- hd . chainCode = IR ;
404
- hd . depth = hdkey . depth + 1 ;
405
- hd . parentFingerprint = hdkey . getFingerprint ( ) ;
406
- hd . index = index ;
407
-
408
- return hd ;
397
+ return _hdkey ;
409
398
} ;
410
399
411
400
hdkey . wipePrivateData = function ( ) {
@@ -420,8 +409,7 @@ var DashHd = ("object" === typeof module && exports) || {};
420
409
} ;
421
410
422
411
DashHd . fromMasterSeed = async function ( seedBuffer , versions ) {
423
- let IBuf = await Utils . sha512hmac ( MASTER_SECRET , seedBuffer ) ;
424
- let I = new Uint8Array ( IBuf ) ;
412
+ let I = await Utils . sha512hmac ( MASTER_SECRET , seedBuffer ) ;
425
413
let IL = I . subarray ( 0 , 32 ) ;
426
414
let IR = I . subarray ( 32 ) ;
427
415
@@ -549,6 +537,7 @@ if ("object" === typeof module) {
549
537
/**
550
538
* @callback HDDeriveChild
551
539
* @param {Number } index - includes HARDENED_OFFSET, if applicable
540
+ * @param {Boolean } hardened
552
541
* returns {Promise<HDKey>}
553
542
*/
554
543
0 commit comments