fcoin/lib/bcoin/keypair.js
Christopher Jeffrey f8c3f37f0c
keypair: minor.
2016-07-30 18:24:45 -07:00

373 lines
8.1 KiB
JavaScript

/*!
* keypair.js - keypair object for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var bcoin = require('./env');
var utils = require('./utils');
var assert = utils.assert;
var network = bcoin.protocol.network;
var BufferWriter = require('./writer');
var BufferReader = require('./reader');
/**
* Represents an ecdsa keypair.
* @exports KeyPair
* @constructor
* @param {Object} options
* @param {Buffer?} options.privateKey
* @param {Buffer?} options.publicKey
* @param {Boolean?} options.compressed
* @param {(Network|NetworkType)?} options.network
* @property {Buffer} privateKey
* @property {Buffer} publicKey
* @property {Boolean} compressed
* @property {Network} network
*/
function KeyPair(options) {
if (!(this instanceof KeyPair))
return new KeyPair(options);
this.network = bcoin.network.get();
this.compressed = true;
this.privateKey = null;
this.publicKey = null;
if (options)
this.fromOptions(options);
}
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
KeyPair.prototype.fromOptions = function fromOptions(options) {
if (options.privateKey) {
return this.fromPrivate(
options.privateKey,
options.compressed,
options.network);
}
if (options.publicKey)
return this.fromPublic(options.publicKey, options.network);
throw new Error('Must provide a key.');
};
/**
* Instantiate key pair from options object.
* @param {Object} options
* @returns {KeyPair}
*/
KeyPair.fromOptions = function fromOptions(options) {
return new KeyPair().fromOptions(options);
};
/**
* Generate a keypair.
* @param {(Network|NetworkType)?} network
* @returns {KeyPair}
*/
KeyPair.generate = function(network) {
var key = new KeyPair();
key.network = bcoin.network.get(network);
key.privateKey = bcoin.ec.generatePrivateKey();
key.publicKey = bcoin.ec.publicKeyCreate(key.privateKey, true);
return key;
};
/**
* Inject data from private key.
* @private
* @param {Buffer} privateKey
* @param {Boolean?} compressed
* @param {(NetworkType|Network}) network
*/
KeyPair.prototype.fromPrivate = function fromPrivate(privateKey, compressed, network) {
assert(Buffer.isBuffer(privateKey));
this.network = bcoin.network.get(network);
this.privateKey = privateKey;
this.compressed = compressed !== false;
this.publicKey = bcoin.ec.publicKeyCreate(this.privateKey, this.compressed);
return this;
};
/**
* Instantiate key pair from a private key.
* @param {Buffer} privateKey
* @param {Boolean?} compressed
* @param {(NetworkType|Network}) network
* @returns {KeyPair}
*/
KeyPair.fromPrivate = function fromPrivate(privateKey, compressed, network) {
return new KeyPair().fromPrivate(privateKey, compressed, network);
};
/**
* Inject data from public key.
* @private
* @param {Buffer} privateKey
* @param {(NetworkType|Network}) network
*/
KeyPair.prototype.fromPublic = function fromPublic(publicKey, network) {
assert(Buffer.isBuffer(publicKey));
this.network = bcoin.network.get(network);
this.publicKey = publicKey;
this.compressed = publicKey[0] <= 0x03;
return this;
};
/**
* Instantiate key pair from a public key.
* @param {Buffer} publicKey
* @param {(NetworkType|Network}) network
* @returns {KeyPair}
*/
KeyPair.fromPublic = function fromPublic(publicKey, network) {
return new KeyPair().fromPublic(publicKey, network);
};
/**
* Sign a message.
* @param {Buffer} msg
* @returns {Buffer} Signature in DER format.
*/
KeyPair.prototype.sign = function sign(msg) {
assert(this.privateKey, 'Cannot sign without private key.');
return bcoin.ec.sign(msg, this.getPrivateKey());
};
/**
* Verify a message.
* @param {Buffer} msg
* @param {Buffer} sig - Signature in DER format.
* @returns {Boolean}
*/
KeyPair.prototype.verify = function verify(msg, sig) {
return bcoin.ec.verify(msg, sig, this.getPublicKey());
};
/**
* Get private key.
* @param {String?} enc - Can be `"hex"`, `"base58"`, or `null`.
* @returns {Buffer} Private key.
*/
KeyPair.prototype.getPrivateKey = function getPrivateKey(enc) {
if (!this.privateKey)
return;
if (enc === 'base58')
return this.toSecret();
if (enc === 'hex')
return this.privateKey.toString('hex');
return this.privateKey;
};
/**
* Get public key.
* @param {String?} enc - Can be `"hex"`, or `null`.
* @returns {Buffer} Public key.
*/
KeyPair.prototype.getPublicKey = function getPublicKey(enc) {
if (enc === 'base58')
return utils.toBase58(this.publicKey);
if (enc === 'hex')
return this.publicKey.toString('hex');
return this.publicKey;
};
/**
* Convert key to a CBitcoinSecret.
* @param {(Network|NetworkType)?} network
* @returns {Buffer}
*/
KeyPair.prototype.toRaw = function toRaw(network, writer) {
var p = new BufferWriter(writer);
assert(this.privateKey, 'Cannot serialize without private key.');
if (!network)
network = this.network;
network = bcoin.network.get(network);
p.writeU8(network.keyPrefix.privkey);
p.writeBytes(this.getPrivateKey());
if (this.compressed)
p.writeU8(1);
p.writeChecksum();
if (!writer)
p = p.render();
return p;
};
/**
* Convert key to a CBitcoinSecret.
* @param {(Network|NetworkType)?} network
* @returns {Base58String}
*/
KeyPair.prototype.toSecret = function toSecret(network) {
return utils.toBase58(this.toRaw(network));
};
/**
* Inject properties from serialized CBitcoinSecret.
* @private
* @param {Buffer} data
*/
KeyPair.prototype.fromRaw = function fromRaw(data) {
var p = new BufferReader(data, true);
var i, prefix, version, type, key, compressed;
version = p.readU8();
for (i = 0; i < network.types.length; i++) {
type = network.types[i];
prefix = network[type].keyPrefix.privkey;
if (version === prefix)
break;
}
assert(i < network.types.length, 'Network not found.');
key = p.readBytes(32);
if (p.left() > 4) {
assert(p.readU8() === 1, 'Bad compression flag.');
compressed = true;
} else {
compressed = false;
}
p.verifyChecksum();
assert(bcoin.ec.privateKeyVerify(key));
return this.fromPrivate(key, compressed, type);
};
/**
* Inject properties from serialized CBitcoinSecret.
* @private
* @param {Base58String} secret
*/
KeyPair.prototype.fromSecret = function fromSecret(secret) {
return this.fromRaw(utils.fromBase58(secret));
};
/**
* Instantiate a key pair from a serialized CBitcoinSecret.
* @param {Buffer} data
* @returns {KeyPair}
*/
KeyPair.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new KeyPair().fromRaw(data);
};
/**
* Instantiate a key pair from a serialized CBitcoinSecret.
* @param {Base58String} secret
* @returns {KeyPair}
*/
KeyPair.fromSecret = function fromSecret(secret) {
return new KeyPair().fromSecret(secret);
};
/**
* Convert the keypair to an object suitable
* for JSON serialization.
* @returns {Object}
*/
KeyPair.prototype.toJSON = function toJSON() {
return {
network: this.network.type,
compressed: this.compressed,
privateKey: this.privateKey ? this.toSecret() : null,
publicKey: this.getPublicKey('base58')
};
};
/**
* Inject properties from json object.
* @private
* @param {Object} json
*/
KeyPair.prototype.fromJSON = function fromJSON(json) {
var key;
if (json.privateKey)
return this.fromSecret(json.privateKey);
if (json.publicKey) {
key = utils.fromBase58(json.publicKey);
assert(bcoin.ec.publicKeyVerify(key));
return this.fromPublic(key, json.network);
}
assert(false, 'Could not parse KeyPair JSON.');
};
/**
* Instantiate a key pair from a jsonified object.
* @param {Object} json - The jsonified key pair object.
* @returns {KeyPair}
*/
KeyPair.fromJSON = function fromJSON(json) {
return new KeyPair().fromJSON(json);
};
/**
* Test whether an object is a key pair.
* @param {Object?} obj
* @returns {Boolean}
*/
KeyPair.isKeyPair = function isKeyPair(obj) {
return obj
&& obj.privateKey !== undefined
&& typeof obj.fromSecret === 'function';
};
/*
* Expose
*/
module.exports = KeyPair;