HDKey.prototype.deriveChild = function (index) { var isHardened = index >= HARDENED_OFFSET var indexBuffer = new Buffer(4) indexBuffer.writeUInt32BE(index, 0) var data if (isHardened) { // Hardened child assert(this.privateKey, 'Could not derive hardened child key') var pk = this.privateKey var zb = new Buffer([0]) pk = Buffer.concat([zb, pk]) // data = 0x00 || ser256(kpar) || ser32(index) data = Buffer.concat([pk, indexBuffer]) } else { // Normal child // data = serP(point(kpar)) || ser32(index) // = serP(Kpar) || ser32(index) data = Buffer.concat([this.publicKey, indexBuffer]) } var I = crypto.createHmac('sha512', this.chainCode).update(data).digest() var IL = I.slice(0, 32) var IR = I.slice(32) var hd = new HDKey(this.versions) // Private parent key -> private child key if (this.privateKey) { // ki = parse256(IL) + kpar (mod n) try { hd.privateKey = secp256k1.privateKeyTweakAdd(this.privateKey, IL) // throw if IL >= n || (privateKey + IL) === 0 } catch (err) { // In case parse256(IL) >= n or ki == 0, one should proceed with the next value for i return this.derive(index + 1) } // Public parent key -> public child key } else { // Ki = point(parse256(IL)) + Kpar // = G*IL + Kpar try { hd.publicKey = secp256k1.publicKeyTweakAdd(this.publicKey, IL, true) // throw if IL >= n || (g**IL + publicKey) is infinity } catch (err) { // In case parse256(IL) >= n or Ki is the point at infinity, one should proceed with the next value for i return this.derive(index + 1, isHardened) } } hd.chainCode = IR hd.depth = this.depth + 1 hd.parentFingerprint = this.fingerprint// .readUInt32BE(0) hd.index = index return hd }
HDNode.prototype._deriveWithNumber = function (index, isHardened) { typeforce(types.BIP32Index(network.highestBit), index) typeforce(typeforce.maybe(types.Boolean), isHardened) var data = new Buffer(37) // Hardened child if (isHardened) { if (this.isNeutered()) throw new TypeError('Could not derive hardened child key') // data = 0x00 || ser256(kpar) || ser32(index) data[0] = 0x00 this.privateKey.copy(data, 1) data.writeUInt32BE(index + network.highestBit, 33) // Normal child } else { // data = serP(point(kpar)) || ser32(index) // = serP(Kpar) || ser32(index) this.getPublicKey().copy(data, 0) data.writeUInt32BE(index, 33) } var I = createHmac('sha512', this.chainCode).update(data).digest() var IL = I.slice(0, 32) var IR = I.slice(32) var privateKey var publicKey if (this.isNeutered()) { try { // throw if IL >= n || (privateKey + IL) === 0 privateKey = secp256k1.privateKeyTweakAdd(this.privateKey, IL) } catch (err) { return this.derive(index + 1, isHardened) } } else { try { // throw if IL >= n || (g**IL + publicKey) is infinity publicKey = secp256k1.publicKeyTweakAdd(this.getPublicKey(), IL, true) } catch (err) { return this.derive(index + 1, isHardened) } } return new HDNode({ depth: this.depth + 1, parentFingerprint: this.getFingerprint().readUInt32BE(0), index: index + (isHardened ? network.highestBit : 0), chainCode: IR, privateKey: privateKey, publicKey: publicKey }) }
ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compressed) { return secp256k1.publicKeyTweakAdd(publicKey, tweak, compressed); };