port message to common.js style and add tests

This commit is contained in:
Roman Shtylman 2013-03-02 12:28:13 -05:00
parent 981203e982
commit 41f0027883
4 changed files with 59 additions and 24 deletions

View file

@ -70,7 +70,7 @@ var ECDSA = {
r = sig.r; r = sig.r;
s = sig.s; s = sig.s;
} else { } else {
throw "Invalid value for signature"; throw new Error("Invalid value for signature");
} }
var Q; var Q;
@ -79,7 +79,7 @@ var ECDSA = {
} else if (util.isArray(pubkey)) { } else if (util.isArray(pubkey)) {
Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey); Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey);
} else { } 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); var e = BigInteger.fromByteArrayUnsigned(hash);
@ -176,14 +176,14 @@ var ECDSA = {
parseSigCompact: function (sig) { parseSigCompact: function (sig) {
if (sig.length !== 65) { 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 // Signature is prefixed with a type byte storing three bits of
// information. // information.
var i = sig[0] - 27; var i = sig[0] - 27;
if (i < 0 || i > 7) { if (i < 0 || i > 7) {
throw "Invalid signature type"; throw new Error("Invalid signature type");
} }
var n = ecparams.getN(); var n = ecparams.getN();
@ -253,10 +253,13 @@ var ECDSA = {
Q.validate(); Q.validate();
if (!ECDSA.verifyRaw(e, r, s, Q)) { 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; pubKey.pub = Q;
return pubKey; return pubKey;
}, },
@ -275,14 +278,13 @@ var ECDSA = {
calcPubkeyRecoveryParam: function (address, r, s, hash) calcPubkeyRecoveryParam: function (address, r, s, hash)
{ {
for (var i = 0; i < 4; i++) { for (var i = 0; i < 4; i++) {
try { var pubkey = ECDSA.recoverPubKey(r, s, hash, i);
var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i); if (pubkey.getBitcoinAddress().toString() == address) {
if (pubkey.getBitcoinAddress().toString() == address) { return i;
return i; }
}
} catch (e) {}
} }
throw "Unable to find valid recovery factor";
throw new Error("Unable to find valid recovery factor");
} }
}; };

View file

@ -25,6 +25,7 @@ var endian = function (n) {
module.exports = { module.exports = {
Address: require('./address'), Address: require('./address'),
Key: require('./eckey'), Key: require('./eckey'),
Message: require('./message'),
BigInteger: require('./jsbn/jsbn'), BigInteger: require('./jsbn/jsbn'),
Script: require('./script'), Script: require('./script'),
Opcode: require('./opcode'), Opcode: require('./opcode'),

View file

@ -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 = {}; var Message = {};
Message.magicPrefix = "Bitcoin Signed Message:\n"; Message.magicPrefix = "Bitcoin Signed Message:\n";
@ -10,9 +14,9 @@ Message.makeMagicMessage = function (message) {
var messageBytes = Crypto.charenc.UTF8.stringToBytes(message); var messageBytes = Crypto.charenc.UTF8.stringToBytes(message);
var buffer = []; var buffer = [];
buffer = buffer.concat(Bitcoin.Util.numToVarInt(magicBytes.length)); buffer = buffer.concat(util.numToVarInt(magicBytes.length));
buffer = buffer.concat(magicBytes); buffer = buffer.concat(magicBytes);
buffer = buffer.concat(Bitcoin.Util.numToVarInt(messageBytes.length)); buffer = buffer.concat(util.numToVarInt(messageBytes.length));
buffer = buffer.concat(messageBytes); buffer = buffer.concat(messageBytes);
return buffer; return buffer;
@ -28,10 +32,10 @@ Message.signMessage = function (key, message, compressed) {
var sig = key.sign(hash); var sig = key.sign(hash);
var obj = Bitcoin.ECDSA.parseSig(sig); var obj = ecdsa.parseSig(sig);
var address = key.getBitcoinAddress().toString(); 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; i += 27;
if (compressed) i += 4; if (compressed) i += 4;
@ -45,17 +49,17 @@ Message.signMessage = function (key, message, compressed) {
sig = [i].concat(rBa).concat(sBa); sig = [i].concat(rBa).concat(sBa);
return Crypto.util.bytesToBase64(sig); return conv.bytesToBase64(sig);
}; };
Message.verifyMessage = function (address, sig, message) { Message.verifyMessage = function (address, sig, message) {
sig = Crypto.util.base64ToBytes(sig); sig = conv.base64ToBytes(sig);
sig = Bitcoin.ECDSA.parseSigCompact(sig); sig = ecdsa.parseSigCompact(sig);
var hash = Message.getHash(message); var hash = Message.getHash(message);
var isCompressed = !!(sig.i & 4); 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); pubKey.setCompressed(isCompressed);

28
test/message.js Normal file
View file

@ -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));
});