diff --git a/src/base58.js b/src/base58.js index 3cf1739..f0c9dfc 100644 --- a/src/base58.js +++ b/src/base58.js @@ -1,5 +1,5 @@ -(function () { - var B58 = Bitcoin.Base58 = { +(function (Bitcoin) { + Bitcoin.Base58 = { alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", base: BigInteger.valueOf(58), @@ -61,4 +61,8 @@ return bytes; } }; -})(); + + var B58 = Bitcoin.Base58; +})( + 'undefined' != typeof Bitcoin ? Bitcoin : module.exports +); diff --git a/src/bitcoin.js b/src/bitcoin.js index 452158b..cefb268 100755 --- a/src/bitcoin.js +++ b/src/bitcoin.js @@ -1,69 +1,77 @@ -var Bitcoin = {}; - - -function makeKeypair() -{ - // Generate private key - var n = ecparams.getN(); - var n1 = n.subtract(BigInteger.ONE); - var r = new BigInteger(n.bitLength(), rng); - - var privateKey = r.mod(n1).add(BigInteger.ONE); - - // Generate public key - var G = ecparams.getG(); - var publicPoint = G.multiply(privateKey); - - return {priv: privateKey, pubkey: publicPoint}; -}; - -function serializeTransaction(tx) -{ - var buffer = []; - buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(tx.version)])); - buffer = buffer.concat(numToVarInt(tx.ins.length)); - for (var i = 0; i < tx.ins.length; i++) { - var txin = tx.ins[i]; - buffer = buffer.concat(Crypto.util.base64ToBytes(txin.outpoint.hash)); - buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.index)])); - var scriptBytes = Crypto.util.base64ToBytes(txin.script); - buffer = buffer.concat(numToVarInt(scriptBytes.length)); - buffer = buffer.concat(scriptBytes); - buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.sequence)])); - } - buffer = buffer.concat(numToVarInt(tx.outs.length)); - for (var i = 0; i < tx.outs.length; i++) { - var txout = tx.outs[i]; - var valueHex = (new BigInteger(txout.value, 10)).toString(16); - while (valueHex.length < 16) valueHex = "0" + valueHex; - buffer = buffer.concat(Crypto.util.hexToBytes(valueHex)); - var scriptBytes = Crypto.util.base64ToBytes(txout.script); - buffer = buffer.concat(numToVarInt(scriptBytes.length)); - buffer = buffer.concat(scriptBytes); - } - buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(tx.lock_time)])); - - return buffer; -}; - -var OP_CODESEPARATOR = 171; - -var SIGHASH_ALL = 1; -var SIGHASH_NONE = 2; -var SIGHASH_SINGLE = 3; -var SIGHASH_ANYONECANPAY = 80; - -function hashTransactionForSignature(scriptCode, tx, inIndex, hashType) -{ - // TODO: We need to actually deep copy here - var txTmp = tx; - - // In case concatenating two scripts ends up with two codeseparators, +(function (exports) { + var Bitcoin = exports; + + if ('object' !== typeof module) { + Bitcoin.EventEmitter = EventEmitter; + } +})( + 'object' === typeof module ? module.exports : (window.Bitcoin = {}) +); + +/* + function makeKeypair() + { + // Generate private key + var n = ecparams.getN(); + var n1 = n.subtract(BigInteger.ONE); + var r = new BigInteger(n.bitLength(), rng); + + var privateKey = r.mod(n1).add(BigInteger.ONE); + + // Generate public key + var G = ecparams.getG(); + var publicPoint = G.multiply(privateKey); + + return {priv: privateKey, pubkey: publicPoint}; + }; + + function serializeTransaction(tx) + { + var buffer = []; + buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(tx.version)])); + buffer = buffer.concat(numToVarInt(tx.ins.length)); + for (var i = 0; i < tx.ins.length; i++) { + var txin = tx.ins[i]; + buffer = buffer.concat(Crypto.util.base64ToBytes(txin.outpoint.hash)); + buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.index)])); + var scriptBytes = Crypto.util.base64ToBytes(txin.script); + buffer = buffer.concat(numToVarInt(scriptBytes.length)); + buffer = buffer.concat(scriptBytes); + buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.sequence)])); + } + buffer = buffer.concat(numToVarInt(tx.outs.length)); + for (var i = 0; i < tx.outs.length; i++) { + var txout = tx.outs[i]; + var valueHex = (new BigInteger(txout.value, 10)).toString(16); + while (valueHex.length < 16) valueHex = "0" + valueHex; + buffer = buffer.concat(Crypto.util.hexToBytes(valueHex)); + var scriptBytes = Crypto.util.base64ToBytes(txout.script); + buffer = buffer.concat(numToVarInt(scriptBytes.length)); + buffer = buffer.concat(scriptBytes); + } + buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(tx.lock_time)])); + + return buffer; + }; + + var OP_CODESEPARATOR = 171; + + var SIGHASH_ALL = 1; + var SIGHASH_NONE = 2; + var SIGHASH_SINGLE = 3; + var SIGHASH_ANYONECANPAY = 80; + + function hashTransactionForSignature(scriptCode, tx, inIndex, hashType) + { + // TODO: We need to actually deep copy here + var txTmp = tx; + + // 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; - }); - + scriptCode = scriptCode.filter(function (val) { + return val !== OP_CODESEPARATOR; + }); + // Blank out other inputs' signatures for (var i = 0; i < txTmp.ins.length; i++) { txTmp.ins[i].script = Crypto.util.bytesToBase64([]); @@ -74,93 +82,94 @@ function hashTransactionForSignature(scriptCode, tx, inIndex, hashType) if ((hashType & 0x1f) == SIGHASH_NONE) { txTmp.outs = []; - // Let the others update at will - for (var i = 0; i < txTmp.ins.length; i++) - if (i != inIndex) - txTmp.ins[i].sequence = 0; + // 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 + // TODO: Implement } // Blank out other inputs completely, not recommended for open transactions if (hashType & SIGHASH_ANYONECANPAY) { - txTmp.ins = [txTmp.ins[inIndex]]; + txTmp.ins = [txTmp.ins[inIndex]]; } - var buffer = serializeTransaction(txTmp); - - buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)])); - - console.log(buffer); - - return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); -}; - -function verifyTransactionSignature(tx) { - var hash = hashTransactionForSignature([], tx, 0, 0); - return Crypto.util.bytesToHex(hash); -}; - -function numToVarInt(i) -{ - // TODO: THIS IS TOTALLY UNTESTED! - 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])); + var buffer = serializeTransaction(txTmp); + + buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)])); + + console.log(buffer); + + return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); + }; + + function verifyTransactionSignature(tx) { + var hash = hashTransactionForSignature([], tx, 0, 0); + return Crypto.util.bytesToHex(hash); + }; + + function numToVarInt(i) + { + // TODO: THIS IS TOTALLY UNTESTED! + 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])); + // unsigned long long (LE) + return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i])); } -}; - -var testTx = { - "version":"1", - "lock_time":"0", - "block": { - "hash":"N/A", - "height":115806 - }, - "index":6, - "hash":"WUFzjKubG1kqfJWMb4qZdlhU2F3l5NGXN7AUg8Jwl14=", - "ins":[{ - "outpoint":{ - "hash":"nqcbMM1oRhfLdZga11q7x0CpUMujm+vtxHXO9V0gnwE=", - "index":0 - }, - "script":"RzBEAiB2XXkx1pca9SlfCmCGNUVf+h2sAFBttcxG1VnypIcvEgIgXrOp7LSdYBYp3nPsQAz8BOLD3K4pAlXfZImP1rkzk2EBQQRi7NcODzNfnVqLtG79Axp5UF6EhFIhCmzqKqssfKpfCIOmzCuXEeDFUFvFzeGLJx5N+wp2qRS1TqYezGD3yERk", - "sequence":4294967295 - }], - "outs":[{ - "value":"3000000000", - "script":"dqkUBLZwqhAPRVgZvwI8MN5gLHbU8NOIrA==" - },{ - "value":"25937000000", - "script":"dqkUQ82gJ0O5vOBg6yK5/yorLLV5zLKIrA==" - }] -}; - -/* TODO: Make this stuff into test cases ;) -$(function () { - var key = new Bitcoin.ECKey(Crypto.util.hexToBytes("5c0b98e524ad188ddef35dc6abba13c34a351a05409e5d285403718b93336a4a")); - key = new Bitcoin.ECKey(Crypto.util.hexToBytes("180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19")); - //console.log(key.getBitcoinAddress().toString()); - //var message = Crypto.util.hexToBytes("2aec28d323ee7b06a799d540d224b351161fe48967174ca5e43164e86137da11"); - //message = [0]; - //var out = key.sign(message); - //console.log("pubkey: "+Crypto.util.bytesToHex(key.getPub())); - //console.log("sig: "+Crypto.util.bytesToHex(out)); - - //console.log(key.verify(message, out)); - - //console.log(Bitcoin.ECDSA.verify(message, Crypto.util.hexToBytes("3046022100dffbc26774fc841bbe1c1362fd643609c6e42dcb274763476d87af2c0597e89e022100c59e3c13b96b316cae9fa0ab0260612c7a133a6fe2b3445b6bf80b3123bf274d"), Crypto.util.hexToBytes("0401de173aa944eacf7e44e5073baca93fb34fe4b7897a1c82c92dfdc8a1f75ef58cd1b06e8052096980cb6e1ad6d3df143c34b3d7394bae2782a4df570554c2fb"))); - - //console.log(Bitcoin.ECDSA.verify(Crypto.util.hexToBytes("230aba77ccde46bb17fcb0295a92c0cc42a6ea9f439aaadeb0094625f49e6ed8"), Crypto.util.hexToBytes("3046022100a3ee5408f0003d8ef00ff2e0537f54ba09771626ff70dca1f01296b05c510e85022100d4dc70a5bb50685b65833a97e536909a6951dd247a2fdbde6688c33ba6d6407501"),Crypto.util.hexToBytes("04a19c1f07c7a0868d86dbb37510305843cc730eb3bea8a99d92131f44950cecd923788419bfef2f635fad621d753f30d4b4b63b29da44b4f3d92db974537ad5a4"))); - //console.log(Bitcoin.ECDSA.verify(Crypto.util.hexToBytes("c2c75bb77d7a5acddceb1d45ceef58e7451fd0d3abc9d4c16df7848eefafe00d"), Crypto.util.hexToBytes("3045022100ff9362dadcbf1f6ef954bc8eb27144bbb4f49abd32be1eb04c311151dcf4bcf802205112c2ca6a25aefb8be98bf460c5a9056c01253f31e118d80b81ec9604e3201a01"),Crypto.util.hexToBytes("04fe62ce7892ec209310c176ef7f06565865e286e8699e884603657efa9aa51086785099d544d4e04f1f7b4b065205c1783fade8daf4ba1e0d1962292e8eb722cd"))); -}); -//*/ + }; + + var testTx = { + "version":"1", + "lock_time":"0", + "block": { + "hash":"N/A", + "height":115806 + }, + "index":6, + "hash":"WUFzjKubG1kqfJWMb4qZdlhU2F3l5NGXN7AUg8Jwl14=", + "ins":[{ + "outpoint":{ + "hash":"nqcbMM1oRhfLdZga11q7x0CpUMujm+vtxHXO9V0gnwE=", + "index":0 + }, + "script":"RzBEAiB2XXkx1pca9SlfCmCGNUVf+h2sAFBttcxG1VnypIcvEgIgXrOp7LSdYBYp3nPsQAz8BOLD3K4pAlXfZImP1rkzk2EBQQRi7NcODzNfnVqLtG79Axp5UF6EhFIhCmzqKqssfKpfCIOmzCuXEeDFUFvFzeGLJx5N+wp2qRS1TqYezGD3yERk", + "sequence":4294967295 + }], + "outs":[{ + "value":"3000000000", + "script":"dqkUBLZwqhAPRVgZvwI8MN5gLHbU8NOIrA==" + },{ + "value":"25937000000", + "script":"dqkUQ82gJ0O5vOBg6yK5/yorLLV5zLKIrA==" + }] + }; + + TODO: Make this stuff into test cases ;) + $(function () { + var key = new Bitcoin.ECKey(Crypto.util.hexToBytes("5c0b98e524ad188ddef35dc6abba13c34a351a05409e5d285403718b93336a4a")); + key = new Bitcoin.ECKey(Crypto.util.hexToBytes("180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19")); + //console.log(key.getBitcoinAddress().toString()); + //var message = Crypto.util.hexToBytes("2aec28d323ee7b06a799d540d224b351161fe48967174ca5e43164e86137da11"); + //message = [0]; + //var out = key.sign(message); + //console.log("pubkey: "+Crypto.util.bytesToHex(key.getPub())); + //console.log("sig: "+Crypto.util.bytesToHex(out)); + + //console.log(key.verify(message, out)); + + //console.log(Bitcoin.ECDSA.verify(message, Crypto.util.hexToBytes("3046022100dffbc26774fc841bbe1c1362fd643609c6e42dcb274763476d87af2c0597e89e022100c59e3c13b96b316cae9fa0ab0260612c7a133a6fe2b3445b6bf80b3123bf274d"), Crypto.util.hexToBytes("0401de173aa944eacf7e44e5073baca93fb34fe4b7897a1c82c92dfdc8a1f75ef58cd1b06e8052096980cb6e1ad6d3df143c34b3d7394bae2782a4df570554c2fb"))); + + //console.log(Bitcoin.ECDSA.verify(Crypto.util.hexToBytes("230aba77ccde46bb17fcb0295a92c0cc42a6ea9f439aaadeb0094625f49e6ed8"), Crypto.util.hexToBytes("3046022100a3ee5408f0003d8ef00ff2e0537f54ba09771626ff70dca1f01296b05c510e85022100d4dc70a5bb50685b65833a97e536909a6951dd247a2fdbde6688c33ba6d6407501"),Crypto.util.hexToBytes("04a19c1f07c7a0868d86dbb37510305843cc730eb3bea8a99d92131f44950cecd923788419bfef2f635fad621d753f30d4b4b63b29da44b4f3d92db974537ad5a4"))); + //console.log(Bitcoin.ECDSA.verify(Crypto.util.hexToBytes("c2c75bb77d7a5acddceb1d45ceef58e7451fd0d3abc9d4c16df7848eefafe00d"), Crypto.util.hexToBytes("3045022100ff9362dadcbf1f6ef954bc8eb27144bbb4f49abd32be1eb04c311151dcf4bcf802205112c2ca6a25aefb8be98bf460c5a9056c01253f31e118d80b81ec9604e3201a01"),Crypto.util.hexToBytes("04fe62ce7892ec209310c176ef7f06565865e286e8699e884603657efa9aa51086785099d544d4e04f1f7b4b065205c1783fade8daf4ba1e0d1962292e8eb722cd"))); + }); + // +*/