diff --git a/src/bip32.js b/src/bip32.js index db3406f..998fc1a 100644 --- a/src/bip32.js +++ b/src/bip32.js @@ -4,6 +4,7 @@ var util = require('./util'), ECKey = require('./eckey').ECKey, ECPubKey = require('./eckey').ECPubKey, base58 = require('./base58'), + assert = require('assert'), Crypto = require('./crypto-js/crypto'); var BIP32key = function(opts) { @@ -51,17 +52,48 @@ BIP32key.deserialize = function(str) { }) } -BIP32key.prototype.serialize = function() { - var bytes = this.vbytes.concat( - [this.depth], - this.fingerprint, - util.numToBytes(this.i,4).reverse(), - this.chaincode, - this.type == 'priv' ? [0].concat(this.key.export('bytes').slice(0,32)) - : this.key.export('bytes')) - var checksum = Crypto.SHA256(Crypto.SHA256(bytes,{asBytes: true}), {asBytes: true}) - .slice(0,4) - return base58.encode(bytes.concat(checksum)) +BIP32key.prototype.serialize = function(enc) { + var bytes = [] + + // 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private) + bytes = bytes.concat(this.vbytes) + assert.equal(bytes.length, 4) + + // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, .... + bytes = bytes.concat([this.depth]) + assert.equal(bytes.length, 4 + 1) + + // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) + bytes = bytes.concat(this.fingerprint) + assert.equal(bytes.length, 4 + 1 + 4) + + // 4 bytes: child number. This is the number i in xi = xpar/i, + // with xi the key being serialized. This is encoded in MSB order. (0x00000000 if master key) + bytes = bytes.concat(util.numToBytes(this.i, 4).reverse()) + assert.equal(bytes.length, 4 + 1 + 4 + 4) + + // 32 bytes: the chain code + bytes = bytes.concat(this.chaincode) + assert.equal(bytes.length, 4 + 1 + 4 + 4 + 32) + + // 33 bytes: the public key or private key data + // (0x02 + X or 0x03 + X for public keys, 0x00 + k for private keys) + if (this.type == 'priv') { + bytes.push(0) + bytes = bytes.concat(this.key.toBytes().slice(0, 32)) + } else { + bytes = bytes.concat(this.key.toBytes()) + } + + assert.equal(bytes.length, 78) + + if (enc == 'bytes') return bytes + if (enc == 'hex') return conv.bytesToHex(bytes) + + var checksum = Crypto.SHA256(Crypto.SHA256(bytes, {asBytes: true}), { asBytes: true }).slice(0,4) + bytes = bytes.concat(checksum) + + return base58.encode(bytes) } BIP32key.prototype.ckd = function(i) {