Added some transaction methods, and removed all internal use of base64

This commit is contained in:
vub 2013-10-07 15:27:19 -04:00
parent 9922864da4
commit e43d23235b
10 changed files with 107 additions and 41 deletions

6
bitcoinjs-min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -35,8 +35,8 @@ Address.prototype.toString = function () {
return base58.checkEncode(hash,this.version); return base58.checkEncode(hash,this.version);
}; };
Address.prototype.getHashBase64 = function () { Address.prototype.getHash = function () {
return conv.bytesToBase64(this.hash); return conv.bytesToHex(this.hash);
}; };
Address.getVersion = function(string) { Address.getVersion = function(string) {

View file

@ -2,6 +2,7 @@
// https://en.bitcoin.it/wiki/Base58Check_encoding // https://en.bitcoin.it/wiki/Base58Check_encoding
var BigInteger = require('./jsbn/jsbn'); var BigInteger = require('./jsbn/jsbn');
var Crypto = require('./crypto-js/crypto');
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
var base = BigInteger.valueOf(58); var base = BigInteger.valueOf(58);
@ -36,6 +37,10 @@ module.exports.encode = function (input) {
return chars.reverse().join(''); return chars.reverse().join('');
}, },
module.exports.encodeHex = function (input) {
return Crypto.util.bytesToHex(module.exports.encode(input));
}
// decode a base58 string into a byte array // decode a base58 string into a byte array
// input should be a base58 encoded string // input should be a base58 encoded string
// @return Array // @return Array
@ -76,16 +81,24 @@ module.exports.decode = function (input) {
return bytes; return bytes;
} }
module.exports.checkEncode = function(x,vbyte,format) { module.exports.decodeHex = function (input) {
return module.exports.decode(Crypto.util.hexToBytes(input));
}
module.exports.checkEncode = function(input, vbyte) {
vbyte = vbyte || 0; vbyte = vbyte || 0;
var front = [vbyte].concat(x); var front = [vbyte].concat(input);
var checksum = Crypto.SHA256(Crypto.SHA256(front, {asBytes: true}), {asBytes: true}) var checksum = Crypto.SHA256(Crypto.SHA256(front, {asBytes: true}), {asBytes: true})
.slice(0,4); .slice(0,4);
return module.exports.encode(front.concat(checksum)); return module.exports.encode(front.concat(checksum));
} }
module.exports.checkDecode = function(x) { module.exports.checkEncodeHex = function (input, vbyte) {
var bytes = module.exports.decode(x), return Crypto.util.bytesToHex(module.exports.encode(input));
}
module.exports.checkDecode = function(input) {
var bytes = module.exports.decode(input),
front = bytes.slice(0,bytes.length-4), front = bytes.slice(0,bytes.length-4),
back = bytes.slice(bytes.length-4); back = bytes.slice(bytes.length-4);
var checksum = Crypto.SHA256(Crypto.SHA256(front,{asBytes: true}), {asBytes: true}) var checksum = Crypto.SHA256(Crypto.SHA256(front,{asBytes: true}), {asBytes: true})
@ -98,4 +111,8 @@ module.exports.checkDecode = function(x) {
return o; return o;
} }
module.exports.checkDecodeHex = function (input) {
return module.exports.checkDecode(Crypto.util.hexToBytes(input));
}

View file

@ -22,9 +22,9 @@
buffer = buffer.concat(numToVarInt(tx.ins.length)); buffer = buffer.concat(numToVarInt(tx.ins.length));
for (var i = 0; i < tx.ins.length; i++) { for (var i = 0; i < tx.ins.length; i++) {
var txin = tx.ins[i]; var txin = tx.ins[i];
buffer = buffer.concat(Crypto.util.base64ToBytes(txin.outpoint.hash)); buffer = buffer.concat(Crypto.util.hexToBytes(txin.outpoint.hash));
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.index)])); buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.index)]));
var scriptBytes = Crypto.util.base64ToBytes(txin.script); var scriptBytes = Crypto.util.hexToBytes(txin.script);
buffer = buffer.concat(numToVarInt(scriptBytes.length)); buffer = buffer.concat(numToVarInt(scriptBytes.length));
buffer = buffer.concat(scriptBytes); buffer = buffer.concat(scriptBytes);
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.sequence)])); buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.sequence)]));
@ -35,7 +35,7 @@
var valueHex = (new BigInteger(txout.value, 10)).toString(16); var valueHex = (new BigInteger(txout.value, 10)).toString(16);
while (valueHex.length < 16) valueHex = "0" + valueHex; while (valueHex.length < 16) valueHex = "0" + valueHex;
buffer = buffer.concat(Crypto.util.hexToBytes(valueHex)); buffer = buffer.concat(Crypto.util.hexToBytes(valueHex));
var scriptBytes = Crypto.util.base64ToBytes(txout.script); var scriptBytes = Crypto.util.hexToBytes(txout.script);
buffer = buffer.concat(numToVarInt(scriptBytes.length)); buffer = buffer.concat(numToVarInt(scriptBytes.length));
buffer = buffer.concat(scriptBytes); buffer = buffer.concat(scriptBytes);
} }
@ -64,9 +64,9 @@
// Blank out other inputs' signatures // Blank out other inputs' signatures
for (var i = 0; i < txTmp.ins.length; i++) { for (var i = 0; i < txTmp.ins.length; i++) {
txTmp.ins[i].script = Crypto.util.bytesToBase64([]); txTmp.ins[i].script = Crypto.util.bytesToHex([]);
} }
txTmp.ins[inIndex].script = Crypto.util.bytesToBase64(scriptCode); txTmp.ins[inIndex].script = Crypto.util.bytesToHex(scriptCode);
// Blank out some of the outputs // Blank out some of the outputs
if ((hashType & 0x1f) == SIGHASH_NONE) { if ((hashType & 0x1f) == SIGHASH_NONE) {

View file

@ -40,11 +40,13 @@ var ECKey = function (input) {
this.compressed = true; this.compressed = true;
} else { } else {
// hex string? // hex string?
// //wtf is base64 here for?
// Prepend zero byte to prevent interpretation as negative integer // Prepend zero byte to prevent interpretation as negative integer
this.priv = BigInteger.fromByteArrayUnsigned(conv.base64ToBytes(input)); this.priv = BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(input));
} }
} }
else if (input.constructor == [].constructor) {
this.priv = BigInteger.fromByteArrayUnsigned(input);
}
}; };
// TODO(shtylman) methods // TODO(shtylman) methods
@ -116,8 +118,8 @@ ECKey.prototype.setPub = function (pub) {
}; };
ECKey.prototype.toString = function (format) { ECKey.prototype.toString = function (format) {
if (format === "base64") { if (format === "base58") {
return conv.bytesToBase64(this.priv.toByteArrayUnsigned()); return base58.checkEncode(this.priv.toByteArrayUnsigned(),128);
} else { } else {
return Crypto.util.bytesToHex(this.priv.toByteArrayUnsigned()); return Crypto.util.bytesToHex(this.priv.toByteArrayUnsigned());
} }

View file

@ -27,6 +27,7 @@ module.exports = {
Key: require('./eckey'), Key: require('./eckey'),
Message: require('./message'), Message: require('./message'),
BigInteger: require('./jsbn/jsbn'), BigInteger: require('./jsbn/jsbn'),
Crypto: require('./crypto-js/crypto'),
Script: require('./script'), Script: require('./script'),
Opcode: require('./opcode'), Opcode: require('./opcode'),
Transaction: require('./transaction').Transaction, Transaction: require('./transaction').Transaction,

View file

@ -49,11 +49,11 @@ Message.signMessage = function (key, message, compressed) {
sig = [i].concat(rBa).concat(sBa); sig = [i].concat(rBa).concat(sBa);
return conv.bytesToBase64(sig); return conv.bytesToHex(sig);
}; };
Message.verifyMessage = function (address, sig, message) { Message.verifyMessage = function (address, sig, message) {
sig = conv.base64ToBytes(sig); sig = conv.hexToBytes(sig);
sig = ecdsa.parseSigCompact(sig); sig = ecdsa.parseSigCompact(sig);
var hash = Message.getHash(message); var hash = Message.getHash(message);

View file

@ -6,7 +6,7 @@ var Script = function (data) {
if (!data) { if (!data) {
this.buffer = []; this.buffer = [];
} else if ("string" == typeof data) { } else if ("string" == typeof data) {
this.buffer = Crypto.util.base64ToBytes(data); this.buffer = Crypto.util.hexToBytes(data);
} else if (util.isArray(data)) { } else if (util.isArray(data)) {
this.buffer = data; this.buffer = data;
} else if (data instanceof Script) { } else if (data instanceof Script) {

View file

@ -85,7 +85,7 @@ Transaction.prototype.addOutput = function (address, value) {
if (value instanceof BigInteger) { if (value instanceof BigInteger) {
value = value.toByteArrayUnsigned().reverse(); value = value.toByteArrayUnsigned().reverse();
while (value.length < 8) value.push(0); while (value.length < 8) value.push(0);
} else if (Bitcoin.Util.isArray(value)) { } else if (util.isArray(value)) {
// Nothing to do // Nothing to do
} }
@ -351,7 +351,7 @@ Transaction.prototype.getTotalOutValue = function () {
var totalValue = BigInteger.ZERO; var totalValue = BigInteger.ZERO;
for (var j = 0; j < this.outs.length; j++) { for (var j = 0; j < this.outs.length; j++) {
var txout = this.outs[j]; var txout = this.outs[j];
totalValue = totalValue.add(Bitcoin.Util.valueToBigInt(txout.value)); totalValue = totalValue.add(util.valueToBigInt(txout.value));
} }
return totalValue; return totalValue;
}; };
@ -382,9 +382,9 @@ Transaction.prototype.calcImpact = function (wallet) {
var valueOut = BigInteger.ZERO; var valueOut = BigInteger.ZERO;
for (var j = 0; j < this.outs.length; j++) { for (var j = 0; j < this.outs.length; j++) {
var txout = this.outs[j]; var txout = this.outs[j];
var hash = Crypto.util.bytesToBase64(txout.script.simpleOutPubKeyHash()); var hash = Crypto.util.bytesToHex(txout.script.simpleOutPubKeyHash());
if (wallet.hasHash(hash)) { if (wallet.hasHash(hash)) {
valueOut = valueOut.add(Bitcoin.Util.valueToBigInt(txout.value)); valueOut = valueOut.add(util.valueToBigInt(txout.value));
} }
} }
@ -392,11 +392,11 @@ Transaction.prototype.calcImpact = function (wallet) {
var valueIn = BigInteger.ZERO; var valueIn = BigInteger.ZERO;
for (var j = 0; j < this.ins.length; j++) { for (var j = 0; j < this.ins.length; j++) {
var txin = this.ins[j]; var txin = this.ins[j];
var hash = Crypto.util.bytesToBase64(txin.script.simpleInPubKeyHash()); var hash = Crypto.util.bytesToHex(txin.script.simpleInPubKeyHash());
if (wallet.hasHash(hash)) { if (wallet.hasHash(hash)) {
var fromTx = wallet.txIndex[txin.outpoint.hash]; var fromTx = wallet.txIndex[txin.outpoint.hash];
if (fromTx) { if (fromTx) {
valueIn = valueIn.add(Bitcoin.Util.valueToBigInt(fromTx.outs[txin.outpoint.index].value)); valueIn = valueIn.add(util.valueToBigInt(fromTx.outs[txin.outpoint.index].value));
} }
} }
} }
@ -412,6 +412,11 @@ Transaction.prototype.calcImpact = function (wallet) {
}; };
} }
}; };
/**
* Converts a serialized transaction into a transaction object
*/
Transaction.deserialize = function(buffer) { Transaction.deserialize = function(buffer) {
var pos = 0; var pos = 0;
var readAsInt = function(bytes) { var readAsInt = function(bytes) {
@ -443,7 +448,7 @@ Transaction.deserialize = function(buffer) {
for (var i = 0; i < ins; i++) { for (var i = 0; i < ins; i++) {
obj.ins.push({ obj.ins.push({
outpoint: { outpoint: {
hash: Bitcoin.Util.bytesToBase64(readBytes(32)), hash: util.bytesToHex(readBytes(32)),
index: readAsInt(4) index: readAsInt(4)
}, },
script: new Script(readVarString()), script: new Script(readVarString()),
@ -461,6 +466,47 @@ Transaction.deserialize = function(buffer) {
return new Transaction(obj); return new Transaction(obj);
} }
/**
* Signs a standard output at some index with the given key
*/
Transaction.prototype.sign = function(index, key, type) {
type = type || SIGHASH_ALL;
key = new Bitcoin.ECKey(key);
var pub = key.getPub(),
hash160 = Bitcoin.Util.sha256ripe160(pub),
script = Bitcoin.Script.createOutputScript(new Bitcoin.Address(hash160)),
hash = this.hashTransactionForSignature( script, index, type),
sig = key.sign(hash).concat([type]);
this.ins[i].script = Bitcoin.Script.createInputScript(sig,pub);
}
/**
* Signs a P2SH output at some index with the given key
*/
Transaction.prototype.p2shsign = function(index, script, key, type) {
script = new Bitcoin.Script(script);
key = new Bitcoin.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;
// In progress
/*Transaction.prototype.validateInput = function(index,script,sig,pub) {
script = new Bitcoin.Script(script);
scriptBytes = bw.h2b(script),
scriptObj = new Bitcoin.Script(scriptBytes),
hash = txObj.hashTransactionForSignature(scriptObj,i,1);
return Bitcoin.ECDSA.verify(hash, bw.h2b(sig),
bw.h2b(pub));
}*/
var TransactionIn = function (data) var TransactionIn = function (data)
{ {

View file

@ -44,12 +44,12 @@ var Wallet = function () {
if (pub) { if (pub) {
if ("string" === typeof pub) { if ("string" === typeof pub) {
pub = Crypto.util.base64ToBytes(pub); pub = Crypto.util.hexToBytes(pub);
} }
key.setPub(pub); key.setPub(pub);
} }
this.addressHashes.push(key.getBitcoinAddress().getHashBase64()); this.addressHashes.push(key.getBitcoinAddress().getHash());
}; };
/** /**
@ -77,13 +77,13 @@ var Wallet = function () {
/** /**
* Get the key chain. * Get the key chain.
* *
* Returns an array of base64-encoded private values. * Returns an array of hex-encoded private values.
*/ */
this.getKeys = function () { this.getKeys = function () {
var serializedWallet = []; var serializedWallet = [];
for (var i = 0; i < keys.length; i++) { for (var i = 0; i < keys.length; i++) {
serializedWallet.push(keys[i].toString('base64')); serializedWallet.push(keys[i].toString());
} }
return serializedWallet; return serializedWallet;
@ -92,13 +92,13 @@ var Wallet = function () {
/** /**
* Get the public keys. * Get the public keys.
* *
* Returns an array of base64-encoded public keys. * Returns an array of hex-encoded public keys.
*/ */
this.getPubKeys = function () { this.getPubKeys = function () {
var pubs = []; var pubs = [];
for (var i = 0; i < keys.length; i++) { for (var i = 0; i < keys.length; i++) {
pubs.push(Crypto.util.bytesToBase64(keys[i].getPub())); pubs.push(Crypto.util.bytesToHex(keys[i].getPub()));
} }
return pubs; return pubs;
@ -171,7 +171,7 @@ var Wallet = function () {
* to be signed as the second parameter. * to be signed as the second parameter.
*/ */
this.signWithKey = function (pubKeyHash, hash) { this.signWithKey = function (pubKeyHash, hash) {
pubKeyHash = conv.bytesToBase64(pubKeyHash); pubKeyHash = conv.bytesToHex(pubKeyHash);
for (var i = 0; i < this.addressHashes.length; i++) { for (var i = 0; i < this.addressHashes.length; i++) {
if (this.addressHashes[i] == pubKeyHash) { if (this.addressHashes[i] == pubKeyHash) {
return keys[i].sign(hash); return keys[i].sign(hash);
@ -187,7 +187,7 @@ var Wallet = function () {
* wallet. * wallet.
*/ */
this.getPubKeyFromHash = function (pubKeyHash) { this.getPubKeyFromHash = function (pubKeyHash) {
pubKeyHash = conv.bytesToBase64(pubKeyHash); pubKeyHash = conv.bytesToHex(pubKeyHash);
for (var i = 0; i < this.addressHashes.length; i++) { for (var i = 0; i < this.addressHashes.length; i++) {
if (this.addressHashes[i] == pubKeyHash) { if (this.addressHashes[i] == pubKeyHash) {
return keys[i].getPub(); return keys[i].getPub();
@ -222,8 +222,8 @@ Wallet.prototype.process = function (tx) {
for (j = 0; j < tx.out.length; j++) { for (j = 0; j < tx.out.length; j++) {
var raw_tx = tx.out[j]; var raw_tx = tx.out[j];
var txout = new TransactionOut(raw_tx); var txout = new TransactionOut(raw_tx);
// this hash is the base64 hash of the pubkey which is the address the output when to // this hash is the hash of the pubkey which is the address the output when to
hash = conv.bytesToBase64(txout.script.simpleOutPubKeyHash()); hash = conv.bytesToHex(txout.script.simpleOutPubKeyHash());
for (k = 0; k < this.addressHashes.length; k++) { for (k = 0; k < this.addressHashes.length; k++) {
// if our address, then we add the unspent out to a list of unspent outputs // if our address, then we add the unspent out to a list of unspent outputs
if (this.addressHashes[k] === hash) { if (this.addressHashes[k] === hash) {
@ -245,7 +245,7 @@ Wallet.prototype.process = function (tx) {
var txin = new TransactionIn(raw_tx); var txin = new TransactionIn(raw_tx);
var pubkey = txin.script.simpleInPubKey(); var pubkey = txin.script.simpleInPubKey();
hash = conv.bytesToBase64(util.sha256ripe160(pubkey)); hash = conv.bytesToHex(util.sha256ripe160(pubkey));
for (k = 0; k < this.addressHashes.length; k++) { for (k = 0; k < this.addressHashes.length; k++) {
if (this.addressHashes[k] === hash) { if (this.addressHashes[k] === hash) {
for (var l = 0; l < this.unspentOuts.length; l++) { for (var l = 0; l < this.unspentOuts.length; l++) {
@ -329,9 +329,9 @@ Wallet.prototype.clearTransactions = function () {
* Check to see if a pubKeyHash belongs to this wallet. * Check to see if a pubKeyHash belongs to this wallet.
*/ */
Wallet.prototype.hasHash = function (hash) { Wallet.prototype.hasHash = function (hash) {
if (Bitcoin.Util.isArray(hash)) hash = Crypto.util.bytesToBase64(hash); if (Bitcoin.Util.isArray(hash)) hash = Crypto.util.bytesToHex(hash);
// TODO: Just create an object with base64 hashes as keys for faster lookup // TODO: Just create an object with hashes as keys for faster lookup
for (var k = 0; k < this.addressHashes.length; k++) { for (var k = 0; k < this.addressHashes.length; k++) {
if (this.addressHashes[k] === hash) return true; if (this.addressHashes[k] === hash) return true;
} }