├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── lib ├── crypto.js └── stealth.js ├── package.json └── test ├── fixtures.json ├── stealth-cp.test.js └── stealth.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | .travis.yml -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | before_install: 3 | - "npm install npm -g" 4 | node_js: 5 | - 0.12 6 | - 0.10 7 | env: 8 | - TEST_SUITE=test 9 | - TEST_SUITE=coveralls 10 | script: "npm run-script $TEST_SUITE" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 0.4.0 / 2015-08-31 2 | ------------------ 3 | - `toJSON()` returns an object instead of a string 4 | - `fromJSON()` accepts either object or string 5 | 6 | 0.3.0 / 2015-05-28 7 | ------------------ 8 | - added `fromRandom([config])` 9 | 10 | 0.2.1 / 2015-03-31 11 | ------------------ 12 | - return `null` for `checkPaymentPubKeyHash()` if `OP_RETURN` payload is not 33 bytes 13 | 14 | 0.2.0 / 2015-03-05 15 | ------------------ 16 | - added `Stealth.prototype.toJSON()` and `Stealth.fromJSON()` 17 | 18 | 0.1.0 / 2015-02-14 19 | ------------------ 20 | - initial release 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stealth 2 | ======= 3 | 4 | [![build status](https://secure.travis-ci.org/cryptocoinjs/stealth.svg)](http://travis-ci.org/cryptocoinjs/stealth) 5 | [![Coverage Status](https://img.shields.io/coveralls/cryptocoinjs/stealth.svg)](https://coveralls.io/r/cryptocoinjs/stealth) 6 | 7 | [![js-standard-style](https://raw.githubusercontent.com/feross/standard/master/badge.png)](https://github.com/feross/standard) 8 | 9 | This module is used for stealth addresses for Bitcoin and other crypto currencies. 10 | 11 | 12 | Usage 13 | ----- 14 | 15 | First, you should really read this excellent resource: https://gist.github.com/ryanxcharles/1c0f95d0892b4a92d70a 16 | 17 | This module depends upon [ecurve](https://github.com/cryptocoinjs/ecurve) and may change to 18 | [elliptic](https://github.com/indutny/elliptic) in the future. However, this is just an implementation detail 19 | that shouldn't affect your code. 20 | 21 | ### Example 22 | 23 | #### If you're the payer (sender) 24 | 25 | ```js 26 | var Stealth = require('stealth') 27 | 28 | // you get this from the person you're going to pay (receiver) 29 | var addr = 'vJmtuUb8ysKiM1HtHQF23FGfjGAKu5sM94UyyjknqhJHNdj5CZzwtpGzeyaATQ2HvuzomNVtiwsTJSWzzCBgCTtUZbRFpzKVq9MAUr' 30 | var stealth = Stealth.fromString(addr) 31 | 32 | // single-use nonce key pair, works with CoinKey, bitcoinjs-lib, bitcore, etc 33 | var keypair = require('coinkey').createRandom() 34 | 35 | // generate payment address 36 | var payToAddress = stealth.genPaymentAddress(keypair.privateKey) 37 | 38 | // create transaction with two outputs: 39 | // 1. Regular pay-to-pubkeyhash with `payToAddress` as recipient 40 | // 2. OP_RETURN with `keypair.publicKey` 41 | ``` 42 | 43 | 44 | #### If you're the payee (recipient) 45 | 46 | ```js 47 | var Stealth = require('stealth') 48 | 49 | // you need to scan every transaction and look for the following: 50 | // 1. does the transaction contain an OP_RETURN? 51 | // 2. if yes, then extract the OP_RETURN 52 | // 3. is the OP_RETURN data a compressed public key (33 bytes)? 53 | // 4. if yes, check if mine 54 | 55 | // generate two key pairs, can use CoinKey, bitcoinjs-lib, bitcore, etc 56 | var payloadKeyPair = require('coinkey').createRandom() 57 | var scanKeyPair = require('coinkey').createRandom() 58 | 59 | // note, the private keys are NOT encoded in the Stealth address 60 | // you need to save them somewhere 61 | var stealth = new Stealth({ 62 | payloadPrivKey: payloadKeyPair.privateKey, 63 | payloadPubKey: payloadKeyPair.publicKey, 64 | scanPrivKey: scanKeyPair.privateKey, 65 | scanPubKey: scanKeyPair.publicKey 66 | }) 67 | 68 | var addr = stealth.toString() 69 | // => 'vJmtuUb8ysKiM1HtHQF23FGfjGAKu5sM94UyyjknqhJHNdj5CZzwtpGzeyaATQ2HvuzomNVtiwsTJSWzzCBgCTtUZbRFpzKVq9MAUr' 70 | 71 | // publish addr or give it someone 72 | // unlike regular Bitcoin addresses, you can use 73 | // stealth address as much as you like 74 | 75 | // scan and decode transactions 76 | 77 | var opReturnPubKey = /* */ 78 | var pubKeyHashWithPayment = /* */ 79 | 80 | var keypair = stealth.checkPaymentPubKeyHash(opReturnPubKey, pubKeyHashWithPayment) 81 | 82 | // it NOT YOURS, `keypair` will be falsey 83 | 84 | if (keypair == null) { 85 | console.log('payment is not mine') 86 | } else { 87 | console.log('payment is mine') 88 | 89 | // redeem with `privKey` 90 | console.log(keypair.privKey) 91 | } 92 | ``` 93 | 94 | API 95 | --- 96 | 97 | (TODO) 98 | 99 | ### + fromRandom([config]) 100 | 101 | Class method to create a stealth key from a random entropy. Optionally pass in `config` with the following: 102 | - `rng`: A function that should accept a number `n` and return a `Buffer`/`Array` with length `n`. 103 | - `version`: Version code for stealth string. 104 | 105 | 106 | 107 | Resources 108 | --------- 109 | 110 | ### Credits 111 | 112 | The creation of this module owes a lot of credit to the prior work of [Ryan X. Charles](https://github.com/ryanxcharles), specifically the following 113 | resources: 114 | 115 | - https://github.com/ryanxcharles/fullnode 116 | - https://gist.github.com/ryanxcharles/1c0f95d0892b4a92d70a 117 | 118 | 119 | ### Additional Resources 120 | 121 | - Dark Wallet description: https://wiki.unsystem.net/en/index.php/DarkWallet/Stealth 122 | - Dark Wallet infographic: https://wiki.unsystem.net/en/images/e/e5/RHhNKL6.jpg 123 | - Stealth Whitepaper: http://sourceforge.net/p/bitcoin/mailman/message/31813471/ 124 | 125 | 126 | License 127 | ------- 128 | 129 | MIT 130 | -------------------------------------------------------------------------------- /lib/crypto.js: -------------------------------------------------------------------------------- 1 | var crypto = require('crypto') 2 | var ecurve = require('ecurve') 3 | 4 | // hack to get bigi without including it as a dep 5 | var ecparams = ecurve.getCurveByName('secp256k1') 6 | var BigInteger = ecparams.n.constructor 7 | 8 | function hash160 (buffer) { 9 | buffer = crypto.createHash('sha256').update(buffer).digest() 10 | return crypto.createHash('rmd160').update(buffer).digest() 11 | } 12 | 13 | function hmacSha256 (buffer) { 14 | return crypto.createHmac('sha256', new Buffer([])).update(buffer).digest() 15 | } 16 | 17 | function sha256x2 (buffer) { 18 | buffer = crypto.createHash('sha256').update(buffer).digest() 19 | return crypto.createHash('sha256').update(buffer).digest() 20 | } 21 | 22 | module.exports = { 23 | BigInteger: BigInteger, 24 | ecparams: ecparams, 25 | hash160: hash160, 26 | hmacSha256: hmacSha256, 27 | sha256x2: sha256x2 28 | } 29 | -------------------------------------------------------------------------------- /lib/stealth.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var bs58 = require('bs58') 3 | var ecurve = require('ecurve') 4 | var crypto = require('./crypto') 5 | var ecparams = ecurve.getCurveByName('secp256k1') 6 | var Point = ecurve.Point 7 | var BigInteger = crypto.BigInteger 8 | 9 | Stealth.MAINNET = 42 10 | Stealth.TESTNET = 43 11 | 12 | function Stealth (config) { 13 | // required 14 | this.payloadPubKey = config.payloadPubKey 15 | this.scanPubKey = config.scanPubKey 16 | 17 | // only makes sense if you're the receiver, i.e. you own the stealth addresss 18 | this.payloadPrivKey = config.payloadPrivKey 19 | this.scanPrivKey = config.scanPrivKey 20 | 21 | assert(Buffer.isBuffer(this.payloadPubKey), 'payloadPubKey must be a buffer') 22 | assert(Buffer.isBuffer(this.scanPubKey), 'scanPubKey must be a buffer') 23 | 24 | // default to bitcoin 25 | this.version = config.version || Stealth.MAINNET 26 | } 27 | 28 | Stealth.prototype.toBuffer = function () { 29 | return bconcat([ 30 | this.version, 31 | 0, // options 32 | this.scanPubKey, 33 | 1, // number of payload keys, only 1 atm 34 | this.payloadPubKey, 35 | 1, // number of sigs, only 1 atm 36 | 0 // prefix length, not supported (actually, don't even know what the hell it is) 37 | ]) 38 | } 39 | 40 | Stealth.prototype.toJSON = function () { 41 | // sucky converting to hex, but want to still support Node v0.10 42 | var o = { 43 | payloadPrivKey: this.payloadPrivKey ? this.payloadPrivKey.toString('hex') : undefined, 44 | payloadPubKey: this.payloadPubKey.toString('hex'), 45 | scanPrivKey: this.scanPrivKey ? this.scanPrivKey.toString('hex') : undefined, 46 | scanPubKey: this.scanPubKey.toString('hex'), 47 | version: this.version 48 | } 49 | 50 | // remove undefineds, when we use to return JSON string, stringify did this 51 | if (!o.payloadPrivKey) delete o.payloadPrivKey 52 | if (!o.scanPrivKey) delete o.scanPrivKey 53 | 54 | return o 55 | } 56 | 57 | Stealth.prototype.toString = function () { 58 | var payload = this.toBuffer() 59 | var checksum = crypto.sha256x2(payload).slice(0, 4) 60 | 61 | return bs58.encode(Buffer.concat([ 62 | payload, 63 | checksum 64 | ])) 65 | } 66 | 67 | Stealth.fromBuffer = function (buffer) { 68 | const pkLen = 33 69 | var pos = 0 70 | var version = buffer.readUInt8(pos++) 71 | var options = buffer.readUInt8(pos++) 72 | assert.equal(options, 0) 73 | 74 | var scanPubKey = buffer.slice(pos, pos += pkLen) 75 | var nPayloadPubkeys = buffer.readUInt8(pos++) 76 | 77 | var payloadPubkeys = [] 78 | for (var i = 0; i < nPayloadPubkeys; i++) { 79 | payloadPubkeys.push(buffer.slice(pos, pos += pkLen)) 80 | } 81 | 82 | var nSigs = buffer.readUInt8(pos++) 83 | var nPrefix = buffer.readUInt8(pos++) 84 | var prefix = buffer.slice(pos, pos + nPrefix / 8) 85 | 86 | assert.equal(nSigs, 1) 87 | assert.equal(nPrefix, 0) 88 | assert.equal(prefix.length, 0) 89 | 90 | return new Stealth({ 91 | payloadPubKey: payloadPubkeys[0], 92 | scanPubKey: scanPubKey, 93 | version: version 94 | }) 95 | } 96 | 97 | Stealth.fromRandom = function (config) { 98 | config = config || {} 99 | var rng = config.rng || require('crypto').randomBytes 100 | var version = config.version || Stealth.MAINNET 101 | 102 | var payloadPrivKey = new Buffer(rng(32)) 103 | var scanPrivKey = new Buffer(rng(32)) 104 | 105 | var payloadPubKey = ecparams.G.multiply(BigInteger.fromBuffer(payloadPrivKey)).getEncoded(true) 106 | var scanPubKey = ecparams.G.multiply(BigInteger.fromBuffer(scanPrivKey)).getEncoded(true) 107 | 108 | return new Stealth({ 109 | scanPrivKey: scanPrivKey, 110 | scanPubKey: scanPubKey, 111 | payloadPrivKey: payloadPrivKey, 112 | payloadPubKey: payloadPubKey, 113 | version: version 114 | }) 115 | } 116 | 117 | // https://gist.github.com/ryanxcharles/1c0f95d0892b4a92d70a 118 | Stealth.prototype.genPaymentPubKeyHash = function (senderPrivKey) { 119 | var kdf = crypto.hmacSha256 120 | 121 | var Ap = Point.decodeFrom(ecparams, this.scanPubKey) 122 | var A = Point.decodeFrom(ecparams, this.payloadPubKey) 123 | 124 | var S = Ap.multiply(BigInteger.fromBuffer(senderPrivKey)) 125 | 126 | var d = BigInteger.fromBuffer(kdf(S.getEncoded(true))) 127 | var D = ecparams.G.multiply(d) 128 | 129 | var E = A.add(D) 130 | 131 | var pubKeyHash = crypto.hash160(E.getEncoded(true)) 132 | return pubKeyHash 133 | } 134 | 135 | Stealth.prototype.genPaymentAddress = function (senderPrivKey, version) { 136 | var pubKeyHash = this.genPaymentPubKeyHash(senderPrivKey) 137 | var payload = Buffer.concat([new Buffer([version || 0x0]), pubKeyHash]) 138 | var checksum = crypto.sha256x2(payload).slice(0, 4) 139 | 140 | return bs58.encode(Buffer.concat([ 141 | payload, 142 | checksum 143 | ])) 144 | } 145 | 146 | // https://gist.github.com/ryanxcharles/1c0f95d0892b4a92d70a 147 | Stealth.prototype.checkPaymentPubKeyHash = function (opReturnPubKey, pubKeyHashToCompare) { 148 | assert(this.payloadPrivKey, 'payloadPrivKey must be set if you use this method. i.e. Must be owner / receiver.') 149 | assert(this.scanPrivKey, 'scanPrivKey must be set if you use this method. i.e. Must be owner / receiver.') 150 | 151 | if (opReturnPubKey.length !== 33) return null 152 | 153 | var kdf = crypto.hmacSha256 154 | 155 | var a = this.payloadPrivKey 156 | var ap = this.scanPrivKey 157 | var B = Point.decodeFrom(ecparams, opReturnPubKey) 158 | 159 | var S = B.multiply(BigInteger.fromBuffer(ap)) 160 | 161 | var d = kdf(S.getEncoded(true)) 162 | var e = BigInteger.fromBuffer(a).add(BigInteger.fromBuffer(d)).mod(ecparams.n) 163 | 164 | var E = ecparams.G.multiply(e) 165 | 166 | var pubKeyHash = crypto.hash160(E.getEncoded(true)) 167 | if (pubKeyHash.toString('hex') !== pubKeyHashToCompare.toString('hex')) { 168 | return null 169 | } 170 | 171 | return { 172 | privKey: e.toBuffer(32), 173 | pubKey: E.getEncoded(true) 174 | } 175 | } 176 | 177 | Stealth.fromJSON = function (json) { 178 | var o 179 | if (typeof json === 'string') { 180 | o = JSON.parse(json) 181 | } else { 182 | o = json 183 | } 184 | 185 | return new Stealth({ 186 | payloadPubKey: new Buffer(o.payloadPubKey, 'hex'), 187 | scanPubKey: new Buffer(o.scanPubKey, 'hex'), 188 | payloadPrivKey: o.payloadPrivKey ? new Buffer(o.payloadPrivKey, 'hex') : undefined, 189 | scanPrivKey: o.scanPrivKey ? new Buffer(o.scanPrivKey, 'hex') : undefined, 190 | version: o.version 191 | }) 192 | } 193 | 194 | Stealth.fromString = function (str) { 195 | var buffer = new Buffer(bs58.decode(str)) 196 | 197 | var payload = buffer.slice(0, -4) 198 | var checksum = buffer.slice(-4) 199 | var newChecksum = crypto.sha256x2(payload).slice(0, 4) 200 | 201 | assert.deepEqual(newChecksum, checksum, 'Invalid checksum') 202 | 203 | return Stealth.fromBuffer(payload) 204 | } 205 | 206 | function bconcat (arr) { 207 | arr = arr.map(function (item) { 208 | return Buffer.isBuffer(item) ? item : new Buffer([item]) 209 | }) 210 | return Buffer.concat(arr) 211 | } 212 | 213 | module.exports = Stealth 214 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stealth", 3 | "version": "0.4.0", 4 | "description": "Stealth addresses for Bitcoin and other crypto currencies.", 5 | "main": "lib/stealth.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter list test/*.js", 11 | "coveralls": "npm run coverage && coveralls < coverage/lcov.info", 12 | "test": "standard && mocha" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/cryptocoinjs/stealth" 17 | }, 18 | "keywords": [ 19 | "bitcoin", 20 | "steatlth", 21 | "addresses", 22 | "privacy" 23 | ], 24 | "author": "JP Richardson", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/cryptocoinjs/stealth/issues" 28 | }, 29 | "homepage": "https://github.com/cryptocoinjs/stealth", 30 | "dependencies": { 31 | "bs58": "^2.0.1", 32 | "ecurve": "^1.0.1" 33 | }, 34 | "devDependencies": { 35 | "coveralls": "^2.11.2", 36 | "istanbul": "^0.3.5", 37 | "mocha": "^2.1.0", 38 | "standard": "^2.10.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": [ 3 | { 4 | "__COMMENT__": "The following private keys are are sha256 hashes of 'test 1', 'test 2', 'test 3' respectively.", 5 | "receiverPayload": { 6 | "privKey": "f67213b122a5d442d2b93bda8cc45c564a70ec5d2a4e0e95bb585cf199869c98", 7 | "pubKey": "0362408459041e0473298af3824dbabe4d2b7f846825ed4d1c2e2c670c07cb275d" 8 | }, 9 | "receiverScan": { 10 | "privKey": "dec2e4bc4992314a9c9a51bbd859e1b081b74178818c53c19d18d6f761f5d804", 11 | "pubKey": "02697763d7e9becb0c180083738c32c05b0e2fee26d6278020c06bbb04d5f66b32" 12 | }, 13 | "sender": { 14 | "privKey": "f8c02a45667e1390e9702876dd4dc6c0066e49b5cdaa6ec1c83e7d88be92e2e2", 15 | "pubKey": "0266d5c408bb3752c5b2900b04cad54ec98d930c5d6370dcbe45a09a5bc5e083cb" 16 | }, 17 | "base58": "vJmtuUb8ysKiM1HtHQF23FGfjGAKu5sM94UyyjknqhJHNdj5CZzwtpGzeyaATQ2HvuzomNVtiwsTJSWzzCBgCTtUZbRFpzKVq9MAUr", 18 | "JSON": "{\n \"payloadPrivKey\": \"f67213b122a5d442d2b93bda8cc45c564a70ec5d2a4e0e95bb585cf199869c98\",\n \"payloadPubKey\": \"0362408459041e0473298af3824dbabe4d2b7f846825ed4d1c2e2c670c07cb275d\",\n \"scanPrivKey\": \"dec2e4bc4992314a9c9a51bbd859e1b081b74178818c53c19d18d6f761f5d804\",\n \"scanPubKey\": \"02697763d7e9becb0c180083738c32c05b0e2fee26d6278020c06bbb04d5f66b32\",\n \"version\": 42\n}", 19 | "JSONpub": "{\n \"payloadPubKey\": \"0362408459041e0473298af3824dbabe4d2b7f846825ed4d1c2e2c670c07cb275d\",\n \"scanPubKey\": \"02697763d7e9becb0c180083738c32c05b0e2fee26d6278020c06bbb04d5f66b32\",\n \"version\": 42\n}", 20 | "paymentPubKeyHash": "3cb64fa6ee9b3e8754e3e2bd033bf61048604a99", 21 | "paymentAddress": "16Y1wiBLH4QVgM38vNwhB2ccTLQm5P7WNh" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /test/stealth-cp.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var Stealth = require('../') 3 | var fixtures = require('./fixtures') 4 | 5 | /* global describe, it */ 6 | 7 | describe('checkPaymentPubKeyHash()', function () { 8 | var f = fixtures.valid[0] 9 | 10 | describe('> when OP_RETURN data is not 33 bytes (i.e. not pubKey)', function () { 11 | it('should return null', function () { 12 | var stealth = new Stealth({ 13 | payloadPrivKey: new Buffer(f.receiverPayload.privKey, 'hex'), 14 | payloadPubKey: new Buffer(f.receiverPayload.pubKey, 'hex'), 15 | scanPrivKey: new Buffer(f.receiverScan.privKey, 'hex'), 16 | scanPubKey: new Buffer(f.receiverScan.pubKey, 'hex') 17 | }) 18 | 19 | var buf 20 | for (var i = 0; i <= 80; ++i) { 21 | if (i === 33) continue 22 | buf = new Buffer(i) 23 | var res = stealth.checkPaymentPubKeyHash(buf, new Buffer(f.paymentPubKeyHash, 'hex')) 24 | assert.equal(res, null) 25 | } 26 | }) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /test/stealth.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var Stealth = require('../') 3 | var crypto = require('../lib/crypto') 4 | var fixtures = require('./fixtures') 5 | 6 | /* global describe, it */ 7 | // trinity: mocha 8 | 9 | describe('stealth', function () { 10 | fixtures.valid.forEach(function (f) { 11 | describe('toString()', function () { 12 | it('should convert to base58-check string', function () { 13 | var stealth = new Stealth({ 14 | payloadPubKey: new Buffer(f.receiverPayload.pubKey, 'hex'), 15 | scanPubKey: new Buffer(f.receiverScan.pubKey, 'hex') 16 | }) 17 | assert.equal(stealth.toString(), f.base58) 18 | }) 19 | }) 20 | 21 | describe('fromString()', function () { 22 | it('should convert from base58-check string to object', function () { 23 | var stealth = Stealth.fromString(f.base58) 24 | assert.equal(stealth.scanPubKey.toString('hex'), f.receiverScan.pubKey) 25 | assert.equal(stealth.payloadPubKey.toString('hex'), f.receiverPayload.pubKey) 26 | }) 27 | }) 28 | 29 | describe('fromRandom()', function () { 30 | it('should create a random stealth key', function () { 31 | var stealth = Stealth.fromRandom() 32 | assert(stealth.toString()) 33 | assert.strictEqual(stealth.version, 42) 34 | }) 35 | 36 | describe('> when rng is passed', function () { 37 | it('should return a stealth key using the new rng', function () { 38 | var stealth = Stealth.fromRandom({ 39 | rng: function () { 40 | // return as Buffer 41 | return new Buffer('5873d4af699b9a35cca3d38219a13184c616e5d433c99ff39353687d4736ac1d', 'hex') 42 | } 43 | }) 44 | assert.strictEqual(stealth.scanPrivKey.toString('hex'), '5873d4af699b9a35cca3d38219a13184c616e5d433c99ff39353687d4736ac1d') 45 | assert.strictEqual(stealth.payloadPrivKey.toString('hex'), '5873d4af699b9a35cca3d38219a13184c616e5d433c99ff39353687d4736ac1d') 46 | assert.strictEqual(stealth.scanPubKey.toString('hex'), '02a8001c07fabf92175cb93f35df6d4d5f6cba8f35c9e080558bc44eedd95c2568') 47 | assert.strictEqual(stealth.payloadPubKey.toString('hex'), '02a8001c07fabf92175cb93f35df6d4d5f6cba8f35c9e080558bc44eedd95c2568') 48 | 49 | var stealth2 = Stealth.fromRandom({ 50 | rng: function () { 51 | // return as Array 52 | return [].slice.call(new Buffer('9f817a572bd5e89fe0b98c771de29de5ce1720e83fd43fc8d57de2db328b9d1a', 'hex')) 53 | } 54 | }) 55 | assert.strictEqual(stealth2.scanPrivKey.toString('hex'), '9f817a572bd5e89fe0b98c771de29de5ce1720e83fd43fc8d57de2db328b9d1a') 56 | assert.strictEqual(stealth2.payloadPrivKey.toString('hex'), '9f817a572bd5e89fe0b98c771de29de5ce1720e83fd43fc8d57de2db328b9d1a') 57 | assert.strictEqual(stealth2.scanPubKey.toString('hex'), '0393b6e74a36b1c9769acd749ed18d82457b52d78f00def709f03c526ae895d7c1') 58 | assert.strictEqual(stealth2.payloadPubKey.toString('hex'), '0393b6e74a36b1c9769acd749ed18d82457b52d78f00def709f03c526ae895d7c1') 59 | }) 60 | }) 61 | 62 | describe('> when version is passed', function () { 63 | it('should use the new version number', function () { 64 | var stealth = Stealth.fromRandom({ 65 | version: 5 66 | }) 67 | assert.strictEqual(stealth.version, 5) 68 | }) 69 | }) 70 | }) 71 | 72 | describe('genPaymentPubKeyHash()', function () { 73 | it('should generate the payment pubkeyhash for the sender (payer) to send money to', function () { 74 | var stealth = Stealth.fromString(f.base58) 75 | var pubKeyHash = stealth.genPaymentPubKeyHash(new Buffer(f.sender.privKey, 'hex')) 76 | assert.equal(pubKeyHash.toString('hex'), f.paymentPubKeyHash) 77 | }) 78 | }) 79 | 80 | describe('genPaymentAddress()', function () { 81 | it('should generate the payment address for the sender', function () { 82 | var stealth = Stealth.fromString(f.base58) 83 | var address = stealth.genPaymentAddress(new Buffer(f.sender.privKey, 'hex')) 84 | assert.equal(address, f.paymentAddress) 85 | }) 86 | }) 87 | 88 | describe('checkPaymentPubKeyHash()', function () { 89 | it('should check the payment is indeed owned by me', function () { 90 | var stealth = new Stealth({ 91 | payloadPrivKey: new Buffer(f.receiverPayload.privKey, 'hex'), 92 | payloadPubKey: new Buffer(f.receiverPayload.pubKey, 'hex'), 93 | scanPrivKey: new Buffer(f.receiverScan.privKey, 'hex'), 94 | scanPubKey: new Buffer(f.receiverScan.pubKey, 'hex') 95 | }) 96 | 97 | var res = stealth.checkPaymentPubKeyHash(new Buffer(f.sender.pubKey, 'hex'), new Buffer(f.paymentPubKeyHash, 'hex')) 98 | assert(res) 99 | 100 | assert(res.privKey) 101 | assert(res.pubKey) 102 | assert.equal(crypto.hash160(res.pubKey).toString('hex'), f.paymentPubKeyHash) 103 | }) 104 | }) 105 | 106 | describe('toJSON()', function () { 107 | it('should convert to JSON string', function () { 108 | var stealth = new Stealth({ 109 | payloadPrivKey: new Buffer(f.receiverPayload.privKey, 'hex'), 110 | payloadPubKey: new Buffer(f.receiverPayload.pubKey, 'hex'), 111 | scanPrivKey: new Buffer(f.receiverScan.privKey, 'hex'), 112 | scanPubKey: new Buffer(f.receiverScan.pubKey, 'hex') 113 | }) 114 | 115 | assert.deepEqual(stealth.toJSON(), JSON.parse(f.JSON)) 116 | }) 117 | 118 | describe('when > only pub (sender)', function () { 119 | it('should convert to JSON string', function () { 120 | var stealth = new Stealth({ 121 | payloadPubKey: new Buffer(f.receiverPayload.pubKey, 'hex'), 122 | scanPubKey: new Buffer(f.receiverScan.pubKey, 'hex') 123 | }) 124 | 125 | assert.deepEqual(stealth.toJSON(), JSON.parse(f.JSONpub)) 126 | }) 127 | }) 128 | }) 129 | 130 | describe('fromJSON()', function () { 131 | it('should parse from JSON', function () { 132 | var stealth1 = Stealth.fromJSON(f.JSON) 133 | var stealth1o = Stealth.fromJSON(JSON.parse(f.JSON)) 134 | assert.equal(JSON.stringify(stealth1.toJSON(), null, 2), f.JSON) 135 | assert.deepEqual(stealth1o.toJSON(), JSON.parse(f.JSON)) 136 | assert.equal(stealth1.toString(), f.base58) 137 | 138 | var stealth2 = Stealth.fromJSON(f.JSONpub) 139 | var stealth2o = Stealth.fromJSON(JSON.parse(f.JSONpub)) 140 | assert.equal(JSON.stringify(stealth2.toJSON(), null, 2), f.JSONpub) 141 | assert.deepEqual(stealth2o.toJSON(), JSON.parse(f.JSONpub)) 142 | assert.equal(stealth2.toString(), f.base58) 143 | }) 144 | }) 145 | }) 146 | }) 147 | --------------------------------------------------------------------------------