UNPKG

5.94 kBJavaScriptView Raw
1'use strict';
2Object.defineProperty(exports, '__esModule', { value: true });
3exports.ECPairFactory = exports.networks = void 0;
4const networks = require('./networks');
5exports.networks = networks;
6const types = require('./types');
7const randomBytes = require('randombytes');
8const wif = require('wif');
9const testecc_1 = require('./testecc');
10const isOptions = types.typeforce.maybe(
11 types.typeforce.compile({
12 compressed: types.maybe(types.Boolean),
13 network: types.maybe(types.Network),
14 }),
15);
16const toXOnly = (pubKey) =>
17 pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);
18function 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 // list of networks?
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 // otherwise, assume a network object (or default to bitcoin)
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 // It is not possible for both `__Q` and `__D` to be `undefined` at the same time.
90 // The factory methods guard for this.
91 const p = ecc.pointFromScalar(this.__D, this.compressed);
92 // It is not possible for `p` to be null.
93 // `fromPrivateKey()` checks that `__D` is a valid scalar.
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 // if first try is lowR, skip the loop
116 // for second try and on, add extra entropy counting up
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}
175exports.ECPairFactory = ECPairFactory;