Completed
Push — master ( abcf31...a8a46d )
by thomas
28:08 queued 25:46
created

ExtendedKeySerializer   B

Complexity

Total Complexity 11

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Test Coverage

Coverage 89.09%

Importance

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