1 | 'use strict';
|
2 |
|
3 | var owsCommon = require('@owstack/ows-common');
|
4 | var BN = owsCommon.BN;
|
5 | var Point = require('./crypto/point');
|
6 | var Hash = owsCommon.Hash;
|
7 | var JSUtil = owsCommon.util.js;
|
8 | var Networks = require('@owstack/network-lib');
|
9 | var lodash = owsCommon.deps.lodash;
|
10 | var $ = owsCommon.util.preconditions;
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | function PublicKey(data, network, opts) {
|
38 | if (!(this instanceof PublicKey)) {
|
39 | return new PublicKey(data, network, opts);
|
40 | }
|
41 |
|
42 | $.checkArgument(data, 'First argument is required, please include public key data.');
|
43 |
|
44 | if (data instanceof PublicKey) {
|
45 |
|
46 | return data;
|
47 | }
|
48 |
|
49 | opts = opts || {};
|
50 | var info = this._classifyArgs(data, network, opts);
|
51 |
|
52 |
|
53 | info.point.validate();
|
54 |
|
55 | JSUtil.defineImmutable(this, {
|
56 | point: info.point,
|
57 | compressed: info.compressed,
|
58 | network: info.network || Networks.defaultNetwork
|
59 | });
|
60 |
|
61 | return this;
|
62 | };
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | PublicKey.prototype._classifyArgs = function(data, network, opts) {
|
71 |
|
72 | var info = {
|
73 | compressed: lodash.isUndefined(opts.compressed) || opts.compressed
|
74 | };
|
75 |
|
76 |
|
77 | if (data instanceof Point) {
|
78 | info.point = data;
|
79 | } else if (data.x && data.y) {
|
80 | info = PublicKey._transformObject(data);
|
81 | } else if (typeof(data) === 'string') {
|
82 | info = PublicKey._transformDER(new Buffer(data, 'hex'));
|
83 | } else if (PublicKey._isBuffer(data)) {
|
84 | info = PublicKey._transformDER(data);
|
85 | } else if (PublicKey._isPrivateKey(data)) {
|
86 | info = PublicKey._transformPrivateKey(data);
|
87 | } else {
|
88 | throw new TypeError('First argument is an unrecognized data format.');
|
89 | }
|
90 |
|
91 | if (!info.network) {
|
92 | info.network = lodash.isUndefined(network) ? undefined : Networks.get(network);
|
93 | }
|
94 | return info;
|
95 | };
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 | PublicKey._isPrivateKey = function(param) {
|
105 | var PrivateKey = require('./privatekey');
|
106 | return param instanceof PrivateKey;
|
107 | };
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | PublicKey._isBuffer = function(param) {
|
117 | return (param instanceof Buffer) || (param instanceof Uint8Array);
|
118 | };
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | PublicKey._transformPrivateKey = function(privkey) {
|
128 | $.checkArgument(PublicKey._isPrivateKey(privkey), 'Must be an instance of PrivateKey');
|
129 | var info = {};
|
130 | info.point = Point.getG().mul(privkey.bn);
|
131 | info.compressed = privkey.compressed;
|
132 | info.network = privkey.network;
|
133 | return info;
|
134 | };
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 | PublicKey._transformDER = function(buf, strict) {
|
145 |
|
146 |
|
147 | $.checkArgument(PublicKey._isBuffer(buf), 'Must be a hex buffer of DER encoded public key');
|
148 | var info = {};
|
149 |
|
150 | strict = lodash.isUndefined(strict) ? true : strict;
|
151 |
|
152 | var x;
|
153 | var y;
|
154 | var xbuf;
|
155 | var ybuf;
|
156 |
|
157 | if (buf[0] === 0x04 || (!strict && (buf[0] === 0x06 || buf[0] === 0x07))) {
|
158 | xbuf = buf.slice(1, 33);
|
159 | ybuf = buf.slice(33, 65);
|
160 | if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) {
|
161 | throw new TypeError('Length of x and y must be 32 bytes');
|
162 | }
|
163 | x = new BN(xbuf);
|
164 | y = new BN(ybuf);
|
165 | info.point = new Point(x, y);
|
166 | info.compressed = false;
|
167 | } else if (buf[0] === 0x03) {
|
168 | xbuf = buf.slice(1);
|
169 | x = new BN(xbuf);
|
170 | info = PublicKey._transformX(true, x);
|
171 | info.compressed = true;
|
172 | } else if (buf[0] === 0x02) {
|
173 | xbuf = buf.slice(1);
|
174 | x = new BN(xbuf);
|
175 | info = PublicKey._transformX(false, x);
|
176 | info.compressed = true;
|
177 | } else {
|
178 | throw new TypeError('Invalid DER format public key');
|
179 | }
|
180 | return info;
|
181 | };
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 | PublicKey._transformX = function(odd, x) {
|
192 | $.checkArgument(typeof odd === 'boolean', 'Must specify whether y is odd or not (true or false)');
|
193 | var info = {};
|
194 | info.point = Point.fromX(odd, x);
|
195 | return info;
|
196 | };
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 | PublicKey._transformObject = function(json) {
|
206 | var x = new BN(json.x, 'hex');
|
207 | var y = new BN(json.y, 'hex');
|
208 | var point = new Point(x, y);
|
209 | return new PublicKey(point, null, {
|
210 | compressed: json.compressed
|
211 | });
|
212 | };
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 | PublicKey.fromPrivateKey = function(privkey) {
|
221 | $.checkArgument(PublicKey._isPrivateKey(privkey), 'Must be an instance of PrivateKey');
|
222 | var info = PublicKey._transformPrivateKey(privkey);
|
223 | return new PublicKey(info.point, info.network, {
|
224 | compressed: info.compressed
|
225 | });
|
226 | };
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 | PublicKey.fromDER = PublicKey.fromBuffer = function(buf, strict) {
|
235 | $.checkArgument(PublicKey._isBuffer(buf), 'Must be a hex buffer of DER encoded public key');
|
236 | var info = PublicKey._transformDER(buf, strict);
|
237 | return new PublicKey(info.point, null, {
|
238 | compressed: info.compressed
|
239 | });
|
240 | };
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 | PublicKey.fromPoint = function(point, compressed) {
|
250 | $.checkArgument(point instanceof Point, 'First argument must be an instance of Point.');
|
251 | return new PublicKey(point, null, {
|
252 | compressed: compressed
|
253 | });
|
254 | };
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | PublicKey.fromString = function(str, encoding) {
|
264 | var buf = new Buffer(str, encoding || 'hex');
|
265 | var info = PublicKey._transformDER(buf);
|
266 | return new PublicKey(info.point, null, {
|
267 | compressed: info.compressed
|
268 | });
|
269 | };
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 | PublicKey.fromX = function(odd, x) {
|
279 | var info = PublicKey._transformX(odd, x);
|
280 | return new PublicKey(info.point, null, {
|
281 | compressed: info.compressed
|
282 | });
|
283 | };
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 | PublicKey.getValidationError = function(data) {
|
292 | var error;
|
293 | try {
|
294 |
|
295 | new PublicKey(data);
|
296 | } catch (e) {
|
297 | error = e;
|
298 | }
|
299 | return error;
|
300 | };
|
301 |
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 | PublicKey.isValid = function(data) {
|
309 | return !PublicKey.getValidationError(data);
|
310 | };
|
311 |
|
312 |
|
313 |
|
314 |
|
315 | PublicKey.prototype.toObject = PublicKey.prototype.toJSON = function toObject() {
|
316 | return {
|
317 | x: this.point.getX().toString('hex', 2),
|
318 | y: this.point.getY().toString('hex', 2),
|
319 | compressed: this.compressed
|
320 | };
|
321 | };
|
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 | PublicKey.prototype.toBuffer = PublicKey.prototype.toDER = function() {
|
329 | var x = this.point.getX();
|
330 | var y = this.point.getY();
|
331 |
|
332 | var xbuf = x.toBuffer({
|
333 | size: 32
|
334 | });
|
335 | var ybuf = y.toBuffer({
|
336 | size: 32
|
337 | });
|
338 |
|
339 | var prefix;
|
340 | if (!this.compressed) {
|
341 | prefix = new Buffer([0x04]);
|
342 | return Buffer.concat([prefix, xbuf, ybuf]);
|
343 | } else {
|
344 | var odd = ybuf[ybuf.length - 1] % 2;
|
345 | if (odd) {
|
346 | prefix = new Buffer([0x03]);
|
347 | } else {
|
348 | prefix = new Buffer([0x02]);
|
349 | }
|
350 | return Buffer.concat([prefix, xbuf]);
|
351 | }
|
352 | };
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 | PublicKey.prototype._getID = function _getID() {
|
360 | return Hash.sha256ripemd160(this.toBuffer());
|
361 | };
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 | PublicKey.prototype.toString = function() {
|
369 | return this.toDER().toString('hex');
|
370 | };
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 | PublicKey.prototype.inspect = function() {
|
378 | return '<PublicKey: ' + this.toString() +
|
379 | (this.compressed ? '' : ', uncompressed') + '>';
|
380 | };
|
381 |
|
382 |
|
383 | module.exports = PublicKey;
|