├── test
├── mocha.opts
├── data
│ ├── blk86756-testnet.dat
│ └── bitcoind
│ │ ├── sig_canonical.json
│ │ ├── sig_noncanonical.json
│ │ └── base58_keys_invalid.json
├── index.js
├── docs.js
├── index.html
├── transaction
│ ├── deserialize.js
│ ├── sighashwitness.js
│ ├── sighash.js
│ ├── input
│ │ ├── publickeyhash.js
│ │ ├── publickey.js
│ │ └── input.js
│ ├── unspentoutput.js
│ └── signature.js
├── crypto
│ ├── random.js
│ ├── bn.js
│ └── hash.js
├── util
│ ├── js.js
│ ├── preconditions.js
│ └── buffer.js
├── encoding
│ ├── base58.js
│ ├── varint.js
│ ├── base58check.js
│ └── bufferwriter.js
├── networks.js
├── opcode.js
└── unit.js
├── .coveralls.yml
├── gulpfile.js
├── lib
├── script
│ └── index.js
├── block
│ └── index.js
├── transaction
│ ├── input
│ │ ├── index.js
│ │ ├── publickey.js
│ │ └── publickeyhash.js
│ ├── index.js
│ ├── signature.js
│ ├── unspentoutput.js
│ ├── sighash.js
│ ├── output.js
│ └── sighashwitness.js
├── util
│ ├── preconditions.js
│ ├── js.js
│ └── buffer.js
├── crypto
│ ├── random.js
│ ├── hash.js
│ ├── point.js
│ └── bn.js
├── encoding
│ ├── varint.js
│ ├── base58.js
│ ├── base58check.js
│ ├── bufferwriter.js
│ └── bufferreader.js
├── errors
│ ├── index.js
│ └── spec.js
└── opcode.js
├── README.md
├── benchmark
├── package.json
├── script.js
└── serialization.js
├── .zuul.yml
├── .gitignore
├── .travis.yml
├── karma.conf.js
├── docs
├── encoding.md
├── crypto.md
├── unspentoutput.md
├── uri.md
├── privatekey.md
├── browser.md
├── block.md
├── networks.md
├── address.md
├── unit.md
├── publickey.md
├── hierarchical.md
├── index.md
└── examples.md
├── .jsdoc.conf
├── package.json
├── LICENSE
├── .jshintrc
└── index.js
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --recursive
2 | --timeout 5000
3 |
--------------------------------------------------------------------------------
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | repo_token: 5ki6iPbGaiwHzIwcfNDzTXoiqAcffqUQs
2 |
--------------------------------------------------------------------------------
/test/data/blk86756-testnet.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitpay/bitcore-lib/HEAD/test/data/blk86756-testnet.dat
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var startGulp = require('bitcore-build');
4 | Object.assign(exports, startGulp('lib'))
5 |
--------------------------------------------------------------------------------
/lib/script/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./script');
2 |
3 | module.exports.Interpreter = require('./interpreter');
4 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/block/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./block');
2 |
3 | module.exports.BlockHeader = require('./blockheader');
4 | module.exports.MerkleBlock = require('./merkleblock');
5 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/data/bitcoind/sig_canonical.json:
--------------------------------------------------------------------------------
1 | [
2 | "300602010002010001",
3 | "3008020200ff020200ff01",
4 | "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001",
5 | "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01",
6 | "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"
7 | ]
8 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mocha
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 '