Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ These examples assume you are running bitcoinjs-lib in the browser.

```javascript

key = new Bitcoin.ECKey()
key = Bitcoin.ECKey.makeRandom()

// Print your private key (a hex string)
console.log(key.toString())
// => 8c112cf628362ecf4d482f68af2dbb50c8a2cb90d226215de925417aa9336a48

// Print your public key (defaults to a Bitcoin address)
console.log(key.getPub().getAddress())
console.log(key.pub.getAddress())
// => 14bZ7YWde4KdRb5YN7GYkToz3EHVCvRxkF
```

Expand All @@ -72,7 +72,7 @@ tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31",
tx.addOutput("1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK", 15000)

// Initialize a private key using hex
key = new Bitcoin.ECKey("8c112cf628362ecf4d482f68af2dbb50c8a2cb90d226215de925417aa9336a48")
key = Bitcoin.ECKey.fromHex("8c112cf628362ecf4d482f68af2dbb50c8a2cb90d226215de925417aa9336a48")

// Sign the first input with the new key
tx.sign(0, key)
Expand Down
222 changes: 83 additions & 139 deletions src/eckey.js
Original file line number Diff line number Diff line change
@@ -1,191 +1,135 @@
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 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
}
else this.import(input,compressed)
}
var network = require('./network')
var secureRandom = require('secure-random')

