Completed
Pull Request — master (#583)
by thomas
72:17
created

Network::validateHexString()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 5
nc 3
nop 3
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 4
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Network;
4
5
use BitWasp\Bitcoin\Exceptions\InvalidNetworkParameter;
6
use BitWasp\Bitcoin\Exceptions\MissingBase58Prefix;
7
use BitWasp\Bitcoin\Exceptions\MissingBech32Prefix;
8
use BitWasp\Bitcoin\Exceptions\MissingNetworkParameter;
9
10
class Network implements NetworkInterface
11
{
12
13
    const BECH32_PREFIX_SEGWIT = "segwit";
14
15
    const BASE58_PREFIX_P2PKH = "p2pkh";
16
    const BASE58_PREFIX_P2SH = "p2sh";
17
18
    const BIP32_PREFIX_XPUB = "xpub";
19
    const BIP32_PREFIX_XPRV = "xprv";
20
21
    /**
22
     * @var array map of base58 address type to byte
23
     */
24
    protected $base58PrefixMap = [];
25
26
    /**
27
     * @var array map of bech32 address type to HRP
28
     */
29
    protected $bech32PrefixMap = [];
30
31
    /**
32
     * @var array map of bip32 type to bytes
33
     */
34
    protected $bip32ByteMap = [];
35
36
    /**
37
     * @var array map of bip32 key type to script type
38
     */
39
    protected $bip32ScriptTypeMap = [];
40
41
    /**
42
     * @var string - single byte prefix for WIF encoding
43
     */
44
    protected $wifPrefix;
45
46
    /**
47
     * @var string - message prefix for bitcoin signed messages
48
     */
49
    protected $signedMessagePrefix;
50
51
    /**
52
     * @var string - 4 bytes for p2p magic
53
     */
54
    protected $p2pMagic;
55
56 134
    private function validateHexString($field, $value, $length)
57
    {
58 134
        if (!is_string($value) || strlen($value) !== 2 * $length) {
59 2
            throw new InvalidNetworkParameter("{$field} must be a {$length} byte hex string");
60
        }
61
62 132
        if (!ctype_xdigit($value)) {
63 2
            throw new InvalidNetworkParameter("{$field} prefix must be a valid hex string");
64
        }
65
    }
66 130
67 2
    public function __construct()
68
    {
69
        if (null !== $this->wifPrefix) {
70 128
            $this->validateHexString("WIF prefix", $this->wifPrefix, 1);
71 2
        }
72
73
        if (null !== $this->p2pMagic) {
74 126
            $this->validateHexString("P2P magic", $this->p2pMagic, 4);
75 126
        }
76 126
77 126
        foreach ($this->base58PrefixMap as $type => $byte) {
78 126
            $this->validateHexString("{$type} base58 prefix", $byte, 1);
79
        }
80
81
        foreach ($this->bip32ByteMap as $type => $bytes) {
82
            $this->validateHexString("{$type} bip32 prefix", $bytes, 4);
83 8
        }
84
    }
85 8
86
    /**
87
     * @param string $prefixType
88
     * @return bool
89
     */
90
    protected function hasBase58Prefix($prefixType)
91 48
    {
92
        return array_key_exists($prefixType, $this->base58PrefixMap);
93 48
    }
94
95
    /**
96
     * @param string $prefixType
97
     * @return string
98
     * @throws MissingBase58Prefix
99 20
     */
100
    protected function getBase58Prefix($prefixType)
101 20
    {
102
        if (!$this->hasBase58Prefix($prefixType)) {
103
            throw new MissingBase58Prefix();
104
        }
105
        return $this->base58PrefixMap[$prefixType];
106
    }
107 70
108
    /**
109 70
     * @param string $prefixType
110
     * @return bool
111
     */
112
    protected function hasBech32Prefix($prefixType)
113
    {
114
        return array_key_exists($prefixType, $this->bech32PrefixMap);
115
    }
116
117
    /**
118 60
     * @param string $prefixType
119
     * @return string
120 60
     * @throws MissingBech32Prefix
121 2
     */
122
    protected function getBech32Prefix($prefixType)
123
    {
124 58
        if (!$this->hasBase58Prefix($prefixType)) {
125
            throw new MissingBech32Prefix();
126
        }
127
        return $this->bech32PrefixMap[$prefixType];
128
    }
129
130
    /**
131
     * @param string $prefixType
132
     * @return bool
133 108
     */
134
    protected function hasBip32Prefix($prefixType)
135 108
    {
136 108
        return array_key_exists($prefixType, $this->bech32PrefixMap);
137
    }
138
139 108
    /**
140
     * @param string $prefixType
141
     * @return string
142
     * @throws MissingBech32Prefix
143
     */
144
    protected function getBip32Prefix($prefixType)
145
    {
146
        if (!$this->hasBase58Prefix($prefixType)) {
147
            throw new MissingBech32Prefix();
148 60
        }
149
        return $this->bech32PrefixMap[$prefixType];
150 60
    }
151 2
152
    /**
153
     * @return string
154 58
     * @throws MissingNetworkParameter
155
     */
156
    public function getSignedMessageMagic()
157
    {
158
        if (null === $this->signedMessagePrefix) {
159
            throw new MissingNetworkParameter("Missing magic string for signed message");
160
        }
161
        return $this->signedMessagePrefix;
162
    }
163 108
164
    /**
165 108
     * @return string
166 108
     * @throws MissingNetworkParameter
167
     */
168
    public function getNetMagicBytes()
169 108
    {
170
        if (null === $this->p2pMagic) {
171
            throw new MissingNetworkParameter("Missing network magic bytes");
172
        }
173
        return $this->p2pMagic;
174
    }
175
176 104
    /**
177
     * @return string
178 104
     * @throws MissingNetworkParameter
179 104
     */
180
    public function getPrivByte()
181
    {
182
        if (null === $this->wifPrefix) {
183
            throw new MissingNetworkParameter("Missing private key / WIF prefix");
184
        }
185
        return $this->wifPrefix;
186 10
    }
187
188 10
    /**
189 2
     * @inheritdoc
190
     */
191
    public function getAddressByte()
192 8
    {
193
        return $this->getBase58Prefix(self::BASE58_PREFIX_P2PKH);
194
    }
195
196
    /**
197
     * @inheritdoc
198
     */
199 104
    public function getP2shByte()
200
    {
201 104
        return $this->getBase58Prefix(self::BASE58_PREFIX_P2SH);
202
    }
203
204
    /**
205 104
     * Get version bytes for XPUB key
206 104
     *
207
     * @return string
208
     * @throws \Exception
209
     */
210
    public function getHDPubByte()
211
    {
212
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPUB);
213 54
    }
214
215 54
    /**
216
     * Get version bytes for XPUB key
217
     *
218
     * @return string
219 54
     * @throws \Exception
220
     */
221
    public function getHDPrivByte()
222
    {
223
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPRV);
224
    }
225
226
    /**
227
     * @return bool
228
     * @throws \Exception
229
     */
230
    public function getSegwitBech32Prefix()
231
    {
232
        return $this->getBech32Prefix(self::BECH32_PREFIX_SEGWIT);
233
    }
234
}
235