Completed
Pull Request — 0.0.35 (#660)
by thomas
29:47 queued 20:44
created

ExtendedKeySerializer   B

Complexity

Total Complexity 11

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Test Coverage

Coverage 98.18%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
dl 0
loc 128
ccs 54
cts 55
cp 0.9818
rs 8.4614
c 3
b 1
f 0
wmc 11
lcom 1
cbo 16

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
B serialize() 0 36 4
B fromParser() 0 35 5
A parse() 0 4 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Serializer\Key\HierarchicalKey;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Key\Deterministic\HdPrefix\GlobalPrefixConfig;
7
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKey;
8
use BitWasp\Bitcoin\Key\KeyToScript\Factory\P2pkhScriptDataFactory;
9
use BitWasp\Bitcoin\Key\PrivateKeyFactory;
10
use BitWasp\Bitcoin\Key\PublicKeyFactory;
11
use BitWasp\Bitcoin\Network\NetworkInterface;
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 RawExtendedKeySerializer
26
     */
27
    private $rawSerializer;
28
29
    /**
30
     * @var P2pkhScriptDataFactory
31
     */
32
    private $defaultScriptFactory;
33
34
    /**
35
     * @var GlobalPrefixConfig
36
     */
37
    private $prefixConfig;
38
39
    /**
40
     * @param EcAdapterInterface $ecAdapter
41
     * @param GlobalPrefixConfig|null $config
42
     */
43 56
    public function __construct(EcAdapterInterface $ecAdapter, GlobalPrefixConfig $config = null)
44
    {
45 56
        $this->ecAdapter = $ecAdapter;
46 56
        $this->rawSerializer = new RawExtendedKeySerializer($ecAdapter);
47 56
        $this->defaultScriptFactory = new P2pkhScriptDataFactory();
48 56
        $this->prefixConfig = $config;
49 56
    }
50
51
    /**
52
     * @param NetworkInterface $network
53
     * @param HierarchicalKey $key
54
     * @return BufferInterface
55
     */
56 28
    public function serialize(NetworkInterface $network, HierarchicalKey $key)
57
    {
58 28
        if (null === $this->prefixConfig) {
59 18
            if ($key->getScriptDataFactory()->getScriptType() !== $this->defaultScriptFactory->getScriptType()) {
60
                throw new \InvalidArgumentException("Cannot serialize non-P2PKH HierarchicalKeys without a GlobalPrefixConfig");
61
            }
62 18
            $privatePrefix = $network->getHDPrivByte();
63 18
            $publicPrefix = $network->getHDPubByte();
64
        } else {
65 10
            $scriptConfig = $this->prefixConfig
66 10
                ->getNetworkConfig($network)
67 10
                ->getConfigForScriptType($key->getScriptDataFactory()->getScriptType())
68
            ;
69 10
            $privatePrefix = $scriptConfig->getPrivatePrefix();
70 10
            $publicPrefix = $scriptConfig->getPublicPrefix();
71
        }
72
73 28
        if ($key->isPrivate()) {
74 28
            $prefix = $privatePrefix;
75 28
            $keyData = new Buffer("\x00{$key->getPrivateKey()->getBinary()}");
76
        } else {
77 25
            $prefix = $publicPrefix;
78 25
            $keyData = $key->getPublicKey()->getBuffer();
79
        }
80
81 28
        return $this->rawSerializer->serialize(
82 28
            new RawKeyParams(
83 28
                $prefix,
84 28
                $key->getDepth(),
85 28
                $key->getFingerprint(),
86 28
                $key->getSequence(),
87 28
                $key->getChainCode(),
88 28
                $keyData
89
            )
90
        );
91
    }
92
93
    /**
94
     * @param NetworkInterface $network
95
     * @param Parser $parser
96
     * @return HierarchicalKey
97
     * @throws ParserOutOfRange
98
     */
99 40
    public function fromParser(NetworkInterface $network, Parser $parser)
100
    {
101 40
        $params = $this->rawSerializer->fromParser($parser);
102
103 37
        if (null === $this->prefixConfig) {
104 35
            if (!($params->getPrefix() === $network->getHDPubByte() || $params->getPrefix() === $network->getHDPrivByte())) {
105 1
                throw new \InvalidArgumentException('HD key magic bytes do not match network magic bytes');
106
            }
107 34
            $privatePrefix = $network->getHDPrivByte();
108 34
            $scriptFactory = $this->defaultScriptFactory;
109
        } else {
110 2
            $scriptConfig = $this->prefixConfig
111 2
                ->getNetworkConfig($network)
112 2
                ->getConfigForPrefix($params->getPrefix())
113
            ;
114 2
            $privatePrefix = $scriptConfig->getPrivatePrefix();
115 2
            $scriptFactory = $scriptConfig->getScriptDataFactory();
116
        }
117
118 36
        if ($params->getPrefix() === $privatePrefix) {
119 20
            $key = PrivateKeyFactory::fromHex($params->getKeyData()->slice(1), true, $this->ecAdapter);
120
        } else {
121 24
            $key = PublicKeyFactory::fromHex($params->getKeyData(), $this->ecAdapter);
122
        }
123
124 36
        return new HierarchicalKey(
125 36
            $this->ecAdapter,
126 36
            $scriptFactory,
127 36
            $params->getDepth(),
128 36
            $params->getParentFingerprint(),
129 36
            $params->getSequence(),
130 36
            $params->getChainCode(),
131 36
            $key
132
        );
133
    }
134
135
    /**
136
     * @param NetworkInterface $network
137
     * @param BufferInterface $buffer
138
     * @return HierarchicalKey
139
     */
140 40
    public function parse(NetworkInterface $network, BufferInterface $buffer)
141
    {
142 40
        return $this->fromParser($network, new Parser($buffer));
143
    }
144
}
145