UNPKG

3.28 kBJavaScriptView Raw
1/**
2 * Point (on secp256k1)
3 * ====================
4 *
5 * A point is a point on the secp256k1 curve which is the elliptic curve used
6 * by bitcoin. This code is a wrapper for Fedor Indutny's Point class from his
7 * elliptic library. This code adds a few minor conveniences, but is mostly the
8 * same. Since Fedor's code returns points and big numbers that are instances
9 * of his point and big number classes, we have to wrap all the methods such as
10 * getX() to return the Yours Bitcoin point and big number types.
11 */
12'use strict'
13
14import { Bn } from './bn'
15import elliptic from 'bitcoin-elliptic'
16
17const ec = elliptic.curves.secp256k1
18const _point = ec.curve.point()
19const _Point = _point.constructor
20
21class Point extends _Point {
22 constructor (x, y, isRed) {
23 super(ec.curve, x, y, isRed)
24 }
25
26 static fromX (isOdd, x) {
27 const _point = ec.curve.pointFromX(x, isOdd)
28 const point = Object.create(Point.prototype)
29 return point.copyFrom(_point)
30 }
31
32 copyFrom (point) {
33 if (!(point instanceof _Point)) {
34 throw new Error('point should be an external point')
35 }
36 Object.keys(point).forEach(
37 function (key) {
38 this[key] = point[key]
39 }.bind(this)
40 )
41 return this
42 }
43
44 add (p) {
45 p = _Point.prototype.add.call(this, p)
46 const point = Object.create(Point.prototype)
47 return point.copyFrom(p)
48 }
49
50 mul (bn) {
51 if (!bn.lt(Point.getN())) {
52 throw new Error('point mul out of range')
53 }
54 const p = _Point.prototype.mul.call(this, bn)
55 const point = Object.create(Point.prototype)
56 return point.copyFrom(p)
57 }
58
59 mulAdd (bn1, point, bn2) {
60 const p = _Point.prototype.mulAdd.call(this, bn1, point, bn2)
61 point = Object.create(Point.prototype)
62 return point.copyFrom(p)
63 }
64
65 getX () {
66 const _x = _Point.prototype.getX.call(this)
67 const x = Object.create(Bn.prototype)
68 _x.copy(x)
69 return x
70 }
71
72 getY () {
73 const _y = _Point.prototype.getY.call(this)
74 const y = Object.create(Bn.prototype)
75 _y.copy(y)
76 return y
77 }
78
79 fromX (isOdd, x) {
80 const point = Point.fromX(isOdd, x)
81 return this.copyFrom(point)
82 }
83
84 toJSON () {
85 return {
86 x: this.getX().toString(),
87 y: this.getY().toString()
88 }
89 }
90
91 fromJSON (json) {
92 const x = new Bn().fromString(json.x)
93 const y = new Bn().fromString(json.y)
94 const point = new Point(x, y)
95 return this.copyFrom(point)
96 }
97
98 toString () {
99 return JSON.stringify(this.toJSON())
100 }
101
102 fromString (str) {
103 const json = JSON.parse(str)
104 const p = new Point().fromJSON(json)
105 return this.copyFrom(p)
106 }
107
108 static getG () {
109 const _g = ec.curve.g
110 const g = Object.create(Point.prototype)
111 return g.copyFrom(_g)
112 }
113
114 static getN () {
115 return new Bn(ec.curve.n.toArray())
116 }
117
118 // https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
119 validate () {
120 const p2 = Point.fromX(this.getY().isOdd(), this.getX())
121 if (!(p2.getY().cmp(this.getY()) === 0)) {
122 throw new Error('Invalid y value of public key')
123 }
124 if (
125 !(this.getX().gt(-1) && this.getX().lt(Point.getN())) ||
126 !(this.getY().gt(-1) && this.getY().lt(Point.getN()))
127 ) {
128 throw new Error('Point does not lie on the curve')
129 }
130 return this
131 }
132}
133
134export { Point }