Completed
Push — master ( c780c0...f2b04e )
by thomas
60:38 queued 58:10
created

PrivateKey   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 220
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 91.67%

Importance

Changes 0
Metric Value
dl 0
loc 220
ccs 77
cts 84
cp 0.9167
rs 10
c 0
b 0
f 0
wmc 21
lcom 1
cbo 12

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 3
A sign() 0 21 2
A signCompact() 0 26 3
A isCompressed() 0 4 1
A getSecret() 0 4 1
A getSecretBinary() 0 4 1
A getPublicKey() 0 15 3
A toWif() 0 6 2
A getBuffer() 0 4 1
A tweakAdd() 0 20 2
A tweakMul() 0 19 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key;
6
7
use BitWasp\Bitcoin\Bitcoin;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Adapter\EcAdapter;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Serializer\Key\PrivateKeySerializer;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\CompactSignature;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\Signature;
12
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\Key;
13
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\KeyInterface;
14
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
15
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\CompactSignatureInterface;
16
use BitWasp\Bitcoin\Crypto\Random\RbgInterface;
17
use BitWasp\Bitcoin\Exceptions\InvalidPrivateKey;
18
use BitWasp\Bitcoin\Network\NetworkInterface;
19
use BitWasp\Bitcoin\Serializer\Key\PrivateKey\WifPrivateKeySerializer;
20
use BitWasp\Buffertools\Buffer;
21
use BitWasp\Buffertools\BufferInterface;
22
23
class PrivateKey extends Key implements PrivateKeyInterface
24
{
25
    /**
26
     * @var \GMP
27
     */
28
    private $secret;
29
30
    /**
31
     * @var string
32
     */
33
    private $secretBin;
34
35
    /**
36
     * @var bool
37
     */
38
    private $compressed;
39
40
    /**
41
     * @var PublicKey
42
     */
43
    private $publicKey;
44
45
    /**
46
     * @var EcAdapter
47
     */
48
    private $ecAdapter;
49
50
    /**
51
     * @param EcAdapter $adapter
52
     * @param \GMP $secret
53
     * @param bool|false $compressed
54
     * @throws \Exception
55
     */
56 91
    public function __construct(EcAdapter $adapter, \GMP $secret, bool $compressed = false)
57
    {
58 91
        $buffer = Buffer::int(gmp_strval($secret, 10), 32);
59 91
        if (!$adapter->validatePrivateKey($buffer)) {
60 1
            throw new InvalidPrivateKey('Invalid private key');
61
        }
62
63 90
        if (false === is_bool($compressed)) {
64
            throw new \InvalidArgumentException('PrivateKey: Compressed argument must be a boolean');
65
        }
66
67 90
        $this->ecAdapter = $adapter;
68 90
        $this->secret = $secret;
69 90
        $this->secretBin = $buffer->getBinary();
70 90
        $this->compressed = $compressed;
71 90
    }
72
73
    /**
74
     * @param BufferInterface $msg32
75
     * @param RbgInterface|null $rbgInterface
76
     * @return Signature
77
     */
78 69
    public function sign(BufferInterface $msg32, RbgInterface $rbgInterface = null): Signature
79
    {
80 69
        $context = $this->ecAdapter->getContext();
81
82
        /** @var resource $sig_t */
83 69
        $sig_t = '';
84 69
        if (1 !== secp256k1_ecdsa_sign($context, $sig_t, $msg32->getBinary(), $this->secretBin)) {
85
            throw new \RuntimeException('Secp256k1: failed to sign');
86
        }
87
88 69
        $derSig = '';
89 69
        secp256k1_ecdsa_signature_serialize_der($context, $derSig, $sig_t);
90
91 69
        $rL = ord($derSig[3]);
92 69
        $r = (new Buffer(substr($derSig, 4, $rL), $rL))->getGmp();
93
94 69
        $sL = ord($derSig[4+$rL + 1]);
95 69
        $s = (new Buffer(substr($derSig, 4 + $rL + 2, $sL), $sL))->getGmp();
96
97 69
        return new Signature($this->ecAdapter, $r, $s, $sig_t);
98
    }
99
100
    /**
101
     * @param BufferInterface $msg32
102
     * @param RbgInterface|null $rbfInterface
103
     * @return CompactSignature
104
     */
105 5
    public function signCompact(BufferInterface $msg32, RbgInterface $rbfInterface = null): CompactSignatureInterface
106
    {
107 5
        $context = $this->ecAdapter->getContext();
108
        
109 5
        $sig_t = '';
110 5
        if (1 !== secp256k1_ecdsa_sign_recoverable($context, $sig_t, $msg32->getBinary(), $this->secretBin)) {
0 ignored issues
show
Documentation introduced by
$sig_t is of type string, but the function expects a resource.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
111
            throw new \RuntimeException('Secp256k1: failed to sign');
112
        }
113
114 5
        $recid = '';
115 5
        $ser = '';
116 5
        if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($context, $sig_t, $ser, $recid)) {
0 ignored issues
show
Documentation introduced by
$sig_t is of type string, but the function expects a resource.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
117
            throw new \RuntimeException('Failed to obtain recid');
118
        }
119
120
        /** @var resource $sig_t */
121
        /** @var int $recid */
122
123 5
        unset($ser);
124 5
        return new CompactSignature(
125 5
            $this->ecAdapter,
126 5
            $sig_t,
0 ignored issues
show
Documentation introduced by
$sig_t is of type string, but the function expects a resource.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
127 5
            $recid,
128 5
            $this->isCompressed()
129
        );
130
    }
