port message to common.js style and add tests
This commit is contained in:
parent
981203e982
commit
41f0027883
4 changed files with 59 additions and 24 deletions
28
src/ecdsa.js
28
src/ecdsa.js
|
@ -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");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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
28
test/message.js
Normal 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));
|
||||||
|
});
|
Loading…
Reference in a new issue