Completed
Push — master ( 4963c9...d80e29 )
by thomas
18:26 queued 14:36
created

PrivateKey   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 60.44%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 18
c 1
b 0
f 0
lcom 1
cbo 9
dl 0
loc 177
ccs 55
cts 91
cp 0.6044
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A sign() 0 4 1
A isCompressed() 0 4 1
A getSecretMultiplier() 0 4 1
A getSecretBinary() 0 4 1
A getBuffer() 0 4 1
A __construct() 0 20 4
A getPublicKey() 0 15 3
A tweakAdd() 0 20 2
A tweakMul() 0 20 2
A toWif() 0 6 2
1
<?php
2
3
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Adapter\EcAdapter;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Serializer\Key\PrivateKeySerializer;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\Signature;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\Key;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
11
use BitWasp\Bitcoin\Crypto\Random\RbgInterface;
12
use BitWasp\Bitcoin\Exceptions\InvalidPrivateKey;
13
use BitWasp\Bitcoin\Network\NetworkInterface;
14
use BitWasp\Bitcoin\Serializer\Key\PrivateKey\WifPrivateKeySerializer;
15
use BitWasp\Buffertools\Buffer;
16
use BitWasp\Buffertools\BufferInterface;
17
18
class PrivateKey extends Key implements PrivateKeyInterface
19
{
20
    /**
21
     * @var int|string
22
     */
23
    private $secret;
24
25
    /**
26
     * @var string
27
     */
28
    private $secretBin;
29
30
    /**
31
     * @var bool
32
     */
33
    private $compressed;
34
35
    /**
36
     * @var PublicKey
37
     */
38
    private $publicKey;
39
40
    /**
41
     * @var EcAdapter
42
     */
43
    private $ecAdapter;
44
45
    /**
46
     * @param EcAdapter $adapter
47
     * @param $secret
48
     * @param bool|false $compressed
49
     * @throws \Exception
50
     */
51 213
    public function __construct(EcAdapter $adapter, $secret, $compressed = false)
52
    {
53 213
        $buffer = Buffer::int($secret, 32, $adapter->getMath());
54 213
        if (!$adapter->validatePrivateKey($buffer)) {
55 3
            throw new InvalidPrivateKey('Invalid private key');
56
        }
57
58 210
        if (false === is_numeric($secret)) {
59
            throw new \InvalidArgumentException('PrivateKey: Secret must be an integer');
60
        }
61
62 210
        if (false === is_bool($compressed)) {
63
            throw new \InvalidArgumentException('PrivateKey: Compressed argument must be a boolean');
64
        }
65
66 210
        $this->ecAdapter = $adapter;
67 210
        $this->secret = $secret;
0 ignored issues
show
Documentation Bug introduced by
It seems like $secret can also be of type double. However, the property $secret is declared as type integer|string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
68 210
        $this->secretBin = $buffer->getBinary();
69 210
        $this->compressed = $compressed;
70 210
    }
71
72
    /**
73
     * @param BufferInterface $msg32
74
     * @param RbgInterface|null $rbgInterface
75
     * @return Signature
76
     */
77
    public function sign(BufferInterface $msg32, RbgInterface $rbgInterface = null)
78
    {
79
        return $this->ecAdapter->sign($msg32, $this, $rbgInterface);
80
    }
81
82
    /**
83
     * @return bool|false
84
     */
85 102
    public function isCompressed()
86
    {
87 102
        return $this->compressed;
88
    }
89
90
    /**
91
     * @return int|string
92
     */
93 87
    public function getSecretMultiplier()
94
    {
95 87
        return $this->secret;
96
    }
97
98
    /**
99
     * @return string
100
     */
101 237
    public function getSecretBinary()
102
    {
103 237
        return $this->secretBin;
104
    }
105
106
    /**
107
     * @return PublicKey
108
     */
109 216
    public function getPublicKey()
110
    {
111 216
        if (null === $this->publicKey) {
112 180
            $context = $this->ecAdapter->getContext();
113 180
            $publicKey_t = '';
114
            /** @var resource $publicKey_t */
115 180
            if (1 !== secp256k1_ec_pubkey_create($context, $this->getBinary(), $publicKey_t)) {
116
                throw new \RuntimeException('Failed to create public key');
117
            }
118
119 180
            $this->publicKey = new PublicKey($this->ecAdapter, $publicKey_t, $this->compressed);
120 180
        }
121
122 216
        return $this->publicKey;
123
    }
124
125
    /**
126
     * @param int $tweak
127
     * @var string $tweak
128
     * @return PrivateKey
129
     */
130 18
    public function tweakAdd($tweak)
131
    {
132 18
        $adapter = $this->ecAdapter;
133 18
        $math = $adapter->getMath();
134 18
        $context = $adapter->getContext();
135 18
        $privKey = $this->getBinary(); // mod by reference
136 18
        $tweak = Buffer::int($tweak, 32, $math)->getBinary();
137 18
        $ret = \secp256k1_ec_privkey_tweak_add(
138 18
            $context,
139
            $privKey,
140
            $tweak
141 18
        );
142
143 18
        if ($ret !== 1) {
144
            throw new \RuntimeException('Secp256k1 privkey tweak add: failed');
145
        }
146
147 18
        $secret = $math->hexDec(bin2hex($privKey));
148 18
        return $adapter->getPrivateKey($secret, $this->compressed);
149
    }
150
151
    /**
152
     * @param int $tweak
153
     * @return PrivateKey
154
     */
155 3
    public function tweakMul($tweak)
156
    {
157 3
        $adapter = $this->ecAdapter;
158 3
        $math = $adapter->getMath();
159 3
        $context = $adapter->getContext();
160 3
        $privateKey = $this->getBinary(); // mod by reference
161 3
        $tweak = Buffer::int($tweak, 32, $math)->getBinary();
162 3
        $ret = \secp256k1_ec_privkey_tweak_mul(
163 3
            $context,
164
            $privateKey,
165
            $tweak
166 3
        );
167
168 3
        if ($ret !== 1) {
169
            throw new \RuntimeException('Secp256k1 privkey tweak mul: failed');
170
        }
171
172 3
        $secret = $math->hexDec(bin2hex($privateKey));
173 3
        return $adapter->getPrivateKey($secret, $this->compressed);
174
    }
175
176
    /**
177
     * @param NetworkInterface $network
178
     * @return string
179
     */
180 12
    public function toWif(NetworkInterface $network = null)
181
    {
182 12
        $network = $network ?: Bitcoin::getNetwork();
183 12
        $wifSerializer = new WifPrivateKeySerializer($this->ecAdapter->getMath(), new PrivateKeySerializer($this->ecAdapter));
184 12
        return $wifSerializer->serialize($network, $this);
185
    }
186
187
    /**
188
     * @return BufferInterface
189
     */
190 228
    public function getBuffer()
191
    {
192 228
        return (new PrivateKeySerializer($this->ecAdapter))->serialize($this);
193
    }
194
}
195