131
132
    /**
133
     * @return bool
134
     */
135 75
    public function isCompressed(): bool
136
    {
137 75
        return $this->compressed;
138
    }
139
140
    /**
141
     * @return \GMP
142
     */
143 3
    public function getSecret()
144
    {
145 3
        return $this->secret;
146
    }
147
148
    /**
149
     * @return string
150
     */
151 102
    public function getSecretBinary(): string
152
    {
153 102
        return $this->secretBin;
154
    }
155
156
    /**
157
     * @return PublicKey
158
     */
159 127
    public function getPublicKey()
160
    {
161 127
        if (null === $this->publicKey) {
162 97
            $context = $this->ecAdapter->getContext();
163 97
            $publicKey_t = '';
164
            /** @var resource $publicKey_t */
165 97
            if (1 !== secp256k1_ec_pubkey_create($context, $publicKey_t, $this->getBinary())) {
166
                throw new \RuntimeException('Failed to create public key');
167
            }
168
169 97
            $this->publicKey = new PublicKey($this->ecAdapter, $publicKey_t, $this->compressed);
170
        }
171
172 127
        return $this->publicKey;
173
    }
174
175
    /**
176
     * @param \GMP $tweak
177
     * @return KeyInterface
178
     */
179 18
    public function tweakAdd(\GMP $tweak): KeyInterface
180
    {
181 18
        $adapter = $this->ecAdapter;
182 18
        $math = $adapter->getMath();
183 18
        $context = $adapter->getContext();
184 18
        $privateKey = $this->getBinary(); // mod by reference
185 18
        $tweak = Buffer::int($math->toString($tweak), 32)->getBinary();
186 18
        $ret = \secp256k1_ec_privkey_tweak_add(
187 18
            $context,
188 18
            $privateKey,
189 18
            $tweak
190
        );
191
192 18
        if ($ret !== 1) {
193
            throw new \RuntimeException('Secp256k1 privkey tweak add: failed');
194
        }
195
196 18
        $secret = new Buffer($privateKey);
197 18
        return $adapter->getPrivateKey($secret->getGmp(), $this->compressed);
198
    }
199
200
    /**
201
     * @param \GMP $tweak
202
     * @return KeyInterface
203
     */
204 1
    public function tweakMul(\GMP $tweak): KeyInterface
205
    {
206 1
        $privateKey = $this->getBinary();
207 1
        $math = $this->ecAdapter->getMath();
208 1
        $tweak = Buffer::int($math->toString($tweak), 32)->getBinary();
209 1
        $ret = \secp256k1_ec_privkey_tweak_mul(
210 1
            $this->ecAdapter->getContext(),
211 1
            $privateKey,
212 1
            $tweak
213
        );
214
215 1
        if ($ret !== 1) {
216
            throw new \RuntimeException('Secp256k1 privkey tweak mul: failed');
217
        }
218
219 1
        $secret = new Buffer($privateKey);
220
221 1
        return $this->ecAdapter->getPrivateKey($secret->getGmp(), $this->compressed);
222
    }
223
224
    /**
225
     * @param NetworkInterface $network
226
     * @return string
227
     */
228 5
    public function toWif(NetworkInterface $network = null): string
229
    {
230 5
        $network = $network ?: Bitcoin::getNetwork();
231 5
        $wifSerializer = new WifPrivateKeySerializer(new PrivateKeySerializer($this->ecAdapter));
232 5
        return $wifSerializer->serialize($network, $this);
233
    }
234
235
    /**
236
     * @return BufferInterface
237
     */
238 100
    public function getBuffer(): BufferInterface
239
    {
240 100
        return (new PrivateKeySerializer($this->ecAdapter))->serialize($this);
241
    }
242
}
243