Merge pull request #713 from braydonf/ref/private-key-network

PrivateKey: Add docs and refactor to use network object
This commit is contained in:
Manuel Aráoz 2014-12-11 17:20:24 -03:00
commit d1b4c25c6f
3 changed files with 87 additions and 49 deletions

56
docs/PrivateKey.md Normal file
View File

@ -0,0 +1,56 @@
# Private Key
Represents a bitcoin private key and is needed to be able to spend bitcoin and sign transactions. See the official [Bitcoin Wiki](https://en.bitcoin.it/wiki/Private_key) for more information about private keys. A PrivateKey in Bitcore is an immutable object that has methods to import and export into a variety of formats including [Wallet Import Format](https://en.bitcoin.it/wiki/Wallet_import_format).
## Instantiate a Private Key
Here is how to create a new private key. It will generate a new random number using `window.crypto` or the Node.js 'crypto' library.
```javascript
var PrivateKey = require('bitcore/lib/privatekey');
var privateKey = new PrivateKey();
```
To export and import a private key, you can do the following:
```javascript
// encode into wallet export format
var exported = privateKey.toWIF();
// instantiate from the exported (and saved) private key
var imported = PrivateKey.fromWIF('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m');
```
Note: The WIF (Wallet Import Format) includes information about the network and if the associated public key is compressed or uncompressed (thus the same bitcoin address will be generated by using this format).
To generate an Address or PublicKey from a PrivateKey:
```javascript
var address = privateKey.toAddress();
var publicKey = privateKey.toPublicKey();
```
## Validating a Private Key
The code to do these validations looks like this:
```javascript
// validate an address
if (PrivateKey.isValid(input)){
...
}
// get the specific validation error that can occurred
var error = PrivateKey.getValidationError(input, Networks.livenet);
if (error) {
// handle the error
}
```

View File

@ -1,16 +1,15 @@
'use strict'; 'use strict';
var BN = require('./crypto/bn');
var Point = require('./crypto/point');
var Random = require('./crypto/random');
var networks = require('./networks');
var base58check = require('./encoding/base58check');
var Address = require('./address'); var Address = require('./address');
var PublicKey = require('./publickey'); var base58check = require('./encoding/base58check');
var BN = require('./crypto/bn');
var jsUtil = require('./util/js'); var jsUtil = require('./util/js');
var Networks = require('./networks');
var Point = require('./crypto/point');
var PublicKey = require('./publickey');
var Random = require('./crypto/random');
/** /**
*
* Instantiate a PrivateKey from a BN, Buffer and WIF. * Instantiate a PrivateKey from a BN, Buffer and WIF.
* *
* @example * @example
@ -21,12 +20,12 @@ var jsUtil = require('./util/js');
* // get the associated address * // get the associated address
* var address = key.toAddress(); * var address = key.toAddress();
* *
* // encode into wallet export format * // encode into wallet export format
* var exported = key.toWIF(); * var exported = key.toWIF();
* *
* // instantiate from the exported (and saved) private key * // instantiate from the exported (and saved) private key
* var imported = PrivateKey.fromWIF(exported); * var imported = PrivateKey.fromWIF(exported);
* *
* @param {String} data - The encoded data in various formats * @param {String} data - The encoded data in various formats
* @param {String} [network] - Either "livenet" or "testnet" * @param {String} [network] - Either "livenet" or "testnet"
* @param {Boolean} [compressed] - If the key is in compressed format * @param {Boolean} [compressed] - If the key is in compressed format
@ -41,7 +40,7 @@ var PrivateKey = function PrivateKey(data, network, compressed) {
var info = { var info = {
compressed: typeof(compressed) !== 'undefined' ? compressed : true, compressed: typeof(compressed) !== 'undefined' ? compressed : true,
network: network || networks.defaultNetwork.name network: network ? Networks.get(network) : Networks.defaultNetwork
}; };
// detect type of data // detect type of data
@ -65,7 +64,7 @@ var PrivateKey = function PrivateKey(data, network, compressed) {
if (!info.bn.lt(Point.getN())) { if (!info.bn.lt(Point.getN())) {
throw new TypeError('Number must be less than N'); throw new TypeError('Number must be less than N');
} }
if (typeof(networks[info.network]) === 'undefined') { if (typeof(info.network) === 'undefined') {
throw new TypeError('Must specify the network ("livenet" or "testnet")'); throw new TypeError('Must specify the network ("livenet" or "testnet")');
} }
if (typeof(info.compressed) !== 'boolean') { if (typeof(info.compressed) !== 'boolean') {
@ -102,10 +101,9 @@ var PrivateKey = function PrivateKey(data, network, compressed) {
}; };
/** /**
*
* Internal function to get a random BN * Internal function to get a random BN
* *
* @returns {Object} An object with keys: bn, network and compressed * @returns {BN} A new randomly generated BN
* @private * @private
*/ */
PrivateKey._getRandomBN = function(){ PrivateKey._getRandomBN = function(){
@ -120,10 +118,9 @@ PrivateKey._getRandomBN = function(){
}; };
/** /**
* Internal function to transform a WIF Buffer into a private key
* *
* Internal function to transform a WIF Buffer into a private key * @param {Buffer} buf - An WIF string
*
* @param {Buffer} buf - An WIF string
* @param {String} [network] - Either "livenet" or "testnet" * @param {String} [network] - Either "livenet" or "testnet"
* @param {String} [compressed] - If the private key is compressed * @param {String} [compressed] - If the private key is compressed
* @returns {Object} An object with keys: bn, network and compressed * @returns {Object} An object with keys: bn, network and compressed
@ -141,22 +138,22 @@ PrivateKey._transformBuffer = function(buf, network, compressed) {
throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)'); throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)');
} }
if (buf[0] === networks.livenet.privatekey) { if (buf[0] === Networks.livenet.privatekey) {
info.network = networks.livenet.name; info.network = Networks.livenet;
} else if (buf[0] === networks.testnet.privatekey) { } else if (buf[0] === Networks.testnet.privatekey) {
info.network = networks.testnet.name; info.network = Networks.testnet;
} else { } else {
throw new Error('Invalid network'); throw new Error('Invalid network');
} }
if (network && networks.get(info.network) !== networks.get(network)) { if (network && info.network !== Networks.get(network)) {
throw TypeError('Private key network mismatch'); throw TypeError('Private key network mismatch');
} }
if (typeof(compressed) !== 'undefined' && info.compressed !== compressed){ if (typeof(compressed) !== 'undefined' && info.compressed !== compressed){
throw TypeError('Private key compression mismatch'); throw TypeError('Private key compression mismatch');
} }
info.bn = BN.fromBuffer(buf.slice(1, 32 + 1)); info.bn = BN.fromBuffer(buf.slice(1, 32 + 1));
return info; return info;
@ -164,10 +161,9 @@ PrivateKey._transformBuffer = function(buf, network, compressed) {
}; };
/** /**
* Internal function to transform a WIF string into a private key
* *
* Internal function to transform a WIF string into a private key * @param {String} buf - An WIF string
*
* @param {String} buf - An WIF string
* @returns {Object} An object with keys: bn, network and compressed * @returns {Object} An object with keys: bn, network and compressed
* @private * @private
*/ */
@ -176,7 +172,6 @@ PrivateKey._transformWIF = function(str, network, compressed) {
}; };
/** /**
*
* Instantiate a PrivateKey from a WIF string * Instantiate a PrivateKey from a WIF string
* *
* @param {String} str - The WIF encoded private key string * @param {String} str - The WIF encoded private key string
@ -188,7 +183,6 @@ PrivateKey.fromWIF = function(str) {
}; };
/** /**
*
* Instantiate a PrivateKey from a WIF JSON string * Instantiate a PrivateKey from a WIF JSON string
* *
* @param {String} str - The WIF encoded private key string * @param {String} str - The WIF encoded private key string
@ -200,7 +194,6 @@ PrivateKey.fromJSON = function(json) {
}; };
/** /**
*
* Instantiate a PrivateKey from random bytes * Instantiate a PrivateKey from random bytes
* *
* @param {String} [network] - Either "livenet" or "testnet" * @param {String} [network] - Either "livenet" or "testnet"
@ -213,7 +206,6 @@ PrivateKey.fromRandom = function(network, compressed) {
}; };
/** /**
*
* Instantiate a PrivateKey from a WIF string * Instantiate a PrivateKey from a WIF string
* *
* @param {String} str - The WIF encoded private key string * @param {String} str - The WIF encoded private key string
@ -225,7 +217,6 @@ PrivateKey.fromString = function(str) {
}; };
/** /**
*
* Check if there would be any errors when initializing a PrivateKey * Check if there would be any errors when initializing a PrivateKey
* *
* @param {String} data - The encoded data in various formats * @param {String} data - The encoded data in various formats
@ -245,7 +236,6 @@ PrivateKey.getValidationError = function(data, network, compressed) {
}; };
/** /**
*
* Check if the parameters are valid * Check if the parameters are valid
* *
* @param {String} data - The encoded data in various formats * @param {String} data - The encoded data in various formats
@ -258,7 +248,6 @@ PrivateKey.isValid = function(data, network, compressed){
}; };
/** /**
*
* Will output the PrivateKey to a WIF string * Will output the PrivateKey to a WIF string
* *
* @returns {String} A WIP representation of the private key * @returns {String} A WIP representation of the private key
@ -269,11 +258,11 @@ PrivateKey.prototype.toWIF = function() {
var buf; var buf;
if (compressed) { if (compressed) {
buf = Buffer.concat([new Buffer([networks[network].privatekey]), buf = Buffer.concat([new Buffer([network.privatekey]),
this.bn.toBuffer({size: 32}), this.bn.toBuffer({size: 32}),
new Buffer([0x01])]); new Buffer([0x01])]);
} else { } else {
buf = Buffer.concat([new Buffer([networks[network].privatekey]), buf = Buffer.concat([new Buffer([network.privatekey]),
this.bn.toBuffer({size: 32})]); this.bn.toBuffer({size: 32})]);
} }
@ -281,7 +270,6 @@ PrivateKey.prototype.toWIF = function() {
}; };
/** /**
*
* Will return the private key as a BN instance * Will return the private key as a BN instance
* *
* @returns {BN} A BN instance of the private key * @returns {BN} A BN instance of the private key
@ -291,7 +279,6 @@ PrivateKey.prototype.toBigNumber = function(){
}; };
/** /**
*
* Will return the private key as a BN buffer * Will return the private key as a BN buffer
* *
* @returns {Buffer} A buffer of the private key * @returns {Buffer} A buffer of the private key
@ -301,7 +288,6 @@ PrivateKey.prototype.toBuffer = function(){
}; };
/** /**
*
* Will return the corresponding public key * Will return the corresponding public key
* *
* @returns {PublicKey} A public key generated from the private key * @returns {PublicKey} A public key generated from the private key
@ -311,7 +297,6 @@ PrivateKey.prototype.toPublicKey = function(){
}; };
/** /**
*
* Will return an address for the private key * Will return an address for the private key
* *
* @returns {Address} An address generated from the private key * @returns {Address} An address generated from the private key
@ -322,7 +307,6 @@ PrivateKey.prototype.toAddress = function() {
}; };
/** /**
*
* Will output the PrivateKey to a WIF string * Will output the PrivateKey to a WIF string
* *
* @returns {String} A WIF representation of the private key * @returns {String} A WIF representation of the private key
@ -332,7 +316,6 @@ PrivateKey.prototype.toJSON = function() {
}; };
/** /**
*
* Will output the PrivateKey to a WIF string * Will output the PrivateKey to a WIF string
* *
* @returns {String} A WIF representation of the private key * @returns {String} A WIF representation of the private key
@ -342,7 +325,6 @@ PrivateKey.prototype.toString = function() {
}; };
/** /**
*
* Will return a string formatted for the console * Will return a string formatted for the console
* *
* @returns {String} Private key * @returns {String} Private key

View File

@ -5,7 +5,7 @@ var bitcore = require('..');
var BN = bitcore.crypto.BN; var BN = bitcore.crypto.BN;
var Point = bitcore.crypto.Point; var Point = bitcore.crypto.Point;
var PrivateKey = bitcore.PrivateKey; var PrivateKey = bitcore.PrivateKey;
var networks = bitcore.Networks; var Networks = bitcore.Networks;
var base58check = bitcore.encoding.Base58Check; var base58check = bitcore.encoding.Base58Check;
describe('PrivateKey', function() { describe('PrivateKey', function() {
@ -110,13 +110,13 @@ describe('PrivateKey', function() {
it('should create a default network private key', function() { it('should create a default network private key', function() {
var a = new PrivateKey(BN.fromBuffer(buf)); var a = new PrivateKey(BN.fromBuffer(buf));
a.network.should.equal('livenet'); a.network.should.equal(Networks.livenet);
// change the default // change the default
networks.defaultNetwork = networks.testnet; Networks.defaultNetwork = Networks.testnet;
var b = new PrivateKey(BN.fromBuffer(buf)); var b = new PrivateKey(BN.fromBuffer(buf));
b.network.should.equal('testnet'); b.network.should.equal(Networks.testnet);
// restore the default // restore the default
networks.defaultNetwork = networks.livenet; Networks.defaultNetwork = Networks.livenet;
}); });
it('should create an uncompressed testnet private key', function() { it('should create an uncompressed testnet private key', function() {