Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dcousens committed May 15, 2018
1 parent 29d6f92 commit 2666b68
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 91 deletions.
100 changes: 50 additions & 50 deletions src/ecpair.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,79 @@
var randomBytes = require('randombytes')
var typeforce = require('typeforce')
var types = require('./types')
var wif = require('wif')
let randomBytes = require('randombytes')
let ecc = require('tiny-secp256k1')
let typeforce = require('typeforce')
let types = require('./types')
let wif = require('wif')

var NETWORKS = require('./networks')
var tinysecp = require('tiny-secp256k1')
let NETWORKS = require('./networks')

function isPrivate (x) { return tinysecp.isPrivate(x) }
function isPoint (x) { return tinysecp.isPoint(x) }
// TODO: why is the function name toJSON weird?
function isPoint (x) { return ecc.isPoint(x) }
let isOptions = typeforce.maybe(typeforce.compile({
compressed: types.maybe(types.Boolean),
network: types.maybe(types.Network)
}))

function ECPair (d, Q, options) {
options = options || {}

typeforce({
d: types.maybe(isPrivate),
Q: types.maybe(isPoint),
options: {
compressed: types.maybe(types.Boolean),
network: types.maybe(types.Network)
}
}, {
d: d,
Q: Q,
options: options
})

this.compressed = options.compressed === undefined ? true : options.compressed
this.network = options.network || NETWORKS.bitcoin

if (d) {
if (Q) throw new TypeError('Unexpected publicKey parameter')
this.__d = d || null
this.__Q = null
if (Q) this.__Q = ecc.pointCompress(Q, this.compressed)
}

this.__d = d
} else {
this.__Q = tinysecp.pointCompress(Q, this.compressed)
}
var baddress = require('./address')
var bcrypto = require('./crypto')
ECPair.prototype.getAddress = function () {
return baddress.toBase58Check(bcrypto.hash160(this.getPublicKey()), this.getNetwork().pubKeyHash)
}

ECPair.prototype.getNetwork = function () {
return this.network
}

