Completed
Pull Request — master (#583)
by thomas
58:28 queued 55:50
created

ExtendedKeySerializer::fromParser()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 19
c 2
b 0
f 0
nc 5
nop 2
dl 0
loc 29
ccs 17
cts 17
cp 1
crap 5
rs 8.439
1
<?php
2
3
4
namespace BitWasp\Bitcoin\Serializer\Key\HierarchicalKey;
5
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
7
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKey;
8
use BitWasp\Bitcoin\Key\PrivateKeyFactory;
9
use BitWasp\Bitcoin\Key\PublicKeyFactory;
10
use BitWasp\Bitcoin\Network\NetworkInterface;
11
use BitWasp\Bitcoin\Serializer\Types;
12
use BitWasp\Buffertools\Buffer;
13
use BitWasp\Buffertools\BufferInterface;
14
use BitWasp\Buffertools\Exceptions\ParserOutOfRange;
15
use BitWasp\Buffertools\Parser;
16
17
class ExtendedKeySerializer
18
{
19
    /**
20
     * @var EcAdapterInterface
21
     */
22
    private $ecAdapter;
23
24
    /**
25
     * @var \BitWasp\Buffertools\Types\ByteString
26
     */
27
    private $bytestring4;
28
29
    /**
30
     * @var \BitWasp\Buffertools\Types\Uint8
31
     */
32
    private $uint8;
33
34
    /**
35
     * @var \BitWasp\Buffertools\Types\Uint32
36
     */
37
    private $uint32;
38
39
    /**
40
     * @var \BitWasp\Buffertools\Types\ByteString
41
     */
42
    private $bytestring32;
43
44
    /**
45
     * @var \BitWasp\Buffertools\Types\ByteString
46
     */
47
    private $bytestring33;
48
49
    /**
50
     * @param EcAdapterInterface $ecAdapter
51
     * @throws \Exception
52
     */
53 26
    public function __construct(EcAdapterInterface $ecAdapter)
54
    {
55 26
        $this->ecAdapter = $ecAdapter;
56 26
        $this->bytestring4 = Types::bytestring(4);
57 26
        $this->uint8 = Types::uint8();
58 26
        $this->uint32 = Types::uint32();
59 26
        $this->bytestring32 = Types::bytestring(32);
60 26
        $this->bytestring33 = Types::bytestring(33);
61 26
    }
62
63
    /**
64
     * @param NetworkInterface $network
65
     * @throws \Exception
66
     */
67 26
    private function checkNetwork(NetworkInterface $network)
68
    {
69
        try {
70 26
            $network->getHDPrivByte();
71 26
            $network->getHDPubByte();
72
        } catch (\Exception $e) {
73
            throw new \Exception('Network not configured for HD wallets');
74
        }
75 26
    }
76
77
    /**
78
     * @param NetworkInterface $network
79
     * @param HierarchicalKey $key
80
     * @return Buffer
81
     */
82 6
    public function serialize(NetworkInterface $network, HierarchicalKey $key)
83
    {
84 6
        $this->checkNetwork($network);
85
86 6
        list ($prefix, $data) = $key->isPrivate()
87 6
            ? [$network->getHDPrivByte(), new Buffer("\x00". $key->getPrivateKey()->getBinary(), 33)]
88 6
            : [$network->getHDPubByte(), $key->getPublicKey()->getBuffer()];
89
90 6
        return new Buffer(
91 6
            pack("H*", $prefix) .
92 6
            $this->uint8->write($key->getDepth()) .
93 6
            $this->uint32->write($key->getFingerprint()) .
94 6
            $this->uint32->write($key->getSequence()) .
95 6
            $this->bytestring32->write($key->getChainCode()) .
96 6
            $this->bytestring33->write($data)
97
        );
98
    }
99
100
    /**
101
     * @param NetworkInterface $network
102
     * @param Parser $parser
103
     * @return HierarchicalKey
104
     * @throws ParserOutOfRange
105
     */
106 22
    public function fromParser(NetworkInterface $network, Parser $parser)
107
    {
108 22
        $this->checkNetwork($network);
109
110
        try {
111
            list ($bytes, $depth, $parentFingerprint, $sequence, $chainCode, $keyData) = [
112 22
                $this->bytestring4->read($parser),
113 21
                $this->uint8->read($parser),
114 21
                $this->uint32->read($parser),
115 21
                $this->uint32->read($parser),
116 21
                $this->bytestring32->read($parser),
117 20
                $this->bytestring33->read($parser),
118
            ];
119
120 20
            $bytes = $bytes->getHex();
121 2
        } catch (ParserOutOfRange $e) {
122 2
            throw new ParserOutOfRange('Failed to extract HierarchicalKey from parser');
123
        }
124
125 20
        if ($bytes !== $network->getHDPubByte() && $bytes !== $network->getHDPrivByte()) {
126 1
            throw new \InvalidArgumentException('HD key magic bytes do not match network magic bytes');
127
        }
128
129 19
        $key = ($network->getHDPrivByte() === $bytes)
130 11
            ? PrivateKeyFactory::fromHex($keyData->slice(1), true, $this->ecAdapter)
131 19
            : PublicKeyFactory::fromHex($keyData, $this->ecAdapter);
132
133 19
        return new HierarchicalKey($this->ecAdapter, $depth, $parentFingerprint, $sequence, $chainCode, $key);
134
    }
135
136
    /**
137
     * @param NetworkInterface $network
138
     * @param BufferInterface $buffer
139
     * @return HierarchicalKey
140
     */
141 22
    public function parse(NetworkInterface $network, BufferInterface $buffer)
142
    {
143 22
        return $this->fromParser($network, new Parser($buffer));
144
    }
145
}
146