Completed
Pull Request — master (#446)
by thomas
228:15 queued 224:06
created

ExtendedKeySerializer::getTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 11
ccs 7
cts 7
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
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
use BitWasp\Buffertools\Template;
17
18
class ExtendedKeySerializer
19
{
20
    /**
21
     * @var EcAdapterInterface
22
     */
23
    private $ecAdapter;
24
25
    /**
26
     * @param EcAdapterInterface $ecAdapter
27
     * @throws \Exception
28
     */
29
    public function __construct(EcAdapterInterface $ecAdapter)
30
    {
31
        $this->ecAdapter = $ecAdapter;
32
        $uint32 = Types::uint32();
33
        $this->template = new Template([
0 ignored issues
show
Bug introduced by
The property template does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
34 120
            Types::bytestring(4),
35
            Types::uint8(),
36
            $uint32,
37 120
            $uint32,
38 114
            Types::bytestring(32),
39 63
            Types::bytestring(33)
40 6
        ]);
41
    }
42
43 114
    /**
44 114
     * @param NetworkInterface $network
45 114
     * @throws \Exception
46
     */
47
    private function checkNetwork(NetworkInterface $network)
48
    {
49
        try {
50 114
            $network->getHDPrivByte();
51
            $network->getHDPubByte();
52 114
        } catch (\Exception $e) {
53 114
            throw new \Exception('Network not configured for HD wallets');
54 114
        }
55 114
    }
56 114
57 114
    /**
58 114
     * @param NetworkInterface $network
59 114
     * @param HierarchicalKey $key
60
     * @return Buffer
61
     */
62
    public function serialize(NetworkInterface $network, HierarchicalKey $key)
63
    {
64
        $this->checkNetwork($network);
65
66 30
        list ($prefix, $data) = $key->isPrivate()
67
            ? [$network->getHDPrivByte(), new Buffer("\x00". $key->getPrivateKey()->getBinary(), 33)]
68 30
            : [$network->getHDPubByte(), $key->getPublicKey()->getBuffer()];
69 30
70 30
        return $this->template->write([
71
            Buffer::hex($prefix, 4),
72 30
            $key->getDepth(),
73 30
            $key->getFingerprint(),
74 30
            $key->getSequence(),
75 30
            $key->getChainCode(),
76 30
            $data
77 30
        ]);
78 30
    }
79 15
80
    /**
81
     * @param NetworkInterface $network
82
     * @param Parser $parser
83
     * @return HierarchicalKey
84
     * @throws ParserOutOfRange
85
     */
86
    public function fromParser(NetworkInterface $network, Parser $parser)
87 96
    {
88
        $this->checkNetwork($network);
89
90 96
        try {
91
            list ($bytes, $depth, $parentFingerprint, $sequence, $chainCode, $keyData) = $this->template->parse($parser);
92
93 84
            /** @var BufferInterface $keyData */
94 54
            /** @var BufferInterface $bytes */
95 12
            $bytes = $bytes->getHex();
96
        } catch (ParserOutOfRange $e) {
97
            throw new ParserOutOfRange('Failed to extract HierarchicalKey from parser');
98 84
        }
99 6
100
        if ($bytes !== $network->getHDPubByte() && $bytes !== $network->getHDPrivByte()) {
101
            throw new \InvalidArgumentException('HD key magic bytes do not match network magic bytes');
102 78
        }
103 54
104 78
        $key = ($network->getHDPrivByte() === $bytes)
105
            ? PrivateKeyFactory::fromHex($keyData->slice(1), true, $this->ecAdapter)
106 78
            : PublicKeyFactory::fromHex($keyData, $this->ecAdapter);
107
108
        return new HierarchicalKey($this->ecAdapter, $depth, $parentFingerprint, $sequence, $chainCode, $key);
109
    }
110
111
    /**
112
     * @param NetworkInterface $network
113
     * @param BufferInterface $buffer
114
     * @return HierarchicalKey
115 96
     */
116
    public function parse(NetworkInterface $network, BufferInterface $buffer)
117 96
    {
118 96
        return $this->fromParser($network, new Parser($buffer));
119
    }
120
}
121