Skip to content

Commit

Permalink
HD: encode x/y/z purpose to database
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed Oct 6, 2018
1 parent 8c7ffd7 commit d998aa8
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 73 deletions.
50 changes: 24 additions & 26 deletions lib/hd/private.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class HDPrivateKey {
* Create an hd private key.
* @constructor
* @param {Object|String} options
* @param {string} options.keyType
* @param {string} options.purpose
* @param {Number?} options.depth
* @param {Number?} options.parentFingerPrint
* @param {Number?} options.childIndex
Expand All @@ -51,7 +51,7 @@ class HDPrivateKey {
*/

constructor(options) {
this.keyType = 'x';
this.purpose = 'x';
this.depth = 0;
this.parentFingerPrint = 0;
this.childIndex = 0;
Expand Down Expand Up @@ -81,14 +81,14 @@ class HDPrivateKey {
assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.privateKey));

if (options.keyType){
if (options.purpose) {
assert(
['x','y','z'].indexOf(options.keyType) !== -1,
'Bad key type'
['x','y','z'].indexOf(options.purpose) !== -1,
'Bad purpose'
);
this.keyType = options.keyType;
this.purpose = options.purpose;
} else {
this.keyType = 'x';
this.purpose = 'x';
}

this.depth = options.depth;
Expand Down Expand Up @@ -121,7 +121,7 @@ class HDPrivateKey {

if (!key) {
key = new HDPublicKey();
key.keyType = this.keyType;
key.purpose = this.purpose;
key.depth = this.depth;
key.parentFingerPrint = this.parentFingerPrint;
key.childIndex = this.childIndex;
Expand Down Expand Up @@ -231,7 +231,7 @@ class HDPrivateKey {
}

const child = new this.constructor();
child.keyType = this.keyType;
child.purpose = this.purpose;
child.depth = this.depth + 1;
child.parentFingerPrint = this.fingerPrint;
child.childIndex = index;
Expand Down Expand Up @@ -450,7 +450,7 @@ class HDPrivateKey {
if (!secp256k1.privateKeyVerify(left))
throw new Error('Master private key is invalid.');

this.keyType = 'x';
this.purpose = 'x';
this.depth = 0;
this.parentFingerPrint = 0;
this.childIndex = 0;
Expand Down Expand Up @@ -578,30 +578,28 @@ class HDPrivateKey {

fromReader(br, network) {
const version = br.readU32BE();

const confirmNetwork = Network.fromPrivate(version, network);
let type = null;
for (const label in confirmNetwork.keyPrefix){
if (confirmNetwork.keyPrefix[label] === version){
type = label;

let purpose = null;
for (const label in confirmNetwork.keyPrefix) {
if (confirmNetwork.keyPrefix[label] === version) {
purpose = label;
break;
}
}

switch (type) {
switch (purpose) {
case 'xprivkey':
this.keyType = 'x';
this.purpose = 'x';
break;
case 'yprivkey':
this.keyType = 'y';
this.purpose = 'y';
break;
case 'zprivkey':
this.keyType = 'z';
this.purpose = 'z';
break;
default:
throw new Error('Bad version/type bytes');
break;
throw new Error('Bad purpose bytes');
}

this.depth = br.readU8();
Expand Down Expand Up @@ -656,16 +654,16 @@ class HDPrivateKey {
toWriter(bw, network) {
network = Network.get(network);

switch (this.keyType) {
switch (this.purpose) {
case 'x':
bw.writeU32BE(network.keyPrefix.xprivkey);
break;
case 'y':
bw.writeU32BE(network.keyPrefix.yprivkey);
break;
case 'z':
bw.writeU32BE(network.keyPrefix.zprivkey);
break;
case 'x':
default:
bw.writeU32BE(network.keyPrefix.xprivkey);
}
bw.writeU8(this.depth);
bw.writeU32BE(this.parentFingerPrint);
Expand Down
43 changes: 21 additions & 22 deletions lib/hd/public.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class HDPublicKey {
* @constructor
* @param {Object|Base58String} options
* @param {Base58String?} options.xkey - Serialized base58 key.
* @param {string} options.keyType
* @param {string} options.purpose
* @param {Number?} options.depth
* @param {Number?} options.parentFingerPrint
* @param {Number?} options.childIndex
Expand All @@ -43,7 +43,7 @@ class HDPublicKey {
*/

constructor(options) {
this.keyType = 'x';
this.purpose = 'x';
this.depth = 0;
this.parentFingerPrint = 0;
this.childIndex = 0;
Expand All @@ -70,14 +70,14 @@ class HDPublicKey {
assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.publicKey));

if (options.keyType){
if (options.purpose) {
assert(
['x','y','z'].indexOf(options.keyType) !== -1,
'Bad key type'
['x','y','z'].indexOf(options.purpose) !== -1,
'Bad purpose'
);
this.keyType = options.keyType;
this.purpose = options.purpose;
} else {
this.keyType = 'x';
this.purpose = 'x';
}

this.depth = options.depth;
Expand Down Expand Up @@ -448,27 +448,26 @@ class HDPublicKey {

const confirmNetwork = Network.fromPublic(version, network);

let type = null;
for (const label in confirmNetwork.keyPrefix){
if (confirmNetwork.keyPrefix[label] === version){
type = label;
let purpose = null;
for (const label in confirmNetwork.keyPrefix) {
if (confirmNetwork.keyPrefix[label] === version) {
purpose = label;
break;
}
}

switch (type) {
switch (purpose) {
case 'xpubkey':
this.keyType = 'x';
this.purpose = 'x';
break;
case 'ypubkey':
this.keyType = 'y';
this.purpose = 'y';
break;
case 'zpubkey':
this.keyType = 'z';
this.purpose = 'z';
break;
default:
throw new Error('Bad version/type bytes');
break;
throw new Error('Bad purpose bytes');
}

this.depth = br.readU8();
Expand Down Expand Up @@ -507,22 +506,22 @@ class HDPublicKey {
* Write the key to a buffer writer.
* @param {BufferWriter} bw
* @param {(Network|NetworkType)?} network
* @param {string} type
* @param {string} type
*/

toWriter(bw, network) {
network = Network.get(network);

switch (this.keyType) {
switch (this.purpose) {
case 'x':
bw.writeU32BE(network.keyPrefix.xpubkey);
break;
case 'y':
bw.writeU32BE(network.keyPrefix.ypubkey);
break;
case 'z':
bw.writeU32BE(network.keyPrefix.zpubkey);
break;
case 'x':
default:
bw.writeU32BE(network.keyPrefix.xpubkey);
}
bw.writeU8(this.depth);
bw.writeU32BE(this.parentFingerPrint);
Expand Down
2 changes: 1 addition & 1 deletion lib/primitives/keyring.js
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ class KeyRing {
*/

getAddress(enc, network) {
if (this.nested || this.addressFromKeyType === 'y')
if (this.nested || this.purpose === 'y')
return this.getNestedAddress(enc, network);

if (this.script)
Expand Down
50 changes: 36 additions & 14 deletions lib/wallet/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Account {
this.initialized = false;
this.witness = wdb.options.witness === true;
this.watchOnly = false;
this.keyType = 'x',
this.purpose = 'x',
this.type = Account.types.PUBKEYHASH;
this.m = 1;
this.n = 1;
Expand Down Expand Up @@ -102,16 +102,16 @@ class Account {
this.watchOnly = options.watchOnly;
}

if (options.keyType != null) {
assert(typeof options.keyType === 'string');
if (options.purpose != null) {
assert(typeof options.purpose === 'string');
assert(
['x','y','z'].indexOf(options.keyType) !== -1,
'Bad key type'
['x','y','z'].indexOf(options.purpose) !== -1,
'Bad purpose'
);
this.keyType = options.keyType;
this.purpose = options.purpose;
}

if (this.keyType === 'y' || this.keyType === 'z')
if (this.purpose === 'y' || this.purpose === 'z')
this.witness = true;

if (options.type != null) {
Expand Down Expand Up @@ -481,8 +481,8 @@ class Account {
let key;
if (master && master.key && !this.watchOnly) {
const coinType = this.network.keyPrefix.coinType;
switch (this.keyType) {

switch (this.purpose) {
case 'x':
key = master.key.deriveAccount(44, coinType, this.accountIndex);
break;
Expand All @@ -499,7 +499,7 @@ class Account {
key = this.accountKey.derive(branch).derive(index);
}

key.keyType = this.keyType;
key.purpose = this.purpose;
const ring = WalletKey.fromHD(this, key, branch, index);

switch (this.type) {
Expand Down Expand Up @@ -562,9 +562,6 @@ class Account {

for (let i = 0; i <= this.lookahead; i++) {
const key = this.deriveReceive(i);

console.log(key); // ------ right here, the address is correct (nested)

await this.saveKey(b, key);
}

Expand Down Expand Up @@ -892,6 +889,9 @@ console.log(key); // ------ right here, the address is correct (nested)
if (this.witness)
flags |= 2;

const purposeBits = Account.purposes[this.purpose];
flags |= (purposeBits << 6);

bw.writeU8(flags);
bw.writeU8(this.type);
bw.writeU8(this.m);
Expand Down Expand Up @@ -920,6 +920,9 @@ console.log(key); // ------ right here, the address is correct (nested)
const br = bio.read(data);
const flags = br.readU8();

const purposeBits = flags >> 6;
this.purpose = Account.purposesByVal[purposeBits];

this.initialized = (flags & 1) !== 0;
this.witness = (flags & 2) !== 0;
this.type = br.readU8();
Expand All @@ -930,7 +933,6 @@ console.log(key); // ------ right here, the address is correct (nested)
this.nestedDepth = br.readU32();
this.lookahead = br.readU8();
this.accountKey = readKey(br);

assert(this.type < Account.typesByVal.length);

const count = br.readU8();
Expand Down Expand Up @@ -986,6 +988,26 @@ Account.typesByVal = [
'MULTISIG'
];

/**
* Account purposes.
* @enum {Number}
* @default
*/

Account.purposes = {
x: 0,
y: 1,
z: 2
};

/**
* Account purposes by value.
* @enum {Number}
* @default
*/

Account.purposesByVal = ['x', 'y', 'z'];

/**
* Default address lookahead.
* @const {Number}
Expand Down
10 changes: 5 additions & 5 deletions lib/wallet/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Wallet extends EventEmitter {
this.writeLock = new Lock();
this.fundLock = new Lock();

this.keyType = 'x';
this.purpose = 'x';
this.wid = 0;
this.id = null;
this.watchOnly = false;
Expand Down Expand Up @@ -91,7 +91,7 @@ class Wallet extends EventEmitter {
assert(HD.isPrivate(key),
'Must create wallet with hd private key.');

this.keyType = key.keyType;
this.purpose = key.purpose;
} else {
mnemonic = new Mnemonic(options.mnemonic);
key = HD.fromMnemonic(mnemonic, options.password);
Expand Down Expand Up @@ -587,11 +587,11 @@ class Wallet extends EventEmitter {
if (!HD.isPublic(key))
throw new Error('Must add HD public keys to watch only wallet.');

this.keyType = key.keyType;
this.purpose = key.purpose;
} else {
assert(this.master.key);
const coinType = this.network.keyPrefix.coinType;
switch (this.keyType) {
switch (this.purpose) {
case 'x':
key = this.master.key.deriveAccount(44, coinType, this.accountDepth);
break;
Expand All @@ -614,7 +614,7 @@ class Wallet extends EventEmitter {
accountKey: key,
accountIndex: this.accountDepth,
type: options.type,
keyType: this.keyType,
purpose: this.purpose,
m: options.m,
n: options.n,
keys: options.keys
Expand Down
Loading

0 comments on commit d998aa8

Please sign in to comment.