2013-02-17 00:39:15 -05:00
|
|
|
var BigInteger = require('./jsbn/jsbn');
|
|
|
|
var sec = require('./jsbn/sec');
|
|
|
|
var base58 = require('./base58');
|
|
|
|
var Crypto = require('./crypto-js/crypto');
|
|
|
|
var util = require('./util');
|
|
|
|
var conv = require('./convert');
|
|
|
|
var Address = require('./address');
|
|
|
|
var ecdsa = require('./ecdsa');
|
2013-11-18 23:47:56 -05:00
|
|
|
var ECPointFp = require('./jsbn/ec').ECPointFp;
|
2013-02-17 00:39:15 -05:00
|
|
|
|
|
|
|
var ecparams = sec("secp256k1");
|
|
|
|
|
|
|
|
// input can be nothing, array of bytes, hex string, or base58 string
|
|
|
|
var ECKey = function (input) {
|
2013-11-18 23:47:56 -05:00
|
|
|
if (!(this instanceof ECKey)) {
|
|
|
|
return new ECKey(input);
|
2012-01-11 02:40:45 +01:00
|
|
|
}
|
2013-11-18 23:47:56 -05:00
|
|
|
|
|
|
|
this.compressed = !!ECKey.compressByDefault;
|
|
|
|
|
|
|
|
if (!input) {
|
|
|
|
// Generate new key
|
|
|
|
var n = ecparams.getN();
|
|
|
|
this.priv = ecdsa.getBigRandom(n);
|
2012-08-02 20:03:13 +02:00
|
|
|
}
|
2013-11-18 23:47:56 -05:00
|
|
|
else this.import(input)
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether public keys should be returned compressed by default.
|
|
|
|
*/
|
|
|
|
ECKey.compressByDefault = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set whether the public key should be returned compressed or not.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.setCompressed = function (v) {
|
|
|
|
this.compressed = !!v;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return public key in DER encoding.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.getPub = function () {
|
2013-11-18 23:47:56 -05:00
|
|
|
return this.getPubPoint().getEncoded(this.compressed);
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return public point as ECPoint object.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.getPubPoint = function () {
|
2013-11-18 23:47:56 -05:00
|
|
|
if (!this.pub) this.pub = ecparams.getG().multiply(this.priv);
|
|
|
|
return this.pub;
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the pubKeyHash for this key.
|
|
|
|
*
|
|
|
|
* This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as
|
|
|
|
* a byte array.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.getPubKeyHash = function () {
|
2013-11-18 23:47:56 -05:00
|
|
|
if (this.pubKeyHash) return this.pubKeyHash;
|
|
|
|
return this.pubKeyHash = util.sha256ripe160(this.getPub());
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
|
|
|
|
2014-01-02 20:33:23 -05:00
|
|
|
ECKey.prototype.getBitcoinAddress = function (version) {
|
2013-11-18 23:47:56 -05:00
|
|
|
var hash = this.getPubKeyHash();
|
2014-01-02 20:33:23 -05:00
|
|
|
var addr = new Address(hash,version);
|
2013-11-18 23:47:56 -05:00
|
|
|
return addr;
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
|
|
|
|
2013-11-18 23:47:56 -05:00
|
|
|
ECKey.prototype.setPub = function (pub) {
|
|
|
|
this.pub = ECPointFp.decodeFrom(ecparams.getCurve(), pub);
|
|
|
|
this.compressed = (pub[0] < 4)
|
|
|
|
return this
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
|
|
|
|
2013-11-18 23:47:56 -05:00
|
|
|
ECKey.prototype.export = function (format) {
|
|
|
|
var bytes = this.priv.toByteArrayUnsigned();
|
|
|
|
if (this.compressed)
|
|
|
|
bytes.push(1)
|
|
|
|
return format === "base58" ? base58.checkEncode(bytes,128)
|
|
|
|
: format === "bin" ? conv.bytesToString(bytes)
|
|
|
|
: format === "bytes" ? bytes
|
|
|
|
: format === "hex" ? conv.bytesToHex(bytes)
|
|
|
|
: bytes
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
2013-11-18 23:47:56 -05:00
|
|
|
ECKey.prototype.getExportedPrivateKey = ECKey.prototype.export;
|
2013-02-17 00:39:15 -05:00
|
|
|
|
|
|
|
ECKey.prototype.toString = function (format) {
|
2013-11-18 23:47:56 -05:00
|
|
|
return ''+this.export(format)
|
|
|
|
}
|
2013-02-17 00:39:15 -05:00
|
|
|
|
|
|
|
ECKey.prototype.sign = function (hash) {
|
|
|
|
return ecdsa.sign(hash, this.priv);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECKey.prototype.verify = function (hash, sig) {
|
|
|
|
return ecdsa.verify(hash, sig, this.getPub());
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse an exported private key contained in a string.
|
|
|
|
*/
|
2013-11-18 23:47:56 -05:00
|
|
|
ECKey.prototype.import = function (input) {
|
|
|
|
if (input instanceof ECKey) {
|
|
|
|
this.priv = input.priv;
|
|
|
|
this.compressed = input.compressed;
|
|
|
|
}
|
|
|
|
else if (input instanceof BigInteger) {
|
|
|
|
// Input is a private key value
|
|
|
|
this.priv = input;
|
|
|
|
this.compressed = ECKey.compressByDefault;
|
|
|
|
}
|
|
|
|
else if (util.isArray(input)) {
|
|
|
|
// Prepend zero byte to prevent interpretation as negative integer
|
|
|
|
this.priv = BigInteger.fromByteArrayUnsigned(input.slice(0,32));
|
|
|
|
this.compressed = (input.length == 33);
|
|
|
|
}
|
|
|
|
else if ("string" == typeof input) {
|
|
|
|
if (input.length == 51 && input[0] == '5') {
|
|
|
|
// Base58 encoded private key
|
|
|
|
this.priv = BigInteger.fromByteArrayUnsigned(base58.checkDecode(input));
|
|
|
|
this.compressed = false;
|
|
|
|
}
|
|
|
|
else if (input.length == 52 && (input[0] === 'K' || input[0] === 'L')) {
|
|
|
|
// Base58 encoded private key
|
|
|
|
this.priv = BigInteger.fromByteArrayUnsigned(base58.checkDecode(input));
|
|
|
|
this.compressed = true;
|
|
|
|
}
|
|
|
|
else if (input.length >= 64) {
|
|
|
|
// hex string?
|
|
|
|
this.priv = BigInteger.fromByteArrayUnsigned(conv.hexToBytes(input.slice(0,64)));
|
|
|
|
this.compressed = (input.length == 66)
|
|
|
|
}
|
|
|
|
}
|
2013-02-17 00:39:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = ECKey;
|