├── .coveralls.yml ├── .gitignore ├── .jsdoc.conf ├── .jshintrc ├── .travis.yml ├── .zuul.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── benchmark ├── block-357238.json ├── package.json ├── script.js └── serialization.js ├── bitcore-lib.js ├── docs ├── address.md ├── block.md ├── browser.md ├── crypto.md ├── encoding.md ├── examples.md ├── hierarchical.md ├── index.md ├── networks.md ├── privatekey.md ├── publickey.md ├── script.md ├── transaction.md ├── unit.md ├── unspentoutput.md └── uri.md ├── gulpfile.js ├── index.js ├── karma.conf.js ├── lib ├── address.js ├── block │ ├── block.js │ ├── blockheader.js │ ├── index.js │ └── merkleblock.js ├── crypto │ ├── bn.js │ ├── ecdsa.js │ ├── hash.js │ ├── point.js │ ├── random.js │ └── signature.js ├── encoding │ ├── base58.js │ ├── base58check.js │ ├── bufferreader.js │ ├── bufferwriter.js │ └── varint.js ├── errors │ ├── index.js │ └── spec.js ├── hdprivatekey.js ├── hdpublickey.js ├── networks.js ├── opcode.js ├── privatekey.js ├── publickey.js ├── script │ ├── index.js │ ├── interpreter.js │ └── script.js ├── transaction │ ├── index.js │ ├── input │ │ ├── index.js │ │ ├── input.js │ │ ├── multisig.js │ │ ├── multisigscripthash.js │ │ ├── publickey.js │ │ └── publickeyhash.js │ ├── output.js │ ├── sighash.js │ ├── sighashwitness.js │ ├── signature.js │ ├── transaction.js │ └── unspentoutput.js ├── unit.js ├── uri.js └── util │ ├── buffer.js │ ├── js.js │ └── preconditions.js ├── package-lock.json ├── package.json └── test ├── address.js ├── block ├── block.js ├── blockheader.js └── merkleblock.js ├── crypto ├── bn.js ├── ecdsa.js ├── hash.js ├── point.js ├── random.js └── signature.js ├── data ├── bip69.json ├── bitcoind │ ├── base58_keys_invalid.json │ ├── base58_keys_valid.json │ ├── blocks.json │ ├── script_tests.json │ ├── sig_canonical.json │ ├── sig_noncanonical.json │ ├── tx_invalid.json │ └── tx_valid.json ├── blk86756-testnet.dat ├── blk86756-testnet.js ├── blk86756-testnet.json ├── ecdsa.json ├── merkleblocks.js ├── messages.json ├── sighash.json └── tx_creation.json ├── docs.js ├── encoding ├── base58.js ├── base58check.js ├── bufferreader.js ├── bufferwriter.js └── varint.js ├── hdkeys.js ├── hdprivatekey.js ├── hdpublickey.js ├── index.html ├── index.js ├── mocha.opts ├── networks.js ├── opcode.js ├── privatekey.js ├── publickey.js ├── script ├── interpreter.js └── script.js ├── transaction ├── deserialize.js ├── input │ ├── input.js │ ├── multisig.js │ ├── multisigscripthash.js │ ├── publickey.js │ └── publickeyhash.js ├── output.js ├── sighash.js ├── sighashwitness.js ├── signature.js ├── transaction.js └── unspentoutput.js ├── unit.js ├── uri.js └── util ├── buffer.js ├── js.js └── preconditions.js /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: 5ki6iPbGaiwHzIwcfNDzTXoiqAcffqUQs 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | coverage 3 | node_modules 4 | browser/tests.js 5 | docs/api 6 | 7 | CONTRIBUTING.html 8 | LICENSE.html 9 | README.html 10 | examples.html 11 | npm-debug.log 12 | 13 | apiref 14 | bower_components 15 | report 16 | .DS_Store 17 | 18 | 19 | bitcore.js 20 | bitcore.min.js 21 | bitcore.js.sig 22 | bitcore.min.js.sig 23 | tests.js 24 | -------------------------------------------------------------------------------- /.jsdoc.conf: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true 4 | }, 5 | "source": { 6 | "include": ["docs/README.md"], 7 | "exclude": [], 8 | "includePattern": "lib/.+\\.js(doc)?$", 9 | "excludePattern": "(^|\\/|\\\\)_" 10 | }, 11 | "plugins": ["plugins/markdown"], 12 | "templates": { 13 | "cleverLinks": false, 14 | "monospaceLinks": false 15 | }, 16 | "opts": { 17 | "template": "node_modules/ink-docstrap/template", 18 | "encoding": "utf8", 19 | "destination": "./apiref/", 20 | "recurse": true, 21 | "query": "value", 22 | "private": true, 23 | "lenient": true 24 | }, 25 | "templates": { 26 | "systemName": "bitcore", 27 | "copyright": "© 2013-2015, BitPay Inc.", 28 | "navType": "vertical", 29 | "theme": "journal", 30 | "linenums": true, 31 | "collapseSymbols": false, 32 | "inverseNav": false, 33 | "outputSourceFiles": true 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": false, // Prohibit bitwise operators (&, |, ^, etc.). 3 | "browser": true, // Standard browser globals e.g. `window`, `document`. 4 | "camelcase": false, // Permit only camelcase for `var` and `object indexes`. 5 | "curly": true, // Require {} for every new block or scope. 6 | "devel": false, // Allow development statements e.g. `console.log();`. 7 | "eqeqeq": true, // Require triple equals i.e. `===`. 8 | "esnext": true, // Allow ES.next specific features such as `const` and `let`. 9 | "freeze": true, // Forbid overwriting prototypes of native objects such as Array, Date and so on. 10 | "immed": true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 11 | "indent": 2, // Specify indentation spacing 12 | "latedef": true, // Prohibit variable use before definition. 13 | "newcap": false, // Require capitalization of all constructor functions e.g. `new F()`. 14 | "noarg": true, // Prohibit use of `arguments.caller` and `arguments.callee`. 15 | "node": true, // Enable globals available when code is running inside of the NodeJS runtime environment. 16 | "noempty": true, // Prohibit use of empty blocks. 17 | "nonew": true, // Prohibits the use of constructor functions for side-effects 18 | "quotmark": "single", // Define quotes to string values. 19 | "regexp": true, // Prohibit `.` and `[^...]` in regular expressions. 20 | "smarttabs": false, // Supress warnings about mixed tabs and spaces 21 | "strict": true, // Require `use strict` pragma in every file. 22 | "trailing": true, // Prohibit trailing whitespaces. 23 | "undef": true, // Require all non-global variables be declared before they are used. 24 | "unused": true, // Warn unused variables. 25 | 26 | "maxparams": 4, // Maximum number of parameters for a function 27 | "maxstatements": 15, // Maximum number of statements in a function 28 | "maxcomplexity": 10, // Cyclomatic complexity (http://en.wikipedia.org/wiki/Cyclomatic_complexity) 29 | "maxdepth": 4, // Maximum depth of nested control structures 30 | "maxlen": 120, // Maximum number of cols in a line 31 | "multistr": true, // Allow use of multiline EOL escaping 32 | 33 | "predef": [ // Extra globals. 34 | "after", 35 | "afterEach", 36 | "before", 37 | "beforeEach", 38 | "define", 39 | "describe", 40 | "exports", 41 | "it", 42 | "module", 43 | "require" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '8' 5 | install: 6 | - npm ci 7 | after_script: 8 | - gulp coveralls 9 | 10 | cache: 11 | directories: 12 | - "$HOME/.npm" 13 | 14 | dist: trusty # needs Ubuntu Trusty 15 | # Note: if you switch to sudo: false, you'll need to launch Chrome with --no-sandbox. 16 | # See https://github.com/travis-ci/travis-ci/issues/8836 17 | sudo: required 18 | addons: 19 | chrome: stable # have Travis install Chrome stable. 20 | -------------------------------------------------------------------------------- /.zuul.yml: -------------------------------------------------------------------------------- 1 | ui: mocha-bdd 2 | browsers: 3 | - name: chrome 4 | version: 30..latest 5 | - name: firefox 6 | version: 30..latest 7 | - name: ie 8 | version: latest 9 | - name: safari 10 | version: latest 11 | browserify: 12 | - transform: brfs 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2017 BitPay, Inc. 2 | 3 | Parts of this software are based on Bitcoin Core 4 | Copyright (c) 2009-2015 The Bitcoin Core developers 5 | 6 | Parts of this software are based on fullnode 7 | Copyright (c) 2014 Ryan X. Charles 8 | Copyright (c) 2014 reddit, Inc. 9 | 10 | Parts of this software are based on BitcoinJS 11 | Copyright (c) 2011 Stefan Thomas 12 | 13 | Parts of this software are based on BitcoinJ 14 | Copyright (c) 2011 Google Inc. 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in 24 | all copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 | THE SOFTWARE. 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bitcore Library 2 | ======= 3 | THIS REPO HAVE BEEN MOVED TO BITCORE's MONO REPO. Check: 4 | 5 | https://github.com/bitpay/bitcore/tree/v8.0.0/packages/bitcore-lib 6 | -------------------------------------------------------------------------------- /benchmark/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "bcoin": "0.15.0", 4 | "bitcoinjs-lib": "^1.5.7", 5 | "fullnode": "^0.9.0", 6 | "benchmark": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /benchmark/script.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var benchmark = require('benchmark'); 4 | var bitcore = require('..'); 5 | var async = require('async'); 6 | var blockData = require('./block-357238.json'); 7 | 8 | var maxTime = 30; 9 | 10 | console.log('Benchmarking Script'); 11 | console.log('---------------------------------------'); 12 | 13 | async.series([ 14 | function(next) { 15 | 16 | var c = 0; 17 | var scripts = []; 18 | var block = bitcore.Block.fromString(blockData); 19 | for (var i = 0; i < block.transactions.length; i++) { 20 | var tx = block.transactions[i]; 21 | for (var j = 0; j < tx.inputs.length; j++) { 22 | var input = tx.inputs[j]; 23 | if (input.script) { 24 | scripts.push(input.script); 25 | } 26 | } 27 | for (var k = 0; k < tx.outputs.length; k++) { 28 | var output = tx.outputs[k]; 29 | if (output.script) { 30 | scripts.push(output.script); 31 | } 32 | } 33 | } 34 | 35 | function isPublicKeyOut() { 36 | if (c >= scripts.length) { 37 | c = 0; 38 | } 39 | scripts[c].isPublicKeyOut(); 40 | c++; 41 | } 42 | 43 | function isPublicKeyHashIn() { 44 | if (c >= scripts.length) { 45 | c = 0; 46 | } 47 | scripts[c].isPublicKeyHashIn(); 48 | c++; 49 | } 50 | 51 | function toAddress() { 52 | if (c >= scripts.length) { 53 | c = 0; 54 | } 55 | scripts[c].toAddress(); 56 | c++; 57 | } 58 | 59 | function getAddressInfo() { 60 | if (c >= scripts.length) { 61 | c = 0; 62 | } 63 | scripts[c].getAddressInfo(); 64 | c++; 65 | } 66 | 67 | var suite = new benchmark.Suite(); 68 | suite.add('isPublicKeyHashIn', isPublicKeyHashIn, {maxTime: maxTime}); 69 | suite.add('isPublicKeyOut', isPublicKeyOut, {maxTime: maxTime}); 70 | suite.add('toAddress', toAddress, {maxTime: maxTime}); 71 | suite.add('getAddressInfo', getAddressInfo, {maxTime: maxTime}); 72 | suite 73 | .on('cycle', function(event) { 74 | console.log(String(event.target)); 75 | }) 76 | .on('complete', function() { 77 | console.log('Done'); 78 | console.log('----------------------------------------------------------------------'); 79 | next(); 80 | }) 81 | .run(); 82 | } 83 | ], function(err) { 84 | console.log('Finished'); 85 | }); 86 | -------------------------------------------------------------------------------- /benchmark/serialization.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var benchmark = require('benchmark'); 4 | var bitcore = require('..'); 5 | var bitcoinjs = require('bitcoinjs-lib'); 6 | var bcoin = require('bcoin'); 7 | var async = require('async'); 8 | var fullnode = require('fullnode'); 9 | var blockData = require('./block-357238.json'); 10 | 11 | var maxTime = 20; 12 | 13 | console.log('Benchmarking Block/Transaction Serialization'); 14 | console.log('---------------------------------------'); 15 | 16 | async.series([ 17 | function(next) { 18 | 19 | var buffers = []; 20 | var hashBuffers = []; 21 | console.log('Generating Random Test Data...'); 22 | for (var i = 0; i < 100; i++) { 23 | 24 | // uint64le 25 | var br = new bitcore.encoding.BufferWriter(); 26 | var num = Math.round(Math.random() * 10000000000000); 27 | br.writeUInt64LEBN(new bitcore.crypto.BN(num)); 28 | buffers.push(br.toBuffer()); 29 | 30 | // hashes 31 | var data = bitcore.crypto.Hash.sha256sha256(new Buffer(32)); 32 | hashBuffers.push(data); 33 | } 34 | 35 | var c = 0; 36 | var bn; 37 | 38 | function readUInt64LEBN() { 39 | if (c >= buffers.length) { 40 | c = 0; 41 | } 42 | var buf = buffers[c]; 43 | var br = new bitcore.encoding.BufferReader(buf); 44 | bn = br.readUInt64LEBN(); 45 | c++; 46 | } 47 | 48 | var reversed; 49 | 50 | function readReverse() { 51 | if (c >= hashBuffers.length) { 52 | c = 0; 53 | } 54 | var buf = hashBuffers[c]; 55 | var br = new bitcore.encoding.BufferReader(buf); 56 | reversed = br.readReverse(); 57 | c++; 58 | } 59 | 60 | console.log('Starting benchmark...'); 61 | 62 | var suite = new benchmark.Suite(); 63 | suite.add('bufferReader.readUInt64LEBN()', readUInt64LEBN, {maxTime: maxTime}); 64 | suite.add('bufferReader.readReverse()', readReverse, {maxTime: maxTime}); 65 | suite 66 | .on('cycle', function(event) { 67 | console.log(String(event.target)); 68 | }) 69 | .on('complete', function() { 70 | console.log('Done'); 71 | console.log('----------------------------------------------------------------------'); 72 | next(); 73 | }) 74 | .run(); 75 | }, 76 | function(next) { 77 | 78 | var block1; 79 | var block2; 80 | var block3; 81 | 82 | function bitcoreTest() { 83 | block1 = bitcore.Block.fromString(blockData); 84 | } 85 | 86 | function bitcoinJSTest() { 87 | block2 = bitcoinjs.Block.fromHex(blockData); 88 | } 89 | 90 | var parser = new bcoin.protocol.parser(); 91 | 92 | function bcoinTest() { 93 | var raw = bcoin.utils.toArray(blockData, 'hex'); 94 | var data = parser.parseBlock(raw); 95 | block3 = new bcoin.block(data, 'block'); 96 | } 97 | 98 | var blockDataMessage = '0000000000000000' + blockData; // add mock leading magic and size 99 | 100 | function fullnodeTest() { 101 | fullnode.Block().fromHex(blockDataMessage); 102 | } 103 | 104 | var suite = new benchmark.Suite(); 105 | suite.add('bitcore', bitcoreTest, {maxTime: maxTime}); 106 | suite.add('bitcoinjs', bitcoinJSTest, {maxTime: maxTime}); 107 | suite.add('bcoin', bcoinTest, {maxTime: maxTime}); 108 | suite.add('fullnode', fullnodeTest, {maxTime: maxTime}); 109 | suite 110 | .on('cycle', function(event) { 111 | console.log(String(event.target)); 112 | }) 113 | .on('complete', function() { 114 | console.log('Fastest is ' + this.filter('fastest').pluck('name')); 115 | console.log('----------------------------------------------------------------------'); 116 | next(); 117 | }) 118 | .run(); 119 | } 120 | ], function(err) { 121 | console.log('Finished'); 122 | }); 123 | -------------------------------------------------------------------------------- /docs/address.md: -------------------------------------------------------------------------------- 1 | # Bitcoin Address 2 | Represents a bitcoin address. Addresses are the most popular way to make bitcoin transactions. See [the official Bitcoin Wiki](https://en.bitcoin.it/wiki/Address) for technical background information. 3 | 4 | ## Instantiate an Address 5 | To be able to receive bitcoins an address is needed, but in order to spend them a private key is necessary. Please take a look at the [`PrivateKey`](privatekey.md) docs for more information about exporting and saving a key. 6 | 7 | ```javascript 8 | var privateKey = new PrivateKey(); 9 | var address = privateKey.toAddress(); 10 | ``` 11 | 12 | You can also instantiate an Address from a String, [PublicKey](publickey.md), or [HDPublicKey](hierarchical.md), in case you are not the owner of the private key. 13 | 14 | ```javascript 15 | // from a string 16 | var address = Address.fromString('mwkXG8NnB2snbqWTcpNiK6qqGHm1LebHDc'); 17 | 18 | // a default network address from a public key 19 | var publicKey = PublicKey(privateKey); 20 | var address = new Address(publicKey); 21 | // alternative interface 22 | var address = Address.fromPublicKey(publicKey); 23 | 24 | // a testnet address from a public key 25 | var publicKey = new PublicKey(privateKey); 26 | var address = new Address(publicKey, Networks.testnet); 27 | ``` 28 | 29 | A pay-to-script-hash multisignature Address can be instantiated from an array of [PublicKeys](publickey.md). 30 | 31 | ```javascript 32 | // a 2-of-3 address from public keys 33 | var p2shAddress = new Address([publicKey1, publicKey2, publicKey3], 2); 34 | ``` 35 | 36 | ## Validating an Address 37 | The main use that we expect you'll have for the `Address` class in Bitcore is validating that an address is a valid one, what type of address it is (you may be interested on knowing if the address is a simple "pay to public key hash" address or a "pay to script hash" address) and what network does the address belong to. 38 | 39 | The code to do these validations looks like this: 40 | 41 | ```javascript 42 | // validate an address 43 | if (Address.isValid(input){ 44 | ... 45 | } 46 | 47 | // validate that an input field is a valid testnet address 48 | if (Address.isValid(input, Networks.testnet){ 49 | ... 50 | } 51 | 52 | // validate that an input field is a valid livenet pubkeyhash 53 | if (Address.isValid(input, Networks.livenet, Address.PayToPublicKeyHash){ 54 | ... 55 | } 56 | 57 | // get the specific validation error that can occurred 58 | var error = Address.getValidationError(input, Networks.testnet); 59 | if (error) { 60 | // handle the error 61 | } 62 | } 63 | ``` 64 | 65 | The errors are listed in the generated file in the [errors folder](https://github.com/bitpay/bitcore/tree/master/lib/errors). There's a structure to errors defined in the [spec.js file](https://github.com/bitpay/bitcore/tree/master/lib/errors/spec.js). 66 | -------------------------------------------------------------------------------- /docs/block.md: -------------------------------------------------------------------------------- 1 | # Bitcoin Block 2 | A Block instance represents the information of a block in the bitcoin network. Given a hexadecimal string representation of the serialization of a block with its transactions, you can instantiate a Block instance. Methods are provided to calculate and check the merkle root hash (if enough data is provided), but transactions won't necessarily be valid spends, and this class won't validate them. A binary representation as a `Buffer` instance is also valid input for a Block's constructor. 3 | 4 | ```javascript 5 | // instantiate a new block instance 6 | var block = new Block(hexaEncodedBlock); 7 | 8 | // will verify that the corresponding block transactions match the header 9 | assert(block.validMerkleRoot()); 10 | 11 | // blocks have several properties 12 | assert(block.header); // an instance of block header, more info below 13 | assert(block.transactions); // an array of transactions, more info below 14 | ``` 15 | 16 | For detailed technical information about a block please visit [Blocks](https://en.bitcoin.it/wiki/Blocks#Block_structure) on the Bitcoin Wiki. 17 | 18 | ## Block Header 19 | Each instance of Block has a BlockHeader _(which can be instantiated separately)_. The header has validation methods, to verify that the block. 20 | 21 | ```javascript 22 | // will verify that the nonce demonstrates enough proof of work 23 | assert(block.header.validProofOfWork()); 24 | 25 | // will verify that timestamp is not too far in the future 26 | assert(block.header.validTimestamp()); 27 | 28 | // each header has the following properties 29 | assert(block.header.version); 30 | assert(block.header.prevHash); 31 | assert(block.header.merkleRoot); 32 | assert(block.header.time); 33 | assert(block.header.bits); 34 | assert(block.header.nonce); 35 | ``` 36 | 37 | For more information about the specific properties of a block header please visit the [Block hashing algorithm](https://en.bitcoin.it/wiki/Block_hashing_algorithm) page on the Bitcoin Wiki. 38 | 39 | ## Transactions 40 | The set of transactions in a block is an array of instances of [Transaction](transaction.md) and can be explored by iterating on the block's `transactions` member. 41 | 42 | ```javascript 43 | for (var i in block.transactions) { 44 | var transaction = block.transactions[i]; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/browser.md: -------------------------------------------------------------------------------- 1 | # Browser Builds 2 | Bitcore and most official submodules work in the browser, thanks to [browserify](http://browserify.org/) (some modules are not fully compatible with web browsers). 3 | 4 | The easiest and recommended way to use them, is via [Bower](http://bower.io/), a browser package manager, and get the release bundles. For example, when building an app that uses `bitcore` and `bitcore-mnemonic`, you do: 5 | 6 | ```sh 7 | bower install bitcore-lib 8 | bower install bitcore-mnemonic 9 | ``` 10 | 11 | You can also use a `bower.json` file to store the dependencies of your project: 12 | 13 | ```json 14 | { 15 | "name": "Your app name", 16 | "version": "0.0.1", 17 | "license": "MIT", 18 | "dependencies": { 19 | "bitcore-lib": "^0.13.7", 20 | "bitcore-mnemonic": "^1.0.1" 21 | } 22 | } 23 | ``` 24 | 25 | and run `bower install` to install the dependencies. 26 | 27 | After this, you can include the bundled release versions in your HTML file: 28 | 29 | ```html 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | ``` 51 | 52 | ## Building Custom Bundles 53 | If you want to use a specific version of a module, instead of a release version (not recommended), you must run browserify yourself. You can get a minified browser bundle by running the following on the project root folder. 54 | 55 | ```sh 56 | browserify --require ./index.js:bitcore-lib | uglifyjs > bitcore-lib.min.js 57 | ``` 58 | 59 | ```sh 60 | browserify --require ./index.js:bitcore-mnemonic --external bitcore-lib | uglifyjs > bitcore-mnemonic.min.js 61 | ``` 62 | 63 | In many of the modules you can also run the command to build a browser bundle: 64 | ```sh 65 | gulp browser 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/crypto.md: -------------------------------------------------------------------------------- 1 | # Bitcoin Crypto 2 | The cryptographic primitives (ECDSA and HMAC) implementations in this package have been reviewed by the BitPay engineering team. More audits and reviews are welcomed. 3 | 4 | ## Random 5 | The `bitcore.crypto.Random` namespace contains a single function, named `getRandomBuffer(size)` that returns a `Buffer` instance with random bytes. It may not work depending on the engine that bitcore is running on (doesn't work with IE versions lesser than 11). 6 | 7 | ## BN 8 | The `bitcore.crypto.BN` class contains a wrapper around [bn.js](https://github.com/indutny/bn.js), the bignum library used internally in bitcore. 9 | 10 | ## Point 11 | The `bitcore.crypto.Point` class contains a wrapper around the class Point of [elliptic.js](https://github.com/indutny/elliptic), the elliptic curve library used internally in bitcore. 12 | 13 | ## Hash 14 | The `bitcore.crypto.Hash` namespace contains a set of hashes and utilities. These are either the native `crypto` hash functions from `node.js` or their respective browser shims as provided by the `browserify` library. 15 | 16 | ## ECDSA 17 | `bitcore.crypto.ECDSA` contains a pure JavaScript implementation of the elliptic curve DSA signature scheme based on [elliptic.js](https://github.com/indutny/elliptic). 18 | -------------------------------------------------------------------------------- /docs/encoding.md: -------------------------------------------------------------------------------- 1 | # Encoding 2 | The `bitcore.Encoding` namespace contains utilities for encoding information in common formats in the bitcoin ecosystem. 3 | 4 | ## Base58 & Base58Check 5 | Two classes are provided: `Base58` and `Base58Check`. The first one merely encodes/decodes a set of bytes in base58 format. The second one will also take the double `sha256` hash of the information and append the last 4 bytes of the hash as a checksum when encoding, and check this checksum when decoding. 6 | 7 | ## BufferReader & BufferWriter 8 | These classes are used internally to write information in buffers. 9 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | # Bitcore examples 2 | 3 | ## Generate a random address 4 | ```javascript 5 | var privateKey = new bitcore.PrivateKey(); 6 | 7 | var address = privateKey.toAddress(); 8 | ``` 9 | 10 | ## Generate a address from a SHA256 hash 11 | ```javascript 12 | var value = Buffer.from('correct horse battery staple'); 13 | var hash = bitcore.crypto.Hash.sha256(value); 14 | var bn = bitcore.crypto.BN.fromBuffer(hash); 15 | 16 | var address = new bitcore.PrivateKey(bn).toAddress(); 17 | ``` 18 | 19 | ## Import an address via WIF 20 | ```javascript 21 | var wif = 'Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct'; 22 | 23 | var address = new bitcore.PrivateKey(wif).toAddress(); 24 | ``` 25 | 26 | ## Create a Transaction 27 | ```javascript 28 | var privateKey = new bitcore.PrivateKey('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy'); 29 | var utxo = { 30 | "txId" : "115e8f72f39fad874cfab0deed11a80f24f967a84079fb56ddf53ea02e308986", 31 | "outputIndex" : 0, 32 | "address" : "17XBj6iFEsf8kzDMGQk5ghZipxX49VXuaV", 33 | "script" : "76a91447862fe165e6121af80d5dde1ecb478ed170565b88ac", 34 | "satoshis" : 50000 35 | }; 36 | 37 | var transaction = new bitcore.Transaction() 38 | .from(utxo) 39 | .to('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000) 40 | .sign(privateKey); 41 | ``` 42 | 43 | ## Sign a Bitcoin message 44 | ```javascript 45 | var Message = require('bitcore-message'); 46 | 47 | var privateKey = new bitcore.PrivateKey('L23PpjkBQqpAF4vbMHNfTZAb3KFPBSawQ7KinFTzz7dxq6TZX8UA'); 48 | var message = new Message('This is an example of a signed message.'); 49 | 50 | var signature = message.sign(privateKey); 51 | ``` 52 | 53 | ## Verify a Bitcoin message 54 | ```javascript 55 | var Message = require('bitcore-message'); 56 | 57 | var address = '13Js7D3q4KvfSqgKN8LpNq57gcahrVc5JZ'; 58 | var signature = 'IBOvIfsAs/da1e36W8kw1cQOPqPVXCW5zJgNQ5kI8m57FycZXdeFmeyoIqJSREzE4W7vfDmdmPk0HokuJPvgPPE='; 59 | 60 | var verified = new Message('This is an example of a signed message.').verify(address, signature); 61 | ``` 62 | 63 | ## Create an OP RETURN transaction 64 | ```javascript 65 | var privateKey = new bitcore.PrivateKey('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy'); 66 | var utxo = { 67 | "txId" : "115e8f72f39fad874cfab0deed11a80f24f967a84079fb56ddf53ea02e308986", 68 | "outputIndex" : 0, 69 | "address" : "17XBj6iFEsf8kzDMGQk5ghZipxX49VXuaV", 70 | "script" : "76a91447862fe165e6121af80d5dde1ecb478ed170565b88ac", 71 | "satoshis" : 50000 72 | }; 73 | 74 | var transaction = new bitcore.Transaction() 75 | .from(utxo) 76 | .addData('bitcore rocks') // Add OP_RETURN data 77 | .sign(privateKey); 78 | ``` 79 | 80 | ## Create a 2-of-3 multisig P2SH address 81 | ```javascript 82 | var publicKeys = [ 83 | '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', 84 | '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', 85 | '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9' 86 | ]; 87 | var requiredSignatures = 2; 88 | 89 | var address = new bitcore.Address(publicKeys, requiredSignatures); 90 | ``` 91 | 92 | ## Spend from a 2-of-2 multisig P2SH address 93 | ```javascript 94 | var privateKeys = [ 95 | new bitcore.PrivateKey('91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx'), 96 | new bitcore.PrivateKey('91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT') 97 | ]; 98 | var publicKeys = privateKeys.map(bitcore.PublicKey); 99 | var address = new bitcore.Address(publicKeys, 2); // 2 of 2 100 | 101 | var utxo = { 102 | "txId" : "153068cdd81b73ec9d8dcce27f2c77ddda12dee3db424bff5cafdbe9f01c1756", 103 | "outputIndex" : 0, 104 | "address" : address.toString(), 105 | "script" : new bitcore.Script(address).toHex(), 106 | "satoshis" : 20000 107 | }; 108 | 109 | var transaction = new bitcore.Transaction() 110 | .from(utxo, publicKeys, 2) 111 | .to('mtoKs9V381UAhUia3d7Vb9GNak8Qvmcsme', 20000) 112 | .sign(privateKeys); 113 | ``` 114 | -------------------------------------------------------------------------------- /docs/hierarchical.md: -------------------------------------------------------------------------------- 1 | # HDKeys 2 | Create and derive extended public and private keys according to the BIP32 standard for Hierarchical Deterministic (HD) keys. 3 | 4 | ## Hierarchically Derived Keys 5 | Bitcore provides full support for [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), allowing for many key management schemas that benefit from this property. Please be sure to read and understand the basic concepts and the warnings on that BIP before using these classes. 6 | 7 | ## HDPrivateKey 8 | An instance of a [PrivateKey](privatekey.md) that also contains information required to derive child keys. 9 | 10 | Sample usage: 11 | 12 | ```javascript 13 | var bitcore = require('bitcore'); 14 | var HDPrivateKey = bitcore.HDPrivateKey; 15 | 16 | var hdPrivateKey = new HDPrivateKey(); 17 | var retrieved = new HDPrivateKey('xpriv...'); 18 | var derived = hdPrivateKey.derive("m/0'"); // see deprecation warning for derive 19 | var derivedByNumber = hdPrivateKey.derive(1).derive(2, true); 20 | var derivedByArgument = hdPrivateKey.derive("m/1/2'"); 21 | assert(derivedByNumber.xprivkey === derivedByArgument.xprivkey); 22 | 23 | var address = derived.privateKey.toAddress(); 24 | 25 | // obtain HDPublicKey 26 | var hdPublicKey = hdPrivateKey.hdPublicKey; 27 | ``` 28 | 29 | ## HDPublicKey 30 | An instance of a PublicKey that can be derived to build extended public keys. Note that hardened paths are not available when deriving an HDPublicKey. 31 | 32 | ```javascript 33 | var hdPrivateKey = new HDPrivateKey(); 34 | var hdPublicKey = hdPrivateKey.hdPublicKey; 35 | try { 36 | new HDPublicKey(); 37 | } catch(e) { 38 | console.log("Can't generate a public key without a private key"); 39 | } 40 | 41 | var address = new Address(hdPublicKey.publicKey, Networks.livenet); 42 | var derivedAddress = new Address(hdPublicKey.derive(100).publicKey, Networks.testnet); // see deprecation warning for derive 43 | ``` 44 | 45 | ## Deprecation Warning for `HDPublicKey.derive()` and `HDPrivateKey.derive()` 46 | 47 | 48 | There was a bug that was discovered with derivation that would incorrectly calculate the child key against the [BIP32 specification](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki). 49 | The bug only affected hardened derivations using an extended private key, and did not affect public key derivation. It also did not affect every derivation and would happen 1 in 256 times where where the private key for the extended private key had a leading zero *(e.g. any private key less than or equal to '0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')*. The leading zero was not included in serialization before hashing to derive a child key, as it should have been. 50 | 51 | As a result, `HDPublicKey.derive()` and `HDPrivateKey.derive()` are now deprecated. These methods will throw an error in the next major release. 52 | `HDPublicKey.deriveChild()`, `HDPrivateKey.deriveChild()`, and `HDPrivateKey.deriveNonCompliantChild()` have been implemented as alternatives. Note that these new methods will not be officially supported until v1.0.0. `deriveNonCompliantChild` will derive using the non-BIP32 derivation and is equivalent to the buggy version, `derive`. The `deriveNonCompliantChild` method should not be used unless you're upgrading and need to maintain compatibility with the old derivation. 53 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Bitcore v0.16.0 2 | 3 | ## Principles 4 | 5 | Bitcoin is a powerful new peer-to-peer platform for the next generation of financial technology. The decentralized nature of the Bitcoin network allows for highly resilient bitcoin infrastructure, and the developer community needs reliable, open-source tools to implement bitcoin apps and services. Bitcore provides a reliable API for JavaScript apps that need to interface with Bitcoin. 6 | 7 | To get started, just `npm install bitcore` or `bower install bitcore`. 8 | 9 | # Documentation Index 10 | 11 | ## Addresses and Key Management 12 | 13 | * [Addresses](address.md) 14 | * [Using Different Networks](networks.md) 15 | * [Private Keys](privatekey.md) and [Public Keys](publickey.md) 16 | * [Hierarchically-derived Private and Public Keys](hierarchical.md) 17 | 18 | ## Payment Handling 19 | * [Using Different Units](unit.md) 20 | * [Acknowledging and Requesting Payments: Bitcoin URIs](uri.md) 21 | * [The Transaction Class](transaction.md) 22 | 23 | ## Bitcoin Internals 24 | * [Scripts](script.md) 25 | * [Block](block.md) 26 | 27 | ## Extra 28 | * [Crypto](crypto.md) 29 | * [Encoding](encoding.md) 30 | 31 | ## Module Development 32 | * [Browser Builds](browser.md) 33 | 34 | ## Modules 35 | 36 | Some functionality is implemented as a module that can be installed separately: 37 | 38 | * [Payment Protocol Support](https://github.com/bitpay/bitcore-payment-protocol) 39 | * [Peer to Peer Networking](https://github.com/bitpay/bitcore-p2p) 40 | * [Bitcoin Core JSON-RPC](https://github.com/bitpay/bitcoind-rpc) 41 | * [Payment Channels](https://github.com/bitpay/bitcore-channel) 42 | * [Mnemonics](https://github.com/bitpay/bitcore-mnemonic) 43 | * [Elliptical Curve Integrated Encryption Scheme](https://github.com/bitpay/bitcore-ecies) 44 | * [Blockchain Explorers](https://github.com/bitpay/bitcore-explorers) 45 | * [Signed Messages](https://github.com/bitpay/bitcore-message) 46 | 47 | # Examples 48 | 49 | ## Create and Save a Private Key 50 | 51 | ```javascript 52 | var privateKey = new bitcore.PrivateKey(); 53 | 54 | var exported = privateKey.toWIF(); 55 | // e.g. L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m 56 | var imported = bitcore.PrivateKey.fromWIF(exported); 57 | var hexa = privateKey.toString(); 58 | // e.g. 'b9de6e778fe92aa7edb69395556f843f1dce0448350112e14906efc2a80fa61a' 59 | ``` 60 | 61 | ## Create an Address 62 | 63 | ```javascript 64 | var address = privateKey.toAddress(); 65 | ``` 66 | 67 | ## Create a Multisig Address 68 | 69 | ```javascript 70 | // Build a 2-of-3 address from public keys 71 | var p2shAddress = new bitcore.Address([publicKey1, publicKey2, publicKey3], 2); 72 | ``` 73 | 74 | ## Request a Payment 75 | 76 | ```javascript 77 | var paymentInfo = { 78 | address: '1DNtTk4PUCGAdiNETAzQFWZiy2fCHtGnPx', 79 | amount: 120000 //satoshis 80 | }; 81 | var uri = new bitcore.URI(paymentInfo).toString(); 82 | ``` 83 | 84 | ## Create a Transaction 85 | 86 | ```javascript 87 | var transaction = new Transaction() 88 | .from(utxos) // Feed information about what unspent outputs one can use 89 | .to(address, amount) // Add an output with the given amount of satoshis 90 | .change(address) // Sets up a change address where the rest of the funds will go 91 | .sign(privkeySet) // Signs all the inputs it can 92 | ``` 93 | 94 | ## Connect to the Network 95 | 96 | ```javascript 97 | var peer = new Peer('5.9.85.34'); 98 | 99 | peer.on('inv', function(message) { 100 | // new inventory 101 | }); 102 | 103 | peer.connect(); 104 | ``` 105 | -------------------------------------------------------------------------------- /docs/networks.md: -------------------------------------------------------------------------------- 1 | # Networks 2 | Bitcore provides support for the main bitcoin network as well as for `testnet3`, the current test blockchain. We encourage the use of `Networks.livenet` and `Networks.testnet` as constants. Note that the library sometimes may check for equality against this object. Please avoid creating a deep copy of this object. 3 | 4 | The `Network` namespace has a function, `get(...)` that returns an instance of a `Network` or `undefined`. The only argument to this function is some kind of identifier of the network: either its name, a reference to a Network object, or a number used as a magic constant to identify the network (for example, the value `0` that gives bitcoin addresses the distinctive `'1'` at its beginning on livenet, is a `0x6F` for testnet). 5 | 6 | ## Regtest 7 | 8 | The regtest network is useful for development as it's possible to programmatically and instantly generate blocks for testing. It's currently supported as a variation of testnet. Here is an example of how to use regtest with the Bitcore Library: 9 | 10 | ```js 11 | // Standard testnet 12 | > bitcore.Networks.testnet.networkMagic; 13 | 14 | ``` 15 | 16 | ```js 17 | // Enabling testnet to use the regtest port and magicNumber 18 | > bitcore.Networks.enableRegtest(); 19 | > bitcore.Networks.testnet.networkMagic; 20 | 21 | ``` 22 | 23 | ## Setting the Default Network 24 | Most projects will only need to work with one of the networks. The value of `Networks.defaultNetwork` can be set to `Networks.testnet` if the project will need to only to work on testnet (the default is `Networks.livenet`). 25 | 26 | ## Network constants 27 | The functionality of testnet and livenet is mostly similar (except for some relaxed block validation rules on testnet). They differ in the constants being used for human representation of base58 encoded strings. These are sometimes referred to as "version" constants. 28 | 29 | Take a look at this modified snippet from [networks.js](https://github.com/bitpay/bitcore/blob/master/lib/networks.js) 30 | 31 | ```javascript 32 | var livenet = new Network(); 33 | _.extend(livenet, { 34 | name: 'livenet', 35 | alias: 'mainnet', 36 | pubkeyhash: 0x00, 37 | privatekey: 0x80, 38 | scripthash: 0x05, 39 | xpubkey: 0x0488b21e, 40 | xprivkey: 0x0488ade4, 41 | port: 8333 42 | }); 43 | 44 | var testnet = new Network(); 45 | _.extend(testnet, { 46 | name: 'testnet', 47 | alias: 'testnet', 48 | pubkeyhash: 0x6f, 49 | privatekey: 0xef, 50 | scripthash: 0xc4, 51 | xpubkey: 0x043587cf, 52 | xprivkey: 0x04358394, 53 | port: 18333 54 | }); 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/privatekey.md: -------------------------------------------------------------------------------- 1 | # Private Key 2 | Represents a bitcoin private key and is needed to be able to spend bitcoin and sign transactions. See the official [Bitcoin Wiki](https://en.bitcoin.it/wiki/Private_key) for more information about private keys. A PrivateKey in Bitcore is an immutable object that has methods to import and export into a variety of formats including [Wallet Import Format](https://en.bitcoin.it/wiki/Wallet_import_format). 3 | 4 | ## Instantiate a Private Key 5 | Here is how to create a new private key. It will generate a new random number using `window.crypto` or the Node.js `crypto` library. 6 | 7 | ```javascript 8 | var privateKey = new PrivateKey(); 9 | 10 | // Creates a private key from a hexa encoded number 11 | var privateKey2 = new PrivateKey('b221d9dbb083a7f33428d7c2a3c3198ae925614d70210e28716ccaa7cd4ddb79'); 12 | ``` 13 | 14 | To export and import a private key, you can do the following: 15 | 16 | ```javascript 17 | // encode into wallet export format 18 | var exported = privateKey.toWIF(); 19 | 20 | // instantiate from the exported (and saved) private key 21 | var imported = PrivateKey.fromWIF('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m'); 22 | ``` 23 | 24 | Note: The WIF (Wallet Import Format) includes information about the network and if the associated public key is compressed or uncompressed (thus the same bitcoin address will be generated by using this format). 25 | 26 | To generate an Address or PublicKey from a PrivateKey: 27 | 28 | ```javascript 29 | var publicKey = privateKey.toPublicKey(); 30 | var address = publicKey.toAddress(Networks.livenet); 31 | ``` 32 | 33 | ## Validating a Private Key 34 | The code to do these validations looks like this: 35 | 36 | ```javascript 37 | // validate an address 38 | if (PrivateKey.isValid(input)){ 39 | ... 40 | } 41 | 42 | // get the specific validation error that can occurred 43 | var error = PrivateKey.getValidationError(input, Networks.livenet); 44 | if (error) { 45 | // handle the error 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/publickey.md: -------------------------------------------------------------------------------- 1 | # Public Key 2 | Represents a bitcoin public key and is needed to be able to receive bitcoin, as is usually represented as a bitcoin [Address](address.md). See the official [Bitcoin Wiki](https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses). 3 | 4 | A PublicKey in Bitcore is an immutable object and can be instantiated from a [Point](crypto.md), string, [PrivateKey](privatekey.md), Buffer or a [BN](crypto.md). 5 | 6 | ## Instantiate a Public Key 7 | Here is how to instantiate a public key: 8 | 9 | ```javascript 10 | 11 | var privateKey = new PrivateKey(); 12 | 13 | // from a private key 14 | var publicKey = new PublicKey(privateKey); 15 | 16 | // from a der hex encoded string 17 | var publicKey2 = new PublicKey('02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc'); 18 | ``` 19 | 20 | ## Validating a Public Key 21 | A public key point should be on the [secp256k1](https://en.bitcoin.it/wiki/Secp256k1) curve, instantiating a new PublicKey will validate this and will throw an error if it's invalid. To check that a public key is valid: 22 | 23 | ```javascript 24 | if (PublicKey.isValid('02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc')){ 25 | // valid public key 26 | } 27 | ``` 28 | 29 | ## Compressed vs Uncompressed 30 | It's important to note that there are two possible ways to represent a public key. The standard is _compressed_ and includes the X value and parity (as represented above in the documentation). There is also a longer version that is _uncompressed_ which includes both X and Y values. Using this encoding will generate a different bitcoin address, so be careful when selecting the encoding. Uncompressed public keys start with 0x04; compressed public keys begin with 0x03 or 0x02 depending on whether they're greater or less than the midpoint of the curve. These prefix bytes are all used in official secp256k1 documentation. 31 | 32 | Example: 33 | 34 | ```javascript 35 | > var bitcore = require('bitcore'); 36 | 37 | // compressed public key starting with 0x03 (greater than midpoint of curve) 38 | > var compressedPK = bitcore.PublicKey('030589ee559348bd6a7325994f9c8eff12bd'+ 39 | '5d73cc683142bd0dd1a17abc99b0dc'); 40 | > compressedPK.compressed; 41 | true 42 | > compressedPK.toAddress().toString(); 43 | '1KbUJ4x8epz6QqxkmZbTc4f79JbWWz6g37' 44 | // compressed public key starting with 0x02 (smaller than midpoint of curve) 45 | > var compressedPK2 = new bitcore.PublicKey('02a1633cafcc01ebfb6d78e39f687a1f'+ 46 | '0995c62fc95f51ead10a02ee0be551b5dc'); 47 | > compressedPK2.compressed; 48 | true 49 | > compressedPK.toAddress().toString(); 50 | '1KbUJ4x8epz6QqxkmZbTc4f79JbWWz6g37' 51 | // uncompressed public key, starting with 0x04. Contains both X and Y encoded 52 | > var uncompressed = bitcore.PublicKey('0479BE667EF9DCBBAC55A06295CE870B07029'+ 53 | 'BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68'+ 54 | '554199C47D08FFB10D4B8'); 55 | > uncompressed.compressed 56 | false 57 | > uncompressed.toAddress().toString() 58 | '1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm' 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/unit.md: -------------------------------------------------------------------------------- 1 | # Unit 2 | Unit is a utility for handling and converting bitcoin units. We strongly recommend to always use satoshis to represent amount inside your application and only convert them to other units in the front-end. 3 | 4 | To understand the need of using the `Unit` class when dealing with unit conversions, see this example: 5 | 6 | ``` 7 | > 81.99 * 100000 // wrong 8 | 8198999.999999999 9 | > var bitcore = require('bitcore'); 10 | > var Unit = bitcore.Unit; 11 | > Unit.fromMilis(81.99).toSatoshis() // correct 12 | 8199000 13 | ``` 14 | 15 | ## Supported units 16 | The supported units are BTC, mBTC, bits (micro BTCs, uBTC) and satoshis. The codes for each unit can be found as members of the Unit class. 17 | 18 | ```javascript 19 | var btcCode = Unit.BTC; 20 | var mbtcCode = Unit.mBTC; 21 | var ubtcCode = Unit.uBTC; 22 | var bitsCode = Unit.bits; 23 | var satsCode = Unit.satoshis; 24 | ``` 25 | 26 | ## Creating units 27 | There are two ways for creating a unit instance. You can instantiate the class using a value and a unit code; alternatively if the unit it's fixed you could you some of the static methods. Check some examples below: 28 | 29 | ```javascript 30 | var unit; 31 | var amount = 100; 32 | 33 | // using a unit code 34 | var unitPreference = Unit.BTC; 35 | unit = new Unit(amount, unitPreference); 36 | 37 | // using a known unit 38 | unit = Unit.fromBTC(amount); 39 | unit = Unit.fromMilis(amount); 40 | unit = Unit.fromBits(amount); 41 | unit = Unit.fromSatoshis(amount); 42 | ``` 43 | 44 | ## Conversion 45 | Once you have a unit instance, you can check its representation in all the available units. For your convenience the classes expose three ways to accomplish this. Using the `.to(unitCode)` method, using a fixed unit like `.toSatoshis()` or by using the accessors. 46 | 47 | ```javascript 48 | var unit; 49 | 50 | // using a unit code 51 | var unitPreference = Unit.BTC; 52 | value = Unit.fromSatoshis(amount).to(unitPreference); 53 | 54 | // using a known unit 55 | value = Unit.fromBTC(amount).toBTC(); 56 | value = Unit.fromBTC(amount).toMilis(); 57 | value = Unit.fromBTC(amount).toBits(); 58 | value = Unit.fromBTC(amount).toSatoshis(); 59 | 60 | // using accessors 61 | value = Unit.fromBTC(amount).BTC; 62 | value = Unit.fromBTC(amount).mBTC; 63 | value = Unit.fromBTC(amount).bits; 64 | value = Unit.fromBTC(amount).satoshis; 65 | ``` 66 | 67 | ## Using a fiat currency 68 | The unit class also provides a convenient alternative to create an instance from a fiat amount and the corresponding BTC/fiat exchange rate. Any unit instance can be converted to a fiat amount by providing the current exchange rate. Check the example below: 69 | 70 | ```javascript 71 | var unit, fiat; 72 | var amount = 100; 73 | var exchangeRate = 350; 74 | 75 | unit = new Unit(amount, exchangeRate); 76 | unit = Unit.fromFiat(amount, exchangeRate); 77 | 78 | fiat = Unit.fromBits(amount).atRate(exchangeRate); 79 | fiat = Unit.fromBits(amount).to(exchangeRate); 80 | ``` 81 | -------------------------------------------------------------------------------- /docs/unspentoutput.md: -------------------------------------------------------------------------------- 1 | # UnspentOutput 2 | `bitcore.Transaction.UnspentOutput` is a class with stateless instances that provides information about an unspent output: 3 | - Transaction ID and output index 4 | - The "scriptPubKey", the script included in the output 5 | - Amount of satoshis associated 6 | - Address, if available 7 | 8 | ## Parameters 9 | The constructor is quite permissive with the input arguments. It can take outputs straight out of bitcoind's getunspent RPC call. Some of the names are not very informative for new users, so the UnspentOutput constructor also understands these aliases: 10 | - `scriptPubKey`: just `script` is also accepted 11 | - `amount`: expected value in BTC. If the `satoshis` alias is used, make sure to use satoshis instead of BTC. 12 | - `vout`: this is the index of the output in the transaction, renamed to `outputIndex` 13 | - `txid`: `txId` 14 | 15 | ## Example 16 | 17 | ```javascript 18 | var utxo = new UnspentOutput({ 19 | "txid" : "a0a08e397203df68392ee95b3f08b0b3b3e2401410a38d46ae0874f74846f2e9", 20 | "vout" : 0, 21 | "address" : "mgJT8iegL4f9NCgQFeFyfvnSw1Yj4M5Woi", 22 | "scriptPubKey" : "76a914089acaba6af8b2b4fb4bed3b747ab1e4e60b496588ac", 23 | "amount" : 0.00070000 24 | }); 25 | var utxo = new UnspentOutput({ 26 | "txId" : "a0a08e397203df68392ee95b3f08b0b3b3e2401410a38d46ae0874f74846f2e9", 27 | "outputIndex" : 0, 28 | "address" : "mgJT8iegL4f9NCgQFeFyfvnSw1Yj4M5Woi", 29 | "script" : "76a914089acaba6af8b2b4fb4bed3b747ab1e4e60b496588ac", 30 | "satoshis" : 70000 31 | }); 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/uri.md: -------------------------------------------------------------------------------- 1 | # Bitcoin URIs 2 | Represents a bitcoin payment URI. Bitcoin URI strings became the most popular way to share payment request, sometimes as a bitcoin link and others using a QR code. 3 | 4 | URI Examples: 5 | 6 | ``` 7 | bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu 8 | bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2 9 | bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2&message=Payment&label=Satoshi&extra=other-param 10 | ``` 11 | 12 | ## URI Validation 13 | The main use that we expect you'll have for the `URI` class in bitcore is validating and parsing bitcoin URIs. A `URI` instance exposes the address as a bitcore `Address` object and the amount in Satoshis, if present. 14 | 15 | The code for validating URIs looks like this: 16 | 17 | ```javascript 18 | var uriString = 'bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2'; 19 | var valid = URI.isValid(uriString); 20 | var uri = new URI(uriString); 21 | console.log(uri.address.network, uri.amount); // 'livenet', 120000000 22 | ``` 23 | 24 | ## URI Parameters 25 | All standard parameters can be found as members of the `URI` instance. However a bitcoin URI may contain other non-standard parameters, all those can be found under the `extra` namespace. 26 | 27 | See [the official BIP21 spec](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) for more information. 28 | 29 | ## Create URI 30 | Another important use case for the `URI` class is creating a bitcoin URI for sharing a payment request. That can be accomplished by using a dictionary to create an instance of URI. 31 | 32 | The code for creating an URI from an Object looks like this: 33 | 34 | ```javascript 35 | var uriString = new URI({ 36 | address: '12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu', 37 | amount : 10000, // in satoshis 38 | message: 'My payment request' 39 | }); 40 | var uriString = uri.toString(); 41 | ``` 42 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var startGulp = require('bitcore-build'); 4 | Object.assign(exports, startGulp('lib')) 5 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var bitcore = module.exports; 4 | 5 | // module information 6 | bitcore.version = 'v' + require('./package.json').version; 7 | bitcore.versionGuard = function(version) { 8 | if (version !== undefined) { 9 | var message = 'More than one instance of bitcore-lib found. ' + 10 | 'Please make sure to require bitcore-lib and check that submodules do' + 11 | ' not also include their own bitcore-lib dependency.'; 12 | throw new Error(message); 13 | } 14 | }; 15 | bitcore.versionGuard(global._bitcore); 16 | global._bitcore = bitcore.version; 17 | 18 | // crypto 19 | bitcore.crypto = {}; 20 | bitcore.crypto.BN = require('./lib/crypto/bn'); 21 | bitcore.crypto.ECDSA = require('./lib/crypto/ecdsa'); 22 | bitcore.crypto.Hash = require('./lib/crypto/hash'); 23 | bitcore.crypto.Random = require('./lib/crypto/random'); 24 | bitcore.crypto.Point = require('./lib/crypto/point'); 25 | bitcore.crypto.Signature = require('./lib/crypto/signature'); 26 | 27 | // encoding 28 | bitcore.encoding = {}; 29 | bitcore.encoding.Base58 = require('./lib/encoding/base58'); 30 | bitcore.encoding.Base58Check = require('./lib/encoding/base58check'); 31 | bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader'); 32 | bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter'); 33 | bitcore.encoding.Varint = require('./lib/encoding/varint'); 34 | 35 | // utilities 36 | bitcore.util = {}; 37 | bitcore.util.buffer = require('./lib/util/buffer'); 38 | bitcore.util.js = require('./lib/util/js'); 39 | bitcore.util.preconditions = require('./lib/util/preconditions'); 40 | 41 | // errors thrown by the library 42 | bitcore.errors = require('./lib/errors'); 43 | 44 | // main bitcoin library 45 | bitcore.Address = require('./lib/address'); 46 | bitcore.Block = require('./lib/block'); 47 | bitcore.MerkleBlock = require('./lib/block/merkleblock'); 48 | bitcore.BlockHeader = require('./lib/block/blockheader'); 49 | bitcore.HDPrivateKey = require('./lib/hdprivatekey.js'); 50 | bitcore.HDPublicKey = require('./lib/hdpublickey.js'); 51 | bitcore.Networks = require('./lib/networks'); 52 | bitcore.Opcode = require('./lib/opcode'); 53 | bitcore.PrivateKey = require('./lib/privatekey'); 54 | bitcore.PublicKey = require('./lib/publickey'); 55 | bitcore.Script = require('./lib/script'); 56 | bitcore.Transaction = require('./lib/transaction'); 57 | bitcore.URI = require('./lib/uri'); 58 | bitcore.Unit = require('./lib/unit'); 59 | 60 | // dependencies, subject to change 61 | bitcore.deps = {}; 62 | bitcore.deps.bnjs = require('bn.js'); 63 | bitcore.deps.bs58 = require('bs58'); 64 | bitcore.deps.Buffer = Buffer; 65 | bitcore.deps.elliptic = require('elliptic'); 66 | bitcore.deps._ = require('lodash'); 67 | 68 | // Internal usage, exposed for testing/advanced tweaking 69 | bitcore.Transaction.sighash = require('./lib/transaction/sighash'); 70 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // karma.conf.js 4 | module.exports = function(config) { 5 | 6 | config.set({ 7 | browsers: ['ChromeHeadless'], 8 | frameworks: ['mocha'], 9 | singleRun: false, 10 | reporters: ['progress'], 11 | logLevel: config.LOG_INFO, 12 | // port: 9876, // karma web server port 13 | autoWatch: false, 14 | files: [ 15 | '../../tests.js' 16 | ], 17 | plugins: [ 18 | 'karma-mocha', 19 | 'karma-chrome-launcher', 20 | ] 21 | }); 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /lib/block/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./block'); 2 | 3 | module.exports.BlockHeader = require('./blockheader'); 4 | module.exports.MerkleBlock = require('./merkleblock'); 5 | -------------------------------------------------------------------------------- /lib/crypto/bn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('bn.js'); 4 | var $ = require('../util/preconditions'); 5 | var _ = require('lodash'); 6 | 7 | var reversebuf = function(buf) { 8 | var buf2 = Buffer.alloc(buf.length); 9 | for (var i = 0; i < buf.length; i++) { 10 | buf2[i] = buf[buf.length - 1 - i]; 11 | } 12 | return buf2; 13 | }; 14 | 15 | BN.Zero = new BN(0); 16 | BN.One = new BN(1); 17 | BN.Minus1 = new BN(-1); 18 | 19 | BN.fromNumber = function(n) { 20 | $.checkArgument(_.isNumber(n)); 21 | return new BN(n); 22 | }; 23 | 24 | BN.fromString = function(str, base) { 25 | $.checkArgument(_.isString(str)); 26 | return new BN(str, base); 27 | }; 28 | 29 | BN.fromBuffer = function(buf, opts) { 30 | if (typeof opts !== 'undefined' && opts.endian === 'little') { 31 | buf = reversebuf(buf); 32 | } 33 | var hex = buf.toString('hex'); 34 | var bn = new BN(hex, 16); 35 | return bn; 36 | }; 37 | 38 | /** 39 | * Instantiate a BigNumber from a "signed magnitude buffer" 40 | * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative)) 41 | */ 42 | BN.fromSM = function(buf, opts) { 43 | var ret; 44 | if (buf.length === 0) { 45 | return BN.fromBuffer(Buffer.from([0])); 46 | } 47 | 48 | var endian = 'big'; 49 | if (opts) { 50 | endian = opts.endian; 51 | } 52 | if (endian === 'little') { 53 | buf = reversebuf(buf); 54 | } 55 | 56 | if (buf[0] & 0x80) { 57 | buf[0] = buf[0] & 0x7f; 58 | ret = BN.fromBuffer(buf); 59 | ret.neg().copy(ret); 60 | } else { 61 | ret = BN.fromBuffer(buf); 62 | } 63 | return ret; 64 | }; 65 | 66 | 67 | BN.prototype.toNumber = function() { 68 | return parseInt(this.toString(10), 10); 69 | }; 70 | 71 | BN.prototype.toBuffer = function(opts) { 72 | var buf, hex; 73 | if (opts && opts.size) { 74 | hex = this.toString(16, 2); 75 | var natlen = hex.length / 2; 76 | buf = Buffer.from(hex, 'hex'); 77 | 78 | if (natlen === opts.size) { 79 | buf = buf; 80 | } else if (natlen > opts.size) { 81 | buf = BN.trim(buf, natlen); 82 | } else if (natlen < opts.size) { 83 | buf = BN.pad(buf, natlen, opts.size); 84 | } 85 | } else { 86 | hex = this.toString(16, 2); 87 | buf = Buffer.from(hex, 'hex'); 88 | } 89 | 90 | if (typeof opts !== 'undefined' && opts.endian === 'little') { 91 | buf = reversebuf(buf); 92 | } 93 | 94 | return buf; 95 | }; 96 | 97 | BN.prototype.toSMBigEndian = function() { 98 | var buf; 99 | if (this.cmp(BN.Zero) === -1) { 100 | buf = this.neg().toBuffer(); 101 | if (buf[0] & 0x80) { 102 | buf = Buffer.concat([Buffer.from([0x80]), buf]); 103 | } else { 104 | buf[0] = buf[0] | 0x80; 105 | } 106 | } else { 107 | buf = this.toBuffer(); 108 | if (buf[0] & 0x80) { 109 | buf = Buffer.concat([Buffer.from([0x00]), buf]); 110 | } 111 | } 112 | 113 | if (buf.length === 1 & buf[0] === 0) { 114 | buf = Buffer.from([]); 115 | } 116 | return buf; 117 | }; 118 | 119 | BN.prototype.toSM = function(opts) { 120 | var endian = opts ? opts.endian : 'big'; 121 | var buf = this.toSMBigEndian(); 122 | 123 | if (endian === 'little') { 124 | buf = reversebuf(buf); 125 | } 126 | return buf; 127 | }; 128 | 129 | /** 130 | * Create a BN from a "ScriptNum": 131 | * This is analogous to the constructor for CScriptNum in bitcoind. Many ops in 132 | * bitcoind's script interpreter use CScriptNum, which is not really a proper 133 | * bignum. Instead, an error is thrown if trying to input a number bigger than 134 | * 4 bytes. We copy that behavior here. A third argument, `size`, is provided to 135 | * extend the hard limit of 4 bytes, as some usages require more than 4 bytes. 136 | */ 137 | BN.fromScriptNumBuffer = function(buf, fRequireMinimal, size) { 138 | var nMaxNumSize = size || 4; 139 | $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow')); 140 | if (fRequireMinimal && buf.length > 0) { 141 | // Check that the number is encoded with the minimum possible 142 | // number of bytes. 143 | // 144 | // If the most-significant-byte - excluding the sign bit - is zero 145 | // then we're not minimal. Note how this test also rejects the 146 | // negative-zero encoding, 0x80. 147 | if ((buf[buf.length - 1] & 0x7f) === 0) { 148 | // One exception: if there's more than one byte and the most 149 | // significant bit of the second-most-significant-byte is set 150 | // it would conflict with the sign bit. An example of this case 151 | // is +-255, which encode to 0xff00 and 0xff80 respectively. 152 | // (big-endian). 153 | if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) { 154 | throw new Error('non-minimally encoded script number'); 155 | } 156 | } 157 | } 158 | return BN.fromSM(buf, { 159 | endian: 'little' 160 | }); 161 | }; 162 | 163 | /** 164 | * The corollary to the above, with the notable exception that we do not throw 165 | * an error if the output is larger than four bytes. (Which can happen if 166 | * performing a numerical operation that results in an overflow to more than 4 167 | * bytes). 168 | */ 169 | BN.prototype.toScriptNumBuffer = function() { 170 | return this.toSM({ 171 | endian: 'little' 172 | }); 173 | }; 174 | 175 | BN.trim = function(buf, natlen) { 176 | return buf.slice(natlen - buf.length, buf.length); 177 | }; 178 | 179 | BN.pad = function(buf, natlen, size) { 180 | var rbuf = Buffer.alloc(size); 181 | for (var i = 0; i < buf.length; i++) { 182 | rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i]; 183 | } 184 | for (i = 0; i < size - natlen; i++) { 185 | rbuf[i] = 0; 186 | } 187 | return rbuf; 188 | }; 189 | 190 | module.exports = BN; 191 | -------------------------------------------------------------------------------- /lib/crypto/hash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var crypto = require('crypto'); 4 | var BufferUtil = require('../util/buffer'); 5 | var $ = require('../util/preconditions'); 6 | 7 | var Hash = module.exports; 8 | 9 | Hash.sha1 = function(buf) { 10 | $.checkArgument(BufferUtil.isBuffer(buf)); 11 | return crypto.createHash('sha1').update(buf).digest(); 12 | }; 13 | 14 | Hash.sha1.blocksize = 512; 15 | 16 | Hash.sha256 = function(buf) { 17 | $.checkArgument(BufferUtil.isBuffer(buf)); 18 | return crypto.createHash('sha256').update(buf).digest(); 19 | }; 20 | 21 | Hash.sha256.blocksize = 512; 22 | 23 | Hash.sha256sha256 = function(buf) { 24 | $.checkArgument(BufferUtil.isBuffer(buf)); 25 | return Hash.sha256(Hash.sha256(buf)); 26 | }; 27 | 28 | Hash.ripemd160 = function(buf) { 29 | $.checkArgument(BufferUtil.isBuffer(buf)); 30 | return crypto.createHash('ripemd160').update(buf).digest(); 31 | }; 32 | 33 | Hash.sha256ripemd160 = function(buf) { 34 | $.checkArgument(BufferUtil.isBuffer(buf)); 35 | return Hash.ripemd160(Hash.sha256(buf)); 36 | }; 37 | 38 | Hash.sha512 = function(buf) { 39 | $.checkArgument(BufferUtil.isBuffer(buf)); 40 | return crypto.createHash('sha512').update(buf).digest(); 41 | }; 42 | 43 | Hash.sha512.blocksize = 1024; 44 | 45 | Hash.hmac = function(hashf, data, key) { 46 | //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code 47 | //http://tools.ietf.org/html/rfc4868#section-2 48 | $.checkArgument(BufferUtil.isBuffer(data)); 49 | $.checkArgument(BufferUtil.isBuffer(key)); 50 | $.checkArgument(hashf.blocksize); 51 | 52 | var blocksize = hashf.blocksize / 8; 53 | 54 | if (key.length > blocksize) { 55 | key = hashf(key); 56 | } else if (key < blocksize) { 57 | var fill = Buffer.alloc(blocksize); 58 | fill.fill(0); 59 | key.copy(fill); 60 | key = fill; 61 | } 62 | 63 | var o_key = Buffer.alloc(blocksize); 64 | o_key.fill(0x5c); 65 | 66 | var i_key = Buffer.alloc(blocksize); 67 | i_key.fill(0x36); 68 | 69 | var o_key_pad = Buffer.alloc(blocksize); 70 | var i_key_pad = Buffer.alloc(blocksize); 71 | for (var i = 0; i < blocksize; i++) { 72 | o_key_pad[i] = o_key[i] ^ key[i]; 73 | i_key_pad[i] = i_key[i] ^ key[i]; 74 | } 75 | 76 | return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); 77 | }; 78 | 79 | Hash.sha256hmac = function(data, key) { 80 | return Hash.hmac(Hash.sha256, data, key); 81 | }; 82 | 83 | Hash.sha512hmac = function(data, key) { 84 | return Hash.hmac(Hash.sha512, data, key); 85 | }; 86 | -------------------------------------------------------------------------------- /lib/crypto/point.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BN = require('./bn'); 4 | var BufferUtil = require('../util/buffer'); 5 | 6 | var EC = require('elliptic').ec; 7 | var ec = new EC('secp256k1'); 8 | var ecPoint = ec.curve.point.bind(ec.curve); 9 | var ecPointFromX = ec.curve.pointFromX.bind(ec.curve); 10 | 11 | /** 12 | * 13 | * Instantiate a valid secp256k1 Point from the X and Y coordinates. 14 | * 15 | * @param {BN|String} x - The X coordinate 16 | * @param {BN|String} y - The Y coordinate 17 | * @link https://github.com/indutny/elliptic 18 | * @augments elliptic.curve.point 19 | * @throws {Error} A validation error if exists 20 | * @returns {Point} An instance of Point 21 | * @constructor 22 | */ 23 | var Point = function Point(x, y, isRed) { 24 | try { 25 | var point = ecPoint(x, y, isRed); 26 | } catch (e) { 27 | throw new Error('Invalid Point'); 28 | } 29 | point.validate(); 30 | return point; 31 | }; 32 | 33 | Point.prototype = Object.getPrototypeOf(ec.curve.point()); 34 | 35 | /** 36 | * 37 | * Instantiate a valid secp256k1 Point from only the X coordinate 38 | * 39 | * @param {boolean} odd - If the Y coordinate is odd 40 | * @param {BN|String} x - The X coordinate 41 | * @throws {Error} A validation error if exists 42 | * @returns {Point} An instance of Point 43 | */ 44 | Point.fromX = function fromX(odd, x){ 45 | try { 46 | var point = ecPointFromX(x, odd); 47 | } catch (e) { 48 | throw new Error('Invalid X'); 49 | } 50 | point.validate(); 51 | return point; 52 | }; 53 | 54 | /** 55 | * 56 | * Will return a secp256k1 ECDSA base point. 57 | * 58 | * @link https://en.bitcoin.it/wiki/Secp256k1 59 | * @returns {Point} An instance of the base point. 60 | */ 61 | Point.getG = function getG() { 62 | return ec.curve.g; 63 | }; 64 | 65 | /** 66 | * 67 | * Will return the max of range of valid private keys as governed by the secp256k1 ECDSA standard. 68 | * 69 | * @link https://en.bitcoin.it/wiki/Private_key#Range_of_valid_ECDSA_private_keys 70 | * @returns {BN} A BN instance of the number of points on the curve 71 | */ 72 | Point.getN = function getN() { 73 | return new BN(ec.curve.n.toArray()); 74 | }; 75 | 76 | Point.prototype._getX = Point.prototype.getX; 77 | 78 | /** 79 | * 80 | * Will return the X coordinate of the Point 81 | * 82 | * @returns {BN} A BN instance of the X coordinate 83 | */ 84 | Point.prototype.getX = function getX() { 85 | return new BN(this._getX().toArray()); 86 | }; 87 | 88 | Point.prototype._getY = Point.prototype.getY; 89 | 90 | /** 91 | * 92 | * Will return the Y coordinate of the Point 93 | * 94 | * @returns {BN} A BN instance of the Y coordinate 95 | */ 96 | Point.prototype.getY = function getY() { 97 | return new BN(this._getY().toArray()); 98 | }; 99 | 100 | /** 101 | * 102 | * Will determine if the point is valid 103 | * 104 | * @link https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf 105 | * @param {Point} An instance of Point 106 | * @throws {Error} A validation error if exists 107 | * @returns {Point} An instance of the same Point 108 | */ 109 | Point.prototype.validate = function validate() { 110 | 111 | if (this.isInfinity()){ 112 | throw new Error('Point cannot be equal to Infinity'); 113 | } 114 | 115 | var p2; 116 | try { 117 | p2 = ecPointFromX(this.getX(), this.getY().isOdd()); 118 | } catch (e) { 119 | throw new Error('Point does not lie on the curve'); 120 | } 121 | 122 | if (p2.y.cmp(this.y) !== 0) { 123 | throw new Error('Invalid y value for curve.'); 124 | } 125 | 126 | 127 | //todo: needs test case 128 | if (!(this.mul(Point.getN()).isInfinity())) { 129 | throw new Error('Point times N must be infinity'); 130 | } 131 | 132 | return this; 133 | 134 | }; 135 | 136 | Point.pointToCompressed = function pointToCompressed(point) { 137 | var xbuf = point.getX().toBuffer({size: 32}); 138 | var ybuf = point.getY().toBuffer({size: 32}); 139 | 140 | var prefix; 141 | var odd = ybuf[ybuf.length - 1] % 2; 142 | if (odd) { 143 | prefix = Buffer.from([0x03]); 144 | } else { 145 | prefix = Buffer.from([0x02]); 146 | } 147 | return BufferUtil.concat([prefix, xbuf]); 148 | }; 149 | 150 | module.exports = Point; 151 | -------------------------------------------------------------------------------- /lib/crypto/random.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function Random() { 4 | } 5 | 6 | /* secure random bytes that sometimes throws an error due to lack of entropy */ 7 | Random.getRandomBuffer = function(size) { 8 | if (process.browser) 9 | return Random.getRandomBufferBrowser(size); 10 | else 11 | return Random.getRandomBufferNode(size); 12 | }; 13 | 14 | Random.getRandomBufferNode = function(size) { 15 | var crypto = require('crypto'); 16 | return crypto.randomBytes(size); 17 | }; 18 | 19 | Random.getRandomBufferBrowser = function(size) { 20 | if (!window.crypto && !window.msCrypto) 21 | throw new Error('window.crypto not available'); 22 | 23 | if (window.crypto && window.crypto.getRandomValues) 24 | var crypto = window.crypto; 25 | else if (window.msCrypto && window.msCrypto.getRandomValues) //internet explorer 26 | var crypto = window.msCrypto; 27 | else 28 | throw new Error('window.crypto.getRandomValues not available'); 29 | 30 | var bbuf = new Uint8Array(size); 31 | crypto.getRandomValues(bbuf); 32 | var buf = Buffer.from(bbuf); 33 | 34 | return buf; 35 | }; 36 | 37 | /* insecure random bytes, but it never fails */ 38 | Random.getPseudoRandomBuffer = function(size) { 39 | var b32 = 0x100000000; 40 | var b = Buffer.alloc(size); 41 | var r; 42 | 43 | for (var i = 0; i <= size; i++) { 44 | var j = Math.floor(i / 4); 45 | var k = i - j * 4; 46 | if (k === 0) { 47 | r = Math.random() * b32; 48 | b[i] = r & 0xff; 49 | } else { 50 | b[i] = (r = r >>> 8) & 0xff; 51 | } 52 | } 53 | 54 | return b; 55 | }; 56 | 57 | module.exports = Random; 58 | -------------------------------------------------------------------------------- /lib/encoding/base58.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var bs58 = require('bs58'); 5 | var buffer = require('buffer'); 6 | 7 | var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split(''); 8 | 9 | var Base58 = function Base58(obj) { 10 | /* jshint maxcomplexity: 8 */ 11 | if (!(this instanceof Base58)) { 12 | return new Base58(obj); 13 | } 14 | if (Buffer.isBuffer(obj)) { 15 | var buf = obj; 16 | this.fromBuffer(buf); 17 | } else if (typeof obj === 'string') { 18 | var str = obj; 19 | this.fromString(str); 20 | } else if (obj) { 21 | this.set(obj); 22 | } 23 | }; 24 | 25 | Base58.validCharacters = function validCharacters(chars) { 26 | if (buffer.Buffer.isBuffer(chars)) { 27 | chars = chars.toString(); 28 | } 29 | return _.every(_.map(chars, function(char) { return _.includes(ALPHABET, char); })); 30 | }; 31 | 32 | Base58.prototype.set = function(obj) { 33 | this.buf = obj.buf || this.buf || undefined; 34 | return this; 35 | }; 36 | 37 | Base58.encode = function(buf) { 38 | if (!buffer.Buffer.isBuffer(buf)) { 39 | throw new Error('Input should be a buffer'); 40 | } 41 | return bs58.encode(buf); 42 | }; 43 | 44 | Base58.decode = function(str) { 45 | if (typeof str !== 'string') { 46 | throw new Error('Input should be a string'); 47 | } 48 | return Buffer.from(bs58.decode(str)); 49 | }; 50 | 51 | Base58.prototype.fromBuffer = function(buf) { 52 | this.buf = buf; 53 | return this; 54 | }; 55 | 56 | Base58.prototype.fromString = function(str) { 57 | var buf = Base58.decode(str); 58 | this.buf = buf; 59 | return this; 60 | }; 61 | 62 | Base58.prototype.toBuffer = function() { 63 | return this.buf; 64 | }; 65 | 66 | Base58.prototype.toString = function() { 67 | return Base58.encode(this.buf); 68 | }; 69 | 70 | module.exports = Base58; 71 | -------------------------------------------------------------------------------- /lib/encoding/base58check.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Base58 = require('./base58'); 5 | var buffer = require('buffer'); 6 | var sha256sha256 = require('../crypto/hash').sha256sha256; 7 | 8 | var Base58Check = function Base58Check(obj) { 9 | if (!(this instanceof Base58Check)) 10 | return new Base58Check(obj); 11 | if (Buffer.isBuffer(obj)) { 12 | var buf = obj; 13 | this.fromBuffer(buf); 14 | } else if (typeof obj === 'string') { 15 | var str = obj; 16 | this.fromString(str); 17 | } else if (obj) { 18 | this.set(obj); 19 | } 20 | }; 21 | 22 | Base58Check.prototype.set = function(obj) { 23 | this.buf = obj.buf || this.buf || undefined; 24 | return this; 25 | }; 26 | 27 | Base58Check.validChecksum = function validChecksum(data, checksum) { 28 | if (_.isString(data)) { 29 | data = new buffer.Buffer(Base58.decode(data)); 30 | } 31 | if (_.isString(checksum)) { 32 | checksum = new buffer.Buffer(Base58.decode(checksum)); 33 | } 34 | if (!checksum) { 35 | checksum = data.slice(-4); 36 | data = data.slice(0, -4); 37 | } 38 | return Base58Check.checksum(data).toString('hex') === checksum.toString('hex'); 39 | }; 40 | 41 | Base58Check.decode = function(s) { 42 | if (typeof s !== 'string') 43 | throw new Error('Input must be a string'); 44 | 45 | var buf = Buffer.from(Base58.decode(s)); 46 | 47 | if (buf.length < 4) 48 | throw new Error("Input string too short"); 49 | 50 | var data = buf.slice(0, -4); 51 | var csum = buf.slice(-4); 52 | 53 | var hash = sha256sha256(data); 54 | var hash4 = hash.slice(0, 4); 55 | 56 | if (csum.toString('hex') !== hash4.toString('hex')) 57 | throw new Error("Checksum mismatch"); 58 | 59 | return data; 60 | }; 61 | 62 | Base58Check.checksum = function(buffer) { 63 | return sha256sha256(buffer).slice(0, 4); 64 | }; 65 | 66 | Base58Check.encode = function(buf) { 67 | if (!Buffer.isBuffer(buf)) 68 | throw new Error('Input must be a buffer'); 69 | var checkedBuf = Buffer.alloc(buf.length + 4); 70 | var hash = Base58Check.checksum(buf); 71 | buf.copy(checkedBuf); 72 | hash.copy(checkedBuf, buf.length); 73 | return Base58.encode(checkedBuf); 74 | }; 75 | 76 | Base58Check.prototype.fromBuffer = function(buf) { 77 | this.buf = buf; 78 | return this; 79 | }; 80 | 81 | Base58Check.prototype.fromString = function(str) { 82 | var buf = Base58Check.decode(str); 83 | this.buf = buf; 84 | return this; 85 | }; 86 | 87 | Base58Check.prototype.toBuffer = function() { 88 | return this.buf; 89 | }; 90 | 91 | Base58Check.prototype.toString = function() { 92 | return Base58Check.encode(this.buf); 93 | }; 94 | 95 | module.exports = Base58Check; 96 | -------------------------------------------------------------------------------- /lib/encoding/bufferreader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var $ = require('../util/preconditions'); 5 | var BufferUtil = require('../util/buffer'); 6 | var BN = require('../crypto/bn'); 7 | 8 | var BufferReader = function BufferReader(buf) { 9 | if (!(this instanceof BufferReader)) { 10 | return new BufferReader(buf); 11 | } 12 | if (_.isUndefined(buf)) { 13 | return; 14 | } 15 | if (Buffer.isBuffer(buf)) { 16 | this.set({ 17 | buf: buf 18 | }); 19 | } else if (_.isString(buf)) { 20 | this.set({ 21 | buf: Buffer.from(buf, 'hex'), 22 | }); 23 | } else if (_.isObject(buf)) { 24 | var obj = buf; 25 | this.set(obj); 26 | } else { 27 | throw new TypeError('Unrecognized argument for BufferReader'); 28 | } 29 | }; 30 | 31 | BufferReader.prototype.set = function(obj) { 32 | this.buf = obj.buf || this.buf || undefined; 33 | this.pos = obj.pos || this.pos || 0; 34 | return this; 35 | }; 36 | 37 | BufferReader.prototype.eof = function() { 38 | return this.pos >= this.buf.length; 39 | }; 40 | 41 | BufferReader.prototype.finished = BufferReader.prototype.eof; 42 | 43 | BufferReader.prototype.read = function(len) { 44 | $.checkArgument(!_.isUndefined(len), 'Must specify a length'); 45 | var buf = this.buf.slice(this.pos, this.pos + len); 46 | this.pos = this.pos + len; 47 | return buf; 48 | }; 49 | 50 | BufferReader.prototype.readAll = function() { 51 | var buf = this.buf.slice(this.pos, this.buf.length); 52 | this.pos = this.buf.length; 53 | return buf; 54 | }; 55 | 56 | BufferReader.prototype.readUInt8 = function() { 57 | var val = this.buf.readUInt8(this.pos); 58 | this.pos = this.pos + 1; 59 | return val; 60 | }; 61 | 62 | BufferReader.prototype.readUInt16BE = function() { 63 | var val = this.buf.readUInt16BE(this.pos); 64 | this.pos = this.pos + 2; 65 | return val; 66 | }; 67 | 68 | BufferReader.prototype.readUInt16LE = function() { 69 | var val = this.buf.readUInt16LE(this.pos); 70 | this.pos = this.pos + 2; 71 | return val; 72 | }; 73 | 74 | BufferReader.prototype.readUInt32BE = function() { 75 | var val = this.buf.readUInt32BE(this.pos); 76 | this.pos = this.pos + 4; 77 | return val; 78 | }; 79 | 80 | BufferReader.prototype.readUInt32LE = function() { 81 | var val = this.buf.readUInt32LE(this.pos); 82 | this.pos = this.pos + 4; 83 | return val; 84 | }; 85 | 86 | BufferReader.prototype.readInt32LE = function() { 87 | var val = this.buf.readInt32LE(this.pos); 88 | this.pos = this.pos + 4; 89 | return val; 90 | }; 91 | 92 | BufferReader.prototype.readUInt64BEBN = function() { 93 | var buf = this.buf.slice(this.pos, this.pos + 8); 94 | var bn = BN.fromBuffer(buf); 95 | this.pos = this.pos + 8; 96 | return bn; 97 | }; 98 | 99 | BufferReader.prototype.readUInt64LEBN = function() { 100 | var second = this.buf.readUInt32LE(this.pos); 101 | var first = this.buf.readUInt32LE(this.pos + 4); 102 | var combined = (first * 0x100000000) + second; 103 | // Instantiating an instance of BN with a number is faster than with an 104 | // array or string. However, the maximum safe number for a double precision 105 | // floating point is 2 ^ 52 - 1 (0x1fffffffffffff), thus we can safely use 106 | // non-floating point numbers less than this amount (52 bits). And in the case 107 | // that the number is larger, we can instatiate an instance of BN by passing 108 | // an array from the buffer (slower) and specifying the endianness. 109 | var bn; 110 | if (combined <= 0x1fffffffffffff) { 111 | bn = new BN(combined); 112 | } else { 113 | var data = Array.prototype.slice.call(this.buf, this.pos, this.pos + 8); 114 | bn = new BN(data, 10, 'le'); 115 | } 116 | this.pos = this.pos + 8; 117 | return bn; 118 | }; 119 | 120 | BufferReader.prototype.readVarintNum = function() { 121 | var first = this.readUInt8(); 122 | switch (first) { 123 | case 0xFD: 124 | return this.readUInt16LE(); 125 | case 0xFE: 126 | return this.readUInt32LE(); 127 | case 0xFF: 128 | var bn = this.readUInt64LEBN(); 129 | var n = bn.toNumber(); 130 | if (n <= Math.pow(2, 53)) { 131 | return n; 132 | } else { 133 | throw new Error('number too large to retain precision - use readVarintBN'); 134 | } 135 | break; 136 | default: 137 | return first; 138 | } 139 | }; 140 | 141 | /** 142 | * reads a length prepended buffer 143 | */ 144 | BufferReader.prototype.readVarLengthBuffer = function() { 145 | var len = this.readVarintNum(); 146 | var buf = this.read(len); 147 | $.checkState(buf.length === len, 'Invalid length while reading varlength buffer. ' + 148 | 'Expected to read: ' + len + ' and read ' + buf.length); 149 | return buf; 150 | }; 151 | 152 | BufferReader.prototype.readVarintBuf = function() { 153 | var first = this.buf.readUInt8(this.pos); 154 | switch (first) { 155 | case 0xFD: 156 | return this.read(1 + 2); 157 | case 0xFE: 158 | return this.read(1 + 4); 159 | case 0xFF: 160 | return this.read(1 + 8); 161 | default: 162 | return this.read(1); 163 | } 164 | }; 165 | 166 | BufferReader.prototype.readVarintBN = function() { 167 | var first = this.readUInt8(); 168 | switch (first) { 169 | case 0xFD: 170 | return new BN(this.readUInt16LE()); 171 | case 0xFE: 172 | return new BN(this.readUInt32LE()); 173 | case 0xFF: 174 | return this.readUInt64LEBN(); 175 | default: 176 | return new BN(first); 177 | } 178 | }; 179 | 180 | BufferReader.prototype.reverse = function() { 181 | var buf = Buffer.alloc(this.buf.length); 182 | for (var i = 0; i < buf.length; i++) { 183 | buf[i] = this.buf[this.buf.length - 1 - i]; 184 | } 185 | this.buf = buf; 186 | return this; 187 | }; 188 | 189 | BufferReader.prototype.readReverse = function(len) { 190 | if (_.isUndefined(len)) { 191 | len = this.buf.length; 192 | } 193 | var buf = this.buf.slice(this.pos, this.pos + len); 194 | this.pos = this.pos + len; 195 | return BufferUtil.reverse(buf); 196 | }; 197 | 198 | module.exports = BufferReader; 199 | -------------------------------------------------------------------------------- /lib/encoding/bufferwriter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var bufferUtil = require('../util/buffer'); 4 | var assert = require('assert'); 5 | 6 | var BufferWriter = function BufferWriter(obj) { 7 | if (!(this instanceof BufferWriter)) 8 | return new BufferWriter(obj); 9 | this.bufLen = 0; 10 | if (obj) 11 | this.set(obj); 12 | else 13 | this.bufs = []; 14 | }; 15 | 16 | BufferWriter.prototype.set = function(obj) { 17 | this.bufs = obj.bufs || this.bufs || []; 18 | this.bufLen = this.bufs.reduce(function(prev, buf){ return prev + buf.length; }, 0); 19 | return this; 20 | }; 21 | 22 | BufferWriter.prototype.toBuffer = function() { 23 | return this.concat(); 24 | }; 25 | 26 | BufferWriter.prototype.concat = function() { 27 | return Buffer.concat(this.bufs, this.bufLen); 28 | }; 29 | 30 | BufferWriter.prototype.write = function(buf) { 31 | assert(bufferUtil.isBuffer(buf)); 32 | this.bufs.push(buf); 33 | this.bufLen += buf.length; 34 | return this; 35 | }; 36 | 37 | BufferWriter.prototype.writeReverse = function(buf) { 38 | assert(bufferUtil.isBuffer(buf)); 39 | this.bufs.push(bufferUtil.reverse(buf)); 40 | this.bufLen += buf.length; 41 | return this; 42 | }; 43 | 44 | BufferWriter.prototype.writeUInt8 = function(n) { 45 | var buf = Buffer.alloc(1); 46 | buf.writeUInt8(n, 0); 47 | this.write(buf); 48 | return this; 49 | }; 50 | 51 | BufferWriter.prototype.writeUInt16BE = function(n) { 52 | var buf = Buffer.alloc(2); 53 | buf.writeUInt16BE(n, 0); 54 | this.write(buf); 55 | return this; 56 | }; 57 | 58 | BufferWriter.prototype.writeUInt16LE = function(n) { 59 | var buf = Buffer.alloc(2); 60 | buf.writeUInt16LE(n, 0); 61 | this.write(buf); 62 | return this; 63 | }; 64 | 65 | BufferWriter.prototype.writeUInt32BE = function(n) { 66 | var buf = Buffer.alloc(4); 67 | buf.writeUInt32BE(n, 0); 68 | this.write(buf); 69 | return this; 70 | }; 71 | 72 | BufferWriter.prototype.writeInt32LE = function(n) { 73 | var buf = Buffer.alloc(4); 74 | buf.writeInt32LE(n, 0); 75 | this.write(buf); 76 | return this; 77 | }; 78 | 79 | BufferWriter.prototype.writeUInt32LE = function(n) { 80 | var buf = Buffer.alloc(4); 81 | buf.writeUInt32LE(n, 0); 82 | this.write(buf); 83 | return this; 84 | }; 85 | 86 | BufferWriter.prototype.writeUInt64BEBN = function(bn) { 87 | var buf = bn.toBuffer({size: 8}); 88 | this.write(buf); 89 | return this; 90 | }; 91 | 92 | BufferWriter.prototype.writeUInt64LEBN = function(bn) { 93 | var buf = bn.toBuffer({size: 8}); 94 | this.writeReverse(buf); 95 | return this; 96 | }; 97 | 98 | BufferWriter.prototype.writeVarintNum = function(n) { 99 | var buf = BufferWriter.varintBufNum(n); 100 | this.write(buf); 101 | return this; 102 | }; 103 | 104 | BufferWriter.prototype.writeVarintBN = function(bn) { 105 | var buf = BufferWriter.varintBufBN(bn); 106 | this.write(buf); 107 | return this; 108 | }; 109 | 110 | BufferWriter.varintBufNum = function(n) { 111 | var buf = undefined; 112 | if (n < 253) { 113 | buf = Buffer.alloc(1); 114 | buf.writeUInt8(n, 0); 115 | } else if (n < 0x10000) { 116 | buf = Buffer.alloc(1 + 2); 117 | buf.writeUInt8(253, 0); 118 | buf.writeUInt16LE(n, 1); 119 | } else if (n < 0x100000000) { 120 | buf = Buffer.alloc(1 + 4); 121 | buf.writeUInt8(254, 0); 122 | buf.writeUInt32LE(n, 1); 123 | } else { 124 | buf = Buffer.alloc(1 + 8); 125 | buf.writeUInt8(255, 0); 126 | buf.writeInt32LE(n & -1, 1); 127 | buf.writeUInt32LE(Math.floor(n / 0x100000000), 5); 128 | } 129 | return buf; 130 | }; 131 | 132 | BufferWriter.varintBufBN = function(bn) { 133 | var buf = undefined; 134 | var n = bn.toNumber(); 135 | if (n < 253) { 136 | buf = Buffer.alloc(1); 137 | buf.writeUInt8(n, 0); 138 | } else if (n < 0x10000) { 139 | buf = Buffer.alloc(1 + 2); 140 | buf.writeUInt8(253, 0); 141 | buf.writeUInt16LE(n, 1); 142 | } else if (n < 0x100000000) { 143 | buf = Buffer.alloc(1 + 4); 144 | buf.writeUInt8(254, 0); 145 | buf.writeUInt32LE(n, 1); 146 | } else { 147 | var bw = new BufferWriter(); 148 | bw.writeUInt8(255); 149 | bw.writeUInt64LEBN(bn); 150 | var buf = bw.concat(); 151 | } 152 | return buf; 153 | }; 154 | 155 | module.exports = BufferWriter; 156 | -------------------------------------------------------------------------------- /lib/encoding/varint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BufferWriter = require('./bufferwriter'); 4 | var BufferReader = require('./bufferreader'); 5 | var BN = require('../crypto/bn'); 6 | 7 | var Varint = function Varint(buf) { 8 | if (!(this instanceof Varint)) 9 | return new Varint(buf); 10 | if (Buffer.isBuffer(buf)) { 11 | this.buf = buf; 12 | } else if (typeof buf === 'number') { 13 | var num = buf; 14 | this.fromNumber(num); 15 | } else if (buf instanceof BN) { 16 | var bn = buf; 17 | this.fromBN(bn); 18 | } else if (buf) { 19 | var obj = buf; 20 | this.set(obj); 21 | } 22 | }; 23 | 24 | Varint.prototype.set = function(obj) { 25 | this.buf = obj.buf || this.buf; 26 | return this; 27 | }; 28 | 29 | Varint.prototype.fromString = function(str) { 30 | this.set({ 31 | buf: Buffer.from(str, 'hex') 32 | }); 33 | return this; 34 | }; 35 | 36 | Varint.prototype.toString = function() { 37 | return this.buf.toString('hex'); 38 | }; 39 | 40 | Varint.prototype.fromBuffer = function(buf) { 41 | this.buf = buf; 42 | return this; 43 | }; 44 | 45 | Varint.prototype.fromBufferReader = function(br) { 46 | this.buf = br.readVarintBuf(); 47 | return this; 48 | }; 49 | 50 | Varint.prototype.fromBN = function(bn) { 51 | this.buf = BufferWriter().writeVarintBN(bn).concat(); 52 | return this; 53 | }; 54 | 55 | Varint.prototype.fromNumber = function(num) { 56 | this.buf = BufferWriter().writeVarintNum(num).concat(); 57 | return this; 58 | }; 59 | 60 | Varint.prototype.toBuffer = function() { 61 | return this.buf; 62 | }; 63 | 64 | Varint.prototype.toBN = function() { 65 | return BufferReader(this.buf).readVarintBN(); 66 | }; 67 | 68 | Varint.prototype.toNumber = function() { 69 | return BufferReader(this.buf).readVarintNum(); 70 | }; 71 | 72 | module.exports = Varint; 73 | -------------------------------------------------------------------------------- /lib/errors/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | 5 | function format(message, args) { 6 | return message 7 | .replace('{0}', args[0]) 8 | .replace('{1}', args[1]) 9 | .replace('{2}', args[2]); 10 | } 11 | var traverseNode = function(parent, errorDefinition) { 12 | var NodeError = function() { 13 | if (_.isString(errorDefinition.message)) { 14 | this.message = format(errorDefinition.message, arguments); 15 | } else if (_.isFunction(errorDefinition.message)) { 16 | this.message = errorDefinition.message.apply(null, arguments); 17 | } else { 18 | throw new Error('Invalid error definition for ' + errorDefinition.name); 19 | } 20 | this.stack = this.message + '\n' + (new Error()).stack; 21 | }; 22 | NodeError.prototype = Object.create(parent.prototype); 23 | NodeError.prototype.name = parent.prototype.name + errorDefinition.name; 24 | parent[errorDefinition.name] = NodeError; 25 | if (errorDefinition.errors) { 26 | childDefinitions(NodeError, errorDefinition.errors); 27 | } 28 | return NodeError; 29 | }; 30 | 31 | /* jshint latedef: false */ 32 | var childDefinitions = function(parent, childDefinitions) { 33 | _.each(childDefinitions, function(childDefinition) { 34 | traverseNode(parent, childDefinition); 35 | }); 36 | }; 37 | /* jshint latedef: true */ 38 | 39 | var traverseRoot = function(parent, errorsDefinition) { 40 | childDefinitions(parent, errorsDefinition); 41 | return parent; 42 | }; 43 | 44 | 45 | var bitcore = {}; 46 | bitcore.Error = function() { 47 | this.message = 'Internal error'; 48 | this.stack = this.message + '\n' + (new Error()).stack; 49 | }; 50 | bitcore.Error.prototype = Object.create(Error.prototype); 51 | bitcore.Error.prototype.name = 'bitcore.Error'; 52 | 53 | 54 | var data = require('./spec'); 55 | traverseRoot(bitcore.Error, data); 56 | 57 | module.exports = bitcore.Error; 58 | 59 | module.exports.extend = function(spec) { 60 | return traverseNode(bitcore.Error, spec); 61 | }; 62 | -------------------------------------------------------------------------------- /lib/errors/spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var docsURL = 'http://bitcore.io/'; 4 | 5 | module.exports = [{ 6 | name: 'InvalidB58Char', 7 | message: 'Invalid Base58 character: {0} in {1}' 8 | }, { 9 | name: 'InvalidB58Checksum', 10 | message: 'Invalid Base58 checksum for {0}' 11 | }, { 12 | name: 'InvalidNetwork', 13 | message: 'Invalid version for network: got {0}' 14 | }, { 15 | name: 'InvalidState', 16 | message: 'Invalid state: {0}' 17 | }, { 18 | name: 'NotImplemented', 19 | message: 'Function {0} was not implemented yet' 20 | }, { 21 | name: 'InvalidNetworkArgument', 22 | message: 'Invalid network: must be "livenet" or "testnet", got {0}' 23 | }, { 24 | name: 'InvalidArgument', 25 | message: function() { 26 | return 'Invalid Argument' + (arguments[0] ? (': ' + arguments[0]) : '') + 27 | (arguments[1] ? (' Documentation: ' + docsURL + arguments[1]) : ''); 28 | } 29 | }, { 30 | name: 'AbstractMethodInvoked', 31 | message: 'Abstract Method Invocation: {0}' 32 | }, { 33 | name: 'InvalidArgumentType', 34 | message: function() { 35 | return 'Invalid Argument for ' + arguments[2] + ', expected ' + arguments[1] + ' but got ' + typeof arguments[0]; 36 | } 37 | }, { 38 | name: 'Unit', 39 | message: 'Internal Error on Unit {0}', 40 | errors: [{ 41 | 'name': 'UnknownCode', 42 | 'message': 'Unrecognized unit code: {0}' 43 | }, { 44 | 'name': 'InvalidRate', 45 | 'message': 'Invalid exchange rate: {0}' 46 | }] 47 | }, { 48 | name: 'MerkleBlock', 49 | message: 'Internal Error on MerkleBlock {0}', 50 | errors: [{ 51 | 'name': 'InvalidMerkleTree', 52 | 'message': 'This MerkleBlock contain an invalid Merkle Tree' 53 | }] 54 | }, { 55 | name: 'Transaction', 56 | message: 'Internal Error on Transaction {0}', 57 | errors: [{ 58 | name: 'Input', 59 | message: 'Internal Error on Input {0}', 60 | errors: [{ 61 | name: 'MissingScript', 62 | message: 'Need a script to create an input' 63 | }, { 64 | name: 'UnsupportedScript', 65 | message: 'Unsupported input script type: {0}' 66 | }, { 67 | name: 'MissingPreviousOutput', 68 | message: 'No previous output information.' 69 | }] 70 | }, { 71 | name: 'NeedMoreInfo', 72 | message: '{0}' 73 | }, { 74 | name: 'InvalidSorting', 75 | message: 'The sorting function provided did not return the change output as one of the array elements' 76 | }, { 77 | name: 'InvalidOutputAmountSum', 78 | message: '{0}' 79 | }, { 80 | name: 'MissingSignatures', 81 | message: 'Some inputs have not been fully signed' 82 | }, { 83 | name: 'InvalidIndex', 84 | message: 'Invalid index: {0} is not between 0, {1}' 85 | }, { 86 | name: 'UnableToVerifySignature', 87 | message: 'Unable to verify signature: {0}' 88 | }, { 89 | name: 'DustOutputs', 90 | message: 'Dust amount detected in one output' 91 | }, { 92 | name: 'InvalidSatoshis', 93 | message: 'Output satoshis are invalid', 94 | }, { 95 | name: 'FeeError', 96 | message: 'Internal Error on Fee {0}', 97 | errors: [{ 98 | name: 'TooSmall', 99 | message: 'Fee is too small: {0}', 100 | }, { 101 | name: 'TooLarge', 102 | message: 'Fee is too large: {0}', 103 | }, { 104 | name: 'Different', 105 | message: 'Unspent value is different from specified fee: {0}', 106 | }] 107 | }, { 108 | name: 'ChangeAddressMissing', 109 | message: 'Change address is missing' 110 | }, { 111 | name: 'BlockHeightTooHigh', 112 | message: 'Block Height can be at most 2^32 -1' 113 | }, { 114 | name: 'NLockTimeOutOfRange', 115 | message: 'Block Height can only be between 0 and 499 999 999' 116 | }, { 117 | name: 'LockTimeTooEarly', 118 | message: 'Lock Time can\'t be earlier than UNIX date 500 000 000' 119 | }] 120 | }, { 121 | name: 'Script', 122 | message: 'Internal Error on Script {0}', 123 | errors: [{ 124 | name: 'UnrecognizedAddress', 125 | message: 'Expected argument {0} to be an address' 126 | }, { 127 | name: 'CantDeriveAddress', 128 | message: 'Can\'t derive address associated with script {0}, needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out.' 129 | }, { 130 | name: 'InvalidBuffer', 131 | message: 'Invalid script buffer: can\'t parse valid script from given buffer {0}' 132 | }] 133 | }, { 134 | name: 'HDPrivateKey', 135 | message: 'Internal Error on HDPrivateKey {0}', 136 | errors: [{ 137 | name: 'InvalidDerivationArgument', 138 | message: 'Invalid derivation argument {0}, expected string, or number and boolean' 139 | }, { 140 | name: 'InvalidEntropyArgument', 141 | message: 'Invalid entropy: must be an hexa string or binary buffer, got {0}', 142 | errors: [{ 143 | name: 'TooMuchEntropy', 144 | message: 'Invalid entropy: more than 512 bits is non standard, got "{0}"' 145 | }, { 146 | name: 'NotEnoughEntropy', 147 | message: 'Invalid entropy: at least 128 bits needed, got "{0}"' 148 | }] 149 | }, { 150 | name: 'InvalidLength', 151 | message: 'Invalid length for xprivkey string in {0}' 152 | }, { 153 | name: 'InvalidPath', 154 | message: 'Invalid derivation path: {0}' 155 | }, { 156 | name: 'UnrecognizedArgument', 157 | message: 'Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"' 158 | }] 159 | }, { 160 | name: 'HDPublicKey', 161 | message: 'Internal Error on HDPublicKey {0}', 162 | errors: [{ 163 | name: 'ArgumentIsPrivateExtended', 164 | message: 'Argument is an extended private key: {0}' 165 | }, { 166 | name: 'InvalidDerivationArgument', 167 | message: 'Invalid derivation argument: got {0}' 168 | }, { 169 | name: 'InvalidLength', 170 | message: 'Invalid length for xpubkey: got "{0}"' 171 | }, { 172 | name: 'InvalidPath', 173 | message: 'Invalid derivation path, it should look like: "m/1/100", got "{0}"' 174 | }, { 175 | name: 'InvalidIndexCantDeriveHardened', 176 | message: 'Invalid argument: creating a hardened path requires an HDPrivateKey' 177 | }, { 178 | name: 'MustSupplyArgument', 179 | message: 'Must supply an argument to create a HDPublicKey' 180 | }, { 181 | name: 'UnrecognizedArgument', 182 | message: 'Invalid argument for creation, must be string, json, buffer, or object' 183 | }] 184 | }]; 185 | -------------------------------------------------------------------------------- /lib/opcode.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var $ = require('./util/preconditions'); 5 | var BufferUtil = require('./util/buffer'); 6 | var JSUtil = require('./util/js'); 7 | 8 | function Opcode(num) { 9 | if (!(this instanceof Opcode)) { 10 | return new Opcode(num); 11 | } 12 | 13 | var value; 14 | 15 | if (_.isNumber(num)) { 16 | value = num; 17 | } else if (_.isString(num)) { 18 | value = Opcode.map[num]; 19 | } else { 20 | throw new TypeError('Unrecognized num type: "' + typeof(num) + '" for Opcode'); 21 | } 22 | 23 | JSUtil.defineImmutable(this, { 24 | num: value 25 | }); 26 | 27 | return this; 28 | } 29 | 30 | Opcode.fromBuffer = function(buf) { 31 | $.checkArgument(BufferUtil.isBuffer(buf)); 32 | return new Opcode(Number('0x' + buf.toString('hex'))); 33 | }; 34 | 35 | Opcode.fromNumber = function(num) { 36 | $.checkArgument(_.isNumber(num)); 37 | return new Opcode(num); 38 | }; 39 | 40 | Opcode.fromString = function(str) { 41 | $.checkArgument(_.isString(str)); 42 | var value = Opcode.map[str]; 43 | if (typeof value === 'undefined') { 44 | throw new TypeError('Invalid opcodestr'); 45 | } 46 | return new Opcode(value); 47 | }; 48 | 49 | Opcode.prototype.toHex = function() { 50 | return this.num.toString(16); 51 | }; 52 | 53 | Opcode.prototype.toBuffer = function() { 54 | return Buffer.from(this.toHex(), 'hex'); 55 | }; 56 | 57 | Opcode.prototype.toNumber = function() { 58 | return this.num; 59 | }; 60 | 61 | Opcode.prototype.toString = function() { 62 | var str = Opcode.reverseMap[this.num]; 63 | if (typeof str === 'undefined') { 64 | throw new Error('Opcode does not have a string representation'); 65 | } 66 | return str; 67 | }; 68 | 69 | Opcode.smallInt = function(n) { 70 | $.checkArgument(_.isNumber(n), 'Invalid Argument: n should be number'); 71 | $.checkArgument(n >= 0 && n <= 16, 'Invalid Argument: n must be between 0 and 16'); 72 | if (n === 0) { 73 | return Opcode('OP_0'); 74 | } 75 | return new Opcode(Opcode.map.OP_1 + n - 1); 76 | }; 77 | 78 | Opcode.map = { 79 | // push value 80 | OP_FALSE: 0, 81 | OP_0: 0, 82 | OP_PUSHDATA1: 76, 83 | OP_PUSHDATA2: 77, 84 | OP_PUSHDATA4: 78, 85 | OP_1NEGATE: 79, 86 | OP_RESERVED: 80, 87 | OP_TRUE: 81, 88 | OP_1: 81, 89 | OP_2: 82, 90 | OP_3: 83, 91 | OP_4: 84, 92 | OP_5: 85, 93 | OP_6: 86, 94 | OP_7: 87, 95 | OP_8: 88, 96 | OP_9: 89, 97 | OP_10: 90, 98 | OP_11: 91, 99 | OP_12: 92, 100 | OP_13: 93, 101 | OP_14: 94, 102 | OP_15: 95, 103 | OP_16: 96, 104 | 105 | // control 106 | OP_NOP: 97, 107 | OP_VER: 98, 108 | OP_IF: 99, 109 | OP_NOTIF: 100, 110 | OP_VERIF: 101, 111 | OP_VERNOTIF: 102, 112 | OP_ELSE: 103, 113 | OP_ENDIF: 104, 114 | OP_VERIFY: 105, 115 | OP_RETURN: 106, 116 | 117 | // stack ops 118 | OP_TOALTSTACK: 107, 119 | OP_FROMALTSTACK: 108, 120 | OP_2DROP: 109, 121 | OP_2DUP: 110, 122 | OP_3DUP: 111, 123 | OP_2OVER: 112, 124 | OP_2ROT: 113, 125 | OP_2SWAP: 114, 126 | OP_IFDUP: 115, 127 | OP_DEPTH: 116, 128 | OP_DROP: 117, 129 | OP_DUP: 118, 130 | OP_NIP: 119, 131 | OP_OVER: 120, 132 | OP_PICK: 121, 133 | OP_ROLL: 122, 134 | OP_ROT: 123, 135 | OP_SWAP: 124, 136 | OP_TUCK: 125, 137 | 138 | // splice ops 139 | OP_CAT: 126, 140 | OP_SUBSTR: 127, 141 | OP_LEFT: 128, 142 | OP_RIGHT: 129, 143 | OP_SIZE: 130, 144 | 145 | // bit logic 146 | OP_INVERT: 131, 147 | OP_AND: 132, 148 | OP_OR: 133, 149 | OP_XOR: 134, 150 | OP_EQUAL: 135, 151 | OP_EQUALVERIFY: 136, 152 | OP_RESERVED1: 137, 153 | OP_RESERVED2: 138, 154 | 155 | // numeric 156 | OP_1ADD: 139, 157 | OP_1SUB: 140, 158 | OP_2MUL: 141, 159 | OP_2DIV: 142, 160 | OP_NEGATE: 143, 161 | OP_ABS: 144, 162 | OP_NOT: 145, 163 | OP_0NOTEQUAL: 146, 164 | 165 | OP_ADD: 147, 166 | OP_SUB: 148, 167 | OP_MUL: 149, 168 | OP_DIV: 150, 169 | OP_MOD: 151, 170 | OP_LSHIFT: 152, 171 | OP_RSHIFT: 153, 172 | 173 | OP_BOOLAND: 154, 174 | OP_BOOLOR: 155, 175 | OP_NUMEQUAL: 156, 176 | OP_NUMEQUALVERIFY: 157, 177 | OP_NUMNOTEQUAL: 158, 178 | OP_LESSTHAN: 159, 179 | OP_GREATERTHAN: 160, 180 | OP_LESSTHANOREQUAL: 161, 181 | OP_GREATERTHANOREQUAL: 162, 182 | OP_MIN: 163, 183 | OP_MAX: 164, 184 | 185 | OP_WITHIN: 165, 186 | 187 | // crypto 188 | OP_RIPEMD160: 166, 189 | OP_SHA1: 167, 190 | OP_SHA256: 168, 191 | OP_HASH160: 169, 192 | OP_HASH256: 170, 193 | OP_CODESEPARATOR: 171, 194 | OP_CHECKSIG: 172, 195 | OP_CHECKSIGVERIFY: 173, 196 | OP_CHECKMULTISIG: 174, 197 | OP_CHECKMULTISIGVERIFY: 175, 198 | 199 | OP_CHECKLOCKTIMEVERIFY: 177, 200 | OP_CHECKSEQUENCEVERIFY: 178, 201 | 202 | // expansion 203 | OP_NOP1: 176, 204 | OP_NOP2: 177, 205 | OP_NOP3: 178, 206 | OP_NOP4: 179, 207 | OP_NOP5: 180, 208 | OP_NOP6: 181, 209 | OP_NOP7: 182, 210 | OP_NOP8: 183, 211 | OP_NOP9: 184, 212 | OP_NOP10: 185, 213 | 214 | // template matching params 215 | OP_PUBKEYHASH: 253, 216 | OP_PUBKEY: 254, 217 | OP_INVALIDOPCODE: 255 218 | }; 219 | 220 | Opcode.reverseMap = []; 221 | 222 | for (var k in Opcode.map) { 223 | Opcode.reverseMap[Opcode.map[k]] = k; 224 | } 225 | 226 | // Easier access to opcodes 227 | _.extend(Opcode, Opcode.map); 228 | 229 | /** 230 | * @returns true if opcode is one of OP_0, OP_1, ..., OP_16 231 | */ 232 | Opcode.isSmallIntOp = function(opcode) { 233 | if (opcode instanceof Opcode) { 234 | opcode = opcode.toNumber(); 235 | } 236 | return ((opcode === Opcode.map.OP_0) || 237 | ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))); 238 | }; 239 | 240 | /** 241 | * Will return a string formatted for the console 242 | * 243 | * @returns {string} Script opcode 244 | */ 245 | Opcode.prototype.inspect = function() { 246 | return ''; 247 | }; 248 | 249 | module.exports = Opcode; 250 | -------------------------------------------------------------------------------- /lib/script/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./script'); 2 | 3 | module.exports.Interpreter = require('./interpreter'); 4 | -------------------------------------------------------------------------------- /lib/transaction/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./transaction'); 2 | 3 | module.exports.Input = require('./input'); 4 | module.exports.Output = require('./output'); 5 | module.exports.UnspentOutput = require('./unspentoutput'); 6 | module.exports.Signature = require('./signature'); 7 | module.exports.Sighash = require('./sighash'); 8 | module.exports.SighashWitness = require('./sighashwitness'); 9 | -------------------------------------------------------------------------------- /lib/transaction/input/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./input'); 2 | 3 | module.exports.PublicKey = require('./publickey'); 4 | module.exports.PublicKeyHash = require('./publickeyhash'); 5 | module.exports.MultiSig = require('./multisig.js'); 6 | module.exports.MultiSigScriptHash = require('./multisigscripthash.js'); 7 | -------------------------------------------------------------------------------- /lib/transaction/input/publickey.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var inherits = require('inherits'); 4 | 5 | var $ = require('../../util/preconditions'); 6 | var BufferUtil = require('../../util/buffer'); 7 | 8 | var Input = require('./input'); 9 | var Output = require('../output'); 10 | var Sighash = require('../sighash'); 11 | var Script = require('../../script'); 12 | var Signature = require('../../crypto/signature'); 13 | var TransactionSignature = require('../signature'); 14 | 15 | /** 16 | * Represents a special kind of input of PayToPublicKey kind. 17 | * @constructor 18 | */ 19 | function PublicKeyInput() { 20 | Input.apply(this, arguments); 21 | } 22 | inherits(PublicKeyInput, Input); 23 | 24 | /** 25 | * @param {Transaction} transaction - the transaction to be signed 26 | * @param {PrivateKey} privateKey - the private key with which to sign the transaction 27 | * @param {number} index - the index of the input in the transaction input vector 28 | * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL 29 | * @return {Array} of objects that can be 30 | */ 31 | PublicKeyInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { 32 | $.checkState(this.output instanceof Output); 33 | sigtype = sigtype || Signature.SIGHASH_ALL; 34 | var publicKey = privateKey.toPublicKey(); 35 | if (publicKey.toString() === this.output.script.getPublicKey().toString('hex')) { 36 | return [new TransactionSignature({ 37 | publicKey: publicKey, 38 | prevTxId: this.prevTxId, 39 | outputIndex: this.outputIndex, 40 | inputIndex: index, 41 | signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), 42 | sigtype: sigtype 43 | })]; 44 | } 45 | return []; 46 | }; 47 | 48 | /** 49 | * Add the provided signature 50 | * 51 | * @param {Object} signature 52 | * @param {PublicKey} signature.publicKey 53 | * @param {Signature} signature.signature 54 | * @param {number=} signature.sigtype 55 | * @return {PublicKeyInput} this, for chaining 56 | */ 57 | PublicKeyInput.prototype.addSignature = function(transaction, signature) { 58 | $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); 59 | this.setScript(Script.buildPublicKeyIn( 60 | signature.signature.toDER(), 61 | signature.sigtype 62 | )); 63 | return this; 64 | }; 65 | 66 | /** 67 | * Clear the input's signature 68 | * @return {PublicKeyHashInput} this, for chaining 69 | */ 70 | PublicKeyInput.prototype.clearSignatures = function() { 71 | this.setScript(Script.empty()); 72 | return this; 73 | }; 74 | 75 | /** 76 | * Query whether the input is signed 77 | * @return {boolean} 78 | */ 79 | PublicKeyInput.prototype.isFullySigned = function() { 80 | return this.script.isPublicKeyIn(); 81 | }; 82 | 83 | PublicKeyInput.SCRIPT_MAX_SIZE = 73; // sigsize (1 + 72) 84 | 85 | PublicKeyInput.prototype._estimateSize = function() { 86 | return PublicKeyInput.SCRIPT_MAX_SIZE; 87 | }; 88 | 89 | module.exports = PublicKeyInput; 90 | -------------------------------------------------------------------------------- /lib/transaction/input/publickeyhash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var inherits = require('inherits'); 4 | 5 | var $ = require('../../util/preconditions'); 6 | var BufferUtil = require('../../util/buffer'); 7 | 8 | var Hash = require('../../crypto/hash'); 9 | var Input = require('./input'); 10 | var Output = require('../output'); 11 | var Sighash = require('../sighash'); 12 | var Script = require('../../script'); 13 | var Signature = require('../../crypto/signature'); 14 | var TransactionSignature = require('../signature'); 15 | 16 | /** 17 | * Represents a special kind of input of PayToPublicKeyHash kind. 18 | * @constructor 19 | */ 20 | function PublicKeyHashInput() { 21 | Input.apply(this, arguments); 22 | } 23 | inherits(PublicKeyHashInput, Input); 24 | 25 | /* jshint maxparams: 5 */ 26 | /** 27 | * @param {Transaction} transaction - the transaction to be signed 28 | * @param {PrivateKey} privateKey - the private key with which to sign the transaction 29 | * @param {number} index - the index of the input in the transaction input vector 30 | * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL 31 | * @param {Buffer=} hashData - the precalculated hash of the public key associated with the privateKey provided 32 | * @return {Array} of objects that can be 33 | */ 34 | PublicKeyHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype, hashData) { 35 | $.checkState(this.output instanceof Output); 36 | hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer()); 37 | sigtype = sigtype || Signature.SIGHASH_ALL; 38 | 39 | if (BufferUtil.equals(hashData, this.output.script.getPublicKeyHash())) { 40 | return [new TransactionSignature({ 41 | publicKey: privateKey.publicKey, 42 | prevTxId: this.prevTxId, 43 | outputIndex: this.outputIndex, 44 | inputIndex: index, 45 | signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), 46 | sigtype: sigtype 47 | })]; 48 | } 49 | return []; 50 | }; 51 | /* jshint maxparams: 3 */ 52 | 53 | /** 54 | * Add the provided signature 55 | * 56 | * @param {Object} signature 57 | * @param {PublicKey} signature.publicKey 58 | * @param {Signature} signature.signature 59 | * @param {number=} signature.sigtype 60 | * @return {PublicKeyHashInput} this, for chaining 61 | */ 62 | PublicKeyHashInput.prototype.addSignature = function(transaction, signature) { 63 | $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); 64 | this.setScript(Script.buildPublicKeyHashIn( 65 | signature.publicKey, 66 | signature.signature.toDER(), 67 | signature.sigtype 68 | )); 69 | return this; 70 | }; 71 | 72 | /** 73 | * Clear the input's signature 74 | * @return {PublicKeyHashInput} this, for chaining 75 | */ 76 | PublicKeyHashInput.prototype.clearSignatures = function() { 77 | this.setScript(Script.empty()); 78 | return this; 79 | }; 80 | 81 | /** 82 | * Query whether the input is signed 83 | * @return {boolean} 84 | */ 85 | PublicKeyHashInput.prototype.isFullySigned = function() { 86 | return this.script.isPublicKeyHashIn(); 87 | }; 88 | 89 | PublicKeyHashInput.SCRIPT_MAX_SIZE = 73 + 34; // sigsize (1 + 72) + pubkey (1 + 33) 90 | 91 | PublicKeyHashInput.prototype._estimateSize = function() { 92 | return PublicKeyHashInput.SCRIPT_MAX_SIZE; 93 | }; 94 | 95 | module.exports = PublicKeyHashInput; 96 | -------------------------------------------------------------------------------- /lib/transaction/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var BN = require('../crypto/bn'); 5 | var buffer = require('buffer'); 6 | var bufferUtil = require('../util/buffer'); 7 | var JSUtil = require('../util/js'); 8 | var BufferWriter = require('../encoding/bufferwriter'); 9 | var Script = require('../script'); 10 | var $ = require('../util/preconditions'); 11 | var errors = require('../errors'); 12 | 13 | var MAX_SAFE_INTEGER = 0x1fffffffffffff; 14 | 15 | function Output(args) { 16 | if (!(this instanceof Output)) { 17 | return new Output(args); 18 | } 19 | if (_.isObject(args)) { 20 | this.satoshis = args.satoshis; 21 | if (bufferUtil.isBuffer(args.script)) { 22 | this._scriptBuffer = args.script; 23 | } else { 24 | var script; 25 | if (_.isString(args.script) && JSUtil.isHexa(args.script)) { 26 | script = new buffer.Buffer(args.script, 'hex'); 27 | } else { 28 | script = args.script; 29 | } 30 | this.setScript(script); 31 | } 32 | } else { 33 | throw new TypeError('Unrecognized argument for Output'); 34 | } 35 | } 36 | 37 | Object.defineProperty(Output.prototype, 'script', { 38 | configurable: false, 39 | enumerable: true, 40 | get: function() { 41 | if (this._script) { 42 | return this._script; 43 | } else { 44 | this.setScriptFromBuffer(this._scriptBuffer); 45 | return this._script; 46 | } 47 | 48 | } 49 | }); 50 | 51 | Object.defineProperty(Output.prototype, 'satoshis', { 52 | configurable: false, 53 | enumerable: true, 54 | get: function() { 55 | return this._satoshis; 56 | }, 57 | set: function(num) { 58 | if (num instanceof BN) { 59 | this._satoshisBN = num; 60 | this._satoshis = num.toNumber(); 61 | } else if (_.isString(num)) { 62 | this._satoshis = parseInt(num); 63 | this._satoshisBN = BN.fromNumber(this._satoshis); 64 | } else { 65 | $.checkArgument( 66 | JSUtil.isNaturalNumber(num), 67 | 'Output satoshis is not a natural number' 68 | ); 69 | this._satoshisBN = BN.fromNumber(num); 70 | this._satoshis = num; 71 | } 72 | $.checkState( 73 | JSUtil.isNaturalNumber(this._satoshis), 74 | 'Output satoshis is not a natural number' 75 | ); 76 | } 77 | }); 78 | 79 | Output.prototype.invalidSatoshis = function() { 80 | if (this._satoshis > MAX_SAFE_INTEGER) { 81 | return 'transaction txout satoshis greater than max safe integer'; 82 | } 83 | if (this._satoshis !== this._satoshisBN.toNumber()) { 84 | return 'transaction txout satoshis has corrupted value'; 85 | } 86 | if (this._satoshis < 0) { 87 | return 'transaction txout negative'; 88 | } 89 | return false; 90 | }; 91 | 92 | Output.prototype.toObject = Output.prototype.toJSON = function toObject() { 93 | var obj = { 94 | satoshis: this.satoshis 95 | }; 96 | obj.script = this._scriptBuffer.toString('hex'); 97 | return obj; 98 | }; 99 | 100 | Output.fromObject = function(data) { 101 | return new Output(data); 102 | }; 103 | 104 | Output.prototype.setScriptFromBuffer = function(buffer) { 105 | this._scriptBuffer = buffer; 106 | try { 107 | this._script = Script.fromBuffer(this._scriptBuffer); 108 | this._script._isOutput = true; 109 | } catch(e) { 110 | if (e instanceof errors.Script.InvalidBuffer) { 111 | this._script = null; 112 | } else { 113 | throw e; 114 | } 115 | } 116 | }; 117 | 118 | Output.prototype.setScript = function(script) { 119 | if (script instanceof Script) { 120 | this._scriptBuffer = script.toBuffer(); 121 | this._script = script; 122 | this._script._isOutput = true; 123 | } else if (_.isString(script)) { 124 | this._script = Script.fromString(script); 125 | this._scriptBuffer = this._script.toBuffer(); 126 | this._script._isOutput = true; 127 | } else if (bufferUtil.isBuffer(script)) { 128 | this.setScriptFromBuffer(script); 129 | } else { 130 | throw new TypeError('Invalid argument type: script'); 131 | } 132 | return this; 133 | }; 134 | 135 | Output.prototype.inspect = function() { 136 | var scriptStr; 137 | if (this.script) { 138 | scriptStr = this.script.inspect(); 139 | } else { 140 | scriptStr = this._scriptBuffer.toString('hex'); 141 | } 142 | return ''; 143 | }; 144 | 145 | Output.fromBufferReader = function(br) { 146 | var obj = {}; 147 | obj.satoshis = br.readUInt64LEBN(); 148 | var size = br.readVarintNum(); 149 | if (size !== 0) { 150 | obj.script = br.read(size); 151 | } else { 152 | obj.script = new buffer.Buffer([]); 153 | } 154 | return new Output(obj); 155 | }; 156 | 157 | Output.prototype.toBufferWriter = function(writer) { 158 | if (!writer) { 159 | writer = new BufferWriter(); 160 | } 161 | writer.writeUInt64LEBN(this._satoshisBN); 162 | var script = this._scriptBuffer; 163 | writer.writeVarintNum(script.length); 164 | writer.write(script); 165 | return writer; 166 | }; 167 | 168 | module.exports = Output; 169 | -------------------------------------------------------------------------------- /lib/transaction/sighash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var buffer = require('buffer'); 4 | 5 | var Signature = require('../crypto/signature'); 6 | var Script = require('../script'); 7 | var Output = require('./output'); 8 | var BufferReader = require('../encoding/bufferreader'); 9 | var BufferWriter = require('../encoding/bufferwriter'); 10 | var BN = require('../crypto/bn'); 11 | var Hash = require('../crypto/hash'); 12 | var ECDSA = require('../crypto/ecdsa'); 13 | var $ = require('../util/preconditions'); 14 | var _ = require('lodash'); 15 | 16 | var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001'; 17 | var BITS_64_ON = 'ffffffffffffffff'; 18 | 19 | /** 20 | * Returns a buffer of length 32 bytes with the hash that needs to be signed 21 | * for OP_CHECKSIG. 22 | * 23 | * @name Signing.sighash 24 | * @param {Transaction} transaction the transaction to sign 25 | * @param {number} sighashType the type of the hash 26 | * @param {number} inputNumber the input index for the signature 27 | * @param {Script} subscript the script that will be signed 28 | */ 29 | var sighash = function sighash(transaction, sighashType, inputNumber, subscript) { 30 | var Transaction = require('./transaction'); 31 | var Input = require('./input'); 32 | 33 | var i; 34 | // Copy transaction 35 | var txcopy = Transaction.shallowCopy(transaction); 36 | 37 | // Copy script 38 | subscript = new Script(subscript); 39 | subscript.removeCodeseparators(); 40 | 41 | for (i = 0; i < txcopy.inputs.length; i++) { 42 | // Blank signatures for other inputs 43 | txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty()); 44 | } 45 | 46 | txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript); 47 | 48 | if ((sighashType & 31) === Signature.SIGHASH_NONE || 49 | (sighashType & 31) === Signature.SIGHASH_SINGLE) { 50 | 51 | // clear all sequenceNumbers 52 | for (i = 0; i < txcopy.inputs.length; i++) { 53 | if (i !== inputNumber) { 54 | txcopy.inputs[i].sequenceNumber = 0; 55 | } 56 | } 57 | } 58 | 59 | if ((sighashType & 31) === Signature.SIGHASH_NONE) { 60 | txcopy.outputs = []; 61 | 62 | } else if ((sighashType & 31) === Signature.SIGHASH_SINGLE) { 63 | // The SIGHASH_SINGLE bug. 64 | // https://bitcointalk.org/index.php?topic=260595.0 65 | if (inputNumber >= txcopy.outputs.length) { 66 | return Buffer.from(SIGHASH_SINGLE_BUG, 'hex'); 67 | } 68 | 69 | txcopy.outputs.length = inputNumber + 1; 70 | 71 | for (i = 0; i < inputNumber; i++) { 72 | txcopy.outputs[i] = new Output({ 73 | satoshis: BN.fromBuffer(new buffer.Buffer(BITS_64_ON, 'hex')), 74 | script: Script.empty() 75 | }); 76 | } 77 | } 78 | 79 | if (sighashType & Signature.SIGHASH_ANYONECANPAY) { 80 | txcopy.inputs = [txcopy.inputs[inputNumber]]; 81 | } 82 | 83 | var buf = new BufferWriter() 84 | .write(txcopy.toBuffer()) 85 | .writeInt32LE(sighashType) 86 | .toBuffer(); 87 | var ret = Hash.sha256sha256(buf); 88 | ret = new BufferReader(ret).readReverse(); 89 | return ret; 90 | }; 91 | 92 | /** 93 | * Create a signature 94 | * 95 | * @name Signing.sign 96 | * @param {Transaction} transaction 97 | * @param {PrivateKey} privateKey 98 | * @param {number} sighash 99 | * @param {number} inputIndex 100 | * @param {Script} subscript 101 | * @return {Signature} 102 | */ 103 | function sign(transaction, privateKey, sighashType, inputIndex, subscript) { 104 | var hashbuf = sighash(transaction, sighashType, inputIndex, subscript); 105 | var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({ 106 | nhashtype: sighashType 107 | }); 108 | return sig; 109 | } 110 | 111 | /** 112 | * Verify a signature 113 | * 114 | * @name Signing.verify 115 | * @param {Transaction} transaction 116 | * @param {Signature} signature 117 | * @param {PublicKey} publicKey 118 | * @param {number} inputIndex 119 | * @param {Script} subscript 120 | * @return {boolean} 121 | */ 122 | function verify(transaction, signature, publicKey, inputIndex, subscript) { 123 | $.checkArgument(!_.isUndefined(transaction)); 124 | $.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype)); 125 | var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript); 126 | return ECDSA.verify(hashbuf, signature, publicKey, 'little'); 127 | } 128 | 129 | /** 130 | * @namespace Signing 131 | */ 132 | module.exports = { 133 | sighash: sighash, 134 | sign: sign, 135 | verify: verify 136 | }; 137 | -------------------------------------------------------------------------------- /lib/transaction/sighashwitness.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint maxparams:5 */ 4 | 5 | var Signature = require('../crypto/signature'); 6 | var Script = require('../script'); 7 | var Output = require('./output'); 8 | var BufferReader = require('../encoding/bufferreader'); 9 | var BufferWriter = require('../encoding/bufferwriter'); 10 | var BN = require('../crypto/bn'); 11 | var Hash = require('../crypto/hash'); 12 | var ECDSA = require('../crypto/ecdsa'); 13 | var $ = require('../util/preconditions'); 14 | var _ = require('lodash'); 15 | 16 | /** 17 | * Returns a buffer of length 32 bytes with the hash that needs to be signed 18 | * for witness programs as defined by: 19 | * https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki 20 | * 21 | * @name Signing.sighash 22 | * @param {Transaction} transaction the transaction to sign 23 | * @param {number} sighashType the type of the hash 24 | * @param {number} inputNumber the input index for the signature 25 | * @param {Buffer} scriptCode 26 | * @param {Buffer} satoshisBuffer 27 | */ 28 | var sighash = function sighash(transaction, sighashType, inputNumber, scriptCode, satoshisBuffer) { 29 | /* jshint maxstatements: 50 */ 30 | 31 | var hashPrevouts; 32 | var hashSequence; 33 | var hashOutputs; 34 | 35 | if (!(sighashType & Signature.SIGHASH_ANYONECANPAY)) { 36 | var buffers = []; 37 | for (var n = 0; n < transaction.inputs.length; n++) { 38 | var input = transaction.inputs[n]; 39 | var prevTxIdBuffer = new BufferReader(input.prevTxId).readReverse(); 40 | buffers.push(prevTxIdBuffer); 41 | var outputIndexBuffer = new Buffer(new Array(4)); 42 | outputIndexBuffer.writeUInt32LE(input.outputIndex, 0); 43 | buffers.push(outputIndexBuffer); 44 | } 45 | hashPrevouts = Hash.sha256sha256(Buffer.concat(buffers)); 46 | } 47 | 48 | if (!(sighashType & Signature.SIGHASH_ANYONECANPAY) && 49 | (sighashType & 0x1f) !== Signature.SIGHASH_SINGLE && (sighashType & 0x1f) !== Signature.SIGHASH_NONE) { 50 | 51 | var sequenceBuffers = []; 52 | for (var m = 0; m < transaction.inputs.length; m++) { 53 | var sequenceBuffer = new Buffer(new Array(4)); 54 | sequenceBuffer.writeUInt32LE(transaction.inputs[m].sequenceNumber, 0); 55 | sequenceBuffers.push(sequenceBuffer); 56 | } 57 | hashSequence = Hash.sha256sha256(Buffer.concat(sequenceBuffers)); 58 | } 59 | 60 | var outputWriter = new BufferWriter(); 61 | if ((sighashType & 0x1f) !== Signature.SIGHASH_SINGLE && (sighashType & 0x1f) !== Signature.SIGHASH_NONE) { 62 | for (var p = 0; p < transaction.outputs.length; p++) { 63 | transaction.outputs[p].toBufferWriter(outputWriter); 64 | } 65 | hashOutputs = Hash.sha256sha256(outputWriter.toBuffer()); 66 | } else if ((sighashType & 0x1f) === Signature.SIGHASH_SINGLE && inputNumber < transaction.outputs.length) { 67 | transaction.outputs[inputNumber].toBufferWriter(outputWriter); 68 | hashOutputs = Hash.sha256sha256(outputWriter.toBuffer()); 69 | } 70 | 71 | // Version 72 | var writer = new BufferWriter(); 73 | writer.writeUInt32LE(transaction.version); 74 | 75 | // Input prevouts/nSequence (none/all, depending on flags) 76 | writer.write(hashPrevouts); 77 | writer.write(hashSequence); 78 | 79 | // The input being signed (replacing the scriptSig with scriptCode + amount) 80 | // The prevout may already be contained in hashPrevout, and the nSequence 81 | // may already be contain in hashSequence. 82 | var outpointId = new BufferReader(transaction.inputs[inputNumber].prevTxId).readReverse(); 83 | writer.write(outpointId); 84 | writer.writeUInt32LE(transaction.inputs[inputNumber].outputIndex); 85 | 86 | writer.write(scriptCode); 87 | 88 | writer.write(satoshisBuffer); 89 | 90 | writer.writeUInt32LE(transaction.inputs[inputNumber].sequenceNumber); 91 | 92 | // Outputs (none/one/all, depending on flags) 93 | writer.write(hashOutputs); 94 | 95 | // Locktime 96 | writer.writeUInt32LE(transaction.nLockTime); 97 | 98 | // Sighash type 99 | writer.writeInt32LE(sighashType); 100 | 101 | return Hash.sha256sha256(writer.toBuffer()); 102 | 103 | }; 104 | 105 | /** 106 | * Create a signature 107 | * 108 | * @name Signing.sign 109 | * @param {Transaction} transaction 110 | * @param {PrivateKey} privateKey 111 | * @param {number} sighash 112 | * @param {number} inputIndex 113 | * @param {Script} subscript 114 | * @return {Signature} 115 | */ 116 | function sign(transaction, privateKey, sighashType, inputIndex, scriptCode, satoshisBuffer) { 117 | var hashbuf = sighash(transaction, sighashType, inputIndex, scriptCode, satoshisBuffer); 118 | var sig = ECDSA.sign(hashbuf, privateKey).set({ 119 | nhashtype: sighashType 120 | }); 121 | return sig; 122 | } 123 | 124 | /** 125 | * Verify a signature 126 | * 127 | * @name Signing.verify 128 | * @param {Transaction} transaction 129 | * @param {Signature} signature 130 | * @param {PublicKey} publicKey 131 | * @param {number} inputIndex 132 | * @param {Script} subscript 133 | * @return {boolean} 134 | */ 135 | function verify(transaction, signature, publicKey, inputIndex, scriptCode, satoshisBuffer) { 136 | $.checkArgument(!_.isUndefined(transaction)); 137 | $.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype)); 138 | var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, scriptCode, satoshisBuffer); 139 | return ECDSA.verify(hashbuf, signature, publicKey); 140 | } 141 | 142 | /** 143 | * @namespace Signing 144 | */ 145 | module.exports = { 146 | sighash: sighash, 147 | sign: sign, 148 | verify: verify 149 | }; 150 | -------------------------------------------------------------------------------- /lib/transaction/signature.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var $ = require('../util/preconditions'); 5 | var inherits = require('inherits'); 6 | var BufferUtil = require('../util/buffer'); 7 | var JSUtil = require('../util/js'); 8 | 9 | var PublicKey = require('../publickey'); 10 | var errors = require('../errors'); 11 | var Signature = require('../crypto/signature'); 12 | 13 | /** 14 | * @desc 15 | * Wrapper around Signature with fields related to signing a transaction specifically 16 | * 17 | * @param {Object|string|TransactionSignature} arg 18 | * @constructor 19 | */ 20 | function TransactionSignature(arg) { 21 | if (!(this instanceof TransactionSignature)) { 22 | return new TransactionSignature(arg); 23 | } 24 | if (arg instanceof TransactionSignature) { 25 | return arg; 26 | } 27 | if (_.isObject(arg)) { 28 | return this._fromObject(arg); 29 | } 30 | throw new errors.InvalidArgument('TransactionSignatures must be instantiated from an object'); 31 | } 32 | inherits(TransactionSignature, Signature); 33 | 34 | TransactionSignature.prototype._fromObject = function(arg) { 35 | this._checkObjectArgs(arg); 36 | this.publicKey = new PublicKey(arg.publicKey); 37 | this.prevTxId = BufferUtil.isBuffer(arg.prevTxId) ? arg.prevTxId : Buffer.from(arg.prevTxId, 'hex'); 38 | this.outputIndex = arg.outputIndex; 39 | this.inputIndex = arg.inputIndex; 40 | this.signature = (arg.signature instanceof Signature) ? arg.signature : 41 | BufferUtil.isBuffer(arg.signature) ? Signature.fromBuffer(arg.signature) : 42 | Signature.fromString(arg.signature); 43 | this.sigtype = arg.sigtype; 44 | return this; 45 | }; 46 | 47 | TransactionSignature.prototype._checkObjectArgs = function(arg) { 48 | $.checkArgument(PublicKey(arg.publicKey), 'publicKey'); 49 | $.checkArgument(!_.isUndefined(arg.inputIndex), 'inputIndex'); 50 | $.checkArgument(!_.isUndefined(arg.outputIndex), 'outputIndex'); 51 | $.checkState(_.isNumber(arg.inputIndex), 'inputIndex must be a number'); 52 | $.checkState(_.isNumber(arg.outputIndex), 'outputIndex must be a number'); 53 | $.checkArgument(arg.signature, 'signature'); 54 | $.checkArgument(arg.prevTxId, 'prevTxId'); 55 | $.checkState(arg.signature instanceof Signature || 56 | BufferUtil.isBuffer(arg.signature) || 57 | JSUtil.isHexa(arg.signature), 'signature must be a buffer or hexa value'); 58 | $.checkState(BufferUtil.isBuffer(arg.prevTxId) || 59 | JSUtil.isHexa(arg.prevTxId), 'prevTxId must be a buffer or hexa value'); 60 | $.checkArgument(arg.sigtype, 'sigtype'); 61 | $.checkState(_.isNumber(arg.sigtype), 'sigtype must be a number'); 62 | }; 63 | 64 | /** 65 | * Serializes a transaction to a plain JS object 66 | * @return {Object} 67 | */ 68 | TransactionSignature.prototype.toObject = TransactionSignature.prototype.toJSON = function toObject() { 69 | return { 70 | publicKey: this.publicKey.toString(), 71 | prevTxId: this.prevTxId.toString('hex'), 72 | outputIndex: this.outputIndex, 73 | inputIndex: this.inputIndex, 74 | signature: this.signature.toString(), 75 | sigtype: this.sigtype 76 | }; 77 | }; 78 | 79 | /** 80 | * Builds a TransactionSignature from an object 81 | * @param {Object} object 82 | * @return {TransactionSignature} 83 | */ 84 | TransactionSignature.fromObject = function(object) { 85 | $.checkArgument(object); 86 | return new TransactionSignature(object); 87 | }; 88 | 89 | module.exports = TransactionSignature; 90 | -------------------------------------------------------------------------------- /lib/transaction/unspentoutput.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var $ = require('../util/preconditions'); 5 | var JSUtil = require('../util/js'); 6 | 7 | var Script = require('../script'); 8 | var Address = require('../address'); 9 | var Unit = require('../unit'); 10 | 11 | /** 12 | * Represents an unspent output information: its script, associated amount and address, 13 | * transaction id and output index. 14 | * 15 | * @constructor 16 | * @param {object} data 17 | * @param {string} data.txid the previous transaction id 18 | * @param {string=} data.txId alias for `txid` 19 | * @param {number} data.vout the index in the transaction 20 | * @param {number=} data.outputIndex alias for `vout` 21 | * @param {string|Script} data.scriptPubKey the script that must be resolved to release the funds 22 | * @param {string|Script=} data.script alias for `scriptPubKey` 23 | * @param {number} data.amount amount of bitcoins associated 24 | * @param {number=} data.satoshis alias for `amount`, but expressed in satoshis (1 BTC = 1e8 satoshis) 25 | * @param {string|Address=} data.address the associated address to the script, if provided 26 | */ 27 | function UnspentOutput(data) { 28 | /* jshint maxcomplexity: 20 */ 29 | /* jshint maxstatements: 20 */ 30 | if (!(this instanceof UnspentOutput)) { 31 | return new UnspentOutput(data); 32 | } 33 | $.checkArgument(_.isObject(data), 'Must provide an object from where to extract data'); 34 | var address = data.address ? new Address(data.address) : undefined; 35 | var txId = data.txid ? data.txid : data.txId; 36 | if (!txId || !JSUtil.isHexaString(txId) || txId.length > 64) { 37 | // TODO: Use the errors library 38 | throw new Error('Invalid TXID in object', data); 39 | } 40 | var outputIndex = _.isUndefined(data.vout) ? data.outputIndex : data.vout; 41 | if (!_.isNumber(outputIndex)) { 42 | throw new Error('Invalid outputIndex, received ' + outputIndex); 43 | } 44 | $.checkArgument(!_.isUndefined(data.scriptPubKey) || !_.isUndefined(data.script), 45 | 'Must provide the scriptPubKey for that output!'); 46 | var script = new Script(data.scriptPubKey || data.script); 47 | $.checkArgument(!_.isUndefined(data.amount) || !_.isUndefined(data.satoshis), 48 | 'Must provide an amount for the output'); 49 | var amount = !_.isUndefined(data.amount) ? new Unit.fromBTC(data.amount).toSatoshis() : data.satoshis; 50 | $.checkArgument(_.isNumber(amount), 'Amount must be a number'); 51 | JSUtil.defineImmutable(this, { 52 | address: address, 53 | txId: txId, 54 | outputIndex: outputIndex, 55 | script: script, 56 | satoshis: amount 57 | }); 58 | } 59 | 60 | /** 61 | * Provide an informative output when displaying this object in the console 62 | * @returns string 63 | */ 64 | UnspentOutput.prototype.inspect = function() { 65 | return ''; 67 | }; 68 | 69 | /** 70 | * String representation: just "txid:index" 71 | * @returns string 72 | */ 73 | UnspentOutput.prototype.toString = function() { 74 | return this.txId + ':' + this.outputIndex; 75 | }; 76 | 77 | /** 78 | * Deserialize an UnspentOutput from an object 79 | * @param {object|string} data 80 | * @return UnspentOutput 81 | */ 82 | UnspentOutput.fromObject = function(data) { 83 | return new UnspentOutput(data); 84 | }; 85 | 86 | /** 87 | * Returns a plain object (no prototype or methods) with the associated info for this output 88 | * @return {object} 89 | */ 90 | UnspentOutput.prototype.toObject = UnspentOutput.prototype.toJSON = function toObject() { 91 | return { 92 | address: this.address ? this.address.toString() : undefined, 93 | txid: this.txId, 94 | vout: this.outputIndex, 95 | scriptPubKey: this.script.toBuffer().toString('hex'), 96 | amount: Unit.fromSatoshis(this.satoshis).toBTC() 97 | }; 98 | }; 99 | 100 | module.exports = UnspentOutput; 101 | -------------------------------------------------------------------------------- /lib/util/buffer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var buffer = require('buffer'); 4 | var assert = require('assert'); 5 | 6 | var js = require('./js'); 7 | var $ = require('./preconditions'); 8 | 9 | function equals(a, b) { 10 | if (a.length !== b.length) { 11 | return false; 12 | } 13 | var length = a.length; 14 | for (var i = 0; i < length; i++) { 15 | if (a[i] !== b[i]) { 16 | return false; 17 | } 18 | } 19 | return true; 20 | } 21 | 22 | module.exports = { 23 | /** 24 | * Fill a buffer with a value. 25 | * 26 | * @param {Buffer} buffer 27 | * @param {number} value 28 | * @return {Buffer} 29 | */ 30 | fill: function fill(buffer, value) { 31 | $.checkArgumentType(buffer, 'Buffer', 'buffer'); 32 | $.checkArgumentType(value, 'number', 'value'); 33 | var length = buffer.length; 34 | for (var i = 0; i < length; i++) { 35 | buffer[i] = value; 36 | } 37 | return buffer; 38 | }, 39 | 40 | /** 41 | * Return a copy of a buffer 42 | * 43 | * @param {Buffer} original 44 | * @return {Buffer} 45 | */ 46 | copy: function(original) { 47 | var buffer = Buffer.alloc(original.length); 48 | original.copy(buffer); 49 | return buffer; 50 | }, 51 | 52 | /** 53 | * Returns true if the given argument is an instance of a buffer. Tests for 54 | * both node's Buffer and Uint8Array 55 | * 56 | * @param {*} arg 57 | * @return {boolean} 58 | */ 59 | isBuffer: function isBuffer(arg) { 60 | return buffer.Buffer.isBuffer(arg) || arg instanceof Uint8Array; 61 | }, 62 | 63 | /** 64 | * Returns a zero-filled byte array 65 | * 66 | * @param {number} bytes 67 | * @return {Buffer} 68 | */ 69 | emptyBuffer: function emptyBuffer(bytes) { 70 | $.checkArgumentType(bytes, 'number', 'bytes'); 71 | var result = new buffer.Buffer(bytes); 72 | for (var i = 0; i < bytes; i++) { 73 | result.write('\0', i); 74 | } 75 | return result; 76 | }, 77 | 78 | /** 79 | * Concatenates a buffer 80 | * 81 | * Shortcut for buffer.Buffer.concat 82 | */ 83 | concat: buffer.Buffer.concat, 84 | 85 | equals: equals, 86 | equal: equals, 87 | 88 | /** 89 | * Transforms a number from 0 to 255 into a Buffer of size 1 with that value 90 | * 91 | * @param {number} integer 92 | * @return {Buffer} 93 | */ 94 | integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) { 95 | $.checkArgumentType(integer, 'number', 'integer'); 96 | return new buffer.Buffer([integer & 0xff]); 97 | }, 98 | 99 | /** 100 | * Transform a 4-byte integer into a Buffer of length 4. 101 | * 102 | * @param {number} integer 103 | * @return {Buffer} 104 | */ 105 | integerAsBuffer: function integerAsBuffer(integer) { 106 | $.checkArgumentType(integer, 'number', 'integer'); 107 | var bytes = []; 108 | bytes.push((integer >> 24) & 0xff); 109 | bytes.push((integer >> 16) & 0xff); 110 | bytes.push((integer >> 8) & 0xff); 111 | bytes.push(integer & 0xff); 112 | return Buffer.from(bytes); 113 | }, 114 | 115 | /** 116 | * Transform the first 4 values of a Buffer into a number, in little endian encoding 117 | * 118 | * @param {Buffer} buffer 119 | * @return {number} 120 | */ 121 | integerFromBuffer: function integerFromBuffer(buffer) { 122 | $.checkArgumentType(buffer, 'Buffer', 'buffer'); 123 | return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; 124 | }, 125 | 126 | /** 127 | * Transforms the first byte of an array into a number ranging from -128 to 127 128 | * @param {Buffer} buffer 129 | * @return {number} 130 | */ 131 | integerFromSingleByteBuffer: function integerFromBuffer(buffer) { 132 | $.checkArgumentType(buffer, 'Buffer', 'buffer'); 133 | return buffer[0]; 134 | }, 135 | 136 | /** 137 | * Transforms a buffer into a string with a number in hexa representation 138 | * 139 | * Shorthand for buffer.toString('hex') 140 | * 141 | * @param {Buffer} buffer 142 | * @return {string} 143 | */ 144 | bufferToHex: function bufferToHex(buffer) { 145 | $.checkArgumentType(buffer, 'Buffer', 'buffer'); 146 | return buffer.toString('hex'); 147 | }, 148 | 149 | /** 150 | * Reverse a buffer 151 | * @param {Buffer} param 152 | * @return {Buffer} 153 | */ 154 | reverse: function reverse(param) { 155 | var ret = new buffer.Buffer(param.length); 156 | for (var i = 0; i < param.length; i++) { 157 | ret[i] = param[param.length - i - 1]; 158 | } 159 | return ret; 160 | }, 161 | 162 | /** 163 | * Transforms an hexa encoded string into a Buffer with binary values 164 | * 165 | * Shorthand for Buffer(string, 'hex') 166 | * 167 | * @param {string} string 168 | * @return {Buffer} 169 | */ 170 | hexToBuffer: function hexToBuffer(string) { 171 | assert(js.isHexa(string)); 172 | return new buffer.Buffer(string, 'hex'); 173 | } 174 | }; 175 | 176 | module.exports.NULL_HASH = module.exports.fill(Buffer.alloc(32), 0); 177 | module.exports.EMPTY_BUFFER = Buffer.alloc(0); 178 | -------------------------------------------------------------------------------- /lib/util/js.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | 5 | /** 6 | * Determines whether a string contains only hexadecimal values 7 | * 8 | * @name JSUtil.isHexa 9 | * @param {string} value 10 | * @return {boolean} true if the string is the hexa representation of a number 11 | */ 12 | var isHexa = function isHexa(value) { 13 | if (!_.isString(value)) { 14 | return false; 15 | } 16 | return /^[0-9a-fA-F]+$/.test(value); 17 | }; 18 | 19 | /** 20 | * @namespace JSUtil 21 | */ 22 | module.exports = { 23 | /** 24 | * Test if an argument is a valid JSON object. If it is, returns a truthy 25 | * value (the json object decoded), so no double JSON.parse call is necessary 26 | * 27 | * @param {string} arg 28 | * @return {Object|boolean} false if the argument is not a JSON string. 29 | */ 30 | isValidJSON: function isValidJSON(arg) { 31 | var parsed; 32 | if (!_.isString(arg)) { 33 | return false; 34 | } 35 | try { 36 | parsed = JSON.parse(arg); 37 | } catch (e) { 38 | return false; 39 | } 40 | if (typeof(parsed) === 'object') { 41 | return true; 42 | } 43 | return false; 44 | }, 45 | isHexa: isHexa, 46 | isHexaString: isHexa, 47 | 48 | /** 49 | * Clone an array 50 | */ 51 | cloneArray: function(array) { 52 | return [].concat(array); 53 | }, 54 | 55 | /** 56 | * Define immutable properties on a target object 57 | * 58 | * @param {Object} target - An object to be extended 59 | * @param {Object} values - An object of properties 60 | * @return {Object} The target object 61 | */ 62 | defineImmutable: function defineImmutable(target, values) { 63 | Object.keys(values).forEach(function(key){ 64 | Object.defineProperty(target, key, { 65 | configurable: false, 66 | enumerable: true, 67 | value: values[key] 68 | }); 69 | }); 70 | return target; 71 | }, 72 | /** 73 | * Checks that a value is a natural number, a positive integer or zero. 74 | * 75 | * @param {*} value 76 | * @return {Boolean} 77 | */ 78 | isNaturalNumber: function isNaturalNumber(value) { 79 | return typeof value === 'number' && 80 | isFinite(value) && 81 | Math.floor(value) === value && 82 | value >= 0; 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /lib/util/preconditions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var errors = require('../errors'); 4 | var _ = require('lodash'); 5 | 6 | module.exports = { 7 | checkState: function(condition, message) { 8 | if (!condition) { 9 | throw new errors.InvalidState(message); 10 | } 11 | }, 12 | checkArgument: function(condition, argumentName, message, docsPath) { 13 | if (!condition) { 14 | throw new errors.InvalidArgument(argumentName, message, docsPath); 15 | } 16 | }, 17 | checkArgumentType: function(argument, type, argumentName) { 18 | argumentName = argumentName || '(unknown name)'; 19 | if (_.isString(type)) { 20 | if (type === 'Buffer') { 21 | var buffer = require('buffer'); // './buffer' fails on cordova & RN 22 | if (!buffer.Buffer.isBuffer(argument)) { 23 | throw new errors.InvalidArgumentType(argument, type, argumentName); 24 | } 25 | } else if (typeof argument !== type) { 26 | throw new errors.InvalidArgumentType(argument, type, argumentName); 27 | } 28 | } else { 29 | if (!(argument instanceof type)) { 30 | throw new errors.InvalidArgumentType(argument, type.name, argumentName); 31 | } 32 | } 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitcore-lib", 3 | "version": "0.16.0", 4 | "description": "A pure and powerful JavaScript Bitcoin library.", 5 | "author": "BitPay ", 6 | "main": "index.js", 7 | "scripts": { 8 | "lint": "gulp lint", 9 | "test": "gulp test", 10 | "coverage": "gulp coverage", 11 | "build": "gulp" 12 | }, 13 | "keywords": [ 14 | "bitcoin", 15 | "transaction", 16 | "address", 17 | "p2p", 18 | "ecies", 19 | "cryptocurrency", 20 | "blockchain", 21 | "payment", 22 | "bip21", 23 | "bip32", 24 | "bip37", 25 | "bip69", 26 | "bip70", 27 | "multisig" 28 | ], 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/bitpay/bitcore-lib.git" 32 | }, 33 | "browser": { 34 | "request": "browser-request" 35 | }, 36 | "dependencies": { 37 | "bn.js": "=4.11.8", 38 | "bs58": "=4.0.1", 39 | "buffer-compare": "=1.1.1", 40 | "elliptic": "=6.4.0", 41 | "inherits": "=2.0.1", 42 | "lodash": "=4.17.11" 43 | }, 44 | "devDependencies": { 45 | "bitcore-build": "https://github.com/bitpay/bitcore-build.git#1023e8a99cd42b9241ccafe8e34c52f308c10284", 46 | "brfs": "^2.0.1", 47 | "chai": "^4.2.0", 48 | "gulp": "^4.0.0", 49 | "sinon": "^7.1.1" 50 | }, 51 | "license": "MIT" 52 | } 53 | -------------------------------------------------------------------------------- /test/crypto/bn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | var bitcore = require('../..'); 5 | var BN = bitcore.crypto.BN; 6 | 7 | describe('BN', function() { 8 | it('should create a bn', function() { 9 | var bn = new BN(50); 10 | should.exist(bn); 11 | bn.toString().should.equal('50'); 12 | }); 13 | 14 | it('should parse this number', function() { 15 | var bn = new BN(999970000); 16 | bn.toString().should.equal('999970000'); 17 | }); 18 | 19 | it('should parse numbers below and at bn.js internal word size', function() { 20 | var bn = new BN(Math.pow(2, 26) - 1); 21 | bn.toString().should.equal((Math.pow(2, 26) - 1).toString()); 22 | bn = new BN(Math.pow(2, 26)); 23 | bn.toString().should.equal((Math.pow(2, 26)).toString()); 24 | }); 25 | 26 | describe('#add', function() { 27 | 28 | it('should add two small numbers together', function() { 29 | var bn1 = new BN(50); 30 | var bn2 = new BN(75); 31 | var bn3 = bn1.add(bn2); 32 | bn3.toString().should.equal('125'); 33 | }); 34 | 35 | }); 36 | 37 | describe('#sub', function() { 38 | 39 | it('should subtract a small number', function() { 40 | var bn1 = new BN(50); 41 | var bn2 = new BN(25); 42 | var bn3 = bn1.sub(bn2); 43 | bn3.toString().should.equal('25'); 44 | }); 45 | 46 | }); 47 | 48 | describe('#gt', function() { 49 | 50 | it('should say 1 is greater than 0', function() { 51 | var bn1 = new BN(1); 52 | var bn0 = new BN(0); 53 | bn1.gt(bn0).should.equal(true); 54 | }); 55 | 56 | it('should say a big number is greater than a small big number', function() { 57 | var bn1 = new BN('24023452345398529485723980457'); 58 | var bn0 = new BN('34098234283412341234049357'); 59 | bn1.gt(bn0).should.equal(true); 60 | }); 61 | 62 | it('should say a big number is great than a standard number', function() { 63 | var bn1 = new BN('24023452345398529485723980457'); 64 | var bn0 = new BN(5); 65 | bn1.gt(bn0).should.equal(true); 66 | }); 67 | 68 | }); 69 | 70 | describe('to/from ScriptNumBuffer', function() { 71 | [0, 1, 10, 256, 1000, 65536, 65537, -1, -1000, -65536, -65537].forEach(function(n) { 72 | it('rountrips correctly for ' + n, function() { 73 | BN.fromScriptNumBuffer(new BN(n).toScriptNumBuffer()).toNumber().should.equal(n); 74 | }); 75 | }); 76 | }); 77 | 78 | describe('#fromString', function() { 79 | it('should make BN from a string', function() { 80 | BN.fromString('5').toString().should.equal('5'); 81 | }); 82 | it('should work with hex string', function() { 83 | BN.fromString('7fffff0000000000000000000000000000000000000000000000000000000000', 16) 84 | .toString(16).should.equal('7fffff0000000000000000000000000000000000000000000000000000000000'); 85 | }); 86 | }); 87 | 88 | describe('#toString', function() { 89 | it('should make a string', function() { 90 | new BN(5).toString().should.equal('5'); 91 | }); 92 | }); 93 | 94 | describe('@fromBuffer', function() { 95 | 96 | it('should work with big endian', function() { 97 | var bn = BN.fromBuffer(new Buffer('0001', 'hex'), { 98 | endian: 'big' 99 | }); 100 | bn.toString().should.equal('1'); 101 | }); 102 | 103 | it('should work with big endian 256', function() { 104 | var bn = BN.fromBuffer(new Buffer('0100', 'hex'), { 105 | endian: 'big' 106 | }); 107 | bn.toString().should.equal('256'); 108 | }); 109 | 110 | it('should work with little endian if we specify the size', function() { 111 | var bn = BN.fromBuffer(new Buffer('0100', 'hex'), { 112 | size: 2, 113 | endian: 'little' 114 | }); 115 | bn.toString().should.equal('1'); 116 | }); 117 | 118 | }); 119 | 120 | describe('#toBuffer', function() { 121 | 122 | it('should create a 4 byte buffer', function() { 123 | var bn = new BN(1); 124 | bn.toBuffer({ 125 | size: 4 126 | }).toString('hex').should.equal('00000001'); 127 | }); 128 | 129 | it('should create a 4 byte buffer in little endian', function() { 130 | var bn = new BN(1); 131 | bn.toBuffer({ 132 | size: 4, 133 | endian: 'little' 134 | }).toString('hex').should.equal('01000000'); 135 | }); 136 | 137 | it('should create a 2 byte buffer even if you ask for a 1 byte', function() { 138 | var bn = new BN('ff00', 16); 139 | bn.toBuffer({ 140 | size: 1 141 | }).toString('hex').should.equal('ff00'); 142 | }); 143 | 144 | it('should create a 4 byte buffer even if you ask for a 1 byte', function() { 145 | var bn = new BN('ffffff00', 16); 146 | bn.toBuffer({ 147 | size: 4 148 | }).toString('hex').should.equal('ffffff00'); 149 | }); 150 | 151 | }); 152 | 153 | }); 154 | -------------------------------------------------------------------------------- /test/crypto/hash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('chai').should(); 4 | var bitcore = require('../..'); 5 | var Hash = bitcore.crypto.Hash; 6 | 7 | describe('Hash', function() { 8 | var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]); 9 | var str = 'test string'; 10 | 11 | describe('@sha1', function() { 12 | 13 | it('calculates the hash of this buffer correctly', function() { 14 | var hash = Hash.sha1(buf); 15 | hash.toString('hex').should.equal('de69b8a4a5604d0486e6420db81e39eb464a17b2'); 16 | hash = Hash.sha1(new Buffer(0)); 17 | hash.toString('hex').should.equal('da39a3ee5e6b4b0d3255bfef95601890afd80709'); 18 | }); 19 | 20 | it('throws an error when the input is not a buffer', function() { 21 | Hash.sha1.bind(Hash, str).should.throw('Invalid Argument'); 22 | }); 23 | 24 | }); 25 | 26 | describe('#sha256', function() { 27 | 28 | it('calculates the hash of this buffer correctly', function() { 29 | var hash = Hash.sha256(buf); 30 | hash.toString('hex').should.equal('6f2c7b22fd1626998287b3636089087961091de80311b9279c4033ec678a83e8'); 31 | }); 32 | 33 | it('fails when the input is not a buffer', function() { 34 | Hash.sha256.bind(Hash, str).should.throw('Invalid Argument'); 35 | }); 36 | 37 | }); 38 | 39 | describe('#sha256hmac', function() { 40 | 41 | it('computes this known big key correctly', function() { 42 | var key = new Buffer('b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad' + 43 | 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad' + 44 | 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad' + 45 | 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad'); 46 | var data = new Buffer(''); 47 | Hash.sha256hmac(data, key).toString('hex') 48 | .should.equal('fb1f87218671f1c0c4593a88498e02b6dfe8afd814c1729e89a1f1f6600faa23'); 49 | }); 50 | 51 | it('computes this known empty test vector correctly', function() { 52 | var key = new Buffer(''); 53 | var data = new Buffer(''); 54 | Hash.sha256hmac(data, key).toString('hex') 55 | .should.equal('b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad'); 56 | }); 57 | 58 | it('computes this known non-empty test vector correctly', function() { 59 | var key = new Buffer('key'); 60 | var data = new Buffer('The quick brown fox jumps over the lazy dog'); 61 | Hash.sha256hmac(data, key).toString('hex') 62 | .should.equal('f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8'); 63 | }); 64 | 65 | }); 66 | 67 | describe('#sha256sha256', function() { 68 | 69 | it('calculates the hash of this buffer correctly', function() { 70 | var hash = Hash.sha256sha256(buf); 71 | hash.toString('hex').should.equal('be586c8b20dee549bdd66018c7a79e2b67bb88b7c7d428fa4c970976d2bec5ba'); 72 | }); 73 | 74 | it('fails when the input is not a buffer', function() { 75 | Hash.sha256sha256.bind(Hash, str).should.throw('Invalid Argument'); 76 | }); 77 | 78 | }); 79 | 80 | describe('#sha256ripemd160', function() { 81 | 82 | it('calculates the hash of this buffer correctly', function() { 83 | var hash = Hash.sha256ripemd160(buf); 84 | hash.toString('hex').should.equal('7322e2bd8535e476c092934e16a6169ca9b707ec'); 85 | }); 86 | 87 | it('fails when the input is not a buffer', function() { 88 | Hash.sha256ripemd160.bind(Hash, str).should.throw('Invalid Argument'); 89 | }); 90 | 91 | }); 92 | 93 | describe('#ripemd160', function() { 94 | 95 | it('calculates the hash of this buffer correctly', function() { 96 | var hash = Hash.ripemd160(buf); 97 | hash.toString('hex').should.equal('fa0f4565ff776fee0034c713cbf48b5ec06b7f5c'); 98 | }); 99 | 100 | it('fails when the input is not a buffer', function() { 101 | Hash.ripemd160.bind(Hash, str).should.throw('Invalid Argument'); 102 | }); 103 | 104 | }); 105 | 106 | describe('#sha512', function() { 107 | 108 | it('calculates the hash of this buffer correctly', function() { 109 | var hash = Hash.sha512(buf); 110 | hash.toString('hex') 111 | .should.equal('c0530aa32048f4904ae162bc14b9eb535eab6c465e960130005fedd' + 112 | 'b71613e7d62aea75f7d3333ba06e805fc8e45681454524e3f8050969fe5a5f7f2392e31d0'); 113 | }); 114 | 115 | it('fails when the input is not a buffer', function() { 116 | Hash.sha512.bind(Hash, str).should.throw('Invalid Argument'); 117 | }); 118 | 119 | }); 120 | 121 | describe('#sha512hmac', function() { 122 | 123 | it('calculates this known empty test vector correctly', function() { 124 | var hex = 'b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4a' + 125 | 'c6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47'; 126 | Hash.sha512hmac(new Buffer([]), new Buffer([])).toString('hex').should.equal(hex); 127 | }); 128 | 129 | it('calculates this known non-empty test vector correctly', function() { 130 | var hex = 'c40bd7c15aa493b309c940e08a73ffbd28b2e4cb729eb94480d727e4df577' + 131 | 'b13cc403a78e6150d83595f3b17c4cc331f12ca5952691de3735a63c1d4c69a2bac'; 132 | var data = new Buffer('test1'); 133 | var key = new Buffer('test2'); 134 | Hash.sha512hmac(data, key).toString('hex').should.equal(hex); 135 | }); 136 | 137 | }); 138 | 139 | }); 140 | -------------------------------------------------------------------------------- /test/crypto/random.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var bitcore = require('../..'); 4 | var Random = bitcore.crypto.Random; 5 | 6 | describe('Random', function() { 7 | 8 | describe('@getRandomBuffer', function() { 9 | 10 | it('should return a buffer', function() { 11 | var bytes = Random.getRandomBuffer(8); 12 | bytes.length.should.equal(8); 13 | Buffer.isBuffer(bytes).should.equal(true); 14 | }); 15 | 16 | it('should not equate two 256 bit random buffers', function() { 17 | var bytes1 = Random.getRandomBuffer(32); 18 | var bytes2 = Random.getRandomBuffer(32); 19 | bytes1.toString('hex').should.not.equal(bytes2.toString('hex')); 20 | }); 21 | 22 | it('should generate 100 8 byte buffers in a row that are not equal', function() { 23 | var hexs = []; 24 | for (var i = 0; i < 100; i++) { 25 | hexs[i] = Random.getRandomBuffer(8).toString('hex'); 26 | } 27 | for (i = 0; i < 100; i++) { 28 | for (var j = i + 1; j < 100; j++) { 29 | hexs[i].should.not.equal(hexs[j]); 30 | } 31 | } 32 | }); 33 | 34 | }); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/data/bitcoind/base58_keys_invalid.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "" 4 | ], 5 | [ 6 | "x" 7 | ], 8 | [ 9 | "37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y" 10 | ], 11 | [ 12 | "dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv" 13 | ], 14 | [ 15 | "MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S" 16 | ], 17 | [ 18 | "rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf" 19 | ], 20 | [ 21 | "4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq" 22 | ], 23 | [ 24 | "7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb" 25 | ], 26 | [ 27 | "17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs" 28 | ], 29 | [ 30 | "KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3" 31 | ], 32 | [ 33 | "7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th" 34 | ], 35 | [ 36 | "cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va" 37 | ], 38 | [ 39 | "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk" 40 | ], 41 | [ 42 | "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs" 43 | ], 44 | [ 45 | "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo" 46 | ], 47 | [ 48 | "1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso" 49 | ], 50 | [ 51 | "31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq" 52 | ], 53 | [ 54 | "DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN" 55 | ], 56 | [ 57 | "2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i" 58 | ], 59 | [ 60 | "7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos" 61 | ], 62 | [ 63 | "1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu" 64 | ], 65 | [ 66 | "2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb" 67 | ], 68 | [ 69 | "8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ" 70 | ], 71 | [ 72 | "163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ" 73 | ], 74 | [ 75 | "2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu" 76 | ], 77 | [ 78 | "461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU" 79 | ], 80 | [ 81 | "2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs" 82 | ], 83 | [ 84 | "cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn" 85 | ], 86 | [ 87 | "gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj" 88 | ], 89 | [ 90 | "nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny" 91 | ], 92 | [ 93 | "L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc" 94 | ], 95 | [ 96 | "7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ" 97 | ], 98 | [ 99 | "2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP" 100 | ], 101 | [ 102 | "dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw" 103 | ], 104 | [ 105 | "HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX" 106 | ], 107 | [ 108 | "4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB" 109 | ], 110 | [ 111 | "Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ" 112 | ], 113 | [ 114 | "Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs" 115 | ], 116 | [ 117 | "6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ" 118 | ], 119 | [ 120 | "giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4" 121 | ], 122 | [ 123 | "cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK" 124 | ], 125 | [ 126 | "37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig" 127 | ], 128 | [ 129 | "EsYbG4tWWWY45G31nox838qNdzksbPySWc" 130 | ], 131 | [ 132 | "nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT" 133 | ], 134 | [ 135 | "cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx" 136 | ], 137 | [ 138 | "1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde" 139 | ], 140 | [ 141 | "2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU" 142 | ], 143 | [ 144 | "ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf" 145 | ], 146 | [ 147 | "Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd" 148 | ], 149 | [ 150 | "2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED" 151 | ] 152 | ] 153 | -------------------------------------------------------------------------------- /test/data/bitcoind/sig_canonical.json: -------------------------------------------------------------------------------- 1 | [ 2 | "300602010002010001", 3 | "3008020200ff020200ff01", 4 | "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001", 5 | "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01", 6 | "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01" 7 | ] 8 | -------------------------------------------------------------------------------- /test/data/bitcoind/sig_noncanonical.json: -------------------------------------------------------------------------------- 1 | [ 2 | "non-hex strings are ignored", 3 | 4 | "too short:", "30050201FF020001", 5 | "too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 6 | "hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11", 7 | "type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 8 | "total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 9 | "S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101", 10 | "R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001", 11 | 12 | "R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 13 | "R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 14 | "R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 15 | "R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 16 | 17 | 18 | "S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 19 | "S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001", 20 | "S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 21 | "S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01" 22 | ] 23 | -------------------------------------------------------------------------------- /test/data/blk86756-testnet.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitpay/bitcore-lib/44eb5b264b9a28e376cdcf3506160a95cc499533/test/data/blk86756-testnet.dat -------------------------------------------------------------------------------- /test/docs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai'); 4 | var should = chai.should(); 5 | 6 | var bitcore = require('..'); 7 | var fs = require('fs'); 8 | 9 | describe('Documentation', function() { 10 | 11 | it('major and minor versions should match', function() { 12 | var versionRE = /v[0-9]+\.[0-9]+/; 13 | var docIndex = fs.readFileSync('./docs/index.md', 'ascii'); 14 | var docVersion = docIndex.match(versionRE)[0]; 15 | bitcore.version.indexOf(docVersion).should.equal(0); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/encoding/base58.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | var bitcore = require('../..'); 5 | var buffer = require('buffer'); 6 | var Base58 = bitcore.encoding.Base58; 7 | 8 | describe('Base58', function() { 9 | var buf = new buffer.Buffer([0, 1, 2, 3, 253, 254, 255]); 10 | var enc = '1W7N4RuG'; 11 | 12 | it('should make an instance with "new"', function() { 13 | var b58 = new Base58(); 14 | should.exist(b58); 15 | }); 16 | 17 | it('validates characters with no false negatives', function() { 18 | Base58.validCharacters( 19 | '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 20 | ).should.equal(true); 21 | }); 22 | it('validates characters from buffer', function() { 23 | Base58.validCharacters( 24 | new buffer.Buffer('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz') 25 | ).should.equal(true); 26 | }); 27 | 28 | it('some characters are invalid (no false positives)', function() { 29 | Base58.validCharacters('!@#%^$&*()\\').should.equal(false); 30 | }); 31 | 32 | it('should make an instance without "new"', function() { 33 | var b58 = Base58(); 34 | should.exist(b58); 35 | }); 36 | 37 | it('should allow this handy syntax', function() { 38 | Base58(buf).toString().should.equal(enc); 39 | Base58(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')); 40 | }); 41 | 42 | describe('#set', function() { 43 | 44 | it('should set a blank buffer', function() { 45 | Base58().set({ 46 | buf: new buffer.Buffer([]) 47 | }); 48 | }); 49 | 50 | }); 51 | 52 | describe('@encode', function() { 53 | 54 | it('should encode the buffer accurately', function() { 55 | Base58.encode(buf).should.equal(enc); 56 | }); 57 | 58 | it('should throw an error when the Input is not a buffer', function() { 59 | (function() { 60 | Base58.encode('string'); 61 | }).should.throw('Input should be a buffer'); 62 | }); 63 | 64 | }); 65 | 66 | describe('@decode', function() { 67 | 68 | it('should decode this encoded value correctly', function() { 69 | Base58.decode(enc).toString('hex').should.equal(buf.toString('hex')); 70 | }); 71 | 72 | it('should throw an error when Input is not a string', function() { 73 | (function() { 74 | Base58.decode(5); 75 | }).should.throw('Input should be a string'); 76 | }); 77 | 78 | }); 79 | 80 | describe('#fromBuffer', function() { 81 | 82 | it('should not fail', function() { 83 | should.exist(Base58().fromBuffer(buf)); 84 | }); 85 | 86 | it('should set buffer', function() { 87 | var b58 = Base58().fromBuffer(buf); 88 | b58.buf.toString('hex').should.equal(buf.toString('hex')); 89 | }); 90 | 91 | }); 92 | 93 | describe('#fromString', function() { 94 | 95 | it('should convert this known string to a buffer', function() { 96 | Base58().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')); 97 | }); 98 | 99 | }); 100 | 101 | describe('#toBuffer', function() { 102 | 103 | it('should return the buffer', function() { 104 | var b58 = Base58({ 105 | buf: buf 106 | }); 107 | b58.buf.toString('hex').should.equal(buf.toString('hex')); 108 | }); 109 | 110 | }); 111 | 112 | describe('#toString', function() { 113 | 114 | it('should return the buffer', function() { 115 | var b58 = Base58({ 116 | buf: buf 117 | }); 118 | b58.toString().should.equal(enc); 119 | }); 120 | 121 | }); 122 | 123 | }); 124 | -------------------------------------------------------------------------------- /test/encoding/base58check.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | var bitcore = require('../..'); 5 | var Base58Check = bitcore.encoding.Base58Check; 6 | var Base58 = bitcore.encoding.Base58; 7 | 8 | describe('Base58Check', function() { 9 | var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]); 10 | var enc = '14HV44ipwoaqfg'; 11 | 12 | it('should make an instance with "new"', function() { 13 | var b58 = new Base58Check(); 14 | should.exist(b58); 15 | }); 16 | 17 | it('can validate a serialized string', function() { 18 | var address = '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy'; 19 | Base58Check.validChecksum(address).should.equal(true); 20 | address = address + 'a'; 21 | Base58Check.validChecksum(address).should.equal(false); 22 | }); 23 | 24 | it('should make an instance without "new"', function() { 25 | var b58 = Base58Check(); 26 | should.exist(b58); 27 | }); 28 | 29 | it('should allow this handy syntax', function() { 30 | Base58Check(buf).toString().should.equal(enc); 31 | Base58Check(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')); 32 | }); 33 | 34 | describe('#set', function() { 35 | 36 | it('should set a buf', function() { 37 | should.exist(Base58Check().set({buf: buf}).buf); 38 | }); 39 | 40 | }); 41 | 42 | describe('@encode', function() { 43 | 44 | it('should encode the buffer accurately', function() { 45 | Base58Check.encode(buf).should.equal(enc); 46 | }); 47 | 48 | it('should throw an error when the input is not a buffer', function() { 49 | (function() { 50 | Base58Check.encode('string'); 51 | }).should.throw('Input must be a buffer'); 52 | }); 53 | 54 | }); 55 | 56 | describe('@decode', function() { 57 | 58 | it('should decode this encoded value correctly', function() { 59 | Base58Check.decode(enc).toString('hex').should.equal(buf.toString('hex')); 60 | }); 61 | 62 | it('should throw an error when input is not a string', function() { 63 | (function() { 64 | Base58Check.decode(5); 65 | }).should.throw('Input must be a string'); 66 | }); 67 | 68 | it('should throw an error when input is too short', function() { 69 | (function() { 70 | Base58Check.decode(enc.slice(0, 1)); 71 | }).should.throw('Input string too short'); 72 | }); 73 | 74 | it('should throw an error when there is a checksum mismatch', function() { 75 | var buf2 = Base58.decode(enc); 76 | buf2[0] = buf2[0] + 1; 77 | var enc2 = Base58.encode(buf2); 78 | (function() { 79 | Base58Check.decode(enc2); 80 | }).should.throw('Checksum mismatch'); 81 | }); 82 | 83 | }); 84 | 85 | describe('#fromBuffer', function() { 86 | 87 | it('should not fail', function() { 88 | should.exist(Base58Check().fromBuffer(buf)); 89 | }); 90 | 91 | it('should set buffer', function() { 92 | var b58 = Base58Check().fromBuffer(buf); 93 | b58.buf.toString('hex').should.equal(buf.toString('hex')); 94 | }); 95 | 96 | }); 97 | 98 | describe('#fromString', function() { 99 | 100 | it('should convert this known string to a buffer', function() { 101 | Base58Check().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')); 102 | }); 103 | 104 | }); 105 | 106 | describe('#toBuffer', function() { 107 | 108 | it('should return the buffer', function() { 109 | var b58 = Base58Check({buf: buf}); 110 | b58.buf.toString('hex').should.equal(buf.toString('hex')); 111 | }); 112 | 113 | }); 114 | 115 | describe('#toString', function() { 116 | 117 | it('should return the buffer', function() { 118 | var b58 = Base58Check({buf: buf}); 119 | b58.toString().should.equal(enc); 120 | }); 121 | 122 | }); 123 | 124 | }); 125 | -------------------------------------------------------------------------------- /test/encoding/bufferwriter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var bitcore = require('../..'); 4 | var should = require('chai').should(); 5 | var BufferWriter = bitcore.encoding.BufferWriter; 6 | var BufferReader = bitcore.encoding.BufferReader; 7 | var BN = bitcore.crypto.BN; 8 | 9 | describe('BufferWriter', function() { 10 | 11 | it('should create a new buffer writer', function() { 12 | var bw = new BufferWriter(); 13 | should.exist(bw); 14 | }); 15 | 16 | describe('#set', function() { 17 | 18 | it('set bufs', function() { 19 | var buf1 = new Buffer([0]); 20 | var buf2 = new Buffer([1]); 21 | var bw = new BufferWriter().set({bufs: [buf1, buf2]}); 22 | bw.concat().toString('hex').should.equal('0001'); 23 | }); 24 | 25 | }); 26 | 27 | describe('#toBuffer', function() { 28 | 29 | it('should concat these two bufs', function() { 30 | var buf1 = new Buffer([0]); 31 | var buf2 = new Buffer([1]); 32 | var bw = new BufferWriter({bufs: [buf1, buf2]}); 33 | bw.toBuffer().toString('hex').should.equal('0001'); 34 | }); 35 | 36 | }); 37 | 38 | describe('#concat', function() { 39 | 40 | it('should concat these two bufs', function() { 41 | var buf1 = new Buffer([0]); 42 | var buf2 = new Buffer([1]); 43 | var bw = new BufferWriter({bufs: [buf1, buf2]}); 44 | bw.concat().toString('hex').should.equal('0001'); 45 | }); 46 | 47 | }); 48 | 49 | describe('#write', function() { 50 | 51 | it('should write a buffer', function() { 52 | var buf = new Buffer([0]); 53 | var bw = new BufferWriter(); 54 | bw.write(buf); 55 | bw.concat().toString('hex').should.equal('00'); 56 | }); 57 | 58 | }); 59 | 60 | describe('#writeUInt8', function() { 61 | 62 | it('should write 1', function() { 63 | var bw = new BufferWriter(); 64 | bw.writeUInt8(1).concat().toString('hex').should.equal('01'); 65 | }); 66 | 67 | }); 68 | 69 | describe('#writeUInt16BE', function() { 70 | 71 | it('should write 1', function() { 72 | var bw = new BufferWriter(); 73 | bw.writeUInt16BE(1).concat().toString('hex').should.equal('0001'); 74 | }); 75 | 76 | }); 77 | 78 | describe('#writeUInt16LE', function() { 79 | 80 | it('should write 1', function() { 81 | var bw = new BufferWriter(); 82 | bw.writeUInt16LE(1).concat().toString('hex').should.equal('0100'); 83 | }); 84 | 85 | }); 86 | 87 | describe('#writeUInt32BE', function() { 88 | 89 | it('should write 1', function() { 90 | var bw = new BufferWriter(); 91 | bw.writeUInt32BE(1).concat().toString('hex').should.equal('00000001'); 92 | }); 93 | 94 | }); 95 | 96 | describe('#writeUInt32LE', function() { 97 | 98 | it('should write 1', function() { 99 | var bw = new BufferWriter(); 100 | bw.writeUInt32LE(1).concat().toString('hex').should.equal('01000000'); 101 | }); 102 | 103 | }); 104 | 105 | describe('#writeUInt64BEBN', function() { 106 | 107 | it('should write 1', function() { 108 | var bw = new BufferWriter(); 109 | bw.writeUInt64BEBN(new BN(1)).concat().toString('hex').should.equal('0000000000000001'); 110 | }); 111 | 112 | }); 113 | 114 | describe('#writeUInt64LEBN', function() { 115 | 116 | it('should write 1', function() { 117 | var bw = new BufferWriter(); 118 | bw.writeUInt64LEBN(new BN(1)).concat().toString('hex').should.equal('0100000000000000'); 119 | }); 120 | 121 | }); 122 | 123 | describe('#writeVarint', function() { 124 | 125 | it('should write a 1 byte varint', function() { 126 | var bw = new BufferWriter(); 127 | bw.writeVarintNum(1); 128 | bw.concat().length.should.equal(1); 129 | }); 130 | 131 | it('should write a 3 byte varint', function() { 132 | var bw = new BufferWriter(); 133 | bw.writeVarintNum(1000); 134 | bw.concat().length.should.equal(3); 135 | }); 136 | 137 | it('should write a 5 byte varint', function() { 138 | var bw = new BufferWriter(); 139 | bw.writeVarintNum(Math.pow(2, 16 + 1)); 140 | bw.concat().length.should.equal(5); 141 | }); 142 | 143 | it('should write a 9 byte varint', function() { 144 | var bw = new BufferWriter(); 145 | bw.writeVarintNum(Math.pow(2, 32 + 1)); 146 | bw.concat().length.should.equal(9); 147 | }); 148 | 149 | it('should read back the same value it wrote for a 9 byte varint', function() { 150 | var bw = new BufferWriter(); 151 | var n = Math.pow(2, 53); 152 | n.should.equal(n + 1); //javascript number precision limit 153 | bw.writeVarintNum(n); 154 | var br = new BufferReader({buf: bw.concat()}); 155 | br.readVarintBN().toNumber().should.equal(n); 156 | }); 157 | 158 | }); 159 | 160 | describe('#writeVarintBN', function() { 161 | 162 | it('should write a 1 byte varint', function() { 163 | var bw = new BufferWriter(); 164 | bw.writeVarintBN(new BN(1)); 165 | bw.concat().length.should.equal(1); 166 | }); 167 | 168 | it('should write a 3 byte varint', function() { 169 | var bw = new BufferWriter(); 170 | bw.writeVarintBN(new BN(1000)); 171 | bw.concat().length.should.equal(3); 172 | }); 173 | 174 | it('should write a 5 byte varint', function() { 175 | var bw = new BufferWriter(); 176 | bw.writeVarintBN(new BN(Math.pow(2, 16 + 1))); 177 | bw.concat().length.should.equal(5); 178 | }); 179 | 180 | it('should write a 9 byte varint', function() { 181 | var bw = new BufferWriter(); 182 | bw.writeVarintBN(new BN(Math.pow(2, 32 + 1))); 183 | bw.concat().length.should.equal(9); 184 | }); 185 | 186 | }); 187 | 188 | }); 189 | -------------------------------------------------------------------------------- /test/encoding/varint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | var bitcore = require('../..'); 5 | var BN = bitcore.crypto.BN; 6 | var BufferReader = bitcore.encoding.BufferReader; 7 | var BufferWriter = bitcore.encoding.BufferWriter; 8 | var Varint = bitcore.encoding.Varint; 9 | 10 | describe('Varint', function() { 11 | 12 | it('should make a new varint', function() { 13 | var buf = new Buffer('00', 'hex'); 14 | var varint = new Varint(buf); 15 | should.exist(varint); 16 | varint.buf.toString('hex').should.equal('00'); 17 | varint = Varint(buf); 18 | should.exist(varint); 19 | varint.buf.toString('hex').should.equal('00'); 20 | 21 | //various ways to use the constructor 22 | Varint(Varint(0).toBuffer()).toNumber().should.equal(0); 23 | Varint(0).toNumber().should.equal(0); 24 | Varint(new BN(0)).toNumber().should.equal(0); 25 | }); 26 | 27 | describe('#set', function() { 28 | 29 | it('should set a buffer', function() { 30 | var buf = new Buffer('00', 'hex'); 31 | var varint = Varint().set({buf: buf}); 32 | varint.buf.toString('hex').should.equal('00'); 33 | varint.set({}); 34 | varint.buf.toString('hex').should.equal('00'); 35 | }); 36 | 37 | }); 38 | 39 | describe('#fromString', function() { 40 | 41 | it('should set a buffer', function() { 42 | var buf = BufferWriter().writeVarintNum(5).concat(); 43 | var varint = Varint().fromString(buf.toString('hex')); 44 | varint.toNumber().should.equal(5); 45 | }); 46 | 47 | }); 48 | 49 | describe('#toString', function() { 50 | 51 | it('should return a buffer', function() { 52 | var buf = BufferWriter().writeVarintNum(5).concat(); 53 | var varint = Varint().fromString(buf.toString('hex')); 54 | varint.toString().should.equal('05'); 55 | }); 56 | 57 | }); 58 | 59 | describe('#fromBuffer', function() { 60 | 61 | it('should set a buffer', function() { 62 | var buf = BufferWriter().writeVarintNum(5).concat(); 63 | var varint = Varint().fromBuffer(buf); 64 | varint.toNumber().should.equal(5); 65 | }); 66 | 67 | }); 68 | 69 | describe('#fromBufferReader', function() { 70 | 71 | it('should set a buffer reader', function() { 72 | var buf = BufferWriter().writeVarintNum(5).concat(); 73 | var br = BufferReader(buf); 74 | var varint = Varint().fromBufferReader(br); 75 | varint.toNumber().should.equal(5); 76 | }); 77 | 78 | }); 79 | 80 | describe('#fromBN', function() { 81 | 82 | it('should set a number', function() { 83 | var varint = Varint().fromBN(new BN(5)); 84 | varint.toNumber().should.equal(5); 85 | }); 86 | 87 | }); 88 | 89 | describe('#fromNumber', function() { 90 | 91 | it('should set a number', function() { 92 | var varint = Varint().fromNumber(5); 93 | varint.toNumber().should.equal(5); 94 | }); 95 | 96 | }); 97 | 98 | describe('#toBuffer', function() { 99 | 100 | it('should return a buffer', function() { 101 | var buf = BufferWriter().writeVarintNum(5).concat(); 102 | var varint = Varint(buf); 103 | varint.toBuffer().toString('hex').should.equal(buf.toString('hex')); 104 | }); 105 | 106 | }); 107 | 108 | describe('#toBN', function() { 109 | 110 | it('should return a buffer', function() { 111 | var varint = Varint(5); 112 | varint.toBN().toString().should.equal(new BN(5).toString()); 113 | }); 114 | 115 | }); 116 | 117 | describe('#toNumber', function() { 118 | 119 | it('should return a buffer', function() { 120 | var varint = Varint(5); 121 | varint.toNumber().should.equal(5); 122 | }); 123 | 124 | }); 125 | 126 | }); 127 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var should = require("chai").should(); 4 | var bitcore = require("../"); 5 | 6 | describe('#versionGuard', function() { 7 | it('global._bitcore should be defined', function() { 8 | should.equal(global._bitcore, bitcore.version); 9 | }); 10 | 11 | it('throw an error if version is already defined', function() { 12 | (function() { 13 | bitcore.versionGuard('version'); 14 | }).should.throw('More than one instance of bitcore'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --recursive 2 | --timeout 5000 3 | -------------------------------------------------------------------------------- /test/networks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var expect = require('chai').expect; 4 | var should = require('chai').should(); 5 | var bitcore = require('..'); 6 | var networks = bitcore.Networks; 7 | 8 | describe('Networks', function() { 9 | 10 | var customnet; 11 | 12 | it('should contain all Networks', function() { 13 | should.exist(networks.livenet); 14 | should.exist(networks.testnet); 15 | should.exist(networks.defaultNetwork); 16 | }); 17 | 18 | it('will enable/disable regtest Network', function() { 19 | networks.enableRegtest(); 20 | networks.testnet.networkMagic.should.deep.equal(new Buffer('fabfb5da', 'hex')); 21 | networks.testnet.port.should.equal(18444); 22 | networks.testnet.dnsSeeds.should.deep.equal([]); 23 | networks.testnet.regtestEnabled.should.equal(true); 24 | 25 | networks.disableRegtest(); 26 | networks.testnet.networkMagic.should.deep.equal(new Buffer('0b110907', 'hex')); 27 | networks.testnet.port.should.equal(18333); 28 | networks.testnet.dnsSeeds.should.deep.equal([ 29 | 'testnet-seed.bitcoin.petertodd.org', 30 | 'testnet-seed.bluematt.me', 31 | 'testnet-seed.alexykot.me', 32 | 'testnet-seed.bitcoin.schildbach.de' 33 | ]); 34 | }); 35 | 36 | it('will get network based on string "regtest" value', function() { 37 | var network = networks.get('regtest'); 38 | network.should.equal(networks.testnet); 39 | }); 40 | 41 | it('should be able to define a custom Network', function() { 42 | var custom = { 43 | name: 'customnet', 44 | alias: 'mynet', 45 | pubkeyhash: 0x10, 46 | privatekey: 0x90, 47 | scripthash: 0x08, 48 | xpubkey: 0x0278b20e, 49 | xprivkey: 0x0278ade4, 50 | networkMagic: 0xe7beb4d4, 51 | port: 20001, 52 | dnsSeeds: [ 53 | 'localhost', 54 | 'mynet.localhost' 55 | ] 56 | }; 57 | networks.add(custom); 58 | customnet = networks.get('customnet'); 59 | for (var key in custom) { 60 | if (key !== 'networkMagic') { 61 | customnet[key].should.equal(custom[key]); 62 | } else { 63 | var expected = new Buffer('e7beb4d4', 'hex'); 64 | customnet[key].should.deep.equal(expected); 65 | } 66 | } 67 | }); 68 | 69 | it('can remove a custom network', function() { 70 | networks.remove(customnet); 71 | var net = networks.get('customnet'); 72 | should.equal(net, undefined); 73 | }); 74 | 75 | it('should not set a network map for an undefined value', function() { 76 | var custom = { 77 | name: 'somenet', 78 | pubkeyhash: 0x13, 79 | privatekey: 0x93, 80 | scripthash: 0x11, 81 | xpubkey: 0x0278b20f, 82 | xprivkey: 0x0278ade5, 83 | networkMagic: 0xe7beb4d5, 84 | port: 20008, 85 | dnsSeeds: [ 86 | 'somenet.localhost' 87 | ] 88 | }; 89 | networks.add(custom); 90 | var network = networks.get(undefined); 91 | should.not.exist(network); 92 | var somenet = networks.get('somenet'); 93 | should.exist(somenet); 94 | somenet.name.should.equal('somenet'); 95 | networks.remove(somenet); 96 | }); 97 | 98 | var constants = ['name', 'alias', 'pubkeyhash', 'scripthash', 'xpubkey', 'xprivkey']; 99 | 100 | constants.forEach(function(key){ 101 | it('should have constant '+key+' for livenet and testnet', function(){ 102 | networks.testnet.hasOwnProperty(key).should.equal(true); 103 | networks.livenet.hasOwnProperty(key).should.equal(true); 104 | }); 105 | }); 106 | 107 | it('tests only for the specified key', function() { 108 | expect(networks.get(0x6f, 'pubkeyhash')).to.equal(networks.testnet); 109 | expect(networks.get(0x6f, 'privatekey')).to.equal(undefined); 110 | }); 111 | 112 | it('can test for multiple keys', function() { 113 | expect(networks.get(0x6f, ['pubkeyhash', 'scripthash'])).to.equal(networks.testnet); 114 | expect(networks.get(0xc4, ['pubkeyhash', 'scripthash'])).to.equal(networks.testnet); 115 | expect(networks.get(0x6f, ['privatekey', 'port'])).to.equal(undefined); 116 | }); 117 | 118 | it('converts to string using the "name" property', function() { 119 | networks.livenet.toString().should.equal('livenet'); 120 | }); 121 | 122 | it('network object should be immutable', function() { 123 | expect(networks.testnet.name).to.equal('testnet') 124 | var fn = function() { networks.testnet.name = 'livenet' } 125 | expect(fn).to.throw(TypeError) 126 | }); 127 | 128 | }); 129 | -------------------------------------------------------------------------------- /test/opcode.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var chai = require('chai'); 5 | var should = chai.should(); 6 | var expect = chai.expect; 7 | var bitcore = require('..'); 8 | var Opcode = bitcore.Opcode; 9 | 10 | describe('Opcode', function() { 11 | 12 | it('should create a new Opcode', function() { 13 | var opcode = new Opcode(5); 14 | should.exist(opcode); 15 | }); 16 | 17 | it('should convert to a string with this handy syntax', function() { 18 | Opcode(0).toString().should.equal('OP_0'); 19 | Opcode(96).toString().should.equal('OP_16'); 20 | Opcode(97).toString().should.equal('OP_NOP'); 21 | }); 22 | 23 | it('should convert to a number with this handy syntax', function() { 24 | Opcode('OP_0').toNumber().should.equal(0); 25 | Opcode('OP_16').toNumber().should.equal(96); 26 | Opcode('OP_NOP').toNumber().should.equal(97); 27 | }); 28 | 29 | describe('#fromNumber', function() { 30 | it('should work for 0', function() { 31 | Opcode.fromNumber(0).num.should.equal(0); 32 | }); 33 | it('should fail for non-number', function() { 34 | Opcode.fromNumber.bind(null, 'a string').should.throw('Invalid Argument'); 35 | }); 36 | }); 37 | 38 | describe('#set', function() { 39 | it('should work for object', function() { 40 | Opcode(42).num.should.equal(42); 41 | }); 42 | it('should fail for empty-object', function() { 43 | expect(function() { 44 | Opcode(); 45 | }).to.throw(TypeError); 46 | }); 47 | }); 48 | 49 | describe('#toNumber', function() { 50 | it('should work for 0', function() { 51 | Opcode.fromNumber(0).toNumber().should.equal(0); 52 | }); 53 | }); 54 | 55 | describe('#buffer', function() { 56 | it('should correctly input/output a buffer', function() { 57 | var buf = new Buffer('a6', 'hex'); 58 | Opcode.fromBuffer(buf).toBuffer().should.deep.equal(buf); 59 | }); 60 | }); 61 | 62 | describe('#fromString', function() { 63 | it('should work for OP_0', function() { 64 | Opcode.fromString('OP_0').num.should.equal(0); 65 | }); 66 | it('should fail for invalid string', function() { 67 | Opcode.fromString.bind(null, 'OP_SATOSHI').should.throw('Invalid opcodestr'); 68 | Opcode.fromString.bind(null, 'BANANA').should.throw('Invalid opcodestr'); 69 | }); 70 | it('should fail for non-string', function() { 71 | Opcode.fromString.bind(null, 123).should.throw('Invalid Argument'); 72 | }); 73 | }); 74 | 75 | describe('#toString', function() { 76 | it('should work for OP_0', function() { 77 | Opcode.fromString('OP_0').toString().should.equal('OP_0'); 78 | }); 79 | 80 | it('should not work for non-opcode', function() { 81 | expect(function(){ 82 | Opcode('OP_NOTACODE').toString(); 83 | }).to.throw('Opcode does not have a string representation'); 84 | }); 85 | }); 86 | 87 | describe('@map', function() { 88 | it('should have a map containing 118 elements', function() { 89 | _.size(Opcode.map).should.equal(118); 90 | }); 91 | }); 92 | 93 | describe('@reverseMap', function() { 94 | it('should exist and have op 185', function() { 95 | should.exist(Opcode.reverseMap); 96 | Opcode.reverseMap[185].should.equal('OP_NOP10'); 97 | }); 98 | }); 99 | var smallints = [ 100 | Opcode('OP_0'), 101 | Opcode('OP_1'), 102 | Opcode('OP_2'), 103 | Opcode('OP_3'), 104 | Opcode('OP_4'), 105 | Opcode('OP_5'), 106 | Opcode('OP_6'), 107 | Opcode('OP_7'), 108 | Opcode('OP_8'), 109 | Opcode('OP_9'), 110 | Opcode('OP_10'), 111 | Opcode('OP_11'), 112 | Opcode('OP_12'), 113 | Opcode('OP_13'), 114 | Opcode('OP_14'), 115 | Opcode('OP_15'), 116 | Opcode('OP_16') 117 | ]; 118 | 119 | describe('@smallInt', function() { 120 | var testSmallInt = function(n, op) { 121 | Opcode.smallInt(n).toString().should.equal(op.toString()); 122 | }; 123 | 124 | for (var i = 0; i < smallints.length; i++) { 125 | var op = smallints[i]; 126 | it('should work for small int ' + op, testSmallInt.bind(null, i, op)); 127 | } 128 | 129 | it('with not number', function () { 130 | Opcode.smallInt.bind(null, '2').should.throw('Invalid Argument'); 131 | }); 132 | 133 | it('with n equal -1', function () { 134 | Opcode.smallInt.bind(null, -1).should.throw('Invalid Argument'); 135 | }); 136 | 137 | it('with n equal 17', function () { 138 | Opcode.smallInt.bind(null, 17).should.throw('Invalid Argument'); 139 | }); 140 | }); 141 | describe('@isSmallIntOp', function() { 142 | var testIsSmallInt = function(op) { 143 | Opcode.isSmallIntOp(op).should.equal(true); 144 | }; 145 | for (var i = 0; i < smallints.length; i++) { 146 | var op = smallints[i]; 147 | it('should work for small int ' + op, testIsSmallInt.bind(null, op)); 148 | } 149 | 150 | it('should work for non-small ints', function() { 151 | Opcode.isSmallIntOp(Opcode('OP_RETURN')).should.equal(false); 152 | Opcode.isSmallIntOp(Opcode('OP_CHECKSIG')).should.equal(false); 153 | Opcode.isSmallIntOp(Opcode('OP_IF')).should.equal(false); 154 | Opcode.isSmallIntOp(Opcode('OP_NOP')).should.equal(false); 155 | }); 156 | 157 | }); 158 | 159 | describe('#inspect', function() { 160 | it('should output opcode by name, hex, and decimal', function() { 161 | Opcode.fromString('OP_NOP').inspect().should.equal(''); 162 | }); 163 | }); 164 | 165 | }); 166 | -------------------------------------------------------------------------------- /test/transaction/deserialize.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Transaction = require('../../lib/transaction'); 4 | 5 | var vectors_valid = require('../data/bitcoind/tx_valid.json'); 6 | var vectors_invalid = require('../data/bitcoind/tx_invalid.json'); 7 | 8 | describe('Transaction deserialization', function() { 9 | 10 | describe('valid transaction test case', function() { 11 | var index = 0; 12 | vectors_valid.forEach(function(vector) { 13 | it('vector #' + index, function() { 14 | if (vector.length > 1) { 15 | var hexa = vector[1]; 16 | Transaction(hexa).serialize(true).should.equal(hexa); 17 | index++; 18 | } 19 | }); 20 | }); 21 | }); 22 | describe('invalid transaction test case', function() { 23 | var index = 0; 24 | vectors_invalid.forEach(function(vector) { 25 | it('invalid vector #' + index, function() { 26 | if (vector.length > 1) { 27 | var hexa = vector[1]; 28 | Transaction(hexa).serialize(true).should.equal(hexa); 29 | index++; 30 | } 31 | }); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/transaction/input/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | var expect = require('chai').expect; 5 | var _ = require('lodash'); 6 | 7 | var bitcore = require('../../..'); 8 | var errors = bitcore.errors; 9 | var PrivateKey = bitcore.PrivateKey; 10 | var Address = bitcore.Address; 11 | var Script = bitcore.Script; 12 | var Networks = bitcore.Networks; 13 | var Input = bitcore.Transaction.Input; 14 | 15 | describe('Transaction.Input', function() { 16 | 17 | var privateKey = new PrivateKey('KwF9LjRraetZuEjR8VqEq539z137LW5anYDUnVK11vM3mNMHTWb4'); 18 | var publicKey = privateKey.publicKey; 19 | var address = new Address(publicKey, Networks.livenet); 20 | var output = { 21 | address: '33zbk2aSZYdNbRsMPPt6jgy6Kq1kQreqeb', 22 | prevTxId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140', 23 | outputIndex: 0, 24 | script: new Script(address), 25 | satoshis: 1000000 26 | }; 27 | var coinbase = { 28 | prevTxId: '0000000000000000000000000000000000000000000000000000000000000000', 29 | outputIndex: 0xFFFFFFFF, 30 | script: new Script(), 31 | satoshis: 1000000 32 | }; 33 | 34 | var coinbaseJSON = JSON.stringify({ 35 | prevTxId: '0000000000000000000000000000000000000000000000000000000000000000', 36 | outputIndex: 4294967295, 37 | script:'' 38 | }); 39 | 40 | var otherJSON = JSON.stringify({ 41 | txidbuf: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', 42 | txoutnum: 0, 43 | seqnum:4294967295, 44 | script: '71 0x3044022006553276ec5b885ddf5cc1d79e1e3dadbb404b60ad4cc00318e21565' + 45 | '4f13242102200757c17b36e3d0492fb9cf597032e5afbea67a59274e64af5a05d12e5ea2303901 ' + 46 | '33 0x0223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5e', 47 | output: { 48 | 'satoshis':100000, 49 | 'script':'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a ' + 50 | 'OP_EQUALVERIFY OP_CHECKSIG' 51 | } 52 | }); 53 | 54 | it('has abstract methods: "getSignatures", "isFullySigned", "addSignature", "clearSignatures"', function() { 55 | var input = new Input(output); 56 | _.each(['getSignatures', 'isFullySigned', 'addSignature', 'clearSignatures'], function(method) { 57 | expect(function() { 58 | return input[method](); 59 | }).to.throw(errors.AbstractMethodInvoked); 60 | }); 61 | }); 62 | it('detects coinbase transactions', function() { 63 | new Input(output).isNull().should.equal(false); 64 | var ci = new Input(coinbase); 65 | ci.isNull().should.equal(true); 66 | }); 67 | 68 | describe('instantiation', function() { 69 | it('works without new', function() { 70 | var input = Input(); 71 | should.exist(input); 72 | }); 73 | it('fails with no script info', function() { 74 | expect(function() { 75 | var input = new Input({}); 76 | input.toString(); 77 | }).to.throw('Need a script to create an input'); 78 | }); 79 | it('fromObject should work', function() { 80 | var jsonData = JSON.parse(coinbaseJSON); 81 | var input = Input.fromObject(jsonData); 82 | should.exist(input); 83 | input.prevTxId.toString('hex').should.equal(jsonData.prevTxId); 84 | input.outputIndex.should.equal(jsonData.outputIndex); 85 | }); 86 | it('fromObject should work', function() { 87 | var input = Input.fromObject(JSON.parse(coinbaseJSON)); 88 | var obj = input.toObject(); 89 | Input.fromObject(obj).should.deep.equal(input); 90 | obj.script = 42; 91 | Input.fromObject.bind(null, obj).should.throw('Invalid argument type: script'); 92 | }); 93 | }); 94 | 95 | it('_estimateSize returns correct size', function() { 96 | var input = new Input(output); 97 | input._estimateSize().should.equal(66); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /test/transaction/input/publickey.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | var bitcore = require('../../..'); 5 | var Transaction = bitcore.Transaction; 6 | var PrivateKey = bitcore.PrivateKey; 7 | 8 | describe('PublicKeyInput', function() { 9 | 10 | var utxo = { 11 | txid: '7f3b688cb224ed83e12d9454145c26ac913687086a0a62f2ae0bc10934a4030f', 12 | vout: 0, 13 | address: 'n4McBrSkw42eYGX5YMACGpkGUJKL3jVSbo', 14 | scriptPubKey: '2103c9594cb2ebfebcb0cfd29eacd40ba012606a197beef76f0269ed8c101e56ceddac', 15 | amount: 50, 16 | confirmations: 104, 17 | spendable: true 18 | }; 19 | var privateKey = PrivateKey.fromWIF('cQ7tSSQDEwaxg9usnnP1Aztqvm9nCQVfNWz9kU2rdocDjknF2vd6'); 20 | var address = privateKey.toAddress(); 21 | utxo.address.should.equal(address.toString()); 22 | 23 | var destKey = new PrivateKey(); 24 | 25 | it('will correctly sign a publickey out transaction', function() { 26 | var tx = new Transaction(); 27 | tx.from(utxo); 28 | tx.to(destKey.toAddress(), 10000); 29 | tx.sign(privateKey); 30 | tx.inputs[0].script.toBuffer().length.should.be.above(0); 31 | }); 32 | 33 | it('count can count missing signatures', function() { 34 | var tx = new Transaction(); 35 | tx.from(utxo); 36 | tx.to(destKey.toAddress(), 10000); 37 | var input = tx.inputs[0]; 38 | input.isFullySigned().should.equal(false); 39 | tx.sign(privateKey); 40 | input.isFullySigned().should.equal(true); 41 | }); 42 | 43 | it('it\'s size can be estimated', function() { 44 | var tx = new Transaction(); 45 | tx.from(utxo); 46 | tx.to(destKey.toAddress(), 10000); 47 | var input = tx.inputs[0]; 48 | input._estimateSize().should.equal(73); 49 | }); 50 | 51 | it('it\'s signature can be removed', function() { 52 | var tx = new Transaction(); 53 | tx.from(utxo); 54 | tx.to(destKey.toAddress(), 10000); 55 | var input = tx.inputs[0]; 56 | tx.sign(privateKey); 57 | input.isFullySigned().should.equal(true); 58 | input.clearSignatures(); 59 | input.isFullySigned().should.equal(false); 60 | }); 61 | 62 | it('returns an empty array if private key mismatches', function() { 63 | var tx = new Transaction(); 64 | tx.from(utxo); 65 | tx.to(destKey.toAddress(), 10000); 66 | var input = tx.inputs[0]; 67 | var signatures = input.getSignatures(tx, new PrivateKey(), 0); 68 | signatures.length.should.equal(0); 69 | }); 70 | 71 | }); 72 | -------------------------------------------------------------------------------- /test/transaction/input/publickeyhash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* jshint unused: false */ 3 | 4 | var should = require('chai').should(); 5 | var expect = require('chai').expect; 6 | var _ = require('lodash'); 7 | 8 | var bitcore = require('../../..'); 9 | var Transaction = bitcore.Transaction; 10 | var PrivateKey = bitcore.PrivateKey; 11 | var Address = bitcore.Address; 12 | var Script = bitcore.Script; 13 | var Networks = bitcore.Networks; 14 | var Signature = bitcore.crypto.Signature; 15 | 16 | describe('PublicKeyHashInput', function() { 17 | 18 | var privateKey = new PrivateKey('KwF9LjRraetZuEjR8VqEq539z137LW5anYDUnVK11vM3mNMHTWb4'); 19 | var publicKey = privateKey.publicKey; 20 | var address = new Address(publicKey, Networks.livenet); 21 | 22 | var output = { 23 | address: '33zbk2aSZYdNbRsMPPt6jgy6Kq1kQreqeb', 24 | txId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140', 25 | outputIndex: 0, 26 | script: new Script(address), 27 | satoshis: 1000000 28 | }; 29 | it('can count missing signatures', function() { 30 | var transaction = new Transaction() 31 | .from(output) 32 | .to(address, 1000000); 33 | var input = transaction.inputs[0]; 34 | 35 | input.isFullySigned().should.equal(false); 36 | transaction.sign(privateKey); 37 | input.isFullySigned().should.equal(true); 38 | }); 39 | it('it\'s size can be estimated', function() { 40 | var transaction = new Transaction() 41 | .from(output) 42 | .to(address, 1000000); 43 | var input = transaction.inputs[0]; 44 | input._estimateSize().should.equal(107); 45 | }); 46 | it('it\'s signature can be removed', function() { 47 | var transaction = new Transaction() 48 | .from(output) 49 | .to(address, 1000000); 50 | var input = transaction.inputs[0]; 51 | 52 | transaction.sign(privateKey); 53 | input.clearSignatures(); 54 | input.isFullySigned().should.equal(false); 55 | }); 56 | it('returns an empty array if private key mismatches', function() { 57 | var transaction = new Transaction() 58 | .from(output) 59 | .to(address, 1000000); 60 | var input = transaction.inputs[0]; 61 | var signatures = input.getSignatures(transaction, new PrivateKey(), 0); 62 | signatures.length.should.equal(0); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /test/transaction/sighash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var buffer = require('buffer'); 4 | 5 | var chai = require('chai'); 6 | var should = chai.should(); 7 | var bitcore = require('../../'); 8 | var Script = bitcore.Script; 9 | var Transaction = bitcore.Transaction; 10 | var sighash = Transaction.sighash; 11 | 12 | var vectors_sighash = require('../data/sighash.json'); 13 | 14 | describe('sighash', function() { 15 | 16 | vectors_sighash.forEach(function(vector, i) { 17 | if (i === 0) { 18 | // First element is just a row describing the next ones 19 | return; 20 | } 21 | it('test vector from bitcoind #' + i + ' (' + vector[4].substring(0, 16) + ')', function() { 22 | var txbuf = new buffer.Buffer(vector[0], 'hex'); 23 | var scriptbuf = new buffer.Buffer(vector[1], 'hex'); 24 | var subscript = Script(scriptbuf); 25 | var nin = vector[2]; 26 | var nhashtype = vector[3]; 27 | var sighashbuf = new buffer.Buffer(vector[4], 'hex'); 28 | var tx = new Transaction(txbuf); 29 | 30 | //make sure transacion to/from buffer is isomorphic 31 | tx.uncheckedSerialize().should.equal(txbuf.toString('hex')); 32 | 33 | //sighash ought to be correct 34 | sighash.sighash(tx, nhashtype, nin, subscript).toString('hex').should.equal(sighashbuf.toString('hex')); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/transaction/sighashwitness.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai'); 4 | var should = chai.should(); 5 | var bitcore = require('../../'); 6 | var Transaction = bitcore.Transaction; 7 | var Signature = bitcore.crypto.Signature; 8 | var SighashWitness = Transaction.SighashWitness; 9 | 10 | describe('Sighash Witness Program Version 0', function() { 11 | 12 | it('should create hash for sighash all', function() { 13 | // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki 14 | var unsignedTx = bitcore.Transaction('0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000'); 15 | 16 | var scriptCode = new Buffer('1976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac', 'hex'); 17 | var satoshisBuffer = new Buffer('0046c32300000000', 'hex'); 18 | 19 | var hash = SighashWitness.sighash(unsignedTx, Signature.SIGHASH_ALL, 1, scriptCode, satoshisBuffer); 20 | 21 | hash.toString('hex').should.equal('c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670'); 22 | }); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/transaction/signature.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint unused: false */ 4 | /* jshint latedef: false */ 5 | var should = require('chai').should(); 6 | var expect = require('chai').expect; 7 | var _ = require('lodash'); 8 | 9 | var bitcore = require('../..'); 10 | var Transaction = bitcore.Transaction; 11 | var TransactionSignature = bitcore.Transaction.Signature; 12 | var Script = bitcore.Script; 13 | var PrivateKey = bitcore.PrivateKey; 14 | var errors = bitcore.errors; 15 | 16 | describe('TransactionSignature', function() { 17 | 18 | var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1'; 19 | var privateKey = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY'; 20 | var simpleUtxoWith100000Satoshis = { 21 | address: fromAddress, 22 | txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', 23 | outputIndex: 0, 24 | script: Script.buildPublicKeyHashOut(fromAddress).toString(), 25 | satoshis: 100000 26 | }; 27 | 28 | var getSignatureFromTransaction = function() { 29 | var transaction = new Transaction(); 30 | transaction.from(simpleUtxoWith100000Satoshis); 31 | return transaction.getSignatures(privateKey)[0]; 32 | }; 33 | 34 | it('can be created without the `new` keyword', function() { 35 | var signature = getSignatureFromTransaction(); 36 | var serialized = signature.toObject(); 37 | var nonew = TransactionSignature(serialized); 38 | expect(nonew.toObject()).to.deep.equal(serialized); 39 | }); 40 | 41 | it('can be retrieved from Transaction#getSignatures', function() { 42 | var signature = getSignatureFromTransaction(); 43 | expect(signature instanceof TransactionSignature).to.equal(true); 44 | }); 45 | 46 | it('fails when trying to create from invalid arguments', function() { 47 | expect(function() { 48 | return new TransactionSignature(); 49 | }).to.throw(errors.InvalidArgument); 50 | expect(function() { 51 | return new TransactionSignature(1); 52 | }).to.throw(errors.InvalidArgument); 53 | expect(function() { 54 | return new TransactionSignature('hello world'); 55 | }).to.throw(errors.InvalidArgument); 56 | }); 57 | it('returns the same object if called with a TransactionSignature', function() { 58 | var signature = getSignatureFromTransaction(); 59 | expect(new TransactionSignature(signature)).to.equal(signature); 60 | }); 61 | 62 | it('gets returned by a P2SH multisig output', function() { 63 | var private1 = new PrivateKey('6ce7e97e317d2af16c33db0b9270ec047a91bff3eff8558afb5014afb2bb5976'); 64 | var private2 = new PrivateKey('c9b26b0f771a0d2dad88a44de90f05f416b3b385ff1d989343005546a0032890'); 65 | var public1 = private1.publicKey; 66 | var public2 = private2.publicKey; 67 | var utxo = { 68 | txId: '0000000000000000000000000000000000000000000000000000000000000000', // Not relevant 69 | outputIndex: 0, 70 | script: Script.buildMultisigOut([public1, public2], 2).toScriptHashOut(), 71 | satoshis: 100000 72 | }; 73 | var transaction = new Transaction().from(utxo, [public1, public2], 2); 74 | var signatures = transaction.getSignatures(private1); 75 | expect(signatures[0] instanceof TransactionSignature).to.equal(true); 76 | signatures = transaction.getSignatures(private2); 77 | expect(signatures[0] instanceof TransactionSignature).to.equal(true); 78 | }); 79 | 80 | it('can be aplied to a Transaction with Transaction#addSignature', function() { 81 | var transaction = new Transaction(); 82 | transaction.from(simpleUtxoWith100000Satoshis); 83 | var signature = transaction.getSignatures(privateKey)[0]; 84 | var addSignature = function() { 85 | return transaction.applySignature(signature); 86 | }; 87 | expect(signature instanceof TransactionSignature).to.equal(true); 88 | expect(addSignature).to.not.throw(); 89 | }); 90 | 91 | describe('serialization', function() { 92 | it('serializes to an object and roundtrips correctly', function() { 93 | var signature = getSignatureFromTransaction(); 94 | var serialized = signature.toObject(); 95 | expect(new TransactionSignature(serialized).toObject()).to.deep.equal(serialized); 96 | }); 97 | 98 | it('can be deserialized with fromObject', function() { 99 | var signature = getSignatureFromTransaction(); 100 | var serialized = signature.toObject(); 101 | expect(TransactionSignature.fromObject(serialized).toObject()).to.deep.equal(serialized); 102 | }); 103 | 104 | it('can deserialize when signature is a buffer', function() { 105 | var signature = getSignatureFromTransaction(); 106 | var serialized = signature.toObject(); 107 | serialized.signature = new Buffer(serialized.signature, 'hex'); 108 | expect(TransactionSignature.fromObject(serialized).toObject()).to.deep.equal(signature.toObject()); 109 | }); 110 | 111 | it('can roundtrip to/from json', function() { 112 | var signature = getSignatureFromTransaction(); 113 | var serialized = signature.toObject(); 114 | var json = JSON.stringify(signature); 115 | expect(TransactionSignature(JSON.parse(json)).toObject()).to.deep.equal(serialized); 116 | expect(TransactionSignature.fromObject(JSON.parse(json)).toObject()).to.deep.equal(serialized); 117 | }); 118 | 119 | it('can parse a previously known json string', function() { 120 | var str = JSON.stringify(TransactionSignature(JSON.parse(testJSON))); 121 | expect(JSON.parse(str)).to.deep.equal(JSON.parse(testJSON)); 122 | }); 123 | 124 | it('can deserialize a previously known object', function() { 125 | expect(TransactionSignature(testObject).toObject()).to.deep.equal(testObject); 126 | }); 127 | }); 128 | 129 | /* jshint maxlen: 500 */ 130 | var testJSON = '{"publicKey":"0223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5e","prevTxId":"a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458","outputIndex":0,"inputIndex":0,"signature":"3045022100c728eac064154edba15d4f3e6cbd9be6da3498f80a783ab3391f992b4d9d71ca0220729eff4564dc06aa1d80ab73100540fe5ebb6f280b4a87bc32399f861a7b2563","sigtype":1}'; 131 | var testObject = JSON.parse(testJSON); 132 | 133 | }); 134 | -------------------------------------------------------------------------------- /test/transaction/unspentoutput.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var chai = require('chai'); 5 | var should = chai.should(); 6 | var expect = chai.expect; 7 | 8 | var bitcore = require('../..'); 9 | var UnspentOutput = bitcore.Transaction.UnspentOutput; 10 | 11 | describe('UnspentOutput', function() { 12 | 13 | var sampleData1 = { 14 | 'address': 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1', 15 | 'txId': 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', 16 | 'outputIndex': 0, 17 | 'script': 'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG', 18 | 'satoshis': 1020000 19 | }; 20 | var sampleData2 = { 21 | 'txid': 'e42447187db5a29d6db161661e4bc66d61c3e499690fe5ea47f87b79ca573986', 22 | 'vout': 1, 23 | 'address': 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up', 24 | 'scriptPubKey': '76a914073b7eae2823efa349e3b9155b8a735526463a0f88ac', 25 | 'amount': 0.01080000 26 | }; 27 | 28 | it('roundtrip from raw data', function() { 29 | expect(UnspentOutput(sampleData2).toObject()).to.deep.equal(sampleData2); 30 | }); 31 | 32 | it('can be created without "new" operand', function() { 33 | expect(UnspentOutput(sampleData1) instanceof UnspentOutput).to.equal(true); 34 | }); 35 | 36 | it('fails if no tx id is provided', function() { 37 | expect(function() { 38 | return new UnspentOutput({}); 39 | }).to.throw(); 40 | }); 41 | 42 | it('fails if vout is not a number', function() { 43 | var sample = _.cloneDeep(sampleData2); 44 | sample.vout = '1'; 45 | expect(function() { 46 | return new UnspentOutput(sample); 47 | }).to.throw(); 48 | }); 49 | 50 | it('displays nicely on the console', function() { 51 | var expected = ''; 53 | expect(new UnspentOutput(sampleData1).inspect()).to.equal(expected); 54 | }); 55 | 56 | describe('checking the constructor parameters', function() { 57 | var notDefined = { 58 | 'txId': 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', 59 | 'outputIndex': 0, 60 | 'script': 'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG', 61 | }; 62 | var zero = { 63 | 'txId': 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', 64 | 'outputIndex': 0, 65 | 'script': 'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG', 66 | 'amount': 0 67 | }; 68 | it('fails when no amount is defined', function() { 69 | expect(function() { 70 | return new UnspentOutput(notDefined); 71 | }).to.throw('Must provide an amount for the output'); 72 | }); 73 | it('does not fail when amount is zero', function() { 74 | expect(function() { 75 | return new UnspentOutput(zero); 76 | }).to.not.throw(); 77 | }); 78 | }); 79 | 80 | it('toString returns txid:vout', function() { 81 | var expected = 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458:0'; 82 | expect(new UnspentOutput(sampleData1).toString()).to.equal(expected); 83 | }); 84 | 85 | it('to/from JSON roundtrip', function() { 86 | var utxo = new UnspentOutput(sampleData2); 87 | var obj = UnspentOutput.fromObject(utxo.toJSON()).toObject(); 88 | expect(obj).to.deep.equal(sampleData2); 89 | var str = JSON.stringify(UnspentOutput.fromObject(obj)); 90 | expect(JSON.parse(str)).to.deep.equal(sampleData2); 91 | var str2 = JSON.stringify(new UnspentOutput(JSON.parse(str))); 92 | expect(JSON.parse(str2)).to.deep.equal(sampleData2); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /test/unit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | var expect = require('chai').expect; 5 | 6 | var bitcore = require('..'); 7 | var errors = bitcore.errors; 8 | var Unit = bitcore.Unit; 9 | 10 | describe('Unit', function() { 11 | 12 | it('can be created from a number and unit', function() { 13 | expect(function() { 14 | return new Unit(1.2, 'BTC'); 15 | }).to.not.throw(); 16 | }); 17 | 18 | it('can be created from a number and exchange rate', function() { 19 | expect(function() { 20 | return new Unit(1.2, 350); 21 | }).to.not.throw(); 22 | }); 23 | 24 | it('no "new" is required for creating an instance', function() { 25 | expect(function() { 26 | return Unit(1.2, 'BTC'); 27 | }).to.not.throw(); 28 | 29 | expect(function() { 30 | return Unit(1.2, 350); 31 | }).to.not.throw(); 32 | }); 33 | 34 | it('has property accesors "BTC", "mBTC", "uBTC", "bits", and "satoshis"', function() { 35 | var unit = new Unit(1.2, 'BTC'); 36 | unit.BTC.should.equal(1.2); 37 | unit.mBTC.should.equal(1200); 38 | unit.uBTC.should.equal(1200000); 39 | unit.bits.should.equal(1200000); 40 | unit.satoshis.should.equal(120000000); 41 | }); 42 | 43 | it('a string amount is allowed', function() { 44 | var unit; 45 | 46 | unit = Unit.fromBTC('1.00001'); 47 | unit.BTC.should.equal(1.00001); 48 | 49 | unit = Unit.fromMilis('1.00001'); 50 | unit.mBTC.should.equal(1.00001); 51 | 52 | unit = Unit.fromMillis('1.00001'); 53 | unit.mBTC.should.equal(1.00001); 54 | 55 | unit = Unit.fromBits('100'); 56 | unit.bits.should.equal(100); 57 | 58 | unit = Unit.fromSatoshis('8999'); 59 | unit.satoshis.should.equal(8999); 60 | 61 | unit = Unit.fromFiat('43', 350); 62 | unit.BTC.should.equal(0.12285714); 63 | }); 64 | 65 | it('should have constructor helpers', function() { 66 | var unit; 67 | 68 | unit = Unit.fromBTC(1.00001); 69 | unit.BTC.should.equal(1.00001); 70 | 71 | unit = Unit.fromMilis(1.00001); 72 | unit.mBTC.should.equal(1.00001); 73 | 74 | unit = Unit.fromBits(100); 75 | unit.bits.should.equal(100); 76 | 77 | unit = Unit.fromSatoshis(8999); 78 | unit.satoshis.should.equal(8999); 79 | 80 | unit = Unit.fromFiat(43, 350); 81 | unit.BTC.should.equal(0.12285714); 82 | }); 83 | 84 | it('converts to satoshis correctly', function() { 85 | /* jshint maxstatements: 25 */ 86 | var unit; 87 | 88 | unit = Unit.fromBTC(1.3); 89 | unit.mBTC.should.equal(1300); 90 | unit.bits.should.equal(1300000); 91 | unit.satoshis.should.equal(130000000); 92 | 93 | unit = Unit.fromMilis(1.3); 94 | unit.BTC.should.equal(0.0013); 95 | unit.bits.should.equal(1300); 96 | unit.satoshis.should.equal(130000); 97 | 98 | unit = Unit.fromBits(1.3); 99 | unit.BTC.should.equal(0.0000013); 100 | unit.mBTC.should.equal(0.0013); 101 | unit.satoshis.should.equal(130); 102 | 103 | unit = Unit.fromSatoshis(3); 104 | unit.BTC.should.equal(0.00000003); 105 | unit.mBTC.should.equal(0.00003); 106 | unit.bits.should.equal(0.03); 107 | }); 108 | 109 | it('takes into account floating point problems', function() { 110 | var unit = Unit.fromBTC(0.00000003); 111 | unit.mBTC.should.equal(0.00003); 112 | unit.bits.should.equal(0.03); 113 | unit.satoshis.should.equal(3); 114 | }); 115 | 116 | it('exposes unit codes', function() { 117 | should.exist(Unit.BTC); 118 | Unit.BTC.should.equal('BTC'); 119 | 120 | should.exist(Unit.mBTC); 121 | Unit.mBTC.should.equal('mBTC'); 122 | 123 | should.exist(Unit.bits); 124 | Unit.bits.should.equal('bits'); 125 | 126 | should.exist(Unit.satoshis); 127 | Unit.satoshis.should.equal('satoshis'); 128 | }); 129 | 130 | it('exposes a method that converts to different units', function() { 131 | var unit = new Unit(1.3, 'BTC'); 132 | unit.to(Unit.BTC).should.equal(unit.BTC); 133 | unit.to(Unit.mBTC).should.equal(unit.mBTC); 134 | unit.to(Unit.bits).should.equal(unit.bits); 135 | unit.to(Unit.satoshis).should.equal(unit.satoshis); 136 | }); 137 | 138 | it('exposes shorthand conversion methods', function() { 139 | var unit = new Unit(1.3, 'BTC'); 140 | unit.toBTC().should.equal(unit.BTC); 141 | unit.toMilis().should.equal(unit.mBTC); 142 | unit.toMillis().should.equal(unit.mBTC); 143 | unit.toBits().should.equal(unit.bits); 144 | unit.toSatoshis().should.equal(unit.satoshis); 145 | }); 146 | 147 | it('can convert to fiat', function() { 148 | var unit = new Unit(1.3, 350); 149 | unit.atRate(350).should.equal(1.3); 150 | unit.to(350).should.equal(1.3); 151 | 152 | unit = Unit.fromBTC(0.0123); 153 | unit.atRate(10).should.equal(0.12); 154 | }); 155 | 156 | it('toString works as expected', function() { 157 | var unit = new Unit(1.3, 'BTC'); 158 | should.exist(unit.toString); 159 | unit.toString().should.be.a('string'); 160 | }); 161 | 162 | it('can be imported and exported from/to JSON', function() { 163 | var json = JSON.stringify({amount:1.3, code:'BTC'}); 164 | var unit = Unit.fromObject(JSON.parse(json)); 165 | JSON.stringify(unit).should.deep.equal(json); 166 | }); 167 | 168 | it('importing from invalid JSON fails quickly', function() { 169 | expect(function() { 170 | return Unit.fromJSON('¹'); 171 | }).to.throw(); 172 | }); 173 | 174 | it('inspect method displays nicely', function() { 175 | var unit = new Unit(1.3, 'BTC'); 176 | unit.inspect().should.equal(''); 177 | }); 178 | 179 | it('fails when the unit is not recognized', function() { 180 | expect(function() { 181 | return new Unit(100, 'USD'); 182 | }).to.throw(errors.Unit.UnknownCode); 183 | expect(function() { 184 | return new Unit(100, 'BTC').to('USD'); 185 | }).to.throw(errors.Unit.UnknownCode); 186 | }); 187 | 188 | it('fails when the exchange rate is invalid', function() { 189 | expect(function() { 190 | return new Unit(100, -123); 191 | }).to.throw(errors.Unit.InvalidRate); 192 | expect(function() { 193 | return new Unit(100, 'BTC').atRate(-123); 194 | }).to.throw(errors.Unit.InvalidRate); 195 | }); 196 | 197 | }); 198 | -------------------------------------------------------------------------------- /test/util/buffer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* jshint unused: false */ 3 | 4 | var should = require('chai').should(); 5 | var expect = require('chai').expect; 6 | 7 | var bitcore = require('../..'); 8 | var errors = bitcore.errors; 9 | var BufferUtil = bitcore.util.buffer; 10 | 11 | describe('buffer utils', function() { 12 | 13 | describe('equals', function() { 14 | it('recognizes these two equal buffers', function() { 15 | var bufferA = new Buffer([1, 2, 3]); 16 | var bufferB = new Buffer('010203', 'hex'); 17 | BufferUtil.equal(bufferA, bufferB).should.equal(true); 18 | }); 19 | it('no false positive: returns false with two different buffers', function() { 20 | var bufferA = new Buffer([1, 2, 3]); 21 | var bufferB = new Buffer('010204', 'hex'); 22 | BufferUtil.equal(bufferA, bufferB).should.equal(false); 23 | }); 24 | it('coverage: quickly realizes a difference in size and returns false', function() { 25 | var bufferA = new Buffer([1, 2, 3]); 26 | var bufferB = new Buffer([]); 27 | BufferUtil.equal(bufferA, bufferB).should.equal(false); 28 | }); 29 | it('"equals" is an an alias for "equal"', function() { 30 | var bufferA = new Buffer([1, 2, 3]); 31 | var bufferB = new Buffer([1, 2, 3]); 32 | BufferUtil.equal(bufferA, bufferB).should.equal(true); 33 | BufferUtil.equals(bufferA, bufferB).should.equal(true); 34 | }); 35 | }); 36 | 37 | describe('fill', function() { 38 | it('checks arguments', function() { 39 | expect(function() { 40 | BufferUtil.fill('something'); 41 | }).to.throw(errors.InvalidArgumentType); 42 | expect(function() { 43 | BufferUtil.fill(new Buffer([0, 0, 0]), 'invalid'); 44 | }).to.throw(errors.InvalidArgumentType); 45 | }); 46 | it('works correctly for a small buffer', function() { 47 | var buffer = BufferUtil.fill(new Buffer(10), 6); 48 | for (var i = 0; i < 10; i++) { 49 | buffer[i].should.equal(6); 50 | } 51 | }); 52 | }); 53 | 54 | describe('isBuffer', function() { 55 | it('has no false positive', function() { 56 | expect(BufferUtil.isBuffer(1)).to.equal(false); 57 | }); 58 | it('has no false negative', function() { 59 | expect(BufferUtil.isBuffer(new Buffer(0))).to.equal(true); 60 | }); 61 | }); 62 | 63 | describe('emptyBuffer', function() { 64 | it('creates a buffer filled with zeros', function() { 65 | var buffer = BufferUtil.emptyBuffer(10); 66 | expect(buffer.length).to.equal(10); 67 | for (var i = 0; i < 10; i++) { 68 | expect(buffer[i]).to.equal(0); 69 | } 70 | }); 71 | it('checks arguments', function() { 72 | expect(function() { 73 | BufferUtil.emptyBuffer('invalid'); 74 | }).to.throw(errors.InvalidArgumentType); 75 | }); 76 | }); 77 | 78 | describe('single byte buffer <=> integer', function() { 79 | it('integerAsSingleByteBuffer should return a buffer of length 1', function() { 80 | expect(BufferUtil.integerAsSingleByteBuffer(100)[0]).to.equal(100); 81 | }); 82 | it('should check the type', function() { 83 | expect(function() { 84 | BufferUtil.integerAsSingleByteBuffer('invalid'); 85 | }).to.throw(errors.InvalidArgumentType); 86 | expect(function() { 87 | BufferUtil.integerFromSingleByteBuffer('invalid'); 88 | }).to.throw(errors.InvalidArgumentType); 89 | }); 90 | it('works correctly for edge cases', function() { 91 | expect(BufferUtil.integerAsSingleByteBuffer(255)[0]).to.equal(255); 92 | expect(BufferUtil.integerAsSingleByteBuffer(-1)[0]).to.equal(255); 93 | }); 94 | it('does a round trip', function() { 95 | expect(BufferUtil.integerAsSingleByteBuffer( 96 | BufferUtil.integerFromSingleByteBuffer(new Buffer([255])) 97 | )[0]).to.equal(255); 98 | }); 99 | }); 100 | 101 | describe('4byte buffer integer <=> integer', function() { 102 | it('integerAsBuffer should return a buffer of length 4', function() { 103 | expect(BufferUtil.integerAsBuffer(100).length).to.equal(4); 104 | }); 105 | it('is little endian', function() { 106 | expect(BufferUtil.integerAsBuffer(100)[3]).to.equal(100); 107 | }); 108 | it('should check the type', function() { 109 | expect(function() { 110 | BufferUtil.integerAsBuffer('invalid'); 111 | }).to.throw(errors.InvalidArgumentType); 112 | expect(function() { 113 | BufferUtil.integerFromBuffer('invalid'); 114 | }).to.throw(errors.InvalidArgumentType); 115 | }); 116 | it('works correctly for edge cases', function() { 117 | expect(BufferUtil.integerAsBuffer(4294967295)[0]).to.equal(255); 118 | expect(BufferUtil.integerAsBuffer(4294967295)[3]).to.equal(255); 119 | expect(BufferUtil.integerAsBuffer(-1)[0]).to.equal(255); 120 | expect(BufferUtil.integerAsBuffer(-1)[3]).to.equal(255); 121 | }); 122 | it('does a round trip', function() { 123 | expect(BufferUtil.integerFromBuffer( 124 | BufferUtil.integerAsBuffer(10000) 125 | )).to.equal(10000); 126 | }); 127 | }); 128 | 129 | describe('buffer to hex', function() { 130 | it('returns an expected value in hexa', function() { 131 | expect(BufferUtil.bufferToHex(new Buffer([255, 0, 128]))).to.equal('ff0080'); 132 | }); 133 | it('checks the argument type', function() { 134 | expect(function() { 135 | BufferUtil.bufferToHex('invalid'); 136 | }).to.throw(errors.InvalidArgumentType); 137 | }); 138 | it('round trips', function() { 139 | var original = new Buffer([255, 0, 128]); 140 | var hexa = BufferUtil.bufferToHex(original); 141 | var back = BufferUtil.hexToBuffer(hexa); 142 | expect(BufferUtil.equal(original, back)).to.equal(true); 143 | }); 144 | }); 145 | 146 | describe('reverse', function() { 147 | it('reverses a buffer', function() { 148 | // http://bit.ly/1J2Ai4x 149 | var original = new Buffer([255, 0, 128]); 150 | var reversed = BufferUtil.reverse(original); 151 | original[0].should.equal(reversed[2]); 152 | original[1].should.equal(reversed[1]); 153 | original[2].should.equal(reversed[0]); 154 | }); 155 | }); 156 | }); 157 | -------------------------------------------------------------------------------- /test/util/js.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* jshint unused: false */ 3 | 4 | var should = require('chai').should(); 5 | var expect = require('chai').expect; 6 | 7 | var bitcore = require('../..'); 8 | var JSUtil = bitcore.util.js; 9 | 10 | describe('js utils', function() { 11 | 12 | describe('isValidJSON', function() { 13 | 14 | var hexa = '8080808080808080808080808080808080808080808080808080808080808080'; 15 | var json = '{"key": ["value", "value2"]}'; 16 | var json2 = '["value", "value2", {"key": "value"}]'; 17 | 18 | it('does not mistake an integer as valid json object', function() { 19 | var valid = JSUtil.isValidJSON(hexa); 20 | valid.should.equal(false); 21 | }); 22 | 23 | it('correctly validates a json object', function() { 24 | var valid = JSUtil.isValidJSON(json); 25 | valid.should.equal(true); 26 | }); 27 | 28 | it('correctly validates an array json object', function() { 29 | var valid = JSUtil.isValidJSON(json); 30 | valid.should.equal(true); 31 | }); 32 | 33 | }); 34 | 35 | describe('isNaturalNumber', function() { 36 | it('false for float', function() { 37 | var a = JSUtil.isNaturalNumber(0.1); 38 | a.should.equal(false); 39 | }); 40 | 41 | it('false for string float', function() { 42 | var a = JSUtil.isNaturalNumber('0.1'); 43 | a.should.equal(false); 44 | }); 45 | 46 | it('false for string integer', function() { 47 | var a = JSUtil.isNaturalNumber('1'); 48 | a.should.equal(false); 49 | }); 50 | 51 | it('false for negative integer', function() { 52 | var a = JSUtil.isNaturalNumber(-1); 53 | a.should.equal(false); 54 | }); 55 | 56 | it('false for negative integer string', function() { 57 | var a = JSUtil.isNaturalNumber('-1'); 58 | a.should.equal(false); 59 | }); 60 | 61 | it('false for infinity', function() { 62 | var a = JSUtil.isNaturalNumber(Infinity); 63 | a.should.equal(false); 64 | }); 65 | 66 | it('false for NaN', function() { 67 | var a = JSUtil.isNaturalNumber(NaN); 68 | a.should.equal(false); 69 | }); 70 | 71 | it('true for zero', function() { 72 | var a = JSUtil.isNaturalNumber(0); 73 | a.should.equal(true); 74 | }); 75 | 76 | it('true for positive integer', function() { 77 | var a = JSUtil.isNaturalNumber(1000); 78 | a.should.equal(true); 79 | }); 80 | 81 | }); 82 | 83 | }); 84 | -------------------------------------------------------------------------------- /test/util/preconditions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); 4 | 5 | var bitcore = require('../..'); 6 | var errors = bitcore.errors; 7 | var $ = bitcore.util.preconditions; 8 | var PrivateKey = bitcore.PrivateKey; 9 | 10 | describe('preconditions', function() { 11 | 12 | it('can be used to assert state', function() { 13 | (function() { 14 | $.checkState(false, 'testing'); 15 | }).should.throw(errors.InvalidState); 16 | }); 17 | it('throws no false negative', function() { 18 | (function() { 19 | $.checkState(true, 'testing'); 20 | }).should.not.throw(); 21 | }); 22 | 23 | it('can be used to check an argument', function() { 24 | (function() { 25 | $.checkArgument(false, 'testing'); 26 | }).should.throw(errors.InvalidArgument); 27 | 28 | (function() { 29 | $.checkArgument(true, 'testing'); 30 | }).should.not.throw(errors.InvalidArgument); 31 | }); 32 | 33 | it('can be used to check an argument type', function() { 34 | var error; 35 | try { 36 | $.checkArgumentType(1, 'string', 'argumentName'); 37 | } catch (e) { 38 | error = e; 39 | e.message.should.equal('Invalid Argument for argumentName, expected string but got number'); 40 | } 41 | should.exist(error); 42 | }); 43 | it('has no false negatives when used to check an argument type', function() { 44 | (function() { 45 | $.checkArgumentType('a String', 'string', 'argumentName'); 46 | }).should.not.throw(); 47 | }); 48 | 49 | it('can be used to check an argument type for a class', function() { 50 | var error; 51 | try { 52 | $.checkArgumentType(1, PrivateKey); 53 | } catch (e) { 54 | error = e; 55 | var fail = !(~e.message.indexOf('Invalid Argument for (unknown name)')); 56 | fail.should.equal(false); 57 | } 58 | should.exist(error); 59 | }); 60 | it('has no false negatives when checking a type for a class', function() { 61 | (function() { 62 | $.checkArgumentType(new PrivateKey(), PrivateKey); 63 | }).should.not.throw(); 64 | }); 65 | 66 | it('formats correctly a message on InvalidArgument()', function() { 67 | var error = new errors.InvalidArgument(); 68 | error.message.should.equal('Invalid Argument'); 69 | }); 70 | 71 | it('formats correctly a message on checkArgument', function() { 72 | var error; 73 | try { 74 | $.checkArgument(null, 'parameter must be provided'); 75 | } catch (e) { 76 | error = e; 77 | } 78 | error.message.should.equal('Invalid Argument: parameter must be provided'); 79 | }); 80 | }); 81 | --------------------------------------------------------------------------------