UNPKG

3.5 kBJavaScriptView Raw
1'use strict';
2
3var BN = require('./bn');
4var BufferUtil = require('../util/buffer');
5
6var EC = require('elliptic').ec;
7var ec = new EC('secp256k1');
8var ecPoint = ec.curve.point.bind(ec.curve);
9var ecPointFromX = ec.curve.pointFromX.bind(ec.curve);
10
11/**
12 *
13 * Instantiate a valid secp256k1 Point from the X and Y coordinates.
14 *
15 * @param {BN|String} x - The X coordinate
16 * @param {BN|String} y - The Y coordinate
17 * @link https://github.com/indutny/elliptic
18 * @augments elliptic.curve.point
19 * @throws {Error} A validation error if exists
20 * @returns {Point} An instance of Point
21 * @constructor
22 */
23var Point = function Point(x, y, isRed) {
24 try {
25 var point = ecPoint(x, y, isRed);
26 } catch (e) {
27 throw new Error('Invalid Point');
28 }
29 point.validate();
30 return point;
31};
32
33Point.prototype = Object.getPrototypeOf(ec.curve.point());
34
35/**
36 *
37 * Instantiate a valid secp256k1 Point from only the X coordinate
38 *
39 * @param {boolean} odd - If the Y coordinate is odd
40 * @param {BN|String} x - The X coordinate
41 * @throws {Error} A validation error if exists
42 * @returns {Point} An instance of Point
43 */
44Point.fromX = function fromX(odd, x){
45 try {
46 var point = ecPointFromX(x, odd);
47 } catch (e) {
48 throw new Error('Invalid X');
49 }
50 point.validate();
51 return point;
52};
53
54/**
55 *
56 * Will return a secp256k1 ECDSA base point.
57 *
58 * @link https://en.bitcoin.it/wiki/Secp256k1
59 * @returns {Point} An instance of the base point.
60 */
61Point.getG = function getG() {
62 return ec.curve.g;
63};
64
65/**
66 *
67 * Will return the max of range of valid private keys as governed by the secp256k1 ECDSA standard.
68 *
69 * @link https://en.bitcoin.it/wiki/Private_key#Range_of_valid_ECDSA_private_keys
70 * @returns {BN} A BN instance of the number of points on the curve
71 */
72Point.getN = function getN() {
73 return new BN(ec.curve.n.toArray());
74};
75
76Point.prototype._getX = Point.prototype.getX;
77
78/**
79 *
80 * Will return the X coordinate of the Point
81 *
82 * @returns {BN} A BN instance of the X coordinate
83 */
84Point.prototype.getX = function getX() {
85 return new BN(this._getX().toArray());
86};
87
88Point.prototype._getY = Point.prototype.getY;
89
90/**
91 *
92 * Will return the Y coordinate of the Point
93 *
94 * @returns {BN} A BN instance of the Y coordinate
95 */
96Point.prototype.getY = function getY() {
97 return new BN(this._getY().toArray());
98};
99
100/**
101 *
102 * Will determine if the point is valid
103 *
104 * @link https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
105 * @param {Point} An instance of Point
106 * @throws {Error} A validation error if exists
107 * @returns {Point} An instance of the same Point
108 */
109Point.prototype.validate = function validate() {
110
111 if (this.isInfinity()){
112 throw new Error('Point cannot be equal to Infinity');
113 }
114
115 var p2;
116 try {
117 p2 = ecPointFromX(this.getX(), this.getY().isOdd());
118 } catch (e) {
119 throw new Error('Point does not lie on the curve');
120 }
121
122 if (p2.y.cmp(this.y) !== 0) {
123 throw new Error('Invalid y value for curve.');
124 }
125
126
127 //todo: needs test case
128 if (!(this.mul(Point.getN()).isInfinity())) {
129 throw new Error('Point times N must be infinity');
130 }
131
132 return this;
133
134};
135
136Point.pointToCompressed = function pointToCompressed(point) {
137 var xbuf = point.getX().toBuffer({size: 32});
138 var ybuf = point.getY().toBuffer({size: 32});
139
140 var prefix;
141 var odd = ybuf[ybuf.length - 1] % 2;
142 if (odd) {
143 prefix = Buffer.from([0x03]);
144 } else {
145 prefix = Buffer.from([0x02]);
146 }
147 return BufferUtil.concat([prefix, xbuf]);
148};
149
150module.exports = Point;