Skip to content

Commit

Permalink
Merge pull request #20 from dashevo/develop
Browse files Browse the repository at this point in the history
V0.15.3 Release
  • Loading branch information
Alex-Werner committed Feb 19, 2018
2 parents 5cc92c3 + f07ace8 commit d933ac9
Show file tree
Hide file tree
Showing 9 changed files with 826 additions and 369 deletions.
827 changes: 463 additions & 364 deletions bitcore-lib-dash.js

Large diffs are not rendered by default.

27 changes: 26 additions & 1 deletion bitcore-lib-dash.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bitcore-lib-dash",
"main": "./bitcore-lib-dash.min.js",
"version": "0.15.2",
"version": "0.15.3",
"homepage": "https://github.com/dashevo/bitcore-lib-dash",
"authors": [
"Dash", "BitPay, Inc."
Expand Down
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

var bitcoreTasks = require('bitcore-build-dash');

bitcoreTasks('lib');
bitcoreTasks('lib-dash');
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ bitcore.Transaction = require('./lib/transaction');
bitcore.GovObject = require('./lib/govobject');
bitcore.URI = require('./lib/uri');
bitcore.Unit = require('./lib/unit');
bitcore.Message = require('./lib/message')

// dependencies, subject to change
bitcore.deps = {};
Expand Down
168 changes: 168 additions & 0 deletions lib/message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
'use strict';

var _ = require('lodash');
var PrivateKey = require('./privatekey');
var PublicKey = require('./publickey');
var Address = require('./address');
var BufferWriter = require('./encoding/bufferwriter');
var ECDSA = require('./crypto/ecdsa');
var Signature = require('./crypto/signature');
var Hash = require('./crypto/hash');
var sha256sha256 = Hash.sha256sha256;
var JSUtil = require('./util/js');
var $ = require('./util/preconditions');

/**
* constructs a new message to sign and verify.
*
* @param {String} message
* @returns {Message}
*/
var Message = function Message(message) {
if (!(this instanceof Message)) {
return new Message(message);
}
$.checkArgument(_.isString(message), 'First argument should be a string');
this.message = message;

return this;
};

Message.MAGIC_BYTES = new Buffer('DarkCoin Signed Message:\n');

Message.prototype.magicHash = function magicHash() {
var prefix1 = BufferWriter.varintBufNum(Message.MAGIC_BYTES.length);
var messageBuffer = new Buffer(this.message);
var prefix2 = BufferWriter.varintBufNum(messageBuffer.length);
var buf = Buffer.concat([prefix1, Message.MAGIC_BYTES, prefix2, messageBuffer]);
var hash = sha256sha256(buf);
return hash;
};

Message.prototype._sign = function _sign(privateKey) {
$.checkArgument(privateKey instanceof PrivateKey,
'First argument should be an instance of PrivateKey');
var hash = this.magicHash();
var ecdsa = new ECDSA();
ecdsa.hashbuf = hash;
ecdsa.privkey = privateKey;
ecdsa.pubkey = privateKey.toPublicKey();
ecdsa.signRandomK();
ecdsa.calci();
return ecdsa.sig;
};

/**
* Will sign a message with a given bitcoin private key.
*
* @param {PrivateKey} privateKey - An instance of PrivateKey
* @returns {String} A base64 encoded compact signature
*/
Message.prototype.sign = function sign(privateKey) {
var signature = this._sign(privateKey);
return signature.toCompact().toString('base64');
};

Message.prototype._verify = function _verify(publicKey, signature) {
$.checkArgument(publicKey instanceof PublicKey, 'First argument should be an instance of PublicKey');
$.checkArgument(signature instanceof Signature, 'Second argument should be an instance of Signature');
var hash = this.magicHash();
var verified = ECDSA.verify(hash, signature, publicKey);
if (!verified) {
this.error = 'The signature was invalid';
}
return verified;
};

/**
* Will return a boolean of the signature is valid for a given bitcoin address.
* If it isn't the specific reason is accessible via the "error" member.
*
* @param {Address|String} bitcoinAddress - A bitcoin address
* @param {String} signatureString - A base64 encoded compact signature
* @returns {Boolean}
*/
Message.prototype.verify = function verify(bitcoinAddress, signatureString) {
$.checkArgument(bitcoinAddress);
$.checkArgument(signatureString && _.isString(signatureString));

if (_.isString(bitcoinAddress)) {
bitcoinAddress = Address.fromString(bitcoinAddress);
}
var signature = Signature.fromCompact(new Buffer(signatureString, 'base64'));

// recover the public key
var ecdsa = new ECDSA();
ecdsa.hashbuf = this.magicHash();
ecdsa.sig = signature;
var publicKey = ecdsa.toPublicKey();

var signatureAddress = Address.fromPublicKey(publicKey, bitcoinAddress.network);

// check that the recovered address and specified address match
if (bitcoinAddress.toString() !== signatureAddress.toString()) {
this.error = 'The signature did not match the message digest';
return false;
}

return this._verify(publicKey, signature);
};

/**
* Instantiate a message from a message string
*
* @param {String} str - A string of the message
* @returns {Message} A new instance of a Message
*/
Message.fromString = function(str) {
return new Message(str);
};

/**
* Instantiate a message from JSON
*
* @param {String} json - An JSON string or Object with keys: message
* @returns {Message} A new instance of a Message
*/
Message.fromJSON = function fromJSON(json) {
if (JSUtil.isValidJSON(json)) {
json = JSON.parse(json);
}
return new Message(json.message);
};

/**
* @returns {Object} A plain object with the message information
*/
Message.prototype.toObject = function toObject() {
return {
message: this.message
};
};

/**
* @returns {String} A JSON representation of the message information
*/
Message.prototype.toJSON = function toJSON() {
return JSON.stringify(this.toObject());
};

/**
* Will return a the string representation of the message
*
* @returns {String} Message
*/
Message.prototype.toString = function() {
return this.message;
};

/**
* Will return a string formatted for the console
*
* @returns {String} Message
*/
Message.prototype.inspect = function() {
return '<Message: ' + this.toString() + '>';
};

module.exports = Message;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bitcore-lib-dash",
"version": "0.15.2",
"version": "0.15.3",
"description": "A pure and powerful JavaScript Dash library.",
"author": "BitPay <dev@bitpay.com>",
"main": "index.js",
Expand Down
164 changes: 164 additions & 0 deletions test/message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
'use strict';

var chai = require('chai');
var expect = chai.expect;
var should = chai.should();

var bitcore = require('../.');
var Address = bitcore.Address;
var Signature = bitcore.crypto.Signature;
var Message = bitcore.Message;

describe('Message', function() {

var address = 'yZKdLYCvDXa2kyQr8Tg3N6c3xeZoK7XDcj';
var badAddress = 'yj3v6A6gQkiRbChbGwvahiFZ6EfpYxk9na';
var privateKey = bitcore.PrivateKey.fromWIF('cR4qogdN9UxLZJXCNFNwDRRZNeLRWuds9TTSuLNweFVjiaE4gPaq');
var text = 'hello, world';
var signatureString = 'IB+LpNmaTAkB8e6fGgocGKuZ2tAXJ4ZmhhVs7FbOOcHjHPgMHycpAFIl1ojb+PA6jyhufeOKQZKjPnI8VQnevRI=';

var badSignatureString = 'H69qZ4mbZCcvXk7CWjptD5ypnYVLvQ3eMXLM8+1gX21SLH/GaFnAjQrDn37+TDw79i9zHhbiMMwhtvTwnPigZ6k=';

var signature = Signature.fromCompact(new Buffer(signatureString, 'base64'));
var badSignature = Signature.fromCompact(new Buffer(badSignatureString, 'base64'));

var publicKey = privateKey.toPublicKey();

it('will error with incorrect message type', function() {
expect(function() {
return new Message(new Date());
}).to.throw('First argument should be a string');
});

it('will instantiate without "new"', function() {
var message = Message(text);
should.exist(message);
});

var signature2;
var signature3;

it('can sign a message', function() {
var message2 = new Message(text);
signature2 = message2._sign(privateKey);
signature3 = Message(text).sign(privateKey);
should.exist(signature2);
should.exist(signature3);
});

it('sign will error with incorrect private key argument', function() {
expect(function() {
var message3 = new Message(text);
return message3.sign('not a private key');
}).to.throw('First argument should be an instance of PrivateKey');
});

it('can verify a message with signature', function() {
var message4 = new Message(text);
var verified = message4._verify(publicKey, signature2);
verified.should.equal(true);
});

it('can verify a message with existing signature', function() {
var message5 = new Message(text);
var verified = message5._verify(publicKey, signature);
verified.should.equal(true);
});

it('verify will error with incorrect public key argument', function() {
expect(function() {
var message6 = new Message(text);
return message6._verify('not a public key', signature);
}).to.throw('First argument should be an instance of PublicKey');
});

it('verify will error with incorrect signature argument', function() {
expect(function() {
var message7 = new Message(text);
return message7._verify(publicKey, 'not a signature');
}).to.throw('Second argument should be an instance of Signature');
});

it('verify will correctly identify a bad signature', function() {
var message8 = new Message(text);
var verified = message8._verify(publicKey, badSignature);
should.exist(message8.error);
verified.should.equal(false);
});

it('can verify a message with address and generated signature string', function() {
var message9 = new Message(text);
var verified = message9.verify(address, signature3);
should.not.exist(message9.error);
verified.should.equal(true);
});

it('will not verify with address mismatch', function() {
var message10 = new Message(text);
var verified = message10.verify(badAddress, signatureString);
should.exist(message10.error);
verified.should.equal(false);
});

it('will verify with an uncompressed pubkey', function() {
var privateKey = new bitcore.PrivateKey('67fd2209ce4a95f6f1d421ab3fbea47ada13df11b73b30c4d9a9f78cc80651ac');
var message = new Message('This is an example of a signed message.');
var signature = message.sign(privateKey);
var verified = message.verify(privateKey.toAddress(), signature);
verified.should.equal(true);
});

it('can chain methods', function() {
var verified = Message(text).verify(address, signatureString);
verified.should.equal(true);
});

describe('#json', function() {

it('roundtrip to-from-to', function() {
var json = new Message(text).toJSON();
var message = Message.fromJSON(json);
message.toString().should.equal(text);
});

it('checks that the string parameter is valid JSON', function() {
expect(function() {
return Message.fromJSON('¹');
}).to.throw();
});

});

describe('#toString', function() {

it('message string', function() {
var message = new Message(text);
message.toString().should.equal(text);
});

it('roundtrip to-from-to', function() {
var str = new Message(text).toString();
var message = Message.fromString(str);
message.toString().should.equal(text);
});

});

describe('#inspect', function() {

it('should output formatted output correctly', function() {
var message = new Message(text);
var output = '<Message: '+text+'>';
message.inspect().should.equal(output);
});

});


it('accepts Address for verification', function() {
var verified = Message(text)
.verify(new Address(address), signatureString);
verified.should.equal(true);
});

});
2 changes: 1 addition & 1 deletion test/transaction/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -1265,7 +1265,7 @@ describe('Transaction', function() {
],
nLockTime: 139
});
const copiedTransaction = bitcore.Transaction().fromObject(tx);
var copiedTransaction = bitcore.Transaction().fromObject(tx);
expect(copiedTransaction).to.be.an.instanceof(bitcore.Transaction);
});
});
Expand Down

0 comments on commit d933ac9

Please sign in to comment.