2014-10-17 04:31:01 +02:00
|
|
|
var bcrypto = require('./crypto')
|
2015-08-19 07:12:55 +02:00
|
|
|
var bs58check = require('bs58check')
|
2014-10-17 04:31:01 +02:00
|
|
|
var ecdsa = require('./ecdsa')
|
|
|
|
var randomBytes = require('randombytes')
|
2015-08-11 09:01:47 +02:00
|
|
|
var typeforce = require('typeforce')
|
|
|
|
var types = require('./types')
|
2015-08-20 12:16:57 +02:00
|
|
|
var wif = require('wif')
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2015-08-19 07:12:55 +02:00
|
|
|
var NETWORKS = require('./networks')
|
2014-10-17 04:31:01 +02:00
|
|
|
var BigInteger = require('bigi')
|
|
|
|
|
2015-08-25 12:43:32 +02:00
|
|
|
var ecurve = require('ecurve')
|
|
|
|
var secp256k1 = ecdsa.__curve
|
2015-08-19 07:12:55 +02:00
|
|
|
|
2014-10-17 04:31:01 +02:00
|
|
|
function ECPair (d, Q, options) {
|
2015-08-19 07:12:55 +02:00
|
|
|
if (options) {
|
|
|
|
typeforce({
|
|
|
|
compressed: types.maybe(types.Boolean),
|
|
|
|
network: types.maybe(types.Network)
|
|
|
|
}, options)
|
|
|
|
}
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2015-08-19 07:12:55 +02:00
|
|
|
options = options || {}
|
2014-10-17 04:31:01 +02:00
|
|
|
|
|
|
|
if (d) {
|
2015-08-11 09:01:47 +02:00
|
|
|
if (d.signum() <= 0) throw new Error('Private key must be greater than 0')
|
2015-08-19 07:12:55 +02:00
|
|
|
if (d.compareTo(secp256k1.n) >= 0) throw new Error('Private key must be less than the curve order')
|
2015-08-11 09:01:47 +02:00
|
|
|
if (Q) throw new TypeError('Unexpected publicKey parameter')
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2015-03-19 03:25:41 +01:00
|
|
|
this.d = d
|
2014-10-17 04:31:01 +02:00
|
|
|
} else {
|
2015-08-11 09:01:47 +02:00
|
|
|
typeforce(types.ECPoint, Q)
|
|
|
|
|
2015-03-19 03:25:41 +01:00
|
|
|
this.__Q = Q
|
2014-10-17 04:31:01 +02:00
|
|
|
}
|
|
|
|
|
2015-08-11 09:01:47 +02:00
|
|
|
this.compressed = options.compressed === undefined ? true : options.compressed
|
|
|
|
this.network = options.network || NETWORKS.bitcoin
|
2014-10-17 04:31:01 +02:00
|
|
|
}
|
|
|
|
|
2015-03-19 03:25:41 +01:00
|
|
|
Object.defineProperty(ECPair.prototype, 'Q', {
|
2015-03-19 03:35:25 +01:00
|
|
|
get: function () {
|
2015-03-19 03:25:41 +01:00
|
|
|
if (!this.__Q && this.d) {
|
2015-08-19 07:12:55 +02:00
|
|
|
this.__Q = secp256k1.G.multiply(this.d)
|
2015-03-19 03:25:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.__Q
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2014-10-17 04:31:01 +02:00
|
|
|
ECPair.fromPublicKeyBuffer = function (buffer, network) {
|
2015-08-19 07:12:55 +02:00
|
|
|
var Q = ecurve.Point.decodeFrom(secp256k1, buffer)
|
2014-10-17 04:31:01 +02:00
|
|
|
|
|
|
|
return new ECPair(null, Q, {
|
|
|
|
compressed: Q.compressed,
|
|
|
|
network: network
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-08-20 12:16:57 +02:00
|
|
|
ECPair.fromWIF = function (string, network) {
|
|
|
|
network = network || NETWORKS.bitcoin
|
|
|
|
var buffer = bs58check.decode(string)
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2015-08-20 12:16:57 +02:00
|
|
|
if (types.Array(network)) {
|
|
|
|
var version = buffer[0]
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2015-08-20 12:16:57 +02:00
|
|
|
network = network.filter(function (network) {
|
2015-07-28 09:47:18 +02:00
|
|
|
return version === network.wif
|
2015-07-28 08:42:57 +02:00
|
|
|
}).pop() || {}
|
|
|
|
}
|
|
|
|
|
2015-08-20 12:16:57 +02:00
|
|
|
var decoded = wif.decodeRaw(network.wif, buffer)
|
|
|
|
var d = BigInteger.fromBuffer(decoded.d)
|
2014-10-17 04:31:01 +02:00
|
|
|
|
|
|
|
return new ECPair(d, null, {
|
2015-08-20 12:16:57 +02:00
|
|
|
compressed: decoded.compressed,
|
2014-10-17 04:31:01 +02:00
|
|
|
network: network
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
ECPair.makeRandom = function (options) {
|
|
|
|
options = options || {}
|
|
|
|
|
|
|
|
var rng = options.rng || randomBytes
|
|
|
|
|
2015-08-21 08:46:18 +02:00
|
|
|
var d
|
|
|
|
do {
|
|
|
|
var buffer = rng(32)
|
|
|
|
typeforce(types.Buffer256bit, buffer)
|
|
|
|
|
|
|
|
d = BigInteger.fromBuffer(buffer)
|
2015-09-08 15:45:37 +02:00
|
|
|
} while (d.signum() === 0 || d.compareTo(secp256k1.n) >= 0)
|
2014-10-17 04:31:01 +02:00
|
|
|
|
|
|
|
return new ECPair(d, null, options)
|
|
|
|
}
|
|
|
|
|
|
|
|
ECPair.prototype.getAddress = function () {
|
|
|
|
var pubKey = this.getPublicKeyBuffer()
|
2015-07-08 07:56:21 +02:00
|
|
|
var pubKeyHash = bcrypto.hash160(pubKey)
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2015-07-08 07:56:21 +02:00
|
|
|
var payload = new Buffer(21)
|
|
|
|
payload.writeUInt8(this.network.pubKeyHash, 0)
|
|
|
|
pubKeyHash.copy(payload, 1)
|
|
|
|
|
|
|
|
return bs58check.encode(payload)
|
2014-10-17 04:31:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ECPair.prototype.getPublicKeyBuffer = function () {
|
|
|
|
return this.Q.getEncoded(this.compressed)
|
|
|
|
}
|
|
|
|
|
|
|
|
ECPair.prototype.sign = function (hash) {
|
2015-08-11 09:03:10 +02:00
|
|
|
if (!this.d) throw new Error('Missing private key')
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2015-08-25 12:43:32 +02:00
|
|
|
return ecdsa.sign(hash, this.d)
|
2014-10-17 04:31:01 +02:00
|
|
|
}
|
|
|
|
|
2015-08-20 12:16:57 +02:00
|
|
|
ECPair.prototype.toWIF = function () {
|
|
|
|
if (!this.d) throw new Error('Missing private key')
|
|
|
|
|
|
|
|
return wif.encode(this.network.wif, this.d.toBuffer(32), this.compressed)
|
|
|
|
}
|
|
|
|
|
2014-10-17 04:31:01 +02:00
|
|
|
ECPair.prototype.verify = function (hash, signature) {
|
2015-08-25 12:43:32 +02:00
|
|
|
return ecdsa.verify(hash, signature, this.Q)
|
2014-10-17 04:31:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = ECPair
|