1 | 'use strict';
|
2 |
|
3 | var bitcore = require('bitcore');
|
4 | var PrivateKey = bitcore.PrivateKey;
|
5 | var PublicKey = bitcore.PublicKey;
|
6 | var Address = bitcore.Address;
|
7 | var BufferWriter = bitcore.encoding.BufferWriter;
|
8 | var ECDSA = bitcore.crypto.ECDSA;
|
9 | var Signature = bitcore.crypto.Signature;
|
10 | var sha256sha256 = bitcore.crypto.Hash.sha256sha256;
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | var Message = function Message(message) {
|
19 | if (!(this instanceof Message)) {
|
20 | return new Message(message);
|
21 | }
|
22 | if (typeof message !== 'string') {
|
23 | throw new TypeError('First argument should be a string');
|
24 | }
|
25 | this.message = message;
|
26 |
|
27 | return this;
|
28 | };
|
29 |
|
30 | Message.MAGIC_BYTES = new Buffer('Bitcoin Signed Message:\n');
|
31 |
|
32 | Message.prototype.magicHash = function magicHash() {
|
33 | var prefix1 = BufferWriter.varintBufNum(Message.MAGIC_BYTES.length);
|
34 | var messageBuffer = new Buffer(this.message);
|
35 | var prefix2 = BufferWriter.varintBufNum(messageBuffer.length);
|
36 | var buf = Buffer.concat([prefix1, Message.MAGIC_BYTES, prefix2, messageBuffer]);
|
37 | var hash = sha256sha256(buf);
|
38 | return hash;
|
39 | };
|
40 |
|
41 | Message.prototype._sign = function _sign(privateKey) {
|
42 | if (!(privateKey instanceof PrivateKey)) {
|
43 | throw new TypeError('First argument should be an instance of PrivateKey');
|
44 | }
|
45 | var hash = this.magicHash();
|
46 | var ecdsa = new ECDSA();
|
47 | ecdsa.hashbuf = hash;
|
48 | ecdsa.privkey = privateKey;
|
49 | ecdsa.pubkey = privateKey.toPublicKey();
|
50 | ecdsa.signRandomK();
|
51 | ecdsa.calci();
|
52 | return ecdsa.sig;
|
53 | };
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | Message.prototype.sign = function sign(privateKey) {
|
62 | var signature = this._sign(privateKey);
|
63 | return signature.toCompact().toString('base64');
|
64 | };
|
65 |
|
66 | Message.prototype._verify = function _verify(publicKey, signature) {
|
67 | if (!(publicKey instanceof PublicKey)) {
|
68 | throw new TypeError('First argument should be an instance of PublicKey');
|
69 | }
|
70 | if (!(signature instanceof Signature)) {
|
71 | throw new TypeError('Second argument should be an instance of Signature');
|
72 | }
|
73 | var hash = this.magicHash();
|
74 | var verified = ECDSA.verify(hash, signature, publicKey);
|
75 | if (!verified) {
|
76 | this.error = 'The signature was invalid';
|
77 | }
|
78 | return verified;
|
79 | };
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 | Message.prototype.verify = function verify(bitcoinAddress, signatureString) {
|
90 | var signature = Signature.fromCompact(new Buffer(signatureString, 'base64'));
|
91 |
|
92 |
|
93 | var ecdsa = new ECDSA();
|
94 | ecdsa.hashbuf = this.magicHash();
|
95 | ecdsa.sig = signature;
|
96 | var publicKey = ecdsa.toPublicKey();
|
97 |
|
98 | var expectedAddress = Address.fromString(bitcoinAddress);
|
99 | var signatureAddress = Address.fromPublicKey(publicKey, expectedAddress.network);
|
100 |
|
101 |
|
102 | if (expectedAddress.toString() !== signatureAddress.toString()) {
|
103 | this.error = 'The signature did not match the message digest';
|
104 | return false;
|
105 | }
|
106 |
|
107 | return this._verify(publicKey, signature);
|
108 | };
|
109 |
|
110 | module.exports = Message;
|
111 |
|