diff --git a/src/ecdsa.js b/src/ecdsa.js index 3f6877f..1aa15ed 100644 --- a/src/ecdsa.js +++ b/src/ecdsa.js @@ -70,7 +70,7 @@ var ECDSA = { r = sig.r; s = sig.s; } else { - throw "Invalid value for signature"; + throw new Error("Invalid value for signature"); } var Q; @@ -79,7 +79,7 @@ var ECDSA = { } else if (util.isArray(pubkey)) { Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey); } else { - throw "Invalid format for pubkey value, must be byte array or ECPointFp"; + throw new Error("Invalid format for pubkey value, must be byte array or ECPointFp"); } var e = BigInteger.fromByteArrayUnsigned(hash); @@ -176,14 +176,14 @@ var ECDSA = { parseSigCompact: function (sig) { if (sig.length !== 65) { - throw "Signature has the wrong length"; + throw new Error("Signature has the wrong length"); } // 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("Invalid signature type"); } var n = ecparams.getN(); @@ -253,10 +253,13 @@ var ECDSA = { Q.validate(); if (!ECDSA.verifyRaw(e, r, s, Q)) { - throw "Pubkey recovery unsuccessful"; + throw new Error("Pubkey recovery unsuccessful"); } - var pubKey = new Bitcoin.ECKey(); + // TODO (shtylman) this is stupid because this file and eckey + // have circular dependencies + var ECKey = require('./eckey'); + var pubKey = ECKey(); pubKey.pub = Q; return pubKey; }, @@ -275,14 +278,13 @@ var ECDSA = { 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) {} + var pubkey = ECDSA.recoverPubKey(r, s, hash, i); + if (pubkey.getBitcoinAddress().toString() == address) { + return i; + } } - throw "Unable to find valid recovery factor"; + + throw new Error("Unable to find valid recovery factor"); } }; diff --git a/src/index.js b/src/index.js index 7b7443e..0d06ac1 100644 --- a/src/index.js +++ b/src/index.js @@ -25,6 +25,7 @@ var endian = function (n) { module.exports = { Address: require('./address'), Key: require('./eckey'), + Message: require('./message'), BigInteger: require('./jsbn/jsbn'), Script: require('./script'), Opcode: require('./opcode'), diff --git a/src/message.js b/src/message.js index 0cbd581..b98960c 100644 --- a/src/message.js +++ b/src/message.js @@ -1,6 +1,10 @@ -/** - * Implements Bitcoin's feature for signing arbitrary messages. - */ +/// Implements Bitcoin's feature for signing arbitrary messages. + +var Crypto = require('./crypto-js/crypto'); +var ecdsa = require('./ecdsa'); +var conv = require('./convert'); +var util = require('./util'); + var Message = {}; Message.magicPrefix = "Bitcoin Signed Message:\n"; @@ -10,9 +14,9 @@ Message.makeMagicMessage = function (message) { var messageBytes = Crypto.charenc.UTF8.stringToBytes(message); var buffer = []; - buffer = buffer.concat(Bitcoin.Util.numToVarInt(magicBytes.length)); + buffer = buffer.concat(util.numToVarInt(magicBytes.length)); buffer = buffer.concat(magicBytes); - buffer = buffer.concat(Bitcoin.Util.numToVarInt(messageBytes.length)); + buffer = buffer.concat(util.numToVarInt(messageBytes.length)); buffer = buffer.concat(messageBytes); return buffer; @@ -28,10 +32,10 @@ Message.signMessage = function (key, message, compressed) { var sig = key.sign(hash); - var obj = Bitcoin.ECDSA.parseSig(sig); + var obj = ecdsa.parseSig(sig); var address = key.getBitcoinAddress().toString(); - var i = Bitcoin.ECDSA.calcPubkeyRecoveryParam(address, obj.r, obj.s, hash); + var i = ecdsa.calcPubkeyRecoveryParam(address, obj.r, obj.s, hash); i += 27; if (compressed) i += 4; @@ -45,17 +49,17 @@ Message.signMessage = function (key, message, compressed) { sig = [i].concat(rBa).concat(sBa); - return Crypto.util.bytesToBase64(sig); + return conv.bytesToBase64(sig); }; Message.verifyMessage = function (address, sig, message) { - sig = Crypto.util.base64ToBytes(sig); - sig = Bitcoin.ECDSA.parseSigCompact(sig); + sig = conv.base64ToBytes(sig); + sig = 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); + var pubKey = ecdsa.recoverPubKey(sig.r, sig.s, hash, sig.i); pubKey.setCompressed(isCompressed); diff --git a/test/message.js b/test/message.js new file mode 100644 index 0000000..a202d01 --- /dev/null +++ b/test/message.js @@ -0,0 +1,28 @@ +var assert = require('assert'); +var Message = require('../').Message; +var Key = require('../').Key; +var hexToBytes = require('../').convert.hexToBytes; + +var priv = '18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725'; +var addr = '16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM'; +var msg = 'foobar'; + +test('create', function() { + var key = Key(hexToBytes(priv)); + assert.equal(key.getBitcoinAddress().toString(), addr); + + var sig = Message.signMessage(key, msg); + assert.ok(Message.verifyMessage(addr, sig, msg)); + // wrong message + assert.ok(!Message.verifyMessage(addr, sig, 'not foobar')); + // wrong address + assert.ok(!Message.verifyMessage('1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a', sig, msg)); +}); + +test('incorrect signature', function() { + // wrong signature + var priv = '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh'; + var key = Key(hexToBytes(priv)); + var sig = Message.signMessage(key, msg); + assert.ok(!Message.verifyMessage(addr, sig, msg)); +});