bitcoinjs-lib/src/ecpair.js
2015-08-14 10:56:31 +10:00

157 lines
3.7 KiB
JavaScript

var bs58check = require('bs58check')
var bcrypto = require('./crypto')
var ecdsa = require('./ecdsa')
var ecurve = require('ecurve')
var NETWORKS = require('./networks')
var randomBytes = require('randombytes')
var typeforce = require('typeforce')
var types = require('./types')
var BigInteger = require('bigi')
function ECPair (d, Q, options) {
options = options || {}
typeforce({
compressed: types.maybe(types.Boolean),
network: types.maybe(types.Network)
}, options)
if (d) {
if (d.signum() <= 0) throw new Error('Private key must be greater than 0')
if (d.compareTo(ECPair.curve.n) >= 0) throw new Error('Private key must be less than the curve order')
if (Q) throw new TypeError('Unexpected publicKey parameter')
this.d = d
} else {
typeforce(types.ECPoint, Q)
this.__Q = Q
}
this.compressed = options.compressed === undefined ? true : options.compressed
this.network = options.network || NETWORKS.bitcoin
}
Object.defineProperty(ECPair.prototype, 'Q', {
get: function () {
if (!this.__Q && this.d) {
this.__Q = ECPair.curve.G.multiply(this.d)
}
return this.__Q
}
})
// Public access to secp256k1 curve
ECPair.curve = ecurve.getCurveByName('secp256k1')
ECPair.fromPublicKeyBuffer = function (buffer, network) {
var Q = ecurve.Point.decodeFrom(ECPair.curve, buffer)
return new ECPair(null, Q, {
compressed: Q.compressed,
network: network
})
}
ECPair.fromWIF = function (string, networks) {
var payload = bs58check.decode(string)
var version = payload.readUInt8(0)
var compressed
if (payload.length === 34) {
if (payload[33] !== 0x01) throw new Error('Invalid compression flag')
// truncate the version/compression bytes
payload = payload.slice(1, -1)
compressed = true
// no compression flag
} else {
if (payload.length !== 33) throw new Error('Invalid WIF payload length')
// Truncate the version byte
payload = payload.slice(1)
compressed = false
}
var network
// list of networks?
if (Array.isArray(networks)) {
network = networks.filter(function (network) {
return version === network.wif
}).pop() || {}
// otherwise, assume a network object (or default to bitcoin)
} else {
network = networks || NETWORKS.bitcoin
}
if (version !== network.wif) throw new Error('Invalid network')
var d = BigInteger.fromBuffer(payload)
return new ECPair(d, null, {
compressed: compressed,
network: network
})
}
ECPair.makeRandom = function (options) {
options = options || {}
var rng = options.rng || randomBytes
var buffer = rng(32)
typeforce(types.Buffer256bit, buffer)
var d = BigInteger.fromBuffer(buffer)
d = d.mod(ECPair.curve.n)
return new ECPair(d, null, options)
}
ECPair.prototype.toWIF = function () {
if (!this.d) throw new Error('Missing private key')
var bufferLen = this.compressed ? 34 : 33
var buffer = new Buffer(bufferLen)
buffer.writeUInt8(this.network.wif, 0)
this.d.toBuffer(32).copy(buffer, 1)
if (this.compressed) {
buffer.writeUInt8(0x01, 33)
}
return bs58check.encode(buffer)
}
ECPair.prototype.getAddress = function () {
var pubKey = this.getPublicKeyBuffer()
var pubKeyHash = bcrypto.hash160(pubKey)
var payload = new Buffer(21)
payload.writeUInt8(this.network.pubKeyHash, 0)
pubKeyHash.copy(payload, 1)
return bs58check.encode(payload)
}
ECPair.prototype.getPublicKeyBuffer = function () {
return this.Q.getEncoded(this.compressed)
}
ECPair.prototype.sign = function (hash) {
if (!this.d) throw new Error('Missing private key')
return ecdsa.sign(ECPair.curve, hash, this.d)
}
ECPair.prototype.verify = function (hash, signature) {
return ecdsa.verify(ECPair.curve, hash, signature, this.Q)
}
module.exports = ECPair