Completed
Pull Request — master (#665)
by thomas
45:23 queued 43:14
created

ElectrumKey::withoutPrivateKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Key\Deterministic;
6
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\KeyInterface;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
10
use BitWasp\Bitcoin\Crypto\Hash;
11
use BitWasp\Buffertools\Buffer;
12
use BitWasp\Buffertools\BufferInterface;
13
14
class ElectrumKey
15
{
16
    /**
17
     * @var null|PrivateKeyInterface
18
     */
19
    private $masterPrivate;
20
21
    /**
22
     * @var PublicKeyInterface
23
     */
24
    private $masterPublic;
25
26
    /**
27
     * @param KeyInterface $masterKey
28
     */
29 5
    public function __construct(KeyInterface $masterKey)
30
    {
31 5
        if ($masterKey->isCompressed()) {
32 1
            throw new \RuntimeException('Electrum keys are not compressed');
33
        }
34
35 5
        if ($masterKey instanceof PrivateKeyInterface) {
36 4
            $this->masterPrivate = $masterKey;
37 4
            $this->masterPublic = $masterKey->getPublicKey();
38 1
        } elseif ($masterKey instanceof PublicKeyInterface) {
39 1
            $this->masterPublic = $masterKey;
40
        }
41 5
    }
42
43
    /**
44
     * @return PrivateKeyInterface
45
     */
46 3
    public function getMasterPrivateKey(): PrivateKeyInterface
47
    {
48 3
        if (null === $this->masterPrivate) {
49 1
            throw new \RuntimeException("Cannot produce master private key from master public key");
50
        }
51
52 2
        return $this->masterPrivate;
53
    }
54
55
    /**
56
     * @return PublicKeyInterface
57
     */
58 2
    public function getMasterPublicKey(): PublicKeyInterface
59
    {
60 2
        return $this->masterPublic;
61
    }
62
63
    /**
64
     * @return BufferInterface
65
     */
66 2
    public function getMPK(): BufferInterface
67
    {
68 2
        return $this->getMasterPublicKey()->getBuffer()->slice(1);
69
    }
70
71
    /**
72
     * @param int $sequence
73
     * @param bool $change
74
     * @return \GMP
75
     */
76 2
    public function getSequenceOffset(int $sequence, bool $change = false): \GMP
77
    {
78 2
        $seed = new Buffer(sprintf("%s:%d:%s", $sequence, $change ? 1 : 0, $this->getMPK()->getBinary()));
79 2
        return Hash::sha256d($seed)->getGmp();
80
    }
81
82
    /**
83
     * @param int $sequence
84
     * @param bool $change
85
     * @return KeyInterface
86
     */
87 2
    public function deriveChild(int $sequence, bool $change = false): KeyInterface
88
    {
89 2
        $key = is_null($this->masterPrivate) ? $this->masterPublic : $this->masterPrivate;
90 2
        return $key->tweakAdd($this->getSequenceOffset($sequence, $change));
91
    }
92
93
    /**
94
     * @return ElectrumKey
95
     */
96 2
    public function withoutPrivateKey(): ElectrumKey
97
    {
98 2
        $clone = clone $this;
99 2
        $clone->masterPrivate = null;
100 2
        return $clone;
101
    }
102
}
103