Network::getHDPubByte()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Network;
6
7
use BitWasp\Bitcoin\Exceptions\InvalidNetworkParameter;
8
use BitWasp\Bitcoin\Exceptions\MissingBase58Prefix;
9
use BitWasp\Bitcoin\Exceptions\MissingBech32Prefix;
10
use BitWasp\Bitcoin\Exceptions\MissingBip32Prefix;
11
use BitWasp\Bitcoin\Exceptions\MissingNetworkParameter;
12
13
class Network implements NetworkInterface
14
{
15
    const BECH32_PREFIX_SEGWIT = "segwit";
16
17
    const BASE58_ADDRESS_P2PKH = "p2pkh";
18
    const BASE58_ADDRESS_P2SH = "p2sh";
19
    const BASE58_WIF = "wif";
20
    const BIP32_PREFIX_XPUB = "xpub";
21
    const BIP32_PREFIX_XPRV = "xprv";
22
23
    /**
24
     * @var array map of base58 address type to byte
25
     */
26
    protected $base58PrefixMap = [];
27
28
    /**
29
     * @var array map of bech32 address type to HRP
30
     */
31
    protected $bech32PrefixMap = [];
32
33
    /**
34
     * @var array map of bip32 type to bytes
35
     */
36
    protected $bip32PrefixMap = [];
37
38
    /**
39
     * @var array map of bip32 key type to script type
40
     */
41
    protected $bip32ScriptTypeMap = [];
42
43
    /**
44
     * @var string - message prefix for bitcoin signed messages
45
     */
46
    protected $signedMessagePrefix;
47
48
    /**
49
     * @var string - 4 bytes for p2p magic
50
     */
51
    protected $p2pMagic;
52
53
    /**
54
     * @param string $field - name of field being validated
55
     * @param string $value - we check this value
56
     * @throws InvalidNetworkParameter
57
     */
58 138
    private function validateHexStringRepresentsBytes(string $field, string $value)
59
    {
60 138
        if (!is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
61
            throw new InvalidNetworkParameter("{$field} must be a string");
62
        }
63
64 138
        $length = strlen($value);
65
66 138
        if ($length == 0) {
67
            throw new InvalidNetworkParameter("{$field} must be non-empty string");
68
        }
69
70 138
        if ($length % 2 !== 0) {
71
            throw new InvalidNetworkParameter("{$field} must have even number of characters (hex representing bytes)");
72
        }
73
74 138
        if (!ctype_xdigit($value)) {
75
            throw new InvalidNetworkParameter("{$field} prefix must be a valid hex string");
76
        }
77 138
    }
78
79
    /**
80
     * Network constructor.
81
     * @throws InvalidNetworkParameter
82
     */
83 138
    public function __construct()
84
    {
85 138
        if (null !== $this->p2pMagic) {
86 138
            $this->validateHexStringRepresentsBytes("P2P magic", $this->p2pMagic);
87
        }
88
89 138
        foreach ($this->base58PrefixMap as $type => $byte) {
90 138
            $this->validateHexStringRepresentsBytes("{$type} base58 prefix", $byte);
91
        }
92
93 138
        foreach ($this->bip32PrefixMap as $type => $bytes) {
94 138
            $this->validateHexStringRepresentsBytes("{$type} bip32 prefix", $bytes);
95
        }
96
97 138
        if (count($this->bip32ScriptTypeMap) !== count($this->bip32PrefixMap)) {
98
            throw new InvalidNetworkParameter("BIP32 prefixes not configured correctly. Number of items does not match.");
99
        }
100 138
    }
101
102
    /**
103
     * @param string $prefixType
104
     * @return bool
105
     */
106 78
    protected function hasBase58Prefix(string $prefixType): bool
107
    {
108 78
        return array_key_exists($prefixType, $this->base58PrefixMap);
109
    }
110
111
    /**
112
     * @param string $prefixType
113
     * @return string
114
     * @throws MissingBase58Prefix
115
     */
116 76
    protected function getBase58Prefix(string $prefixType): string
117
    {
118 76
        if (!$this->hasBase58Prefix($prefixType)) {
119 1
            throw new MissingBase58Prefix();
120
        }
121 75
        return $this->base58PrefixMap[$prefixType];
122
    }
123
124
    /**
125
     * @param string $prefixType
126
     * @return bool
127
     */
128 26
    protected function hasBech32Prefix(string $prefixType): bool
129
    {
130 26
        return array_key_exists($prefixType, $this->bech32PrefixMap);
131
    }
132
133
    /**
134
     * @param string $prefixType
135
     * @return string
136
     * @throws MissingBech32Prefix
137
     */
138 24
    protected function getBech32Prefix(string $prefixType): string
139
    {
140 24
        if (!$this->hasBech32Prefix($prefixType)) {
141 1
            throw new MissingBech32Prefix();
142
        }
143 23
        return $this->bech32PrefixMap[$prefixType];
144
    }
145
146
    /**
147
     * @param string $prefixType
148
     * @return bool
149
     */
150 75
    protected function hasBip32Prefix(string $prefixType): bool
151
    {
152 75
        return array_key_exists($prefixType, $this->bip32PrefixMap);
153
    }
154
155
    /**
156
     * @param string $prefixType
157
     * @return string
158
     * @throws MissingBip32Prefix
159
     */
160 73
    protected function getBip32Prefix(string $prefixType): string
161
    {
162 73
        if (!$this->hasBip32Prefix($prefixType)) {
163 1
            throw new MissingBip32Prefix();
164
        }
165 72
        return $this->bip32PrefixMap[$prefixType];
166
    }
167
168
    /**
169
     * @return string
170
     * @throws MissingNetworkParameter
171
     * @see NetworkInterface::getSignedMessageMagic
172
     */
173 22
    public function getSignedMessageMagic(): string
174
    {
175 22
        if (null === $this->signedMessagePrefix) {
176
            throw new MissingNetworkParameter("Missing magic string for signed message");
177
        }
178 22
        return $this->signedMessagePrefix;
179
    }
180
181
    /**
182
     * @return string
183
     * @throws MissingNetworkParameter
184
     * @see NetworkInterface::getNetMagicBytes()
185
     */
186 15
    public function getNetMagicBytes(): string
187
    {
188 15
        if (null === $this->p2pMagic) {
189
            throw new MissingNetworkParameter("Missing network magic bytes");
190
        }
191 15
        return $this->p2pMagic;
192
    }
193
194
    /**
195
     * @return string
196
     * @throws MissingBase58Prefix
197
     */
198 26
    public function getPrivByte(): string
199
    {
200 26
        return $this->getBase58Prefix(self::BASE58_WIF);
201
    }
202
203
    /**
204
     * @return string
205
     * @throws MissingBase58Prefix
206
     * @see NetworkInterface::getAddressByte()
207
     */
208 46
    public function getAddressByte(): string
209
    {
210 46
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2PKH);
211
    }
