UNPKG

19.8 kBJavaScriptView Raw
1'use strict';
2
3var should = require('chai').should();
4var expect = require('chai').expect;
5
6var bitcore = require('..');
7var Point = bitcore.crypto.Point;
8var BN = bitcore.crypto.BN;
9var PublicKey = bitcore.PublicKey;
10var PrivateKey = bitcore.PrivateKey;
11var Address = bitcore.Address;
12var Networks = bitcore.Networks;
13
14/* jshint maxlen: 200 */
15
16describe('PublicKey', function() {
17 /* jshint maxstatements: 30 */
18
19 var invalidPoint = '0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
20
21 describe('validating errors on creation', function() {
22 it('errors if data is missing', function() {
23 (function() {
24 return new PublicKey();
25 }).should.throw('First argument is required, please include public key data.');
26 });
27
28 it('errors if an invalid point is provided', function() {
29 (function() {
30 return new PublicKey(invalidPoint);
31 }).should.throw('Point does not lie on the curve');
32 });
33
34 it('errors if a point not on the secp256k1 curve is provided', function() {
35 (function() {
36 return new PublicKey(new Point(1000, 1000));
37 }).should.throw('Point does not lie on the curve');
38 });
39
40 it('errors if the argument is of an unrecognized type', function() {
41 (function() {
42 return new PublicKey(new Error());
43 }).should.throw('First argument is an unrecognized data format.');
44 });
45 });
46
47 describe('instantiation', function() {
48
49 it('from a private key', function() {
50 var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff';
51 var pubhex = '02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc';
52 var privkey = new PrivateKey(new BN(Buffer.from(privhex, 'hex')));
53 var pk = new PublicKey(privkey);
54 pk.toString().should.equal(pubhex);
55 });
56
57 it('problematic secp256k1 public keys', function() {
58
59 var knownKeys = [
60 {
61 wif: 'KzsjKq2FVqVuQv2ueHVFuB65A9uEZ6S1L6F8NuokCrE3V3kE3Ack',
62 priv: '6d1229a6b24c2e775c062870ad26bc261051e0198c67203167273c7c62538846',
63 pub: '03d6106302d2698d6a41e9c9a114269e7be7c6a0081317de444bb2980bf9265a01',
64 pubx: 'd6106302d2698d6a41e9c9a114269e7be7c6a0081317de444bb2980bf9265a01',
65 puby: 'e05fb262e64b108991a29979809fcef9d3e70cafceb3248c922c17d83d66bc9d'
66 },
67 {
68 wif: 'L5MgSwNB2R76xBGorofRSTuQFd1bm3hQMFVf3u2CneFom8u1Yt7G',
69 priv: 'f2cc9d2b008927db94b89e04e2f6e70c180e547b3e5e564b06b8215d1c264b53',
70 pub: '03e275faa35bd1e88f5df6e8f9f6edb93bdf1d65f4915efc79fd7a726ec0c21700',
71 pubx: 'e275faa35bd1e88f5df6e8f9f6edb93bdf1d65f4915efc79fd7a726ec0c21700',
72 puby: '367216cb35b086e6686d69dddd822a8f4d52eb82ac5d9de18fdcd9bf44fa7df7'
73 }
74 ];
75
76 for(var i = 0; i < knownKeys.length; i++) {
77 var privkey = new PrivateKey(knownKeys[i].wif);
78 var pubkey = privkey.toPublicKey();
79 pubkey.toString().should.equal(knownKeys[i].pub);
80 pubkey.point.x.toString('hex').should.equal(knownKeys[i].pubx);
81 pubkey.point.y.toString('hex').should.equal(knownKeys[i].puby);
82 }
83
84 });
85
86 it('from a compressed public key', function() {
87 var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
88 var publicKey = new PublicKey(publicKeyHex);
89 publicKey.toString().should.equal(publicKeyHex);
90 });
91
92 it('from another publicKey', function() {
93 var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
94 var publicKey = new PublicKey(publicKeyHex);
95 var publicKey2 = new PublicKey(publicKey);
96 publicKey.should.equal(publicKey2);
97 });
98
99 it('sets the network to defaultNetwork if none provided', function() {
100 var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
101 var publicKey = new PublicKey(publicKeyHex);
102 publicKey.network.should.equal(Networks.defaultNetwork);
103 });
104
105 it('from a hex encoded DER string', function() {
106 var pk = new PublicKey('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
107 should.exist(pk.point);
108 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
109 });
110
111 it('from a hex encoded DER buffer', function() {
112 var pk = new PublicKey(Buffer.from('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex'));
113 should.exist(pk.point);
114 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
115 });
116
117 it('from a point', function() {
118 var p = new Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48',
119 '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd');
120 var a = new PublicKey(p);
121 should.exist(a.point);
122 a.point.toString().should.equal(p.toString());
123 var c = new PublicKey(p);
124 should.exist(c.point);
125 c.point.toString().should.equal(p.toString());
126 });
127 });
128
129
130 describe('#getValidationError', function(){
131
132 it('should recieve an invalid point error', function() {
133 var error = PublicKey.getValidationError(invalidPoint);
134 should.exist(error);
135 error.message.should.equal('Point does not lie on the curve');
136 });
137
138 it('should recieve a boolean as false', function() {
139 var valid = PublicKey.isValid(invalidPoint);
140 valid.should.equal(false);
141 });
142
143 it('should recieve a boolean as true for uncompressed', function() {
144 var valid = PublicKey.isValid('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
145 valid.should.equal(true);
146 });
147
148 it('should recieve a boolean as true for compressed', function() {
149 var valid = PublicKey.isValid('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
150 valid.should.equal(true);
151 });
152
153 });
154
155 describe('#fromPoint', function() {
156
157 it('should instantiate from a point', function() {
158 var p = new Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48',
159 '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd');
160 var b = PublicKey.fromPoint(p);
161 should.exist(b.point);
162 b.point.toString().should.equal(p.toString());
163 });
164
165 it('should error because paramater is not a point', function() {
166 (function() {
167 PublicKey.fromPoint(new Error());
168 }).should.throw('First argument must be an instance of Point.');
169 });
170 });
171
172 describe('#json/object', function() {
173
174 it('should input/ouput json', function() {
175 var json = JSON.stringify({
176 x: '1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a',
177 y: '7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341',
178 compressed: false
179 });
180 var pubkey = new PublicKey(JSON.parse(json));
181 JSON.stringify(pubkey).should.deep.equal(json);
182 });
183
184 it('fails if "y" is not provided', function() {
185 expect(function() {
186 return new PublicKey({
187 x: '1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'
188 });
189 }).to.throw();
190 });
191
192 it('fails if invalid JSON is provided', function() {
193 expect(function() {
194 return PublicKey._transformJSON('¹');
195 }).to.throw();
196 });
197
198 it('works for X starting with 0x00', function() {
199 var a = new PublicKey('030589ee559348bd6a7325994f9c8eff12bd5d73cc683142bd0dd1a17abc99b0dc');
200 var b = new PublicKey('03'+a.toObject().x);
201 b.toString().should.equal(a.toString());
202 });
203
204 });
205
206 describe('#fromPrivateKey', function() {
207
208 it('should make a public key from a privkey', function() {
209 should.exist(PublicKey.fromPrivateKey(PrivateKey.fromRandom()));
210 });
211
212 it('should error because not an instance of privkey', function() {
213 (function() {
214 PublicKey.fromPrivateKey(new Error());
215 }).should.throw('Must be an instance of PrivateKey');
216 });
217
218 });
219
220 describe('#fromBuffer', function() {
221
222 it('should parse this uncompressed public key', function() {
223 var pk = PublicKey.fromBuffer(Buffer.from('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex'));
224 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
225 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
226 });
227
228 it('should parse this compressed public key', function() {
229 var pk = PublicKey.fromBuffer(Buffer.from('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
230 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
231 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
232 });
233
234 it('should throw an error on this invalid public key', function() {
235 (function() {
236 PublicKey.fromBuffer(Buffer.from('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
237 }).should.throw();
238 });
239
240 it('should throw error because not a buffer', function() {
241 (function() {
242 PublicKey.fromBuffer('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
243 }).should.throw('Must be a hex buffer of DER encoded public key');
244 });
245
246 it('should throw error because buffer is the incorrect length', function() {
247 (function() {
248 PublicKey.fromBuffer(Buffer.from('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a34112', 'hex'));
249 }).should.throw('Length of x and y must be 32 bytes');
250 });
251
252 });
253
254 describe('#fromDER', function() {
255
256 it('should parse this uncompressed public key', function() {
257 var pk = PublicKey.fromDER(Buffer.from('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex'));
258 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
259 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
260 });
261
262 it('should parse this compressed public key', function() {
263 var pk = PublicKey.fromDER(Buffer.from('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
264 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
265 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
266 });
267
268 it('should throw an error on this invalid public key', function() {
269 (function() {
270 PublicKey.fromDER(Buffer.from('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
271 }).should.throw();
272 });
273
274 });
275
276 describe('#fromString', function() {
277
278 it('should parse this known valid public key', function() {
279 var pk = PublicKey.fromString('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
280 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
281 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
282 });
283
284 });
285
286 describe('#fromX', function() {
287
288 it('should create this known public key', function() {
289 var x = BN.fromBuffer(Buffer.from('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
290 var pk = PublicKey.fromX(true, x);
291 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
292 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
293 });
294
295
296 it('should error because odd was not included as a param', function() {
297 var x = BN.fromBuffer(Buffer.from('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
298 (function() {
299 return PublicKey.fromX(null, x);
300 }).should.throw('Must specify whether y is odd or not (true or false)');
301 });
302
303 });
304
305 describe('#toBuffer', function() {
306
307 it('should return this compressed DER format', function() {
308 var x = BN.fromBuffer(Buffer.from('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
309 var pk = PublicKey.fromX(true, x);
310 pk.toBuffer().toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
311 });
312
313 it('should return this uncompressed DER format', function() {
314 var x = BN.fromBuffer(Buffer.from('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
315 var pk = PublicKey.fromX(true, x);
316 pk.toBuffer().toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
317 });
318
319 });
320
321 describe('#toDER', function() {
322
323 it('should return this compressed DER format', function() {
324 var x = BN.fromBuffer(Buffer.from('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
325 var pk = PublicKey.fromX(true, x);
326 pk.toDER().toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
327 });
328
329 it('should return this uncompressed DER format', function() {
330 var pk = PublicKey.fromString('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
331 pk.toDER().toString('hex').should.equal('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
332 });
333 });
334
335 describe('#toAddress', function() {
336
337 it('should output this known mainnet address correctly', function() {
338 var pk = new PublicKey('03c87bd0e162f26969da8509cafcb7b8c8d202af30b928c582e263dd13ee9a9781');
339 var address = pk.toAddress('livenet');
340 address.toString().should.equal('1A6ut1tWnUq1SEQLMr4ttDh24wcbJ5o9TT');
341 });
342
343 it('should output this known testnet address correctly', function() {
344 var pk = new PublicKey('0293126ccc927c111b88a0fe09baa0eca719e2a3e087e8a5d1059163f5c566feef');
345 var address = pk.toAddress('testnet');
346 address.toString().should.equal('mtX8nPZZdJ8d3QNLRJ1oJTiEi26Sj6LQXS');
347 });
348
349 it('should output this known mainnet witness address correctly', function() {
350 var pk = new PublicKey('03c87bd0e162f26969da8509cafcb7b8c8d202af30b928c582e263dd13ee9a9781');
351 var address = pk.toAddress('livenet', Address.PayToWitnessPublicKeyHash);
352 address.toString().should.equal('bc1qv0t45lutg37ghyg7lg22vgducs3d9hvuarwr89');
353 });
354
355 it('should output this known testnet witness address correctly', function() {
356 var pk = new PublicKey('0293126ccc927c111b88a0fe09baa0eca719e2a3e087e8a5d1059163f5c566feef');
357 var address = pk.toAddress('testnet', Address.PayToWitnessPublicKeyHash);
358 address.toString().should.equal('tb1q363x8lv54fdsywyc9494upd6sp4rg6glhsyzk0');
359 });
360
361 it('should output this known mainnet wrapped witness address correctly', function() {
362 var pk = new PublicKey('03c87bd0e162f26969da8509cafcb7b8c8d202af30b928c582e263dd13ee9a9781');
363 var address = pk.toAddress('livenet', Address.PayToScriptHash);
364 address.toString().should.equal('39wREM7dxb7KNMNR1py1W8nUheUtkPPA5r');
365 });
366
367 it('should output this known testnet wrapped witness address correctly', function() {
368 var pk = new PublicKey('0293126ccc927c111b88a0fe09baa0eca719e2a3e087e8a5d1059163f5c566feef');
369 var address = pk.toAddress('testnet', Address.PayToScriptHash);
370 address.toString().should.equal('2NDgQSsQGdLDGoYvh4NTmesQ2wWgx6RGu3m');
371 });
372
373 });
374
375 describe('hashes', function() {
376
377 // wif private key, address
378 // see: https://github.com/bitcoin/bitcoin/blob/master/src/test/key_tests.cpp#L20
379 var data = [
380 ['5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj', '1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ'],
381 ['5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3', '1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ'],
382 ['Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw', '1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs'],
383 ['L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g', '1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs']
384 ];
385
386 data.forEach(function(d){
387 var publicKey = PrivateKey.fromWIF(d[0]).toPublicKey();
388 var address = Address.fromString(d[1]);
389 address.hashBuffer.should.deep.equal(publicKey._getID());
390 });
391
392 });
393
394 describe('#toString', function() {
395
396 it('should print this known public key', function() {
397 var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
398 var pk = PublicKey.fromString(hex);
399 pk.toString().should.equal(hex);
400 });
401
402 });
403
404 describe('#inspect', function() {
405 it('should output known uncompressed pubkey for console', function() {
406 var pubkey = PublicKey.fromString('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
407 pubkey.inspect().should.equal('<PublicKey: 041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341, uncompressed>');
408 });
409
410 it('should output known compressed pubkey for console', function() {
411 var pubkey = PublicKey.fromString('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
412 pubkey.inspect().should.equal('<PublicKey: 031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a>');
413 });
414
415 it('should output known compressed pubkey with network for console', function() {
416 var privkey = PrivateKey.fromWIF('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m');
417 var pubkey = new PublicKey(privkey);
418 pubkey.inspect().should.equal('<PublicKey: 03c87bd0e162f26969da8509cafcb7b8c8d202af30b928c582e263dd13ee9a9781>');
419 });
420
421 });
422
423 describe('#validate', function() {
424
425 it('should not have an error if pubkey is valid', function() {
426 var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
427 expect(function() {
428 return PublicKey.fromString(hex);
429 }).to.not.throw();
430 });
431
432 it('should throw an error if pubkey is invalid', function() {
433 var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a0000000000000000000000000000000000000000000000000000000000000000';
434 (function() {
435 return PublicKey.fromString(hex);
436 }).should.throw('Invalid y value for curve.');
437 });
438
439 it('should throw an error if pubkey is invalid', function() {
440 var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a00000000000000000000000000000000000000000000000000000000000000FF';
441 (function() {
442 return PublicKey.fromString(hex);
443 }).should.throw('Invalid y value for curve.');
444 });
445
446 it('should throw an error if pubkey is infinity', function() {
447 (function() {
448 return new PublicKey(Point.getG().mul(Point.getN()));
449 }).should.throw('Point cannot be equal to Infinity');
450 });
451
452 });
453
454});