diff --git a/test/integration/stealth.js b/test/integration/stealth.js index d9ce12d..67c34b2 100644 --- a/test/integration/stealth.js +++ b/test/integration/stealth.js @@ -34,6 +34,14 @@ function stealthReceive (d, eG) { return v } +function stealthRecoverLeaked (d, e, Q) { + var eQ = Q.multiply(e) // shared secret + var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded())) + var v = new bitcoin.ECPair(d.subtract(c).mod(n)) + + return v +} + describe('bitcoinjs-lib (crypto)', function () { it('can generate a single-key stealth address', function () { // XXX: should be randomly generated, see next test for example @@ -70,6 +78,23 @@ describe('bitcoinjs-lib (crypto)', function () { assert.equal(forSender.getAddress(), forRecipient.getAddress()) }) + it('can recover parent recipient.d, if a derived private key is leaked [and nonce was revealed]', function () { + var recipient = bitcoin.ECPair.makeRandom() // private to recipient + var nonce = bitcoin.ECPair.makeRandom() // private to sender + + // ... recipient reveals public key (recipient.Q) to sender + var forSender = stealthSend(nonce.d, recipient.Q) + assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/) + + // ... sender reveals nonce public key (nonce.Q) to recipient + var forRecipient = stealthReceive(recipient.d, nonce.Q) + assert.doesNotThrow(function () { forRecipient.toWIF() }) + + // ... recipient accidentally leaks forRecipient.d on the blockchain + var leaked = stealthRecoverLeaked(forRecipient.d, nonce.d, recipient.Q) + assert.equal(leaked.toWIF(), recipient.toWIF()) + }) + // TODO it.skip('can generate a dual-key stealth address', function () {}) })