UNPKG

17.2 kBJavaScriptView Raw
1'use strict';
2
3var expect = require('chai').expect;
4var should = require('chai').should();
5
6var keyLib = require('..');
7var owsCommon = require('@owstack/ows-common');
8var BN = owsCommon.BN;
9var Networks = require('@owstack/network-lib');
10var Point = keyLib.crypto.Point;
11var PublicKey = keyLib.PublicKey;
12var PrivateKey = keyLib.PrivateKey;
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(new Buffer(privhex, 'hex')));
53 var pk = new PublicKey(privkey);
54 pk.toString().should.equal(pubhex);
55 });
56
57 it('problematic secp256k1 public keys', function() {
58 var knownKeys = [
59 {
60 wif: 'KzsjKq2FVqVuQv2ueHVFuB65A9uEZ6S1L6F8NuokCrE3V3kE3Ack',
61 priv: '6d1229a6b24c2e775c062870ad26bc261051e0198c67203167273c7c62538846',
62 pub: '03d6106302d2698d6a41e9c9a114269e7be7c6a0081317de444bb2980bf9265a01',
63 pubx: 'd6106302d2698d6a41e9c9a114269e7be7c6a0081317de444bb2980bf9265a01',
64 puby: 'e05fb262e64b108991a29979809fcef9d3e70cafceb3248c922c17d83d66bc9d'
65 },
66 {
67 wif: 'L5MgSwNB2R76xBGorofRSTuQFd1bm3hQMFVf3u2CneFom8u1Yt7G',
68 priv: 'f2cc9d2b008927db94b89e04e2f6e70c180e547b3e5e564b06b8215d1c264b53',
69 pub: '03e275faa35bd1e88f5df6e8f9f6edb93bdf1d65f4915efc79fd7a726ec0c21700',
70 pubx: 'e275faa35bd1e88f5df6e8f9f6edb93bdf1d65f4915efc79fd7a726ec0c21700',
71 puby: '367216cb35b086e6686d69dddd822a8f4d52eb82ac5d9de18fdcd9bf44fa7df7'
72 }
73 ];
74
75 for(var i = 0; i < knownKeys.length; i++) {
76 var privkey = new PrivateKey(knownKeys[i].wif);
77 var pubkey = privkey.toPublicKey();
78 pubkey.toString().should.equal(knownKeys[i].pub);
79 pubkey.point.x.toString('hex').should.equal(knownKeys[i].pubx);
80 pubkey.point.y.toString('hex').should.equal(knownKeys[i].puby);
81 }
82 });
83
84 it('from a compressed public key', function() {
85 var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
86 var publicKey = new PublicKey(publicKeyHex);
87 publicKey.toString().should.equal(publicKeyHex);
88 });
89
90 it('from another publicKey', function() {
91 var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
92 var publicKey = new PublicKey(publicKeyHex);
93 var publicKey2 = new PublicKey(publicKey);
94 publicKey.should.equal(publicKey2);
95 });
96
97 it('sets the network as specified', function() {
98 var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
99 var publicKey = new PublicKey(publicKeyHex, 'btc');
100 publicKey.network.should.equal(Networks.get('btc'));
101 });
102
103 it('sets root network if none provided', function() {
104 var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
105 var publicKey = new PublicKey(publicKeyHex);
106 publicKey.network.should.equal(Networks.get('root'));
107 });
108
109 it('from a hex encoded DER string', function() {
110 var pk = new PublicKey('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
111 should.exist(pk.point);
112 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
113 });
114
115 it('from a hex encoded DER buffer', function() {
116 var pk = new PublicKey(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex'));
117 should.exist(pk.point);
118 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
119 });
120
121 it('from a point', function() {
122 var p = new Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48',
123 '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd');
124 var a = new PublicKey(p);
125 should.exist(a.point);
126 a.point.toString().should.equal(p.toString());
127 var c = new PublicKey(p);
128 should.exist(c.point);
129 c.point.toString().should.equal(p.toString());
130 });
131 });
132
133 describe('#getValidationError', function() {
134
135 it('should recieve an invalid point error', function() {
136 var error = PublicKey.getValidationError(invalidPoint);
137 should.exist(error);
138 error.message.should.equal('Point does not lie on the curve');
139 });
140
141 it('should recieve a boolean as false', function() {
142 var valid = PublicKey.isValid(invalidPoint);
143 valid.should.equal(false);
144 });
145
146 it('should recieve a boolean as true for uncompressed', function() {
147 var valid = PublicKey.isValid('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
148 valid.should.equal(true);
149 });
150
151 it('should recieve a boolean as true for compressed', function() {
152 var valid = PublicKey.isValid('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
153 valid.should.equal(true);
154 });
155
156 });
157
158 describe('#fromPoint', function() {
159
160 it('should instantiate from a point', function() {
161 var p = new Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48',
162 '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd');
163 var b = PublicKey.fromPoint(p);
164 should.exist(b.point);
165 b.point.toString().should.equal(p.toString());
166 });
167
168 it('should error because paramater is not a point', function() {
169 (function() {
170 PublicKey.fromPoint(new Error());
171 }).should.throw('First argument must be an instance of Point.');
172 });
173 });
174
175 describe('#json/object', function() {
176
177 it('should input/ouput json', function() {
178 var json = JSON.stringify({
179 x: '1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a',
180 y: '7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341',
181 compressed: false
182 });
183 var pubkey = new PublicKey(JSON.parse(json));
184 JSON.stringify(pubkey).should.deep.equal(json);
185 });
186
187 it('fails if "y" is not provided', function() {
188 expect(function() {
189 return new PublicKey({
190 x: '1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'
191 });
192 }).to.throw();
193 });
194
195 it('fails if invalid JSON is provided', function() {
196 expect(function() {
197 return PublicKey._transformJSON('¹');
198 }).to.throw();
199 });
200
201 it('works for X starting with 0x00', function() {
202 var a = new PublicKey('030589ee559348bd6a7325994f9c8eff12bd5d73cc683142bd0dd1a17abc99b0dc');
203 var b = new PublicKey('03'+a.toObject().x);
204 b.toString().should.equal(a.toString());
205 });
206
207 });
208
209 describe('#fromPrivateKey', function() {
210
211 it('should make a public key from a privkey', function() {
212 should.exist(PublicKey.fromPrivateKey(PrivateKey.fromRandom()));
213 });
214
215 it('should error because not an instance of privkey', function() {
216 (function() {
217 PublicKey.fromPrivateKey(new Error());
218 }).should.throw('Must be an instance of PrivateKey');
219 });
220
221 });
222
223 describe('#fromBuffer', function() {
224
225 it('should parse this uncompressed public key', function() {
226 var pk = PublicKey.fromBuffer(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex'));
227 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
228 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
229 });
230
231 it('should parse this compressed public key', function() {
232 var pk = PublicKey.fromBuffer(new Buffer('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
233 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
234 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
235 });
236
237 it('should throw an error on this invalid public key', function() {
238 (function() {
239 PublicKey.fromBuffer(new Buffer('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
240 }).should.throw();
241 });
242
243 it('should throw error because not a buffer', function() {
244 (function() {
245 PublicKey.fromBuffer('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
246 }).should.throw('Must be a hex buffer of DER encoded public key');
247 });
248
249 it('should throw error because buffer is the incorrect length', function() {
250 (function() {
251 PublicKey.fromBuffer(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a34112', 'hex'));
252 }).should.throw('Length of x and y must be 32 bytes');
253 });
254
255 });
256
257 describe('#fromDER', function() {
258
259 it('should parse this uncompressed public key', function() {
260 var pk = PublicKey.fromDER(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex'));
261 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
262 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
263 });
264
265 it('should parse this compressed public key', function() {
266 var pk = PublicKey.fromDER(new Buffer('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
267 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
268 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
269 });
270
271 it('should throw an error on this invalid public key', function() {
272 (function() {
273 PublicKey.fromDER(new Buffer('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
274 }).should.throw();
275 });
276
277 });
278
279 describe('#fromString', function() {
280
281 it('should parse this known valid public key', function() {
282 var pk = PublicKey.fromString('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
283 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
284 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
285 });
286
287 });
288
289 describe('#fromX', function() {
290
291 it('should create this known public key', function() {
292 var x = BN.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
293 var pk = PublicKey.fromX(true, x);
294 pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
295 pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
296 });
297
298
299 it('should error because odd was not included as a param', function() {
300 var x = BN.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
301 (function() {
302 return PublicKey.fromX(null, x);
303 }).should.throw('Must specify whether y is odd or not (true or false)');
304 });
305
306 });
307
308 describe('#toBuffer', function() {
309
310 it('should return this compressed DER format', function() {
311 var x = BN.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
312 var pk = PublicKey.fromX(true, x);
313 pk.toBuffer().toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
314 });
315
316 it('should return this uncompressed DER format', function() {
317 var x = BN.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
318 var pk = PublicKey.fromX(true, x);
319 pk.toBuffer().toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
320 });
321
322 });
323
324 describe('#toDER', function() {
325
326 it('should return this compressed DER format', function() {
327 var x = BN.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex'));
328 var pk = PublicKey.fromX(true, x);
329 pk.toDER().toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
330 });
331
332 it('should return this uncompressed DER format', function() {
333 var pk = PublicKey.fromString('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
334 pk.toDER().toString('hex').should.equal('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
335 });
336
337 });
338
339 describe('#toString', function() {
340
341 it('should print this known public key', function() {
342 var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
343 var pk = PublicKey.fromString(hex);
344 pk.toString().should.equal(hex);
345 });
346
347 });
348
349 describe('#inspect', function() {
350
351 it('should output known uncompressed pubkey for console', function() {
352 var pubkey = PublicKey.fromString('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341');
353 pubkey.inspect().should.equal('<PublicKey: 041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341, uncompressed>');
354 });
355
356 it('should output known compressed pubkey for console', function() {
357 var pubkey = PublicKey.fromString('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a');
358 pubkey.inspect().should.equal('<PublicKey: 031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a>');
359 });
360
361 it('should output known compressed pubkey with network for console', function() {
362 var privkey = PrivateKey.fromWIF('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m');
363 var pubkey = new PublicKey(privkey);
364 pubkey.inspect().should.equal('<PublicKey: 03c87bd0e162f26969da8509cafcb7b8c8d202af30b928c582e263dd13ee9a9781>');
365 });
366
367 });
368
369 describe('#validate', function() {
370
371 it('should not have an error if pubkey is valid', function() {
372 var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
373 expect(function() {
374 return PublicKey.fromString(hex);
375 }).to.not.throw();
376 });
377
378 it('should throw an error if pubkey is invalid', function() {
379 var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a0000000000000000000000000000000000000000000000000000000000000000';
380 (function() {
381 return PublicKey.fromString(hex);
382 }).should.throw('Invalid y value for curve.');
383 });
384
385 it('should throw an error if pubkey is invalid', function() {
386 var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a00000000000000000000000000000000000000000000000000000000000000FF';
387 (function() {
388 return PublicKey.fromString(hex);
389 }).should.throw('Invalid y value for curve.');
390 });
391
392 it('should throw an error if pubkey is infinity', function() {
393 (function() {
394 return new PublicKey(Point.getG().mul(Point.getN()));
395 }).should.throw('Point cannot be equal to Infinity');
396 });
397
398 });
399});