Socket
Socket
Sign inDemoInstall

bitcoinjs-lib

Package Overview
Dependencies
Maintainers
3
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitcoinjs-lib - npm Package Compare versions

Comparing version 0.1.3 to 0.2.0

.travis.yml

44

package.json
{
"name": "bitcoinjs-lib",
"version": "0.1.3",
"version": "0.2.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"keywords": [

@@ -12,14 +12,36 @@ "bitcoin",

],
"author": "Stefan Thomas <justmoon@members.fsf.org> (http://www.justmoon.net)",
"repository" : {
"type" : "git",
"url" : "https://github.com/bitcoinjs/bitcoinjs-lib.git"
"repository": {
"type": "git",
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
},
"devDependencies" : {
"pkginfo" : ">=0.2.1",
"jake-uglify" : ">=1.0.0"
"devDependencies": {
"mocha": "1.18.2",
"istanbul": "0.1.30",
"uglify-js": "2.4.13",
"node-browserify": "https://github.com/substack/node-browserify/tarball/master",
"sinon": "1.9.0"
},
"testling": {
"browsers": [
"chrome/20..latest",
"firefox/21..latest",
"safari/latest",
"opera/15..latest",
"iphone/6..latest",
"ipad/6..latest",
"android-browser/4.2..latest"
],
"harness": "mocha-bdd",
"files": "test/*.js"
},
"scripts": {
"test": "./node_modules/.bin/istanbul test ./node_modules/.bin/_mocha -- --reporter list test/*.js",
"coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --reporter list test/*.js",
"compile": "./node_modules/.bin/browserify ./src/index.js -s Bitcoin | ./node_modules/.bin/uglifyjs > bitcoinjs-min.js"
},
"dependencies": {
"crypto-js": "3.1.2-3",
"secure-random": "0.2.1"
}
}
# bitcoinjs-lib
A library containing Bitcoin client-side functionality in JavaScript,
most notably ECDSA signing and verification.
[![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib)
# Status
[![Browser Support](https://ci.testling.com/bitcoinjs/bitcoinjs-lib.png)](https://ci.testling.com/bitcoinjs/bitcoinjs-lib)
This is currently pretty raw code. We're planning to clean it up,
convert everything into CommonJS modules and put a flexible build
system in place.
A pure JavaScript Bitcoin library for node.js and browsers. Backed by (slowly improving) testing, proven by over a million wallet users. The backbone for almost all Bitcoin web wallets in production today.
Prototype software, use at your own peril.
**Warning**: Master is not stable. Expect the interface to change rapidly, including some of the examples below. This is not the original bitcoinjs-lib that was not updated for a while. The current bitcoinjs-lib has been refactored to clean things up, add new functionality and merge improvements from the community. If you are looking for the original, it will be tagged as `0.1.3`. We will use `0.2.x` for releases based on these changes, so be sure to use the `0.1.3` tag if you need the original version.
# License
## Features
This library is free and open-source software released under the MIT
license.
- Bitcoin Testnet and Mainnet (production) support
- [HD Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
- Highly secure random private key / address generation using [window.crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Window.crypto)
- ECDSA signing and verification
- Transaction creation (pay-to-pubkey-hash), support for multisignature transactions
- A (somewhat incomplete) wallet implementation, improvements ongoing
# Copyright
## Installation
BitcoinJS (c) 2011-2012 Stefan Thomas
Released under MIT license
`npm install bitcoinjs-lib`
Note: The npm version is currently out of date, are working to resolve this. The best way to use the latest code is to clone the repository.
## Setup
### Node.js
var bitcoin = require('bitcoinjs-lib')
From the repo:
var bitcoin = require('./src/index.js')
### Browser
Compile `bitcoinjs-min.js` with the following command:
$ npm run-script compile
After loading this file in your browser, you will be able to use the global `Bitcoin` object.
## Usage
These examples assume you are running bitcoinjs-lib in the browser.
### Generating a Bitcoin address
```javascript
key = new Bitcoin.ECKey()
// Print your private key (a hex string)
console.log(key.toString())
// => 8c112cf628362ecf4d482f68af2dbb50c8a2cb90d226215de925417aa9336a48
// Print your public key (defaults to a Bitcoin address)
console.log(key.getPub().getAddress())
// => 14bZ7YWde4KdRb5YN7GYkToz3EHVCvRxkF
```
### Creating a Transaction
```javascript
tx = new Bitcoin.Transaction()
// Add the input (who is paying) of the form [previous transaction hash, index of the output to use]
tx.addInput("aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31", 0)
// Add the output (who to pay to) of the form [payee's address, amount in satoshis]
tx.addOutput("1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK", 15000)
// Initialize a private key using hex
key = new Bitcoin.ECKey("8c112cf628362ecf4d482f68af2dbb50c8a2cb90d226215de925417aa9336a48")
// Sign the first input with the new key
tx.sign(0, key)
// Print transaction serialized as hex
console.log(tx.serializeHex())
// => 0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000008a47304402200169f1f844936dc60df54e812345f5dd3e6681fea52e33c25154ad9cc23a330402204381ed8e73d74a95b15f312f33d5a0072c7a12dd6c3294df6e8efbe4aff27426014104e75628573696aed32d7656fb35e9c71ea08eb6492837e13d2662b9a36821d0fff992692fd14d74fdec20fae29128ba12653249cbeef521fc5eba84dde0689f27ffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000
// You could now push the transaction onto the Bitcoin network manually (see https://blockchain.info/pushtx)
```
## Projects utilizing bitcoinjs-lib
- [Blockchain.info Wallet](http://blockchain.info/wallet)
- [Bitaddress.org](https://www.bitaddress.org)
- [Coinpunk](https://coinpunk.com)
- [DarkWallet](https://darkwallet.unsystem.net)
- [GreenAddress](https://greenaddress.it)
Feel free to send pull requests to have your project/startup listed here.
## Contributing
### Instructions
1. Fork the repo
2. Push changes to your fork
3. Create a pull request
### Running the test suite
$ npm test
## Alternatives
- [Bitcore](https://github.com/bitpay/bitcore)
- [Cryptocoin](https://github.com/cryptocoinjs/cryptocoin)
## License
This library is free and open-source software released under the MIT license.
## Copyright
BitcoinJS (c) 2011-2012 Stefan Thomas
Released under MIT license
http://bitcoinjs.org/
JSBN (c) 2003-2005 Tom Wu
Released under BSD license
JSBN (c) 2003-2005 Tom Wu
Released under BSD license
http://www-cs-students.stanford.edu/~tjw/jsbn/
CryptoJS (c) 2009–2012 by Jeff Mott
Released under New BSD license
CryptoJS (c) 2009–2012 by Jeff Mott
Released under New BSD license
http://code.google.com/p/crypto-js/

@@ -1,57 +0,65 @@

Bitcoin.Address = function (bytes) {
if ("string" == typeof bytes) {
bytes = Bitcoin.Address.decodeString(bytes);
var base58 = require('./base58')
var base58check = require('./base58check')
var convert = require('./convert')
var error = require('./util').error
var mainnet = require('./network').mainnet.addressVersion
function Address(bytes, version) {
if (!(this instanceof Address)) {
return new Address(bytes, version)
}
this.hash = bytes;
this.version = 0x00;
};
if (bytes instanceof Address) {
this.hash = bytes.hash
this.version = bytes.version
}
else if (typeof bytes === 'string') {
if (bytes.length <= 35) {
var decode = base58check.decode(bytes)
this.hash = decode.payload
this.version = decode.version
}
else if (bytes.length <= 40) {
this.hash = convert.hexToBytes(bytes)
this.version = version || mainnet
}
else {
error('invalid or unrecognized input')
}
}
else {
this.hash = bytes
this.version = version || mainnet
}
}
/**
* Serialize this object as a standard Bitcoin address.
*
* Returns the address as a base58-encoded string in the standardized format.
*/
Bitcoin.Address.prototype.toString = function () {
// Get a copy of the hash
var hash = this.hash.slice(0);
Address.prototype.toString = function () {
return base58check.encode(this.hash.slice(0), this.version)
}
// Version
hash.unshift(this.version);
/**
* Returns the version of an address, e.g. if the address belongs to the main
* net or the test net.
*/
Address.getVersion = function (address) {
return base58.decode(address)[0]
}
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
var bytes = hash.concat(checksum.slice(0,4));
return Bitcoin.Base58.encode(bytes);
};
Bitcoin.Address.prototype.getHashBase64 = function () {
return Crypto.util.bytesToBase64(this.hash);
};
/**
* Parse a Bitcoin address contained in a string.
* Returns true if a bitcoin address is a valid address, otherwise false.
*/
Bitcoin.Address.decodeString = function (string) {
var bytes = Bitcoin.Base58.decode(string);
var hash = bytes.slice(0, 21);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
if (checksum[0] != bytes[21] ||
checksum[1] != bytes[22] ||
checksum[2] != bytes[23] ||
checksum[3] != bytes[24]) {
throw "Checksum validation failed!";
Address.validate = function (address) {
try {
base58check.decode(address)
return true
} catch (e) {
return false
}
}
var version = hash.shift();
if (version != 0) {
throw "Version "+version+" not supported!";
}
return hash;
};
module.exports = Address

@@ -1,71 +0,82 @@

(function (Bitcoin) {
Bitcoin.Base58 = {
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
validRegex: /^[1-9A-HJ-NP-Za-km-z]+$/,
base: BigInteger.valueOf(58),
// Base58 encoding/decoding
// Originally written by Mike Hearn for BitcoinJ
// Copyright (c) 2011 Google Inc
// Ported to JavaScript by Stefan Thomas
/**
* Convert a byte array to a base58-encoded string.
*
* Written by Mike Hearn for BitcoinJ.
* Copyright (c) 2011 Google Inc.
*
* Ported to JavaScript by Stefan Thomas.
*/
encode: function (input) {
var bi = BigInteger.fromByteArrayUnsigned(input);
var chars = [];
var BigInteger = require('./jsbn/jsbn')
while (bi.compareTo(B58.base) >= 0) {
var mod = bi.mod(B58.base);
chars.unshift(B58.alphabet[mod.intValue()]);
bi = bi.subtract(mod).divide(B58.base);
}
chars.unshift(B58.alphabet[bi.intValue()]);
// FIXME: ? This is a Base58Check alphabet
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
var base = BigInteger.valueOf(58)
// Convert leading zeros too.
for (var i = 0; i < input.length; i++) {
if (input[i] == 0x00) {
chars.unshift(B58.alphabet[0]);
} else break;
}
var alphabetMap = {}
for (var i=0; i<alphabet.length; ++i) {
var chr = alphabet[i]
alphabetMap[chr] = BigInteger.valueOf(i)
}
return chars.join('');
},
// encode a byte array into a base58 encoded String
// @return String
function encode(buffer) {
var bi = BigInteger.fromByteArrayUnsigned(buffer)
var chars = []
/**
* Convert a base58-encoded string to a byte array.
*
* Written by Mike Hearn for BitcoinJ.
* Copyright (c) 2011 Google Inc.
*
* Ported to JavaScript by Stefan Thomas.
*/
decode: function (input) {
var bi = BigInteger.valueOf(0);
var leadingZerosNum = 0;
for (var i = input.length - 1; i >= 0; i--) {
var alphaIndex = B58.alphabet.indexOf(input[i]);
if (alphaIndex < 0) {
throw "Invalid character";
}
bi = bi.add(BigInteger.valueOf(alphaIndex)
.multiply(B58.base.pow(input.length - 1 -i)));
while (bi.compareTo(base) >= 0) {
var mod = bi.mod(base)
bi = bi.subtract(mod).divide(base)
// This counts leading zero bytes
if (input[i] == "1") leadingZerosNum++;
else leadingZerosNum = 0;
}
var bytes = bi.toByteArrayUnsigned();
chars.push(alphabet[mod.intValue()])
}
// Add leading zeros
while (leadingZerosNum-- > 0) bytes.unshift(0);
chars.push(alphabet[bi.intValue()])
return bytes;
// Convert leading zeros too.
for (var i=0; i<buffer.length; i++) {
if (buffer[i] !== 0x00) break
chars.push(alphabet[0])
}
return chars.reverse().join('')
}
// decode a base58 encoded String into a byte array
// @return Array
function decode(str) {
var num = BigInteger.valueOf(0)
var leading_zero = 0
var seen_other = false
for (var i=0; i<str.length; ++i) {
var chr = str[i]
var bi = alphabetMap[chr]
// if we encounter an invalid character, decoding fails
if (bi === undefined) {
throw new Error('invalid base58 string: ' + str)
}
};
var B58 = Bitcoin.Base58;
})(
'undefined' != typeof Bitcoin ? Bitcoin : module.exports
);
num = num.multiply(base).add(bi)
if (chr === '1' && !seen_other) {
++leading_zero
} else {
seen_other = true
}
}
var bytes = num.toByteArrayUnsigned()
// remove leading zeros
while (leading_zero-- > 0) {
bytes.unshift(0)
}
return new Buffer(bytes)
}
module.exports = {
encode: encode,
decode: decode
}

@@ -1,475 +0,299 @@

function integerToBytes(i, len) {
var bytes = i.toByteArrayUnsigned();
var sec = require('./jsbn/sec')
var rng = require('secure-random')
var BigInteger = require('./jsbn/jsbn')
var convert = require('./convert')
var HmacSHA256 = require('crypto-js/hmac-sha256')
var ECPointFp = require('./jsbn/ec').ECPointFp
var ecparams = sec("secp256k1")
var P_OVER_FOUR = null
if (len < bytes.length) {
bytes = bytes.slice(bytes.length-len);
} else while (len > bytes.length) {
bytes.unshift(0);
}
function implShamirsTrick(P, k, Q, l) {
var m = Math.max(k.bitLength(), l.bitLength())
var Z = P.add2D(Q)
var R = P.curve.getInfinity()
return bytes;
};
for (var i = m - 1; i >= 0; --i) {
R = R.twice2D()
ECFieldElementFp.prototype.getByteLength = function () {
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
};
R.z = BigInteger.ONE
ECPointFp.prototype.getEncoded = function (compressed) {
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
// Get value as a 32-byte Buffer
// Fixed length based on a patch by bitaddress.org and Casascius
var enc = integerToBytes(x, 32);
if (compressed) {
if (y.isEven()) {
// Compressed even pubkey
// M = 02 || X
enc.unshift(0x02);
if (k.testBit(i)) {
if (l.testBit(i)) {
R = R.add2D(Z)
} else {
R = R.add2D(P)
}
} else {
// Compressed uneven pubkey
// M = 03 || X
enc.unshift(0x03);
if (l.testBit(i)) {
R = R.add2D(Q)
}
}
} else {
// Uncompressed pubkey
// M = 04 || X || Y
enc.unshift(0x04);
enc = enc.concat(integerToBytes(y, 32));
}
return enc;
};
ECPointFp.decodeFrom = function (curve, enc) {
var type = enc[0];
var dataLen = enc.length-1;
return R
}
// Extract x and y as byte arrays
var xBa = enc.slice(1, 1 + dataLen/2);
var yBa = enc.slice(1 + dataLen/2, 1 + dataLen);
function deterministicGenerateK(hash,key) {
var vArr = []
var kArr = []
for (var i = 0;i < 32;i++) vArr.push(1)
for (var i = 0;i < 32;i++) kArr.push(0)
var v = convert.bytesToWordArray(vArr)
var k = convert.bytesToWordArray(kArr)
// Prepend zero byte to prevent interpretation as negative integer
xBa.unshift(0);
yBa.unshift(0);
k = HmacSHA256(convert.bytesToWordArray(vArr.concat([0]).concat(key).concat(hash)), k)
v = HmacSHA256(v, k)
vArr = convert.wordArrayToBytes(v)
k = HmacSHA256(convert.bytesToWordArray(vArr.concat([1]).concat(key).concat(hash)), k)
v = HmacSHA256(v,k)
v = HmacSHA256(v,k)
vArr = convert.wordArrayToBytes(v)
return BigInteger.fromByteArrayUnsigned(vArr)
}
// Convert to BigIntegers
var x = new BigInteger(xBa);
var y = new BigInteger(yBa);
var ECDSA = {
getBigRandom: function (limit) {
return new BigInteger(limit.bitLength(), rng).
mod(limit.subtract(BigInteger.ONE)).
add(BigInteger.ONE)
},
sign: function (hash, priv) {
var d = priv
var n = ecparams.getN()
var e = BigInteger.fromByteArrayUnsigned(hash)
// Return point
return new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
};
var k = deterministicGenerateK(hash,priv.toByteArrayUnsigned())
var G = ecparams.getG()
var Q = G.multiply(k)
var r = Q.getX().toBigInteger().mod(n)
ECPointFp.prototype.add2D = function (b) {
if(this.isInfinity()) return b;
if(b.isInfinity()) return this;
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
if (this.x.equals(b.x)) {
if (this.y.equals(b.y)) {
// this = b, i.e. this must be doubled
return this.twice();
return ECDSA.serializeSig(r, s)
},
verify: function (hash, sig, pubkey) {
var r,s
if (Array.isArray(sig)) {
var obj = ECDSA.parseSig(sig)
r = obj.r
s = obj.s
} else if ("object" === typeof sig && sig.r && sig.s) {
r = sig.r
s = sig.s
} else {
throw new Error("Invalid value for signature")
}
// this = -b, i.e. the result is the point at infinity
return this.curve.getInfinity();
}
var x_x = b.x.subtract(this.x);
var y_y = b.y.subtract(this.y);
var gamma = y_y.divide(x_x);
var Q
if (pubkey instanceof ECPointFp) {
Q = pubkey
} else if (Array.isArray(pubkey)) {
Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey)
} else {
throw new Error("Invalid format for pubkey value, must be byte array or ECPointFp")
}
var e = BigInteger.fromByteArrayUnsigned(hash)
var x3 = gamma.square().subtract(this.x).subtract(b.x);
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
return ECDSA.verifyRaw(e, r, s, Q)
},
return new ECPointFp(this.curve, x3, y3);
};
verifyRaw: function (e, r, s, Q) {
var n = ecparams.getN()
var G = ecparams.getG()
ECPointFp.prototype.twice2D = function () {
if (this.isInfinity()) return this;
if (this.y.toBigInteger().signum() == 0) {
// if y1 == 0, then (x1, y1) == (x1, -y1)
// and hence this = -this and thus 2(x1, y1) == infinity
return this.curve.getInfinity();
}
if (r.compareTo(BigInteger.ONE) < 0 || r.compareTo(n) >= 0) {
return false
}
var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
var x3 = gamma.square().subtract(this.x.multiply(TWO));
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
return new ECPointFp(this.curve, x3, y3);
};
ECPointFp.prototype.multiply2D = function (k) {
if(this.isInfinity()) return this;
if(k.signum() == 0) return this.curve.getInfinity();
var e = k;
var h = e.multiply(new BigInteger("3"));
var neg = this.negate();
var R = this;
var i;
for (i = h.bitLength() - 2; i > 0; --i) {
R = R.twice();
var hBit = h.testBit(i);
var eBit = e.testBit(i);
if (hBit != eBit) {
R = R.add2D(hBit ? this : neg);
if (s.compareTo(BigInteger.ONE) < 0 || s.compareTo(n) >= 0) {
return false
}
}
return R;
};
var c = s.modInverse(n)
ECPointFp.prototype.isOnCurve = function () {
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
var a = this.curve.getA().toBigInteger();
var b = this.curve.getB().toBigInteger();
var n = this.curve.getQ();
var lhs = y.multiply(y).mod(n);
var rhs = x.multiply(x).multiply(x)
.add(a.multiply(x)).add(b).mod(n);
return lhs.equals(rhs);
};
var u1 = e.multiply(c).mod(n)
var u2 = r.multiply(c).mod(n)
ECPointFp.prototype.toString = function () {
return '('+this.getX().toBigInteger().toString()+','+
this.getY().toBigInteger().toString()+')';
};
// TODO(!!!): For some reason Shamir's trick isn't working with
// signed message verification!? Probably an implementation
// error!
//var point = implShamirsTrick(G, u1, Q, u2)
var point = G.multiply(u1).add(Q.multiply(u2))
/**
* Validate an elliptic curve point.
*
* See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
*/
ECPointFp.prototype.validate = function () {
var n = this.curve.getQ();
var v = point.getX().toBigInteger().mod(n)
// Check Q != O
if (this.isInfinity()) {
throw new Error("Point is at infinity.");
}
return v.equals(r)
},
// Check coordinate bounds
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
if (x.compareTo(BigInteger.ONE) < 0 ||
x.compareTo(n.subtract(BigInteger.ONE)) > 0) {
throw new Error('x coordinate out of bounds');
}
if (y.compareTo(BigInteger.ONE) < 0 ||
y.compareTo(n.subtract(BigInteger.ONE)) > 0) {
throw new Error('y coordinate out of bounds');
}
/**
* Serialize a signature into DER format.
*
* Takes two BigIntegers representing r and s and returns a byte array.
*/
serializeSig: function (r, s) {
var rBa = r.toByteArraySigned()
var sBa = s.toByteArraySigned()
// Check y^2 = x^3 + ax + b (mod n)
if (!this.isOnCurve()) {
throw new Error("Point is not on the curve.");
}
var sequence = []
sequence.push(0x02); // INTEGER
sequence.push(rBa.length)
sequence = sequence.concat(rBa)
// Check nQ = 0 (Q is a scalar multiple of G)
if (this.multiply(n).isInfinity()) {
// TODO: This check doesn't work - fix.
throw new Error("Point is not a scalar multiple of G.");
}
sequence.push(0x02); // INTEGER
sequence.push(sBa.length)
sequence = sequence.concat(sBa)
return true;
};
sequence.unshift(sequence.length)
sequence.unshift(0x30); // SEQUENCE
function dmp(v) {
if (!(v instanceof BigInteger)) v = v.toBigInteger();
return Crypto.util.bytesToHex(v.toByteArrayUnsigned());
};
return sequence
},
Bitcoin.ECDSA = (function () {
var ecparams = getSECCurveByName("secp256k1");
var rng = new SecureRandom();
/**
* Parses a byte array containing a DER-encoded signature.
*
* This function will return an object of the form:
*
* {
* r: BigInteger,
* s: BigInteger
* }
*/
parseSig: function (sig) {
var cursor
if (sig[0] != 0x30) {
throw new Error("Signature not a valid DERSequence")
}
var P_OVER_FOUR = null;
cursor = 2
if (sig[cursor] != 0x02) {
throw new Error("First element in signature must be a DERInteger")
}
var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1])
function implShamirsTrick(P, k, Q, l)
{
var m = Math.max(k.bitLength(), l.bitLength());
var Z = P.add2D(Q);
var R = P.curve.getInfinity();
for (var i = m - 1; i >= 0; --i) {
R = R.twice2D();
R.z = BigInteger.ONE;
if (k.testBit(i)) {
if (l.testBit(i)) {
R = R.add2D(Z);
} else {
R = R.add2D(P);
}
} else {
if (l.testBit(i)) {
R = R.add2D(Q);
}
}
cursor += 2+sig[cursor+1]
if (sig[cursor] != 0x02) {
throw new Error("Second element in signature must be a DERInteger")
}
var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1])
return R;
};
cursor += 2+sig[cursor+1]
var ECDSA = {
getBigRandom: function (limit) {
return new BigInteger(limit.bitLength(), rng)
.mod(limit.subtract(BigInteger.ONE))
.add(BigInteger.ONE)
;
},
sign: function (hash, priv) {
var d = priv;
var n = ecparams.getN();
var e = BigInteger.fromByteArrayUnsigned(hash);
//if (cursor != sig.length)
// throw new Error("Extra bytes in signature")
do {
var k = ECDSA.getBigRandom(n);
var G = ecparams.getG();
var Q = G.multiply(k);
var r = Q.getX().toBigInteger().mod(n);
} while (r.compareTo(BigInteger.ZERO) <= 0);
var r = BigInteger.fromByteArrayUnsigned(rBa)
var s = BigInteger.fromByteArrayUnsigned(sBa)
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
return {r: r, s: s}
},
return ECDSA.serializeSig(r, s);
},
parseSigCompact: function (sig) {
if (sig.length !== 65) {
throw new Error("Signature has the wrong length")
}
verify: function (hash, sig, pubkey) {
var r,s;
if (Bitcoin.Util.isArray(sig)) {
var obj = ECDSA.parseSig(sig);
r = obj.r;
s = obj.s;
} else if ("object" === typeof sig && sig.r && sig.s) {
r = sig.r;
s = sig.s;
} else {
throw "Invalid value for signature";
}
// Signature is prefixed with a type byte storing three bits of
// information.
var i = sig[0] - 27
if (i < 0 || i > 7) {
throw new Error("Invalid signature type")
}
var Q;
if (pubkey instanceof ECPointFp) {
Q = pubkey;
} else if (Bitcoin.Util.isArray(pubkey)) {
Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey);
} else {
throw "Invalid format for pubkey value, must be byte array or ECPointFp";
}
var e = BigInteger.fromByteArrayUnsigned(hash);
var n = ecparams.getN()
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n)
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n)
return ECDSA.verifyRaw(e, r, s, Q);
},
return {r: r, s: s, i: i}
},
verifyRaw: function (e, r, s, Q) {
var n = ecparams.getN();
var G = ecparams.getG();
/**
* Recover a public key from a signature.
*
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
* Key Recovery Operation".
*
* http://www.secg.org/download/aid-780/sec1-v2.pdf
*/
recoverPubKey: function (r, s, hash, i) {
// The recovery parameter i has two bits.
i = i & 3
if (r.compareTo(BigInteger.ONE) < 0 ||
r.compareTo(n) >= 0)
return false;
// The less significant bit specifies whether the y coordinate
// of the compressed point is even or not.
var isYEven = i & 1
if (s.compareTo(BigInteger.ONE) < 0 ||
s.compareTo(n) >= 0)
return false;
// The more significant bit specifies whether we should use the
// first or second candidate key.
var isSecondKey = i >> 1
var c = s.modInverse(n);
var n = ecparams.getN()
var G = ecparams.getG()
var curve = ecparams.getCurve()
var p = curve.getQ()
var a = curve.getA().toBigInteger()
var b = curve.getB().toBigInteger()
var u1 = e.multiply(c).mod(n);
var u2 = r.multiply(c).mod(n);
// We precalculate (p + 1) / 4 where p is if the field order
if (!P_OVER_FOUR) {
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4))
}
// TODO(!!!): For some reason Shamir's trick isn't working with
// signed message verification!? Probably an implementation
// error!
//var point = implShamirsTrick(G, u1, Q, u2);
var point = G.multiply(u1).add(Q.multiply(u2));
// 1.1 Compute x
var x = isSecondKey ? r.add(n) : r
var v = point.getX().toBigInteger().mod(n);
// 1.3 Convert x to point
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p)
var beta = alpha.modPow(P_OVER_FOUR, p)
return v.equals(r);
},
// var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2)
// If beta is even, but y isn't or vice versa, then convert it,
// otherwise we're done and y == beta.
var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta)
/**
* Serialize a signature into DER format.
*
* Takes two BigIntegers representing r and s and returns a byte array.
*/
serializeSig: function (r, s) {
var rBa = r.toByteArraySigned();
var sBa = s.toByteArraySigned();
// 1.4 Check that nR is at infinity
var R = new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y))
R.validate()
var sequence = [];
sequence.push(0x02); // INTEGER
sequence.push(rBa.length);
sequence = sequence.concat(rBa);
// 1.5 Compute e from M
var e = BigInteger.fromByteArrayUnsigned(hash)
var eNeg = BigInteger.ZERO.subtract(e).mod(n)
sequence.push(0x02); // INTEGER
sequence.push(sBa.length);
sequence = sequence.concat(sBa);
// 1.6 Compute Q = r^-1 (sR - eG)
var rInv = r.modInverse(n)
var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv)
sequence.unshift(sequence.length);
sequence.unshift(0x30); // SEQUENCE
Q.validate()
if (!ECDSA.verifyRaw(e, r, s, Q)) {
throw new Error("Pubkey recovery unsuccessful")
}
return sequence;
},
return Q
},
/**
* Parses a byte array containing a DER-encoded signature.
*
* This function will return an object of the form:
*
* {
* r: BigInteger,
* s: BigInteger
* }
*/
parseSig: function (sig) {
var cursor;
if (sig[0] != 0x30)
throw new Error("Signature not a valid DERSequence");
/**
* Calculate pubkey extraction parameter.
*
* When extracting a pubkey from a signature, we have to
* distinguish four different cases. Rather than putting this
* burden on the verifier, Bitcoin includes a 2-bit value with the
* signature.
*
* This function simply tries all four cases and returns the value
* that resulted in a successful pubkey recovery.
*/
calcPubKeyRecoveryParam: function (origPubKey, r, s, hash) {
for (var i = 0; i < 4; i++) {
var pubKey = ECDSA.recoverPubKey(r, s, hash, i)
cursor = 2;
if (sig[cursor] != 0x02)
throw new Error("First element in signature must be a DERInteger");;
var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
cursor += 2+sig[cursor+1];
if (sig[cursor] != 0x02)
throw new Error("Second element in signature must be a DERInteger");
var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
cursor += 2+sig[cursor+1];
//if (cursor != sig.length)
// throw new Error("Extra bytes in signature");
var r = BigInteger.fromByteArrayUnsigned(rBa);
var s = BigInteger.fromByteArrayUnsigned(sBa);
return {r: r, s: s};
},
parseSigCompact: function (sig) {
if (sig.length !== 65) {
throw "Signature has the wrong length";
if (pubKey.equals(origPubKey)) {
return i
}
}
// Signature is prefixed with a type byte storing three bits of
// information.
var i = sig[0] - 27;
if (i < 0 || i > 7) {
throw "Invalid signature type";
}
throw new Error("Unable to find valid recovery factor")
}
}
var n = ecparams.getN();
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
return {r: r, s: s, i: i};
},
/**
* Recover a public key from a signature.
*
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
* Key Recovery Operation".
*
* http://www.secg.org/download/aid-780/sec1-v2.pdf
*/
recoverPubKey: function (r, s, hash, i) {
// The recovery parameter i has two bits.
i = i & 3;
// The less significant bit specifies whether the y coordinate
// of the compressed point is even or not.
var isYEven = i & 1;
// The more significant bit specifies whether we should use the
// first or second candidate key.
var isSecondKey = i >> 1;
var n = ecparams.getN();
var G = ecparams.getG();
var curve = ecparams.getCurve();
var p = curve.getQ();
var a = curve.getA().toBigInteger();
var b = curve.getB().toBigInteger();
// We precalculate (p + 1) / 4 where p is if the field order
if (!P_OVER_FOUR) {
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
}
// 1.1 Compute x
var x = isSecondKey ? r.add(n) : r;
// 1.3 Convert x to point
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
var beta = alpha.modPow(P_OVER_FOUR, p);
var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2);
// If beta is even, but y isn't or vice versa, then convert it,
// otherwise we're done and y == beta.
var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
// 1.4 Check that nR is at infinity
var R = new ECPointFp(curve,
curve.fromBigInteger(x),
curve.fromBigInteger(y));
R.validate();
// 1.5 Compute e from M
var e = BigInteger.fromByteArrayUnsigned(hash);
var eNeg = BigInteger.ZERO.subtract(e).mod(n);
// 1.6 Compute Q = r^-1 (sR - eG)
var rInv = r.modInverse(n);
var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
Q.validate();
if (!ECDSA.verifyRaw(e, r, s, Q)) {
throw "Pubkey recovery unsuccessful";
}
var pubKey = new Bitcoin.ECKey();
pubKey.pub = Q;
return pubKey;
},
/**
* Calculate pubkey extraction parameter.
*
* When extracting a pubkey from a signature, we have to
* distinguish four different cases. Rather than putting this
* burden on the verifier, Bitcoin includes a 2-bit value with the
* signature.
*
* This function simply tries all four cases and returns the value
* that resulted in a successful pubkey recovery.
*/
calcPubkeyRecoveryParam: function (address, r, s, hash)
{
for (var i = 0; i < 4; i++) {
try {
var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
if (pubkey.getBitcoinAddress().toString() == address) {
return i;
}
} catch (e) {}
}
throw "Unable to find valid recovery factor";
}
};
return ECDSA;
})();
module.exports = ECDSA

@@ -1,131 +0,188 @@

Bitcoin.ECKey = (function () {
var ECDSA = Bitcoin.ECDSA;
var ecparams = getSECCurveByName("secp256k1");
var rng = new SecureRandom();
var Address = require('./address')
var assert = require('assert')
var convert = require('./convert')
var base58check = require('./base58check')
var BigInteger = require('./jsbn/jsbn')
var ecdsa = require('./ecdsa')
var ECPointFp = require('./jsbn/ec').ECPointFp
var sec = require('./jsbn/sec')
var Network = require('./network')
var util = require('./util')
var ecparams = sec("secp256k1")
var ECKey = function (input) {
if (!input) {
// Generate new key
var n = ecparams.getN();
this.priv = ECDSA.getBigRandom(n);
} else if (input instanceof BigInteger) {
// Input is a private key value
this.priv = input;
} else if (Bitcoin.Util.isArray(input)) {
// Prepend zero byte to prevent interpretation as negative integer
this.priv = BigInteger.fromByteArrayUnsigned(input);
} else if ("string" == typeof input) {
if (input.length == 51 && input[0] == '5') {
// Base58 encoded private key
this.priv = BigInteger.fromByteArrayUnsigned(ECKey.decodeString(input));
} else {
// Prepend zero byte to prevent interpretation as negative integer
this.priv = BigInteger.fromByteArrayUnsigned(Crypto.util.base64ToBytes(input));
}
}
this.compressed = !!ECKey.compressByDefault;
};
// input can be nothing, array of bytes, hex string, or base58 string
var ECKey = function (input, compressed) {
if (!(this instanceof ECKey)) { return new ECKey(input, compressed) }
if (!input) {
// Generate new key
var n = ecparams.getN()
this.priv = ecdsa.getBigRandom(n)
this.compressed = compressed || false
}
else this.import(input,compressed)
}
/**
* Whether public keys should be returned compressed by default.
*/
ECKey.compressByDefault = false;
ECKey.prototype.import = function (input, compressed) {
function has(li, v) { return li.indexOf(v) >= 0 }
function fromBin(x) { return BigInteger.fromByteArrayUnsigned(x) }
/**
* Set whether the public key should be returned compressed or not.
*/
ECKey.prototype.setCompressed = function (v) {
this.compressed = !!v;
};
this.priv =
input instanceof ECKey ? input.priv
: input instanceof BigInteger ? input.mod(ecparams.getN())
: Array.isArray(input) ? fromBin(input.slice(0, 32))
: typeof input != "string" ? null
: input.length == 44 ? fromBin(convert.base64ToBytes(input))
: input.length == 51 && input[0] == '5' ? fromBin(base58check.decode(input).payload)
: input.length == 51 && input[0] == '9' ? fromBin(base58check.decode(input).payload)
: input.length == 52 && has('LK', input[0]) ? fromBin(base58check.decode(input).payload.slice(0, 32))
: input.length == 52 && input[0] == 'c' ? fromBin(base58check.decode(input).payload.slice(0, 32))
: has([64,65],input.length) ? fromBin(convert.hexToBytes(input.slice(0, 64)))
: null
/**
* Return public key in DER encoding.
*/
ECKey.prototype.getPub = function () {
return this.getPubPoint().getEncoded(this.compressed);
};
assert(this.priv !== null)
/**
* Return public point as ECPoint object.
*/
ECKey.prototype.getPubPoint = function () {
if (!this.pub) this.pub = ecparams.getG().multiply(this.priv);
this.compressed =
compressed !== undefined ? compressed
: input instanceof ECKey ? input.compressed
: input instanceof BigInteger ? false
: Array.isArray(input) ? false
: typeof input != "string" ? null
: input.length == 44 ? false
: input.length == 51 && input[0] == '5' ? false
: input.length == 51 && input[0] == '9' ? false
: input.length == 52 && has('LK', input[0]) ? true
: input.length == 52 && input[0] == 'c' ? true
: input.length == 64 ? false
: input.length == 65 ? true
: null
return this.pub;
};
assert(this.compressed !== null)
}
/**
* Get the pubKeyHash for this key.
*
* This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as
* a byte array.
*/
ECKey.prototype.getPubKeyHash = function () {
if (this.pubKeyHash) return this.pubKeyHash;
ECKey.prototype.getPub = function(compressed) {
if (compressed === undefined) compressed = this.compressed
return ECPubKey(ecparams.getG().multiply(this.priv), compressed)
}
return this.pubKeyHash = Bitcoin.Util.sha256ripe160(this.getPub());
};
ECKey.prototype.toBin = function() {
return convert.bytesToString(this.toBytes())
}
ECKey.prototype.getBitcoinAddress = function () {
var hash = this.getPubKeyHash();
var addr = new Bitcoin.Address(hash);
return addr;
};
ECKey.version_bytes = {
0: 128,
111: 239
}
ECKey.prototype.getExportedPrivateKey = function () {
var hash = this.priv.toByteArrayUnsigned();
while (hash.length < 32) hash.unshift(0);
hash.unshift(0x80);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
var bytes = hash.concat(checksum.slice(0,4));
return Bitcoin.Base58.encode(bytes);
};
ECKey.prototype.toWif = function(version) {
version = version || Network.mainnet.addressVersion
ECKey.prototype.setPub = function (pub) {
this.pub = ECPointFp.decodeFrom(ecparams.getCurve(), pub);
};
return base58check.encode(this.toBytes(), ECKey.version_bytes[version])
}
ECKey.prototype.toString = function (format) {
if (format === "base64") {
return Crypto.util.bytesToBase64(this.priv.toByteArrayUnsigned());
} else {
return Crypto.util.bytesToHex(this.priv.toByteArrayUnsigned());
}
};
ECKey.prototype.toHex = function() {
return convert.bytesToHex(this.toBytes())
}
ECKey.prototype.sign = function (hash) {
return ECDSA.sign(hash, this.priv);
};
ECKey.prototype.toBytes = function() {
var bytes = this.priv.toByteArrayUnsigned()
if (this.compressed) bytes.push(1)
return bytes
}
ECKey.prototype.verify = function (hash, sig) {
return ECDSA.verify(hash, sig, this.getPub());
};
ECKey.prototype.toBase64 = function() {
return convert.bytesToBase64(this.toBytes())
}
/**
* Parse an exported private key contained in a string.
*/
ECKey.decodeString = function (string) {
var bytes = Bitcoin.Base58.decode(string);
ECKey.prototype.toString = ECKey.prototype.toHex
var hash = bytes.slice(0, 33);
ECKey.prototype.getAddress = function(version) {
return this.getPub().getAddress(version)
}
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
ECKey.prototype.add = function(key) {
return ECKey(this.priv.add(ECKey(key).priv), this.compressed)
}
if (checksum[0] != bytes[33] ||
checksum[1] != bytes[34] ||
checksum[2] != bytes[35] ||
checksum[3] != bytes[36]) {
throw "Checksum validation failed!";
}
ECKey.prototype.multiply = function(key) {
return ECKey(this.priv.multiply(ECKey(key).priv), this.compressed)
}
var version = hash.shift();
ECKey.prototype.sign = function(hash) {
return ecdsa.sign(hash, this.priv)
}
if (version != 0x80) {
throw "Version "+version+" not supported!";
}
ECKey.prototype.verify = function(hash, sig) {
return this.getPub().verify(hash, sig)
}
return hash;
};
var ECPubKey = function(input, compressed) {
if (!(this instanceof ECPubKey)) {
return new ECPubKey(input, compressed)
}
return ECKey;
})();
this.import(input, compressed)
}
ECPubKey.prototype.import = function(input, compressed) {
var decode = function(x) { return ECPointFp.decodeFrom(ecparams.getCurve(), x) }
this.pub =
input instanceof ECPointFp ? input
: input instanceof ECKey ? ecparams.getG().multiply(input.priv)
: input instanceof ECPubKey ? input.pub
: typeof input == "string" ? decode(convert.hexToBytes(input))
: Array.isArray(input) ? decode(input)
: null
assert(this.pub !== null)
this.compressed =
compressed ? compressed
: input instanceof ECPointFp ? input.compressed
: input instanceof ECPubKey ? input.compressed
: (this.pub[0] < 4)
}
ECPubKey.prototype.add = function(key) {
return ECPubKey(this.pub.add(ECPubKey(key).pub), this.compressed)
}
ECPubKey.prototype.multiply = function(key) {
return ECPubKey(this.pub.multiply(ECKey(key).priv), this.compressed)
}
ECPubKey.prototype.toBytes = function(compressed) {
if (compressed === undefined) compressed = this.compressed
return this.pub.getEncoded(compressed)
}
ECPubKey.prototype.toHex = function(compressed) {
return convert.bytesToHex(this.toBytes(compressed))
}
ECPubKey.prototype.toBin = function(compressed) {
return convert.bytesToString(this.toBytes(compressed))
}
ECPubKey.prototype.toWif = function(version) {
version = version || Network.mainnet.addressVersion
return base58check.encode(this.toBytes(), version)
}
ECPubKey.prototype.toString = ECPubKey.prototype.toHex
ECPubKey.prototype.getAddress = function(version) {
version = version || Network.mainnet.addressVersion
return new Address(util.sha256ripe160(this.toBytes()), version)
}
ECPubKey.prototype.verify = function(hash, sig) {
return ecdsa.verify(hash, sig, this.toBytes())
}
module.exports = {
ECKey: ECKey,
ECPubKey: ECPubKey
}

@@ -5,3 +5,4 @@ // Basic Javascript Elliptic Curve implementation

// Requires jsbn.js and jsbn2.js
var BigInteger = require('./jsbn'),
sec = require('./sec');

@@ -318,1 +319,206 @@ // ----------------

ECCurveFp.prototype.decodePointHex = curveFpDecodePointHex;
// prepends 0 if bytes < len
// cuts off start if bytes > len
function integerToBytes(i, len) {
var bytes = i.toByteArrayUnsigned();
if (len < bytes.length) {
bytes = bytes.slice(bytes.length-len);
} else while (len > bytes.length) {
bytes.unshift(0);
}
return bytes;
};
ECFieldElementFp.prototype.getByteLength = function () {
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
};
ECPointFp.prototype.getEncoded = function (compressed) {
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
// Get value as a 32-byte Buffer
// Fixed length based on a patch by bitaddress.org and Casascius
var enc = integerToBytes(x, 32);
if (compressed) {
if (y.isEven()) {
// Compressed even pubkey
// M = 02 || X
enc.unshift(0x02);
} else {
// Compressed uneven pubkey
// M = 03 || X
enc.unshift(0x03);
}
} else {
// Uncompressed pubkey
// M = 04 || X || Y
enc.unshift(0x04);
enc = enc.concat(integerToBytes(y, 32));
}
return enc;
};
ECPointFp.decodeFrom = function (ecparams, enc) {
var type = enc[0];
var dataLen = enc.length-1;
// Extract x and y as byte arrays
if (type == 4) {
var xBa = enc.slice(1, 1 + dataLen/2),
yBa = enc.slice(1 + dataLen/2, 1 + dataLen),
x = BigInteger.fromByteArrayUnsigned(xBa),
y = BigInteger.fromByteArrayUnsigned(yBa);
}
else {
var xBa = enc.slice(1),
x = BigInteger.fromByteArrayUnsigned(xBa),
p = ecparams.getQ(),
xCubedPlus7 = x.multiply(x).multiply(x).add(new BigInteger('7')).mod(p),
pPlus1Over4 = p.add(new BigInteger('1'))
.divide(new BigInteger('4')),
y = xCubedPlus7.modPow(pPlus1Over4,p);
if (y.mod(new BigInteger('2')).toString() != ''+(type % 2)) {
y = p.subtract(y)
}
}
// Prepend zero byte to prevent interpretation as negative integer
// Convert to BigIntegers
// Return point
return new ECPointFp(ecparams,
ecparams.fromBigInteger(x),
ecparams.fromBigInteger(y));
};
ECPointFp.prototype.add2D = function (b) {
if(this.isInfinity()) return b;
if(b.isInfinity()) return this;
if (this.x.equals(b.x)) {
if (this.y.equals(b.y)) {
// this = b, i.e. this must be doubled
return this.twice();
}
// this = -b, i.e. the result is the point at infinity
return this.curve.getInfinity();
}
var x_x = b.x.subtract(this.x);
var y_y = b.y.subtract(this.y);
var gamma = y_y.divide(x_x);
var x3 = gamma.square().subtract(this.x).subtract(b.x);
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
return new ECPointFp(this.curve, x3, y3);
};
ECPointFp.prototype.twice2D = function () {
if (this.isInfinity()) return this;
if (this.y.toBigInteger().signum() == 0) {
// if y1 == 0, then (x1, y1) == (x1, -y1)
// and hence this = -this and thus 2(x1, y1) == infinity
return this.curve.getInfinity();
}
var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
var x3 = gamma.square().subtract(this.x.multiply(TWO));
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
return new ECPointFp(this.curve, x3, y3);
};
ECPointFp.prototype.multiply2D = function (k) {
if(this.isInfinity()) return this;
if(k.signum() == 0) return this.curve.getInfinity();
var e = k;
var h = e.multiply(new BigInteger("3"));
var neg = this.negate();
var R = this;
var i;
for (i = h.bitLength() - 2; i > 0; --i) {
R = R.twice();
var hBit = h.testBit(i);
var eBit = e.testBit(i);
if (hBit != eBit) {
R = R.add2D(hBit ? this : neg);
}
}
return R;
};
ECPointFp.prototype.isOnCurve = function () {
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
var a = this.curve.getA().toBigInteger();
var b = this.curve.getB().toBigInteger();
var n = this.curve.getQ();
var lhs = y.multiply(y).mod(n);
var rhs = x.multiply(x).multiply(x)
.add(a.multiply(x)).add(b).mod(n);
return lhs.equals(rhs);
};
ECPointFp.prototype.toString = function () {
return '('+this.getX().toBigInteger().toString()+','+
this.getY().toBigInteger().toString()+')';
};
/**
* Validate an elliptic curve point.
*
* See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
*/
ECPointFp.prototype.validate = function () {
var n = this.curve.getQ();
// Check Q != O
if (this.isInfinity()) {
throw new Error("Point is at infinity.");
}
// Check coordinate bounds
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
if (x.compareTo(BigInteger.ONE) < 0 ||
x.compareTo(n.subtract(BigInteger.ONE)) > 0) {
throw new Error('x coordinate out of bounds');
}
if (y.compareTo(BigInteger.ONE) < 0 ||
y.compareTo(n.subtract(BigInteger.ONE)) > 0) {
throw new Error('y coordinate out of bounds');
}
// Check y^2 = x^3 + ax + b (mod n)
if (!this.isOnCurve()) {
throw new Error("Point is not on the curve.");
}
// Check nQ = 0 (Q is a scalar multiple of G)
if (this.multiply(n).isInfinity()) {
// TODO: This check doesn't work - fix.
throw new Error("Point is not a scalar multiple of G.");
}
return true;
};
module.exports = ECCurveFp;
module.exports.ECPointFp = ECPointFp;

@@ -16,8 +16,15 @@ // Copyright (c) 2005 Tom Wu

function BigInteger(a,b,c) {
if(a != null)
if (!(this instanceof BigInteger)) {
return new BigInteger(a, b, c);
}
if(a != null) {
if("number" == typeof a) this.fromNumber(a,b,c);
else if(b == null && "string" != typeof a) this.fromString(a,256);
else this.fromString(a,b);
}
}
var proto = BigInteger.prototype;
// return new, unset BigInteger

@@ -71,2 +78,8 @@ function nbi() { return new BigInteger(null); }

}
// wtf?
BigInteger.prototype.am = am1;
dbits = 26;
/*
if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {

@@ -84,6 +97,7 @@ BigInteger.prototype.am = am2;

}
*/
BigInteger.prototype.DB = dbits;
BigInteger.prototype.DM = ((1<<dbits)-1);
BigInteger.prototype.DV = (1<<dbits);
var DV = BigInteger.prototype.DV = (1<<dbits);

@@ -133,2 +147,4 @@ var BI_FP = 52;

function bnpFromString(s,b) {
var self = this;
var k;

@@ -141,5 +157,5 @@ if(b == 16) k = 4;

else if(b == 4) k = 2;
else { this.fromRadix(s,b); return; }
this.t = 0;
this.s = 0;
else { self.fromRadix(s,b); return; }
self.t = 0;
self.s = 0;
var i = s.length, mi = false, sh = 0;

@@ -154,18 +170,18 @@ while(--i >= 0) {

if(sh == 0)
this[this.t++] = x;
else if(sh+k > this.DB) {
this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
this[this.t++] = (x>>(this.DB-sh));
self[self.t++] = x;
else if(sh+k > self.DB) {
self[self.t-1] |= (x&((1<<(self.DB-sh))-1))<<sh;
self[self.t++] = (x>>(self.DB-sh));
}
else
this[this.t-1] |= x<<sh;
self[self.t-1] |= x<<sh;
sh += k;
if(sh >= this.DB) sh -= this.DB;
if(sh >= self.DB) sh -= self.DB;
}
if(k == 8 && (s[0]&0x80) != 0) {
this.s = -1;
if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
self.s = -1;
if(sh > 0) self[self.t-1] |= ((1<<(self.DB-sh))-1)<<sh;
}
this.clamp();
if(mi) BigInteger.ZERO.subTo(this,this);
self.clamp();
if(mi) BigInteger.ZERO.subTo(self,self);
}

@@ -181,3 +197,4 @@

function bnToString(b) {
if(this.s < 0) return "-"+this.negate().toString(b);
var self = this;
if(self.s < 0) return "-"+self.negate().toString(b);
var k;

@@ -189,15 +206,15 @@ if(b == 16) k = 4;

else if(b == 4) k = 2;
else return this.toRadix(b);
var km = (1<<k)-1, d, m = false, r = "", i = this.t;
var p = this.DB-(i*this.DB)%k;
else return self.toRadix(b);
var km = (1<<k)-1, d, m = false, r = "", i = self.t;
var p = self.DB-(i*self.DB)%k;
if(i-- > 0) {
if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
if(p < self.DB && (d = self[i]>>p) > 0) { m = true; r = int2char(d); }
while(i >= 0) {
if(p < k) {
d = (this[i]&((1<<p)-1))<<(k-p);
d |= this[--i]>>(p+=this.DB-k);
d = (self[i]&((1<<p)-1))<<(k-p);
d |= self[--i]>>(p+=self.DB-k);
}
else {
d = (this[i]>>(p-=k))&km;
if(p <= 0) { p += this.DB; --i; }
d = (self[i]>>(p-=k))&km;
if(p <= 0) { p += self.DB; --i; }
}

@@ -263,14 +280,15 @@ if(d > 0) m = true;

function bnpLShiftTo(n,r) {
var bs = n%this.DB;
var cbs = this.DB-bs;
var self = this;
var bs = n%self.DB;
var cbs = self.DB-bs;
var bm = (1<<cbs)-1;
var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
for(i = this.t-1; i >= 0; --i) {
r[i+ds+1] = (this[i]>>cbs)|c;
c = (this[i]&bm)<<bs;
var ds = Math.floor(n/self.DB), c = (self.s<<bs)&self.DM, i;
for(i = self.t-1; i >= 0; --i) {
r[i+ds+1] = (self[i]>>cbs)|c;
c = (self[i]&bm)<<bs;
}
for(i = ds-1; i >= 0; --i) r[i] = 0;
r[ds] = c;
r.t = this.t+ds+1;
r.s = this.s;
r.t = self.t+ds+1;
r.s = self.s;
r.clamp();

@@ -281,15 +299,16 @@ }

function bnpRShiftTo(n,r) {
r.s = this.s;
var ds = Math.floor(n/this.DB);
if(ds >= this.t) { r.t = 0; return; }
var bs = n%this.DB;
var cbs = this.DB-bs;
var self = this;
r.s = self.s;
var ds = Math.floor(n/self.DB);
if(ds >= self.t) { r.t = 0; return; }
var bs = n%self.DB;
var cbs = self.DB-bs;
var bm = (1<<bs)-1;
r[0] = this[ds]>>bs;
for(var i = ds+1; i < this.t; ++i) {
r[i-ds-1] |= (this[i]&bm)<<cbs;
r[i-ds] = this[i]>>bs;
r[0] = self[ds]>>bs;
for(var i = ds+1; i < self.t; ++i) {
r[i-ds-1] |= (self[i]&bm)<<cbs;
r[i-ds] = self[i]>>bs;
}
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
r.t = this.t-ds;
if(bs > 0) r[self.t-ds-1] |= (self.s&bm)<<cbs;
r.t = self.t-ds;
r.clamp();

@@ -300,23 +319,24 @@ }

function bnpSubTo(a,r) {
var i = 0, c = 0, m = Math.min(a.t,this.t);
var self = this;
var i = 0, c = 0, m = Math.min(a.t,self.t);
while(i < m) {
c += this[i]-a[i];
r[i++] = c&this.DM;
c >>= this.DB;
c += self[i]-a[i];
r[i++] = c&self.DM;
c >>= self.DB;
}
if(a.t < this.t) {
if(a.t < self.t) {
c -= a.s;
while(i < this.t) {
c += this[i];
r[i++] = c&this.DM;
c >>= this.DB;
while(i < self.t) {
c += self[i];
r[i++] = c&self.DM;
c >>= self.DB;
}
c += this.s;
c += self.s;
}
else {
c += this.s;
c += self.s;
while(i < a.t) {
c -= a[i];
r[i++] = c&this.DM;
c >>= this.DB;
r[i++] = c&self.DM;
c >>= self.DB;
}

@@ -326,3 +346,3 @@ c -= a.s;

r.s = (c<0)?-1:0;
if(c < -1) r[i++] = this.DV+c;
if(c < -1) r[i++] = self.DV+c;
else if(c > 0) r[i++] = c;

@@ -366,13 +386,14 @@ r.t = i;

function bnpDivRemTo(m,q,r) {
var self = this;
var pm = m.abs();
if(pm.t <= 0) return;
var pt = this.abs();
var pt = self.abs();
if(pt.t < pm.t) {
if(q != null) q.fromInt(0);
if(r != null) this.copyTo(r);
if(r != null) self.copyTo(r);
return;
}
if(r == null) r = nbi();
var y = nbi(), ts = this.s, ms = m.s;
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
var y = nbi(), ts = self.s, ms = m.s;
var nsh = self.DB-nbits(pm[pm.t-1]); // normalize modulus
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }

@@ -383,4 +404,4 @@ else { pm.copyTo(y); pt.copyTo(r); }

if(y0 == 0) return;
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
var yt = y0*(1<<self.F1)+((ys>1)?y[ys-2]>>self.F2:0);
var d1 = self.FV/yt, d2 = (1<<self.F1)/yt, e = 1<<self.F2;
var i = r.t, j = i-ys, t = (q==null)?nbi():q;

@@ -397,3 +418,3 @@ y.dlShiftTo(j,t);

// Estimate quotient digit
var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
var qd = (r[--i]==y0)?self.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out

@@ -547,29 +568,753 @@ y.dlShiftTo(j,t);

// protected
BigInteger.prototype.copyTo = bnpCopyTo;
BigInteger.prototype.fromInt = bnpFromInt;
BigInteger.prototype.fromString = bnpFromString;
BigInteger.prototype.clamp = bnpClamp;
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
BigInteger.prototype.lShiftTo = bnpLShiftTo;
BigInteger.prototype.rShiftTo = bnpRShiftTo;
BigInteger.prototype.subTo = bnpSubTo;
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
BigInteger.prototype.squareTo = bnpSquareTo;
BigInteger.prototype.divRemTo = bnpDivRemTo;
BigInteger.prototype.invDigit = bnpInvDigit;
BigInteger.prototype.isEven = bnpIsEven;
BigInteger.prototype.exp = bnpExp;
proto.copyTo = bnpCopyTo;
proto.fromInt = bnpFromInt;
proto.fromString = bnpFromString;
proto.clamp = bnpClamp;
proto.dlShiftTo = bnpDLShiftTo;
proto.drShiftTo = bnpDRShiftTo;
proto.lShiftTo = bnpLShiftTo;
proto.rShiftTo = bnpRShiftTo;
proto.subTo = bnpSubTo;
proto.multiplyTo = bnpMultiplyTo;
proto.squareTo = bnpSquareTo;
proto.divRemTo = bnpDivRemTo;
proto.invDigit = bnpInvDigit;
proto.isEven = bnpIsEven;
proto.exp = bnpExp;
// public
BigInteger.prototype.toString = bnToString;
BigInteger.prototype.negate = bnNegate;
BigInteger.prototype.abs = bnAbs;
BigInteger.prototype.compareTo = bnCompareTo;
BigInteger.prototype.bitLength = bnBitLength;
BigInteger.prototype.mod = bnMod;
BigInteger.prototype.modPowInt = bnModPowInt;
proto.toString = bnToString;
proto.negate = bnNegate;
proto.abs = bnAbs;
proto.compareTo = bnCompareTo;
proto.bitLength = bnBitLength;
proto.mod = bnMod;
proto.modPowInt = bnModPowInt;
//// jsbn2
function nbi() { return new BigInteger(null); }
// (public)
function bnClone() { var r = nbi(); this.copyTo(r); return r; }
// (public) return value as integer
function bnIntValue() {
if(this.s < 0) {
if(this.t == 1) return this[0]-this.DV;
else if(this.t == 0) return -1;
}
else if(this.t == 1) return this[0];
else if(this.t == 0) return 0;
// assumes 16 < DB < 32
return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
}
// (public) return value as byte
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
// (public) return value as short (assumes DB>=16)
function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
// (protected) return x s.t. r^x < DV
function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
// (public) 0 if this == 0, 1 if this > 0
function bnSigNum() {
if(this.s < 0) return -1;
else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
else return 1;
}
// (protected) convert to radix string
function bnpToRadix(b) {
if(b == null) b = 10;
if(this.signum() == 0 || b < 2 || b > 36) return "0";
var cs = this.chunkSize(b);
var a = Math.pow(b,cs);
var d = nbv(a), y = nbi(), z = nbi(), r = "";
this.divRemTo(d,y,z);
while(y.signum() > 0) {
r = (a+z.intValue()).toString(b).substr(1) + r;
y.divRemTo(d,y,z);
}
return z.intValue().toString(b) + r;
}
// (protected) convert from radix string
function bnpFromRadix(s,b) {
var self = this;
self.fromInt(0);
if(b == null) b = 10;
var cs = self.chunkSize(b);
var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
for(var i = 0; i < s.length; ++i) {
var x = intAt(s,i);
if(x < 0) {
if(s.charAt(i) == "-" && self.signum() == 0) mi = true;
continue;
}
w = b*w+x;
if(++j >= cs) {
self.dMultiply(d);
self.dAddOffset(w,0);
j = 0;
w = 0;
}
}
if(j > 0) {
self.dMultiply(Math.pow(b,j));
self.dAddOffset(w,0);
}
if(mi) BigInteger.ZERO.subTo(self,self);
}
// (protected) alternate constructor
function bnpFromNumber(a,b,c) {
var self = this;
if("number" == typeof b) {
// new BigInteger(int,int,RNG)
if(a < 2) self.fromInt(1);
else {
self.fromNumber(a,c);
if(!self.testBit(a-1)) // force MSB set
self.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,self);
if(self.isEven()) self.dAddOffset(1,0); // force odd
while(!self.isProbablePrime(b)) {
self.dAddOffset(2,0);
if(self.bitLength() > a) self.subTo(BigInteger.ONE.shiftLeft(a-1),self);
}
}
}
else {
// new BigInteger(int,RNG)
var t = a&7;
var length = (a>>3)+1;
var x = b(length, {array: true});
if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
self.fromString(x,256);
}
}
// (public) convert to bigendian byte array
function bnToByteArray() {
var self = this;
var i = self.t, r = new Array();
r[0] = self.s;
var p = self.DB-(i*self.DB)%8, d, k = 0;
if(i-- > 0) {
if(p < self.DB && (d = self[i]>>p) != (self.s&self.DM)>>p)
r[k++] = d|(self.s<<(self.DB-p));
while(i >= 0) {
if(p < 8) {
d = (self[i]&((1<<p)-1))<<(8-p);
d |= self[--i]>>(p+=self.DB-8);
}
else {
d = (self[i]>>(p-=8))&0xff;
if(p <= 0) { p += self.DB; --i; }
}
if((d&0x80) != 0) d |= -256;
if(k === 0 && (self.s&0x80) != (d&0x80)) ++k;
if(k > 0 || d != self.s) r[k++] = d;
}
}
return r;
}
function bnEquals(a) { return(this.compareTo(a)==0); }
function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
// (protected) r = this op a (bitwise)
function bnpBitwiseTo(a,op,r) {
var self = this;
var i, f, m = Math.min(a.t,self.t);
for(i = 0; i < m; ++i) r[i] = op(self[i],a[i]);
if(a.t < self.t) {
f = a.s&self.DM;
for(i = m; i < self.t; ++i) r[i] = op(self[i],f);
r.t = self.t;
}
else {
f = self.s&self.DM;
for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
r.t = a.t;
}
r.s = op(self.s,a.s);
r.clamp();
}
// (public) this & a
function op_and(x,y) { return x&y; }
function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
// (public) this | a
function op_or(x,y) { return x|y; }
function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
// (public) this ^ a
function op_xor(x,y) { return x^y; }
function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
// (public) this & ~a
function op_andnot(x,y) { return x&~y; }
function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
// (public) ~this
function bnNot() {
var r = nbi();
for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
r.t = this.t;
r.s = ~this.s;
return r;
}
// (public) this << n
function bnShiftLeft(n) {
var r = nbi();
if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
return r;
}
// (public) this >> n
function bnShiftRight(n) {
var r = nbi();
if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
return r;
}
// return index of lowest 1-bit in x, x < 2^31
function lbit(x) {
if(x == 0) return -1;
var r = 0;
if((x&0xffff) == 0) { x >>= 16; r += 16; }
if((x&0xff) == 0) { x >>= 8; r += 8; }
if((x&0xf) == 0) { x >>= 4; r += 4; }
if((x&3) == 0) { x >>= 2; r += 2; }
if((x&1) == 0) ++r;
return r;
}
// (public) returns index of lowest 1-bit (or -1 if none)
function bnGetLowestSetBit() {
for(var i = 0; i < this.t; ++i)
if(this[i] != 0) return i*this.DB+lbit(this[i]);
if(this.s < 0) return this.t*this.DB;
return -1;
}
// return number of 1 bits in x
function cbit(x) {
var r = 0;
while(x != 0) { x &= x-1; ++r; }
return r;
}
// (public) return number of set bits
function bnBitCount() {
var r = 0, x = this.s&this.DM;
for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
return r;
}
// (public) true iff nth bit is set
function bnTestBit(n) {
var j = Math.floor(n/this.DB);
if(j >= this.t) return(this.s!=0);
return((this[j]&(1<<(n%this.DB)))!=0);
}
// (protected) this op (1<<n)
function bnpChangeBit(n,op) {
var r = BigInteger.ONE.shiftLeft(n);
this.bitwiseTo(r,op,r);
return r;
}
// (public) this | (1<<n)
function bnSetBit(n) { return this.changeBit(n,op_or); }
// (public) this & ~(1<<n)
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
// (public) this ^ (1<<n)
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
// (protected) r = this + a
function bnpAddTo(a,r) {
var self = this;
var i = 0, c = 0, m = Math.min(a.t,self.t);
while(i < m) {
c += self[i]+a[i];
r[i++] = c&self.DM;
c >>= self.DB;
}
if(a.t < self.t) {
c += a.s;
while(i < self.t) {
c += self[i];
r[i++] = c&self.DM;
c >>= self.DB;
}
c += self.s;
}
else {
c += self.s;
while(i < a.t) {
c += a[i];
r[i++] = c&self.DM;
c >>= self.DB;
}
c += a.s;
}
r.s = (c<0)?-1:0;
if(c > 0) r[i++] = c;
else if(c < -1) r[i++] = self.DV+c;
r.t = i;
r.clamp();
}
// (public) this + a
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
// (public) this - a
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
// (public) this * a
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
// (public) this^2
function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
// (public) this / a
function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
// (public) this % a
function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
// (public) [this/a,this%a]
function bnDivideAndRemainder(a) {
var q = nbi(), r = nbi();
this.divRemTo(a,q,r);
return new Array(q,r);
}
// (protected) this *= n, this >= 0, 1 < n < DV
function bnpDMultiply(n) {
this[this.t] = this.am(0,n-1,this,0,0,this.t);
++this.t;
this.clamp();
}
// (protected) this += n << w words, this >= 0
function bnpDAddOffset(n,w) {
if(n == 0) return;
while(this.t <= w) this[this.t++] = 0;
this[w] += n;
while(this[w] >= this.DV) {
this[w] -= this.DV;
if(++w >= this.t) this[this.t++] = 0;
++this[w];
}
}
// A "null" reducer
function NullExp() {}
function nNop(x) { return x; }
function nMulTo(x,y,r) { x.multiplyTo(y,r); }
function nSqrTo(x,r) { x.squareTo(r); }
NullExp.prototype.convert = nNop;
NullExp.prototype.revert = nNop;
NullExp.prototype.mulTo = nMulTo;
NullExp.prototype.sqrTo = nSqrTo;
// (public) this^e
function bnPow(e) { return this.exp(e,new NullExp()); }
// (protected) r = lower n words of "this * a", a.t <= n
// "this" should be the larger one if appropriate.
function bnpMultiplyLowerTo(a,n,r) {
var i = Math.min(this.t+a.t,n);
r.s = 0; // assumes a,this >= 0
r.t = i;
while(i > 0) r[--i] = 0;
var j;
for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
r.clamp();
}
// (protected) r = "this * a" without lower n words, n > 0
// "this" should be the larger one if appropriate.
function bnpMultiplyUpperTo(a,n,r) {
--n;
var i = r.t = this.t+a.t-n;
r.s = 0; // assumes a,this >= 0
while(--i >= 0) r[i] = 0;
for(i = Math.max(n-this.t,0); i < a.t; ++i)
r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
r.clamp();
r.drShiftTo(1,r);
}
// Barrett modular reduction
function Barrett(m) {
// setup Barrett
this.r2 = nbi();
this.q3 = nbi();
BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
this.mu = this.r2.divide(m);
this.m = m;
}
function barrettConvert(x) {
if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
else if(x.compareTo(this.m) < 0) return x;
else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
}
function barrettRevert(x) { return x; }
// x = x mod m (HAC 14.42)
function barrettReduce(x) {
var self = this;
x.drShiftTo(self.m.t-1,self.r2);
if(x.t > self.m.t+1) { x.t = self.m.t+1; x.clamp(); }
self.mu.multiplyUpperTo(self.r2,self.m.t+1,self.q3);
self.m.multiplyLowerTo(self.q3,self.m.t+1,self.r2);
while(x.compareTo(self.r2) < 0) x.dAddOffset(1,self.m.t+1);
x.subTo(self.r2,x);
while(x.compareTo(self.m) >= 0) x.subTo(self.m,x);
}
// r = x^2 mod m; x != r
function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
// r = x*y mod m; x,y != r
function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
Barrett.prototype.convert = barrettConvert;
Barrett.prototype.revert = barrettRevert;
Barrett.prototype.reduce = barrettReduce;
Barrett.prototype.mulTo = barrettMulTo;
Barrett.prototype.sqrTo = barrettSqrTo;
// (public) this^e % m (HAC 14.85)
function bnModPow(e,m) {
var i = e.bitLength(), k, r = nbv(1), z;
if(i <= 0) return r;
else if(i < 18) k = 1;
else if(i < 48) k = 3;
else if(i < 144) k = 4;
else if(i < 768) k = 5;
else k = 6;
if(i < 8)
z = new Classic(m);
else if(m.isEven())
z = new Barrett(m);
else
z = new Montgomery(m);
// precomputation
var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
g[1] = z.convert(this);
if(k > 1) {
var g2 = nbi();
z.sqrTo(g[1],g2);
while(n <= km) {
g[n] = nbi();
z.mulTo(g2,g[n-2],g[n]);
n += 2;
}
}
var j = e.t-1, w, is1 = true, r2 = nbi(), t;
i = nbits(e[j])-1;
while(j >= 0) {
if(i >= k1) w = (e[j]>>(i-k1))&km;
else {
w = (e[j]&((1<<(i+1))-1))<<(k1-i);
if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
}
n = k;
while((w&1) == 0) { w >>= 1; --n; }
if((i -= n) < 0) { i += this.DB; --j; }
if(is1) { // ret == 1, don't bother squaring or multiplying it
g[w].copyTo(r);
is1 = false;
}
else {
while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
z.mulTo(r2,g[w],r);
}
while(j >= 0 && (e[j]&(1<<i)) == 0) {
z.sqrTo(r,r2); t = r; r = r2; r2 = t;
if(--i < 0) { i = this.DB-1; --j; }
}
}
return z.revert(r);
}
// (public) gcd(this,a) (HAC 14.54)
function bnGCD(a) {
var x = (this.s<0)?this.negate():this.clone();
var y = (a.s<0)?a.negate():a.clone();
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
if(g < 0) return x;
if(i < g) g = i;
if(g > 0) {
x.rShiftTo(g,x);
y.rShiftTo(g,y);
}
while(x.signum() > 0) {
if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
if(x.compareTo(y) >= 0) {
x.subTo(y,x);
x.rShiftTo(1,x);
}
else {
y.subTo(x,y);
y.rShiftTo(1,y);
}
}
if(g > 0) y.lShiftTo(g,y);
return y;
}
// (protected) this % n, n < 2^26
function bnpModInt(n) {
if(n <= 0) return 0;
var d = this.DV%n, r = (this.s<0)?n-1:0;
if(this.t > 0)
if(d == 0) r = this[0]%n;
else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
return r;
}
// (public) 1/this % m (HAC 14.61)
function bnModInverse(m) {
var ac = m.isEven();
if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
var u = m.clone(), v = this.clone();
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
while(u.signum() != 0) {
while(u.isEven()) {
u.rShiftTo(1,u);
if(ac) {
if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
a.rShiftTo(1,a);
}
else if(!b.isEven()) b.subTo(m,b);
b.rShiftTo(1,b);
}
while(v.isEven()) {
v.rShiftTo(1,v);
if(ac) {
if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
c.rShiftTo(1,c);
}
else if(!d.isEven()) d.subTo(m,d);
d.rShiftTo(1,d);
}
if(u.compareTo(v) >= 0) {
u.subTo(v,u);
if(ac) a.subTo(c,a);
b.subTo(d,b);
}
else {
v.subTo(u,v);
if(ac) c.subTo(a,c);
d.subTo(b,d);
}
}
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
if(d.compareTo(m) >= 0) return d.subtract(m);
if(d.signum() < 0) d.addTo(m,d); else return d;
if(d.signum() < 0) return d.add(m); else return d;
}
// protected
proto.chunkSize = bnpChunkSize;
proto.toRadix = bnpToRadix;
proto.fromRadix = bnpFromRadix;
proto.fromNumber = bnpFromNumber;
proto.bitwiseTo = bnpBitwiseTo;
proto.changeBit = bnpChangeBit;
proto.addTo = bnpAddTo;
proto.dMultiply = bnpDMultiply;
proto.dAddOffset = bnpDAddOffset;
proto.multiplyLowerTo = bnpMultiplyLowerTo;
proto.multiplyUpperTo = bnpMultiplyUpperTo;
proto.modInt = bnpModInt;
// public
proto.clone = bnClone;
proto.intValue = bnIntValue;
proto.byteValue = bnByteValue;
proto.shortValue = bnShortValue;
proto.signum = bnSigNum;
proto.toByteArray = bnToByteArray;
proto.equals = bnEquals;
proto.min = bnMin;
proto.max = bnMax;
proto.and = bnAnd;
proto.or = bnOr;
proto.xor = bnXor;
proto.andNot = bnAndNot;
proto.not = bnNot;
proto.shiftLeft = bnShiftLeft;
proto.shiftRight = bnShiftRight;
proto.getLowestSetBit = bnGetLowestSetBit;
proto.bitCount = bnBitCount;
proto.testBit = bnTestBit;
proto.setBit = bnSetBit;
proto.clearBit = bnClearBit;
proto.flipBit = bnFlipBit;
proto.add = bnAdd;
proto.subtract = bnSubtract;
proto.multiply = bnMultiply;
proto.divide = bnDivide;
proto.remainder = bnRemainder;
proto.divideAndRemainder = bnDivideAndRemainder;
proto.modPow = bnModPow;
proto.modInverse = bnModInverse;
proto.pow = bnPow;
proto.gcd = bnGCD;
// JSBN-specific extension
proto.square = bnSquare;
// BigInteger interfaces not implemented in jsbn:
// BigInteger(int signum, byte[] magnitude)
// double doubleValue()
// float floatValue()
// int hashCode()
// long longValue()
// static BigInteger valueOf(long val)
// "constants"
BigInteger.ZERO = nbv(0);
BigInteger.ONE = nbv(1);
BigInteger.valueOf = nbv;
/// bitcoinjs addons
/**
* Turns a byte array into a big integer.
*
* This function will interpret a byte array as a big integer in big
* endian notation and ignore leading zeros.
*/
BigInteger.fromByteArrayUnsigned = function(ba) {
// FIXME: BigInteger doesn't yet support Buffers
if (Buffer.isBuffer(ba)) {
ba = Array.prototype.map.bind(ba, function(x) { return x })()
}
if (!ba.length) {
return new BigInteger.valueOf(0);
} else if (ba[0] & 0x80) {
// Prepend a zero so the BigInteger class doesn't mistake this
// for a negative integer.
return new BigInteger([0].concat(ba));
} else {
return new BigInteger(ba);
}
};
/**
* Parse a signed big integer byte representation.
*
* For details on the format please see BigInteger.toByteArraySigned.
*/
BigInteger.fromByteArraySigned = function(ba) {
// Check for negative value
if (ba[0] & 0x80) {
// Remove sign bit
ba[0] &= 0x7f;
return BigInteger.fromByteArrayUnsigned(ba).negate();
} else {
return BigInteger.fromByteArrayUnsigned(ba);
}
};
/**
* Returns a byte array representation of the big integer.
*
* This returns the absolute of the contained value in big endian
* form. A value of zero results in an empty array.
*/
BigInteger.prototype.toByteArrayUnsigned = function() {
var ba = this.abs().toByteArray();
// Empty array, nothing to do
if (!ba.length) {
return ba;
}
// remove leading 0
if (ba[0] === 0) {
ba = ba.slice(1);
}
// all values must be positive
for (var i=0 ; i<ba.length ; ++i) {
ba[i] = (ba[i] < 0) ? ba[i] + 256 : ba[i];
}
return ba;
};
/*
* Converts big integer to signed byte representation.
*
* The format for this value uses the most significant bit as a sign
* bit. If the most significant bit is already occupied by the
* absolute value, an extra byte is prepended and the sign bit is set
* there.
*
* Examples:
*
* 0 => 0x00
* 1 => 0x01
* -1 => 0x81
* 127 => 0x7f
* -127 => 0xff
* 128 => 0x0080
* -128 => 0x8080
* 255 => 0x00ff
* -255 => 0x80ff
* 16300 => 0x3fac
* -16300 => 0xbfac
* 62300 => 0x00f35c
* -62300 => 0x80f35c
*/
BigInteger.prototype.toByteArraySigned = function() {
var val = this.toByteArrayUnsigned();
var neg = this.s < 0;
// if the first bit is set, we always unshift
// either unshift 0x80 or 0x00
if (val[0] & 0x80) {
val.unshift((neg) ? 0x80 : 0x00);
}
// if the first bit isn't set, set it if negative
else if (neg) {
val[0] |= 0x80;
}
return val;
};
module.exports = BigInteger;

@@ -5,2 +5,5 @@ // Named EC curves

var ECCurveFp = require('./ec');
var BigInteger = require('./jsbn');
// ----------------

@@ -175,1 +178,3 @@ // X9ECParameters

}
module.exports = getSECCurveByName;

@@ -1,69 +0,64 @@

/**
* Implements Bitcoin's feature for signing arbitrary messages.
*/
Bitcoin.Message = (function () {
var Message = {};
/// Implements Bitcoin's feature for signing arbitrary messages.
Message.magicPrefix = "Bitcoin Signed Message:\n";
var Address = require('./address')
var convert = require('./convert')
var ecdsa = require('./ecdsa')
var ECPubKey = require('./eckey').ECPubKey
var SHA256 = require('crypto-js/sha256')
Message.makeMagicMessage = function (message) {
var magicBytes = Crypto.charenc.UTF8.stringToBytes(Message.magicPrefix);
var messageBytes = Crypto.charenc.UTF8.stringToBytes(message);
// FIXME: magicHash is incompatible with other magic messages
var magicBytes = convert.stringToBytes('Bitcoin Signed Message:\n')
var buffer = [];
buffer = buffer.concat(Bitcoin.Util.numToVarInt(magicBytes.length));
buffer = buffer.concat(magicBytes);
buffer = buffer.concat(Bitcoin.Util.numToVarInt(messageBytes.length));
buffer = buffer.concat(messageBytes);
function magicHash(message) {
var messageBytes = convert.stringToBytes(message)
return buffer;
};
var buffer = [].concat(
convert.numToVarInt(magicBytes.length),
magicBytes,
convert.numToVarInt(messageBytes.length),
messageBytes
)
Message.getHash = function (message) {
var buffer = Message.makeMagicMessage(message);
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true});
};
return convert.wordArrayToBytes(SHA256(SHA256(convert.bytesToWordArray(buffer))))
}
Message.signMessage = function (key, message, compressed) {
var hash = Message.getHash(message);
// TODO: parameterize compression instead of using ECKey.compressed
function sign(key, message) {
var hash = magicHash(message)
var sig = key.sign(hash)
var obj = ecdsa.parseSig(sig)
var i = ecdsa.calcPubKeyRecoveryParam(key.getPub().pub, obj.r, obj.s, hash)
var sig = key.sign(hash);
i += 27
if (key.compressed) {
i += 4
}
var obj = Bitcoin.ECDSA.parseSig(sig);
var rBa = obj.r.toByteArrayUnsigned()
var sBa = obj.s.toByteArrayUnsigned()
var address = key.getBitcoinAddress().toString();
var i = Bitcoin.ECDSA.calcPubkeyRecoveryParam(address, obj.r, obj.s, hash);
// Pad to 32 bytes per value
while (rBa.length < 32) rBa.unshift(0);
while (sBa.length < 32) sBa.unshift(0);
i += 27;
if (compressed) i += 4;
sig = [i].concat(rBa, sBa)
var rBa = obj.r.toByteArrayUnsigned();
var sBa = obj.s.toByteArrayUnsigned();
return sig
}
// Pad to 32 bytes per value
while (rBa.length < 32) rBa.unshift(0);
while (sBa.length < 32) sBa.unshift(0);
function verify(address, sig, message) {
sig = ecdsa.parseSigCompact(sig)
sig = [i].concat(rBa).concat(sBa);
var pubKey = new ECPubKey(ecdsa.recoverPubKey(sig.r, sig.s, magicHash(message), sig.i))
var isCompressed = !!(sig.i & 4)
pubKey.compressed = isCompressed
return Crypto.util.bytesToBase64(sig);
};
address = new Address(address)
return pubKey.getAddress(address.version).toString() === address.toString()
}
Message.verifyMessage = function (address, sig, message) {
sig = Crypto.util.base64ToBytes(sig);
sig = Bitcoin.ECDSA.parseSigCompact(sig);
var hash = Message.getHash(message);
var isCompressed = !!(sig.i & 4);
var pubKey = Bitcoin.ECDSA.recoverPubKey(sig.r, sig.s, hash, sig.i);
pubKey.setCompressed(isCompressed);
var expectedAddress = pubKey.getBitcoinAddress().toString();
return (address === expectedAddress);
};
return Message;
})();
module.exports = {
magicHash: magicHash,
sign: sign,
verify: verify
}

@@ -1,11 +0,3 @@

(function () {
var Opcode = Bitcoin.Opcode = function (num) {
this.code = num;
};
Opcode.prototype.toString = function () {
return Opcode.reverseMap[this.code];
};
Opcode.map = {
var Opcode = {
map: {
// push value

@@ -147,9 +139,10 @@ OP_0 : 0,

OP_INVALIDOPCODE : 255
};
},
reverseMap: []
}
Opcode.reverseMap = [];
for(var i in Opcode.map) {
Opcode.reverseMap[Opcode.map[i]] = i
}
for (var i in Opcode.map) {
Opcode.reverseMap[Opcode.map[i]] = i;
}
})();
module.exports = Opcode

@@ -1,347 +0,391 @@

(function () {
var Opcode = Bitcoin.Opcode;
var Opcode = require('./opcode')
var util = require('./util')
var convert = require('./convert')
var Address = require('./address')
var network = require('./network')
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval("var " + i + " = " + Opcode.map[i] + ";");
var Script = function(data) {
this.buffer = data || []
if(!Array.isArray(this.buffer)) {
throw new Error('expect Script to be initialized with Array, but got ' + data)
}
this.parse()
}
var Script = Bitcoin.Script = function (data) {
if (!data) {
this.buffer = [];
} else if ("string" == typeof data) {
this.buffer = Crypto.util.base64ToBytes(data);
} else if (Bitcoin.Util.isArray(data)) {
this.buffer = data;
} else if (data instanceof Script) {
this.buffer = data.buffer;
Script.fromHex = function(data) {
return new Script(convert.hexToBytes(data))
}
Script.fromPubKey = function(str) {
var script = new Script()
var s = str.split(' ')
for (var i in s) {
if (Opcode.map.hasOwnProperty(s[i])) {
script.writeOp(Opcode.map[s[i]])
} else {
throw new Error("Invalid script");
script.writeBytes(convert.hexToBytes(s[i]))
}
}
return script
}
this.parse();
};
Script.fromScriptSig = function(str) {
var script = new Script()
var s = str.split(' ')
for (var i in s) {
if (Opcode.map.hasOwnProperty(s[i])) {
script.writeOp(Opcode.map[s[i]])
} else {
script.writeBytes(convert.hexToBytes(s[i]))
}
}
return script
}
/**
* Update the parsed script representation.
*
* Each Script object stores the script in two formats. First as a raw byte
* array and second as an array of "chunks", such as opcodes and pieces of
* data.
*
* This method updates the chunks cache. Normally this is called by the
* constructor and you don't need to worry about it. However, if you change
* the script buffer manually, you should update the chunks using this method.
*/
Script.prototype.parse = function () {
var self = this;
/**
* Update the parsed script representation.
*
* Each Script object stores the script in two formats. First as a raw byte
* array and second as an array of 'chunks', such as opcodes and pieces of
* data.
*
* This method updates the chunks cache. Normally this is called by the
* constructor and you don't need to worry about it. However, if you change
* the script buffer manually, you should update the chunks using this method.
*/
Script.prototype.parse = function() {
var self = this
this.chunks = [];
this.chunks = []
// Cursor
var i = 0;
// Cursor
var i = 0
// Read n bytes and store result as a chunk
function readChunk(n) {
self.chunks.push(self.buffer.slice(i, i + n));
i += n;
};
// Read n bytes and store result as a chunk
function readChunk(n) {
self.chunks.push(self.buffer.slice(i, i + n))
i += n
}
while (i < this.buffer.length) {
var opcode = this.buffer[i++];
if (opcode >= 0xF0) {
// Two byte opcode
opcode = (opcode << 8) | this.buffer[i++];
}
while (i < this.buffer.length) {
var opcode = this.buffer[i++]
if (opcode >= 0xF0) {
// Two byte opcode
opcode = (opcode << 8) | this.buffer[i++]
}
var len;
if (opcode > 0 && opcode < OP_PUSHDATA1) {
// Read some bytes of data, opcode value is the length of data
readChunk(opcode);
} else if (opcode == OP_PUSHDATA1) {
len = this.buffer[i++];
readChunk(len);
} else if (opcode == OP_PUSHDATA2) {
len = (this.buffer[i++] << 8) | this.buffer[i++];
readChunk(len);
} else if (opcode == OP_PUSHDATA4) {
len = (this.buffer[i++] << 24) |
(this.buffer[i++] << 16) |
(this.buffer[i++] << 8) |
this.buffer[i++];
readChunk(len);
} else {
this.chunks.push(opcode);
}
var len
if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) {
// Read some bytes of data, opcode value is the length of data
readChunk(opcode)
} else if (opcode == Opcode.map.OP_PUSHDATA1) {
len = this.buffer[i++]
readChunk(len)
} else if (opcode == Opcode.map.OP_PUSHDATA2) {
len = (this.buffer[i++] << 8) | this.buffer[i++]
readChunk(len)
} else if (opcode == Opcode.map.OP_PUSHDATA4) {
len = (this.buffer[i++] << 24) |
(this.buffer[i++] << 16) |
(this.buffer[i++] << 8) |
this.buffer[i++]
readChunk(len)
} else {
this.chunks.push(opcode)
}
};
}
}
/**
* Compare the script to known templates of scriptPubKey.
*
* This method will compare the script to a small number of standard script
* templates and return a string naming the detected type.
*
* Currently supported are:
* Address:
* Paying to a Bitcoin address which is the hash of a pubkey.
* OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG
*
* Pubkey:
* Paying to a public key directly.
* [pubKey] OP_CHECKSIG
*
* Strange:
* Any other script (no template matched).
*/
Script.prototype.getOutType = function () {
if (this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG && this.chunks[this.chunks.length-2] <= 3) {
/**
* Compare the script to known templates of scriptPubKey.
*
* This method will compare the script to a small number of standard script
* templates and return a string naming the detected type.
*
* Currently supported are:
* Address:
* Paying to a Bitcoin address which is the hash of a pubkey.
* OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG
*
* Pubkey:
* Paying to a public key directly.
* [pubKey] OP_CHECKSIG
*
* Strange:
* Any other script (no template matched).
*/
Script.prototype.getOutType = function() {
if (this.chunks[this.chunks.length - 1] == Opcode.map.OP_EQUAL &&
this.chunks[0] == Opcode.map.OP_HASH160 &&
this.chunks.length == 3) {
// Transfer to M-OF-N
return 'Multisig';
return 'P2SH'
} else if (this.chunks.length == 5 &&
this.chunks[0] == OP_DUP &&
this.chunks[1] == OP_HASH160 &&
this.chunks[3] == OP_EQUALVERIFY &&
this.chunks[4] == OP_CHECKSIG) {
this.chunks[0] == Opcode.map.OP_DUP &&
this.chunks[1] == Opcode.map.OP_HASH160 &&
this.chunks[3] == Opcode.map.OP_EQUALVERIFY &&
this.chunks[4] == Opcode.map.OP_CHECKSIG) {
// Transfer to Bitcoin address
return 'Address';
} else if (this.chunks.length == 2 &&
this.chunks[1] == OP_CHECKSIG) {
// Transfer to IP address
return 'Pubkey';
return 'Pubkey'
} else {
return 'Strange';
}
return 'Strange'
}
}
/**
* Returns the affected address hash for this output.
*
* For standard transactions, this will return the hash of the pubKey that
* can spend this output.
*
* In the future, for payToScriptHash outputs, this will return the
* scriptHash. Note that non-standard and standard payToScriptHash transactions
* look the same
*
* This method is useful for indexing transactions.
*/
Script.prototype.simpleOutHash = function ()
{
switch (this.getOutType()) {
case 'Address':
return this.chunks[2];
case 'Pubkey':
return Bitcoin.Util.sha256ripe160(this.chunks[0]);
default:
throw new Error("Encountered non-standard scriptPubKey");
}
};
/**
* Returns the address corresponding to this output in hash160 form.
* Assumes strange scripts are P2SH
*/
Script.prototype.toScriptHash = function() {
var outType = this.getOutType()
/**
* Old name for Script#simpleOutHash.
*
* @deprecated
*/
Script.prototype.simpleOutPubKeyHash = Script.prototype.simpleOutHash;
if (outType == 'Pubkey') {
return this.chunks[2]
}
/**
* Compare the script to known templates of scriptSig.
*
* This method will compare the script to a small number of standard script
* templates and return a string naming the detected type.
*
* WARNING: Use this method with caution. It merely represents a heuristic
* based on common transaction formats. A non-standard transaction could
* very easily match one of these templates by accident.
*
* Currently supported are:
* Address:
* Paying to a Bitcoin address which is the hash of a pubkey.
* [sig] [pubKey]
*
* Pubkey:
* Paying to a public key directly.
* [sig]
*
* Strange:
* Any other script (no template matched).
*/
Script.prototype.getInType = function ()
{
if (this.chunks.length == 1 &&
Bitcoin.Util.isArray(this.chunks[0])) {
// Direct IP to IP transactions only have the signature in their scriptSig.
// TODO: We could also check that the length of the data is correct.
return 'Pubkey';
} else if (this.chunks.length == 2 &&
Bitcoin.Util.isArray(this.chunks[0]) &&
Bitcoin.Util.isArray(this.chunks[1])) {
return 'Address';
} else {
return 'Strange';
}
};
if (outType == 'P2SH') {
return util.sha256ripe160(this.buffer)
}
/**
* Returns the affected public key for this input.
*
* This currently only works with payToPubKeyHash transactions. It will also
* work in the future for standard payToScriptHash transactions that use a
* single public key.
*
* However for multi-key and other complex transactions, this will only return
* one of the keys or raise an error. Therefore, it is recommended for indexing
* purposes to use Script#simpleInHash or Script#simpleOutHash instead.
*
* @deprecated
*/
Script.prototype.simpleInPubKey = function ()
{
switch (this.getInType()) {
return util.sha256ripe160(this.buffer)
}
//TODO: support testnet
Script.prototype.getToAddress = function() {
var outType = this.getOutType()
if (outType == 'Pubkey') {
return new Address(this.chunks[2])
}
if (outType == 'P2SH') {
return new Address(this.chunks[1], 5)
}
return new Address(this.chunks[1], 5)
}
//TODO: support testnet
Script.prototype.getFromAddress = function(){
return new Address(this.simpleInHash())
}
/**
* Compare the script to known templates of scriptSig.
*
* This method will compare the script to a small number of standard script
* templates and return a string naming the detected type.
*
* WARNING: Use this method with caution. It merely represents a heuristic
* based on common transaction formats. A non-standard transaction could
* very easily match one of these templates by accident.
*
* Currently supported are:
* Address:
* Paying to a Bitcoin address which is the hash of a pubkey.
* [sig] [pubKey]
*
* Pubkey:
* Paying to a public key directly.
* [sig]
*
* Multisig:
* Paying to M-of-N public keys.
*
* Strange:
* Any other script (no template matched).
*/
Script.prototype.getInType = function() {
if (this.chunks.length == 1 &&
Array.isArray(this.chunks[0])) {
// Direct IP to IP transactions only have the signature in their scriptSig.
// TODO: We could also check that the length of the data is correct.
return 'Pubkey'
} else if (this.chunks.length == 2 &&
Array.isArray(this.chunks[0]) &&
Array.isArray(this.chunks[1])) {
return 'Address'
} else if (this.chunks[0] == Opcode.map.OP_0 &&
this.chunks.slice(1).reduce(function(t, chunk, i) {
return t && Array.isArray(chunk) && (chunk[0] == 48 || i == this.chunks.length - 1)
}, true)) {
return 'Multisig'
} else {
return 'Strange'
}
}
/**
* Returns the affected public key for this input.
*
* This currently only works with payToPubKeyHash transactions. It will also
* work in the future for standard payToScriptHash transactions that use a
* single public key.
*
* However for multi-key and other complex transactions, this will only return
* one of the keys or raise an error. Therefore, it is recommended for indexing
* purposes to use Script#simpleInHash or Script#simpleOutHash instead.
*
* @deprecated
*/
Script.prototype.simpleInPubKey = function() {
switch (this.getInType()) {
case 'Address':
return this.chunks[1];
return this.chunks[1]
case 'Pubkey':
// TODO: Theoretically, we could recover the pubkey from the sig here.
// See https://bitcointalk.org/?topic=6430.0
throw new Error("Script does not contain pubkey.");
throw new Error('Script does not contain pubkey')
default:
throw new Error("Encountered non-standard scriptSig");
}
};
throw new Error('Encountered non-standard scriptSig')
}
}
/**
* Returns the affected address hash for this input.
*
* For standard transactions, this will return the hash of the pubKey that
* can spend this output.
*
* In the future, for standard payToScriptHash inputs, this will return the
* scriptHash.
*
* Note: This function provided for convenience. If you have the corresponding
* scriptPubKey available, you are urged to use Script#simpleOutHash instead
* as it is more reliable for non-standard payToScriptHash transactions.
*
* This method is useful for indexing transactions.
*/
Script.prototype.simpleInHash = function ()
{
return Bitcoin.Util.sha256ripe160(this.simpleInPubKey());
};
/**
* Returns the affected address hash for this input.
*
* For standard transactions, this will return the hash of the pubKey that
* can spend this output.
*
* In the future, for standard payToScriptHash inputs, this will return the
* scriptHash.
*
* Note: This function provided for convenience. If you have the corresponding
* scriptPubKey available, you are urged to use Script#simpleOutHash instead
* as it is more reliable for non-standard payToScriptHash transactions.
*
* This method is useful for indexing transactions.
*/
Script.prototype.simpleInHash = function() {
return util.sha256ripe160(this.simpleInPubKey())
}
/**
* Old name for Script#simpleInHash.
*
* @deprecated
*/
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash;
/**
* Old name for Script#simpleInHash.
*
* @deprecated
*/
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash
/**
* Add an op code to the script.
*/
Script.prototype.writeOp = function (opcode)
{
this.buffer.push(opcode);
this.chunks.push(opcode);
};
/**
* Add an op code to the script.
*/
Script.prototype.writeOp = function(opcode) {
this.buffer.push(opcode)
this.chunks.push(opcode)
}
/**
* Add a data chunk to the script.
*/
Script.prototype.writeBytes = function (data)
{
if (data.length < OP_PUSHDATA1) {
this.buffer.push(data.length);
} else if (data.length <= 0xff) {
this.buffer.push(OP_PUSHDATA1);
this.buffer.push(data.length);
} else if (data.length <= 0xffff) {
this.buffer.push(OP_PUSHDATA2);
this.buffer.push(data.length & 0xff);
this.buffer.push((data.length >>> 8) & 0xff);
} else {
this.buffer.push(OP_PUSHDATA4);
this.buffer.push(data.length & 0xff);
this.buffer.push((data.length >>> 8) & 0xff);
this.buffer.push((data.length >>> 16) & 0xff);
this.buffer.push((data.length >>> 24) & 0xff);
}
this.buffer = this.buffer.concat(data);
this.chunks.push(data);
};
/**
* Add a data chunk to the script.
*/
Script.prototype.writeBytes = function(data) {
// FIXME: Script module doesn't support buffers yet
if (Buffer.isBuffer(data)) {
data = Array.prototype.map.bind(data, function(x) { return x })()
}
/**
* Create a standard payToPubKeyHash output.
*/
Script.createOutputScript = function (address)
{
var script = new Script();
script.writeOp(OP_DUP);
script.writeOp(OP_HASH160);
script.writeBytes(address.hash);
script.writeOp(OP_EQUALVERIFY);
script.writeOp(OP_CHECKSIG);
return script;
};
/**
* Extract bitcoin addresses from an output script
*/
Script.prototype.extractAddresses = function (addresses)
{
switch (this.getOutType()) {
case 'Address':
addresses.push(new Address(this.chunks[2]));
return 1;
case 'Pubkey':
addresses.push(new Address(Util.sha256ripe160(this.chunks[0])));
return 1;
case 'Multisig':
for (var i = 1; i < this.chunks.length-2; ++i) {
addresses.push(new Address(Util.sha256ripe160(this.chunks[i])));
}
return this.chunks[0] - OP_1 + 1;
default:
throw new Error("Encountered non-standard scriptPubKey");
}
};
if (data.length < Opcode.map.OP_PUSHDATA1) {
this.buffer.push(data.length)
} else if (data.length <= 0xff) {
this.buffer.push(Opcode.map.OP_PUSHDATA1)
this.buffer.push(data.length)
} else if (data.length <= 0xffff) {
this.buffer.push(Opcode.map.OP_PUSHDATA2)
this.buffer.push(data.length & 0xff)
this.buffer.push((data.length >>> 8) & 0xff)
} else {
this.buffer.push(Opcode.map.OP_PUSHDATA4)
this.buffer.push(data.length & 0xff)
this.buffer.push((data.length >>> 8) & 0xff)
this.buffer.push((data.length >>> 16) & 0xff)
this.buffer.push((data.length >>> 24) & 0xff)
}
this.buffer = this.buffer.concat(data)
this.chunks.push(data)
}
/**
* Create an m-of-n output script
*/
Script.createMultiSigOutputScript = function (m, pubkeys)
{
var script = new Bitcoin.Script();
script.writeOp(OP_1 + m - 1);
for (var i = 0; i < pubkeys.length; ++i) {
script.writeBytes(pubkeys[i]);
}
script.writeOp(OP_1 + pubkeys.length - 1);
/**
* Create an output for an address
*/
Script.createOutputScript = function(address) {
var script = new Script()
address = new Address(address)
if (address.version == network.mainnet.p2shVersion ||
address.version == network.testnet.p2shVersion) {
// Standard pay-to-script-hash
script.writeOp(Opcode.map.OP_HASH160)
script.writeBytes(address.hash)
script.writeOp(Opcode.map.OP_EQUAL)
}
else {
// Standard pay-to-pubkey-hash
script.writeOp(Opcode.map.OP_DUP)
script.writeOp(Opcode.map.OP_HASH160)
script.writeBytes(address.hash)
script.writeOp(Opcode.map.OP_EQUALVERIFY)
script.writeOp(Opcode.map.OP_CHECKSIG)
}
return script
}
script.writeOp(OP_CHECKMULTISIG);
/**
* Extract pubkeys from a multisig script
*/
return script;
};
Script.prototype.extractPubkeys = function() {
return this.chunks.filter(function(chunk) {
return(chunk[0] == 4 && chunk.length == 65 || chunk[0] < 4 && chunk.length == 33)
})
}
/**
* Create a standard payToPubKeyHash input.
*/
Script.createInputScript = function (signature, pubKey)
{
var script = new Script();
script.writeBytes(signature);
script.writeBytes(pubKey);
return script;
};
/**
* Create an m-of-n output script
*/
Script.createMultiSigOutputScript = function(m, pubkeys) {
var script = new Script()
pubkeys = pubkeys.sort()
Script.prototype.clone = function ()
{
return new Script(this.buffer);
};
})();
script.writeOp(Opcode.map.OP_1 + m - 1)
for (var i = 0; i < pubkeys.length; ++i) {
script.writeBytes(pubkeys[i])
}
script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1)
script.writeOp(Opcode.map.OP_CHECKMULTISIG)
return script
}
/**
* Create a standard payToPubKeyHash input.
*/
Script.createInputScript = function(signature, pubKey) {
var script = new Script()
script.writeBytes(signature)
script.writeBytes(pubKey)
return script
}
/**
* Create a multisig input
*/
Script.createMultiSigInputScript = function(signatures, script) {
script = new Script(script)
var k = script.chunks[0][0]
//Not enough sigs
if (signatures.length < k) return false;
var inScript = new Script()
inScript.writeOp(Opcode.map.OP_0)
signatures.map(function(sig) {
inScript.writeBytes(sig)
})
inScript.writeBytes(script.buffer)
return inScript
}
Script.prototype.clone = function() {
return new Script(this.buffer)
}
module.exports = Script

@@ -1,445 +0,448 @@

(function () {
var Script = Bitcoin.Script;
var BigInteger = require('./jsbn/jsbn')
var Script = require('./script')
var util = require('./util')
var convert = require('./convert')
var ECKey = require('./eckey').ECKey
var ECDSA = require('./ecdsa')
var Address = require('./address')
var SHA256 = require('crypto-js/sha256')
var Transaction = Bitcoin.Transaction = function (doc) {
this.version = 1;
this.lock_time = 0;
this.ins = [];
this.outs = [];
this.timestamp = null;
this.block = null;
var Transaction = function (doc) {
if (!(this instanceof Transaction)) { return new Transaction(doc) }
this.version = 1
this.locktime = 0
this.ins = []
this.outs = []
this.defaultSequence = [255, 255, 255, 255] // 0xFFFFFFFF
if (doc) {
if (doc.hash) this.hash = doc.hash;
if (doc.version) this.version = doc.version;
if (doc.lock_time) this.lock_time = doc.lock_time;
if (doc.ins && doc.ins.length) {
for (var i = 0; i < doc.ins.length; i++) {
this.addInput(new TransactionIn(doc.ins[i]));
}
}
if (doc.outs && doc.outs.length) {
for (var i = 0; i < doc.outs.length; i++) {
this.addOutput(new TransactionOut(doc.outs[i]));
}
}
if (doc.timestamp) this.timestamp = doc.timestamp;
if (doc.block) this.block = doc.block;
if (doc) {
if (typeof doc == "string" || Array.isArray(doc)) {
doc = Transaction.deserialize(doc)
}
};
/**
* Turn transaction data into Transaction objects.
*
* Takes an array of plain JavaScript objects containing transaction data and
* returns an array of Transaction objects.
*/
Transaction.objectify = function (txs) {
var objs = [];
for (var i = 0; i < txs.length; i++) {
objs.push(new Transaction(txs[i]));
if (doc.hash) this.hash = doc.hash;
if (doc.version) this.version = doc.version;
if (doc.locktime) this.locktime = doc.locktime;
if (doc.ins && doc.ins.length) {
doc.ins.forEach(function(input) {
this.addInput(new TransactionIn(input))
}, this)
}
return objs;
};
/**
* Create a new txin.
*
* Can be called with an existing TransactionIn object to add it to the
* transaction. Or it can be called with a Transaction object and an integer
* output index, in which case a new TransactionIn object pointing to the
* referenced output will be created.
*
* Note that this method does not sign the created input.
*/
Transaction.prototype.addInput = function (tx, outIndex) {
if (arguments[0] instanceof TransactionIn) {
this.ins.push(arguments[0]);
} else {
this.ins.push(new TransactionIn({
outpoint: {
hash: tx.hash,
index: outIndex
},
script: new Bitcoin.Script(),
sequence: 4294967295
}));
if (doc.outs && doc.outs.length) {
doc.outs.forEach(function(output) {
this.addOutput(new TransactionOut(output))
}, this)
}
};
/**
* Create a new txout.
*
* Can be called with an existing TransactionOut object to add it to the
* transaction. Or it can be called with an Address object and a BigInteger
* for the amount, in which case a new TransactionOut object with those
* values will be created.
*/
Transaction.prototype.addOutput = function (address, value) {
if (arguments[0] instanceof TransactionOut) {
this.outs.push(arguments[0]);
} else {
if (value instanceof BigInteger) {
value = value.toByteArrayUnsigned().reverse();
while (value.length < 8) value.push(0);
} else if (Bitcoin.Util.isArray(value)) {
// Nothing to do
}
this.hash = this.hash || this.getHash()
}
}
this.outs.push(new TransactionOut({
value: value,
script: Script.createOutputScript(address)
}));
}
};
/**
* Create a new txin.
*
* Can be called with any of:
*
* - An existing TransactionIn object
* - A transaction and an index
* - A transaction hash and an index
* - A single string argument of the form txhash:index
*
* Note that this method does not sign the created input.
*/
Transaction.prototype.addInput = function (tx, outIndex) {
if (arguments[0] instanceof TransactionIn) {
this.ins.push(arguments[0])
}
else if (arguments[0].length > 65) {
var args = arguments[0].split(':')
return this.addInput(args[0], args[1])
}
else {
var hash = typeof tx === "string" ? tx : tx.hash
hash = Array.isArray(hash) ? convert.bytesToHex(hash) : hash
/**
* Serialize this transaction.
*
* Returns the transaction as a byte array in the standard Bitcoin binary
* format. This method is byte-perfect, i.e. the resulting byte array can
* be hashed to get the transaction's standard Bitcoin hash.
*/
Transaction.prototype.serialize = function ()
{
var buffer = [];
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(this.version)]).reverse());
buffer = buffer.concat(Bitcoin.Util.numToVarInt(this.ins.length));
for (var i = 0; i < this.ins.length; i++) {
var txin = this.ins[i];
buffer = buffer.concat(Crypto.util.base64ToBytes(txin.outpoint.hash));
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.outpoint.index)]).reverse());
var scriptBytes = txin.script.buffer;
buffer = buffer.concat(Bitcoin.Util.numToVarInt(scriptBytes.length));
buffer = buffer.concat(scriptBytes);
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.sequence)]).reverse());
}
buffer = buffer.concat(Bitcoin.Util.numToVarInt(this.outs.length));
for (var i = 0; i < this.outs.length; i++) {
var txout = this.outs[i];
buffer = buffer.concat(txout.value);
var scriptBytes = txout.script.buffer;
buffer = buffer.concat(Bitcoin.Util.numToVarInt(scriptBytes.length));
buffer = buffer.concat(scriptBytes);
}
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(this.lock_time)]).reverse());
this.ins.push(new TransactionIn({
outpoint: {
hash: hash,
index: outIndex
},
script: new Script(),
sequence: this.defaultSequence
}))
}
}
return buffer;
};
/**
* Create a new txout.
*
* Can be called with:
*
* i) An existing TransactionOut object
* ii) An address object or an address and a value
* iii) An address:value string
*
*/
Transaction.prototype.addOutput = function (address, value) {
if (arguments[0] instanceof TransactionOut) {
this.outs.push(arguments[0])
return
}
var OP_CODESEPARATOR = 171;
if (arguments[0].indexOf(':') >= 0) {
var args = arguments[0].split(':')
address = args[0]
value = parseInt(args[1])
}
var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2;
var SIGHASH_SINGLE = 3;
var SIGHASH_ANYONECANPAY = 80;
this.outs.push(new TransactionOut({
value: value,
script: Script.createOutputScript(address)
}))
}
/**
* Hash transaction for signing a specific input.
*
* Bitcoin uses a different hash for each signed transaction input. This
* method copies the transaction, makes the necessary changes based on the
* hashType, serializes and finally hashes the result. This hash can then be
* used to sign the transaction input in question.
*/
Transaction.prototype.hashTransactionForSignature =
function (connectedScript, inIndex, hashType)
{
var txTmp = this.clone();
/**
* Serialize this transaction.
*
* Returns the transaction as a byte array in the standard Bitcoin binary
* format. This method is byte-perfect, i.e. the resulting byte array can
* be hashed to get the transaction's standard Bitcoin hash.
*/
Transaction.prototype.serialize = function () {
var buffer = []
buffer = buffer.concat(convert.numToBytes(parseInt(this.version), 4))
buffer = buffer.concat(convert.numToVarInt(this.ins.length))
// In case concatenating two scripts ends up with two codeseparators,
// or an extra one at the end, this prevents all those possible
// incompatibilities.
/*scriptCode = scriptCode.filter(function (val) {
return val !== OP_CODESEPARATOR;
});*/
this.ins.forEach(function(txin) {
// Why do blockchain.info, blockexplorer.com, sx and just about everybody
// else use little-endian hashes? No idea...
buffer = buffer.concat(convert.hexToBytes(txin.outpoint.hash).reverse())
// Blank out other inputs' signatures
for (var i = 0; i < txTmp.ins.length; i++) {
txTmp.ins[i].script = new Script();
}
buffer = buffer.concat(convert.numToBytes(parseInt(txin.outpoint.index), 4))
txTmp.ins[inIndex].script = connectedScript;
var scriptBytes = txin.script.buffer
buffer = buffer.concat(convert.numToVarInt(scriptBytes.length))
buffer = buffer.concat(scriptBytes)
buffer = buffer.concat(txin.sequence)
})
// Blank out some of the outputs
if ((hashType & 0x1f) == SIGHASH_NONE) {
txTmp.outs = [];
buffer = buffer.concat(convert.numToVarInt(this.outs.length))
// Let the others update at will
for (var i = 0; i < txTmp.ins.length; i++)
if (i != inIndex)
txTmp.ins[i].sequence = 0;
} else if ((hashType & 0x1f) == SIGHASH_SINGLE) {
// TODO: Implement
}
this.outs.forEach(function(txout) {
buffer = buffer.concat(convert.numToBytes(txout.value,8))
// Blank out other inputs completely, not recommended for open transactions
if (hashType & SIGHASH_ANYONECANPAY) {
txTmp.ins = [txTmp.ins[inIndex]];
}
var scriptBytes = txout.script.buffer
buffer = buffer.concat(convert.numToVarInt(scriptBytes.length))
buffer = buffer.concat(scriptBytes)
})
var buffer = txTmp.serialize();
buffer = buffer.concat(convert.numToBytes(parseInt(this.locktime), 4))
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)]).reverse());
return buffer
}
var hash1 = Crypto.SHA256(buffer, {asBytes: true});
Transaction.prototype.serializeHex = function() {
return convert.bytesToHex(this.serialize())
}
return Crypto.SHA256(hash1, {asBytes: true});
};
//var OP_CODESEPARATOR = 171
/**
* Calculate and return the transaction's hash.
*/
Transaction.prototype.getHash = function ()
{
var buffer = this.serialize();
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true});
};
var SIGHASH_ALL = 1
var SIGHASH_NONE = 2
var SIGHASH_SINGLE = 3
var SIGHASH_ANYONECANPAY = 80
/**
* Create a copy of this transaction object.
*/
Transaction.prototype.clone = function ()
{
var newTx = new Transaction();
newTx.version = this.version;
newTx.lock_time = this.lock_time;
for (var i = 0; i < this.ins.length; i++) {
var txin = this.ins[i].clone();
newTx.addInput(txin);
}
for (var i = 0; i < this.outs.length; i++) {
var txout = this.outs[i].clone();
newTx.addOutput(txout);
}
return newTx;
};
/**
* Hash transaction for signing a specific input.
*
* Bitcoin uses a different hash for each signed transaction input. This
* method copies the transaction, makes the necessary changes based on the
* hashType, serializes and finally hashes the result. This hash can then be
* used to sign the transaction input in question.
*/
Transaction.prototype.hashTransactionForSignature =
function (connectedScript, inIndex, hashType)
{
var txTmp = this.clone()
/**
* Analyze how this transaction affects a wallet.
*
* Returns an object with properties 'impact', 'type' and 'addr'.
*
* 'impact' is an object, see Transaction#calcImpact.
*
* 'type' can be one of the following:
*
* recv:
* This is an incoming transaction, the wallet received money.
* 'addr' contains the first address in the wallet that receives money
* from this transaction.
*
* self:
* This is an internal transaction, money was sent within the wallet.
* 'addr' is undefined.
*
* sent:
* This is an outgoing transaction, money was sent out from the wallet.
* 'addr' contains the first external address, i.e. the recipient.
*
* other:
* This method was unable to detect what the transaction does. Either it
*/
Transaction.prototype.analyze = function (wallet) {
if (!(wallet instanceof Bitcoin.Wallet)) return null;
// In case concatenating two scripts ends up with two codeseparators,
// or an extra one at the end, this prevents all those possible
// incompatibilities.
/*scriptCode = scriptCode.filter(function (val) {
return val !== OP_CODESEPARATOR
});*/
var allFromMe = true,
allToMe = true,
firstRecvHash = null,
firstMeRecvHash = null,
firstSendHash = null;
// Blank out other inputs' signatures
txTmp.ins.forEach(function(txin) {
txin.script = new Script()
})
for (var i = this.outs.length-1; i >= 0; i--) {
var txout = this.outs[i];
var hash = txout.script.simpleOutPubKeyHash();
if (!wallet.hasHash(hash)) {
allToMe = false;
} else {
firstMeRecvHash = hash;
txTmp.ins[inIndex].script = connectedScript
// Blank out some of the outputs
if ((hashType & 0x1f) == SIGHASH_NONE) {
txTmp.outs = []
// Let the others update at will
txTmp.ins.forEach(function(txin, i) {
if (i != inIndex) {
txTmp.ins[i].sequence = 0
}
firstRecvHash = hash;
}
for (var i = this.ins.length-1; i >= 0; i--) {
var txin = this.ins[i];
firstSendHash = txin.script.simpleInPubKeyHash();
if (!wallet.hasHash(firstSendHash)) {
allFromMe = false;
break;
}
}
})
var impact = this.calcImpact(wallet);
} else if ((hashType & 0x1f) == SIGHASH_SINGLE) {
// TODO: Implement
}
var analysis = {};
// Blank out other inputs completely, not recommended for open transactions
if (hashType & SIGHASH_ANYONECANPAY) {
txTmp.ins = [txTmp.ins[inIndex]]
}
analysis.impact = impact;
var buffer = txTmp.serialize()
if (impact.sign > 0 && impact.value.compareTo(BigInteger.ZERO) > 0) {
analysis.type = 'recv';
analysis.addr = new Bitcoin.Address(firstMeRecvHash);
} else if (allFromMe && allToMe) {
analysis.type = 'self';
} else if (allFromMe) {
analysis.type = 'sent';
// TODO: Right now, firstRecvHash is the first output, which - if the
// transaction was not generated by this library could be the
// change address.
analysis.addr = new Bitcoin.Address(firstRecvHash);
} else {
analysis.type = "other";
}
buffer = buffer.concat(convert.numToBytes(parseInt(hashType), 4))
buffer = convert.bytesToWordArray(buffer)
return analysis;
};
return convert.wordArrayToBytes(SHA256(SHA256(buffer)))
}
/**
* Get a human-readable version of the data returned by Transaction#analyze.
*
* This is merely a convenience function. Clients should consider implementing
* this themselves based on their UI, I18N, etc.
*/
Transaction.prototype.getDescription = function (wallet) {
var analysis = this.analyze(wallet);
/**
* Calculate and return the transaction's hash.
* Reverses hash since blockchain.info, blockexplorer.com and others
* use little-endian hashes for some stupid reason
*/
Transaction.prototype.getHash = function ()
{
var buffer = convert.bytesToWordArray(this.serialize())
return convert.wordArrayToBytes(SHA256(SHA256(buffer))).reverse()
}
if (!analysis) return "";
Transaction.prototype.clone = function ()
{
var newTx = new Transaction()
newTx.version = this.version
newTx.locktime = this.locktime
switch (analysis.type) {
case 'recv':
return "Received with "+analysis.addr;
break;
this.ins.forEach(function(txin) {
newTx.addInput(txin.clone())
})
case 'sent':
return "Payment to "+analysis.addr;
break;
this.outs.forEach(function(txout) {
newTx.addOutput(txout.clone())
})
case 'self':
return "Payment to yourself";
break;
return newTx
}
case 'other':
default:
return "";
}
};
Transaction.deserialize = function(buffer) {
if (typeof buffer == "string") {
buffer = convert.hexToBytes(buffer)
}
var pos = 0
var readAsInt = function(bytes) {
if (bytes === 0) return 0;
pos++;
return buffer[pos-1] + readAsInt(bytes-1) * 256
}
var readVarInt = function() {
var bytes = buffer.slice(pos, pos + 9) // maximum possible number of bytes to read
var result = convert.varIntToNum(bytes)
/**
* Get the total amount of a transaction's outputs.
*/
Transaction.prototype.getTotalOutValue = function () {
var totalValue = BigInteger.ZERO;
for (var j = 0; j < this.outs.length; j++) {
var txout = this.outs[j];
totalValue = totalValue.add(Bitcoin.Util.valueToBigInt(txout.value));
}
return totalValue;
};
pos += result.bytes.length
return result.number
}
var readBytes = function(bytes) {
pos += bytes
return buffer.slice(pos - bytes, pos)
}
var readVarString = function() {
var size = readVarInt()
return readBytes(size)
}
var obj = {
ins: [],
outs: []
}
obj.version = readAsInt(4)
var ins = readVarInt()
var i
/**
* Old name for Transaction#getTotalOutValue.
*
* @deprecated
*/
Transaction.prototype.getTotalValue = Transaction.prototype.getTotalOutValue;
for (i = 0; i < ins; i++) {
obj.ins.push({
outpoint: {
hash: convert.bytesToHex(readBytes(32).reverse()),
index: readAsInt(4)
},
script: new Script(readVarString()),
sequence: readBytes(4)
})
}
var outs = readVarInt()
/**
* Calculates the impact a transaction has on this wallet.
*
* Based on the its public keys, the wallet will calculate the
* credit or debit of this transaction.
*
* It will return an object with two properties:
* - sign: 1 or -1 depending on sign of the calculated impact.
* - value: amount of calculated impact
*
* @returns Object Impact on wallet
*/
Transaction.prototype.calcImpact = function (wallet) {
if (!(wallet instanceof Bitcoin.Wallet)) return BigInteger.ZERO;
for (i = 0; i < outs; i++) {
obj.outs.push({
value: convert.bytesToNum(readBytes(8)),
script: new Script(readVarString())
})
}
// Calculate credit to us from all outputs
var valueOut = BigInteger.ZERO;
for (var j = 0; j < this.outs.length; j++) {
var txout = this.outs[j];
var hash = Crypto.util.bytesToBase64(txout.script.simpleOutPubKeyHash());
if (wallet.hasHash(hash)) {
valueOut = valueOut.add(Bitcoin.Util.valueToBigInt(txout.value));
}
}
obj.locktime = readAsInt(4)
// Calculate debit to us from all ins
var valueIn = BigInteger.ZERO;
for (var j = 0; j < this.ins.length; j++) {
var txin = this.ins[j];
var hash = Crypto.util.bytesToBase64(txin.script.simpleInPubKeyHash());
if (wallet.hasHash(hash)) {
var fromTx = wallet.txIndex[txin.outpoint.hash];
if (fromTx) {
valueIn = valueIn.add(Bitcoin.Util.valueToBigInt(fromTx.outs[txin.outpoint.index].value));
}
}
}
if (valueOut.compareTo(valueIn) >= 0) {
return {
sign: 1,
value: valueOut.subtract(valueIn)
};
} else {
return {
sign: -1,
value: valueIn.subtract(valueOut)
};
}
};
return new Transaction(obj)
}
var TransactionIn = Bitcoin.TransactionIn = function (data)
{
this.outpoint = data.outpoint;
if (data.script instanceof Script) {
this.script = data.script;
} else {
this.script = new Script(data.script);
}
this.sequence = data.sequence;
};
/**
* Signs a standard output at some index with the given key
*/
Transaction.prototype.sign = function(index, key, type) {
type = type || SIGHASH_ALL
key = new ECKey(key)
TransactionIn.prototype.clone = function ()
{
var newTxin = new TransactionIn({
outpoint: {
hash: this.outpoint.hash,
index: this.outpoint.index
},
script: this.script.clone(),
sequence: this.sequence
});
return newTxin;
};
// TODO: getPub is slow, sha256ripe160 probably is too.
// This could be sped up a lot by providing these as inputs.
var pub = key.getPub().toBytes(),
hash160 = util.sha256ripe160(pub),
script = Script.createOutputScript(new Address(hash160)),
hash = this.hashTransactionForSignature(script, index, type),
sig = key.sign(hash).concat([type])
this.ins[index].script = Script.createInputScript(sig, pub)
}
var TransactionOut = Bitcoin.TransactionOut = function (data)
{
if (data.script instanceof Script) {
this.script = data.script;
} else {
this.script = new Script(data.script);
}
// Takes outputs of the form [{ output: 'txhash:index', address: 'address' },...]
Transaction.prototype.signWithKeys = function(keys, outputs, type) {
type = type || SIGHASH_ALL
if (Bitcoin.Util.isArray(data.value)) {
this.value = data.value;
} else if ("string" == typeof data.value) {
var valueHex = (new BigInteger(data.value, 10)).toString(16);
while (valueHex.length < 16) valueHex = "0" + valueHex;
this.value = Crypto.util.hexToBytes(valueHex);
var addrdata = keys.map(function(key) {
key = new ECKey(key)
return {
key: key,
address: key.getAddress().toString()
}
};
})
TransactionOut.prototype.clone = function ()
{
var newTxout = new TransactionOut({
script: this.script.clone(),
value: this.value.slice(0)
});
return newTxout;
};
})();
var hmap = {}
outputs.forEach(function(o) {
hmap[o.output] = o
})
for (var i = 0; i < this.ins.length; i++) {
var outpoint = this.ins[i].outpoint.hash + ':' + this.ins[i].outpoint.index
var histItem = hmap[outpoint]
if (!histItem) continue;
var thisInputAddrdata = addrdata.filter(function(a) {
return a.address == histItem.address
})
if (thisInputAddrdata.length === 0) continue;
this.sign(i,thisInputAddrdata[0].key)
}
}
/**
* Signs a P2SH output at some index with the given key
*/
Transaction.prototype.p2shsign = function(index, script, key, type) {
script = new Script(script)
key = new ECKey(key)
type = type || SIGHASH_ALL
var hash = this.hashTransactionForSignature(script, index, type),
sig = key.sign(hash).concat([type])
return sig
}
Transaction.prototype.multisign = Transaction.prototype.p2shsign
Transaction.prototype.applyMultisigs = function(index, script, sigs/*, type*/) {
this.ins[index].script = Script.createMultiSigInputScript(sigs, script)
}
Transaction.prototype.validateSig = function(index, script, sig, pub) {
script = new Script(script)
var hash = this.hashTransactionForSignature(script,index,1)
return ECDSA.verify(hash, convert.coerceToBytes(sig),
convert.coerceToBytes(pub))
}
Transaction.feePerKb = 20000
Transaction.prototype.estimateFee = function(feePerKb){
var uncompressedInSize = 180
var outSize = 34
var fixedPadding = 34
if(feePerKb == undefined) feePerKb = Transaction.feePerKb;
var size = this.ins.length * uncompressedInSize + this.outs.length * outSize + fixedPadding
return feePerKb * Math.ceil(size / 1000)
}
var TransactionIn = function (data) {
if (typeof data == "string") {
this.outpoint = { hash: data.split(':')[0], index: data.split(':')[1] }
} else if (data.outpoint) {
this.outpoint = data.outpoint
} else {
this.outpoint = { hash: data.hash, index: data.index }
}
if (data.scriptSig) {
this.script = Script.fromScriptSig(data.scriptSig)
} else if (data.script) {
this.script = data.script
} else {
this.script = new Script(data.script)
}
this.sequence = data.sequence || this.defaultSequence
}
TransactionIn.prototype.clone = function () {
return new TransactionIn({
outpoint: {
hash: this.outpoint.hash,
index: this.outpoint.index
},
script: this.script.clone(),
sequence: this.sequence
})
}
var TransactionOut = function (data) {
this.script =
data.script instanceof Script ? data.script.clone()
: Array.isArray(data.script) ? new Script(data.script)
: typeof data.script == "string" ? new Script(convert.hexToBytes(data.script))
: data.scriptPubKey ? Script.fromScriptSig(data.scriptPubKey)
: data.address ? Script.createOutputScript(data.address)
: new Script()
if (this.script.buffer.length > 0) this.address = this.script.getToAddress();
this.value =
Array.isArray(data.value) ? convert.bytesToNum(data.value)
: "string" == typeof data.value ? parseInt(data.value)
: data.value instanceof BigInteger ? parseInt(data.value.toString())
: data.value
}
TransactionOut.prototype.clone = function() {
var newTxout = new TransactionOut({
script: this.script.clone(),
value: this.value
})
return newTxout
}
TransactionOut.prototype.scriptPubKey = function() {
return convert.bytesToHex(this.script.buffer)
}
module.exports = {
Transaction: Transaction,
TransactionIn: TransactionIn,
TransactionOut: TransactionOut
}