ECPair.prototype.getPrivateKeyBuffer = function () {
ECPair.prototype.getPrivateKey = function () {
return this.__d
}

ECPair.prototype.getPublicKeyBuffer = function () {
if (!this.__Q) this.__Q = tinysecp.pointFromScalar(this.__d, this.compressed)
ECPair.prototype.getPublicKey = function () {
if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed)
return this.__Q
}

ECPair.prototype.sign = function (hash) {
ECPair.prototype.toWIF = function () {
if (!this.__d) throw new Error('Missing private key')
return tinysecp.sign(hash, this.__d)
return wif.encode(this.network.wif, this.__d, this.compressed)
}

ECPair.prototype.toWIF = function () {
ECPair.prototype.sign = function (hash) {
if (!this.__d) throw new Error('Missing private key')
return wif.encode(this.network.wif, this.__d, this.compressed)
return ecc.sign(hash, this.__d)
}

ECPair.prototype.verify = function (hash, signature) {
return tinysecp.verify(hash, this.getPublicKeyBuffer(), signature)
return ecc.verify(hash, this.getPublicKey(), signature)
}

function fromPrivateKey (buffer, options) {
typeforce(types.Buffer256bit, buffer)
if (!ecc.isPrivate(buffer)) throw new TypeError('Private key not in range [1, n)')
typeforce(isOptions, options)

return new ECPair(buffer, null, options)
}

function fromPublicKey (buffer, options) {
typeforce(isPoint, buffer)
typeforce(isOptions, options)
return new ECPair(null, buffer, options)
}

function fromWIF (string, network) {
var decoded = wif.decode(string)
var version = decoded.version
let decoded = wif.decode(string)
let version = decoded.version

// list of networks?
if (types.Array(network)) {
Expand All @@ -83,31 +90,24 @@ function fromWIF (string, network) {
if (version !== network.wif) throw new Error('Invalid network version')
}

return new ECPair(decoded.privateKey, null, {
return fromPrivateKey(decoded.privateKey, {
compressed: decoded.compressed,
network: network
})
}

function fromPrivateKey (buffer, options) {
return new ECPair(buffer, null, options)
}

function fromPublicKey (buffer, options) {
return new ECPair(null, buffer, options)
}

function makeRandom (options) {
typeforce(isOptions, options)
options = options || {}
var rng = options.rng || randomBytes
let rng = options.rng || randomBytes

var d
let d
do {
d = rng(32)
typeforce(types.Buffer256bit, d)
} while (!tinysecp.isPrivate(d))
} while (!ecc.isPrivate(d))

return new ECPair(d, null, options)
return fromPrivateKey(d, options)
}

module.exports = {
Expand Down
7 changes: 6 additions & 1 deletion src/script_signature.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ let Buffer = require('safe-buffer').Buffer
let ZERO = Buffer.alloc(1, 0)
function toDER (x) {
if (x[0] & 0x80) return Buffer.concat([ZERO, x], x.length + 1)
return x
let i = 0
while (x[i] === 0) ++i
if (i === x.length) --i
return x.slice(i)
}

function fromDER (x) {
Expand Down Expand Up @@ -37,6 +40,8 @@ function encode (signature, hashType) {

let r = toDER(signature.slice(0, 32))
let s = toDER(signature.slice(32, 64))
console.log(r)
console.log(s)

return Buffer.concat([
bip66.encode(r, s),
Expand Down
4 changes: 2 additions & 2 deletions src/transaction_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ function fixMultisigOrder (input, transaction, vin) {
var unmatched = input.signatures.concat()

input.signatures = input.pubKeys.map(function (pubKey) {
var keyPair = ECPair.fromPublicKeyBuffer(pubKey)
var keyPair = ECPair.fromPublicKey(pubKey)
var match

// check for a signature
Expand Down Expand Up @@ -684,7 +684,7 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy
throw new Error('Inconsistent redeemScript')
}

var kpPubKey = keyPair.publicKey || keyPair.getPublicKeyBuffer()
var kpPubKey = keyPair.publicKey || keyPair.getPublicKey()
if (!canSign(input)) {
if (witnessValue !== undefined) {
if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue')
Expand Down
2 changes: 1 addition & 1 deletion test/bitcoin.core.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe('Bitcoin-core', function () {
var keyPair = bitcoin.ECPair.fromWIF(string, network)

it('fromWIF imports ' + string, function () {
assert.strictEqual(keyPair.d.toHex(), hex)
assert.strictEqual(keyPair.getPrivateKey().toString('hex'), hex)
assert.strictEqual(keyPair.compressed, params.isCompressed)
})

Expand Down
12 changes: 6 additions & 6 deletions test/ecpair.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('ECPair', function () {
compressed: f.compressed
})

assert.strictEqual(keyPair.getPublicKeyBuffer().toString('hex'), f.Q)
assert.strictEqual(keyPair.getPublicKey().toString('hex'), f.Q)
})
})

Expand All @@ -76,7 +76,7 @@ describe('ECPair', function () {
})
})

describe('getPublicKeyBuffer', function () {
describe('getPublicKey', function () {
let keyPair

beforeEach(function () {
Expand All @@ -85,7 +85,7 @@ describe('ECPair', function () {

it('calls pointFromScalar lazily', hoodwink(function () {
assert.strictEqual(keyPair.__Q, undefined)
keyPair.getPublicKeyBuffer()
keyPair.getPublicKey()
assert.strictEqual(keyPair.__Q.toString('hex'), '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')
}))
})
Expand All @@ -96,7 +96,7 @@ describe('ECPair', function () {
let network = NETWORKS[f.network]
let keyPair = ECPair.fromWIF(f.WIF, network)

assert.strictEqual(keyPair.getPrivateKeyBuffer().toString('hex'), f.d)
assert.strictEqual(keyPair.getPrivateKey().toString('hex'), f.d)
assert.strictEqual(keyPair.compressed, f.compressed)
assert.strictEqual(keyPair.network, network)
})
Expand All @@ -106,7 +106,7 @@ describe('ECPair', function () {
it('imports ' + f.WIF + ' (via list of networks)', function () {
let keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)

assert.strictEqual(keyPair.getPrivateKeyBuffer().toString('hex'), f.d)
assert.strictEqual(keyPair.getPrivateKey().toString('hex'), f.d)
assert.strictEqual(keyPair.compressed, f.compressed)
assert.strictEqual(keyPair.network, NETWORKS[f.network])
})
Expand Down Expand Up @@ -226,7 +226,7 @@ describe('ECPair', function () {
it('wraps tinysecp.sign', hoodwink(function () {
this.mock(tinysecp, 'sign', function (h, d) {
assert.strictEqual(h, hash)
assert.strictEqual(d, keyPair.getPrivateKeyBuffer())
assert.strictEqual(d, keyPair.getPrivateKey())
}, 1)

keyPair.sign(hash)
Expand Down
4 changes: 1 addition & 3 deletions test/integration/addresses.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* global describe, it */

var assert = require('assert')
var bigi = require('bigi')
var bitcoin = require('../../')
var dhttp = require('dhttp/200')

Expand All @@ -18,9 +17,8 @@ describe('bitcoinjs-lib (addresses)', function () {

it('can generate an address from a SHA256 hash', function () {
var hash = bitcoin.crypto.sha256(Buffer.from('correct horse battery staple'))
var d = bigi.fromBuffer(hash)

var keyPair = new bitcoin.ECPair(d)
var keyPair = bitcoin.ECPair.fromPrivateKey(hash)
var address = keyPair.getAddress()
// Generating addresses from SHA256 hashes is not secure if the input to the hash function is predictable
// Do not use with predictable inputs
Expand Down
7 changes: 5 additions & 2 deletions test/integration/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ describe('bitcoinjs-lib (crypto)', function () {
assert(bitcoin.script.pubKeyHash.input.check(scriptChunks), 'Expected pubKeyHash script')
var prevOutScript = bitcoin.address.toOutputScript('1ArJ9vRaQcoQ29mTWZH768AmRwzb6Zif1z')
var scriptSignature = bitcoin.script.signature.decode(scriptChunks[0])
var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(scriptChunks[1])
var publicKey = bitcoin.ECPair.fromPublicKey(scriptChunks[1])

var m = tx.hashForSignature(vin, prevOutScript, scriptSignature.hashType)
assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m')

// store the required information
input.signature = scriptSignature.signature
input.signature = {
r: bigi.fromBuffer(scriptSignature.signature.slice(0, 32)),
s: bigi.fromBuffer(scriptSignature.signature.slice(32, 64))
}
input.z = bigi.fromBuffer(m)
})

Expand Down
51 changes: 25 additions & 26 deletions test/integration/stealth.js
Original file line number Diff line number Diff line change
@@ -1,67 +1,66 @@
/* global describe, it */

var assert = require('assert')
var bigi = require('bigi')
var bitcoin = require('../../')

var ecurve = require('ecurve')
var secp256k1 = ecurve.getCurveByName('secp256k1')
var G = secp256k1.G
var n = secp256k1.n
var ecc = require('tiny-secp256k1')

// vG = (dG \+ sha256(e * dG)G)
function stealthSend (e, Q) {
var eQ = Q.multiply(e) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var cG = G.multiply(c)
var vG = new bitcoin.ECPair(null, Q.add(cG))
var eQ = ecc.pointMultiply(Q, e) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var Qc = ecc.pointAddScalar(Q, c)
var vG = bitcoin.ECPair.fromPublicKey(Qc)

return vG
}

// v = (d + sha256(eG * d))
function stealthReceive (d, eG) {
var eQ = eG.multiply(d) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var v = new bitcoin.ECPair(d.add(c).mod(n))
var eQ = ecc.pointMultiply(eG, d) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var dc = ecc.privateAdd(d, c)
var v = bitcoin.ECPair.fromPrivateKey(dc)

return v
}

// d = (v - sha256(e * dG))
function stealthRecoverLeaked (v, e, Q) {
var eQ = Q.multiply(e) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var d = new bitcoin.ECPair(v.subtract(c).mod(n))
var eQ = ecc.pointMultiply(Q, e) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var vc = ecc.privateSub(v, c)
var d = bitcoin.ECPair.fromPrivateKey(vc)

return d
}

// vG = (rG \+ sha256(e * dG)G)
function stealthDualSend (e, R, Q) {
var eQ = Q.multiply(e) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var cG = G.multiply(c)
var vG = new bitcoin.ECPair(null, R.add(cG))
var eQ = ecc.pointMultiply(Q, e) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var Rc = ecc.pointAddScalar(R, c)
var vG = bitcoin.ECPair.fromPublicKey(Rc)

return vG
}

// vG = (rG \+ sha256(eG * d)G)
function stealthDualScan (d, R, eG) {
var eQ = eG.multiply(d) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var cG = G.multiply(c)
var vG = new bitcoin.ECPair(null, R.add(cG))
var eQ = ecc.pointMultiply(eG, d) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var Rc = ecc.pointAddScalar(R, c)
var vG = bitcoin.ECPair.fromPublicKey(Rc)

return vG
}

// v = (r + sha256(eG * d))
function stealthDualReceive (d, r, eG) {
var eQ = eG.multiply(d) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var v = new bitcoin.ECPair(r.add(c).mod(n))
var eQ = ecc.pointMultiply(eG, d) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var rc = ecc.privateAdd(r, c)
var v = bitcoin.ECPair.fromPrivateKey(rc)

return v
}
Expand Down

0 comments on commit 2666b68

Please sign in to comment.