├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── src ├── address.js ├── block.js ├── bufferutils.js ├── crypto.js ├── ecdsa.js ├── ecpair.js ├── ecsignature.js ├── hdnode.js ├── index.js ├── message.js ├── networks.js ├── opcodes.json ├── script.js ├── script_number.js ├── transaction.js ├── transaction_builder.js └── types.js └── test ├── address.js ├── bitcoin.core.js ├── block.js ├── bufferutils.js ├── crypto.js ├── ecdsa.js ├── ecpair.js ├── ecsignature.js ├── fixtures ├── address.json ├── block.json ├── bufferutils.json ├── core │ ├── README.md │ ├── base58_encode_decode.json │ ├── base58_keys_invalid.json │ ├── base58_keys_valid.json │ ├── blocks.json │ ├── sig_canonical.json │ ├── sig_noncanonical.json │ ├── sighash.json │ └── tx_valid.json ├── crypto.json ├── ecdsa.json ├── ecpair.json ├── ecsignature.json ├── hdnode.json ├── message.json ├── script.json ├── script_number.json ├── transaction.json └── transaction_builder.json ├── hdnode.js ├── integration ├── _blockchain.js ├── advanced.js ├── basic.js ├── crypto.js └── multisig.js ├── message.js ├── script.js ├── script_number.js ├── transaction.js ├── transaction_builder.js └── types.js /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2.2.0 2 | __added__ 3 | - Added `Block.calculateTarget` for difficulty calculations (#509) 4 | - Added `Block.prototype.checkProofOfWork` (#509) 5 | - Added `opcodes.OP_CHECKLOCKTIMEVERIFY` alias for `OP_NOP2` (#511) 6 | - Added `script.number.[encode/decode]` for CScriptNum-encoded `Buffer`s (#516) 7 | - Added `TransactionBuilder.prototype.setLockTime` (#507) 8 | 9 | __fixed__ 10 | - Bumped `typeforce` version to fix erroneous error message from `types.Hash*bit` types (#534) 11 | 12 | 13 | # 2.1.4 14 | __fixed__ 15 | - script.isPubKeyHashOutput and script.isScriptHashOutput no longer allow for non-minimal data pushes (per bitcoin/bitcoin `IsStandard` policy) (#499) 16 | - TransactionBuilder.addOutput now allows for SIGHASH_SINGLE, throwing if the contract is violated (#504) 17 | - remove use of `const`, use ES5 only (#502) 18 | 19 | 20 | # 2.1.3 21 | __fixed__ 22 | - Bumped typeforce to 1.5.5 (see #493) 23 | 24 | 25 | # 2.1.2 26 | __fixed__ 27 | - Add missing CHANGELOG entry for 2.1.1 28 | 29 | 30 | # 2.1.1 31 | __changed__ 32 | - removed use of `buffer-reverse`, dependency only kept for `bufferutils.reverse`, to be deprecated (#478) 33 | 34 | __fixed__ 35 | - `isMultisigOutput` no longer allows data chunks for `m`/`n` (#482) 36 | - `isMultisigOutput`'s `n` value must now match the number of public keys (as per bitcoin/bitcoin) (#484) 37 | 38 | 39 | # 2.1.0 40 | From this release users should use the HDNode directly (compared to accessing `.keyPair`) when performing ECDSA operations such as `sign` or `verify`. 41 | Ideally you shoud not have to directly access `HDNode` internals for general usage, as it can often be confusing and error prone. 42 | 43 | __added__ 44 | - `ECPair.prototype.getNetwork` 45 | - `HDNode.prototype.getNetwork`, wraps the underyling keyPair's `getNetwork` method 46 | - `HDNode.prototype.getPublicKeyBuffer`, wraps the underyling keyPair's `getPublicKeyBuffer` method 47 | - `HDNode.prototype.sign`, wraps the underlying keyPair's `sign` method 48 | - `HDNode.prototype.verify`, wraps the underlying keyPair's `verify` method 49 | 50 | 51 | # 2.0.0 52 | In this release we have strived to simplify the API, [using native types](https://github.com/bitcoinjs/bitcoinjs-lib/issues/407) wherevever possible to encourage cross-compatibility with other open source community modules. 53 | 54 | The `ecdsa` module has been removed in lieu of using a new ECDSA module (for performance and safety reasons) during the `2.x.y` major release. 55 | Several other cumbersome modules have been removed, with their new independent modules recommended for usage instead for greater modularity in your projects. 56 | 57 | ----------------------------- 58 | 59 | Backward incompatible changes: 60 | 61 | __added__ 62 | - export `address`, for `address` based [utility functions](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/address.js), most compatible, just without `Address` instantiation, see #401, #444 63 | - export `script`, for `script` based [utility functions](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/script.js), mostly compatible, just without `Script` instantiation, see #438, #444 64 | - export `ECPair`, a merged replacement for `ECKey`/`ECPubKey`, invalid types will throw via `typeforce` 65 | 66 | __changed__ 67 | - `address.toOutputScript`, `ECPair.prototype.fromWIF` and `HDNode.prototype.fromBase58` no longer automatically detect the network, `networks.bitcoin` is always assumed unless given. 68 | - `assert` was used for type checking, now replaced by `typeforce` 69 | - `BIP66` compliant strict DER signature validation was added to `ECSignature.fromDER`, changing the exact exception messages slightly, see #448. 70 | 71 | - `new HDNode(d/Q, chainCode, network)` -> `new HDNode(keyPair, chainCode)`, now uses `ECPair` 72 | - `HDNode.prototype.toBase58(false)` -> `HDNode.prototype.neutered().toBase58()` for exporting an extended public key 73 | - `HDNode.prototype.toBase58(true)` -> `HDNode.prototype.toBase58()` for exporting an extended private key 74 | 75 | - `Transaction.prototype.hashForSignature(prevOutScript, inIndex, hashType)` -> `Transaction.prototype.hashForSignature(inIndex, prevOutScript, hashType)` 76 | - `Transaction.prototype.addInput(hash, ...)`: `hash` could be a string, Transaction or Buffer -> `hash` can now **only** be a `Buffer`. 77 | - `Transaction.prototype.addOutput(scriptPubKey, ...)`: `scriptPubKey ` could be a string, `Address` or a `Buffer` -> `scriptPubKey` can now **only** be a `Buffer`. 78 | - `TransactionBuilder` API unchanged. 79 | 80 | __removed__ 81 | - export `Address`, `strings` are now used, benchwith no performance loss for most use cases 82 | - export `base58check`, use [`bs58check`](https://github.com/bitcoinjs/bs58check) instead 83 | - export `ecdsa`, use [`ecurve`](https://github.com/cryptocoinjs/ecurve) instead 84 | - export `ECKey`, use new export `ECPair` instead 85 | - export `ECPubKey`, use new export `ECPair` instead 86 | - export `Wallet`, see README.md#complementing-libraries instead 87 | - export `Script`, use new utility export `script` instead (#438 for more information) 88 | 89 | - `crypto.HmacSHA256 `, use [node crypto](https://nodejs.org/api/crypto.html) instead 90 | - `crypto.HmacSHA512 `, use [node crypto](https://nodejs.org/api/crypto.html) instead 91 | 92 | - `Transaction.prototype.sign`, use `TransactionBuilder.prototype.sign` 93 | - `Transaction.prototype.signInput`, use `TransactionBuilder.prototype.sign` 94 | - `Transaction.prototype.validateInput`, use `Transaction.prototype.hashForSignature` and `ECPair.verify` 95 | 96 | - `HDNode.fromBuffer`, use `HDNode.fromBase58` instead 97 | - `HDNode.fromHex`, use `HDNode.fromBase58` instead 98 | - `HDNode.toBuffer`, use `HDNode.prototype.toBase58` instead 99 | - `HDNode.toHex`, use `HDNode.prototype.toBase58` instead 100 | 101 | - `networks.*.magic`, see the comment [here](https://github.com/bitcoinjs/bitcoinjs-lib/pull/432/files#r36715792) 102 | - `networks.[viacoin|viacointestnet|gamerscoin|jumbucks|zetacoin]`, import these yourself (see #383/a0e6ee7) 103 | - `networks.*.estimateFee`, out-dated 104 | 105 | __renamed__ 106 | - `Message` -> `message` 107 | - `scripts` -> `script` 108 | - `scripts.dataOutput ` -> `script.nullDataOutput` (per [convention](https://org/en/glossary/null-data-transaction)) 109 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2016 bitcoinjs-lib contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BitcoinJS (bitcoinjs-lib) 2 | 3 | [![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib) 4 | [![NPM](https://img.shields.io/npm/v/bitcoinjs-lib.svg)](https://www.npmjs.org/package/bitcoinjs-lib) 5 | [![tip for next commit](https://tip4commit.com/projects/735.svg)](http://tip4commit.com/projects/735) 6 | 7 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) 8 | 9 | 10 | The pure JavaScript Bitcoin library for node.js and browsers. 11 | Used by over a million wallet users and the backbone for almost all Bitcoin web wallets in production today. 12 | 13 | 14 | ## Features 15 | 16 | - Clean: Pure JavaScript, concise code, easy to read. 17 | - Tested: Coverage > 90%, third-party integration tests. 18 | - Careful: Two person approval process for small, focused pull requests. 19 | - Compatible: Works on Node.js and all modern browsers. 20 | - Powerful: Support for advanced features, such as multi-sig, HD Wallets. 21 | - Secure: Strong random number generation, PGP signed releases, trusted developers. 22 | - Principled: No support for browsers with crap RNG (IE < 11) 23 | - Standardized: Node community coding style, Browserify, Node's stdlib and Buffers. 24 | - Fast: Optimized code, uses typed arrays instead of byte arrays for performance. 25 | - Experiment-friendly: Bitcoin Mainnet and Testnet support. 26 | - Altcoin-ready: Capable of working with bitcoin-derived cryptocurrencies (such as Dogecoin). 27 | 28 | 29 | ## Should I use this in production? 30 | 31 | If you are thinking of using the master branch of this library in production, *stop*. 32 | Master is not stable; it is our development branch, and only tagged releases may be classified as stable. 33 | 34 | If you are looking for the original, it is tagged as `0.1.3`. Unless you need it for dependency reasons, it is strongly recommended that you use (or upgrade to) the newest version, which adds major functionality, cleans up the interface, fixes many bugs, and adds over 1,300 more tests. 35 | 36 | 37 | ## Installation 38 | 39 | `npm install bitcoinjs-lib` 40 | 41 | 42 | ## Setup 43 | 44 | ### Node.js 45 | 46 | var bitcoin = require('bitcoinjs-lib') 47 | 48 | 49 | ### Browser 50 | 51 | If you're familiar with how to use browserify, ignore this and proceed normally. 52 | These steps are advisory only and allow you to use the API to its full extent. 53 | 54 | [Browserify](https://github.com/substack/node-browserify) is assumed to be installed for these steps. 55 | 56 | From your repository, create a `foobar.js` file 57 | 58 | ``` javascript 59 | var foobar = { 60 | base58: require('bs58'), 61 | bitcoin: require('bitcoinjs-lib'), 62 | ecurve: require('ecurve'), 63 | BigInteger: require('bigi'), 64 | Buffer: require('buffer') 65 | } 66 | 67 | module.exports = foobar 68 | ``` 69 | 70 | Each of these included packages are seperate to `bitcoinjs-lib`, and must be installed separately. 71 | They are however used in the bitcoinjs-lib public API. 72 | 73 | Using browserify, compile `foobar.js` for use in the browser: 74 | 75 | $ browserify foobar.js -s foobar > foobar.js 76 | 77 | You will then be able to load `foobar.js` into your browser, with each of the dependencies above accessible from the global `foobar` object. 78 | 79 | **NOTE**: See our package.json for the currently supported version of browserify used by this repository. 80 | 81 | **NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Array`, `BigInteger`, `Boolean`, `Buffer`, `ECPair`, `Function`, `Number`, `Point` and `Script`. 82 | This is because of the function-name-duck-typing used in [typeforce](https://github.com/dcousens/typeforce). 83 | 84 | 85 | ## Examples 86 | 87 | The below examples are implemented as integration tests, they should be very easy to understand. Otherwise, pull requests are appreciated. 88 | 89 | - [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L8) 90 | - [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L20) 91 | - [Generate a address and WIF for Litecoin](https://github.com/bitcoin/bitcoinjs-lib/blob/master/test/integration/basic.js#L29) 92 | - [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L43) 93 | - [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L50) 94 | - [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L9) 95 | - [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L17) 96 | - [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L24) 97 | - [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L8) 98 | - [Spend from a 2-of-4 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L22) 99 | - [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L7) 100 | - [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L52) 101 | - [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L54) 102 | - [Recover a Private key from duplicate R values in a signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L101) 103 | 104 | If you have a use case that you feel could be listed here, please [ask for it](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new)! 105 | 106 | 107 | ## Projects utilizing BitcoinJS 108 | 109 | - [BitAddress](https://www.bitaddress.org) 110 | - [Blockchain.info](https://blockchain.info/wallet) 111 | - [Blocktrail](https://www.blocktrail.com/) 112 | - [Brainwallet](https://brainwallet.github.io) 113 | - [Coinkite](https://coinkite.com) 114 | - [Coinpunk](https://coinpunk.com) 115 | - [Dark Wallet](https://darkwallet.unsystem.net) 116 | - [DecentralBank](http://decentralbank.com/) 117 | - [Dogechain Wallet](https://dogechain.info) 118 | - [EI8HT Wallet](http://ei8.ht/) 119 | - [GreenAddress](https://greenaddress.it) 120 | - [Hive Wallet](https://www.hivewallet.com) 121 | - [QuickCoin](https://wallet.quickcoin.co) 122 | - [Robocoin](https://wallet.robocoin.com) 123 | - [Skyhook ATM](http://projectskyhook.com) 124 | 125 | 126 | ## Contributors 127 | 128 | Stefan Thomas is the inventor and creator of this project. His pioneering work made Bitcoin web wallets possible. 129 | 130 | Since then, many people have contributed. [Click here](https://github.com/bitcoinjs/bitcoinjs-lib/graphs/contributors) to see the comprehensive list. 131 | 132 | Daniel Cousens, Wei Lu, JP Richardson and Kyle Drake lead the major refactor of the library from 0.1.3 to 1.0.0. 133 | 134 | 135 | ## Contributing 136 | 137 | We are always accepting of pull requests, but we do adhere to specific standards in regards to coding style, test driven development and commit messages. 138 | 139 | Please make your best effort to adhere to these when contributing to save on trivial corrections. 140 | 141 | 142 | ### Running the test suite 143 | 144 | $ npm test 145 | $ npm run-script coverage 146 | 147 | 148 | ## Complementing Libraries 149 | 150 | - [BIP21](https://github.com/bitcoinjs/bip21) - A BIP21 compatible URL encoding utility library 151 | - [BIP38](https://github.com/bitcoinjs/bip38) - Passphrase-protected private keys 152 | - [BIP39](https://github.com/bitcoinjs/bip39) - Mnemonic generation for deterministic keys 153 | - [BIP32-Utils](https://github.com/bitcoinjs/bip32-utils) - A set of utilities for working with BIP32 154 | - [BIP32-Wallet](https://github.com/bitcoinjs/bip32-wallet) - A BIP32 Wallet backed by bitcoinjs-lib, lite on features but heavily tested 155 | - [BIP66](https://github.com/bitcoinjs/bip66) - Strict DER signature decoding 156 | - [BIP69](https://github.com/bitcoinjs/bip69) - Mnemonic generation for deterministic keys 157 | - [Base58](https://github.com/cryptocoinjs/bs58) - Base58 encoding/decoding 158 | - [Base58 Check](https://github.com/bitcoinjs/bs58check) - Base58 check encoding/decoding 159 | - [BCoin](https://github.com/indutny/bcoin) - BIP37 / Bloom Filters / SPV client 160 | - [insight](https://github.com/bitpay/insight) - A bitcoin blockchain API for web wallets. 161 | 162 | 163 | ## Alternatives 164 | 165 | - [Bitcore](https://github.com/bitpay/bitcore) 166 | - [Cryptocoin](https://github.com/cryptocoinjs/cryptocoin) 167 | 168 | 169 | ## LICENSE [MIT](LICENSE) 170 | 171 | 172 | ## Copyright 173 | 174 | BitcoinJS (c) 2011-2016 bitcoinjs-lib contributors 175 | 176 | Released under MIT license 177 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitcoinjs-lib", 3 | "version": "2.2.0", 4 | "description": "Client-side Bitcoin JavaScript library", 5 | "main": "./src/index.js", 6 | "keywords": [ 7 | "bitcoin", 8 | "browser", 9 | "client", 10 | "library" 11 | ], 12 | "contributors": [ 13 | { 14 | "name": "Daniel Cousens", 15 | "email": "bitcoin@dcousens.com", 16 | "url": "http://dcousens.com" 17 | }, 18 | { 19 | "name": "Kyle Drake", 20 | "email": "kyle@kyledrake.net", 21 | "url": "http://kyledrake.net/" 22 | }, 23 | { 24 | "name": "Wei Lu", 25 | "email": "luwei.here@gmail.com", 26 | "url": "http://weilu.github.io/" 27 | }, 28 | { 29 | "name": "Stefan Thomas", 30 | "email": "justmoon@members.fsf.org", 31 | "url": "http://www.justmoon.net" 32 | } 33 | ], 34 | "scripts": { 35 | "coverage": "mocha --require blanket -R travis-cov", 36 | "coverage-local": "mocha --require blanket -R html-cov", 37 | "integration": "mocha test/integration/", 38 | "prepublish": "npm run test", 39 | "standard": "standard", 40 | "test": "npm run standard && npm run unit", 41 | "unit": "mocha" 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/bitcoinjs/bitcoinjs-lib.git" 46 | }, 47 | "files": [ 48 | "src" 49 | ], 50 | "config": { 51 | "blanket": { 52 | "pattern": [ 53 | "" 54 | ], 55 | "data-cover-never": [ 56 | "node_modules", 57 | "test" 58 | ] 59 | }, 60 | "travis-cov": { 61 | "threshold": 99 62 | } 63 | }, 64 | "dependencies": { 65 | "bigi": "^1.4.0", 66 | "bip66": "^1.1.0", 67 | "bs58check": "^1.0.5", 68 | "buffer-compare": "^1.1.0", 69 | "buffer-equals": "^1.0.3", 70 | "buffer-reverse": "^1.0.0", 71 | "create-hash": "^1.1.0", 72 | "create-hmac": "^1.1.3", 73 | "ecurve": "^1.0.0", 74 | "randombytes": "^2.0.1", 75 | "typeforce": "^1.6.2", 76 | "wif": "^2.0.1" 77 | }, 78 | "devDependencies": { 79 | "async": "^1.5.0", 80 | "blanket": "^1.1.0", 81 | "browserify": "^10.0.0", 82 | "bs58": "^2.0.1", 83 | "cb-http-client": "^0.2.0", 84 | "httpify": "^1.0.0", 85 | "mocha": "^2.2.0", 86 | "proxyquire": "^1.4.0", 87 | "sinon": "^1.12.2", 88 | "standard": "^5.0.0", 89 | "travis-cov": "^0.2.0" 90 | }, 91 | "license": "MIT" 92 | } 93 | -------------------------------------------------------------------------------- /src/address.js: -------------------------------------------------------------------------------- 1 | var bs58check = require('bs58check') 2 | var bscript = require('./script') 3 | var networks = require('./networks') 4 | var typeforce = require('typeforce') 5 | var types = require('./types') 6 | 7 | function fromBase58Check (address) { 8 | var payload = bs58check.decode(address) 9 | if (payload.length < 21) throw new TypeError(address + ' is too short') 10 | if (payload.length > 21) throw new TypeError(address + ' is too long') 11 | 12 | var version = payload[0] 13 | var hash = payload.slice(1) 14 | 15 | return { hash: hash, version: version } 16 | } 17 | 18 | function fromOutputScript (scriptPubKey, network) { 19 | network = network || networks.bitcoin 20 | 21 | if (bscript.isPubKeyHashOutput(scriptPubKey)) return toBase58Check(bscript.compile(scriptPubKey).slice(3, 23), network.pubKeyHash) 22 | if (bscript.isScriptHashOutput(scriptPubKey)) return toBase58Check(bscript.compile(scriptPubKey).slice(2, 22), network.scriptHash) 23 | 24 | throw new Error(bscript.toASM(scriptPubKey) + ' has no matching Address') 25 | } 26 | 27 | function toBase58Check (hash, version) { 28 | typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments) 29 | 30 | var payload = new Buffer(21) 31 | payload.writeUInt8(version, 0) 32 | hash.copy(payload, 1) 33 | 34 | return bs58check.encode(payload) 35 | } 36 | 37 | function toOutputScript (address, network) { 38 | network = network || networks.bitcoin 39 | 40 | var decode = fromBase58Check(address) 41 | if (decode.version === network.pubKeyHash) return bscript.pubKeyHashOutput(decode.hash) 42 | if (decode.version === network.scriptHash) return bscript.scriptHashOutput(decode.hash) 43 | 44 | throw new Error(address + ' has no matching Script') 45 | } 46 | 47 | module.exports = { 48 | fromBase58Check: fromBase58Check, 49 | fromOutputScript: fromOutputScript, 50 | toBase58Check: toBase58Check, 51 | toOutputScript: toOutputScript 52 | } 53 | -------------------------------------------------------------------------------- /src/block.js: -------------------------------------------------------------------------------- 1 | var bufferutils = require('./bufferutils') 2 | var bcrypto = require('./crypto') 3 | var compare = require('buffer-compare') 4 | 5 | var Transaction = require('./transaction') 6 | 7 | function Block () { 8 | this.version = 1 9 | this.prevHash = null 10 | this.merkleRoot = null 11 | this.timestamp = 0 12 | this.bits = 0 13 | this.nonce = 0 14 | } 15 | 16 | Block.fromBuffer = function (buffer) { 17 | if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)') 18 | 19 | var offset = 0 20 | function readSlice (n) { 21 | offset += n 22 | return buffer.slice(offset - n, offset) 23 | } 24 | 25 | function readUInt32 () { 26 | var i = buffer.readUInt32LE(offset) 27 | offset += 4 28 | return i 29 | } 30 | 31 | var block = new Block() 32 | block.version = readUInt32() 33 | block.prevHash = readSlice(32) 34 | block.merkleRoot = readSlice(32) 35 | block.timestamp = readUInt32() 36 | block.bits = readUInt32() 37 | block.nonce = readUInt32() 38 | 39 | if (buffer.length === 80) return block 40 | 41 | function readVarInt () { 42 | var vi = bufferutils.readVarInt(buffer, offset) 43 | offset += vi.size 44 | return vi.number 45 | } 46 | 47 | function readTransaction () { 48 | var tx = Transaction.fromBuffer(buffer.slice(offset), true) 49 | 50 | offset += tx.byteLength() 51 | return tx 52 | } 53 | 54 | var nTransactions = readVarInt() 55 | block.transactions = [] 56 | 57 | for (var i = 0; i < nTransactions; ++i) { 58 | var tx = readTransaction() 59 | block.transactions.push(tx) 60 | } 61 | 62 | return block 63 | } 64 | 65 | Block.fromHex = function (hex) { 66 | return Block.fromBuffer(new Buffer(hex, 'hex')) 67 | } 68 | 69 | Block.prototype.getHash = function () { 70 | return bcrypto.hash256(this.toBuffer(true)) 71 | } 72 | 73 | Block.prototype.getId = function () { 74 | return [].reverse.call(this.getHash()).toString('hex') 75 | } 76 | 77 | Block.prototype.getUTCDate = function () { 78 | var date = new Date(0) // epoch 79 | date.setUTCSeconds(this.timestamp) 80 | 81 | return date 82 | } 83 | 84 | Block.prototype.toBuffer = function (headersOnly) { 85 | var buffer = new Buffer(80) 86 | 87 | var offset = 0 88 | function writeSlice (slice) { 89 | slice.copy(buffer, offset) 90 | offset += slice.length 91 | } 92 | 93 | function writeUInt32 (i) { 94 | buffer.writeUInt32LE(i, offset) 95 | offset += 4 96 | } 97 | 98 | writeUInt32(this.version) 99 | writeSlice(this.prevHash) 100 | writeSlice(this.merkleRoot) 101 | writeUInt32(this.timestamp) 102 | writeUInt32(this.bits) 103 | writeUInt32(this.nonce) 104 | 105 | if (headersOnly || !this.transactions) return buffer 106 | 107 | var txLenBuffer = bufferutils.varIntBuffer(this.transactions.length) 108 | var txBuffers = this.transactions.map(function (tx) { 109 | return tx.toBuffer() 110 | }) 111 | 112 | return Buffer.concat([buffer, txLenBuffer].concat(txBuffers)) 113 | } 114 | 115 | Block.prototype.toHex = function (headersOnly) { 116 | return this.toBuffer(headersOnly).toString('hex') 117 | } 118 | 119 | Block.calculateTarget = function (bits) { 120 | var exponent = ((bits & 0xff000000) >> 24) - 3 121 | var mantissa = bits & 0x007fffff 122 | var i = 31 - exponent 123 | 124 | var target = new Buffer(32) 125 | target.fill(0) 126 | 127 | target[i] = mantissa & 0xff 128 | target[i - 1] = mantissa >> 8 129 | target[i - 2] = mantissa >> 16 130 | target[i - 3] = mantissa >> 24 131 | 132 | return target 133 | } 134 | 135 | Block.prototype.checkProofOfWork = function () { 136 | var hash = [].reverse.call(this.getHash()) 137 | var target = Block.calculateTarget(this.bits) 138 | 139 | return compare(hash, target) <= 0 140 | } 141 | 142 | module.exports = Block 143 | -------------------------------------------------------------------------------- /src/bufferutils.js: -------------------------------------------------------------------------------- 1 | var opcodes = require('./opcodes') 2 | 3 | // https://github.com/feross/buffer/blob/master/index.js#L1127 4 | function verifuint (value, max) { 5 | if (typeof value !== 'number') throw new Error('cannot write a non-number as a number') 6 | if (value < 0) throw new Error('specified a negative value for writing an unsigned value') 7 | if (value > max) throw new Error('value is larger than maximum value for type') 8 | if (Math.floor(value) !== value) throw new Error('value has a fractional component') 9 | } 10 | 11 | function pushDataSize (i) { 12 | return i < opcodes.OP_PUSHDATA1 ? 1 13 | : i < 0xff ? 2 14 | : i < 0xffff ? 3 15 | : 5 16 | } 17 | 18 | function readPushDataInt (buffer, offset) { 19 | var opcode = buffer.readUInt8(offset) 20 | var number, size 21 | 22 | // ~6 bit 23 | if (opcode < opcodes.OP_PUSHDATA1) { 24 | number = opcode 25 | size = 1 26 | 27 | // 8 bit 28 | } else if (opcode === opcodes.OP_PUSHDATA1) { 29 | if (offset + 2 > buffer.length) return null 30 | number = buffer.readUInt8(offset + 1) 31 | size = 2 32 | 33 | // 16 bit 34 | } else if (opcode === opcodes.OP_PUSHDATA2) { 35 | if (offset + 3 > buffer.length) return null 36 | number = buffer.readUInt16LE(offset + 1) 37 | size = 3 38 | 39 | // 32 bit 40 | } else { 41 | if (offset + 5 > buffer.length) return null 42 | if (opcode !== opcodes.OP_PUSHDATA4) throw new Error('Unexpected opcode') 43 | 44 | number = buffer.readUInt32LE(offset + 1) 45 | size = 5 46 | } 47 | 48 | return { 49 | opcode: opcode, 50 | number: number, 51 | size: size 52 | } 53 | } 54 | 55 | function readUInt64LE (buffer, offset) { 56 | var a = buffer.readUInt32LE(offset) 57 | var b = buffer.readUInt32LE(offset + 4) 58 | b *= 0x100000000 59 | 60 | verifuint(b + a, 0x001fffffffffffff) 61 | 62 | return b + a 63 | } 64 | 65 | function readVarInt (buffer, offset) { 66 | var t = buffer.readUInt8(offset) 67 | var number, size 68 | 69 | // 8 bit 70 | if (t < 253) { 71 | number = t 72 | size = 1 73 | 74 | // 16 bit 75 | } else if (t < 254) { 76 | number = buffer.readUInt16LE(offset + 1) 77 | size = 3 78 | 79 | // 32 bit 80 | } else if (t < 255) { 81 | number = buffer.readUInt32LE(offset + 1) 82 | size = 5 83 | 84 | // 64 bit 85 | } else { 86 | number = readUInt64LE(buffer, offset + 1) 87 | size = 9 88 | } 89 | 90 | return { 91 | number: number, 92 | size: size 93 | } 94 | } 95 | 96 | function writePushDataInt (buffer, number, offset) { 97 | var size = pushDataSize(number) 98 | 99 | // ~6 bit 100 | if (size === 1) { 101 | buffer.writeUInt8(number, offset) 102 | 103 | // 8 bit 104 | } else if (size === 2) { 105 | buffer.writeUInt8(opcodes.OP_PUSHDATA1, offset) 106 | buffer.writeUInt8(number, offset + 1) 107 | 108 | // 16 bit 109 | } else if (size === 3) { 110 | buffer.writeUInt8(opcodes.OP_PUSHDATA2, offset) 111 | buffer.writeUInt16LE(number, offset + 1) 112 | 113 | // 32 bit 114 | } else { 115 | buffer.writeUInt8(opcodes.OP_PUSHDATA4, offset) 116 | buffer.writeUInt32LE(number, offset + 1) 117 | } 118 | 119 | return size 120 | } 121 | 122 | function writeUInt64LE (buffer, value, offset) { 123 | verifuint(value, 0x001fffffffffffff) 124 | 125 | buffer.writeInt32LE(value & -1, offset) 126 | buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4) 127 | } 128 | 129 | function varIntSize (i) { 130 | return i < 253 ? 1 131 | : i < 0x10000 ? 3 132 | : i < 0x100000000 ? 5 133 | : 9 134 | } 135 | 136 | function writeVarInt (buffer, number, offset) { 137 | var size = varIntSize(number) 138 | 139 | // 8 bit 140 | if (size === 1) { 141 | buffer.writeUInt8(number, offset) 142 | 143 | // 16 bit 144 | } else if (size === 3) { 145 | buffer.writeUInt8(253, offset) 146 | buffer.writeUInt16LE(number, offset + 1) 147 | 148 | // 32 bit 149 | } else if (size === 5) { 150 | buffer.writeUInt8(254, offset) 151 | buffer.writeUInt32LE(number, offset + 1) 152 | 153 | // 64 bit 154 | } else { 155 | buffer.writeUInt8(255, offset) 156 | writeUInt64LE(buffer, number, offset + 1) 157 | } 158 | 159 | return size 160 | } 161 | 162 | function varIntBuffer (i) { 163 | var size = varIntSize(i) 164 | var buffer = new Buffer(size) 165 | writeVarInt(buffer, i, 0) 166 | 167 | return buffer 168 | } 169 | 170 | module.exports = { 171 | equal: require('buffer-equals'), 172 | pushDataSize: pushDataSize, 173 | readPushDataInt: readPushDataInt, 174 | readUInt64LE: readUInt64LE, 175 | readVarInt: readVarInt, 176 | reverse: require('buffer-reverse'), 177 | varIntBuffer: varIntBuffer, 178 | varIntSize: varIntSize, 179 | writePushDataInt: writePushDataInt, 180 | writeUInt64LE: writeUInt64LE, 181 | writeVarInt: writeVarInt 182 | } 183 | -------------------------------------------------------------------------------- /src/crypto.js: -------------------------------------------------------------------------------- 1 | var createHash = require('create-hash') 2 | 3 | function hash160 (buffer) { 4 | return ripemd160(sha256(buffer)) 5 | } 6 | 7 | function hash256 (buffer) { 8 | return sha256(sha256(buffer)) 9 | } 10 | 11 | function ripemd160 (buffer) { 12 | return createHash('rmd160').update(buffer).digest() 13 | } 14 | 15 | function sha1 (buffer) { 16 | return createHash('sha1').update(buffer).digest() 17 | } 18 | 19 | function sha256 (buffer) { 20 | return createHash('sha256').update(buffer).digest() 21 | } 22 | 23 | module.exports = { 24 | hash160: hash160, 25 | hash256: hash256, 26 | ripemd160: ripemd160, 27 | sha1: sha1, 28 | sha256: sha256 29 | } 30 | -------------------------------------------------------------------------------- /src/ecdsa.js: -------------------------------------------------------------------------------- 1 | var createHmac = require('create-hmac') 2 | var typeforce = require('typeforce') 3 | var types = require('./types') 4 | 5 | var BigInteger = require('bigi') 6 | var ECSignature = require('./ecsignature') 7 | 8 | var ZERO = new Buffer([0]) 9 | var ONE = new Buffer([1]) 10 | 11 | var ecurve = require('ecurve') 12 | var secp256k1 = ecurve.getCurveByName('secp256k1') 13 | 14 | // https://tools.ietf.org/html/rfc6979#section-3.2 15 | function deterministicGenerateK (hash, x, checkSig) { 16 | typeforce(types.tuple( 17 | types.Hash256bit, 18 | types.Buffer256bit, 19 | types.Function 20 | ), arguments) 21 | 22 | var k = new Buffer(32) 23 | var v = new Buffer(32) 24 | 25 | // Step A, ignored as hash already provided 26 | // Step B 27 | v.fill(1) 28 | 29 | // Step C 30 | k.fill(0) 31 | 32 | // Step D 33 | k = createHmac('sha256', k) 34 | .update(v) 35 | .update(ZERO) 36 | .update(x) 37 | .update(hash) 38 | .digest() 39 | 40 | // Step E 41 | v = createHmac('sha256', k).update(v).digest() 42 | 43 | // Step F 44 | k = createHmac('sha256', k) 45 | .update(v) 46 | .update(ONE) 47 | .update(x) 48 | .update(hash) 49 | .digest() 50 | 51 | // Step G 52 | v = createHmac('sha256', k).update(v).digest() 53 | 54 | // Step H1/H2a, ignored as tlen === qlen (256 bit) 55 | // Step H2b 56 | v = createHmac('sha256', k).update(v).digest() 57 | 58 | var T = BigInteger.fromBuffer(v) 59 | 60 | // Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA 61 | while (T.signum() <= 0 || T.compareTo(secp256k1.n) >= 0 || !checkSig(T)) { 62 | k = createHmac('sha256', k) 63 | .update(v) 64 | .update(ZERO) 65 | .digest() 66 | 67 | v = createHmac('sha256', k).update(v).digest() 68 | 69 | // Step H1/H2a, again, ignored as tlen === qlen (256 bit) 70 | // Step H2b again 71 | v = createHmac('sha256', k).update(v).digest() 72 | T = BigInteger.fromBuffer(v) 73 | } 74 | 75 | return T 76 | } 77 | 78 | var N_OVER_TWO = secp256k1.n.shiftRight(1) 79 | 80 | function sign (hash, d) { 81 | typeforce(types.tuple(types.Hash256bit, types.BigInt), arguments) 82 | 83 | var x = d.toBuffer(32) 84 | var e = BigInteger.fromBuffer(hash) 85 | var n = secp256k1.n 86 | var G = secp256k1.G 87 | 88 | var r, s 89 | deterministicGenerateK(hash, x, function (k) { 90 | var Q = G.multiply(k) 91 | 92 | if (secp256k1.isInfinity(Q)) return false 93 | 94 | r = Q.affineX.mod(n) 95 | if (r.signum() === 0) return false 96 | 97 | s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n) 98 | if (s.signum() === 0) return false 99 | 100 | return true 101 | }) 102 | 103 | // enforce low S values, see bip62: 'low s values in signatures' 104 | if (s.compareTo(N_OVER_TWO) > 0) { 105 | s = n.subtract(s) 106 | } 107 | 108 | return new ECSignature(r, s) 109 | } 110 | 111 | function verify (hash, signature, Q) { 112 | typeforce(types.tuple( 113 | types.Hash256bit, 114 | types.ECSignature, 115 | types.ECPoint 116 | ), arguments) 117 | 118 | var n = secp256k1.n 119 | var G = secp256k1.G 120 | 121 | var r = signature.r 122 | var s = signature.s 123 | 124 | // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1] 125 | if (r.signum() <= 0 || r.compareTo(n) >= 0) return false 126 | if (s.signum() <= 0 || s.compareTo(n) >= 0) return false 127 | 128 | // 1.4.2 H = Hash(M), already done by the user 129 | // 1.4.3 e = H 130 | var e = BigInteger.fromBuffer(hash) 131 | 132 | // Compute s^-1 133 | var sInv = s.modInverse(n) 134 | 135 | // 1.4.4 Compute u1 = es^−1 mod n 136 | // u2 = rs^−1 mod n 137 | var u1 = e.multiply(sInv).mod(n) 138 | var u2 = r.multiply(sInv).mod(n) 139 | 140 | // 1.4.5 Compute R = (xR, yR) 141 | // R = u1G + u2Q 142 | var R = G.multiplyTwo(u1, Q, u2) 143 | 144 | // 1.4.5 (cont.) Enforce R is not at infinity 145 | if (secp256k1.isInfinity(R)) return false 146 | 147 | // 1.4.6 Convert the field element R.x to an integer 148 | var xR = R.affineX 149 | 150 | // 1.4.7 Set v = xR mod n 151 | var v = xR.mod(n) 152 | 153 | // 1.4.8 If v = r, output "valid", and if v != r, output "invalid" 154 | return v.equals(r) 155 | } 156 | 157 | /** 158 | * Recover a public key from a signature. 159 | * 160 | * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public 161 | * Key Recovery Operation". 162 | * 163 | * http://www.secg.org/download/aid-780/sec1-v2.pdf 164 | */ 165 | function recoverPubKey (e, signature, i) { 166 | typeforce(types.tuple( 167 | types.BigInt, 168 | types.ECSignature, 169 | types.UInt2 170 | ), arguments) 171 | 172 | var n = secp256k1.n 173 | var G = secp256k1.G 174 | var r = signature.r 175 | var s = signature.s 176 | 177 | if (r.signum() <= 0 || r.compareTo(n) >= 0) throw new Error('Invalid r value') 178 | if (s.signum() <= 0 || s.compareTo(n) >= 0) throw new Error('Invalid s value') 179 | 180 | // A set LSB signifies that the y-coordinate is odd 181 | var isYOdd = i & 1 182 | 183 | // The more significant bit specifies whether we should use the 184 | // first or second candidate key. 185 | var isSecondKey = i >> 1 186 | 187 | // 1.1 Let x = r + jn 188 | var x = isSecondKey ? r.add(n) : r 189 | var R = secp256k1.pointFromX(isYOdd, x) 190 | 191 | // 1.4 Check that nR is at infinity 192 | var nR = R.multiply(n) 193 | if (!secp256k1.isInfinity(nR)) throw new Error('nR is not a valid curve point') 194 | 195 | // Compute r^-1 196 | var rInv = r.modInverse(n) 197 | 198 | // Compute -e from e 199 | var eNeg = e.negate().mod(n) 200 | 201 | // 1.6.1 Compute Q = r^-1 (sR - eG) 202 | // Q = r^-1 (sR + -eG) 203 | var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv) 204 | 205 | secp256k1.validate(Q) 206 | 207 | return Q 208 | } 209 | 210 | /** 211 | * Calculate pubkey extraction parameter. 212 | * 213 | * When extracting a pubkey from a signature, we have to 214 | * distinguish four different cases. Rather than putting this 215 | * burden on the verifier, Bitcoin includes a 2-bit value with the 216 | * signature. 217 | * 218 | * This function simply tries all four cases and returns the value 219 | * that resulted in a successful pubkey recovery. 220 | */ 221 | function calcPubKeyRecoveryParam (e, signature, Q) { 222 | typeforce(types.tuple( 223 | types.BigInt, 224 | types.ECSignature, 225 | types.ECPoint 226 | ), arguments) 227 | 228 | for (var i = 0; i < 4; i++) { 229 | var Qprime = recoverPubKey(e, signature, i) 230 | 231 | // 1.6.2 Verify Q 232 | if (Qprime.equals(Q)) { 233 | return i 234 | } 235 | } 236 | 237 | throw new Error('Unable to find valid recovery factor') 238 | } 239 | 240 | module.exports = { 241 | calcPubKeyRecoveryParam: calcPubKeyRecoveryParam, 242 | deterministicGenerateK: deterministicGenerateK, 243 | recoverPubKey: recoverPubKey, 244 | sign: sign, 245 | verify: verify, 246 | 247 | // TODO: remove 248 | __curve: secp256k1 249 | } 250 | -------------------------------------------------------------------------------- /src/ecpair.js: -------------------------------------------------------------------------------- 1 | var bcrypto = require('./crypto') 2 | var bs58check = require('bs58check') 3 | var ecdsa = require('./ecdsa') 4 | var randomBytes = require('randombytes') 5 | var typeforce = require('typeforce') 6 | var types = require('./types') 7 | var wif = require('wif') 8 | 9 | var NETWORKS = require('./networks') 10 | var BigInteger = require('bigi') 11 | 12 | var ecurve = require('ecurve') 13 | var secp256k1 = ecdsa.__curve 14 | 15 | function ECPair (d, Q, options) { 16 | if (options) { 17 | typeforce({ 18 | compressed: types.maybe(types.Boolean), 19 | network: types.maybe(types.Network) 20 | }, options) 21 | } 22 | 23 | options = options || {} 24 | 25 | if (d) { 26 | if (d.signum() <= 0) throw new Error('Private key must be greater than 0') 27 | if (d.compareTo(secp256k1.n) >= 0) throw new Error('Private key must be less than the curve order') 28 | if (Q) throw new TypeError('Unexpected publicKey parameter') 29 | 30 | this.d = d 31 | } else { 32 | typeforce(types.ECPoint, Q) 33 | 34 | this.__Q = Q 35 | } 36 | 37 | this.compressed = options.compressed === undefined ? true : options.compressed 38 | this.network = options.network || NETWORKS.bitcoin 39 | } 40 | 41 | Object.defineProperty(ECPair.prototype, 'Q', { 42 | get: function () { 43 | if (!this.__Q && this.d) { 44 | this.__Q = secp256k1.G.multiply(this.d) 45 | } 46 | 47 | return this.__Q 48 | } 49 | }) 50 | 51 | ECPair.fromPublicKeyBuffer = function (buffer, network) { 52 | var Q = ecurve.Point.decodeFrom(secp256k1, buffer) 53 | 54 | return new ECPair(null, Q, { 55 | compressed: Q.compressed, 56 | network: network 57 | }) 58 | } 59 | 60 | ECPair.fromWIF = function (string, network) { 61 | var buffer = bs58check.decode(string) 62 | 63 | if (types.Array(network)) { 64 | var version = buffer[0] 65 | 66 | network = network.filter(function (network) { 67 | return version === network.wif 68 | }).pop() 69 | 70 | if (!network) throw new Error('Unknown network version') 71 | } 72 | 73 | network = network || NETWORKS.bitcoin 74 | var decoded = wif.decodeRaw(buffer, network.wif) 75 | var d = BigInteger.fromBuffer(decoded.privateKey) 76 | 77 | return new ECPair(d, null, { 78 | compressed: decoded.compressed, 79 | network: network 80 | }) 81 | } 82 | 83 | ECPair.makeRandom = function (options) { 84 | options = options || {} 85 | 86 | var rng = options.rng || randomBytes 87 | 88 | var d 89 | do { 90 | var buffer = rng(32) 91 | typeforce(types.Buffer256bit, buffer) 92 | 93 | d = BigInteger.fromBuffer(buffer) 94 | } while (d.signum() <= 0 || d.compareTo(secp256k1.n) >= 0) 95 | 96 | return new ECPair(d, null, options) 97 | } 98 | 99 | ECPair.prototype.getAddress = function () { 100 | var pubKey = this.getPublicKeyBuffer() 101 | var pubKeyHash = bcrypto.hash160(pubKey) 102 | 103 | var payload = new Buffer(21) 104 | payload.writeUInt8(this.network.pubKeyHash, 0) 105 | pubKeyHash.copy(payload, 1) 106 | 107 | return bs58check.encode(payload) 108 | } 109 | 110 | ECPair.prototype.getNetwork = function () { 111 | return this.network 112 | } 113 | 114 | ECPair.prototype.getPublicKeyBuffer = function () { 115 | return this.Q.getEncoded(this.compressed) 116 | } 117 | 118 | ECPair.prototype.sign = function (hash) { 119 | if (!this.d) throw new Error('Missing private key') 120 | 121 | return ecdsa.sign(hash, this.d) 122 | } 123 | 124 | ECPair.prototype.toWIF = function () { 125 | if (!this.d) throw new Error('Missing private key') 126 | 127 | return wif.encode(this.network.wif, this.d.toBuffer(32), this.compressed) 128 | } 129 | 130 | ECPair.prototype.verify = function (hash, signature) { 131 | return ecdsa.verify(hash, signature, this.Q) 132 | } 133 | 134 | module.exports = ECPair 135 | -------------------------------------------------------------------------------- /src/ecsignature.js: -------------------------------------------------------------------------------- 1 | var bip66 = require('bip66') 2 | var typeforce = require('typeforce') 3 | var types = require('./types') 4 | 5 | var BigInteger = require('bigi') 6 | 7 | function ECSignature (r, s) { 8 | typeforce(types.tuple(types.BigInt, types.BigInt), arguments) 9 | 10 | this.r = r 11 | this.s = s 12 | } 13 | 14 | ECSignature.parseCompact = function (buffer) { 15 | if (buffer.length !== 65) throw new Error('Invalid signature length') 16 | 17 | var flagByte = buffer.readUInt8(0) - 27 18 | if (flagByte !== (flagByte & 7)) throw new Error('Invalid signature parameter') 19 | 20 | var compressed = !!(flagByte & 4) 21 | var recoveryParam = flagByte & 3 22 | 23 | var r = BigInteger.fromBuffer(buffer.slice(1, 33)) 24 | var s = BigInteger.fromBuffer(buffer.slice(33)) 25 | 26 | return { 27 | compressed: compressed, 28 | i: recoveryParam, 29 | signature: new ECSignature(r, s) 30 | } 31 | } 32 | 33 | ECSignature.fromDER = function (buffer) { 34 | var decode = bip66.decode(buffer) 35 | var r = BigInteger.fromDERInteger(decode.r) 36 | var s = BigInteger.fromDERInteger(decode.s) 37 | 38 | return new ECSignature(r, s) 39 | } 40 | 41 | // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) 42 | ECSignature.parseScriptSignature = function (buffer) { 43 | var hashType = buffer.readUInt8(buffer.length - 1) 44 | var hashTypeMod = hashType & ~0x80 45 | 46 | if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04) throw new Error('Invalid hashType ' + hashType) 47 | 48 | return { 49 | signature: ECSignature.fromDER(buffer.slice(0, -1)), 50 | hashType: hashType 51 | } 52 | } 53 | 54 | ECSignature.prototype.toCompact = function (i, compressed) { 55 | if (compressed) { 56 | i += 4 57 | } 58 | 59 | i += 27 60 | 61 | var buffer = new Buffer(65) 62 | buffer.writeUInt8(i, 0) 63 | 64 | this.r.toBuffer(32).copy(buffer, 1) 65 | this.s.toBuffer(32).copy(buffer, 33) 66 | 67 | return buffer 68 | } 69 | 70 | ECSignature.prototype.toDER = function () { 71 | var r = new Buffer(this.r.toDERInteger()) 72 | var s = new Buffer(this.s.toDERInteger()) 73 | 74 | return bip66.encode(r, s) 75 | } 76 | 77 | ECSignature.prototype.toScriptSignature = function (hashType) { 78 | var hashTypeMod = hashType & ~0x80 79 | if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) 80 | 81 | var hashTypeBuffer = new Buffer(1) 82 | hashTypeBuffer.writeUInt8(hashType, 0) 83 | 84 | return Buffer.concat([this.toDER(), hashTypeBuffer]) 85 | } 86 | 87 | module.exports = ECSignature 88 | -------------------------------------------------------------------------------- /src/hdnode.js: -------------------------------------------------------------------------------- 1 | var base58check = require('bs58check') 2 | var bcrypto = require('./crypto') 3 | var createHmac = require('create-hmac') 4 | var typeforce = require('typeforce') 5 | var types = require('./types') 6 | var NETWORKS = require('./networks') 7 | 8 | var BigInteger = require('bigi') 9 | var ECPair = require('./ecpair') 10 | 11 | var ecurve = require('ecurve') 12 | var curve = ecurve.getCurveByName('secp256k1') 13 | 14 | function HDNode (keyPair, chainCode) { 15 | typeforce(types.tuple('ECPair', types.Buffer256bit), arguments) 16 | 17 | if (!keyPair.compressed) throw new TypeError('BIP32 only allows compressed keyPairs') 18 | 19 | this.keyPair = keyPair 20 | this.chainCode = chainCode 21 | this.depth = 0 22 | this.index = 0 23 | this.parentFingerprint = 0x00000000 24 | } 25 | 26 | HDNode.HIGHEST_BIT = 0x80000000 27 | HDNode.LENGTH = 78 28 | HDNode.MASTER_SECRET = new Buffer('Bitcoin seed') 29 | 30 | HDNode.fromSeedBuffer = function (seed, network) { 31 | typeforce(types.tuple(types.Buffer, types.maybe(types.Network)), arguments) 32 | 33 | if (seed.length < 16) throw new TypeError('Seed should be at least 128 bits') 34 | if (seed.length > 64) throw new TypeError('Seed should be at most 512 bits') 35 | 36 | var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest() 37 | var IL = I.slice(0, 32) 38 | var IR = I.slice(32) 39 | 40 | // In case IL is 0 or >= n, the master key is invalid 41 | // This is handled by the ECPair constructor 42 | var pIL = BigInteger.fromBuffer(IL) 43 | var keyPair = new ECPair(pIL, null, { 44 | network: network 45 | }) 46 | 47 | return new HDNode(keyPair, IR) 48 | } 49 | 50 | HDNode.fromSeedHex = function (hex, network) { 51 | return HDNode.fromSeedBuffer(new Buffer(hex, 'hex'), network) 52 | } 53 | 54 | HDNode.fromBase58 = function (string, networks) { 55 | var buffer = base58check.decode(string) 56 | if (buffer.length !== 78) throw new Error('Invalid buffer length') 57 | 58 | // 4 bytes: version bytes 59 | var version = buffer.readUInt32BE(0) 60 | var network 61 | 62 | // list of networks? 63 | if (Array.isArray(networks)) { 64 | network = networks.filter(function (network) { 65 | return version === network.bip32.private || 66 | version === network.bip32.public 67 | }).pop() 68 | 69 | if (!network) throw new Error('Unknown network version') 70 | 71 | // otherwise, assume a network object (or default to bitcoin) 72 | } else { 73 | network = networks || NETWORKS.bitcoin 74 | } 75 | 76 | if (version !== network.bip32.private && 77 | version !== network.bip32.public) throw new Error('Invalid network version') 78 | 79 | // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ... 80 | var depth = buffer[4] 81 | 82 | // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) 83 | var parentFingerprint = buffer.readUInt32BE(5) 84 | if (depth === 0) { 85 | if (parentFingerprint !== 0x00000000) throw new Error('Invalid parent fingerprint') 86 | } 87 | 88 | // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized. 89 | // This is encoded in MSB order. (0x00000000 if master key) 90 | var index = buffer.readUInt32BE(9) 91 | if (depth === 0 && index !== 0) throw new Error('Invalid index') 92 | 93 | // 32 bytes: the chain code 94 | var chainCode = buffer.slice(13, 45) 95 | var keyPair 96 | 97 | // 33 bytes: private key data (0x00 + k) 98 | if (version === network.bip32.private) { 99 | if (buffer.readUInt8(45) !== 0x00) throw new Error('Invalid private key') 100 | 101 | var d = BigInteger.fromBuffer(buffer.slice(46, 78)) 102 | 103 | keyPair = new ECPair(d, null, { 104 | network: network 105 | }) 106 | 107 | // 33 bytes: public key data (0x02 + X or 0x03 + X) 108 | } else { 109 | var Q = ecurve.Point.decodeFrom(curve, buffer.slice(45, 78)) 110 | if (!Q.compressed) throw new Error('Invalid public key') 111 | 112 | // Verify that the X coordinate in the public point corresponds to a point on the curve. 113 | // If not, the extended public key is invalid. 114 | curve.validate(Q) 115 | 116 | keyPair = new ECPair(null, Q, { 117 | network: network 118 | }) 119 | } 120 | 121 | var hd = new HDNode(keyPair, chainCode) 122 | hd.depth = depth 123 | hd.index = index 124 | hd.parentFingerprint = parentFingerprint 125 | 126 | return hd 127 | } 128 | 129 | HDNode.prototype.getAddress = function () { 130 | return this.keyPair.getAddress() 131 | } 132 | 133 | HDNode.prototype.getIdentifier = function () { 134 | return bcrypto.hash160(this.keyPair.getPublicKeyBuffer()) 135 | } 136 | 137 | HDNode.prototype.getFingerprint = function () { 138 | return this.getIdentifier().slice(0, 4) 139 | } 140 | 141 | HDNode.prototype.getNetwork = function () { 142 | return this.keyPair.getNetwork() 143 | } 144 | 145 | HDNode.prototype.getPublicKeyBuffer = function () { 146 | return this.keyPair.getPublicKeyBuffer() 147 | } 148 | 149 | HDNode.prototype.neutered = function () { 150 | var neuteredKeyPair = new ECPair(null, this.keyPair.Q, { 151 | network: this.keyPair.network 152 | }) 153 | 154 | var neutered = new HDNode(neuteredKeyPair, this.chainCode) 155 | neutered.depth = this.depth 156 | neutered.index = this.index 157 | neutered.parentFingerprint = this.parentFingerprint 158 | 159 | return neutered 160 | } 161 | 162 | HDNode.prototype.sign = function (hash) { 163 | return this.keyPair.sign(hash) 164 | } 165 | 166 | HDNode.prototype.verify = function (hash, signature) { 167 | return this.keyPair.verify(hash, signature) 168 | } 169 | 170 | HDNode.prototype.toBase58 = function (__isPrivate) { 171 | if (__isPrivate !== undefined) throw new TypeError('Unsupported argument in 2.0.0') 172 | 173 | // Version 174 | var network = this.keyPair.network 175 | var version = (!this.isNeutered()) ? network.bip32.private : network.bip32.public 176 | var buffer = new Buffer(78) 177 | 178 | // 4 bytes: version bytes 179 | buffer.writeUInt32BE(version, 0) 180 | 181 | // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, .... 182 | buffer.writeUInt8(this.depth, 4) 183 | 184 | // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) 185 | buffer.writeUInt32BE(this.parentFingerprint, 5) 186 | 187 | // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized. 188 | // This is encoded in big endian. (0x00000000 if master key) 189 | buffer.writeUInt32BE(this.index, 9) 190 | 191 | // 32 bytes: the chain code 192 | this.chainCode.copy(buffer, 13) 193 | 194 | // 33 bytes: the public key or private key data 195 | if (!this.isNeutered()) { 196 | // 0x00 + k for private keys 197 | buffer.writeUInt8(0, 45) 198 | this.keyPair.d.toBuffer(32).copy(buffer, 46) 199 | 200 | // 33 bytes: the public key 201 | } else { 202 | // X9.62 encoding for public keys 203 | this.keyPair.getPublicKeyBuffer().copy(buffer, 45) 204 | } 205 | 206 | return base58check.encode(buffer) 207 | } 208 | 209 | // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions 210 | HDNode.prototype.derive = function (index) { 211 | typeforce(types.UInt32, index) 212 | 213 | var isHardened = index >= HDNode.HIGHEST_BIT 214 | var data = new Buffer(37) 215 | 216 | // Hardened child 217 | if (isHardened) { 218 | if (this.isNeutered()) throw new TypeError('Could not derive hardened child key') 219 | 220 | // data = 0x00 || ser256(kpar) || ser32(index) 221 | data[0] = 0x00 222 | this.keyPair.d.toBuffer(32).copy(data, 1) 223 | data.writeUInt32BE(index, 33) 224 | 225 | // Normal child 226 | } else { 227 | // data = serP(point(kpar)) || ser32(index) 228 | // = serP(Kpar) || ser32(index) 229 | this.keyPair.getPublicKeyBuffer().copy(data, 0) 230 | data.writeUInt32BE(index, 33) 231 | } 232 | 233 | var I = createHmac('sha512', this.chainCode).update(data).digest() 234 | var IL = I.slice(0, 32) 235 | var IR = I.slice(32) 236 | 237 | var pIL = BigInteger.fromBuffer(IL) 238 | 239 | // In case parse256(IL) >= n, proceed with the next value for i 240 | if (pIL.compareTo(curve.n) >= 0) { 241 | return this.derive(index + 1) 242 | } 243 | 244 | // Private parent key -> private child key 245 | var derivedKeyPair 246 | if (!this.isNeutered()) { 247 | // ki = parse256(IL) + kpar (mod n) 248 | var ki = pIL.add(this.keyPair.d).mod(curve.n) 249 | 250 | // In case ki == 0, proceed with the next value for i 251 | if (ki.signum() === 0) { 252 | return this.derive(index + 1) 253 | } 254 | 255 | derivedKeyPair = new ECPair(ki, null, { 256 | network: this.keyPair.network 257 | }) 258 | 259 | // Public parent key -> public child key 260 | } else { 261 | // Ki = point(parse256(IL)) + Kpar 262 | // = G*IL + Kpar 263 | var Ki = curve.G.multiply(pIL).add(this.keyPair.Q) 264 | 265 | // In case Ki is the point at infinity, proceed with the next value for i 266 | if (curve.isInfinity(Ki)) { 267 | return this.derive(index + 1) 268 | } 269 | 270 | derivedKeyPair = new ECPair(null, Ki, { 271 | network: this.keyPair.network 272 | }) 273 | } 274 | 275 | var hd = new HDNode(derivedKeyPair, IR) 276 | hd.depth = this.depth + 1 277 | hd.index = index 278 | hd.parentFingerprint = this.getFingerprint().readUInt32BE(0) 279 | 280 | return hd 281 | } 282 | 283 | HDNode.prototype.deriveHardened = function (index) { 284 | typeforce(types.UInt31, index) 285 | 286 | // Only derives hardened private keys by default 287 | return this.derive(index + HDNode.HIGHEST_BIT) 288 | } 289 | 290 | // Private === not neutered 291 | // Public === neutered 292 | HDNode.prototype.isNeutered = function () { 293 | return !(this.keyPair.d) 294 | } 295 | 296 | HDNode.prototype.derivePath = function (path) { 297 | typeforce(types.Bip32Path, path) 298 | 299 | var splitPath = path.split('/') 300 | if (splitPath[0] === 'm') { 301 | if (this.parentFingerprint) { 302 | throw new Error('Not a master node') 303 | } 304 | 305 | splitPath = splitPath.slice(1) 306 | } 307 | 308 | return splitPath.reduce(function (prevHd, indexStr) { 309 | var index 310 | if (indexStr.slice(-1) === "'") { 311 | index = parseInt(indexStr.slice(0, -1), 10) 312 | return prevHd.deriveHardened(index) 313 | } else { 314 | index = parseInt(indexStr, 10) 315 | return prevHd.derive(index) 316 | } 317 | }, this) 318 | } 319 | 320 | HDNode.prototype.toString = HDNode.prototype.toBase58 321 | 322 | module.exports = HDNode 323 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Block: require('./block'), 3 | ECPair: require('./ecpair'), 4 | ECSignature: require('./ecsignature'), 5 | HDNode: require('./hdnode'), 6 | Transaction: require('./transaction'), 7 | TransactionBuilder: require('./transaction_builder'), 8 | 9 | address: require('./address'), 10 | bufferutils: require('./bufferutils'), 11 | crypto: require('./crypto'), 12 | message: require('./message'), 13 | networks: require('./networks'), 14 | opcodes: require('./opcodes'), 15 | script: require('./script') 16 | } 17 | -------------------------------------------------------------------------------- /src/message.js: -------------------------------------------------------------------------------- 1 | var bufferutils = require('./bufferutils') 2 | var bcrypto = require('./crypto') 3 | var ecdsa = require('./ecdsa') 4 | var networks = require('./networks') 5 | 6 | var BigInteger = require('bigi') 7 | var ECPair = require('./ecpair') 8 | var ECSignature = require('./ecsignature') 9 | 10 | function magicHash (message, network) { 11 | var messagePrefix = new Buffer(network.messagePrefix) 12 | var messageBuffer = new Buffer(message) 13 | var lengthBuffer = bufferutils.varIntBuffer(messageBuffer.length) 14 | 15 | var buffer = Buffer.concat([messagePrefix, lengthBuffer, messageBuffer]) 16 | return bcrypto.hash256(buffer) 17 | } 18 | 19 | function sign (keyPair, message, network) { 20 | network = network || networks.bitcoin 21 | 22 | var hash = magicHash(message, network) 23 | var signature = keyPair.sign(hash) 24 | var e = BigInteger.fromBuffer(hash) 25 | var i = ecdsa.calcPubKeyRecoveryParam(e, signature, keyPair.Q) 26 | 27 | return signature.toCompact(i, keyPair.compressed) 28 | } 29 | 30 | function verify (address, signature, message, network) { 31 | if (!Buffer.isBuffer(signature)) { 32 | signature = new Buffer(signature, 'base64') 33 | } 34 | 35 | network = network || networks.bitcoin 36 | 37 | var hash = magicHash(message, network) 38 | var parsed = ECSignature.parseCompact(signature) 39 | var e = BigInteger.fromBuffer(hash) 40 | var Q = ecdsa.recoverPubKey(e, parsed.signature, parsed.i) 41 | 42 | var keyPair = new ECPair(null, Q, { 43 | compressed: parsed.compressed, 44 | network: network 45 | }) 46 | 47 | return keyPair.getAddress() === address 48 | } 49 | 50 | module.exports = { 51 | magicHash: magicHash, 52 | sign: sign, 53 | verify: verify 54 | } 55 | -------------------------------------------------------------------------------- /src/networks.js: -------------------------------------------------------------------------------- 1 | // https://en.bitcoin.it/wiki/List_of_address_prefixes 2 | // Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 3 | 4 | module.exports = { 5 | bitcoin: { 6 | messagePrefix: '\x18Bitcoin Signed Message:\n', 7 | bip32: { 8 | public: 0x0488b21e, 9 | private: 0x0488ade4 10 | }, 11 | pubKeyHash: 0x00, 12 | scriptHash: 0x05, 13 | wif: 0x80, 14 | dustThreshold: 546 // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162 15 | }, 16 | testnet: { 17 | messagePrefix: '\x18Bitcoin Signed Message:\n', 18 | bip32: { 19 | public: 0x043587cf, 20 | private: 0x04358394 21 | }, 22 | pubKeyHash: 0x6f, 23 | scriptHash: 0xc4, 24 | wif: 0xef, 25 | dustThreshold: 546 26 | }, 27 | litecoin: { 28 | messagePrefix: '\x19Litecoin Signed Message:\n', 29 | bip32: { 30 | public: 0x019da462, 31 | private: 0x019d9cfe 32 | }, 33 | pubKeyHash: 0x30, 34 | scriptHash: 0x05, 35 | wif: 0xb0, 36 | dustThreshold: 0 // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365 37 | }, 38 | dogecoin: { 39 | messagePrefix: '\x19Dogecoin Signed Message:\n', 40 | bip32: { 41 | public: 0x02facafd, 42 | private: 0x02fac398 43 | }, 44 | pubKeyHash: 0x1e, 45 | scriptHash: 0x16, 46 | wif: 0x9e, 47 | dustThreshold: 0 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160 48 | }, 49 | smileycoin: { 50 | messagePrefix: '\x21Smileycoin Signed Message:\n', 51 | bip32: { 52 | public: 0x13562D9A, 53 | private: 0x1E5631BC 54 | }, 55 | pubKeyHash: 0x19, 56 | scriptHash: 0x05, 57 | wif: 0x99, 58 | dustThreshold: 0 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/opcodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "OP_FALSE": 0, 3 | "OP_0": 0, 4 | "OP_PUSHDATA1": 76, 5 | "OP_PUSHDATA2": 77, 6 | "OP_PUSHDATA4": 78, 7 | "OP_1NEGATE": 79, 8 | "OP_RESERVED": 80, 9 | "OP_1": 81, 10 | "OP_TRUE": 81, 11 | "OP_2": 82, 12 | "OP_3": 83, 13 | "OP_4": 84, 14 | "OP_5": 85, 15 | "OP_6": 86, 16 | "OP_7": 87, 17 | "OP_8": 88, 18 | "OP_9": 89, 19 | "OP_10": 90, 20 | "OP_11": 91, 21 | "OP_12": 92, 22 | "OP_13": 93, 23 | "OP_14": 94, 24 | "OP_15": 95, 25 | "OP_16": 96, 26 | 27 | "OP_NOP": 97, 28 | "OP_VER": 98, 29 | "OP_IF": 99, 30 | "OP_NOTIF": 100, 31 | "OP_VERIF": 101, 32 | "OP_VERNOTIF": 102, 33 | "OP_ELSE": 103, 34 | "OP_ENDIF": 104, 35 | "OP_VERIFY": 105, 36 | "OP_RETURN": 106, 37 | 38 | "OP_TOALTSTACK": 107, 39 | "OP_FROMALTSTACK": 108, 40 | "OP_2DROP": 109, 41 | "OP_2DUP": 110, 42 | "OP_3DUP": 111, 43 | "OP_2OVER": 112, 44 | "OP_2ROT": 113, 45 | "OP_2SWAP": 114, 46 | "OP_IFDUP": 115, 47 | "OP_DEPTH": 116, 48 | "OP_DROP": 117, 49 | "OP_DUP": 118, 50 | "OP_NIP": 119, 51 | "OP_OVER": 120, 52 | "OP_PICK": 121, 53 | "OP_ROLL": 122, 54 | "OP_ROT": 123, 55 | "OP_SWAP": 124, 56 | "OP_TUCK": 125, 57 | 58 | "OP_CAT": 126, 59 | "OP_SUBSTR": 127, 60 | "OP_LEFT": 128, 61 | "OP_RIGHT": 129, 62 | "OP_SIZE": 130, 63 | 64 | "OP_INVERT": 131, 65 | "OP_AND": 132, 66 | "OP_OR": 133, 67 | "OP_XOR": 134, 68 | "OP_EQUAL": 135, 69 | "OP_EQUALVERIFY": 136, 70 | "OP_RESERVED1": 137, 71 | "OP_RESERVED2": 138, 72 | 73 | "OP_1ADD": 139, 74 | "OP_1SUB": 140, 75 | "OP_2MUL": 141, 76 | "OP_2DIV": 142, 77 | "OP_NEGATE": 143, 78 | "OP_ABS": 144, 79 | "OP_NOT": 145, 80 | "OP_0NOTEQUAL": 146, 81 | "OP_ADD": 147, 82 | "OP_SUB": 148, 83 | "OP_MUL": 149, 84 | "OP_DIV": 150, 85 | "OP_MOD": 151, 86 | "OP_LSHIFT": 152, 87 | "OP_RSHIFT": 153, 88 | 89 | "OP_BOOLAND": 154, 90 | "OP_BOOLOR": 155, 91 | "OP_NUMEQUAL": 156, 92 | "OP_NUMEQUALVERIFY": 157, 93 | "OP_NUMNOTEQUAL": 158, 94 | "OP_LESSTHAN": 159, 95 | "OP_GREATERTHAN": 160, 96 | "OP_LESSTHANOREQUAL": 161, 97 | "OP_GREATERTHANOREQUAL": 162, 98 | "OP_MIN": 163, 99 | "OP_MAX": 164, 100 | 101 | "OP_WITHIN": 165, 102 | 103 | "OP_RIPEMD160": 166, 104 | "OP_SHA1": 167, 105 | "OP_SHA256": 168, 106 | "OP_HASH160": 169, 107 | "OP_HASH256": 170, 108 | "OP_CODESEPARATOR": 171, 109 | "OP_CHECKSIG": 172, 110 | "OP_CHECKSIGVERIFY": 173, 111 | "OP_CHECKMULTISIG": 174, 112 | "OP_CHECKMULTISIGVERIFY": 175, 113 | 114 | "OP_NOP1": 176, 115 | "OP_NOP2": 177, 116 | "OP_CHECKLOCKTIMEVERIFY": 177, 117 | 118 | "OP_NOP3": 178, 119 | "OP_NOP4": 179, 120 | "OP_NOP5": 180, 121 | "OP_NOP6": 181, 122 | "OP_NOP7": 182, 123 | "OP_NOP8": 183, 124 | "OP_NOP9": 184, 125 | "OP_NOP10": 185, 126 | 127 | "OP_PUBKEYHASH": 253, 128 | "OP_PUBKEY": 254, 129 | "OP_INVALIDOPCODE": 255 130 | } 131 | -------------------------------------------------------------------------------- /src/script.js: -------------------------------------------------------------------------------- 1 | var bip66 = require('bip66') 2 | var bufferutils = require('./bufferutils') 3 | var typeforce = require('typeforce') 4 | var types = require('./types') 5 | 6 | var OPS = require('./opcodes') 7 | var REVERSE_OPS = (function () { 8 | var result = {} 9 | for (var op in OPS) { 10 | var code = OPS[op] 11 | result[code] = op 12 | } 13 | return result 14 | })() 15 | 16 | var OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 17 | 18 | function toASM (chunks) { 19 | if (Buffer.isBuffer(chunks)) { 20 | chunks = decompile(chunks) 21 | } 22 | 23 | return chunks.map(function (chunk) { 24 | // data? 25 | if (Buffer.isBuffer(chunk)) return chunk.toString('hex') 26 | 27 | // opcode! 28 | return REVERSE_OPS[chunk] 29 | }).join(' ') 30 | } 31 | 32 | function fromASM (asm) { 33 | typeforce(types.String, asm) 34 | 35 | return compile(asm.split(' ').map(function (chunkStr) { 36 | // opcode? 37 | if (OPS[chunkStr] !== undefined) return OPS[chunkStr] 38 | 39 | // data! 40 | return new Buffer(chunkStr, 'hex') 41 | })) 42 | } 43 | 44 | function compile (chunks) { 45 | // TODO: remove me 46 | if (Buffer.isBuffer(chunks)) return chunks 47 | 48 | typeforce(types.Array, chunks) 49 | 50 | var bufferSize = chunks.reduce(function (accum, chunk) { 51 | // data chunk 52 | if (Buffer.isBuffer(chunk)) { 53 | return accum + bufferutils.pushDataSize(chunk.length) + chunk.length 54 | } 55 | 56 | // opcode 57 | return accum + 1 58 | }, 0.0) 59 | 60 | var buffer = new Buffer(bufferSize) 61 | var offset = 0 62 | 63 | chunks.forEach(function (chunk) { 64 | // data chunk 65 | if (Buffer.isBuffer(chunk)) { 66 | offset += bufferutils.writePushDataInt(buffer, chunk.length, offset) 67 | 68 | chunk.copy(buffer, offset) 69 | offset += chunk.length 70 | 71 | // opcode 72 | } else { 73 | buffer.writeUInt8(chunk, offset) 74 | offset += 1 75 | } 76 | }) 77 | 78 | if (offset !== buffer.length) throw new Error('Could not decode chunks') 79 | return buffer 80 | } 81 | 82 | function decompile (buffer) { 83 | // TODO: remove me 84 | if (types.Array(buffer)) return buffer 85 | 86 | typeforce(types.Buffer, buffer) 87 | 88 | var chunks = [] 89 | var i = 0 90 | 91 | while (i < buffer.length) { 92 | var opcode = buffer[i] 93 | 94 | // data chunk 95 | if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) { 96 | var d = bufferutils.readPushDataInt(buffer, i) 97 | 98 | // did reading a pushDataInt fail? empty script 99 | if (d === null) return [] 100 | i += d.size 101 | 102 | // attempt to read too much data? empty script 103 | if (i + d.number > buffer.length) return [] 104 | 105 | var data = buffer.slice(i, i + d.number) 106 | i += d.number 107 | 108 | chunks.push(data) 109 | 110 | // opcode 111 | } else { 112 | chunks.push(opcode) 113 | 114 | i += 1 115 | } 116 | } 117 | 118 | return chunks 119 | } 120 | 121 | function isCanonicalPubKey (buffer) { 122 | if (!Buffer.isBuffer(buffer)) return false 123 | if (buffer.length < 33) return false 124 | 125 | switch (buffer[0]) { 126 | case 0x02: 127 | case 0x03: 128 | return buffer.length === 33 129 | case 0x04: 130 | return buffer.length === 65 131 | } 132 | 133 | return false 134 | } 135 | 136 | function isCanonicalSignature (buffer) { 137 | if (!Buffer.isBuffer(buffer)) return false 138 | if (!isDefinedHashType(buffer[buffer.length - 1])) return false 139 | 140 | return bip66.check(buffer.slice(0, -1)) 141 | } 142 | 143 | function isDefinedHashType (hashType) { 144 | var hashTypeMod = hashType & ~0x80 145 | 146 | // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE 147 | return hashTypeMod > 0x00 && hashTypeMod < 0x04 148 | } 149 | 150 | function isPubKeyHashInput (script) { 151 | var chunks = decompile(script) 152 | 153 | return chunks.length === 2 && 154 | isCanonicalSignature(chunks[0]) && 155 | isCanonicalPubKey(chunks[1]) 156 | } 157 | 158 | function isPubKeyHashOutput (script) { 159 | var buffer = compile(script) 160 | 161 | return buffer.length === 25 && 162 | buffer[0] === OPS.OP_DUP && 163 | buffer[1] === OPS.OP_HASH160 && 164 | buffer[2] === 0x14 && 165 | buffer[23] === OPS.OP_EQUALVERIFY && 166 | buffer[24] === OPS.OP_CHECKSIG 167 | } 168 | 169 | function isPubKeyInput (script) { 170 | var chunks = decompile(script) 171 | 172 | return chunks.length === 1 && 173 | isCanonicalSignature(chunks[0]) 174 | } 175 | 176 | function isPubKeyOutput (script) { 177 | var chunks = decompile(script) 178 | 179 | return chunks.length === 2 && 180 | isCanonicalPubKey(chunks[0]) && 181 | chunks[1] === OPS.OP_CHECKSIG 182 | } 183 | 184 | function isScriptHashInput (script, allowIncomplete) { 185 | var chunks = decompile(script) 186 | if (chunks.length < 2) return false 187 | 188 | var lastChunk = chunks[chunks.length - 1] 189 | if (!Buffer.isBuffer(lastChunk)) return false 190 | 191 | var scriptSigChunks = chunks.slice(0, -1) 192 | var redeemScriptChunks = decompile(lastChunk) 193 | 194 | // is redeemScript a valid script? 195 | if (redeemScriptChunks.length === 0) return false 196 | 197 | return classifyInput(scriptSigChunks, allowIncomplete) === classifyOutput(redeemScriptChunks) 198 | } 199 | 200 | function isScriptHashOutput (script) { 201 | var buffer = compile(script) 202 | 203 | return buffer.length === 23 && 204 | buffer[0] === OPS.OP_HASH160 && 205 | buffer[1] === 0x14 && 206 | buffer[22] === OPS.OP_EQUAL 207 | } 208 | 209 | // allowIncomplete is to account for combining signatures 210 | // See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197 211 | function isMultisigInput (script, allowIncomplete) { 212 | var chunks = decompile(script) 213 | if (chunks.length < 2) return false 214 | if (chunks[0] !== OPS.OP_0) return false 215 | 216 | if (allowIncomplete) { 217 | return chunks.slice(1).every(function (chunk) { 218 | return chunk === OPS.OP_0 || isCanonicalSignature(chunk) 219 | }) 220 | } 221 | 222 | return chunks.slice(1).every(isCanonicalSignature) 223 | } 224 | 225 | function isMultisigOutput (script) { 226 | var chunks = decompile(script) 227 | if (chunks.length < 4) return false 228 | if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false 229 | 230 | var mOp = chunks[0] 231 | var nOp = chunks[chunks.length - 2] 232 | 233 | if (!types.Number(mOp)) return false 234 | if (!types.Number(nOp)) return false 235 | 236 | var m = mOp - OP_INT_BASE 237 | var n = nOp - OP_INT_BASE 238 | 239 | // 0 < m <= n <= 16 240 | if (m <= 0) return false 241 | if (m > n) return false 242 | if (n > 16) return false 243 | if (n !== chunks.length - 3) return false 244 | 245 | return chunks.slice(1, -2).every(isCanonicalPubKey) 246 | } 247 | 248 | function isNullDataOutput (script) { 249 | var chunks = decompile(script) 250 | return chunks[0] === OPS.OP_RETURN 251 | } 252 | 253 | function classifyOutput (script) { 254 | var chunks = decompile(script) 255 | 256 | if (isPubKeyHashOutput(chunks)) { 257 | return 'pubkeyhash' 258 | } else if (isScriptHashOutput(chunks)) { 259 | return 'scripthash' 260 | } else if (isMultisigOutput(chunks)) { 261 | return 'multisig' 262 | } else if (isPubKeyOutput(chunks)) { 263 | return 'pubkey' 264 | } else if (isNullDataOutput(chunks)) { 265 | return 'nulldata' 266 | } 267 | 268 | return 'nonstandard' 269 | } 270 | 271 | function classifyInput (script, allowIncomplete) { 272 | var chunks = decompile(script) 273 | 274 | if (isPubKeyHashInput(chunks)) { 275 | return 'pubkeyhash' 276 | } else if (isMultisigInput(chunks, allowIncomplete)) { 277 | return 'multisig' 278 | } else if (isScriptHashInput(chunks, allowIncomplete)) { 279 | return 'scripthash' 280 | } else if (isPubKeyInput(chunks)) { 281 | return 'pubkey' 282 | } 283 | 284 | return 'nonstandard' 285 | } 286 | 287 | // Standard Script Templates 288 | // {pubKey} OP_CHECKSIG 289 | function pubKeyOutput (pubKey) { 290 | return compile([pubKey, OPS.OP_CHECKSIG]) 291 | } 292 | 293 | // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG 294 | function pubKeyHashOutput (pubKeyHash) { 295 | typeforce(types.Hash160bit, pubKeyHash) 296 | 297 | return compile([OPS.OP_DUP, OPS.OP_HASH160, pubKeyHash, OPS.OP_EQUALVERIFY, OPS.OP_CHECKSIG]) 298 | } 299 | 300 | // OP_HASH160 {scriptHash} OP_EQUAL 301 | function scriptHashOutput (scriptHash) { 302 | typeforce(types.Hash160bit, scriptHash) 303 | 304 | return compile([OPS.OP_HASH160, scriptHash, OPS.OP_EQUAL]) 305 | } 306 | 307 | // m [pubKeys ...] n OP_CHECKMULTISIG 308 | function multisigOutput (m, pubKeys) { 309 | typeforce(types.tuple(types.Number, [types.Buffer]), arguments) 310 | 311 | var n = pubKeys.length 312 | if (n < m) throw new Error('Not enough pubKeys provided') 313 | 314 | return compile([].concat( 315 | OP_INT_BASE + m, 316 | pubKeys, 317 | OP_INT_BASE + n, 318 | OPS.OP_CHECKMULTISIG 319 | )) 320 | } 321 | 322 | // {signature} 323 | function pubKeyInput (signature) { 324 | typeforce(types.Buffer, signature) 325 | 326 | return compile([signature]) 327 | } 328 | 329 | // {signature} {pubKey} 330 | function pubKeyHashInput (signature, pubKey) { 331 | typeforce(types.tuple(types.Buffer, types.Buffer), arguments) 332 | 333 | return compile([signature, pubKey]) 334 | } 335 | 336 | // {serialized scriptPubKey script} 337 | function scriptHashInput (scriptSig, scriptPubKey) { 338 | var scriptSigChunks = decompile(scriptSig) 339 | var serializedScriptPubKey = compile(scriptPubKey) 340 | 341 | return compile([].concat( 342 | scriptSigChunks, 343 | serializedScriptPubKey 344 | )) 345 | } 346 | 347 | // OP_0 [signatures ...] 348 | function multisigInput (signatures, scriptPubKey) { 349 | if (scriptPubKey) { 350 | var chunks = decompile(scriptPubKey) 351 | if (!isMultisigOutput(chunks)) throw new Error('Expected multisig scriptPubKey') 352 | 353 | var mOp = chunks[0] 354 | var nOp = chunks[chunks.length - 2] 355 | var m = mOp - OP_INT_BASE 356 | var n = nOp - OP_INT_BASE 357 | 358 | if (signatures.length < m) throw new Error('Not enough signatures provided') 359 | if (signatures.length > n) throw new Error('Too many signatures provided') 360 | } 361 | 362 | return compile([].concat(OPS.OP_0, signatures)) 363 | } 364 | 365 | function nullDataOutput (data) { 366 | return compile([OPS.OP_RETURN, data]) 367 | } 368 | 369 | module.exports = { 370 | compile: compile, 371 | decompile: decompile, 372 | fromASM: fromASM, 373 | toASM: toASM, 374 | 375 | number: require('./script_number'), 376 | 377 | isCanonicalPubKey: isCanonicalPubKey, 378 | isCanonicalSignature: isCanonicalSignature, 379 | isDefinedHashType: isDefinedHashType, 380 | isPubKeyHashInput: isPubKeyHashInput, 381 | isPubKeyHashOutput: isPubKeyHashOutput, 382 | isPubKeyInput: isPubKeyInput, 383 | isPubKeyOutput: isPubKeyOutput, 384 | isScriptHashInput: isScriptHashInput, 385 | isScriptHashOutput: isScriptHashOutput, 386 | isMultisigInput: isMultisigInput, 387 | isMultisigOutput: isMultisigOutput, 388 | isNullDataOutput: isNullDataOutput, 389 | classifyOutput: classifyOutput, 390 | classifyInput: classifyInput, 391 | pubKeyOutput: pubKeyOutput, 392 | pubKeyHashOutput: pubKeyHashOutput, 393 | scriptHashOutput: scriptHashOutput, 394 | multisigOutput: multisigOutput, 395 | pubKeyInput: pubKeyInput, 396 | pubKeyHashInput: pubKeyHashInput, 397 | scriptHashInput: scriptHashInput, 398 | multisigInput: multisigInput, 399 | nullDataOutput: nullDataOutput 400 | } 401 | -------------------------------------------------------------------------------- /src/script_number.js: -------------------------------------------------------------------------------- 1 | function decode (buffer, maxLength, minimal) { 2 | maxLength = maxLength || 4 3 | minimal = minimal === undefined ? true : minimal 4 | 5 | var length = buffer.length 6 | if (length === 0) return 0 7 | if (length > maxLength) throw new TypeError('Script number overflow') 8 | if (minimal) { 9 | if ((buffer[length - 1] & 0x7f) === 0) { 10 | if (length <= 1 || (buffer[length - 2] & 0x80) === 0) throw new Error('Non-minimally encoded script number') 11 | } 12 | } 13 | 14 | // 40-bit 15 | if (length === 5) { 16 | var a = buffer.readUInt32LE(0) 17 | var b = buffer.readUInt8(4) 18 | 19 | if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a) 20 | return b * 0x100000000 + a 21 | } 22 | 23 | var result = 0 24 | 25 | // 32-bit / 24-bit / 16-bit / 8-bit 26 | for (var i = 0; i < length; ++i) { 27 | result |= buffer[i] << (8 * i) 28 | } 29 | 30 | if (buffer[length - 1] & 0x80) return -(result & ~(0x80 << (8 * (length - 1)))) 31 | return result 32 | } 33 | 34 | function scriptNumSize (i) { 35 | return i > 0x7fffffff ? 5 36 | : i > 0x7fffff ? 4 37 | : i > 0x7fff ? 3 38 | : i > 0x7f ? 2 39 | : i > 0x00 ? 1 40 | : 0 41 | } 42 | 43 | function encode (number) { 44 | var value = Math.abs(number) 45 | var size = scriptNumSize(value) 46 | var buffer = new Buffer(size) 47 | var negative = number < 0 48 | 49 | for (var i = 0; i < size; ++i) { 50 | buffer.writeUInt8(value & 0xff, i) 51 | value >>= 8 52 | } 53 | 54 | if (buffer[size - 1] & 0x80) { 55 | buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1) 56 | } else if (negative) { 57 | buffer[size - 1] |= 0x80 58 | } 59 | 60 | return buffer 61 | } 62 | 63 | module.exports = { 64 | decode: decode, 65 | encode: encode 66 | } 67 | -------------------------------------------------------------------------------- /src/transaction.js: -------------------------------------------------------------------------------- 1 | var bcrypto = require('./crypto') 2 | var bscript = require('./script') 3 | var bufferutils = require('./bufferutils') 4 | var opcodes = require('./opcodes') 5 | var typeforce = require('typeforce') 6 | var types = require('./types') 7 | 8 | function Transaction () { 9 | this.version = 1 10 | this.locktime = 0 11 | this.ins = [] 12 | this.outs = [] 13 | } 14 | 15 | Transaction.DEFAULT_SEQUENCE = 0xffffffff 16 | Transaction.SIGHASH_ALL = 0x01 17 | Transaction.SIGHASH_NONE = 0x02 18 | Transaction.SIGHASH_SINGLE = 0x03 19 | Transaction.SIGHASH_ANYONECANPAY = 0x80 20 | 21 | Transaction.fromBuffer = function (buffer, __noStrict) { 22 | var offset = 0 23 | function readSlice (n) { 24 | offset += n 25 | return buffer.slice(offset - n, offset) 26 | } 27 | 28 | function readUInt32 () { 29 | var i = buffer.readUInt32LE(offset) 30 | offset += 4 31 | return i 32 | } 33 | 34 | function readUInt64 () { 35 | var i = bufferutils.readUInt64LE(buffer, offset) 36 | offset += 8 37 | return i 38 | } 39 | 40 | function readVarInt () { 41 | var vi = bufferutils.readVarInt(buffer, offset) 42 | offset += vi.size 43 | return vi.number 44 | } 45 | 46 | function readScript () { 47 | return readSlice(readVarInt()) 48 | } 49 | 50 | var tx = new Transaction() 51 | tx.version = readUInt32() 52 | 53 | var vinLen = readVarInt() 54 | for (var i = 0; i < vinLen; ++i) { 55 | tx.ins.push({ 56 | hash: readSlice(32), 57 | index: readUInt32(), 58 | script: readScript(), 59 | sequence: readUInt32() 60 | }) 61 | } 62 | 63 | var voutLen = readVarInt() 64 | for (i = 0; i < voutLen; ++i) { 65 | tx.outs.push({ 66 | value: readUInt64(), 67 | script: readScript() 68 | }) 69 | } 70 | 71 | tx.locktime = readUInt32() 72 | 73 | if (__noStrict) return tx 74 | if (offset !== buffer.length) throw new Error('Transaction has unexpected data') 75 | 76 | return tx 77 | } 78 | 79 | Transaction.fromHex = function (hex) { 80 | return Transaction.fromBuffer(new Buffer(hex, 'hex')) 81 | } 82 | 83 | Transaction.isCoinbaseHash = function (buffer) { 84 | return Array.prototype.every.call(buffer, function (x) { 85 | return x === 0 86 | }) 87 | } 88 | 89 | var EMPTY_SCRIPT = new Buffer(0) 90 | 91 | Transaction.prototype.addInput = function (hash, index, sequence, scriptSig) { 92 | typeforce(types.tuple( 93 | types.Hash256bit, 94 | types.UInt32, 95 | types.maybe(types.UInt32), 96 | types.maybe(types.Buffer) 97 | ), arguments) 98 | 99 | if (types.Null(sequence)) { 100 | sequence = Transaction.DEFAULT_SEQUENCE 101 | } 102 | 103 | // Add the input and return the input's index 104 | return (this.ins.push({ 105 | hash: hash, 106 | index: index, 107 | script: scriptSig || EMPTY_SCRIPT, 108 | sequence: sequence 109 | }) - 1) 110 | } 111 | 112 | Transaction.prototype.addOutput = function (scriptPubKey, value) { 113 | typeforce(types.tuple(types.Buffer, types.UInt53), arguments) 114 | 115 | // Add the output and return the output's index 116 | return (this.outs.push({ 117 | script: scriptPubKey, 118 | value: value 119 | }) - 1) 120 | } 121 | 122 | Transaction.prototype.byteLength = function () { 123 | function scriptSize (someScript) { 124 | var length = someScript.length 125 | 126 | return bufferutils.varIntSize(length) + length 127 | } 128 | 129 | return ( 130 | 8 + 131 | bufferutils.varIntSize(this.ins.length) + 132 | bufferutils.varIntSize(this.outs.length) + 133 | this.ins.reduce(function (sum, input) { return sum + 40 + scriptSize(input.script) }, 0) + 134 | this.outs.reduce(function (sum, output) { return sum + 8 + scriptSize(output.script) }, 0) 135 | ) 136 | } 137 | 138 | Transaction.prototype.clone = function () { 139 | var newTx = new Transaction() 140 | newTx.version = this.version 141 | newTx.locktime = this.locktime 142 | 143 | newTx.ins = this.ins.map(function (txIn) { 144 | return { 145 | hash: txIn.hash, 146 | index: txIn.index, 147 | script: txIn.script, 148 | sequence: txIn.sequence 149 | } 150 | }) 151 | 152 | newTx.outs = this.outs.map(function (txOut) { 153 | return { 154 | script: txOut.script, 155 | value: txOut.value 156 | } 157 | }) 158 | 159 | return newTx 160 | } 161 | 162 | var ONE = new Buffer('0000000000000000000000000000000000000000000000000000000000000001', 'hex') 163 | var VALUE_UINT64_MAX = new Buffer('ffffffffffffffff', 'hex') 164 | 165 | /** 166 | * Hash transaction for signing a specific input. 167 | * 168 | * Bitcoin uses a different hash for each signed transaction input. 169 | * This method copies the transaction, makes the necessary changes based on the 170 | * hashType, and then hashes the result. 171 | * This hash can then be used to sign the provided transaction input. 172 | */ 173 | Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { 174 | typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) 175 | 176 | // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 177 | if (inIndex >= this.ins.length) return ONE 178 | 179 | var txTmp = this.clone() 180 | 181 | // in case concatenating two scripts ends up with two codeseparators, 182 | // or an extra one at the end, this prevents all those possible incompatibilities. 183 | var hashScript = bscript.compile(bscript.decompile(prevOutScript).filter(function (x) { 184 | return x !== opcodes.OP_CODESEPARATOR 185 | })) 186 | var i 187 | 188 | // blank out other inputs' signatures 189 | txTmp.ins.forEach(function (input) { input.script = EMPTY_SCRIPT }) 190 | txTmp.ins[inIndex].script = hashScript 191 | 192 | // blank out some of the inputs 193 | if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { 194 | // wildcard payee 195 | txTmp.outs = [] 196 | 197 | // let the others update at will 198 | txTmp.ins.forEach(function (input, i) { 199 | if (i !== inIndex) { 200 | input.sequence = 0 201 | } 202 | }) 203 | } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { 204 | var nOut = inIndex 205 | 206 | // only lock-in the txOut payee at same index as txIn 207 | // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 208 | if (nOut >= this.outs.length) return ONE 209 | 210 | txTmp.outs = txTmp.outs.slice(0, nOut + 1) 211 | 212 | // blank all other outputs (clear scriptPubKey, value === -1) 213 | var stubOut = { 214 | script: EMPTY_SCRIPT, 215 | valueBuffer: VALUE_UINT64_MAX 216 | } 217 | 218 | for (i = 0; i < nOut; i++) { 219 | txTmp.outs[i] = stubOut 220 | } 221 | 222 | // let the others update at will 223 | txTmp.ins.forEach(function (input, i) { 224 | if (i !== inIndex) { 225 | input.sequence = 0 226 | } 227 | }) 228 | } 229 | 230 | // blank out other inputs completely, not recommended for open transactions 231 | if (hashType & Transaction.SIGHASH_ANYONECANPAY) { 232 | txTmp.ins[0] = txTmp.ins[inIndex] 233 | txTmp.ins = txTmp.ins.slice(0, 1) 234 | } 235 | 236 | // serialize and hash 237 | var buffer = new Buffer(txTmp.byteLength() + 4) 238 | buffer.writeInt32LE(hashType, buffer.length - 4) 239 | txTmp.toBuffer().copy(buffer, 0) 240 | 241 | return bcrypto.hash256(buffer) 242 | } 243 | 244 | Transaction.prototype.getHash = function () { 245 | return bcrypto.hash256(this.toBuffer()) 246 | } 247 | 248 | Transaction.prototype.getId = function () { 249 | // transaction hash's are displayed in reverse order 250 | return [].reverse.call(this.getHash()).toString('hex') 251 | } 252 | 253 | Transaction.prototype.toBuffer = function () { 254 | var buffer = new Buffer(this.byteLength()) 255 | 256 | var offset = 0 257 | function writeSlice (slice) { 258 | slice.copy(buffer, offset) 259 | offset += slice.length 260 | } 261 | 262 | function writeUInt32 (i) { 263 | buffer.writeUInt32LE(i, offset) 264 | offset += 4 265 | } 266 | 267 | function writeUInt64 (i) { 268 | bufferutils.writeUInt64LE(buffer, i, offset) 269 | offset += 8 270 | } 271 | 272 | function writeVarInt (i) { 273 | var n = bufferutils.writeVarInt(buffer, i, offset) 274 | offset += n 275 | } 276 | 277 | writeUInt32(this.version) 278 | writeVarInt(this.ins.length) 279 | 280 | this.ins.forEach(function (txIn) { 281 | writeSlice(txIn.hash) 282 | writeUInt32(txIn.index) 283 | writeVarInt(txIn.script.length) 284 | writeSlice(txIn.script) 285 | writeUInt32(txIn.sequence) 286 | }) 287 | 288 | writeVarInt(this.outs.length) 289 | this.outs.forEach(function (txOut) { 290 | if (!txOut.valueBuffer) { 291 | writeUInt64(txOut.value) 292 | } else { 293 | writeSlice(txOut.valueBuffer) 294 | } 295 | 296 | writeVarInt(txOut.script.length) 297 | writeSlice(txOut.script) 298 | }) 299 | 300 | writeUInt32(this.locktime) 301 | 302 | return buffer 303 | } 304 | 305 | Transaction.prototype.toHex = function () { 306 | return this.toBuffer().toString('hex') 307 | } 308 | 309 | Transaction.prototype.setInputScript = function (index, scriptSig) { 310 | typeforce(types.tuple(types.Number, types.Buffer), arguments) 311 | 312 | this.ins[index].script = scriptSig 313 | } 314 | 315 | module.exports = Transaction 316 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | var typeforce = require('typeforce') 2 | 3 | function nBuffer (value, n) { 4 | typeforce(types.Buffer, value) 5 | if (value.length !== n) throw new typeforce.TfTypeError('Expected ' + (n * 8) + '-bit Buffer, got ' + (value.length * 8) + '-bit Buffer') 6 | 7 | return true 8 | } 9 | 10 | function Hash160bit (value) { return nBuffer(value, 20) } 11 | function Hash256bit (value) { return nBuffer(value, 32) } 12 | function Buffer256bit (value) { return nBuffer(value, 32) } 13 | 14 | var UINT53_MAX = Math.pow(2, 53) - 1 15 | var UINT31_MAX = Math.pow(2, 31) - 1 16 | function UInt2 (value) { return (value & 3) === value } 17 | function UInt8 (value) { return (value & 0xff) === value } 18 | function UInt32 (value) { return (value >>> 0) === value } 19 | function UInt31 (value) { 20 | return UInt32(value) && value <= UINT31_MAX 21 | } 22 | function UInt53 (value) { 23 | return typeforce.Number(value) && 24 | value >= 0 && 25 | value <= UINT53_MAX && 26 | Math.floor(value) === value 27 | } 28 | 29 | function Bip32Path (value) { 30 | return typeforce.String(value) && 31 | value.match(/^(m\/)?(\d+'?\/)*\d+'?$/) 32 | } 33 | 34 | // external dependent types 35 | var BigInt = typeforce.quacksLike('BigInteger') 36 | var ECPoint = typeforce.quacksLike('Point') 37 | 38 | // exposed, external API 39 | var ECSignature = typeforce.compile({ r: BigInt, s: BigInt }) 40 | var Network = typeforce.compile({ 41 | messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), 42 | bip32: { 43 | public: UInt32, 44 | private: UInt32 45 | }, 46 | pubKeyHash: UInt8, 47 | scriptHash: UInt8, 48 | wif: UInt8, 49 | dustThreshold: UInt53 50 | }) 51 | 52 | // extend typeforce types with ours 53 | var types = { 54 | BigInt: BigInt, 55 | Buffer256bit: Buffer256bit, 56 | ECPoint: ECPoint, 57 | ECSignature: ECSignature, 58 | Hash160bit: Hash160bit, 59 | Hash256bit: Hash256bit, 60 | Network: Network, 61 | UInt2: UInt2, 62 | UInt8: UInt8, 63 | UInt31: UInt31, 64 | UInt32: UInt32, 65 | UInt53: UInt53, 66 | Bip32Path: Bip32Path 67 | } 68 | 69 | for (var typeName in typeforce) { 70 | types[typeName] = typeforce[typeName] 71 | } 72 | 73 | module.exports = types 74 | -------------------------------------------------------------------------------- /test/address.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var baddress = require('../src/address') 5 | var networks = require('../src/networks') 6 | var bscript = require('../src/script') 7 | var fixtures = require('./fixtures/address.json') 8 | 9 | describe('address', function () { 10 | describe('fromBase58Check', function () { 11 | fixtures.valid.forEach(function (f) { 12 | it('decodes ' + f.base58check, function () { 13 | var decode = baddress.fromBase58Check(f.base58check) 14 | 15 | assert.strictEqual(decode.version, f.version) 16 | assert.strictEqual(decode.hash.toString('hex'), f.hash) 17 | }) 18 | }) 19 | 20 | fixtures.invalid.fromBase58Check.forEach(function (f) { 21 | it('throws on ' + f.exception, function () { 22 | assert.throws(function () { 23 | baddress.fromBase58Check(f.address) 24 | }, new RegExp(f.address + ' ' + f.exception)) 25 | }) 26 | }) 27 | }) 28 | 29 | describe('fromOutputScript', function () { 30 | fixtures.valid.forEach(function (f) { 31 | it('parses ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () { 32 | var script = bscript.fromASM(f.script) 33 | var address = baddress.fromOutputScript(script, networks[f.network]) 34 | 35 | assert.strictEqual(address, f.base58check) 36 | }) 37 | }) 38 | 39 | fixtures.valid.forEach(function (f) { 40 | it('parses (as chunks) ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () { 41 | var chunks = bscript.decompile(bscript.fromASM(f.script)) 42 | var address = baddress.fromOutputScript(chunks, networks[f.network]) 43 | 44 | assert.strictEqual(address, f.base58check) 45 | }) 46 | }) 47 | 48 | fixtures.invalid.fromOutputScript.forEach(function (f) { 49 | it('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, function () { 50 | var script = bscript.fromASM(f.script) 51 | 52 | assert.throws(function () { 53 | baddress.fromOutputScript(script) 54 | }, new RegExp(f.script + ' ' + f.exception)) 55 | }) 56 | }) 57 | }) 58 | 59 | describe('toBase58Check', function () { 60 | fixtures.valid.forEach(function (f) { 61 | it('formats ' + f.hash + ' (' + f.network + ')', function () { 62 | var address = baddress.toBase58Check(new Buffer(f.hash, 'hex'), f.version) 63 | 64 | assert.strictEqual(address, f.base58check) 65 | }) 66 | }) 67 | }) 68 | 69 | describe('toOutputScript', function () { 70 | fixtures.valid.forEach(function (f) { 71 | var network = networks[f.network] 72 | 73 | it('exports ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () { 74 | var script = baddress.toOutputScript(f.base58check, network) 75 | 76 | assert.strictEqual(bscript.toASM(script), f.script) 77 | }) 78 | }) 79 | 80 | fixtures.invalid.toOutputScript.forEach(function (f) { 81 | it('throws when ' + f.exception, function () { 82 | assert.throws(function () { 83 | baddress.toOutputScript(f.address) 84 | }, new RegExp(f.address + ' ' + f.exception)) 85 | }) 86 | }) 87 | }) 88 | }) 89 | -------------------------------------------------------------------------------- /test/bitcoin.core.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var base58 = require('bs58') 5 | var bitcoin = require('../') 6 | 7 | var base58_encode_decode = require('./fixtures/core/base58_encode_decode.json') 8 | var base58_keys_invalid = require('./fixtures/core/base58_keys_invalid.json') 9 | var base58_keys_valid = require('./fixtures/core/base58_keys_valid.json') 10 | var blocks_valid = require('./fixtures/core/blocks.json') 11 | var sig_canonical = require('./fixtures/core/sig_canonical.json') 12 | var sig_noncanonical = require('./fixtures/core/sig_noncanonical.json') 13 | var sighash = require('./fixtures/core/sighash.json') 14 | var tx_valid = require('./fixtures/core/tx_valid.json') 15 | 16 | describe('Bitcoin-core', function () { 17 | // base58_encode_decode 18 | describe('base58', function () { 19 | base58_encode_decode.forEach(function (f) { 20 | var fhex = f[0] 21 | var fb58 = f[1] 22 | 23 | it('can decode ' + fb58, function () { 24 | var buffer = base58.decode(fb58) 25 | var actual = new Buffer(buffer).toString('hex') 26 | 27 | assert.strictEqual(actual, fhex) 28 | }) 29 | 30 | it('can encode ' + fhex, function () { 31 | var buffer = new Buffer(fhex, 'hex') 32 | var actual = base58.encode(buffer) 33 | 34 | assert.strictEqual(actual, fb58) 35 | }) 36 | }) 37 | }) 38 | 39 | // base58_keys_valid 40 | describe('address.toBase58Check', function () { 41 | var typeMap = { 42 | 'pubkey': 'pubKeyHash', 43 | 'script': 'scriptHash' 44 | } 45 | 46 | base58_keys_valid.forEach(function (f) { 47 | var expected = f[0] 48 | var hash = new Buffer(f[1], 'hex') 49 | var params = f[2] 50 | 51 | if (params.isPrivkey) return 52 | 53 | var network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin 54 | var version = network[typeMap[params.addrType]] 55 | 56 | it('can export ' + expected, function () { 57 | assert.strictEqual(bitcoin.address.toBase58Check(hash, version), expected) 58 | }) 59 | }) 60 | }) 61 | 62 | // base58_keys_invalid 63 | describe('address.fromBase58Check', function () { 64 | var allowedNetworks = [ 65 | bitcoin.networks.bitcoin.pubkeyhash, 66 | bitcoin.networks.bitcoin.scripthash, 67 | bitcoin.networks.testnet.pubkeyhash, 68 | bitcoin.networks.testnet.scripthash 69 | ] 70 | 71 | base58_keys_invalid.forEach(function (f) { 72 | var string = f[0] 73 | 74 | it('throws on ' + string, function () { 75 | assert.throws(function () { 76 | var address = bitcoin.address.fromBase58Check(string) 77 | 78 | assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network') 79 | }, /(Invalid (checksum|network))|(too (short|long))/) 80 | }) 81 | }) 82 | }) 83 | 84 | // base58_keys_valid 85 | describe('ECPair', function () { 86 | base58_keys_valid.forEach(function (f) { 87 | var string = f[0] 88 | var hex = f[1] 89 | var params = f[2] 90 | 91 | if (!params.isPrivkey) return 92 | 93 | var network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin 94 | var keyPair = bitcoin.ECPair.fromWIF(string, network) 95 | 96 | it('fromWIF imports ' + string, function () { 97 | assert.strictEqual(keyPair.d.toHex(), hex) 98 | assert.strictEqual(keyPair.compressed, params.isCompressed) 99 | }) 100 | 101 | it('toWIF exports ' + hex + ' to ' + string, function () { 102 | assert.strictEqual(keyPair.toWIF(), string) 103 | }) 104 | }) 105 | }) 106 | 107 | // base58_keys_invalid 108 | describe('ECPair.fromWIF', function () { 109 | var allowedNetworks = [ 110 | bitcoin.networks.bitcoin, 111 | bitcoin.networks.testnet 112 | ] 113 | 114 | base58_keys_invalid.forEach(function (f) { 115 | var string = f[0] 116 | 117 | it('throws on ' + string, function () { 118 | assert.throws(function () { 119 | bitcoin.ECPair.fromWIF(string, allowedNetworks) 120 | }, /(Invalid|Unknown) (checksum|compression flag|network version|WIF length)/) 121 | }) 122 | }) 123 | }) 124 | 125 | describe('Block.fromHex', function () { 126 | blocks_valid.forEach(function (f) { 127 | it('can parse ' + f.id, function () { 128 | var block = bitcoin.Block.fromHex(f.hex) 129 | 130 | assert.strictEqual(block.getId(), f.id) 131 | assert.strictEqual(block.transactions.length, f.transactions) 132 | }) 133 | }) 134 | }) 135 | 136 | // tx_valid 137 | describe('Transaction.fromHex', function () { 138 | tx_valid.forEach(function (f) { 139 | // Objects that are only a single string are ignored 140 | if (f.length === 1) return 141 | 142 | var inputs = f[0] 143 | var fhex = f[1] 144 | // var verifyFlags = f[2] // TODO: do we need to test this? 145 | 146 | it('can decode ' + fhex, function () { 147 | var transaction = bitcoin.Transaction.fromHex(fhex) 148 | 149 | transaction.ins.forEach(function (txIn, i) { 150 | var input = inputs[i] 151 | 152 | // reverse because test data is reversed 153 | var prevOutHash = [].reverse.call(new Buffer(input[0], 'hex')) 154 | var prevOutIndex = input[1] 155 | 156 | assert.deepEqual(txIn.hash, prevOutHash) 157 | 158 | // we read UInt32, not Int32 159 | assert.strictEqual(txIn.index & 0xffffffff, prevOutIndex) 160 | }) 161 | }) 162 | }) 163 | }) 164 | 165 | describe('script.fromASM', function () { 166 | tx_valid.forEach(function (f) { 167 | // Objects that are only a single string are ignored 168 | if (f.length === 1) return 169 | 170 | var inputs = f[0] 171 | 172 | inputs.forEach(function (input) { 173 | var prevOutScriptPubKey = input[2] 174 | .replace(/(^| )([0-9])( |$)/g, 'OP_$2 ') 175 | .replace(/0x[a-f0-9]+ 0x([a-f0-9]+)/, '$1') 176 | .replace(/DUP/g, 'OP_DUP') 177 | .replace(/NOT/g, 'OP_NOT') 178 | .replace(/HASH160/g, 'OP_HASH160') 179 | .replace(/EQUALVERIFY/g, 'OP_EQUALVERIFY') 180 | .replace(/EQUAL( |$)/g, 'OP_EQUAL ') 181 | .replace(/CHECKSIG/g, 'OP_CHECKSIG') 182 | .replace(/ CHECKMULTISIG/g, ' OP_CHECKMULTISIG') 183 | .replace(/CODESEPARATOR/g, 'OP_CODESEPARATOR') 184 | .replace(/CHECKSIGVERIFY/g, 'OP_CHECKSIGVERIFY') 185 | 186 | it('can parse ' + prevOutScriptPubKey, function () { 187 | // TODO: we can probably do better validation than this 188 | bitcoin.script.fromASM(prevOutScriptPubKey) 189 | }) 190 | }) 191 | }) 192 | }) 193 | 194 | // sighash 195 | describe('Transaction', function () { 196 | sighash.forEach(function (f) { 197 | // Objects that are only a single string are ignored 198 | if (f.length === 1) return 199 | 200 | var txHex = f[0] 201 | var scriptHex = f[1] 202 | var inIndex = f[2] 203 | var hashType = f[3] 204 | 205 | // reverse because test data is reversed 206 | var expectedHash = [].reverse.call(new Buffer(f[4], 'hex')) 207 | 208 | var hashTypes = [] 209 | if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_NONE) hashTypes.push('SIGHASH_NONE') 210 | else if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_SINGLE) hashTypes.push('SIGHASH_SINGLE') 211 | else hashTypes.push('SIGHASH_ALL') 212 | if (hashType & bitcoin.Transaction.SIGHASH_ANYONECANPAY) hashTypes.push('SIGHASH_ANYONECANPAY') 213 | 214 | var hashTypeName = hashTypes.join(' | ') 215 | 216 | it('should hash ' + txHex.slice(0, 40) + '... (' + hashTypeName + ')', function () { 217 | var transaction = bitcoin.Transaction.fromHex(txHex) 218 | assert.strictEqual(transaction.toHex(), txHex) 219 | 220 | var script = new Buffer(scriptHex, 'hex') 221 | var scriptChunks = bitcoin.script.decompile(script) 222 | assert.strictEqual(bitcoin.script.compile(scriptChunks).toString('hex'), scriptHex) 223 | 224 | var hash = transaction.hashForSignature(inIndex, script, hashType) 225 | assert.deepEqual(hash, expectedHash) 226 | }) 227 | }) 228 | }) 229 | 230 | describe('ECSignature.parseScriptSignature', function () { 231 | sig_canonical.forEach(function (hex) { 232 | var buffer = new Buffer(hex, 'hex') 233 | 234 | it('can parse ' + hex, function () { 235 | var parsed = bitcoin.ECSignature.parseScriptSignature(buffer) 236 | var actual = parsed.signature.toScriptSignature(parsed.hashType) 237 | assert.strictEqual(actual.toString('hex'), hex) 238 | }) 239 | }) 240 | 241 | sig_noncanonical.forEach(function (hex, i) { 242 | if (i === 0) return 243 | if (i % 2 !== 0) return 244 | 245 | var description = sig_noncanonical[i - 1].slice(0, -1) 246 | var buffer = new Buffer(hex, 'hex') 247 | 248 | it('throws on ' + description, function () { 249 | assert.throws(function () { 250 | bitcoin.ECSignature.parseScriptSignature(buffer) 251 | }, /Expected DER (integer|sequence)|(R|S) value (excessively padded|is negative)|(R|S|DER sequence) length is (zero|too short|too long|invalid)|Invalid hashType/) 252 | }) 253 | }) 254 | }) 255 | }) 256 | -------------------------------------------------------------------------------- /test/block.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, beforeEach */ 2 | 3 | var assert = require('assert') 4 | var Block = require('../src/block') 5 | 6 | var fixtures = require('./fixtures/block') 7 | 8 | describe('Block', function () { 9 | describe('calculateTarget', function () { 10 | fixtures.targets.forEach(function (f) { 11 | it('returns ' + f.expected + ' for 0x' + f.bits, function () { 12 | var bits = parseInt(f.bits, 16) 13 | 14 | assert.equal(Block.calculateTarget(bits).toString('hex'), f.expected) 15 | }) 16 | }) 17 | }) 18 | 19 | describe('fromBuffer/fromHex', function () { 20 | fixtures.valid.forEach(function (f) { 21 | it('imports the block: ' + f.description + ' correctly', function () { 22 | var block = Block.fromHex(f.hex) 23 | 24 | assert.strictEqual(block.version, f.version) 25 | assert.strictEqual(block.prevHash.toString('hex'), f.prevHash) 26 | assert.strictEqual(block.merkleRoot.toString('hex'), f.merkleRoot) 27 | assert.strictEqual(block.timestamp, f.timestamp) 28 | assert.strictEqual(block.bits, f.bits) 29 | assert.strictEqual(block.nonce, f.nonce) 30 | }) 31 | }) 32 | 33 | fixtures.invalid.forEach(function (f) { 34 | it('throws on ' + f.exception, function () { 35 | assert.throws(function () { 36 | Block.fromHex(f.hex) 37 | }, new RegExp(f.exception)) 38 | }) 39 | }) 40 | }) 41 | 42 | describe('toBuffer/toHex', function () { 43 | fixtures.valid.forEach(function (f) { 44 | var block 45 | 46 | beforeEach(function () { 47 | block = Block.fromHex(f.hex) 48 | }) 49 | 50 | it('exports the block: ' + f.description + ' correctly', function () { 51 | assert.strictEqual(block.toHex(), f.hex) 52 | }) 53 | }) 54 | }) 55 | 56 | describe('getHash', function () { 57 | fixtures.valid.forEach(function (f) { 58 | var block 59 | 60 | beforeEach(function () { 61 | block = Block.fromHex(f.hex) 62 | }) 63 | 64 | it('returns ' + f.hash + ' for the block: ' + f.description, function () { 65 | assert.strictEqual(block.getHash().toString('hex'), f.hash) 66 | }) 67 | }) 68 | }) 69 | 70 | describe('getId', function () { 71 | fixtures.valid.forEach(function (f) { 72 | var block 73 | 74 | beforeEach(function () { 75 | block = Block.fromHex(f.hex) 76 | }) 77 | 78 | it('returns ' + f.id + ' for the block: ' + f.description, function () { 79 | assert.strictEqual(block.getId(), f.id) 80 | }) 81 | }) 82 | }) 83 | 84 | describe('getUTCDate', function () { 85 | fixtures.valid.forEach(function (f) { 86 | var block 87 | 88 | beforeEach(function () { 89 | block = Block.fromHex(f.hex) 90 | }) 91 | 92 | it('returns UTC date of ' + f.id, function () { 93 | var utcDate = block.getUTCDate().getTime() 94 | 95 | assert.strictEqual(utcDate, f.timestamp * 1e3) 96 | }) 97 | }) 98 | }) 99 | 100 | describe('checkProofOfWork', function () { 101 | fixtures.valid.forEach(function (f) { 102 | var block 103 | 104 | beforeEach(function () { 105 | block = Block.fromHex(f.hex) 106 | }) 107 | 108 | it('returns ' + f.valid + ' for ' + f.id, function () { 109 | assert.strictEqual(block.checkProofOfWork(), f.valid) 110 | }) 111 | }) 112 | }) 113 | }) 114 | -------------------------------------------------------------------------------- /test/bufferutils.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var bufferutils = require('../src/bufferutils') 5 | 6 | var fixtures = require('./fixtures/bufferutils.json') 7 | 8 | describe('bufferutils', function () { 9 | describe('pushDataSize', function () { 10 | fixtures.valid.forEach(function (f) { 11 | it('determines the pushDataSize of ' + f.dec + ' correctly', function () { 12 | if (!f.hexPD) return 13 | 14 | var size = bufferutils.pushDataSize(f.dec) 15 | 16 | assert.strictEqual(size, f.hexPD.length / 2) 17 | }) 18 | }) 19 | }) 20 | 21 | describe('readPushDataInt', function () { 22 | fixtures.valid.forEach(function (f) { 23 | if (!f.hexPD) return 24 | 25 | it('decodes ' + f.hexPD + ' correctly', function () { 26 | var buffer = new Buffer(f.hexPD, 'hex') 27 | var d = bufferutils.readPushDataInt(buffer, 0) 28 | var fopcode = parseInt(f.hexPD.substr(0, 2), 16) 29 | 30 | assert.strictEqual(d.opcode, fopcode) 31 | assert.strictEqual(d.number, f.dec) 32 | assert.strictEqual(d.size, buffer.length) 33 | }) 34 | }) 35 | 36 | fixtures.invalid.readPushDataInt.forEach(function (f) { 37 | if (!f.hexPD) return 38 | 39 | it('decodes ' + f.hexPD + ' as null', function () { 40 | var buffer = new Buffer(f.hexPD, 'hex') 41 | 42 | var n = bufferutils.readPushDataInt(buffer, 0) 43 | assert.strictEqual(n, null) 44 | }) 45 | }) 46 | }) 47 | 48 | describe('readUInt64LE', function () { 49 | fixtures.valid.forEach(function (f) { 50 | it('decodes ' + f.hex64 + ' correctly', function () { 51 | var buffer = new Buffer(f.hex64, 'hex') 52 | var number = bufferutils.readUInt64LE(buffer, 0) 53 | 54 | assert.strictEqual(number, f.dec) 55 | }) 56 | }) 57 | 58 | fixtures.invalid.readUInt64LE.forEach(function (f) { 59 | it('throws on ' + f.description, function () { 60 | var buffer = new Buffer(f.hex64, 'hex') 61 | 62 | assert.throws(function () { 63 | bufferutils.readUInt64LE(buffer, 0) 64 | }, new RegExp(f.exception)) 65 | }) 66 | }) 67 | }) 68 | 69 | describe('readVarInt', function () { 70 | fixtures.valid.forEach(function (f) { 71 | it('decodes ' + f.hexVI + ' correctly', function () { 72 | var buffer = new Buffer(f.hexVI, 'hex') 73 | var d = bufferutils.readVarInt(buffer, 0) 74 | 75 | assert.strictEqual(d.number, f.dec) 76 | assert.strictEqual(d.size, buffer.length) 77 | }) 78 | }) 79 | 80 | fixtures.invalid.readUInt64LE.forEach(function (f) { 81 | it('throws on ' + f.description, function () { 82 | var buffer = new Buffer(f.hexVI, 'hex') 83 | 84 | assert.throws(function () { 85 | bufferutils.readVarInt(buffer, 0) 86 | }, new RegExp(f.exception)) 87 | }) 88 | }) 89 | }) 90 | 91 | describe('varIntBuffer', function () { 92 | fixtures.valid.forEach(function (f) { 93 | it('encodes ' + f.dec + ' correctly', function () { 94 | var buffer = bufferutils.varIntBuffer(f.dec) 95 | 96 | assert.strictEqual(buffer.toString('hex'), f.hexVI) 97 | }) 98 | }) 99 | }) 100 | 101 | describe('varIntSize', function () { 102 | fixtures.valid.forEach(function (f) { 103 | it('determines the varIntSize of ' + f.dec + ' correctly', function () { 104 | var size = bufferutils.varIntSize(f.dec) 105 | 106 | assert.strictEqual(size, f.hexVI.length / 2) 107 | }) 108 | }) 109 | }) 110 | 111 | describe('writePushDataInt', function () { 112 | fixtures.valid.forEach(function (f) { 113 | if (!f.hexPD) return 114 | 115 | it('encodes ' + f.dec + ' correctly', function () { 116 | var buffer = new Buffer(5) 117 | buffer.fill(0) 118 | 119 | var n = bufferutils.writePushDataInt(buffer, f.dec, 0) 120 | assert.strictEqual(buffer.slice(0, n).toString('hex'), f.hexPD) 121 | }) 122 | }) 123 | }) 124 | 125 | describe('writeUInt64LE', function () { 126 | fixtures.valid.forEach(function (f) { 127 | it('encodes ' + f.dec + ' correctly', function () { 128 | var buffer = new Buffer(8) 129 | buffer.fill(0) 130 | 131 | bufferutils.writeUInt64LE(buffer, f.dec, 0) 132 | assert.strictEqual(buffer.toString('hex'), f.hex64) 133 | }) 134 | }) 135 | 136 | fixtures.invalid.readUInt64LE.forEach(function (f) { 137 | it('throws on ' + f.description, function () { 138 | var buffer = new Buffer(8) 139 | buffer.fill(0) 140 | 141 | assert.throws(function () { 142 | bufferutils.writeUInt64LE(buffer, f.dec, 0) 143 | }, new RegExp(f.exception)) 144 | }) 145 | }) 146 | }) 147 | 148 | describe('writeVarInt', function () { 149 | fixtures.valid.forEach(function (f) { 150 | it('encodes ' + f.dec + ' correctly', function () { 151 | var buffer = new Buffer(9) 152 | buffer.fill(0) 153 | 154 | var n = bufferutils.writeVarInt(buffer, f.dec, 0) 155 | assert.strictEqual(buffer.slice(0, n).toString('hex'), f.hexVI) 156 | }) 157 | }) 158 | 159 | fixtures.invalid.readUInt64LE.forEach(function (f) { 160 | it('throws on ' + f.description, function () { 161 | var buffer = new Buffer(9) 162 | buffer.fill(0) 163 | 164 | assert.throws(function () { 165 | bufferutils.writeVarInt(buffer, f.dec, 0) 166 | }, new RegExp(f.exception)) 167 | }) 168 | }) 169 | }) 170 | }) 171 | -------------------------------------------------------------------------------- /test/crypto.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var bcrypto = require('../src/crypto') 5 | 6 | var fixtures = require('./fixtures/crypto') 7 | 8 | describe('crypto', function () { 9 | ['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(function (algorithm) { 10 | describe(algorithm, function () { 11 | fixtures.forEach(function (f) { 12 | var fn = bcrypto[algorithm] 13 | var expected = f[algorithm] 14 | 15 | it('returns ' + expected + ' for ' + f.hex, function () { 16 | var data = new Buffer(f.hex, 'hex') 17 | var actual = fn(data).toString('hex') 18 | 19 | assert.strictEqual(actual, expected) 20 | }) 21 | }) 22 | }) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/ecdsa.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var bcrypto = require('../src/crypto') 5 | var ecdsa = require('../src/ecdsa') 6 | var message = require('../src/message') 7 | var networks = require('../src/networks') 8 | var sinon = require('sinon') 9 | 10 | var BigInteger = require('bigi') 11 | var ECSignature = require('../src/ecsignature') 12 | 13 | var curve = ecdsa.__curve 14 | 15 | var fixtures = require('./fixtures/ecdsa.json') 16 | 17 | describe('ecdsa', function () { 18 | describe('deterministicGenerateK', function () { 19 | function checkSig () { 20 | return true 21 | } 22 | 23 | fixtures.valid.ecdsa.forEach(function (f) { 24 | it('for "' + f.message + '"', function () { 25 | var x = BigInteger.fromHex(f.d).toBuffer(32) 26 | var h1 = bcrypto.sha256(f.message) 27 | 28 | var k = ecdsa.deterministicGenerateK(h1, x, checkSig) 29 | assert.strictEqual(k.toHex(), f.k) 30 | }) 31 | }) 32 | 33 | it('loops until an appropriate k value is found', sinon.test(function () { 34 | this.mock(BigInteger).expects('fromBuffer') 35 | .exactly(3) 36 | .onCall(0).returns(new BigInteger('0')) // < 1 37 | .onCall(1).returns(curve.n) // > n-1 38 | .onCall(2).returns(new BigInteger('42')) // valid 39 | 40 | var x = new BigInteger('1').toBuffer(32) 41 | var h1 = new Buffer(32) 42 | var k = ecdsa.deterministicGenerateK(h1, x, checkSig) 43 | 44 | assert.strictEqual(k.toString(), '42') 45 | })) 46 | 47 | it('loops until a suitable signature is found', sinon.test(function () { 48 | this.mock(BigInteger).expects('fromBuffer') 49 | .exactly(4) 50 | .onCall(0).returns(new BigInteger('0')) // < 1 51 | .onCall(1).returns(curve.n) // > n-1 52 | .onCall(2).returns(new BigInteger('42')) // valid, but 'bad' signature 53 | .onCall(3).returns(new BigInteger('53')) // valid, good signature 54 | 55 | var checkSig = this.mock() 56 | checkSig.exactly(2) 57 | checkSig.onCall(0).returns(false) // bad signature 58 | checkSig.onCall(1).returns(true) // good signature 59 | 60 | var x = new BigInteger('1').toBuffer(32) 61 | var h1 = new Buffer(32) 62 | var k = ecdsa.deterministicGenerateK(h1, x, checkSig) 63 | 64 | assert.strictEqual(k.toString(), '53') 65 | })) 66 | 67 | fixtures.valid.rfc6979.forEach(function (f) { 68 | it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () { 69 | var x = BigInteger.fromHex(f.d).toBuffer(32) 70 | var h1 = bcrypto.sha256(f.message) 71 | 72 | var results = [] 73 | ecdsa.deterministicGenerateK(h1, x, function (k) { 74 | results.push(k) 75 | 76 | return results.length === 16 77 | }) 78 | 79 | assert.strictEqual(results[0].toHex(), f.k0) 80 | assert.strictEqual(results[1].toHex(), f.k1) 81 | assert.strictEqual(results[15].toHex(), f.k15) 82 | }) 83 | }) 84 | }) 85 | 86 | describe('recoverPubKey', function () { 87 | fixtures.valid.ecdsa.forEach(function (f) { 88 | it('recovers the pubKey for ' + f.d, function () { 89 | var d = BigInteger.fromHex(f.d) 90 | var Q = curve.G.multiply(d) 91 | var signature = ECSignature.fromDER(new Buffer(f.signature, 'hex')) 92 | var h1 = bcrypto.sha256(f.message) 93 | var e = BigInteger.fromBuffer(h1) 94 | var Qprime = ecdsa.recoverPubKey(e, signature, f.i) 95 | 96 | assert(Qprime.equals(Q)) 97 | }) 98 | }) 99 | 100 | describe('with i ∈ {0,1,2,3}', function () { 101 | var hash = message.magicHash('1111', networks.bitcoin) 102 | var e = BigInteger.fromBuffer(hash) 103 | 104 | var signatureBuffer = new Buffer('INcvXVVEFyIfHLbDX+xoxlKFn3Wzj9g0UbhObXdMq+YMKC252o5RHFr0/cKdQe1WsBLUBi4morhgZ77obDJVuV0=', 'base64') 105 | var signature = ECSignature.parseCompact(signatureBuffer).signature 106 | var points = [ 107 | '03e3a8c44a8bf712f1fbacee274fb19c0239b1a9e877eff0075ea335f2be8ff380', 108 | '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 109 | '03d49e765f0bc27525c51a1b98fb1c99dacd59abe85a203af90f758260550b56c5', 110 | '027eea09d46ac7fb6aa2e96f9c576677214ffdc238eb167734a9b39d1eb4c3d30d' 111 | ] 112 | 113 | points.forEach(function (expectedHex, i) { 114 | it('recovers an expected point for i of ' + i, function () { 115 | var Qprime = ecdsa.recoverPubKey(e, signature, i) 116 | var QprimeHex = Qprime.getEncoded().toString('hex') 117 | 118 | assert.strictEqual(QprimeHex, expectedHex) 119 | }) 120 | }) 121 | }) 122 | 123 | fixtures.invalid.recoverPubKey.forEach(function (f) { 124 | it('throws on ' + f.description + ' (' + f.exception + ')', function () { 125 | var e = BigInteger.fromHex(f.e) 126 | var signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16)) 127 | 128 | assert.throws(function () { 129 | ecdsa.recoverPubKey(e, signature, f.i) 130 | }, new RegExp(f.exception)) 131 | }) 132 | }) 133 | }) 134 | 135 | describe('sign', function () { 136 | fixtures.valid.ecdsa.forEach(function (f) { 137 | it('produces a deterministic signature for "' + f.message + '"', function () { 138 | var d = BigInteger.fromHex(f.d) 139 | var hash = bcrypto.sha256(f.message) 140 | var signature = ecdsa.sign(hash, d).toDER() 141 | 142 | assert.strictEqual(signature.toString('hex'), f.signature) 143 | }) 144 | }) 145 | 146 | it('should sign with low S value', function () { 147 | var hash = bcrypto.sha256('Vires in numeris') 148 | var sig = ecdsa.sign(hash, BigInteger.ONE) 149 | 150 | // See BIP62 for more information 151 | var N_OVER_TWO = curve.n.shiftRight(1) 152 | assert(sig.s.compareTo(N_OVER_TWO) <= 0) 153 | }) 154 | }) 155 | 156 | describe('verify', function () { 157 | fixtures.valid.ecdsa.forEach(function (f) { 158 | it('verifies a valid signature for "' + f.message + '"', function () { 159 | var d = BigInteger.fromHex(f.d) 160 | var H = bcrypto.sha256(f.message) 161 | var signature = ECSignature.fromDER(new Buffer(f.signature, 'hex')) 162 | var Q = curve.G.multiply(d) 163 | 164 | assert(ecdsa.verify(H, signature, Q)) 165 | }) 166 | }) 167 | 168 | fixtures.invalid.verify.forEach(function (f) { 169 | it('fails to verify with ' + f.description, function () { 170 | var H = bcrypto.sha256(f.message) 171 | var d = BigInteger.fromHex(f.d) 172 | 173 | var signature 174 | if (f.signature) { 175 | signature = ECSignature.fromDER(new Buffer(f.signature, 'hex')) 176 | } else if (f.signatureRaw) { 177 | signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16)) 178 | } 179 | 180 | var Q = curve.G.multiply(d) 181 | 182 | assert.strictEqual(ecdsa.verify(H, signature, Q), false) 183 | }) 184 | }) 185 | }) 186 | }) 187 | -------------------------------------------------------------------------------- /test/ecpair.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, beforeEach */ 2 | /* eslint-disable no-new */ 3 | 4 | var assert = require('assert') 5 | var ecdsa = require('../src/ecdsa') 6 | var ecurve = require('ecurve') 7 | var proxyquire = require('proxyquire') 8 | var sinon = require('sinon') 9 | 10 | var BigInteger = require('bigi') 11 | var ECPair = require('../src/ecpair') 12 | 13 | var fixtures = require('./fixtures/ecpair.json') 14 | var curve = ecdsa.__curve 15 | 16 | var NETWORKS = require('../src/networks') 17 | var NETWORKS_LIST = [] // Object.values(NETWORKS) 18 | for (var networkName in NETWORKS) { 19 | NETWORKS_LIST.push(NETWORKS[networkName]) 20 | } 21 | 22 | describe('ECPair', function () { 23 | describe('constructor', function () { 24 | it('defaults to compressed', function () { 25 | var keyPair = new ECPair(BigInteger.ONE) 26 | 27 | assert.strictEqual(keyPair.compressed, true) 28 | }) 29 | 30 | it('supports the uncompressed option', function () { 31 | var keyPair = new ECPair(BigInteger.ONE, null, { 32 | compressed: false 33 | }) 34 | 35 | assert.strictEqual(keyPair.compressed, false) 36 | }) 37 | 38 | it('supports the network option', function () { 39 | var keyPair = new ECPair(BigInteger.ONE, null, { 40 | compressed: false, 41 | network: NETWORKS.testnet 42 | }) 43 | 44 | assert.strictEqual(keyPair.network, NETWORKS.testnet) 45 | }) 46 | 47 | fixtures.valid.forEach(function (f) { 48 | it('calculates the public point for ' + f.WIF, function () { 49 | var d = new BigInteger(f.d) 50 | var keyPair = new ECPair(d, null, { 51 | compressed: f.compressed 52 | }) 53 | 54 | assert.strictEqual(keyPair.getPublicKeyBuffer().toString('hex'), f.Q) 55 | }) 56 | }) 57 | 58 | fixtures.invalid.constructor.forEach(function (f) { 59 | it('throws ' + f.exception, function () { 60 | var d = f.d && new BigInteger(f.d) 61 | var Q = f.Q && ecurve.Point.decodeFrom(curve, new Buffer(f.Q, 'hex')) 62 | 63 | assert.throws(function () { 64 | new ECPair(d, Q, f.options) 65 | }, new RegExp(f.exception)) 66 | }) 67 | }) 68 | }) 69 | 70 | describe('getPublicKeyBuffer', function () { 71 | var keyPair 72 | 73 | beforeEach(function () { 74 | keyPair = new ECPair(BigInteger.ONE) 75 | }) 76 | 77 | it('wraps Q.getEncoded', sinon.test(function () { 78 | this.mock(keyPair.Q).expects('getEncoded') 79 | .once().withArgs(keyPair.compressed) 80 | 81 | keyPair.getPublicKeyBuffer() 82 | })) 83 | }) 84 | 85 | describe('fromWIF', function () { 86 | fixtures.valid.forEach(function (f) { 87 | it('imports ' + f.WIF + ' (' + f.network + ')', function () { 88 | var network = NETWORKS[f.network] 89 | var keyPair = ECPair.fromWIF(f.WIF, network) 90 | 91 | assert.strictEqual(keyPair.d.toString(), f.d) 92 | assert.strictEqual(keyPair.compressed, f.compressed) 93 | assert.strictEqual(keyPair.network, network) 94 | }) 95 | }) 96 | 97 | fixtures.valid.forEach(function (f) { 98 | it('imports ' + f.WIF + ' (via list of networks)', function () { 99 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST) 100 | 101 | assert.strictEqual(keyPair.d.toString(), f.d) 102 | assert.strictEqual(keyPair.compressed, f.compressed) 103 | assert.strictEqual(keyPair.network, NETWORKS[f.network]) 104 | }) 105 | }) 106 | 107 | fixtures.invalid.fromWIF.forEach(function (f) { 108 | it('throws on ' + f.WIF, function () { 109 | assert.throws(function () { 110 | var networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST 111 | 112 | ECPair.fromWIF(f.WIF, networks) 113 | }, new RegExp(f.exception)) 114 | }) 115 | }) 116 | }) 117 | 118 | describe('toWIF', function () { 119 | fixtures.valid.forEach(function (f) { 120 | it('exports ' + f.WIF, function () { 121 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST) 122 | var result = keyPair.toWIF() 123 | 124 | assert.strictEqual(result, f.WIF) 125 | }) 126 | }) 127 | }) 128 | 129 | describe('makeRandom', function () { 130 | var d = new Buffer('0404040404040404040404040404040404040404040404040404040404040404', 'hex') 131 | var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv' 132 | 133 | describe('uses randombytes RNG', function () { 134 | it('generates a ECPair', function () { 135 | var stub = { randombytes: function () { return d } } 136 | var ProxiedECPair = proxyquire('../src/ecpair', stub) 137 | 138 | var keyPair = ProxiedECPair.makeRandom() 139 | assert.strictEqual(keyPair.toWIF(), exWIF) 140 | }) 141 | }) 142 | 143 | it('allows a custom RNG to be used', function () { 144 | var keyPair = ECPair.makeRandom({ 145 | rng: function (size) { return d.slice(0, size) } 146 | }) 147 | 148 | assert.strictEqual(keyPair.toWIF(), exWIF) 149 | }) 150 | 151 | it('loops until d is within interval [1, n - 1]', sinon.test(function () { 152 | var rng = this.mock() 153 | rng.exactly(3) 154 | rng.onCall(0).returns(new BigInteger('0').toBuffer(32)) // < 1 155 | rng.onCall(1).returns(curve.n.toBuffer(32)) // > n-1 156 | rng.onCall(2).returns(new BigInteger('42').toBuffer(32)) // valid 157 | 158 | ECPair.makeRandom({ rng: rng }) 159 | })) 160 | }) 161 | 162 | describe('getAddress', function () { 163 | fixtures.valid.forEach(function (f) { 164 | it('returns ' + f.address + ' for ' + f.WIF, function () { 165 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST) 166 | 167 | assert.strictEqual(keyPair.getAddress(), f.address) 168 | }) 169 | }) 170 | }) 171 | 172 | describe('getNetwork', function () { 173 | fixtures.valid.forEach(function (f) { 174 | it('returns ' + f.network + ' for ' + f.WIF, function () { 175 | var network = NETWORKS[f.network] 176 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST) 177 | 178 | assert.strictEqual(keyPair.getNetwork(), network) 179 | }) 180 | }) 181 | }) 182 | 183 | describe('ecdsa wrappers', function () { 184 | var keyPair, hash 185 | 186 | beforeEach(function () { 187 | keyPair = ECPair.makeRandom() 188 | hash = new Buffer(32) 189 | }) 190 | 191 | describe('signing', function () { 192 | it('wraps ecdsa.sign', sinon.test(function () { 193 | this.mock(ecdsa).expects('sign') 194 | .once().withArgs(hash, keyPair.d) 195 | 196 | keyPair.sign(hash) 197 | })) 198 | 199 | it('throws if no private key is found', function () { 200 | keyPair.d = null 201 | 202 | assert.throws(function () { 203 | keyPair.sign(hash) 204 | }, /Missing private key/) 205 | }) 206 | }) 207 | 208 | describe('verify', function () { 209 | var signature 210 | 211 | beforeEach(function () { 212 | signature = keyPair.sign(hash) 213 | }) 214 | 215 | it('wraps ecdsa.verify', sinon.test(function () { 216 | this.mock(ecdsa).expects('verify') 217 | .once().withArgs(hash, signature, keyPair.Q) 218 | 219 | keyPair.verify(hash, signature) 220 | })) 221 | }) 222 | }) 223 | }) 224 | -------------------------------------------------------------------------------- /test/ecsignature.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | 5 | var BigInteger = require('bigi') 6 | var ECSignature = require('../src/ecsignature') 7 | 8 | var fixtures = require('./fixtures/ecsignature.json') 9 | 10 | describe('ECSignature', function () { 11 | describe('toCompact', function () { 12 | fixtures.valid.forEach(function (f) { 13 | it('exports ' + f.compact.hex + ' correctly', function () { 14 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) 15 | 16 | var buffer = signature.toCompact(f.compact.i, f.compact.compressed) 17 | assert.strictEqual(buffer.toString('hex'), f.compact.hex) 18 | }) 19 | }) 20 | }) 21 | 22 | describe('parseCompact', function () { 23 | fixtures.valid.forEach(function (f) { 24 | it('imports ' + f.compact.hex + ' correctly', function () { 25 | var buffer = new Buffer(f.compact.hex, 'hex') 26 | var parsed = ECSignature.parseCompact(buffer) 27 | 28 | assert.strictEqual(parsed.compressed, f.compact.compressed) 29 | assert.strictEqual(parsed.i, f.compact.i) 30 | assert.strictEqual(parsed.signature.r.toString(), f.signature.r) 31 | assert.strictEqual(parsed.signature.s.toString(), f.signature.s) 32 | }) 33 | }) 34 | 35 | fixtures.invalid.compact.forEach(function (f) { 36 | it('throws on ' + f.hex, function () { 37 | var buffer = new Buffer(f.hex, 'hex') 38 | 39 | assert.throws(function () { 40 | ECSignature.parseCompact(buffer) 41 | }, new RegExp(f.exception)) 42 | }) 43 | }) 44 | }) 45 | 46 | describe('toDER', function () { 47 | fixtures.valid.forEach(function (f) { 48 | it('exports ' + f.DER + ' correctly', function () { 49 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) 50 | 51 | var DER = signature.toDER() 52 | assert.strictEqual(DER.toString('hex'), f.DER) 53 | }) 54 | }) 55 | }) 56 | 57 | describe('fromDER', function () { 58 | fixtures.valid.forEach(function (f) { 59 | it('imports ' + f.DER + ' correctly', function () { 60 | var buffer = new Buffer(f.DER, 'hex') 61 | var signature = ECSignature.fromDER(buffer) 62 | 63 | assert.strictEqual(signature.r.toString(), f.signature.r) 64 | assert.strictEqual(signature.s.toString(), f.signature.s) 65 | }) 66 | }) 67 | 68 | fixtures.invalid.DER.forEach(function (f) { 69 | it('throws "' + f.exception + '" for ' + f.hex, function () { 70 | var buffer = new Buffer(f.hex, 'hex') 71 | 72 | assert.throws(function () { 73 | ECSignature.fromDER(buffer) 74 | }, new RegExp(f.exception)) 75 | }) 76 | }) 77 | }) 78 | 79 | describe('toScriptSignature', function () { 80 | fixtures.valid.forEach(function (f) { 81 | it('exports ' + f.scriptSignature.hex + ' correctly', function () { 82 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) 83 | 84 | var scriptSignature = signature.toScriptSignature(f.scriptSignature.hashType) 85 | assert.strictEqual(scriptSignature.toString('hex'), f.scriptSignature.hex) 86 | }) 87 | }) 88 | 89 | fixtures.invalid.scriptSignature.forEach(function (f) { 90 | it('throws ' + f.exception, function () { 91 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s)) 92 | 93 | assert.throws(function () { 94 | signature.toScriptSignature(f.hashType) 95 | }, new RegExp(f.exception)) 96 | }) 97 | }) 98 | }) 99 | 100 | describe('parseScriptSignature', function () { 101 | fixtures.valid.forEach(function (f) { 102 | it('imports ' + f.scriptSignature.hex + ' correctly', function () { 103 | var buffer = new Buffer(f.scriptSignature.hex, 'hex') 104 | var parsed = ECSignature.parseScriptSignature(buffer) 105 | 106 | assert.strictEqual(parsed.signature.r.toString(), f.signature.r) 107 | assert.strictEqual(parsed.signature.s.toString(), f.signature.s) 108 | assert.strictEqual(parsed.hashType, f.scriptSignature.hashType) 109 | }) 110 | }) 111 | 112 | fixtures.invalid.scriptSignature.forEach(function (f) { 113 | it('throws on ' + f.hex, function () { 114 | var buffer = new Buffer(f.hex, 'hex') 115 | 116 | assert.throws(function () { 117 | ECSignature.parseScriptSignature(buffer) 118 | }, new RegExp(f.exception)) 119 | }) 120 | }) 121 | }) 122 | }) 123 | -------------------------------------------------------------------------------- /test/fixtures/address.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": [ 3 | { 4 | "network": "bitcoin", 5 | "version": 0, 6 | "hash": "751e76e8199196d454941c45d1b3a323f1433bd6", 7 | "base58check": "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH", 8 | "script": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG" 9 | }, 10 | { 11 | "network": "bitcoin", 12 | "version": 5, 13 | "hash": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6", 14 | "base58check": "3LRW7jeCvQCRdPF8S3yUCfRAx4eqXFmdcr", 15 | "script": "OP_HASH160 cd7b44d0b03f2d026d1e586d7ae18903b0d385f6 OP_EQUAL" 16 | }, 17 | { 18 | "network": "testnet", 19 | "version": 111, 20 | "hash": "751e76e8199196d454941c45d1b3a323f1433bd6", 21 | "base58check": "mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r", 22 | "script": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG" 23 | }, 24 | { 25 | "network": "testnet", 26 | "version": 196, 27 | "hash": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6", 28 | "base58check": "2NByiBUaEXrhmqAsg7BbLpcQSAQs1EDwt5w", 29 | "script": "OP_HASH160 cd7b44d0b03f2d026d1e586d7ae18903b0d385f6 OP_EQUAL" 30 | } 31 | ], 32 | "invalid": { 33 | "fromBase58Check": [ 34 | { 35 | "address": "7SeEnXWPaCCALbVrTnszCVGfRU8cGfx", 36 | "exception": "is too short" 37 | }, 38 | { 39 | "address": "j9ywUkWg2fTQrouxxh5rSZhRvrjMkEUfuiKe", 40 | "exception": "is too long" 41 | } 42 | ], 43 | "fromOutputScript": [ 44 | { 45 | "exception": "has no matching Address", 46 | "script": "031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95 OP_CHECKSIG" 47 | }, 48 | { 49 | "exception": "has no matching Address", 50 | "script": "OP_TRUE 032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca33016 02308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a OP_2 OP_CHECKMULTISIG" 51 | }, 52 | { 53 | "exception": "has no matching Address", 54 | "script": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474" 55 | } 56 | ], 57 | "toOutputScript": [ 58 | { 59 | "exception": "has no matching Script", 60 | "address": "24kPZCmVgzfkpGdXExy56234MRHrsqQxNWE" 61 | } 62 | ] 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/fixtures/bufferutils.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": [ 3 | { 4 | "dec": 0, 5 | "hex64": "0000000000000000", 6 | "hexVI": "00", 7 | "hexPD": "00" 8 | }, 9 | { 10 | "dec": 1, 11 | "hex64": "0100000000000000", 12 | "hexVI": "01", 13 | "hexPD": "01" 14 | }, 15 | { 16 | "dec": 252, 17 | "hex64": "fc00000000000000", 18 | "hexVI": "fc", 19 | "hexPD": "4cfc" 20 | }, 21 | { 22 | "dec": 253, 23 | "hex64": "fd00000000000000", 24 | "hexVI": "fdfd00", 25 | "hexPD": "4cfd" 26 | }, 27 | { 28 | "dec": 254, 29 | "hex64": "fe00000000000000", 30 | "hexVI": "fdfe00", 31 | "hexPD": "4cfe" 32 | }, 33 | { 34 | "dec": 255, 35 | "hex64": "ff00000000000000", 36 | "hexVI": "fdff00", 37 | "hexPD": "4dff00" 38 | }, 39 | { 40 | "dec": 65534, 41 | "hex64": "feff000000000000", 42 | "hexVI": "fdfeff", 43 | "hexPD": "4dfeff" 44 | }, 45 | { 46 | "dec": 65535, 47 | "hex64": "ffff000000000000", 48 | "hexVI": "fdffff", 49 | "hexPD": "4effff0000" 50 | }, 51 | { 52 | "dec": 65536, 53 | "hex64": "0000010000000000", 54 | "hexVI": "fe00000100", 55 | "hexPD": "4e00000100" 56 | }, 57 | { 58 | "dec": 65537, 59 | "hex64": "0100010000000000", 60 | "hexVI": "fe01000100", 61 | "hexPD": "4e01000100" 62 | }, 63 | { 64 | "dec": 4294967295, 65 | "hex64": "ffffffff00000000", 66 | "hexVI": "feffffffff", 67 | "hexPD": "4effffffff" 68 | }, 69 | { 70 | "dec": 4294967296, 71 | "hex64": "0000000001000000", 72 | "hexVI": "ff0000000001000000" 73 | }, 74 | { 75 | "dec": 4294967297, 76 | "hex64": "0100000001000000", 77 | "hexVI": "ff0100000001000000" 78 | }, 79 | { 80 | "dec": 9007199254740991, 81 | "hex64": "ffffffffffff1f00", 82 | "hexVI": "ffffffffffffff1f00" 83 | } 84 | ], 85 | "invalid": { 86 | "readUInt64LE": [ 87 | { 88 | "description": "n === 2^53", 89 | "exception": "value is larger than maximum value for type", 90 | "hex64": "0000000000002000", 91 | "hexVI": "ff0000000000000020", 92 | "dec": 9007199254740992 93 | }, 94 | { 95 | "description": "n > 2^53", 96 | "exception": "value is larger than maximum value for type", 97 | "hex64": "0100000000002000", 98 | "hexVI": "ff0100000000000020", 99 | "dec": 9007199254740993 100 | } 101 | ], 102 | "readPushDataInt": [ 103 | { 104 | "description": "OP_PUSHDATA1, no size", 105 | "hexPD": "4c" 106 | }, 107 | { 108 | "description": "OP_PUSHDATA2, no size", 109 | "hexPD": "4d" 110 | }, 111 | { 112 | "description": "OP_PUSHDATA4, no size", 113 | "hexPD": "4e" 114 | } 115 | ] 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /test/fixtures/core/README.md: -------------------------------------------------------------------------------- 1 | Description 2 | ------------ 3 | 4 | This directory contains data-driven tests for various aspects of Bitcoin. 5 | 6 | 7 | Bitcoinjs-lib notes 8 | ------------------- 9 | 10 | This directory does not contain all the Bitcoin core tests. 11 | Missing core test data includes: 12 | 13 | * `alertTests.raw` 14 | Bitcoin-js does not interact with the Bitcoin network directly. 15 | 16 | * `tx_invalid.json` 17 | Bitcoin-js can not evaluate Scripts, making testing this irrelevant. 18 | It can decode valid Transactions, therefore `tx_valid.json` remains. 19 | 20 | * `script*.json` 21 | Bitcoin-js can not evaluate Scripts, making testing this irrelevant. 22 | 23 | 24 | License 25 | -------- 26 | 27 | The data files in this directory are 28 | 29 | Copyright (c) 2012-2014 The Bitcoin Core developers 30 | Distributed under the MIT/X11 software license, see the accompanying 31 | file COPYING or http://www.opensource.org/licenses/mit-license.php. 32 | -------------------------------------------------------------------------------- /test/fixtures/core/base58_encode_decode.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["", ""], 3 | ["61", "2g"], 4 | ["626262", "a3gV"], 5 | ["636363", "aPEr"], 6 | ["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"], 7 | ["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"], 8 | ["516b6fcd0f", "ABnLTmg"], 9 | ["bf4f89001e670274dd", "3SEo3LWLoPntC"], 10 | ["572e4794", "3EFU7m"], 11 | ["ecac89cad93923c02321", "EJDM8drfXA6uyA"], 12 | ["10c8511e", "Rt5zm"], 13 | ["00000000000000000000", "1111111111"] 14 | ] 15 | -------------------------------------------------------------------------------- /test/fixtures/core/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/fixtures/core/sig_canonical.json: -------------------------------------------------------------------------------- 1 | [ 2 | "300602010002010001", 3 | "3008020200ff020200ff01", 4 | "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001", 5 | "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01", 6 | "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01" 7 | ] 8 | -------------------------------------------------------------------------------- /test/fixtures/core/sig_noncanonical.json: -------------------------------------------------------------------------------- 1 | [ 2 | "non-hex strings are ignored", 3 | 4 | "too short:", "30050201FF020001", 5 | "too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 6 | "hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11", 7 | "type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 8 | "total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 9 | "S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101", 10 | "R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001", 11 | 12 | "R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 13 | "R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 14 | "R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 15 | "R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 16 | 17 | 18 | "S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 19 | "S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001", 20 | "S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 21 | "S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01" 22 | ] 23 | -------------------------------------------------------------------------------- /test/fixtures/crypto.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "hex": "0000000000000001", 4 | "hash160": "cdb00698f02afd929ffabea308340fa99ac2afa8", 5 | "hash256": "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284", 6 | "ripemd160": "8d1a05d1bc08870968eb8a81ad4393fd3aac6633", 7 | "sha1": "cb473678976f425d6ec1339838f11011007ad27d", 8 | "sha256": "cd2662154e6d76b2b2b92e70c0cac3ccf534f9b74eb5b89819ec509083d00a50" 9 | }, 10 | { 11 | "hex": "0101010101010101", 12 | "hash160": "abaf1119f83e384210fe8e222eac76e2f0da39dc", 13 | "hash256": "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23", 14 | "ripemd160": "5825701b4b9767fd35063b286dca3582853e0630", 15 | "sha1": "c0357a32ed1f6a03be92dd094476f7f1a2e214ec", 16 | "sha256": "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061" 17 | }, 18 | { 19 | "hex": "ffffffffffffffff", 20 | "hash160": "f86221f5a1fca059a865c0b7d374dfa9d5f3aeb4", 21 | "hash256": "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad", 22 | "ripemd160": "cb760221600ed34337ca3ab70016b5f58c838120", 23 | "sha1": "be673e8a56eaa9d8c1d35064866701c11ef8e089", 24 | "sha256": "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca" 25 | }, 26 | { 27 | "hex": "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e65632061742066617563696275732073617069656e2c2076656c20666163696c6973697320617263752e20536564207574206d61737361206e6962682e205574206d6f6c6c69732070756c76696e6172206d617373612e20557420756c6c616d636f7270657220646f6c6f7220656e696d2c20696e206d6f6c657374696520656e696d20636f6e64696d656e74756d2061632e20416c697175616d206572617420766f6c75747061742e204e756c6c6120736f64616c657320617420647569206e656320", 28 | "hash160": "9763e6b367c363bd6b88a7b361c98e6beee243a5", 29 | "hash256": "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799", 30 | "ripemd160": "cad8593dcdef12ee334c97bab9787f07b3f3a1a5", 31 | "sha1": "10d96fb43aca84e342206887bbeed3065d4e4344", 32 | "sha256": "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da" 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /test/fixtures/ecdsa.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": { 3 | "ecdsa": [ 4 | { 5 | "d": "01", 6 | "k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5", 7 | "message": "Everything should be made as simple as possible, but not simpler.", 8 | "i": 0, 9 | "signature": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262" 10 | }, 11 | { 12 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 13 | "k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4", 14 | "message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.", 15 | "i": 0, 16 | "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5" 17 | }, 18 | { 19 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 20 | "k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5", 21 | "message": "Not only is the Universe stranger than we think, it is stranger than we can think.", 22 | "i": 0, 23 | "signature": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283" 24 | }, 25 | { 26 | "d": "0000000000000000000000000000000000000000000000000000000000000001", 27 | "k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f", 28 | "message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.", 29 | "i": 1, 30 | "signature": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3" 31 | }, 32 | { 33 | "d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64", 34 | "k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97", 35 | "message": "Computer science is no more about computers than astronomy is about telescopes.", 36 | "i": 0, 37 | "signature": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6" 38 | }, 39 | { 40 | "d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637", 41 | "k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb", 42 | "message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough", 43 | "i": 1, 44 | "signature": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37" 45 | }, 46 | { 47 | "d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3", 48 | "k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b", 49 | "message": "The question of whether computers can think is like the question of whether submarines can swim.", 50 | "i": 1, 51 | "signature": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef" 52 | } 53 | ], 54 | "rfc6979": [ 55 | { 56 | "message": "test data", 57 | "d": "fee0a1f7afebf9d2a5a80c0c98a31c709681cce195cbcd06342b517970c0be1e", 58 | "k0": "fcce1de7a9bcd6b2d3defade6afa1913fb9229e3b7ddf4749b55c4848b2a196e", 59 | "k1": "727fbcb59eb48b1d7d46f95a04991fc512eb9dbf9105628e3aec87428df28fd8", 60 | "k15": "398f0e2c9f79728f7b3d84d447ac3a86d8b2083c8f234a0ffa9c4043d68bd258" 61 | }, 62 | { 63 | "message": "Everything should be made as simple as possible, but not simpler.", 64 | "d": "0000000000000000000000000000000000000000000000000000000000000001", 65 | "k0": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5", 66 | "k1": "df55b6d1b5c48184622b0ead41a0e02bfa5ac3ebdb4c34701454e80aabf36f56", 67 | "k15": "def007a9a3c2f7c769c75da9d47f2af84075af95cadd1407393dc1e26086ef87" 68 | }, 69 | { 70 | "message": "Satoshi Nakamoto", 71 | "d": "0000000000000000000000000000000000000000000000000000000000000002", 72 | "k0": "d3edc1b8224e953f6ee05c8bbf7ae228f461030e47caf97cde91430b4607405e", 73 | "k1": "f86d8e43c09a6a83953f0ab6d0af59fb7446b4660119902e9967067596b58374", 74 | "k15": "241d1f57d6cfd2f73b1ada7907b199951f95ef5ad362b13aed84009656e0254a" 75 | }, 76 | { 77 | "message": "Diffie Hellman", 78 | "d": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 79 | "k0": "c378a41cb17dce12340788dd3503635f54f894c306d52f6e9bc4b8f18d27afcc", 80 | "k1": "90756c96fef41152ac9abe08819c4e95f16da2af472880192c69a2b7bac29114", 81 | "k15": "7b3f53300ab0ccd0f698f4d67db87c44cf3e9e513d9df61137256652b2e94e7c" 82 | }, 83 | { 84 | "message": "Japan", 85 | "d": "8080808080808080808080808080808080808080808080808080808080808080", 86 | "k0": "f471e61b51d2d8db78f3dae19d973616f57cdc54caaa81c269394b8c34edcf59", 87 | "k1": "6819d85b9730acc876fdf59e162bf309e9f63dd35550edf20869d23c2f3e6d17", 88 | "k15": "d8e8bae3ee330a198d1f5e00ad7c5f9ed7c24c357c0a004322abca5d9cd17847" 89 | }, 90 | { 91 | "message": "Bitcoin", 92 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 93 | "k0": "36c848ffb2cbecc5422c33a994955b807665317c1ce2a0f59c689321aaa631cc", 94 | "k1": "4ed8de1ec952a4f5b3bd79d1ff96446bcd45cabb00fc6ca127183e14671bcb85", 95 | "k15": "56b6f47babc1662c011d3b1f93aa51a6e9b5f6512e9f2e16821a238d450a31f8" 96 | }, 97 | { 98 | "message": "i2FLPP8WEus5WPjpoHwheXOMSobUJVaZM1JPMQZq", 99 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 100 | "k0": "6e9b434fcc6bbb081a0463c094356b47d62d7efae7da9c518ed7bac23f4e2ed6", 101 | "k1": "ae5323ae338d6117ce8520a43b92eacd2ea1312ae514d53d8e34010154c593bb", 102 | "k15": "3eaa1b61d1b8ab2f1ca71219c399f2b8b3defa624719f1e96fe3957628c2c4ea" 103 | }, 104 | { 105 | "message": "lEE55EJNP7aLrMtjkeJKKux4Yg0E8E1SAJnWTCEh", 106 | "d": "3881e5286abc580bb6139fe8e83d7c8271c6fe5e5c2d640c1f0ed0e1ee37edc9", 107 | "k0": "5b606665a16da29cc1c5411d744ab554640479dd8abd3c04ff23bd6b302e7034", 108 | "k1": "f8b25263152c042807c992eacd2ac2cc5790d1e9957c394f77ea368e3d9923bd", 109 | "k15": "ea624578f7e7964ac1d84adb5b5087dd14f0ee78b49072aa19051cc15dab6f33" 110 | }, 111 | { 112 | "message": "2SaVPvhxkAPrayIVKcsoQO5DKA8Uv5X/esZFlf+y", 113 | "d": "7259dff07922de7f9c4c5720d68c9745e230b32508c497dd24cb95ef18856631", 114 | "k0": "3ab6c19ab5d3aea6aa0c6da37516b1d6e28e3985019b3adb388714e8f536686b", 115 | "k1": "19af21b05004b0ce9cdca82458a371a9d2cf0dc35a813108c557b551c08eb52e", 116 | "k15": "117a32665fca1b7137a91c4739ac5719fec0cf2e146f40f8e7c21b45a07ebc6a" 117 | }, 118 | { 119 | "message": "00A0OwO2THi7j5Z/jp0FmN6nn7N/DQd6eBnCS+/b", 120 | "d": "0d6ea45d62b334777d6995052965c795a4f8506044b4fd7dc59c15656a28f7aa", 121 | "k0": "79487de0c8799158294d94c0eb92ee4b567e4dc7ca18addc86e49d31ce1d2db6", 122 | "k1": "9561d2401164a48a8f600882753b3105ebdd35e2358f4f808c4f549c91490009", 123 | "k15": "b0d273634129ff4dbdf0df317d4062a1dbc58818f88878ffdb4ec511c77976c0" 124 | } 125 | ] 126 | }, 127 | "invalid": { 128 | "recoverPubKey": [ 129 | { 130 | "description": "Invalid r value (< 0)", 131 | "exception": "Invalid r value", 132 | "e": "01", 133 | "signatureRaw": { 134 | "r": "-01", 135 | "s": "02" 136 | }, 137 | "i": 0 138 | }, 139 | { 140 | "description": "Invalid r value (== 0)", 141 | "exception": "Invalid r value", 142 | "e": "01", 143 | "signatureRaw": { 144 | "r": "00", 145 | "s": "02" 146 | }, 147 | "i": 0 148 | }, 149 | { 150 | "description": "Invalid s value (< 0)", 151 | "exception": "Invalid s value", 152 | "e": "01", 153 | "signatureRaw": { 154 | "r": "02", 155 | "s": "-01" 156 | }, 157 | "i": 0 158 | }, 159 | { 160 | "description": "Invalid s value (== 0)", 161 | "exception": "Invalid s value", 162 | "e": "01", 163 | "signatureRaw": { 164 | "r": "02", 165 | "s": "00" 166 | }, 167 | "i": 0 168 | }, 169 | { 170 | "description": "Invalid r value (nR is infinity)", 171 | "exception": "nR is not a valid curve point", 172 | "e": "01", 173 | "signatureRaw": { 174 | "r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 175 | "s": "01" 176 | }, 177 | "i": 0 178 | }, 179 | { 180 | "description": "Invalid curve point", 181 | "exception": "Point is not on the curve", 182 | "e": "01", 183 | "signatureRaw": { 184 | "r": "4b3b4ca85a86c47a098a223fffffffff", 185 | "s": "01" 186 | }, 187 | "i": 0 188 | }, 189 | { 190 | "description": "Invalid i value (> 3)", 191 | "exception": "Expected UInt2, got Number 4", 192 | "e": "01", 193 | "signatureRaw": { 194 | "r": "00", 195 | "s": "02" 196 | }, 197 | "i": 4 198 | } 199 | ], 200 | "verify": [ 201 | { 202 | "description": "The wrong signature", 203 | "d": "01", 204 | "message": "foo", 205 | "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5" 206 | }, 207 | { 208 | "description": "Invalid r value (< 0)", 209 | "d": "01", 210 | "message": "foo", 211 | "signatureRaw": { 212 | "r": "-01", 213 | "s": "02" 214 | } 215 | }, 216 | { 217 | "description": "Invalid r value (== 0)", 218 | "d": "01", 219 | "message": "foo", 220 | "signatureRaw": { 221 | "r": "00", 222 | "s": "02" 223 | } 224 | }, 225 | { 226 | "description": "Invalid r value (>= n)", 227 | "d": "01", 228 | "message": "foo", 229 | "signatureRaw": { 230 | "r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 231 | "s": "02" 232 | } 233 | }, 234 | { 235 | "description": "Invalid s value (< 0)", 236 | "d": "01", 237 | "message": "foo", 238 | "signatureRaw": { 239 | "r": "02", 240 | "s": "-01" 241 | } 242 | }, 243 | { 244 | "description": "Invalid s value (== 0)", 245 | "d": "01", 246 | "message": "foo", 247 | "signatureRaw": { 248 | "r": "02", 249 | "s": "00" 250 | } 251 | }, 252 | { 253 | "description": "Invalid s value (>= n)", 254 | "d": "01", 255 | "message": "foo", 256 | "signatureRaw": { 257 | "r": "02", 258 | "s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" 259 | } 260 | }, 261 | { 262 | "description": "Invalid r, s values (r = s = -n)", 263 | "d": "01", 264 | "message": "foo", 265 | "signatureRaw": { 266 | "r": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 267 | "s": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" 268 | } 269 | } 270 | ] 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /test/fixtures/ecpair.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": [ 3 | { 4 | "d": "1", 5 | "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 6 | "compressed": true, 7 | "network": "bitcoin", 8 | "address": "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH", 9 | "WIF": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn" 10 | }, 11 | { 12 | "d": "1", 13 | "Q": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 14 | "compressed": false, 15 | "network": "bitcoin", 16 | "address": "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm", 17 | "WIF": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf" 18 | }, 19 | { 20 | "d": "19898843618908353587043383062236220484949425084007183071220218307100305431102", 21 | "Q": "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340", 22 | "compressed": true, 23 | "network": "bitcoin", 24 | "address": "1MasfEKgSiaSeri2C6kgznaqBNtyrZPhNq", 25 | "WIF": "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o" 26 | }, 27 | { 28 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", 29 | "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34", 30 | "compressed": true, 31 | "network": "bitcoin", 32 | "address": "1LwwMWdSEMHJ2dMhSvAHZ3g95tG2UBv9jg", 33 | "WIF": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx" 34 | }, 35 | { 36 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", 37 | "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6", 38 | "compressed": false, 39 | "network": "bitcoin", 40 | "address": "1zXcfvKCLgsFdJDYPuqpu1sF3q92tnnUM", 41 | "WIF": "5JdxzLtFPHNe7CAL8EBC6krdFv9pwPoRo4e3syMZEQT9srmK8hh" 42 | }, 43 | { 44 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", 45 | "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34", 46 | "compressed": true, 47 | "network": "testnet", 48 | "address": "n1TteZiR3NiYojqKAV8fNxtTwsrjM7kVdj", 49 | "WIF": "cRD9b1m3vQxmwmjSoJy7Mj56f4uNFXjcWMCzpQCEmHASS4edEwXv" 50 | }, 51 | { 52 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851", 53 | "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6", 54 | "compressed": false, 55 | "network": "testnet", 56 | "address": "mgWUuj1J1N882jmqFxtDepEC73Rr22E9GU", 57 | "WIF": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj" 58 | }, 59 | { 60 | "d": "115792089237316195423570985008687907852837564279074904382605163141518161494336", 61 | "Q": "0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 62 | "compressed": true, 63 | "network": "bitcoin", 64 | "address": "1GrLCmVQXoyJXaPJQdqssNqwxvha1eUo2E", 65 | "WIF": "L5oLkpV3aqBjhki6LmvChTCV6odsp4SXM6FfU2Gppt5kFLaHLuZ9" 66 | } 67 | ], 68 | "invalid": { 69 | "constructor": [ 70 | { 71 | "exception": "Private key must be greater than 0", 72 | "d": "-1" 73 | }, 74 | { 75 | "exception": "Private key must be greater than 0", 76 | "d": "0" 77 | }, 78 | { 79 | "exception": "Private key must be less than the curve order", 80 | "d": "115792089237316195423570985008687907852837564279074904382605163141518161494337" 81 | }, 82 | { 83 | "exception": "Private key must be less than the curve order", 84 | "d": "115792089237316195423570985008687907853269984665640564039457584007913129639935" 85 | }, 86 | { 87 | "exception": "Expected property \"compressed\" of type \\?Boolean, got Number 2", 88 | "d": "1", 89 | "options": { 90 | "compressed": 2 91 | } 92 | }, 93 | { 94 | "exception": "Unexpected publicKey parameter", 95 | "d": "1", 96 | "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" 97 | }, 98 | { 99 | "exception": "Expected property \"network.messagePrefix\" of type Buffer|String, got undefined", 100 | "d": "1", 101 | "options": { 102 | "network": {} 103 | } 104 | } 105 | 106 | ], 107 | "fromWIF": [ 108 | { 109 | "exception": "Invalid network version", 110 | "network": "bitcoin", 111 | "WIF": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj" 112 | }, 113 | { 114 | "exception": "Unknown network version", 115 | "WIF": "brQnSed3Fia1w9VcbbS6ZGDgJ6ENkgwuQY2LS7pEC5bKHD1fMF" 116 | }, 117 | { 118 | "exception": "Invalid compression flag", 119 | "WIF": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sfZr2ym" 120 | }, 121 | { 122 | "exception": "Invalid WIF length", 123 | "WIF": "3tq8Vmhh9SN5XhjTGSWgx8iKk59XbKG6UH4oqpejRuJhfYD" 124 | }, 125 | { 126 | "exception": "Invalid WIF length", 127 | "WIF": "38uMpGARR2BJy5p4dNFKYg9UsWNoBtkpbdrXDjmfvz8krCtw3T1W92ZDSR" 128 | } 129 | ] 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /test/fixtures/ecsignature.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": [ 3 | { 4 | "compact": { 5 | "hex": "1f33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262", 6 | "compressed": true, 7 | "i": 0 8 | }, 9 | "scriptSignature": { 10 | "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201", 11 | "hashType": 1 12 | }, 13 | "DER": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262", 14 | "signature": { 15 | "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561", 16 | "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938" 17 | } 18 | }, 19 | { 20 | "compact": { 21 | "hex": "1b54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5", 22 | "compressed": false, 23 | "i": 0 24 | }, 25 | "DER": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5", 26 | "scriptSignature": { 27 | "hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502", 28 | "hashType": 2 29 | }, 30 | "signature": { 31 | "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885", 32 | "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757" 33 | } 34 | }, 35 | { 36 | "compact": { 37 | "hex": "1fff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283", 38 | "compressed": true, 39 | "i": 0 40 | }, 41 | "scriptSignature": { 42 | "hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303", 43 | "hashType": 3 44 | }, 45 | "DER": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283", 46 | "signature": { 47 | "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904", 48 | "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971" 49 | } 50 | }, 51 | { 52 | "compact": { 53 | "hex": "1cc0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3", 54 | "compressed": false, 55 | "i": 1 56 | }, 57 | "scriptSignature": { 58 | "hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381", 59 | "hashType": 129 60 | }, 61 | "DER": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3", 62 | "signature": { 63 | "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123", 64 | "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875" 65 | } 66 | }, 67 | { 68 | "compact": { 69 | "hex": "1f7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6", 70 | "compressed": true, 71 | "i": 0 72 | }, 73 | "scriptSignature": { 74 | "hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682", 75 | "hashType": 130 76 | }, 77 | "DER": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6", 78 | "signature": { 79 | "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997", 80 | "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862" 81 | } 82 | }, 83 | { 84 | "compact": { 85 | "hex": "1cfbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37", 86 | "compressed": false, 87 | "i": 1 88 | }, 89 | "scriptSignature": { 90 | "hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783", 91 | "hashType": 131 92 | }, 93 | "DER": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37", 94 | "signature": { 95 | "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671", 96 | "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959" 97 | } 98 | }, 99 | { 100 | "compact": { 101 | "hex": "20cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef", 102 | "compressed": true, 103 | "i": 1 104 | }, 105 | "scriptSignature": { 106 | "hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81", 107 | "hashType": 129 108 | }, 109 | "DER": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef", 110 | "signature": { 111 | "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777", 112 | "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839" 113 | } 114 | } 115 | ], 116 | "invalid": { 117 | "compact": [ 118 | { 119 | "exception": "Invalid signature parameter", 120 | "hex": "23987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62" 121 | }, 122 | { 123 | "exception": "Invalid signature length", 124 | "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62000000" 125 | }, 126 | { 127 | "exception": "Invalid signature length", 128 | "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e9379" 129 | } 130 | ], 131 | "DER": [ 132 | { 133 | "exception": "DER sequence length is too short", 134 | "hex": "ffffffffffffff" 135 | }, 136 | { 137 | "exception": "DER sequence length is too long", 138 | "hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 139 | }, 140 | { 141 | "exception": "Expected DER sequence", 142 | "hex": "00ffff0400ffffff020400ffffff" 143 | }, 144 | { 145 | "exception": "DER sequence length is invalid", 146 | "hex": "30ff020400ffffff020400ffffff" 147 | }, 148 | { 149 | "exception": "DER sequence length is invalid", 150 | "hex": "300c030400ffffff030400ffffff0000" 151 | }, 152 | { 153 | "exception": "Expected DER integer", 154 | "hex": "300cff0400ffffff020400ffffff" 155 | }, 156 | { 157 | "exception": "Expected DER integer \\(2\\)", 158 | "hex": "300c020200ffffff020400ffffff" 159 | }, 160 | { 161 | "exception": "R length is zero", 162 | "hex": "30080200020400ffffff" 163 | }, 164 | { 165 | "exception": "S length is zero", 166 | "hex": "3008020400ffffff0200" 167 | }, 168 | { 169 | "exception": "R length is too long", 170 | "hex": "300c02dd00ffffff020400ffffff" 171 | }, 172 | { 173 | "exception": "S length is invalid", 174 | "hex": "300c020400ffffff02dd00ffffff" 175 | }, 176 | { 177 | "exception": "R value is negative", 178 | "hex": "300c020480000000020400ffffff" 179 | }, 180 | { 181 | "exception": "S value is negative", 182 | "hex": "300c020400ffffff020480000000" 183 | }, 184 | { 185 | "exception": "R value excessively padded", 186 | "hex": "300c02040000ffff020400ffffff" 187 | }, 188 | { 189 | "exception": "S value excessively padded", 190 | "hex": "300c020400ffffff02040000ffff" 191 | } 192 | ], 193 | "scriptSignature": [ 194 | { 195 | "exception": "Invalid hashType 7", 196 | "hashType": 7, 197 | "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207", 198 | "signature": { 199 | "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561", 200 | "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938" 201 | } 202 | }, 203 | { 204 | "exception": "Invalid hashType 140", 205 | "hashType": 140, 206 | "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c", 207 | "signature": { 208 | "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561", 209 | "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938" 210 | } 211 | } 212 | ] 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /test/fixtures/message.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": { 3 | "magicHash": [ 4 | { 5 | "network": "bitcoin", 6 | "message": "", 7 | "magicHash": "80e795d4a4caadd7047af389d9f7f220562feb6196032e2131e10563352c4bcc" 8 | }, 9 | { 10 | "network": "bitcoin", 11 | "message": "Vires is Numeris", 12 | "magicHash": "f8a5affbef4a3241b19067aa694562f64f513310817297089a8929a930f4f933" 13 | }, 14 | { 15 | "network": "dogecoin", 16 | "message": "Vires is Numeris", 17 | "magicHash": "c0963d20d0accd0ea0df6c1020bf85a7e629a40e7b5363f2c3e9dcafd5638f12" 18 | } 19 | ], 20 | "verify": [ 21 | { 22 | "message": "vires is numeris", 23 | "network": "bitcoin", 24 | "address": "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", 25 | "signature": "G8JawPtQOrybrSP1WHQnQPr67B9S3qrxBrl1mlzoTJOSHEpmnF7D3+t+LX0Xei9J20B5AIdPbeL3AaTBZ4N3bY0=", 26 | "compressed": { 27 | "address": "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs", 28 | "signature": "H8JawPtQOrybrSP1WHQnQPr67B9S3qrxBrl1mlzoTJOSHEpmnF7D3+t+LX0Xei9J20B5AIdPbeL3AaTBZ4N3bY0=" 29 | } 30 | }, 31 | { 32 | "message": "vires is numeris", 33 | "network": "dogecoin", 34 | "address": "DFpN6QqFfUm3gKNaxN6tNcab1FArL9cZLE", 35 | "signature": "H6k+dZwJ8oOei3PCSpdj603fDvhlhQ+sqaFNIDvo/bI+Xh6zyIKGzZpyud6YhZ1a5mcrwMVtTWL+VXq/hC5Zj7s=" 36 | } 37 | ], 38 | "signing": [ 39 | { 40 | "description": "gives equal r, s values irrespective of point compression", 41 | "message": "vires is numeris", 42 | "network": "bitcoin", 43 | "d": "1", 44 | "signature": "HF8nHqFr3K2UKYahhX3soVeoW8W1ECNbr0wfck7lzyXjCS5Q16Ek45zyBuy1Fiy9sTPKVgsqqOuPvbycuVSSVl8=", 45 | "compressed": { 46 | "signature": "IF8nHqFr3K2UKYahhX3soVeoW8W1ECNbr0wfck7lzyXjCS5Q16Ek45zyBuy1Fiy9sTPKVgsqqOuPvbycuVSSVl8=" 47 | } 48 | }, 49 | { 50 | "description": "supports alternative networks", 51 | "message": "vires is numeris", 52 | "network": "dogecoin", 53 | "d": "1", 54 | "signature": "G6k+dZwJ8oOei3PCSpdj603fDvhlhQ+sqaFNIDvo/bI+Xh6zyIKGzZpyud6YhZ1a5mcrwMVtTWL+VXq/hC5Zj7s=" 55 | } 56 | ] 57 | }, 58 | "invalid": { 59 | "verify": [ 60 | { 61 | "description": "will fail for the wrong message", 62 | "message": "foobar", 63 | "address": "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", 64 | "signature": "G8JawPtQOrybrSP1WHQnQPr67B9S3qrxBrl1mlzoTJOSHEpmnF7D3+t+LX0Xei9J20B5AIdPbeL3AaTBZ4N3bY0=" 65 | }, 66 | { 67 | "description": "will fail for the wrong address", 68 | "message": "vires is numeris", 69 | "address": "1111111111111111111114oLvT2", 70 | "signature": "H8JawPtQOrybrSP1WHQnQPr67B9S3qrxBrl1mlzoTJOSHEpmnF7D3+t+LX0Xei9J20B5AIdPbeL3AaTBZ4N3bY0=" 71 | }, 72 | { 73 | "description": "does not cross verify (uncompressed address, compressed signature)", 74 | "message": "vires is numeris", 75 | "address": "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", 76 | "signature": "H8JawPtQOrybrSP1WHQnQPr67B9S3qrxBrl1mlzoTJOSHEpmnF7D3+t+LX0Xei9J20B5AIdPbeL3AaTBZ4N3bY0=" 77 | }, 78 | { 79 | "description": "does not cross verify (compressed address, uncompressed signature)", 80 | "message": "vires is numeris", 81 | "address": "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs", 82 | "signature": "G8JawPtQOrybrSP1WHQnQPr67B9S3qrxBrl1mlzoTJOSHEpmnF7D3+t+LX0Xei9J20B5AIdPbeL3AaTBZ4N3bY0=" 83 | } 84 | ] 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test/fixtures/script_number.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "hex": "", 4 | "number": 0 5 | }, 6 | { 7 | "hex": "01", 8 | "number": 1 9 | }, 10 | { 11 | "hex": "02", 12 | "number": 2 13 | }, 14 | { 15 | "hex": "03", 16 | "number": 3 17 | }, 18 | { 19 | "hex": "7e", 20 | "number": 126 21 | }, 22 | { 23 | "hex": "7f", 24 | "number": 127 25 | }, 26 | { 27 | "hex": "8000", 28 | "number": 128 29 | }, 30 | { 31 | "hex": "8100", 32 | "number": 129 33 | }, 34 | { 35 | "hex": "8200", 36 | "number": 130 37 | }, 38 | { 39 | "hex": "ff00", 40 | "number": 255 41 | }, 42 | { 43 | "hex": "fe7f", 44 | "number": 32766 45 | }, 46 | { 47 | "hex": "ff7f", 48 | "number": 32767 49 | }, 50 | { 51 | "hex": "008000", 52 | "number": 32768 53 | }, 54 | { 55 | "hex": "ffff00", 56 | "number": 65535 57 | }, 58 | { 59 | "hex": "018000", 60 | "number": 32769 61 | }, 62 | { 63 | "hex": "028000", 64 | "number": 32770 65 | }, 66 | { 67 | "hex": "ffffff00", 68 | "number": 16777215 69 | }, 70 | { 71 | "hex": "feff7f", 72 | "number": 8388606 73 | }, 74 | { 75 | "hex": "ffff7f", 76 | "number": 8388607 77 | }, 78 | { 79 | "hex": "00008000", 80 | "number": 8388608 81 | }, 82 | { 83 | "hex": "01008000", 84 | "number": 8388609 85 | }, 86 | { 87 | "hex": "02008000", 88 | "number": 8388610 89 | }, 90 | { 91 | "hex": "feffff7f", 92 | "number": 2147483646 93 | }, 94 | { 95 | "hex": "ffffff7f", 96 | "number": 2147483647 97 | }, 98 | { 99 | "bytes": 5, 100 | "hex": "0000008000", 101 | "number": 2147483648 102 | }, 103 | { 104 | "bytes": 5, 105 | "hex": "0100008000", 106 | "number": 2147483649 107 | }, 108 | { 109 | "bytes": 5, 110 | "hex": "0200008000", 111 | "number": 2147483650 112 | }, 113 | { 114 | "bytes": 5, 115 | "hex": "ffffffff00", 116 | "number": 4294967295 117 | }, 118 | { 119 | "bytes": 5, 120 | "hex": "0200008080", 121 | "number": -2147483650 122 | }, 123 | { 124 | "bytes": 5, 125 | "hex": "0100008080", 126 | "number": -2147483649 127 | }, 128 | { 129 | "bytes": 5, 130 | "hex": "0000008080", 131 | "number": -2147483648 132 | }, 133 | { 134 | "hex": "ffffffff", 135 | "number": -2147483647 136 | }, 137 | { 138 | "hex": "feffffff", 139 | "number": -2147483646 140 | }, 141 | { 142 | "hex": "fdffffff", 143 | "number": -2147483645 144 | }, 145 | { 146 | "hex": "ffffff80", 147 | "number": -16777215 148 | }, 149 | { 150 | "hex": "01008080", 151 | "number": -8388609 152 | }, 153 | { 154 | "hex": "00008080", 155 | "number": -8388608 156 | }, 157 | { 158 | "hex": "ffffff", 159 | "number": -8388607 160 | }, 161 | { 162 | "hex": "feffff", 163 | "number": -8388606 164 | }, 165 | { 166 | "hex": "fdffff", 167 | "number": -8388605 168 | }, 169 | { 170 | "hex": "ffff80", 171 | "number": -65535 172 | }, 173 | { 174 | "hex": "018080", 175 | "number": -32769 176 | }, 177 | { 178 | "hex": "008080", 179 | "number": -32768 180 | }, 181 | { 182 | "hex": "ffff", 183 | "number": -32767 184 | }, 185 | { 186 | "hex": "feff", 187 | "number": -32766 188 | }, 189 | { 190 | "hex": "fdff", 191 | "number": -32765 192 | }, 193 | { 194 | "hex": "ff80", 195 | "number": -255 196 | }, 197 | { 198 | "hex": "8180", 199 | "number": -129 200 | }, 201 | { 202 | "hex": "8080", 203 | "number": -128 204 | }, 205 | { 206 | "hex": "ff", 207 | "number": -127 208 | }, 209 | { 210 | "hex": "fe", 211 | "number": -126 212 | }, 213 | { 214 | "hex": "fd", 215 | "number": -125 216 | }, 217 | { 218 | "hex": "82", 219 | "number": -2 220 | }, 221 | { 222 | "hex": "81", 223 | "number": -1 224 | } 225 | ] 226 | -------------------------------------------------------------------------------- /test/integration/_blockchain.js: -------------------------------------------------------------------------------- 1 | var async = require('async') 2 | var Blockchain = require('cb-http-client') 3 | var httpify = require('httpify') 4 | 5 | var BLOCKTRAIL_API_KEY = process.env.BLOCKTRAIL_API_KEY || 'c0bd8155c66e3fb148bb1664adc1e4dacd872548' 6 | 7 | var mainnet = new Blockchain('https://api.blocktrail.com/cb/v0.2.1/BTC', { api_key: BLOCKTRAIL_API_KEY }) 8 | var testnet = new Blockchain('https://api.blocktrail.com/cb/v0.2.1/tBTC', { api_key: BLOCKTRAIL_API_KEY }) 9 | 10 | testnet.faucet = function faucet (address, amount, done) { 11 | httpify({ 12 | method: 'POST', 13 | url: 'https://api.blocktrail.com/v1/tBTC/faucet/withdrawl?api_key=' + BLOCKTRAIL_API_KEY, 14 | headers: { 'Content-Type': 'application/json' }, 15 | body: JSON.stringify({ 16 | address: address, 17 | amount: amount 18 | }) 19 | }, function (err, result) { 20 | if (err) return done(err) 21 | 22 | if (result.body.code === 401) { 23 | return done(new Error('Hit faucet rate limit; ' + result.body.msg)) 24 | } 25 | 26 | // allow for TX to be processed 27 | async.retry(5, function (callback) { 28 | setTimeout(function () { 29 | testnet.addresses.unspents(address, function (err, result) { 30 | if (err) return callback(err) 31 | 32 | var unspent = result.filter(function (unspent) { 33 | return unspent.value >= amount 34 | }).pop() 35 | 36 | if (!unspent) return callback(new Error('No unspent given')) 37 | callback(null, unspent) 38 | }) 39 | }, 600) 40 | }, done) 41 | }) 42 | } 43 | 44 | module.exports = { 45 | m: mainnet, 46 | t: testnet 47 | } 48 | -------------------------------------------------------------------------------- /test/integration/advanced.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, beforeEach */ 2 | 3 | var assert = require('assert') 4 | var bitcoin = require('../../') 5 | var blockchain = require('./_blockchain') 6 | 7 | describe('bitcoinjs-lib (advanced)', function () { 8 | it('can sign a Bitcoin message', function () { 9 | var keyPair = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') 10 | var message = 'This is an example of a signed message.' 11 | 12 | var signature = bitcoin.message.sign(keyPair, message) 13 | assert.strictEqual(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=') 14 | }) 15 | 16 | it('can verify a Bitcoin message', function () { 17 | var address = '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN' 18 | var signature = 'HJLQlDWLyb1Ef8bQKEISzFbDAKctIlaqOpGbrk3YVtRsjmC61lpE5ErkPRUFtDKtx98vHFGUWlFhsh3DiW6N0rE' 19 | var message = 'This is an example of a signed message.' 20 | 21 | assert(bitcoin.message.verify(address, signature, message)) 22 | }) 23 | 24 | it('can create a transaction using OP_RETURN', function (done) { 25 | this.timeout(30000) 26 | 27 | var network = bitcoin.networks.testnet 28 | var keyPair = bitcoin.ECPair.makeRandom({ network: network }) 29 | var address = keyPair.getAddress() 30 | 31 | blockchain.t.faucet(address, 2e4, function (err, unspent) { 32 | if (err) return done(err) 33 | 34 | var tx = new bitcoin.TransactionBuilder(network) 35 | var data = new Buffer('bitcoinjs-lib') 36 | var dataScript = bitcoin.script.nullDataOutput(data) 37 | 38 | tx.addInput(unspent.txId, unspent.vout) 39 | tx.addOutput(dataScript, 1000) 40 | tx.sign(0, keyPair) 41 | var txRaw = tx.build() 42 | 43 | blockchain.t.transactions.propagate(txRaw.toHex(), done) 44 | }) 45 | }) 46 | 47 | describe('can create transactions using OP_CHECKLOCKTIMEVERIFY', function (done) { 48 | var network = bitcoin.networks.testnet 49 | var alice = bitcoin.ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', network) 50 | var bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', network) 51 | 52 | // now - 3 hours 53 | var threeHoursAgo = Math.floor(Date.now() / 1000) - (3600 * 3) 54 | var redeemScript = bitcoin.script.compile([ 55 | bitcoin.opcodes.OP_IF, 56 | 57 | bitcoin.script.number.encode(threeHoursAgo), 58 | bitcoin.opcodes.OP_CHECKLOCKTIMEVERIFY, 59 | bitcoin.opcodes.OP_DROP, 60 | 61 | bitcoin.opcodes.OP_ELSE, 62 | 63 | bob.getPublicKeyBuffer(), 64 | bitcoin.opcodes.OP_CHECKSIGVERIFY, 65 | 66 | bitcoin.opcodes.OP_ENDIF, 67 | 68 | alice.getPublicKeyBuffer(), 69 | bitcoin.opcodes.OP_CHECKSIG 70 | ]) 71 | var scriptPubKey = bitcoin.script.scriptHashOutput(bitcoin.crypto.hash160(redeemScript)) 72 | 73 | var txId 74 | beforeEach(function (done) { 75 | this.timeout(10000) 76 | 77 | blockchain.t.faucet(alice.getAddress(), 2e4, function (err, unspent) { 78 | if (err) return done(err) 79 | 80 | // build the transaction 81 | var tx = new bitcoin.TransactionBuilder(network) 82 | tx.addInput(unspent.txId, unspent.vout) 83 | tx.addOutput(scriptPubKey, 1e4) 84 | tx.sign(0, alice) 85 | var txRaw = tx.build() 86 | 87 | txId = txRaw.getId() 88 | 89 | blockchain.t.transactions.propagate(txRaw.toHex(), done) 90 | }) 91 | }) 92 | 93 | // expiry past, {Alice's signature} OP_TRUE 94 | it('where Alice can redeem after the expiry is past', function (done) { 95 | this.timeout(30000) 96 | 97 | var tx2 = new bitcoin.TransactionBuilder(network) 98 | tx2.setLockTime(threeHoursAgo) 99 | tx2.addInput(txId, 0, 0xfffffffe) 100 | tx2.addOutput(alice.getAddress(), 1000) 101 | 102 | var tx2Raw = tx2.buildIncomplete() 103 | var hashType = bitcoin.Transaction.SIGHASH_ALL 104 | var signatureHash = tx2Raw.hashForSignature(0, redeemScript, hashType) 105 | var signature = alice.sign(signatureHash) 106 | 107 | var redeemScriptSig = bitcoin.script.scriptHashInput([ 108 | signature.toScriptSignature(hashType), bitcoin.opcodes.OP_TRUE 109 | ], redeemScript) 110 | 111 | tx2Raw.setInputScript(0, redeemScriptSig) 112 | 113 | blockchain.t.transactions.propagate(tx2Raw.toHex(), done) 114 | }) 115 | 116 | // {Bob's signature} {Alice's signature} OP_FALSE 117 | it('where Alice and Bob can redeem at any time', function (done) { 118 | this.timeout(30000) 119 | 120 | var tx2 = new bitcoin.TransactionBuilder(network) 121 | tx2.setLockTime(threeHoursAgo) 122 | tx2.addInput(txId, 0, 0xfffffffe) 123 | tx2.addOutput(alice.getAddress(), 1000) 124 | 125 | var tx2Raw = tx2.buildIncomplete() 126 | var hashType = bitcoin.Transaction.SIGHASH_ALL 127 | var signatureHash = tx2Raw.hashForSignature(0, redeemScript, hashType) 128 | var signatureA = alice.sign(signatureHash) 129 | var signatureB = bob.sign(signatureHash) 130 | var redeemScriptSig = bitcoin.script.scriptHashInput([ 131 | signatureA.toScriptSignature(hashType), signatureB.toScriptSignature(hashType), bitcoin.opcodes.OP_FALSE 132 | ], redeemScript) 133 | 134 | tx2Raw.setInputScript(0, redeemScriptSig) 135 | 136 | blockchain.t.transactions.propagate(tx2Raw.toHex(), done) 137 | }) 138 | }) 139 | }) 140 | -------------------------------------------------------------------------------- /test/integration/basic.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var bigi = require('bigi') 5 | var bitcoin = require('../../') 6 | 7 | describe('bitcoinjs-lib (basic)', function () { 8 | it('can generate a random bitcoin address', function () { 9 | // for testing only 10 | function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } 11 | 12 | // generate random keyPair 13 | var keyPair = bitcoin.ECPair.makeRandom({ rng: rng }) 14 | var address = keyPair.getAddress() 15 | 16 | assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64') 17 | }) 18 | 19 | it('can generate an address from a SHA256 hash', function () { 20 | var hash = bitcoin.crypto.sha256('correct horse battery staple') 21 | var d = bigi.fromBuffer(hash) 22 | 23 | var keyPair = new bitcoin.ECPair(d) 24 | var address = keyPair.getAddress() 25 | 26 | assert.strictEqual(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') 27 | }) 28 | 29 | it('can generate a random keypair for alternative networks', function () { 30 | // for testing only 31 | function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') } 32 | 33 | var litecoin = bitcoin.networks.litecoin 34 | 35 | var keyPair = bitcoin.ECPair.makeRandom({ network: litecoin, rng: rng }) 36 | var wif = keyPair.toWIF() 37 | var address = keyPair.getAddress() 38 | 39 | assert.strictEqual(address, 'LZJSxZbjqJ2XVEquqfqHg1RQTDdfST5PTn') 40 | assert.strictEqual(wif, 'T7A4PUSgTDHecBxW1ZiYFrDNRih2o7M8Gf9xpoCgudPF9gDiNvuS') 41 | }) 42 | 43 | it('can import an address via WIF', function () { 44 | var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct') 45 | var address = keyPair.getAddress() 46 | 47 | assert.strictEqual(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') 48 | }) 49 | 50 | it('can create a Transaction', function () { 51 | var keyPair = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy') 52 | var tx = new bitcoin.TransactionBuilder() 53 | 54 | tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0) 55 | tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000) 56 | tx.sign(0, keyPair) 57 | 58 | assert.strictEqual(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000') 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /test/integration/crypto.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var async = require('async') 5 | var bigi = require('bigi') 6 | var bitcoin = require('../../') 7 | var blockchain = require('./_blockchain') 8 | var crypto = require('crypto') 9 | 10 | var ecurve = require('ecurve') 11 | var secp256k1 = ecurve.getCurveByName('secp256k1') 12 | 13 | describe('bitcoinjs-lib (crypto)', function () { 14 | it('can generate a single-key stealth address', function () { 15 | var G = secp256k1.G 16 | var n = secp256k1.n 17 | 18 | function stealthSend (Q) { 19 | var noncePair = bitcoin.ECPair.makeRandom() 20 | var e = noncePair.d 21 | var eQ = Q.multiply(e) // shared secret 22 | var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded())) 23 | var cG = G.multiply(c) 24 | var Qprime = Q.add(cG) 25 | 26 | return { 27 | shared: new bitcoin.ECPair(null, Qprime), 28 | nonce: new bitcoin.ECPair(null, noncePair.Q) 29 | } 30 | } 31 | 32 | function stealthReceive (d, P) { 33 | var dP = P.multiply(d) // shared secret 34 | var c = bigi.fromBuffer(bitcoin.crypto.sha256(dP.getEncoded())) 35 | var derived = new bitcoin.ECPair(d.add(c).mod(n)) 36 | 37 | return derived 38 | } 39 | 40 | // receiver private key 41 | var receiver = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') 42 | 43 | var stealthS = stealthSend(receiver.Q) // public, done by sender 44 | // ... sender now reveals nonce to receiver 45 | 46 | var stealthR = stealthReceive(receiver.d, stealthS.nonce.Q) // private, done by receiver 47 | 48 | // and check that we derived both sides correctly 49 | assert.equal(stealthS.shared.getAddress(), stealthR.getAddress()) 50 | }) 51 | 52 | // TODO 53 | it.skip('can generate a dual-key stealth address', function () {}) 54 | 55 | it("can recover a parent private key from the parent's public key and a derived non-hardened child private key", function () { 56 | function recoverParent (master, child) { 57 | assert(!master.keyPair.d, 'You already have the parent private key') 58 | assert(child.keyPair.d, 'Missing child private key') 59 | 60 | var curve = secp256k1 61 | var QP = master.keyPair.Q 62 | var serQP = master.keyPair.getPublicKeyBuffer() 63 | 64 | var d1 = child.keyPair.d 65 | var d2 66 | var data = new Buffer(37) 67 | serQP.copy(data, 0) 68 | 69 | // search index space until we find it 70 | for (var i = 0; i < bitcoin.HDNode.HIGHEST_BIT; ++i) { 71 | data.writeUInt32BE(i, 33) 72 | 73 | // calculate I 74 | var I = crypto.createHmac('sha512', master.chainCode).update(data).digest() 75 | var IL = I.slice(0, 32) 76 | var pIL = bigi.fromBuffer(IL) 77 | 78 | // See hdnode.js:273 to understand 79 | d2 = d1.subtract(pIL).mod(curve.n) 80 | 81 | var Qp = new bitcoin.ECPair(d2).Q 82 | if (Qp.equals(QP)) break 83 | } 84 | 85 | var node = new bitcoin.HDNode(new bitcoin.ECPair(d2), master.chainCode, master.network) 86 | node.depth = master.depth 87 | node.index = master.index 88 | node.masterFingerprint = master.masterFingerprint 89 | return node 90 | } 91 | 92 | var seed = crypto.randomBytes(32) 93 | var master = bitcoin.HDNode.fromSeedBuffer(seed) 94 | var child = master.derive(6) // m/6 95 | 96 | // now for the recovery 97 | var neuteredMaster = master.neutered() 98 | var recovered = recoverParent(neuteredMaster, child) 99 | assert.strictEqual(recovered.toBase58(), master.toBase58()) 100 | }) 101 | 102 | it('can recover a private key from duplicate R values', function (done) { 103 | this.timeout(10000) 104 | 105 | var inputs = [ 106 | { 107 | txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50', 108 | vout: 0 109 | }, 110 | { 111 | txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50', 112 | vout: 1 113 | } 114 | ] 115 | 116 | var txIds = inputs.map(function (x) { return x.txId }) 117 | 118 | // first retrieve the relevant transactions 119 | blockchain.m.transactions.get(txIds, function (err, results) { 120 | assert.ifError(err) 121 | 122 | var transactions = {} 123 | results.forEach(function (tx) { 124 | transactions[tx.txId] = bitcoin.Transaction.fromHex(tx.txHex) 125 | }) 126 | 127 | var tasks = [] 128 | 129 | // now we need to collect/transform a bit of data from the selected inputs 130 | inputs.forEach(function (input) { 131 | var transaction = transactions[input.txId] 132 | var script = transaction.ins[input.vout].script 133 | var scriptChunks = bitcoin.script.decompile(script) 134 | 135 | assert(bitcoin.script.isPubKeyHashInput(scriptChunks), 'Expected pubKeyHash script') 136 | 137 | var prevOutTxId = [].reverse.call(new Buffer(transaction.ins[input.vout].hash)).toString('hex') 138 | var prevVout = transaction.ins[input.vout].index 139 | 140 | tasks.push(function (callback) { 141 | blockchain.m.transactions.get(prevOutTxId, function (err, result) { 142 | if (err) return callback(err) 143 | 144 | var prevOut = bitcoin.Transaction.fromHex(result.txHex) 145 | var prevOutScript = prevOut.outs[prevVout].script 146 | 147 | var scriptSignature = bitcoin.ECSignature.parseScriptSignature(scriptChunks[0]) 148 | var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(scriptChunks[1]) 149 | 150 | var m = transaction.hashForSignature(input.vout, prevOutScript, scriptSignature.hashType) 151 | assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m') 152 | 153 | // store the required information 154 | input.signature = scriptSignature.signature 155 | input.z = bigi.fromBuffer(m) 156 | 157 | return callback() 158 | }) 159 | }) 160 | }) 161 | 162 | // finally, run the tasks, then on to the math 163 | async.parallel(tasks, function (err) { 164 | if (err) throw err 165 | 166 | var n = secp256k1.n 167 | 168 | for (var i = 0; i < inputs.length; ++i) { 169 | for (var j = i + 1; j < inputs.length; ++j) { 170 | var inputA = inputs[i] 171 | var inputB = inputs[j] 172 | 173 | // enforce matching r values 174 | assert.strictEqual(inputA.signature.r.toString(), inputB.signature.r.toString()) 175 | var r = inputA.signature.r 176 | var rInv = r.modInverse(n) 177 | 178 | var s1 = inputA.signature.s 179 | var s2 = inputB.signature.s 180 | var z1 = inputA.z 181 | var z2 = inputB.z 182 | 183 | var zz = z1.subtract(z2).mod(n) 184 | var ss = s1.subtract(s2).mod(n) 185 | 186 | // k = (z1 - z2) / (s1 - s2) 187 | // d1 = (s1 * k - z1) / r 188 | // d2 = (s2 * k - z2) / r 189 | var k = zz.multiply(ss.modInverse(n)).mod(n) 190 | var d1 = ((s1.multiply(k).mod(n)).subtract(z1).mod(n)).multiply(rInv).mod(n) 191 | var d2 = ((s2.multiply(k).mod(n)).subtract(z2).mod(n)).multiply(rInv).mod(n) 192 | 193 | // enforce matching private keys 194 | assert.strictEqual(d1.toString(), d2.toString()) 195 | } 196 | } 197 | 198 | done() 199 | }) 200 | }) 201 | }) 202 | }) 203 | -------------------------------------------------------------------------------- /test/integration/multisig.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var async = require('async') 4 | var assert = require('assert') 5 | var bitcoin = require('../../') 6 | var blockchain = require('./_blockchain') 7 | 8 | describe('bitcoinjs-lib (multisig)', function () { 9 | it('can create a 2-of-3 multisig P2SH address', function () { 10 | var pubKeys = [ 11 | '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01', 12 | '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9', 13 | '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9' 14 | ].map(function (hex) { 15 | return new Buffer(hex, 'hex') 16 | }) 17 | 18 | var redeemScript = bitcoin.script.multisigOutput(2, pubKeys) // 2 of 3 19 | var scriptPubKey = bitcoin.script.scriptHashOutput(bitcoin.crypto.hash160(redeemScript)) 20 | var address = bitcoin.address.fromOutputScript(scriptPubKey) 21 | 22 | assert.strictEqual(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7') 23 | }) 24 | 25 | it('can spend from a 2-of-4 multsig P2SH address', function (done) { 26 | this.timeout(30000) 27 | 28 | var keyPairs = [ 29 | '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx', 30 | '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT', 31 | '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe', 32 | '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7' 33 | ].map(function (wif) { return bitcoin.ECPair.fromWIF(wif, bitcoin.networks.testnet) }) 34 | var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() }) 35 | 36 | var redeemScript = bitcoin.script.multisigOutput(2, pubKeys) // 2 of 4 37 | var scriptPubKey = bitcoin.script.scriptHashOutput(bitcoin.crypto.hash160(redeemScript)) 38 | var address = bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet) 39 | 40 | // attempt to send funds to the source address 41 | blockchain.t.faucet(address, 2e4, function (err, unspent) { 42 | if (err) return done(err) 43 | 44 | var fee = 1e4 45 | var targetValue = unspent.value - fee 46 | 47 | // make a random destination address 48 | var targetAddress = bitcoin.ECPair.makeRandom({ 49 | network: bitcoin.networks.testnet 50 | }).getAddress() 51 | 52 | var txb = new bitcoin.TransactionBuilder(bitcoin.networks.testnet) 53 | txb.addInput(unspent.txId, unspent.vout) 54 | txb.addOutput(targetAddress, targetValue) 55 | 56 | // sign with 1st and 3rd key 57 | txb.sign(0, keyPairs[0], redeemScript) 58 | txb.sign(0, keyPairs[2], redeemScript) 59 | 60 | // broadcast our transaction 61 | var tx = txb.build() 62 | var txId = tx.getId() 63 | 64 | blockchain.t.transactions.propagate(tx.toHex(), function (err) { 65 | if (err) return done(err) 66 | 67 | // allow for TX to be processed 68 | async.retry(5, function (callback) { 69 | setTimeout(function () { 70 | // check that the above transaction included the intended address 71 | blockchain.t.addresses.unspents(targetAddress, function (err, unspents) { 72 | if (err) return callback(err) 73 | 74 | var unspentFound = unspents.some(function (unspent) { 75 | return unspent.txId === txId && unspent.value === targetValue 76 | }) 77 | 78 | if (!unspentFound) return callback(new Error('Could not find unspent after propagate')) 79 | callback() 80 | }) 81 | }, 600) 82 | }, done) 83 | }) 84 | }) 85 | }) 86 | }) 87 | -------------------------------------------------------------------------------- /test/message.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var message = require('../src/message') 5 | var networks = require('../src/networks') 6 | 7 | var BigInteger = require('bigi') 8 | var ECPair = require('../src/ecpair') 9 | 10 | var fixtures = require('./fixtures/message.json') 11 | 12 | describe('message', function () { 13 | describe('magicHash', function () { 14 | fixtures.valid.magicHash.forEach(function (f) { 15 | it('produces the correct magicHash for "' + f.message + '" (' + f.network + ')', function () { 16 | var network = networks[f.network] 17 | var actual = message.magicHash(f.message, network) 18 | 19 | assert.strictEqual(actual.toString('hex'), f.magicHash) 20 | }) 21 | }) 22 | }) 23 | 24 | describe('verify', function () { 25 | fixtures.valid.verify.forEach(function (f) { 26 | it('verifies a valid signature for "' + f.message + '" (' + f.network + ')', function () { 27 | var network = networks[f.network] 28 | 29 | assert(message.verify(f.address, f.signature, f.message, network)) 30 | 31 | if (f.compressed) { 32 | assert(message.verify(f.compressed.address, f.compressed.signature, f.message, network)) 33 | } 34 | }) 35 | }) 36 | 37 | fixtures.invalid.verify.forEach(function (f) { 38 | it(f.description, function () { 39 | assert(!message.verify(f.address, f.signature, f.message)) 40 | }) 41 | }) 42 | }) 43 | 44 | describe('signing', function () { 45 | fixtures.valid.signing.forEach(function (f) { 46 | it(f.description, function () { 47 | var network = networks[f.network] 48 | 49 | var keyPair = new ECPair(new BigInteger(f.d), null, { 50 | compressed: false 51 | }) 52 | var signature = message.sign(keyPair, f.message, network) 53 | assert.strictEqual(signature.toString('base64'), f.signature) 54 | 55 | if (f.compressed) { 56 | var compressedPrivKey = new ECPair(new BigInteger(f.d)) 57 | var compressedSignature = message.sign(compressedPrivKey, f.message) 58 | 59 | assert.strictEqual(compressedSignature.toString('base64'), f.compressed.signature) 60 | } 61 | }) 62 | }) 63 | }) 64 | }) 65 | -------------------------------------------------------------------------------- /test/script.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var bcrypto = require('../src/crypto') 5 | var bscript = require('../src/script') 6 | var ops = require('../src/opcodes') 7 | 8 | var fixtures = require('./fixtures/script.json') 9 | 10 | describe('script', function () { 11 | // TODO 12 | describe.skip('isCanonicalPubKey', function () {}) 13 | describe.skip('isCanonicalSignature', function () {}) 14 | 15 | describe('fromASM/toASM', function () { 16 | fixtures.valid.forEach(function (f) { 17 | if (f.scriptSig) { 18 | it('encodes/decodes ' + f.scriptSig, function () { 19 | var scriptSig = bscript.fromASM(f.scriptSig) 20 | 21 | assert.strictEqual(bscript.toASM(scriptSig), f.scriptSig) 22 | }) 23 | } 24 | 25 | if (f.scriptPubKey) { 26 | it('encodes/decodes ' + f.scriptPubKey, function () { 27 | var scriptPubKey = bscript.fromASM(f.scriptPubKey) 28 | 29 | assert.strictEqual(bscript.toASM(scriptPubKey), f.scriptPubKey) 30 | }) 31 | } 32 | }) 33 | }) 34 | 35 | describe('compile', function () { 36 | fixtures.valid.forEach(function (f) { 37 | if (f.scriptSig) { 38 | it('compiles ' + f.scriptSig, function () { 39 | var scriptSig = bscript.fromASM(f.scriptSig) 40 | 41 | assert.strictEqual(bscript.compile(scriptSig).toString('hex'), f.scriptSigHex) 42 | }) 43 | } 44 | 45 | if (f.scriptPubKey) { 46 | it('compiles ' + f.scriptPubKey, function () { 47 | var scriptPubKey = bscript.fromASM(f.scriptPubKey) 48 | 49 | assert.strictEqual(bscript.compile(scriptPubKey).toString('hex'), f.scriptPubKeyHex) 50 | }) 51 | } 52 | }) 53 | }) 54 | 55 | describe('decompile', function () { 56 | fixtures.valid.forEach(function (f) { 57 | if (f.scriptSigHex) { 58 | it('decompiles ' + f.scriptSig, function () { 59 | var chunks = bscript.decompile(new Buffer(f.scriptSigHex, 'hex')) 60 | 61 | assert.strictEqual(bscript.toASM(chunks), f.scriptSig) 62 | }) 63 | } 64 | 65 | if (f.scriptPubKeyHex) { 66 | it('decompiles ' + f.scriptPubKey, function () { 67 | var chunks = bscript.decompile(new Buffer(f.scriptPubKeyHex, 'hex')) 68 | 69 | assert.strictEqual(bscript.toASM(chunks), f.scriptPubKey) 70 | }) 71 | } 72 | }) 73 | 74 | fixtures.invalid.decompile.forEach(function (f) { 75 | it('decompiles ' + f.hex + ' to [] because of "' + f.description + '"', function () { 76 | var chunks = bscript.decompile(new Buffer(f.hex, 'hex')) 77 | 78 | assert.strictEqual(chunks.length, 0) 79 | }) 80 | }) 81 | }) 82 | 83 | describe('classifyInput', function () { 84 | fixtures.valid.forEach(function (f) { 85 | if (!f.scriptSig) return 86 | 87 | it('classifies ' + f.scriptSig + ' as ' + f.type, function () { 88 | var scriptSig = bscript.fromASM(f.scriptSig) 89 | var type = bscript.classifyInput(scriptSig) 90 | 91 | assert.strictEqual(type, f.type) 92 | }) 93 | }) 94 | 95 | fixtures.valid.forEach(function (f) { 96 | if (!f.scriptSig) return 97 | if (!f.typeIncomplete) return 98 | 99 | it('classifies incomplete ' + f.scriptSig + ' as ' + f.typeIncomplete, function () { 100 | var scriptSig = bscript.fromASM(f.scriptSig) 101 | var type = bscript.classifyInput(scriptSig, true) 102 | 103 | assert.strictEqual(type, f.typeIncomplete) 104 | }) 105 | }) 106 | }) 107 | 108 | describe('classifyOutput', function () { 109 | fixtures.valid.forEach(function (f) { 110 | if (!f.scriptPubKey) return 111 | 112 | it('classifies ' + f.scriptPubKey + ' as ' + f.type, function () { 113 | var scriptPubKey = bscript.fromASM(f.scriptPubKey) 114 | var type = bscript.classifyOutput(scriptPubKey) 115 | 116 | assert.strictEqual(type, f.type) 117 | }) 118 | }) 119 | }) 120 | 121 | ;['PubKey', 'PubKeyHash', 'ScriptHash', 'Multisig', 'NullData'].forEach(function (type) { 122 | var inputFnName = 'is' + type + 'Input' 123 | var outputFnName = 'is' + type + 'Output' 124 | 125 | var inputFn = bscript[inputFnName] 126 | var outputFn = bscript[outputFnName] 127 | 128 | describe('is' + type + 'Input', function () { 129 | fixtures.valid.forEach(function (f) { 130 | var expected = type.toLowerCase() === f.type 131 | 132 | if (inputFn && f.scriptSig) { 133 | var scriptSig = bscript.fromASM(f.scriptSig) 134 | 135 | it('returns ' + expected + ' for ' + f.scriptSig, function () { 136 | assert.strictEqual(inputFn(scriptSig), expected) 137 | }) 138 | 139 | if (f.typeIncomplete) { 140 | var expectedIncomplete = type.toLowerCase() === f.typeIncomplete 141 | 142 | it('returns ' + expected + ' for ' + f.scriptSig, function () { 143 | assert.strictEqual(inputFn(scriptSig, true), expectedIncomplete) 144 | }) 145 | } 146 | } 147 | }) 148 | 149 | if (!(inputFnName in fixtures.invalid)) return 150 | 151 | fixtures.invalid[inputFnName].forEach(function (f) { 152 | it('returns false for ' + f.description + ' (' + (f.scriptSig || f.scriptSigHex) + ')', function () { 153 | var scriptSig 154 | 155 | if (f.scriptSig) { 156 | scriptSig = bscript.fromASM(f.scriptSig) 157 | } else { 158 | scriptSig = new Buffer(f.scriptSigHex, 'hex') 159 | } 160 | 161 | assert.strictEqual(inputFn(scriptSig), false) 162 | }) 163 | }) 164 | }) 165 | 166 | describe('is' + type + 'Output', function () { 167 | fixtures.valid.forEach(function (f) { 168 | var expected = type.toLowerCase() === f.type 169 | 170 | if (outputFn && f.scriptPubKey) { 171 | it('returns ' + expected + ' for ' + f.scriptPubKey, function () { 172 | var scriptPubKey = bscript.fromASM(f.scriptPubKey) 173 | 174 | assert.strictEqual(outputFn(scriptPubKey), expected) 175 | }) 176 | } 177 | }) 178 | 179 | if (!(outputFnName in fixtures.invalid)) return 180 | 181 | fixtures.invalid[outputFnName].forEach(function (f) { 182 | it('returns false for ' + f.description + ' (' + (f.scriptPubKey || f.scriptPubKeyHex) + ')', function () { 183 | var scriptPubKey 184 | 185 | if (f.scriptPubKey) { 186 | scriptPubKey = bscript.fromASM(f.scriptPubKey) 187 | } else { 188 | scriptPubKey = new Buffer(f.scriptPubKeyHex, 'hex') 189 | } 190 | 191 | assert.strictEqual(outputFn(scriptPubKey), false) 192 | }) 193 | }) 194 | }) 195 | }) 196 | 197 | describe('pubKeyInput', function () { 198 | fixtures.valid.forEach(function (f) { 199 | if (f.type !== 'pubkey') return 200 | 201 | it('returns ' + f.scriptSig, function () { 202 | var signature = new Buffer(f.signature, 'hex') 203 | 204 | var scriptSig = bscript.pubKeyInput(signature) 205 | assert.strictEqual(bscript.toASM(scriptSig), f.scriptSig) 206 | }) 207 | }) 208 | }) 209 | 210 | describe('pubKeyOutput', function () { 211 | fixtures.valid.forEach(function (f) { 212 | if (f.type !== 'pubkey') return 213 | 214 | it('returns ' + f.scriptPubKey, function () { 215 | var pubKey = new Buffer(f.pubKey, 'hex') 216 | var scriptPubKey = bscript.pubKeyOutput(pubKey) 217 | 218 | assert.strictEqual(bscript.toASM(scriptPubKey), f.scriptPubKey) 219 | }) 220 | }) 221 | }) 222 | 223 | describe('pubKeyHashInput', function () { 224 | fixtures.valid.forEach(function (f) { 225 | if (f.type !== 'pubkeyhash') return 226 | 227 | var pubKey = new Buffer(f.pubKey, 'hex') 228 | 229 | it('returns ' + f.scriptSig, function () { 230 | var signature = new Buffer(f.signature, 'hex') 231 | 232 | var scriptSig = bscript.pubKeyHashInput(signature, pubKey) 233 | assert.strictEqual(bscript.toASM(scriptSig), f.scriptSig) 234 | }) 235 | }) 236 | }) 237 | 238 | describe('pubKeyHashOutput', function () { 239 | fixtures.valid.forEach(function (f) { 240 | if (f.type !== 'pubkeyhash') return 241 | 242 | var pubKey = new Buffer(f.pubKey, 'hex') 243 | var pubKeyHash = bcrypto.hash160(pubKey) 244 | 245 | it('returns ' + f.scriptPubKey, function () { 246 | var scriptPubKey = bscript.pubKeyHashOutput(pubKeyHash) 247 | assert.strictEqual(bscript.toASM(scriptPubKey), f.scriptPubKey) 248 | }) 249 | }) 250 | 251 | fixtures.invalid.pubKeyHashOutput.forEach(function (f) { 252 | var hash = new Buffer(f.hash, 'hex') 253 | 254 | it('throws on ' + f.exception, function () { 255 | assert.throws(function () { 256 | bscript.pubKeyHashOutput(hash) 257 | }, new RegExp(f.exception)) 258 | }) 259 | }) 260 | }) 261 | 262 | describe('multisigInput', function () { 263 | fixtures.valid.forEach(function (f) { 264 | if (f.type !== 'multisig') return 265 | 266 | it('returns ' + f.scriptSig, function () { 267 | var signatures = f.signatures.map(function (signature) { 268 | return signature ? new Buffer(signature, 'hex') : ops.OP_0 269 | }) 270 | 271 | var scriptSig = bscript.multisigInput(signatures) 272 | assert.strictEqual(bscript.toASM(scriptSig), f.scriptSig) 273 | }) 274 | }) 275 | 276 | fixtures.invalid.multisigInput.forEach(function (f) { 277 | var scriptPubKey = bscript.fromASM(f.scriptPubKey) 278 | 279 | it('throws on ' + f.exception, function () { 280 | var signatures = f.signatures.map(function (signature) { 281 | return signature ? new Buffer(signature, 'hex') : ops.OP_0 282 | }) 283 | 284 | assert.throws(function () { 285 | bscript.multisigInput(signatures, scriptPubKey) 286 | }, new RegExp(f.exception)) 287 | }) 288 | }) 289 | }) 290 | 291 | describe('multisigOutput', function () { 292 | fixtures.valid.forEach(function (f) { 293 | if (f.type !== 'multisig') return 294 | 295 | var pubKeys = f.pubKeys.map(function (p) { return new Buffer(p, 'hex') }) 296 | var scriptPubKey = bscript.multisigOutput(pubKeys.length, pubKeys) 297 | 298 | it('returns ' + f.scriptPubKey, function () { 299 | assert.strictEqual(bscript.toASM(scriptPubKey), f.scriptPubKey) 300 | }) 301 | }) 302 | 303 | fixtures.invalid.multisigOutput.forEach(function (f) { 304 | var pubKeys = f.pubKeys.map(function (p) { 305 | return new Buffer(p, 'hex') 306 | }) 307 | 308 | it('throws on ' + f.exception, function () { 309 | assert.throws(function () { 310 | bscript.multisigOutput(f.m, pubKeys) 311 | }, new RegExp(f.exception)) 312 | }) 313 | }) 314 | }) 315 | 316 | describe('scriptHashInput', function () { 317 | fixtures.valid.forEach(function (f) { 318 | if (f.type !== 'scripthash') return 319 | 320 | var redeemScript = bscript.fromASM(f.redeemScript) 321 | var redeemScriptSig = bscript.fromASM(f.redeemScriptSig) 322 | 323 | it('returns ' + f.scriptSig, function () { 324 | var scriptSig = bscript.scriptHashInput(redeemScriptSig, redeemScript) 325 | 326 | if (f.scriptSig) { 327 | assert.strictEqual(bscript.toASM(scriptSig), f.scriptSig) 328 | } else { 329 | assert.strictEqual(scriptSig.toString('hex'), f.scriptSigHex) 330 | } 331 | }) 332 | }) 333 | }) 334 | 335 | describe('scriptHashOutput', function () { 336 | fixtures.valid.forEach(function (f) { 337 | if (f.type !== 'scripthash') return 338 | if (!f.scriptPubKey) return 339 | 340 | it('returns ' + f.scriptPubKey, function () { 341 | var redeemScript = bscript.fromASM(f.redeemScript) 342 | var scriptPubKey = bscript.scriptHashOutput(bcrypto.hash160(redeemScript)) 343 | 344 | assert.strictEqual(bscript.toASM(scriptPubKey), f.scriptPubKey) 345 | }) 346 | }) 347 | 348 | fixtures.invalid.scriptHashOutput.forEach(function (f) { 349 | var hash = new Buffer(f.hash, 'hex') 350 | 351 | it('throws on ' + f.exception, function () { 352 | assert.throws(function () { 353 | bscript.scriptHashOutput(hash) 354 | }, new RegExp(f.exception)) 355 | }) 356 | }) 357 | }) 358 | 359 | describe('nullDataOutput', function () { 360 | fixtures.valid.forEach(function (f) { 361 | if (f.type !== 'nulldata') return 362 | 363 | var data = new Buffer(f.data, 'hex') 364 | var scriptPubKey = bscript.nullDataOutput(data) 365 | 366 | it('returns ' + f.scriptPubKey, function () { 367 | assert.strictEqual(bscript.toASM(scriptPubKey), f.scriptPubKey) 368 | }) 369 | }) 370 | }) 371 | }) 372 | -------------------------------------------------------------------------------- /test/script_number.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var scriptNumber = require('../src/script_number') 5 | var fixtures = require('./fixtures/script_number.json') 6 | 7 | describe('script', function () { 8 | describe('decode', function () { 9 | fixtures.forEach(function (f) { 10 | it(f.hex + ' returns ' + f.number, function () { 11 | var actual = scriptNumber.decode(new Buffer(f.hex, 'hex'), f.bytes) 12 | 13 | assert.strictEqual(actual, f.number) 14 | }) 15 | }) 16 | }) 17 | 18 | describe('encode', function () { 19 | fixtures.forEach(function (f) { 20 | it(f.number + ' returns ' + f.hex, function () { 21 | var actual = scriptNumber.encode(f.number) 22 | 23 | assert.strictEqual(actual.toString('hex'), f.hex) 24 | }) 25 | }) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /test/transaction.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, beforeEach */ 2 | 3 | var assert = require('assert') 4 | var bscript = require('../src/script') 5 | 6 | var Transaction = require('../src/transaction') 7 | 8 | var fixtures = require('./fixtures/transaction') 9 | 10 | describe('Transaction', function () { 11 | function fromRaw (raw) { 12 | var tx = new Transaction() 13 | tx.version = raw.version 14 | tx.locktime = raw.locktime 15 | 16 | raw.ins.forEach(function (txIn) { 17 | var txHash = new Buffer(txIn.hash, 'hex') 18 | var scriptSig 19 | 20 | if (txIn.data) { 21 | scriptSig = new Buffer(txIn.data, 'hex') 22 | } else if (txIn.script) { 23 | scriptSig = bscript.fromASM(txIn.script) 24 | } 25 | 26 | tx.addInput(txHash, txIn.index, txIn.sequence, scriptSig) 27 | }) 28 | 29 | raw.outs.forEach(function (txOut) { 30 | var script 31 | 32 | if (txOut.data) { 33 | script = new Buffer(txOut.data, 'hex') 34 | } else if (txOut.script) { 35 | script = bscript.fromASM(txOut.script) 36 | } 37 | 38 | tx.addOutput(script, txOut.value) 39 | }) 40 | 41 | return tx 42 | } 43 | 44 | describe('fromBuffer/fromHex', function () { 45 | fixtures.valid.forEach(function (f) { 46 | it('imports ' + f.description + ' (' + f.id + ')', function () { 47 | var actual = Transaction.fromHex(f.hex) 48 | 49 | assert.strictEqual(actual.toHex(), f.hex, actual.toHex()) 50 | }) 51 | }) 52 | 53 | fixtures.invalid.fromBuffer.forEach(function (f) { 54 | it('throws on ' + f.exception, function () { 55 | assert.throws(function () { 56 | Transaction.fromHex(f.hex) 57 | }, new RegExp(f.exception)) 58 | }) 59 | }) 60 | }) 61 | 62 | describe('toBuffer/toHex', function () { 63 | fixtures.valid.forEach(function (f) { 64 | it('exports ' + f.description + ' (' + f.id + ')', function () { 65 | var actual = fromRaw(f.raw) 66 | 67 | assert.strictEqual(actual.toHex(), f.hex, actual.toHex()) 68 | }) 69 | }) 70 | }) 71 | 72 | describe('addInput', function () { 73 | var prevTxHash 74 | beforeEach(function () { 75 | var f = fixtures.valid[0] 76 | prevTxHash = new Buffer(f.hash, 'hex') 77 | }) 78 | 79 | it('accepts a transaction hash', function () { 80 | var tx = new Transaction() 81 | tx.addInput(prevTxHash, 0) 82 | 83 | assert.deepEqual(tx.ins[0].hash, prevTxHash) 84 | }) 85 | 86 | it('returns an index', function () { 87 | var tx = new Transaction() 88 | assert.strictEqual(tx.addInput(prevTxHash, 0), 0) 89 | assert.strictEqual(tx.addInput(prevTxHash, 0), 1) 90 | }) 91 | 92 | it('defaults to DEFAULT_SEQUENCE', function () { 93 | var tx = new Transaction() 94 | tx.addInput(prevTxHash, 0) 95 | 96 | assert.strictEqual(tx.ins[0].sequence, Transaction.DEFAULT_SEQUENCE) 97 | }) 98 | 99 | it('defaults to empty script', function () { 100 | var tx = new Transaction() 101 | tx.addInput(prevTxHash, 0) 102 | 103 | assert.strictEqual(tx.ins[0].script.length, 0) 104 | }) 105 | 106 | fixtures.invalid.addInput.forEach(function (f) { 107 | it('throws on ' + f.exception, function () { 108 | var tx = new Transaction() 109 | var hash = new Buffer(f.hash, 'hex') 110 | 111 | assert.throws(function () { 112 | tx.addInput(hash, f.index) 113 | }, new RegExp(f.exception)) 114 | }) 115 | }) 116 | }) 117 | 118 | describe('addOutput', function () { 119 | it('returns an index', function () { 120 | var tx = new Transaction() 121 | assert.strictEqual(tx.addOutput(new Buffer(0), 0), 0) 122 | assert.strictEqual(tx.addOutput(new Buffer(0), 0), 1) 123 | }) 124 | }) 125 | 126 | describe('clone', function () { 127 | fixtures.valid.forEach(function (f) { 128 | var actual, expected 129 | 130 | beforeEach(function () { 131 | expected = Transaction.fromHex(f.hex) 132 | actual = expected.clone() 133 | }) 134 | 135 | it('should have value equality', function () { 136 | assert.deepEqual(actual, expected) 137 | }) 138 | 139 | it('should not have reference equality', function () { 140 | assert.notEqual(actual, expected) 141 | }) 142 | }) 143 | }) 144 | 145 | describe('getId', function () { 146 | fixtures.valid.forEach(function (f) { 147 | it('should return the id for ' + f.id, function () { 148 | var tx = Transaction.fromHex(f.hex) 149 | 150 | assert.strictEqual(tx.getId(), f.id) 151 | }) 152 | }) 153 | }) 154 | 155 | describe('getHash', function () { 156 | fixtures.valid.forEach(function (f) { 157 | it('should return the hash for ' + f.id, function () { 158 | var tx = Transaction.fromHex(f.hex) 159 | 160 | assert.strictEqual(tx.getHash().toString('hex'), f.hash) 161 | }) 162 | }) 163 | }) 164 | 165 | // TODO: 166 | // hashForSignature: [Function], 167 | }) 168 | -------------------------------------------------------------------------------- /test/types.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | var assert = require('assert') 4 | var types = require('../src/types') 5 | var typeforce = require('typeforce') 6 | 7 | describe('types', function () { 8 | describe('BigInt/ECPoint', function () { 9 | it('return true for duck types', function () { 10 | assert(types.BigInt(new function BigInteger () {})) 11 | assert(types.ECPoint(new function Point () {})) 12 | }) 13 | 14 | it('return false for bad types', function () { 15 | assert(!types.BigInt(new function NotABigInteger () {})) 16 | assert(!types.ECPoint(new function NotAPoint () {})) 17 | }) 18 | }) 19 | 20 | describe('Buffer Hash160/Hash256', function () { 21 | var buffer20byte = new Buffer((new Array(20 + 1)).join('00'), 'hex') 22 | var buffer32byte = new Buffer((new Array(32 + 1)).join('00'), 'hex') 23 | 24 | it('return true for valid size', function () { 25 | assert(types.Hash160bit(buffer20byte)) 26 | assert(types.Hash256bit(buffer32byte)) 27 | }) 28 | 29 | it('return true for oneOf', function () { 30 | assert(typeforce(types.oneOf(types.Hash160bit, types.Hash256bit), buffer32byte)) 31 | assert(typeforce(types.oneOf(types.Hash256bit, types.Hash160bit), buffer32byte)) 32 | }) 33 | 34 | it('throws for invalid size', function () { 35 | assert.throws(function () { 36 | types.Hash160bit(buffer32byte) 37 | }, /Expected 160-bit Buffer, got 256-bit Buffer/) 38 | 39 | assert.throws(function () { 40 | types.Hash256bit(buffer20byte) 41 | }, /Expected 256-bit Buffer, got 160-bit Buffer/) 42 | }) 43 | }) 44 | }) 45 | --------------------------------------------------------------------------------