Completed
Pull Request — master (#517)
by thomas
72:19
created

SegwitBech32::decode()   C

Complexity

Conditions 8
Paths 14

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 19
nc 14
nop 2
dl 0
loc 32
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin;
4
5
use BitWasp\Bitcoin\Exceptions\Bech32Exception;
6
use BitWasp\Bitcoin\Network\NetworkInterface;
7
use BitWasp\Bitcoin\Script\WitnessProgram;
8
use BitWasp\Buffertools\Buffer;
9
10
class SegwitBech32
11
{
12
    /**
13
     * Takes the $hrp and $witnessProgram and produces a native segwit
14
     * address.
15
     *
16
     * @param WitnessProgram $witnessProgram
17
     * @param NetworkInterface $network
18
     * @return string
19
     */
20
    public static function encode(WitnessProgram $witnessProgram, NetworkInterface $network = null)
21
    {
22
        // do this first, why bother encoding if the network doesn't support it..
23
        $network = $network ?: Bitcoin::getNetwork();
24
        $hrp = $network->getSegwitBech32Prefix();
25
26
        $programChars = array_values(unpack('C*', $witnessProgram->getProgram()->getBinary()));
27
        $programBits = Bech32::convertBits($programChars, count($programChars), 8, 5, true);
28
        $encodeData = array_merge([$witnessProgram->getVersion()], $programBits);
29
30
        return Bech32::encode($hrp, $encodeData);
31
    }
32
33
    /**
34
     * Decodes the provided $bech32 string, validating against
35
     * the chosen prefix.
36
     *
37
     * @param string $bech32
38
     * @param NetworkInterface $network
39
     * @return WitnessProgram
40
     * @throws Bech32Exception
41
     */
42
    public static function decode($bech32, NetworkInterface $network = null)
43
    {
44
        $network = $network ?: Bitcoin::getNetwork();
45
        $hrp = $network->getSegwitBech32Prefix();
46
47
        list ($hrpGot, $data) = Bech32::decode($bech32);
48
        if ($hrpGot !== $hrp) {
49
            throw new Bech32Exception('Invalid prefix for address');
50
        }
51
52
        $decoded = Bech32::convertBits(array_slice($data, 1), count($data) - 1, 5, 8, false);
53
        $decodeLen = count($decoded);
54
        if ($decodeLen < 2 || $decodeLen > 40) {
55
            throw new Bech32Exception('Invalid segwit address');
56
        }
57
58
        if ($data[0] > 16) {
59
            throw new Bech32Exception('Invalid witness program version');
60
        }
61
62
        $bytes = '';
63
        foreach ($decoded as $char) {
64
            $bytes .= chr($char);
65
        }
66
        $decoded = new Buffer($bytes);
67
68
        if (0 === $data[0]) {
69
            return WitnessProgram::v0($decoded);
70
        }
71
72
        return new WitnessProgram($data[0], $decoded);
73
    }
74
}
75