Migrates ECKey to stricter API
This commit is contained in:
parent
669444cb10
commit
b4f70dcdde
11 changed files with 213 additions and 261 deletions
src
266
src/eckey.js
266
src/eckey.js
|
@ -1,191 +1,149 @@
|
|||
var Address = require('./address')
|
||||
var assert = require('assert')
|
||||
var base58check = require('./base58check')
|
||||
var BigInteger = require('./jsbn/jsbn')
|
||||
var convert = require('./convert')
|
||||
var crypto = require('./crypto')
|
||||
var ecdsa = require('./ecdsa')
|
||||
var ECPointFp = require('./jsbn/ec').ECPointFp
|
||||
var network = require('./network')
|
||||
var secureRandom = require('secure-random')
|
||||
|
||||
var Address = require('./address')
|
||||
var crypto = require('./crypto')
|
||||
|
||||
var sec = require('./jsbn/sec')
|
||||
var Network = require('./network')
|
||||
var ecparams = sec("secp256k1")
|
||||
|
||||
// input can be nothing, array of bytes, hex string, or base58 string
|
||||
var ECKey = function (input, compressed) {
|
||||
if (!(this instanceof ECKey)) { return new ECKey(input, compressed) }
|
||||
if (!input) {
|
||||
// Generate new key
|
||||
var n = ecparams.getN()
|
||||
this.priv = ecdsa.getBigRandom(n)
|
||||
this.compressed = compressed || false
|
||||
var BigInteger = require('./jsbn/jsbn')
|
||||
var ECPointFp = require('./jsbn/ec').ECPointFp
|
||||
|
||||
function ECKey(D, compressed) {
|
||||
assert(D instanceof BigInteger)
|
||||
assert(D.compareTo(BigInteger.ZERO) > 0)
|
||||
assert(D.compareTo(ecparams.getN()) < 0)
|
||||
|
||||
var Q = ecparams.getG().multiply(D)
|
||||
|
||||
this.D = D
|
||||
this.pub = new ECPubKey(Q, compressed)
|
||||
}
|
||||
|
||||
// Static constructors
|
||||
ECKey.fromBuffer = function(buffer, compressed) {
|
||||
assert(Buffer.isBuffer(buffer))
|
||||
var D = BigInteger.fromByteArrayUnsigned(buffer)
|
||||
|
||||
return new ECKey(D, compressed)
|
||||
}
|
||||
ECKey.fromHex = function(hex, compressed) {
|
||||
return ECKey.fromBuffer(new Buffer(hex, 'hex'), compressed)
|
||||
}
|
||||
|
||||
ECKey.fromWIF = function(string) {
|
||||
var decode = base58check.decode(string)
|
||||
|
||||
var payload = decode.payload
|
||||
if (payload.length === 33) {
|
||||
assert(payload[32] === 0x01)
|
||||
|
||||
return ECKey.fromBuffer(payload.slice(0, 32), true)
|
||||
}
|
||||
else this.import(input,compressed)
|
||||
|
||||
assert(payload.length === 32)
|
||||
return ECKey.fromBuffer(payload, false)
|
||||
}
|
||||
|
||||
ECKey.prototype.import = function (input, compressed) {
|
||||
function has(li, v) { return li.indexOf(v) >= 0 }
|
||||
function fromBin(x) { return BigInteger.fromByteArrayUnsigned(x) }
|
||||
ECKey.makeRandom = function(compressed, rng) {
|
||||
rng = rng || secureRandom
|
||||
|
||||
this.priv =
|
||||
input instanceof ECKey ? input.priv
|
||||
: input instanceof BigInteger ? input.mod(ecparams.getN())
|
||||
: Array.isArray(input) ? fromBin(input.slice(0, 32))
|
||||
: Buffer.isBuffer(input) ? fromBin(input.slice(0, 32))
|
||||
: typeof input != "string" ? null
|
||||
: input.length == 44 ? fromBin(convert.base64ToBytes(input))
|
||||
: input.length == 51 && input[0] == '5' ? fromBin(base58check.decode(input).payload)
|
||||
: input.length == 51 && input[0] == '9' ? fromBin(base58check.decode(input).payload)
|
||||
: input.length == 52 && has('LK', input[0]) ? fromBin(base58check.decode(input).payload.slice(0, 32))
|
||||
: input.length == 52 && input[0] == 'c' ? fromBin(base58check.decode(input).payload.slice(0, 32))
|
||||
: has([64,65],input.length) ? fromBin(convert.hexToBytes(input.slice(0, 64)))
|
||||
: null
|
||||
var buffer = new Buffer(rng(32))
|
||||
var D = BigInteger.fromByteArrayUnsigned(buffer)
|
||||
D = D.mod(ecparams.getN())
|
||||
|
||||
assert(this.priv !== null)
|
||||
|
||||
this.compressed =
|
||||
compressed !== undefined ? compressed
|
||||
: input instanceof ECKey ? input.compressed
|
||||
: input instanceof BigInteger ? false
|
||||
: Array.isArray(input) ? false
|
||||
: typeof input != "string" ? null
|
||||
: input.length == 44 ? false
|
||||
: input.length == 51 && input[0] == '5' ? false
|
||||
: input.length == 51 && input[0] == '9' ? false
|
||||
: input.length == 52 && has('LK', input[0]) ? true
|
||||
: input.length == 52 && input[0] == 'c' ? true
|
||||
: input.length == 64 ? false
|
||||
: input.length == 65 ? true
|
||||
: null
|
||||
|
||||
assert(this.compressed !== null)
|
||||
}
|
||||
|
||||
ECKey.prototype.getPub = function(compressed) {
|
||||
if (compressed === undefined) compressed = this.compressed
|
||||
return ECPubKey(ecparams.getG().multiply(this.priv), compressed)
|
||||
}
|
||||
|
||||
ECKey.prototype.toBin = function() {
|
||||
return convert.bytesToString(this.toBytes())
|
||||
}
|
||||
|
||||
ECKey.version_bytes = {
|
||||
0: 128,
|
||||
111: 239
|
||||
}
|
||||
|
||||
ECKey.prototype.toWif = function(version) {
|
||||
version = version || Network.bitcoin.pubKeyHash
|
||||
|
||||
return base58check.encode(this.toBytes(), ECKey.version_bytes[version])
|
||||
}
|
||||
|
||||
ECKey.prototype.toHex = function() {
|
||||
return convert.bytesToHex(this.toBytes())
|
||||
}
|
||||
|
||||
ECKey.prototype.toBytes = function() {
|
||||
var bytes = this.priv.toByteArrayUnsigned()
|
||||
|
||||
// ensure 32 bytes
|
||||
while (bytes.length < 32) bytes.unshift(0)
|
||||
|
||||
if (this.compressed) bytes.push(1)
|
||||
return bytes
|
||||
}
|
||||
|
||||
ECKey.prototype.toBase64 = function() {
|
||||
return convert.bytesToBase64(this.toBytes())
|
||||
}
|
||||
|
||||
ECKey.prototype.toString = ECKey.prototype.toHex
|
||||
|
||||
ECKey.prototype.getAddress = function(version) {
|
||||
return this.getPub().getAddress(version)
|
||||
}
|
||||
|
||||
ECKey.prototype.add = function(key) {
|
||||
return ECKey(this.priv.add(ECKey(key).priv), this.compressed)
|
||||
}
|
||||
|
||||
ECKey.prototype.multiply = function(key) {
|
||||
return ECKey(this.priv.multiply(ECKey(key).priv), this.compressed)
|
||||
return new ECKey(D, compressed)
|
||||
}
|
||||
|
||||
// Operations
|
||||
ECKey.prototype.sign = function(hash) {
|
||||
return ecdsa.sign(hash, this.priv)
|
||||
return ecdsa.sign(hash, this.D)
|
||||
}
|
||||
|
||||
ECKey.prototype.verify = function(hash, sig) {
|
||||
return this.getPub().verify(hash, sig)
|
||||
}
|
||||
// Export functions
|
||||
ECKey.prototype.toBuffer = function() {
|
||||
var buffer = new Buffer(this.D.toByteArrayUnsigned())
|
||||
|
||||
var ECPubKey = function(input, compressed) {
|
||||
if (!(this instanceof ECPubKey)) {
|
||||
return new ECPubKey(input, compressed)
|
||||
// pad out the zero bytes
|
||||
if (buffer.length < 32) {
|
||||
var padded = new Buffer(32)
|
||||
|
||||
padded.fill(0)
|
||||
buffer.copy(padded, 32 - buffer.length)
|
||||
|
||||
return padded
|
||||
}
|
||||
|
||||
this.import(input, compressed)
|
||||
assert(buffer.length === 32)
|
||||
|
||||
return buffer
|
||||
}
|
||||
ECKey.prototype.toHex = function() {
|
||||
return this.toBuffer().toString('hex')
|
||||
}
|
||||
|
||||
ECPubKey.prototype.import = function(input, compressed) {
|
||||
var decode = function(x) { return ECPointFp.decodeFrom(ecparams.getCurve(), x) }
|
||||
ECKey.prototype.toWIF = function(version) {
|
||||
version = version || network.bitcoin.wif
|
||||
|
||||
this.pub =
|
||||
input instanceof ECPointFp ? input
|
||||
: input instanceof ECKey ? ecparams.getG().multiply(input.priv)
|
||||
: input instanceof ECPubKey ? input.pub
|
||||
: typeof input == "string" ? decode(convert.hexToBytes(input))
|
||||
: Array.isArray(input) ? decode(input)
|
||||
: Buffer.isBuffer(input) ? decode(input)
|
||||
: null
|
||||
var buffer
|
||||
if (this.pub.compressed) {
|
||||
buffer = Buffer.concat([this.toBuffer(), new Buffer([0x01])])
|
||||
} else {
|
||||
buffer = this.toBuffer()
|
||||
}
|
||||
|
||||
assert(this.pub !== null)
|
||||
|
||||
this.compressed =
|
||||
compressed ? compressed
|
||||
: input instanceof ECPointFp ? input.compressed
|
||||
: input instanceof ECPubKey ? input.compressed
|
||||
: (this.pub[0] < 4)
|
||||
return base58check.encode(buffer, version)
|
||||
}
|
||||
|
||||
ECPubKey.prototype.add = function(key) {
|
||||
return ECPubKey(this.pub.add(ECPubKey(key).pub), this.compressed)
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
function ECPubKey(Q, compressed) {
|
||||
if (compressed == undefined) compressed = true
|
||||
assert(typeof compressed === 'boolean')
|
||||
assert(Q instanceof ECPointFp)
|
||||
|
||||
this.compressed = compressed
|
||||
this.Q = Q
|
||||
}
|
||||
|
||||
ECPubKey.prototype.multiply = function(key) {
|
||||
return ECPubKey(this.pub.multiply(ECKey(key).priv), this.compressed)
|
||||
// Static constructors
|
||||
ECPubKey.fromBuffer = function(buffer) {
|
||||
assert(Buffer.isBuffer(buffer))
|
||||
|
||||
var Q = ECPointFp.decodeFrom(ecparams.getCurve(), buffer)
|
||||
|
||||
var type = buffer.readUInt8(0)
|
||||
assert(type >= 0x02 || type <= 0x04)
|
||||
|
||||
var compressed = (type !== 0x04)
|
||||
return new ECPubKey(Q, compressed)
|
||||
}
|
||||
ECPubKey.fromHex = function(hex) {
|
||||
return ECPubKey.fromBuffer(new Buffer(hex, 'hex'))
|
||||
}
|
||||
|
||||
ECPubKey.prototype.toBytes = function(compressed) {
|
||||
if (compressed === undefined) compressed = this.compressed
|
||||
return this.pub.getEncoded(compressed)
|
||||
// Operations
|
||||
ECPubKey.prototype.verify = function(hash, sig) {
|
||||
return ecdsa.verify(hash, sig, this.Q)
|
||||
}
|
||||
|
||||
ECPubKey.prototype.toHex = function(compressed) {
|
||||
return convert.bytesToHex(this.toBytes(compressed))
|
||||
}
|
||||
|
||||
ECPubKey.prototype.toBin = function(compressed) {
|
||||
return convert.bytesToString(this.toBytes(compressed))
|
||||
}
|
||||
|
||||
ECPubKey.prototype.toWif = function(version) {
|
||||
version = version || Network.bitcoin.pubKeyHash
|
||||
|
||||
return base58check.encode(this.toBytes(), version)
|
||||
}
|
||||
|
||||
ECPubKey.prototype.toString = ECPubKey.prototype.toHex
|
||||
|
||||
ECPubKey.prototype.getAddress = function(version) {
|
||||
version = version || Network.bitcoin.pubKeyHash
|
||||
|
||||
return new Address(crypto.hash160(this.toBytes()), version)
|
||||
return new Address(crypto.hash160(this.toBuffer()), version)
|
||||
}
|
||||
|
||||
ECPubKey.prototype.verify = function(hash, sig) {
|
||||
return ecdsa.verify(hash, sig, this.toBytes())
|
||||
// Export functions
|
||||
ECPubKey.prototype.toBuffer = function() {
|
||||
var buffer = new Buffer(this.Q.getEncoded(this.compressed))
|
||||
assert(buffer.length === (this.compressed ? 33 : 65))
|
||||
|
||||
return buffer
|
||||
}
|
||||
ECPubKey.prototype.toHex = function() {
|
||||
return this.toBuffer().toString('hex')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue