UNPKG

bitcore-payment-codes-cash

Version:

Payment Codes (BIP47) support for Bitcoin Cash

263 lines (199 loc) 9.16 kB
'use strict'; var chai = require('chai'); var should = chai.should(); var expect = chai.expect; var bitcore = require('bitcore-lib-cash'); var _ = bitcore.deps._; var PrivateKey = bitcore.PrivateKey; var PublicKey = bitcore.PublicKey; var HDPrivateKey = bitcore.HDPrivateKey; var Point = bitcore.crypto.Point; var is_browser = process.browser; var PC = require('../'); var PaymentCode = PC.PaymentCode; var NotificationIn = PC.NotificationIn; var NotificationOut = PC.NotificationOut; var Secret = PC.Secret; var x = new bitcore.HDPrivateKey('xprv9s21ZrQH143K2mKd7JFg7TLZaD6kYvuUGCq2RRqBGUxD7r14Acyaizf42LiGpSJxGCd8AKh4KXowS348PuhUxpTx45yw5iUc8ktXrWXLRnR'); var tc1 = { xPrivKey: x, xPubKey: x.hdPublicKey, paymentCode: 'PM8TJgiBF3npDfpxaKqU9W8iDL3T9v8j1RMVqoLqNFQcFdJ6PqjmcosHEQsHMGwe3CcgSdPz46NvJkNpHWym7b3XPF2CMZvcMT5vCvTnh58zpw529bGn', notificationPublicKeys: ['03032f6a9fa2e495b056755dfda82b288e22a71851032c02450e6ebbbef1695191'], notificationAddresses: ['bitcoincash:qpfz0g38sx2gnmne9fe985h7d3myvucjxg4wvv0an4'], }; x = new bitcore.HDPrivateKey('xprv9s21ZrQH143K2nvwJx7FDB1qugo9xZxaRqMzsV72RxWaLwsMpmg8GsYsVEiwQD7qSpyuXn8oCUBdFbKnDBBKogtbtzBR2ubz5nPg8ojowWv'); var tc2 = { xPrivKey: x, xPubKey: x.hdPublicKey, paymentCode: 'PM8TJe68G1AE62CVEchCC7HnXnAa4PfxWPtYPsfnZ5ishRvo2qe6H3DcrN94ZU8DZ2CwAFDzqucPzSy9XstwQkfKD1A3VnhUvqUKvk5V9PFar9Ww3dsD', notificationAddresses: ['bitcoincash:qqjgrtyjvy9hy47sftu7628wyhkcr48auqm0dmjye3'], }; describe('PaymentCode', function() { describe('Constructor', function() { it('should be able to create class', function() { should.exist(PaymentCode); }); it('Should create a code and notification address from given xprivkey', function() { var pc = new PaymentCode(tc1.xPubKey); pc.toString().should.equal(tc1.paymentCode); _.map(pc.notificationPublicKeys, function(x) { return x.toString(); }).should.deep.equal(tc1.notificationPublicKeys); _.map(pc.notificationAddresses, function(x) { return x.toString(); }).should.deep.equal(tc1.notificationAddresses); }); it('Should create a code and notification address for testnet', function() { var xPrivKey = new bitcore.HDPrivateKey('tprv8ZgxMBicQKsPeLrhpQpsUiPJScGKR9BseEnqAgJt9CigLtmXY3Xv6FpBKwfkQmRDPw52gWEudFRSvLZkRZ6LGg6xMiZYdECDZmV2zqJcAwC'); var xPubKey = xPrivKey.hdPublicKey; var pc = new PaymentCode(xPubKey); pc.toString().should.equal('PM8TJgMCSN9tJZYtWNwScstmwtPiRCw5ek8U2xEnJ53Jomji14jitFBEkhDg4SG2Vsj1VfsFbvHHiEa3Asmh4bxNw3kHgsmujPVziR25CUeTpvvH58zu'); _.map(pc.notificationPublicKeys, function(x) { return x.toString(); }).should.deep.equal(['03f89b439914df5f1a6bf274afa8a4f97a2c1639fcc21658d8f29902f42dc1d2f1']); _.map(pc.notificationAddresses, function(x) { return x.toString(); }).should.deep.equal(['bchtest:qr2jdf87twwhffyxr4r58a0nqpk4y0natyp5mhf73q']); }); it('Should create from code', function() { var pc = new PaymentCode(tc1.paymentCode); _.map(pc.notificationPublicKeys, function(x) { return x.toString(); }).should.deep.equal(tc1.notificationPublicKeys); _.map(pc.notificationAddresses, function(x) { return x.toString(); }).should.deep.equal(tc1.notificationAddresses); }); }); describe('Notifications', function() { it('Should create an outgoing notification', function() { var p = new PrivateKey('a0b2bd6acc4fecf7d2b77d637f6bd4450e9ca701d5761b29ed824daab9e76361'); var n = new NotificationOut(tc1.paymentCode, tc2.paymentCode, p); n.secrets[0].s.toString().should.equal('111469559018469246850263566406445487050435344289391776306916960726180370386701'); }); it('Secret notification roundtrip', function() { // ALICE var utxoPrivKey = new PrivateKey('a0b2bd6acc4fecf7d2b77d637f6bd4450e9ca701d5761b29ed824daab9e76361'); var aliceNotification= new NotificationOut(tc1.paymentCode, tc2.paymentCode, utxoPrivKey); var tx = new bitcore.Transaction() .from({ "txid": "3e46af54b2a79e8a343145e91e4801ea8611a69cd29852ff95e4b547cfd90b7b", "vout": 0, "scriptPubKey": aliceNotification.getScriptPubKey().toString(), "amount": 1 }) .addData(aliceNotification.outputs[0]) .to(tc2.notificationAddresses[0], 100000) .sign(utxoPrivKey); // BOB var nIn = NotificationIn.fromTransaction(tx.uncheckedSerialize()); var bobSecret = Secret.fromNotification(nIn, tc2.xPrivKey); bobSecret.s.toString('hex').should.equal(aliceNotification.secrets[0].s.toString('hex')); bobSecret.x.toString('hex').should.equal(aliceNotification.secrets[0].x.toString('hex')); }); }); describe('Payment Notification from Alice to Bob', function() { var a, b; beforeEach(function() { a = tc1; b = tc2; }); it('Should decode a notification tx (Bob receives notification from Alice)', function() { var alice = new PaymentCode([a.xPubKey]); var utxoPrivKey = new PrivateKey('a0b2bd6acc4fecf7d2b77d637f6bd4450e9ca701d5761b29ed824daab9e76361'); //var utxoPrivKey = new PrivateKey(); var fromAliceToBob = alice.buildNotificationTo(b.paymentCode, utxoPrivKey); var txToBob = new bitcore.Transaction() .from({ "txid": "3e46af54b2a79e8a343145e91e4801ea8611a69cd29852ff95e4b547cfd90b7b", "vout": 0, "scriptPubKey": fromAliceToBob.getScriptPubKey().toString(), "amount": 1 }) .addData(fromAliceToBob.outputs[0]) .to(b.notificationAddresses[0], 100000); var x = bitcore.HDPrivateKey(a.xPrivKey); txToBob.sign(utxoPrivKey); var txToBobHex = txToBob.uncheckedSerialize(); // BOB var bob = new PaymentCode(b.paymentCode); var n = NotificationIn.fromTransaction(txToBob); var secret = Secret.fromNotification(n, b.xPrivKey); var herPc = new PaymentCode(n.decrypt(secret)); herPc.toString().should.equal(a.paymentCode); herPc.xPubKeys[0].toString().should.equal(a.xPubKey.toString()); }); }); describe('Key Offsetting with Secret', function() { var a, b; beforeEach(function() { a = tc1; b = tc2; }); it('Should generate a valid key pair after offsetting', function() { var xpriv = HDPrivateKey(a.xPrivKey); var randomPrivateKey = new PrivateKey(); var secret = new Secret(randomPrivateKey.publicKey.point); // New pair var priv = new PrivateKey(); var pub = priv.publicKey; // Offsetted pair var privP = secret.offsetPrivateKey(priv); var pubP = secret.offsetPublicKey(pub); privP.publicKey.toString().should.equal(pubP.toString()); }); it('Should generate a valid key pair after offsetting with paycodes', function() { var randomPrivateKey = new PrivateKey(); var secret = new Secret(randomPrivateKey.publicKey.point); var xpriv = HDPrivateKey(a.xPrivKey); var xpub = xpriv.hdPublicKey; var alice = new PaymentCode(xpub); var pubP = alice.computePaymentPublicKeys(secret, 0)[0]; var privP = secret.computePrivateKey(xpriv, 0); privP.publicKey.toString().should.equal(pubP.toString()); }); }); describe('Multiple Payments from Alice to Bob', function() { var alice, bob, secret, aXPrivKey; before(function() { var a = tc1; var b = tc2; alice = new PaymentCode([a.xPubKey]); var utxoPrivKey = new PrivateKey(); //var utxoPrivKey = new PrivateKey(); var fromAliceToBob = alice.buildNotificationTo(b.paymentCode, utxoPrivKey); var txToBob = new bitcore.Transaction() .from({ "txid": "3e46af54b2a79e8a343145e91e4801ea8611a69cd29852ff95e4b547cfd90b7b", "vout": 0, "scriptPubKey": fromAliceToBob.getScriptPubKey().toString(), "amount": 1 }) .addData(fromAliceToBob.outputs[0]) .to(b.notificationAddresses[0], 100000); var x = bitcore.HDPrivateKey(a.xPrivKey); txToBob.sign(utxoPrivKey); var txToBobHex = txToBob.uncheckedSerialize(); // BOB bob = new PaymentCode(b.paymentCode); var n = NotificationIn.fromTransaction(txToBob); secret = Secret.fromNotification(n, b.xPrivKey); aXPrivKey = new HDPrivateKey(a.xPrivKey); }); var G = Point.getG(); _.each(_.range(1, 10), function(i) { it('Should create valid payment address ' + i + ' (Bob from Alice)', function() { // Alice var paymentAddress = alice.computePaymentAddress(secret, i); var pubKeyP = alice.computePaymentPublicKeys(secret, i)[0]; pubKeyP.toAddress().toString().should.equal(paymentAddress.toString()); }); it('Should create valid payment ' + i + ' (Bob from Alice)', function() { var pubKeyP = alice.computePaymentPublicKeys(secret, i)[0]; var privKeyP = secret.computePrivateKey(aXPrivKey, i); privKeyP.publicKey.toString().should.equal(pubKeyP.toString()); }); }); }); });