Completed
Push — master ( a8a46d...6b0176 )
by thomas
23:45
created

ExtendedKeySerializer   B

Complexity

Total Complexity 11

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Test Coverage

Coverage 89.47%

Importance

Changes 0
Metric Value
dl 0
loc 142
ccs 51
cts 57
cp 0.8947
rs 7.8571
c 0
b 0
f 0
wmc 11
lcom 1
cbo 17

4 Methods

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