1 | 'use strict';
|
2 | Object.defineProperty(exports, '__esModule', { value: true });
|
3 | exports.ECPairFactory = exports.networks = void 0;
|
4 | const networks = require('./networks');
|
5 | exports.networks = networks;
|
6 | const types = require('./types');
|
7 | const randomBytes = require('randombytes');
|
8 | const wif = require('wif');
|
9 | const testecc_1 = require('./testecc');
|
10 | const isOptions = types.typeforce.maybe(
|
11 | types.typeforce.compile({
|
12 | compressed: types.maybe(types.Boolean),
|
13 | network: types.maybe(types.Network),
|
14 | }),
|
15 | );
|
16 | const toXOnly = (pubKey) =>
|
17 | pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);
|
18 | function ECPairFactory(ecc) {
|
19 | (0, testecc_1.testEcc)(ecc);
|
20 | function isPoint(maybePoint) {
|
21 | return ecc.isPoint(maybePoint);
|
22 | }
|
23 | function fromPrivateKey(buffer, options) {
|
24 | types.typeforce(types.Buffer256bit, buffer);
|
25 | if (!ecc.isPrivate(buffer))
|
26 | throw new TypeError('Private key not in range [1, n)');
|
27 | types.typeforce(isOptions, options);
|
28 | return new ECPair(buffer, undefined, options);
|
29 | }
|
30 | function fromPublicKey(buffer, options) {
|
31 | types.typeforce(ecc.isPoint, buffer);
|
32 | types.typeforce(isOptions, options);
|
33 | return new ECPair(undefined, buffer, options);
|
34 | }
|
35 | function fromWIF(wifString, network) {
|
36 | const decoded = wif.decode(wifString);
|
37 | const version = decoded.version;
|
38 |
|
39 | if (types.Array(network)) {
|
40 | network = network
|
41 | .filter((x) => {
|
42 | return version === x.wif;
|
43 | })
|
44 | .pop();
|
45 | if (!network) throw new Error('Unknown network version');
|
46 |
|
47 | } else {
|
48 | network = network || networks.bitcoin;
|
49 | if (version !== network.wif) throw new Error('Invalid network version');
|
50 | }
|
51 | return fromPrivateKey(decoded.privateKey, {
|
52 | compressed: decoded.compressed,
|
53 | network: network,
|
54 | });
|
55 | }
|
56 | function makeRandom(options) {
|
57 | types.typeforce(isOptions, options);
|
58 | if (options === undefined) options = {};
|
59 | const rng = options.rng || randomBytes;
|
60 | let d;
|
61 | do {
|
62 | d = rng(32);
|
63 | types.typeforce(types.Buffer256bit, d);
|
64 | } while (!ecc.isPrivate(d));
|
65 | return fromPrivateKey(d, options);
|
66 | }
|
67 | class ECPair {
|
68 | __D;
|
69 | __Q;
|
70 | compressed;
|
71 | network;
|
72 | lowR;
|
73 | constructor(__D, __Q, options) {
|
74 | this.__D = __D;
|
75 | this.__Q = __Q;
|
76 | this.lowR = false;
|
77 | if (options === undefined) options = {};
|
78 | this.compressed =
|
79 | options.compressed === undefined ? true : options.compressed;
|
80 | this.network = options.network || networks.bitcoin;
|
81 | if (__Q !== undefined)
|
82 | this.__Q = Buffer.from(ecc.pointCompress(__Q, this.compressed));
|
83 | }
|
84 | get privateKey() {
|
85 | return this.__D;
|
86 | }
|
87 | get publicKey() {
|
88 | if (!this.__Q) {
|
89 |
|
90 |
|
91 | const p = ecc.pointFromScalar(this.__D, this.compressed);
|
92 |
|
93 |
|
94 | this.__Q = Buffer.from(p);
|
95 | }
|
96 | return this.__Q;
|
97 | }
|
98 | toWIF() {
|
99 | if (!this.__D) throw new Error('Missing private key');
|
100 | return wif.encode(this.network.wif, this.__D, this.compressed);
|
101 | }
|
102 | tweak(t) {
|
103 | if (this.privateKey) return this.tweakFromPrivateKey(t);
|
104 | return this.tweakFromPublicKey(t);
|
105 | }
|
106 | sign(hash, lowR) {
|
107 | if (!this.__D) throw new Error('Missing private key');
|
108 | if (lowR === undefined) lowR = this.lowR;
|
109 | if (lowR === false) {
|
110 | return Buffer.from(ecc.sign(hash, this.__D));
|
111 | } else {
|
112 | let sig = ecc.sign(hash, this.__D);
|
113 | const extraData = Buffer.alloc(32, 0);
|
114 | let counter = 0;
|
115 |
|
116 |
|
117 | while (sig[0] > 0x7f) {
|
118 | counter++;
|
119 | extraData.writeUIntLE(counter, 0, 6);
|
120 | sig = ecc.sign(hash, this.__D, extraData);
|
121 | }
|
122 | return Buffer.from(sig);
|
123 | }
|
124 | }
|
125 | signSchnorr(hash) {
|
126 | if (!this.privateKey) throw new Error('Missing private key');
|
127 | if (!ecc.signSchnorr)
|
128 | throw new Error('signSchnorr not supported by ecc library');
|
129 | return Buffer.from(ecc.signSchnorr(hash, this.privateKey));
|
130 | }
|
131 | verify(hash, signature) {
|
132 | return ecc.verify(hash, this.publicKey, signature);
|
133 | }
|
134 | verifySchnorr(hash, signature) {
|
135 | if (!ecc.verifySchnorr)
|
136 | throw new Error('verifySchnorr not supported by ecc library');
|
137 | return ecc.verifySchnorr(hash, this.publicKey.subarray(1, 33), signature);
|
138 | }
|
139 | tweakFromPublicKey(t) {
|
140 | const xOnlyPubKey = toXOnly(this.publicKey);
|
141 | const tweakedPublicKey = ecc.xOnlyPointAddTweak(xOnlyPubKey, t);
|
142 | if (!tweakedPublicKey || tweakedPublicKey.xOnlyPubkey === null)
|
143 | throw new Error('Cannot tweak public key!');
|
144 | const parityByte = Buffer.from([
|
145 | tweakedPublicKey.parity === 0 ? 0x02 : 0x03,
|
146 | ]);
|
147 | return fromPublicKey(
|
148 | Buffer.concat([parityByte, tweakedPublicKey.xOnlyPubkey]),
|
149 | { network: this.network, compressed: this.compressed },
|
150 | );
|
151 | }
|
152 | tweakFromPrivateKey(t) {
|
153 | const hasOddY =
|
154 | this.publicKey[0] === 3 ||
|
155 | (this.publicKey[0] === 4 && (this.publicKey[64] & 1) === 1);
|
156 | const privateKey = hasOddY
|
157 | ? ecc.privateNegate(this.privateKey)
|
158 | : this.privateKey;
|
159 | const tweakedPrivateKey = ecc.privateAdd(privateKey, t);
|
160 | if (!tweakedPrivateKey) throw new Error('Invalid tweaked private key!');
|
161 | return fromPrivateKey(Buffer.from(tweakedPrivateKey), {
|
162 | network: this.network,
|
163 | compressed: this.compressed,
|
164 | });
|
165 | }
|
166 | }
|
167 | return {
|
168 | isPoint,
|
169 | fromPrivateKey,
|
170 | fromPublicKey,
|
171 | fromWIF,
|
172 | makeRandom,
|
173 | };
|
174 | }
|
175 | exports.ECPairFactory = ECPairFactory;
|