212
    /**
213
     * @return int
214
     * @throws MissingBase58Prefix
215
     * @see NetworkInterface::getAddressPrefixLength()
216
     */
217 20
    public function getAddressPrefixLength(): int
218
    {
219 20
        return strlen($this->getAddressByte()) / 2;
220
    }
221
222
    /**
223
     * @return string
224
     * @throws MissingBase58Prefix
225
     * @see NetworkInterface::getP2shByte()
226
     */
227 53
    public function getP2shByte(): string
228
    {
229 53
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2SH);
230
    }
231
232
    /**
233
     * @return int
234
     * @throws MissingBase58Prefix
235
     * @see NetworkInterface::getP2shPrefixLength()
236
     */
237 31
    public function getP2shPrefixLength(): int
238
    {
239 31
        return strlen($this->getP2shByte()) / 2;
240
    }
241
242
    /**
243
     * @return string
244
     * @throws MissingBip32Prefix
245
     * @see NetworkInterface::getHDPubByte()
246
     */
247 71
    public function getHDPubByte(): string
248
    {
249 71
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPUB);
250
    }
251
252
    /**
253
     * @return string
254
     * @throws MissingBip32Prefix
255
     * @see NetworkInterface::getHDPrivByte()
256
     */
257 71
    public function getHDPrivByte(): string
258
    {
259 71
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPRV);
260
    }
261
262
    /**
263
     * @return string
264
     * @throws MissingBech32Prefix
265
     * @see NetworkInterface::getSegwitBech32Prefix()
266
     */
267 22
    public function getSegwitBech32Prefix(): string
268
    {
269 22
        return $this->getBech32Prefix(self::BECH32_PREFIX_SEGWIT);
270
    }
271
}
272