ECKey.prototype.import = function (input, compressed) {
function has(li, v) { return li.indexOf(v) >= 0 }
function fromBin(x) { return BigInteger.fromByteArrayUnsigned(x) }
var Address = require('./address')
var crypto = require('./crypto')

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 sec = require('./jsbn/sec')
var ecparams = sec('secp256k1')

assert(this.priv !== null)
var BigInteger = require('./jsbn/jsbn')
var ECPointFp = require('./jsbn/ec').ECPointFp

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
function ECKey(D, compressed) {
assert(D.compareTo(BigInteger.ZERO) > 0, 'Private key must be greater than 0')
assert(D.compareTo(ecparams.getN()) < 0, 'Private key must be less than the curve order')

assert(this.compressed !== null)
}
var Q = ecparams.getG().multiply(D)

ECKey.prototype.getPub = function(compressed) {
if (compressed === undefined) compressed = this.compressed
return ECPubKey(ecparams.getG().multiply(this.priv), compressed)
this.D = D
this.pub = new ECPubKey(Q, compressed)
}

ECKey.prototype.toBin = function() {
return convert.bytesToString(this.toBytes())
}
// Static constructors
ECKey.fromBuffer = function(buffer, compressed) {
assert(Buffer.isBuffer(buffer), 'First argument must be a Buffer')
assert.strictEqual(buffer.length, 32, 'Invalid buffer length')

ECKey.version_bytes = {
0: 128,
111: 239
var D = BigInteger.fromByteArrayUnsigned(buffer)
return new ECKey(D, compressed)
}

ECKey.prototype.toWif = function(version) {
version = version || Network.bitcoin.pubKeyHash

return base58check.encode(this.toBytes(), ECKey.version_bytes[version])
ECKey.fromHex = function(hex, compressed) {
return ECKey.fromBuffer(new Buffer(hex, 'hex'), compressed)
}

ECKey.prototype.toHex = function() {
return convert.bytesToHex(this.toBytes())
}
ECKey.fromWIF = function(string) {
var decode = base58check.decode(string)

ECKey.prototype.toBytes = function() {
var bytes = this.priv.toByteArrayUnsigned()
var payload = decode.payload
if (payload.length === 33) {
assert.strictEqual(payload[32], 0x01, 'Invalid WIF string')

// ensure 32 bytes
while (bytes.length < 32) bytes.unshift(0)
return ECKey.fromBuffer(payload.slice(0, 32), true)
}

if (this.compressed) bytes.push(1)
return bytes
return ECKey.fromBuffer(payload, false)
}

ECKey.prototype.toBase64 = function() {
return convert.bytesToBase64(this.toBytes())
}
ECKey.makeRandom = function(compressed, rng) {
rng = rng || secureRandom

ECKey.prototype.toString = ECKey.prototype.toHex
var buffer = new Buffer(rng(32))
var D = BigInteger.fromByteArrayUnsigned(buffer)
D = D.mod(ecparams.getN())

ECKey.prototype.getAddress = function(version) {
return this.getPub().getAddress(version)
return new ECKey(D, compressed)
}

ECKey.prototype.add = function(key) {
return ECKey(this.priv.add(ECKey(key).priv), this.compressed)
// Operations
ECKey.prototype.sign = function(hash) {
return ecdsa.sign(hash, this.D)
}

ECKey.prototype.multiply = function(key) {
return ECKey(this.priv.multiply(ECKey(key).priv), this.compressed)
}
// Export functions
ECKey.prototype.toBuffer = function() {
var buffer = new Buffer(this.D.toByteArrayUnsigned())

ECKey.prototype.sign = function(hash) {
return ecdsa.sign(hash, this.priv)
}
// pad out to atleast 32 bytes
var padded = new Buffer(32 - buffer.length)
padded.fill(0)

ECKey.prototype.verify = function(hash, sig) {
return this.getPub().verify(hash, sig)
return Buffer.concat([padded, buffer])
}
ECKey.prototype.toHex = function() {
return this.toBuffer().toString('hex')
}

ECKey.prototype.toWIF = function(version) {
version = version || network.bitcoin.wif

var ECPubKey = function(input, compressed) {
if (!(this instanceof ECPubKey)) {
return new ECPubKey(input, compressed)
var buffer = this.toBuffer()
if (this.pub.compressed) {
buffer = Buffer.concat([buffer, new Buffer([0x01])])
}

this.import(input, compressed)
return base58check.encode(buffer, version)
}

ECPubKey.prototype.import = function(input, compressed) {
var decode = function(x) { return ECPointFp.decodeFrom(ecparams.getCurve(), x) }
//////////////////////////////////////////////////////

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
function ECPubKey(Q, compressed) {
assert(Q instanceof ECPointFp, 'Q must be an ECPointFP')

assert(this.pub !== null)
if (compressed == undefined) compressed = true
assert.strictEqual(typeof compressed, 'boolean', 'Invalid compression flag')

this.compressed =
compressed ? compressed
: input instanceof ECPointFp ? input.compressed
: input instanceof ECPubKey ? input.compressed
: (this.pub[0] < 4)
this.compressed = compressed
this.Q = Q
}

ECPubKey.prototype.add = function(key) {
return ECPubKey(this.pub.add(ECPubKey(key).pub), this.compressed)
}
// Static constructors
ECPubKey.fromBuffer = function(buffer) {
var type = buffer.readUInt8(0)
assert(type >= 0x02 || type <= 0x04, 'Invalid public key')

ECPubKey.prototype.multiply = function(key) {
return ECPubKey(this.pub.multiply(ECKey(key).priv), this.compressed)
}
var compressed = (type !== 0x04)
assert.strictEqual(buffer.length, compressed ? 33 : 65, 'Invalid public key')

ECPubKey.prototype.toBytes = function(compressed) {
if (compressed === undefined) compressed = this.compressed
return this.pub.getEncoded(compressed)
var Q = ECPointFp.decodeFrom(ecparams.getCurve(), buffer)
return new ECPubKey(Q, compressed)
}

ECPubKey.prototype.toHex = function(compressed) {
return convert.bytesToHex(this.toBytes(compressed))
}

ECPubKey.prototype.toBin = function(compressed) {
return convert.bytesToString(this.toBytes(compressed))
ECPubKey.fromHex = function(hex) {
return ECPubKey.fromBuffer(new Buffer(hex, 'hex'))
}

ECPubKey.prototype.toWif = function(version) {
version = version || Network.bitcoin.pubKeyHash

return base58check.encode(this.toBytes(), version)
// Operations
ECPubKey.prototype.verify = function(hash, sig) {
return ecdsa.verify(hash, sig, this.Q)
}

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() {
return new Buffer(this.Q.getEncoded(this.compressed))
}
ECPubKey.prototype.toHex = function() {
return this.toBuffer().toString('hex')
}

module.exports = {
Expand Down
30 changes: 16 additions & 14 deletions src/hdwallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ function HDWallet(seed, networkString) {
throw new Error("Unknown network: " + this.network)
}

this.priv = new ECKey(I.slice(0, 32), true)
this.pub = this.priv.getPub()
this.priv = ECKey.fromBuffer(I.slice(0, 32), true)
this.pub = this.priv.pub
this.index = 0
this.depth = 0
}
Expand Down Expand Up @@ -105,25 +105,25 @@ HDWallet.fromBuffer = function(input) {
// 33 bytes: the public key or private key data (0x02 + X or 0x03 + X for
// public keys, 0x00 + k for private keys)
if (type == 'priv') {
hd.priv = new ECKey(input.slice(46, 78), true)
hd.pub = hd.priv.getPub()
hd.priv = ECKey.fromBuffer(input.slice(46, 78), true)
hd.pub = hd.priv.pub
} else {
hd.pub = new ECPubKey(input.slice(45, 78), true)
hd.pub = ECPubKey.fromBuffer(input.slice(45, 78), true)
}

return hd
}

HDWallet.prototype.getIdentifier = function() {
return crypto.hash160(this.pub.toBytes())
return crypto.hash160(this.pub.toBuffer())
}

HDWallet.prototype.getFingerprint = function() {
return this.getIdentifier().slice(0, 4)
}

HDWallet.prototype.getAddress = function() {
return new Address(crypto.hash160(this.pub.toBytes()), this.getKeyVersion())
return this.pub.getAddress(this.getKeyVersion())
}

HDWallet.prototype.toBuffer = function(priv) {
Expand Down Expand Up @@ -155,11 +155,11 @@ HDWallet.prototype.toBuffer = function(priv) {

// 0x00 + k for private keys
buffer.writeUInt8(0, 45)
new Buffer(this.priv.toBytes()).copy(buffer, 46)
this.priv.toBuffer().copy(buffer, 46)
} else {

// X9.62 encoding for public keys
new Buffer(this.pub.toBytes()).copy(buffer, 45)
this.pub.toBuffer().copy(buffer, 45)
}

return buffer
Expand Down Expand Up @@ -190,14 +190,16 @@ HDWallet.prototype.derive = function(i) {

// If 1, private derivation is used:
// let I = HMAC-SHA512(Key = cpar, Data = 0x00 || kpar || i) [Note:]
var kPar = this.priv.toBytes().slice(0, 32)
var kPar = this.priv.toBuffer().slice(0, 32)
kPar = Array.prototype.slice.call(kPar)

// FIXME: Dislikes buffers
I = HmacFromBytesToBytes(SHA512, [0].concat(kPar, iBytes), cPar)
} else {
// If 0, public derivation is used:
// let I = HMAC-SHA512(Key = cpar, Data = χ(kpar*G) || i)
var KPar = this.pub.toBytes()
var KPar = this.pub.toBuffer()
KPar = Array.prototype.slice.call(KPar)

// FIXME: Dislikes buffers
I = HmacFromBytesToBytes(SHA512, KPar.concat(iBytes), cPar)
Expand All @@ -217,13 +219,13 @@ HDWallet.prototype.derive = function(i) {

if (this.priv) {
// ki = IL + kpar (mod n).
var ki = IL.add(this.priv.priv).mod(ecparams.getN())
var ki = IL.add(this.priv.D).mod(ecparams.getN())

hd.priv = new ECKey(ki, true)
hd.pub = hd.priv.getPub()
hd.pub = hd.priv.pub
} else {
// Ki = (IL + kpar)*G = IL*G + Kpar
var Ki = IL.multiply(ecparams.getG()).add(this.pub.pub)
var Ki = IL.multiply(ecparams.getG()).add(this.pub.Q)

hd.pub = new ECPubKey(Ki, true)
}
Expand Down
Loading