1 | 'use strict';
|
2 | Object.defineProperty(exports, '__esModule', { value: true });
|
3 | exports.p2pkh = void 0;
|
4 | const bcrypto = require('../crypto');
|
5 | const networks_1 = require('../networks');
|
6 | const bscript = require('../script');
|
7 | const types_1 = require('../types');
|
8 | const lazy = require('./lazy');
|
9 | const bs58check = require('bs58check');
|
10 | const OPS = bscript.OPS;
|
11 |
|
12 |
|
13 | function p2pkh(a, opts) {
|
14 | if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input)
|
15 | throw new TypeError('Not enough data');
|
16 | opts = Object.assign({ validate: true }, opts || {});
|
17 | (0, types_1.typeforce)(
|
18 | {
|
19 | network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
20 | address: types_1.typeforce.maybe(types_1.typeforce.String),
|
21 | hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
|
22 | output: types_1.typeforce.maybe(types_1.typeforce.BufferN(25)),
|
23 | pubkey: types_1.typeforce.maybe(types_1.isPoint),
|
24 | signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
|
25 | input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
26 | },
|
27 | a,
|
28 | );
|
29 | const _address = lazy.value(() => {
|
30 | const payload = Buffer.from(bs58check.decode(a.address));
|
31 | const version = payload.readUInt8(0);
|
32 | const hash = payload.slice(1);
|
33 | return { version, hash };
|
34 | });
|
35 | const _chunks = lazy.value(() => {
|
36 | return bscript.decompile(a.input);
|
37 | });
|
38 | const network = a.network || networks_1.bitcoin;
|
39 | const o = { name: 'p2pkh', network };
|
40 | lazy.prop(o, 'address', () => {
|
41 | if (!o.hash) return;
|
42 | const payload = Buffer.allocUnsafe(21);
|
43 | payload.writeUInt8(network.pubKeyHash, 0);
|
44 | o.hash.copy(payload, 1);
|
45 | return bs58check.encode(payload);
|
46 | });
|
47 | lazy.prop(o, 'hash', () => {
|
48 | if (a.output) return a.output.slice(3, 23);
|
49 | if (a.address) return _address().hash;
|
50 | if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey);
|
51 | });
|
52 | lazy.prop(o, 'output', () => {
|
53 | if (!o.hash) return;
|
54 | return bscript.compile([
|
55 | OPS.OP_DUP,
|
56 | OPS.OP_HASH160,
|
57 | o.hash,
|
58 | OPS.OP_EQUALVERIFY,
|
59 | OPS.OP_CHECKSIG,
|
60 | ]);
|
61 | });
|
62 | lazy.prop(o, 'pubkey', () => {
|
63 | if (!a.input) return;
|
64 | return _chunks()[1];
|
65 | });
|
66 | lazy.prop(o, 'signature', () => {
|
67 | if (!a.input) return;
|
68 | return _chunks()[0];
|
69 | });
|
70 | lazy.prop(o, 'input', () => {
|
71 | if (!a.pubkey) return;
|
72 | if (!a.signature) return;
|
73 | return bscript.compile([a.signature, a.pubkey]);
|
74 | });
|
75 | lazy.prop(o, 'witness', () => {
|
76 | if (!o.input) return;
|
77 | return [];
|
78 | });
|
79 |
|
80 | if (opts.validate) {
|
81 | let hash = Buffer.from([]);
|
82 | if (a.address) {
|
83 | if (_address().version !== network.pubKeyHash)
|
84 | throw new TypeError('Invalid version or Network mismatch');
|
85 | if (_address().hash.length !== 20) throw new TypeError('Invalid address');
|
86 | hash = _address().hash;
|
87 | }
|
88 | if (a.hash) {
|
89 | if (hash.length > 0 && !hash.equals(a.hash))
|
90 | throw new TypeError('Hash mismatch');
|
91 | else hash = a.hash;
|
92 | }
|
93 | if (a.output) {
|
94 | if (
|
95 | a.output.length !== 25 ||
|
96 | a.output[0] !== OPS.OP_DUP ||
|
97 | a.output[1] !== OPS.OP_HASH160 ||
|
98 | a.output[2] !== 0x14 ||
|
99 | a.output[23] !== OPS.OP_EQUALVERIFY ||
|
100 | a.output[24] !== OPS.OP_CHECKSIG
|
101 | )
|
102 | throw new TypeError('Output is invalid');
|
103 | const hash2 = a.output.slice(3, 23);
|
104 | if (hash.length > 0 && !hash.equals(hash2))
|
105 | throw new TypeError('Hash mismatch');
|
106 | else hash = hash2;
|
107 | }
|
108 | if (a.pubkey) {
|
109 | const pkh = bcrypto.hash160(a.pubkey);
|
110 | if (hash.length > 0 && !hash.equals(pkh))
|
111 | throw new TypeError('Hash mismatch');
|
112 | else hash = pkh;
|
113 | }
|
114 | if (a.input) {
|
115 | const chunks = _chunks();
|
116 | if (chunks.length !== 2) throw new TypeError('Input is invalid');
|
117 | if (!bscript.isCanonicalScriptSignature(chunks[0]))
|
118 | throw new TypeError('Input has invalid signature');
|
119 | if (!(0, types_1.isPoint)(chunks[1]))
|
120 | throw new TypeError('Input has invalid pubkey');
|
121 | if (a.signature && !a.signature.equals(chunks[0]))
|
122 | throw new TypeError('Signature mismatch');
|
123 | if (a.pubkey && !a.pubkey.equals(chunks[1]))
|
124 | throw new TypeError('Pubkey mismatch');
|
125 | const pkh = bcrypto.hash160(chunks[1]);
|
126 | if (hash.length > 0 && !hash.equals(pkh))
|
127 | throw new TypeError('Hash mismatch');
|
128 | }
|
129 | }
|
130 | return Object.assign(o, a);
|
131 | }
|
132 | exports.p2pkh = p2pkh;
|