1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | 'use strict'
|
9 |
|
10 | import { Point } from './point'
|
11 | import { Bn } from './bn'
|
12 | import { Bw } from './bw'
|
13 | import { Struct } from './struct'
|
14 | import { Workers } from './workers'
|
15 |
|
16 | class PubKey extends Struct {
|
17 | constructor (point, compressed) {
|
18 | super({ point, compressed })
|
19 | }
|
20 |
|
21 | fromJSON (json) {
|
22 | this.fromFastHex(json)
|
23 | return this
|
24 | }
|
25 |
|
26 | toJSON () {
|
27 | return this.toFastHex()
|
28 | }
|
29 |
|
30 | fromPrivKey (privKey) {
|
31 | this.fromObject({
|
32 | point: Point.getG().mul(privKey.bn),
|
33 | compressed: privKey.compressed
|
34 | })
|
35 | return this
|
36 | }
|
37 |
|
38 | static fromPrivKey (privKey) {
|
39 | return new this().fromPrivKey(privKey)
|
40 | }
|
41 |
|
42 | async asyncFromPrivKey (privKey) {
|
43 | const workersResult = await Workers.asyncObjectMethod(this, 'fromPrivKey', [
|
44 | privKey
|
45 | ])
|
46 | return this.fromFastBuffer(workersResult.resbuf)
|
47 | }
|
48 |
|
49 | static asyncFromPrivKey (privKey) {
|
50 | return new this().asyncFromPrivKey(privKey)
|
51 | }
|
52 |
|
53 | fromBuffer (buf, strict) {
|
54 | return this.fromDer(buf, strict)
|
55 | }
|
56 |
|
57 | async asyncFromBuffer (buf, strict) {
|
58 | const args = [buf, strict]
|
59 | const workersResult = await Workers.asyncObjectMethod(
|
60 | this,
|
61 | 'fromBuffer',
|
62 | args
|
63 | )
|
64 | return this.fromFastBuffer(workersResult.resbuf)
|
65 | }
|
66 |
|
67 | fromFastBuffer (buf) {
|
68 | if (buf.length === 0) {
|
69 | return this
|
70 | }
|
71 | const compressed = Boolean(buf[0])
|
72 | buf = buf.slice(1)
|
73 | this.fromDer(buf)
|
74 | this.compressed = compressed
|
75 | return this
|
76 | }
|
77 |
|
78 | |
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | fromDer (buf, strict) {
|
86 | if (strict === undefined) {
|
87 | strict = true
|
88 | } else {
|
89 | strict = false
|
90 | }
|
91 | if (
|
92 | buf[0] === 0x04 ||
|
93 | (!strict && (buf[0] === 0x06 || buf[0] === 0x07))
|
94 | ) {
|
95 | const xbuf = buf.slice(1, 33)
|
96 | const ybuf = buf.slice(33, 65)
|
97 | if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) {
|
98 | throw new Error('LEngth of x and y must be 32 bytes')
|
99 | }
|
100 | const x = new Bn(xbuf)
|
101 | const y = new Bn(ybuf)
|
102 | this.point = new Point(x, y)
|
103 | this.compressed = false
|
104 | } else if (buf[0] === 0x03) {
|
105 | const xbuf = buf.slice(1)
|
106 | const x = new Bn(xbuf)
|
107 | this.fromX(true, x)
|
108 | this.compressed = true
|
109 | } else if (buf[0] === 0x02) {
|
110 | const xbuf = buf.slice(1)
|
111 | const x = new Bn(xbuf)
|
112 | this.fromX(false, x)
|
113 | this.compressed = true
|
114 | } else {
|
115 | throw new Error('Invalid DER format pubKey')
|
116 | }
|
117 | return this
|
118 | }
|
119 |
|
120 | static fromDer (buf, strict) {
|
121 | return new this().fromDer(buf, strict)
|
122 | }
|
123 |
|
124 | fromString (str) {
|
125 | this.fromDer(Buffer.from(str, 'hex'))
|
126 | return this
|
127 | }
|
128 |
|
129 | fromX (odd, x) {
|
130 | if (typeof odd !== 'boolean') {
|
131 | throw new Error('Must specify whether y is odd or not (true or false)')
|
132 | }
|
133 | this.point = Point.fromX(odd, x)
|
134 | return this
|
135 | }
|
136 |
|
137 | static fromX (odd, x) {
|
138 | return new this().fromX(odd, x)
|
139 | }
|
140 |
|
141 | toBuffer () {
|
142 | const compressed = this.compressed === undefined ? true : this.compressed
|
143 | return this.toDer(compressed)
|
144 | }
|
145 |
|
146 | toFastBuffer () {
|
147 | if (!this.point) {
|
148 | return Buffer.alloc(0)
|
149 | }
|
150 | const bw = new Bw()
|
151 | const compressed =
|
152 | this.compressed === undefined ? true : Boolean(this.compressed)
|
153 | bw.writeUInt8(Number(compressed))
|
154 | bw.write(this.toDer(false))
|
155 | return bw.toBuffer()
|
156 | }
|
157 |
|
158 | toDer (compressed) {
|
159 | compressed = compressed === undefined ? this.compressed : compressed
|
160 | if (typeof compressed !== 'boolean') {
|
161 | throw new Error(
|
162 | 'Must specify whether the public key is compressed or not (true or false)'
|
163 | )
|
164 | }
|
165 |
|
166 | const x = this.point.getX()
|
167 | const y = this.point.getY()
|
168 |
|
169 | const xbuf = x.toBuffer({ size: 32 })
|
170 | const ybuf = y.toBuffer({ size: 32 })
|
171 |
|
172 | let prefix
|
173 | if (!compressed) {
|
174 | prefix = Buffer.from([0x04])
|
175 | return Buffer.concat([prefix, xbuf, ybuf])
|
176 | } else {
|
177 | const odd = ybuf[ybuf.length - 1] % 2
|
178 | if (odd) {
|
179 | prefix = Buffer.from([0x03])
|
180 | } else {
|
181 | prefix = Buffer.from([0x02])
|
182 | }
|
183 | return Buffer.concat([prefix, xbuf])
|
184 | }
|
185 | }
|
186 |
|
187 | toString () {
|
188 | const compressed = this.compressed === undefined ? true : this.compressed
|
189 | return this.toDer(compressed).toString('hex')
|
190 | }
|
191 |
|
192 | |
193 |
|
194 |
|
195 | static isCompressedOrUncompressed (buf) {
|
196 | if (buf.length < 33) {
|
197 |
|
198 | return false
|
199 | }
|
200 | if (buf[0] === 0x04) {
|
201 | if (buf.length !== 65) {
|
202 |
|
203 | return false
|
204 | }
|
205 | } else if (buf[0] === 0x02 || buf[0] === 0x03) {
|
206 | if (buf.length !== 33) {
|
207 |
|
208 | return false
|
209 | }
|
210 | } else {
|
211 |
|
212 | return false
|
213 | }
|
214 | return true
|
215 | }
|
216 |
|
217 |
|
218 | validate () {
|
219 | if (this.point.isInfinity()) {
|
220 | throw new Error('point: Point cannot be equal to Infinity')
|
221 | }
|
222 | if (this.point.eq(new Point(new Bn(0), new Bn(0)))) {
|
223 | throw new Error('point: Point cannot be equal to 0, 0')
|
224 | }
|
225 | this.point.validate()
|
226 | return this
|
227 | }
|
228 | }
|
229 |
|
230 | export { PubKey }
|