1 | 'use strict';
|
2 |
|
3 | var bitcore = require('bitcore');
|
4 | var _ = bitcore.deps._;
|
5 | var PrivateKey = bitcore.PrivateKey;
|
6 | var PublicKey = bitcore.PublicKey;
|
7 | var Address = bitcore.Address;
|
8 | var BufferWriter = bitcore.encoding.BufferWriter;
|
9 | var ECDSA = bitcore.crypto.ECDSA;
|
10 | var Signature = bitcore.crypto.Signature;
|
11 | var sha256sha256 = bitcore.crypto.Hash.sha256sha256;
|
12 | var JSUtil = bitcore.util.js;
|
13 | var $ = bitcore.util.preconditions;
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | var Message = function Message(message) {
|
22 | if (!(this instanceof Message)) {
|
23 | return new Message(message);
|
24 | }
|
25 | $.checkArgument(_.isString(message), 'First argument should be a string');
|
26 | this.message = message;
|
27 |
|
28 | return this;
|
29 | };
|
30 |
|
31 | Message.MAGIC_BYTES = new Buffer('Bitcoin Signed Message:\n');
|
32 |
|
33 | Message.prototype.magicHash = function magicHash() {
|
34 | var prefix1 = BufferWriter.varintBufNum(Message.MAGIC_BYTES.length);
|
35 | var messageBuffer = new Buffer(this.message);
|
36 | var prefix2 = BufferWriter.varintBufNum(messageBuffer.length);
|
37 | var buf = Buffer.concat([prefix1, Message.MAGIC_BYTES, prefix2, messageBuffer]);
|
38 | var hash = sha256sha256(buf);
|
39 | return hash;
|
40 | };
|
41 |
|
42 | Message.prototype._sign = function _sign(privateKey) {
|
43 | $.checkArgument(privateKey instanceof PrivateKey,
|
44 | 'First argument should be an instance of PrivateKey');
|
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 | $.checkArgument(publicKey instanceof PublicKey, 'First argument should be an instance of PublicKey');
|
68 | $.checkArgument(signature instanceof Signature, 'Second argument should be an instance of Signature');
|
69 | var hash = this.magicHash();
|
70 | var verified = ECDSA.verify(hash, signature, publicKey);
|
71 | if (!verified) {
|
72 | this.error = 'The signature was invalid';
|
73 | }
|
74 | return verified;
|
75 | };
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | Message.prototype.verify = function verify(bitcoinAddress, signatureString) {
|
86 | $.checkArgument(bitcoinAddress);
|
87 | $.checkArgument(signatureString && _.isString(signatureString));
|
88 |
|
89 | if (_.isString(bitcoinAddress)) {
|
90 | bitcoinAddress = Address.fromString(bitcoinAddress);
|
91 | }
|
92 | var signature = Signature.fromCompact(new Buffer(signatureString, 'base64'));
|
93 |
|
94 |
|
95 | var ecdsa = new ECDSA();
|
96 | ecdsa.hashbuf = this.magicHash();
|
97 | ecdsa.sig = signature;
|
98 | var publicKey = ecdsa.toPublicKey();
|
99 |
|
100 | var signatureAddress = Address.fromPublicKey(publicKey, bitcoinAddress.network);
|
101 |
|
102 |
|
103 | if (bitcoinAddress.toString() !== signatureAddress.toString()) {
|
104 | this.error = 'The signature did not match the message digest';
|
105 | return false;
|
106 | }
|
107 |
|
108 | return this._verify(publicKey, signature);
|
109 | };
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | Message.fromString = function(str) {
|
118 | return new Message(str);
|
119 | };
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | Message.fromJSON = function fromJSON(json) {
|
128 | if (JSUtil.isValidJSON(json)) {
|
129 | json = JSON.parse(json);
|
130 | }
|
131 | return new Message(json.message);
|
132 | };
|
133 |
|
134 |
|
135 |
|
136 |
|
137 | Message.prototype.toObject = function toObject() {
|
138 | return {
|
139 | message: this.message
|
140 | };
|
141 | };
|
142 |
|
143 |
|
144 |
|
145 |
|
146 | Message.prototype.toJSON = function toJSON() {
|
147 | return JSON.stringify(this.toObject());
|
148 | };
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 | Message.prototype.toString = function() {
|
156 | return this.message;
|
157 | };
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | Message.prototype.inspect = function() {
|
165 | return '<Message: ' + this.toString() + '>';
|
166 | };
|
167 |
|
168 | module.exports = Message;
|