Completed
Push — 0.0.34 ( 61212b...2e9020 )
by thomas
20:55
created

PrivateKey::tweakMul()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2.2109

Importance

Changes 0
Metric Value
cc 2
eloc 12
nc 2
nop 1
dl 0
loc 19
ccs 10
cts 16
cp 0.625
crap 2.2109
rs 9.4285
c 0
b 0
f 0
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 \GMP
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 \GMP $secret
48
     * @param bool|false $compressed
49
     * @throws \Exception
50
     */
51 59
    public function __construct(EcAdapter $adapter, \GMP $secret, $compressed = false)
52
    {
53 59
        $buffer = Buffer::int(gmp_strval($secret, 10), 32, $adapter->getMath());
54 59
        if (!$adapter->validatePrivateKey($buffer)) {
55 1
            throw new InvalidPrivateKey('Invalid private key');
56
        }
57
58 58
        if (false === is_bool($compressed)) {
59
            throw new \InvalidArgumentException('PrivateKey: Compressed argument must be a boolean');
60
        }
61
62 58
        $this->ecAdapter = $adapter;
63 58
        $this->secret = $secret;
64 58
        $this->secretBin = $buffer->getBinary();
65 58
        $this->compressed = $compressed;
66 58
    }
67
68
    /**
69
     * @param BufferInterface $msg32
70
     * @param RbgInterface|null $rbgInterface
71
     * @return Signature
72
     */
73
    public function sign(BufferInterface $msg32, RbgInterface $rbgInterface = null)
74
    {
75
        return $this->ecAdapter->sign($msg32, $this, $rbgInterface);
76
    }
77
78
    /**
79
     * @return bool|false
80
     */
81 49
    public function isCompressed()
82
    {
83 49
        return $this->compressed;
84
    }
85
86
    /**
87
     * @return int|string
88
     */
89 37
    public function getSecret()
90
    {
91 37
        return $this->secret;
92
    }
93
94
    /**
95
     * @return string
96
     */
97 73
    public function getSecretBinary()
98
    {
99 73
        return $this->secretBin;
100
    }
101
102
    /**
103
     * @return PublicKey
104
     */
105 67
    public function getPublicKey()
106
    {
107 67
        if (null === $this->publicKey) {
108 67
            $context = $this->ecAdapter->getContext();
109 67
            $publicKey_t = '';
110
            /** @var resource $publicKey_t */
111 67
            if (1 !== secp256k1_ec_pubkey_create($context, $publicKey_t, $this->getBinary())) {
112
                throw new \RuntimeException('Failed to create public key');
113
            }
114
115 67
            $this->publicKey = new PublicKey($this->ecAdapter, $publicKey_t, $this->compressed);
116
        }
117
118 67
        return $this->publicKey;
119
    }
120
121
    /**
122
     * @param \GMP $tweak
123
     * @return PrivateKey
124
     */
125 8
    public function tweakAdd(\GMP $tweak)
126
    {
127 8
        $adapter = $this->ecAdapter;
128 8
        $math = $adapter->getMath();
129 8
        $context = $adapter->getContext();
130 8
        $privateKey = $this->getBinary(); // mod by reference
131 8
        $tweak = Buffer::int($math->toString($tweak), 32, $math)->getBinary();
132 8
        $ret = \secp256k1_ec_privkey_tweak_add(
133 8
            $context,
134
            $privateKey,
135 8
            $tweak
136
        );
137
138 8
        if ($ret !== 1) {
139
            throw new \RuntimeException('Secp256k1 privkey tweak add: failed');
140
        }
141
142 8
        $secret = new Buffer($privateKey);
143 8
        return $adapter->getPrivateKey($secret->getGmp(), $this->compressed);
144
    }
145
146
    /**
147
     * @param \GMP $tweak
148
     * @return PrivateKey
149
     */
150 1
    public function tweakMul(\GMP $tweak)
151
    {
152 1
        $privateKey = $this->getBinary();
153 1
        $math = $this->ecAdapter->getMath();
154 1
        $tweak = Buffer::int($math->toString($tweak), 32, $math)->getBinary();
155 1
        $ret = \secp256k1_ec_privkey_tweak_mul(
156 1
            $this->ecAdapter->getContext(),
157
            $privateKey,
158 1
            $tweak
159
        );
160
161 1
        if ($ret !== 1) {
162
            throw new \RuntimeException('Secp256k1 privkey tweak mul: failed');
163
        }
164
165 1
        $secret = new Buffer($privateKey);
166
167 1
        return $this->ecAdapter->getPrivateKey($secret->getGmp(), $this->compressed);
168
    }
169
170
    /**
171
     * @param NetworkInterface $network
172
     * @return string
173
     */
174 3
    public function toWif(NetworkInterface $network = null)
175
    {
176 3
        $network = $network ?: Bitcoin::getNetwork();
177 3
        $wifSerializer = new WifPrivateKeySerializer($this->ecAdapter->getMath(), new PrivateKeySerializer($this->ecAdapter));
178 3
        return $wifSerializer->serialize($network, $this);
179
    }
180
181
    /**
182
     * @return BufferInterface
183
     */
184 71
    public function getBuffer()
185
    {
186 71
        return (new PrivateKeySerializer($this->ecAdapter))->serialize($this);
187
    }
188
}
189