Completed
Pull Request — master (#662)
by thomas
38:24
created

ExtendedKeySerializer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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