@@ -1,228 +0,13 @@

// BigInteger monkey patching
BigInteger.valueOf = nbv;
var convert = require('./convert.js')
var Crypto = require('crypto-js')
var RIPEMD160 = Crypto.RIPEMD160
var SHA256 = Crypto.SHA256
/**
* Returns a byte array representation of the big integer.
*
* This returns the absolute of the contained value in big endian
* form. A value of zero results in an empty array.
*/
BigInteger.prototype.toByteArrayUnsigned = function () {
var ba = this.abs().toByteArray();
if (ba.length) {
if (ba[0] == 0) {
ba = ba.slice(1);
}
return ba.map(function (v) {
return (v < 0) ? v + 256 : v;
});
} else {
// Empty array, nothing to do
return ba;
}
};
exports.sha256ripe160 = function (data) {
var wordArray = RIPEMD160(SHA256(convert.bytesToWordArray(data)))
return convert.wordArrayToBytes(wordArray)
}
/**
* Turns a byte array into a big integer.
*
* This function will interpret a byte array as a big integer in big
* endian notation and ignore leading zeros.
*/
BigInteger.fromByteArrayUnsigned = function (ba) {
if (!ba.length) {
return ba.valueOf(0);
} else if (ba[0] & 0x80) {
// Prepend a zero so the BigInteger class doesn't mistake this
// for a negative integer.
return new BigInteger([0].concat(ba));
} else {
return new BigInteger(ba);
}
};
/**
* Converts big integer to signed byte representation.
*
* The format for this value uses a the most significant bit as a sign
* bit. If the most significant bit is already occupied by the
* absolute value, an extra byte is prepended and the sign bit is set
* there.
*
* Examples:
*
* 0 => 0x00
* 1 => 0x01
* -1 => 0x81
* 127 => 0x7f
* -127 => 0xff
* 128 => 0x0080
* -128 => 0x8080
* 255 => 0x00ff
* -255 => 0x80ff
* 16300 => 0x3fac
* -16300 => 0xbfac
* 62300 => 0x00f35c
* -62300 => 0x80f35c
*/
BigInteger.prototype.toByteArraySigned = function () {
var val = this.abs().toByteArrayUnsigned();
var neg = this.compareTo(BigInteger.ZERO) < 0;
if (neg) {
if (val[0] & 0x80) {
val.unshift(0x80);
} else {
val[0] |= 0x80;
}
} else {
if (val[0] & 0x80) {
val.unshift(0x00);
}
}
return val;
};
/**
* Parse a signed big integer byte representation.
*
* For details on the format please see BigInteger.toByteArraySigned.
*/
BigInteger.fromByteArraySigned = function (ba) {
// Check for negative value
if (ba[0] & 0x80) {
// Remove sign bit
ba[0] &= 0x7f;
return BigInteger.fromByteArrayUnsigned(ba).negate();
} else {
return BigInteger.fromByteArrayUnsigned(ba);
}
};
// Console ignore
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count",
"trace", "profile", "profileEnd"];
if ("undefined" == typeof window.console) window.console = {};
for (var i = 0; i < names.length; ++i)
if ("undefined" == typeof window.console[names[i]])
window.console[names[i]] = function() {};
// Bitcoin utility functions
Bitcoin.Util = {
/**
* Cross-browser compatibility version of Array.isArray.
*/
isArray: Array.isArray || function(o)
{
return Object.prototype.toString.call(o) === '[object Array]';
},
/**
* Create an array of a certain length filled with a specific value.
*/
makeFilledArray: function (len, val)
{
var array = [];
var i = 0;
while (i < len) {
array[i++] = val;
}
return array;
},
/**
* Turn an integer into a "var_int".
*
* "var_int" is a variable length integer used by Bitcoin's binary format.
*
* Returns a byte array.
*/
numToVarInt: function (i)
{
if (i < 0xfd) {
// unsigned char
return [i];
} else if (i <= 1<<16) {
// unsigned short (LE)
return [0xfd, i >>> 8, i & 255];
} else if (i <= 1<<32) {
// unsigned int (LE)
return [0xfe].concat(Crypto.util.wordsToBytes([i]));
} else {
// unsigned long long (LE)
return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
}
},
/**
* Parse a Bitcoin value byte array, returning a BigInteger.
*/
valueToBigInt: function (valueBuffer)
{
if (valueBuffer instanceof BigInteger) return valueBuffer;
// Prepend zero byte to prevent interpretation as negative integer
return BigInteger.fromByteArrayUnsigned(valueBuffer);
},
/**
* Format a Bitcoin value as a string.
*
* Takes a BigInteger or byte-array and returns that amount of Bitcoins in a
* nice standard formatting.
*
* Examples:
* 12.3555
* 0.1234
* 900.99998888
* 34.00
*/
formatValue: function (valueBuffer) {
var value = this.valueToBigInt(valueBuffer).toString();
var integerPart = value.length > 8 ? value.substr(0, value.length-8) : '0';
var decimalPart = value.length > 8 ? value.substr(value.length-8) : value;
while (decimalPart.length < 8) decimalPart = "0"+decimalPart;
decimalPart = decimalPart.replace(/0*$/, '');
while (decimalPart.length < 2) decimalPart += "0";
return integerPart+"."+decimalPart;
},
/**
* Parse a floating point string as a Bitcoin value.
*
* Keep in mind that parsing user input is messy. You should always display
* the parsed value back to the user to make sure we understood his input
* correctly.
*/
parseValue: function (valueString) {
// TODO: Detect other number formats (e.g. comma as decimal separator)
var valueComp = valueString.split('.');
var integralPart = valueComp[0];
var fractionalPart = valueComp[1] || "0";
while (fractionalPart.length < 8) fractionalPart += "0";
fractionalPart = fractionalPart.replace(/^0+/g, '');
var value = BigInteger.valueOf(parseInt(integralPart));
value = value.multiply(BigInteger.valueOf(100000000));
value = value.add(BigInteger.valueOf(parseInt(fractionalPart)));
return value;
},
/**
* Calculate RIPEMD160(SHA256(data)).
*
* Takes an arbitrary byte array as inputs and returns the hash as a byte
* array.
*/
sha256ripe160: function (data) {
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true});
}
};
for (var i in Crypto.util) {
if (Crypto.util.hasOwnProperty(i)) {
Bitcoin.Util[i] = Crypto.util[i];
}
exports.error = function (msg) {
throw new Error(msg)
}

@@ -1,308 +0,311 @@

Bitcoin.Wallet = (function () {
var Script = Bitcoin.Script,
TransactionIn = Bitcoin.TransactionIn,
TransactionOut = Bitcoin.TransactionOut;
var convert = require('./convert')
var Transaction = require('./transaction').Transaction
var HDNode = require('./hdwallet.js')
var rng = require('secure-random')
var Wallet = function () {
// Keychain
//
// The keychain is stored as a var in this closure to make accidental
// serialization less likely.
//
// Any functions accessing this value therefore have to be defined in
// the closure of this constructor.
var keys = [];
function Wallet(seed, options) {
if (!(this instanceof Wallet)) { return new Wallet(seed, options); }
// Public hashes of our keys
this.addressHashes = [];
var options = options || {}
var network = options.network || 'mainnet'
// Transaction data
this.txIndex = {};
this.unspentOuts = [];
// Stored in a closure to make accidental serialization less likely
var masterkey = null
var me = this
var accountZero = null
var internalAccount = null
var externalAccount = null
// Other fields
this.addressPointer = 0;
// Addresses
this.addresses = []
this.changeAddresses = []
/**
* Add a key to the keychain.
*
* The corresponding public key can be provided as a second parameter. This
* adds it to the cache in the ECKey object and avoid the need to
* expensively calculate it later.
*/
this.addKey = function (key, pub) {
if (!(key instanceof Bitcoin.ECKey)) {
key = new Bitcoin.ECKey(key);
}
keys.push(key);
// Transaction output data
this.outputs = {}
if (pub) {
if ("string" === typeof pub) {
pub = Crypto.util.base64ToBytes(pub);
}
key.setPub(pub);
}
// Make a new master key
this.newMasterKey = function(seed, network) {
if (!seed) seed = rng(32, { array: true });
masterkey = new HDNode(seed, network)
this.addressHashes.push(key.getBitcoinAddress().getHashBase64());
};
// HD first-level child derivation method should be private
// See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
accountZero = masterkey.derivePrivate(0)
externalAccount = accountZero.derive(0)
internalAccount = accountZero.derive(1)
/**
* Add multiple keys at once.
*/
this.addKeys = function (keys, pubs) {
if ("string" === typeof keys) {
keys = keys.split(',');
}
if ("string" === typeof pubs) {
pubs = pubs.split(',');
}
var i;
if (Array.isArray(pubs) && keys.length == pubs.length) {
for (i = 0; i < keys.length; i++) {
this.addKey(keys[i], pubs[i]);
}
} else {
for (i = 0; i < keys.length; i++) {
this.addKey(keys[i]);
}
}
};
me.addresses = []
me.changeAddresses = []
/**
* Get the key chain.
*
* Returns an array of base64-encoded private values.
*/
this.getKeys = function () {
var serializedWallet = [];
me.outputs = {}
}
this.newMasterKey(seed, network)
for (var i = 0; i < keys.length; i++) {
serializedWallet.push(keys[i].toString('base64'));
}
return serializedWallet;
};
this.generateAddress = function() {
var key = externalAccount.derive(this.addresses.length)
this.addresses.push(key.getAddress().toString())
return this.addresses[this.addresses.length - 1]
}
/**
* Get the public keys.
*
* Returns an array of base64-encoded public keys.
*/
this.getPubKeys = function () {
var pubs = [];
this.generateChangeAddress = function() {
var key = internalAccount.derive(this.changeAddresses.length)
this.changeAddresses.push(key.getAddress().toString())
return this.changeAddresses[this.changeAddresses.length - 1]
}
for (var i = 0; i < keys.length; i++) {
pubs.push(Crypto.util.bytesToBase64(keys[i].getPub()));
}
this.getBalance = function() {
return this.getUnspentOutputs().reduce(function(memo, output){
return memo + output.value
}, 0)
}
return pubs;
};
this.getUnspentOutputs = function() {
var utxo = []
/**
* Delete all keys.
*/
this.clear = function () {
keys = [];
};
for(var key in this.outputs){
var output = this.outputs[key]
if(!output.spend) utxo.push(outputToUnspentOutput(output))
}
/**
* Return the number of keys in this wallet.
*/
this.getLength = function () {
return keys.length;
};
return utxo
}
/**
* Get the addresses for this wallet.
*
* Returns an array of Address objects.
*/
this.getAllAddresses = function () {
var addresses = [];
for (var i = 0; i < keys.length; i++) {
addresses.push(keys[i].getBitcoinAddress());
}
return addresses;
};
this.setUnspentOutputs = function(utxo) {
var outputs = {}
this.getCurAddress = function () {
if (keys[this.addressPointer]) {
return keys[this.addressPointer].getBitcoinAddress();
} else {
return null;
}
};
utxo.forEach(function(uo){
validateUnspentOutput(uo)
var o = unspentOutputToOutput(uo)
outputs[o.receive] = o
})
/**
* Go to the next address.
*
* If there are no more new addresses available, one will be generated
* automatically.
*/
this.getNextAddress = function () {
this.addressPointer++;
if (!keys[this.addressPointer]) {
this.generateAddress();
this.outputs = outputs
}
this.setUnspentOutputsAsync = function(utxo, callback) {
var error = null
try {
this.setUnspentOutputs(utxo)
} catch(err) {
error = err
} finally {
process.nextTick(function(){ callback(error) })
}
}
function outputToUnspentOutput(output){
var hashAndIndex = output.receive.split(":")
return {
hash: hashAndIndex[0],
hashLittleEndian: convert.reverseEndian(hashAndIndex[0]),
outputIndex: parseInt(hashAndIndex[1]),
address: output.address,
value: output.value
}
}
function unspentOutputToOutput(o) {
var hash = o.hash || convert.reverseEndian(o.hashLittleEndian)
var key = hash + ":" + o.outputIndex
return {
receive: key,
address: o.address,
value: o.value
}
}
function validateUnspentOutput(uo) {
var missingField
if (isNullOrUndefined(uo.hash) && isNullOrUndefined(uo.hashLittleEndian)) {
missingField = "hash(or hashLittleEndian)"
}
var requiredKeys = ['outputIndex', 'address', 'value']
requiredKeys.forEach(function (key) {
if (isNullOrUndefined(uo[key])){
missingField = key
}
return keys[this.addressPointer].getBitcoinAddress();
};
})
/**
* Sign a hash with a key.
*
* This method expects the pubKeyHash as the first parameter and the hash
* to be signed as the second parameter.
*/
this.signWithKey = function (pubKeyHash, hash) {
pubKeyHash = Crypto.util.bytesToBase64(pubKeyHash);
for (var i = 0; i < this.addressHashes.length; i++) {
if (this.addressHashes[i] == pubKeyHash) {
return keys[i].sign(hash);
if (missingField) {
var message = [
'Invalid unspent output: key', missingField, 'is missing.',
'A valid unspent output must contain'
]
message.push(requiredKeys.join(', '))
message.push("and hash(or hashLittleEndian)")
throw new Error(message.join(' '))
}
}
function isNullOrUndefined(value) {
return value == undefined
}
this.processTx = function(tx) {
var txhash = convert.bytesToHex(tx.getHash())
tx.outs.forEach(function(txOut, i){
var address = txOut.address.toString()
if (isMyAddress(address)) {
var output = txhash+':'+i
me.outputs[output] = {
receive: output,
value: txOut.value,
address: address,
}
}
throw new Error("Missing key for signature");
};
})
/**
* Retrieve the corresponding pubKey for a pubKeyHash.
*
* This function only works if the pubKey in question is part of this
* wallet.
*/
this.getPubKeyFromHash = function (pubKeyHash) {
pubKeyHash = Crypto.util.bytesToBase64(pubKeyHash);
for (var i = 0; i < this.addressHashes.length; i++) {
if (this.addressHashes[i] == pubKeyHash) {
return keys[i].getPub();
}
tx.ins.forEach(function(txIn, i){
var op = txIn.outpoint
var o = me.outputs[op.hash+':'+op.index]
if (o) {
o.spend = txhash+':'+i
}
throw new Error("Hash unknown");
};
};
})
}
Wallet.prototype.generateAddress = function () {
this.addKey(new Bitcoin.ECKey());
};
this.createTx = function(to, value, fixedFee) {
checkDust(value)
/**
* Add a transaction to the wallet's processed transaction.
*
* This will add a transaction to the wallet, updating its balance and
* available unspent outputs.
*/
Wallet.prototype.process = function (tx) {
if (this.txIndex[tx.hash]) return;
var tx = new Transaction()
tx.addOutput(to, value)
var j;
var k;
var hash;
// Gather outputs
for (j = 0; j < tx.outs.length; j++) {
var txout = new TransactionOut(tx.outs[j]);
hash = Crypto.util.bytesToBase64(txout.script.simpleOutPubKeyHash());
for (k = 0; k < this.addressHashes.length; k++) {
if (this.addressHashes[k] === hash) {
this.unspentOuts.push({tx: tx, index: j, out: txout});
break;
}
}
}
var utxo = getCandidateOutputs(value)
var totalInValue = 0
for(var i=0; i<utxo.length; i++){
var output = utxo[i]
tx.addInput(output.receive)
// Remove spent outputs
for (j = 0; j < tx.ins.length; j++) {
var txin = new TransactionIn(tx.ins[j]);
var pubkey = txin.script.simpleInPubKey();
hash = Crypto.util.bytesToBase64(Bitcoin.Util.sha256ripe160(pubkey));
for (k = 0; k < this.addressHashes.length; k++) {
if (this.addressHashes[k] === hash) {
for (var l = 0; l < this.unspentOuts.length; l++) {
if (txin.outpoint.hash == this.unspentOuts[l].tx.hash &&
txin.outpoint.index == this.unspentOuts[l].index) {
this.unspentOuts.splice(l, 1);
}
}
break;
}
totalInValue += output.value
if(totalInValue < value) continue
var fee = fixedFee == undefined ? estimateFeePadChangeOutput(tx) : fixedFee
if(totalInValue < value + fee) continue
var change = totalInValue - value - fee
if(change > 0 && !isDust(change)) {
tx.addOutput(getChangeAddress(), change)
}
break
}
// Index transaction
this.txIndex[tx.hash] = tx;
};
checkInsufficientFund(totalInValue, value, fee)
Wallet.prototype.getBalance = function () {
var balance = BigInteger.valueOf(0);
for (var i = 0; i < this.unspentOuts.length; i++) {
var txout = this.unspentOuts[i].out;
balance = balance.add(Bitcoin.Util.valueToBigInt(txout.value));
}
return balance;
};
this.sign(tx)
Wallet.prototype.createSend = function (address, sendValue, feeValue) {
var selectedOuts = [];
var txValue = sendValue.add(feeValue);
var availableValue = BigInteger.ZERO;
var i;
for (i = 0; i < this.unspentOuts.length; i++) {
selectedOuts.push(this.unspentOuts[i]);
availableValue = availableValue.add(Bitcoin.Util.valueToBigInt(this.unspentOuts[i].out.value));
return tx
}
if (availableValue.compareTo(txValue) >= 0) break;
this.createTxAsync = function(to, value, fixedFee, callback){
if(fixedFee instanceof Function) {
callback = fixedFee
fixedFee = undefined
}
var tx = null
var error = null
if (availableValue.compareTo(txValue) < 0) {
throw new Error('Insufficient funds.');
try {
tx = this.createTx(to, value, fixedFee)
} catch(err) {
error = err
} finally {
process.nextTick(function(){ callback(error, tx) })
}
}
this.dustThreshold = 5430
function isDust(amount) {
return amount <= me.dustThreshold
}
var changeValue = availableValue.subtract(txValue);
var sendTx = new Bitcoin.Transaction();
for (i = 0; i < selectedOuts.length; i++) {
sendTx.addInput(selectedOuts[i].tx, selectedOuts[i].index);
function checkDust(value){
if (isNullOrUndefined(value) || isDust(value)) {
throw new Error("Value must be above dust threshold")
}
}
sendTx.addOutput(address, sendValue);
if (changeValue.compareTo(BigInteger.ZERO) > 0) {
sendTx.addOutput(this.getNextAddress(), changeValue);
function getCandidateOutputs(value){
var unspent = []
for (var key in me.outputs){
var output = me.outputs[key]
if(!output.spend) unspent.push(output)
}
var hashType = 1; // SIGHASH_ALL
var sortByValueDesc = unspent.sort(function(o1, o2){
return o2.value - o1.value
})
for (i = 0; i < sendTx.ins.length; i++) {
var hash = sendTx.hashTransactionForSignature(selectedOuts[i].out.script, i, hashType);
var pubKeyHash = selectedOuts[i].out.script.simpleOutPubKeyHash();
var signature = this.signWithKey(pubKeyHash, hash);
return sortByValueDesc
}
// Append hash type
signature.push(parseInt(hashType, 10));
function estimateFeePadChangeOutput(tx){
var tmpTx = tx.clone()
tmpTx.addOutput(getChangeAddress(), 0)
return tmpTx.estimateFee()
}
sendTx.ins[i].script = Script.createInputScript(signature, this.getPubKeyFromHash(pubKeyHash));
function getChangeAddress() {
if(me.changeAddresses.length === 0) me.generateChangeAddress();
return me.changeAddresses[me.changeAddresses.length - 1]
}
function checkInsufficientFund(totalInValue, value, fee) {
if(totalInValue < value + fee) {
throw new Error('Not enough money to send funds including transaction fee. Have: ' +
totalInValue + ', needed: ' + (value + fee))
}
}
return sendTx;
};
this.sign = function(tx) {
tx.ins.forEach(function(inp,i) {
var output = me.outputs[inp.outpoint.hash + ':' + inp.outpoint.index]
if (output) {
tx.sign(i, me.getPrivateKeyForAddress(output.address))
}
})
return tx
}
Wallet.prototype.clearTransactions = function () {
this.txIndex = {};
this.unspentOuts = [];
};
this.getMasterKey = function() { return masterkey }
this.getAccountZero = function() { return accountZero }
this.getInternalAccount = function() { return internalAccount }
this.getExternalAccount = function() { return externalAccount }
/**
* Check to see if a pubKeyHash belongs to this wallet.
*/
Wallet.prototype.hasHash = function (hash) {
if (Bitcoin.Util.isArray(hash)) hash = Crypto.util.bytesToBase64(hash);
this.getPrivateKey = function(index) {
return externalAccount.derive(index).priv
}
// TODO: Just create an object with base64 hashes as keys for faster lookup
for (var k = 0; k < this.addressHashes.length; k++) {
if (this.addressHashes[k] === hash) return true;
this.getInternalPrivateKey = function(index) {
return internalAccount.derive(index).priv
}
this.getPrivateKeyForAddress = function(address) {
var index
if((index = this.addresses.indexOf(address)) > -1) {
return this.getPrivateKey(index)
} else if((index = this.changeAddresses.indexOf(address)) > -1) {
return this.getInternalPrivateKey(index)
} else {
throw new Error('Unknown address. Make sure the address is from the keychain and has been generated.')
}
return false;
};
}
return Wallet;
})();
function isReceiveAddress(address){
return me.addresses.indexOf(address) > -1
}
function isChangeAddress(address){
return me.changeAddresses.indexOf(address) > -1
}
function isMyAddress(address) {
return isReceiveAddress(address) || isChangeAddress(address)
}
}
module.exports = Wallet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc