UNPKG

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