Completed
Pull Request — master (#260)
by thomas
20:01 queued 16:45
created

PrivateKey::sign()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 2
crap 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_bool($compressed)) {
59
            throw new \InvalidArgumentException('PrivateKey: Compressed argument must be a boolean');
60
        }
61
62 210
        $this->ecAdapter = $adapter;
63 210
        $this->secret = $secret;
64 210
        $this->secretBin = $buffer->getBinary();
65 210
        $this->compressed = $compressed;
66 210
    }
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 102
    public function isCompressed()
82
    {
83 102
        return $this->compressed;
84
    }
85
86
    /**
87
     * @return int|string
88
     */
89 87
    public function getSecretMultiplier()
90
    {
91 87
        return $this->secret;
92
    }
93
94
    /**
95
     * @return string
96
     */
97 237
    public function getSecretBinary()
98
    {
99 237
        return $this->secretBin;
100
    }
101
102
    /**
103
     * @return PublicKey
104
     */
105 216
    public function getPublicKey()
106
    {
107 216
        if (null === $this->publicKey) {
108 180
            $context = $this->ecAdapter->getContext();
109 180
            $publicKey_t = '';
110
            /** @var resource $publicKey_t */
111 180
            if (1 !== secp256k1_ec_pubkey_create($context, $this->getBinary(), $publicKey_t)) {
112
                throw new \RuntimeException('Failed to create public key');
113
            }
114
115 180
            $this->publicKey = new PublicKey($this->ecAdapter, $publicKey_t, $this->compressed);
116 180
        }
117
118 216
        return $this->publicKey;
119
    }
120
121
    /**
122
     * @param int $tweak
123
     * @var string $tweak
124
     * @return PrivateKey
125
     */
126 18
    public function tweakAdd($tweak)
127
    {
128 18
        $adapter = $this->ecAdapter;
129 18
        $math = $adapter->getMath();
130 18
        $context = $adapter->getContext();
131 18
        $privKey = $this->getBinary(); // mod by reference
132 18
        $tweak = Buffer::int($tweak, 32, $math)->getBinary();
133 18
        $ret = \secp256k1_ec_privkey_tweak_add(
134 18
            $context,
135
            $privKey,
136
            $tweak
137 18
        );
138
139 18
        if ($ret !== 1) {
140
            throw new \RuntimeException('Secp256k1 privkey tweak add: failed');
141
        }
142
143 18
        $secret = $math->hexDec(bin2hex($privKey));
144 18
        return $adapter->getPrivateKey($secret, $this->compressed);
145
    }
146
147
    /**
148
     * @param int $tweak
149
     * @return PrivateKey
150
     */
151 3
    public function tweakMul($tweak)
152
    {
153 3
        $adapter = $this->ecAdapter;
154 3
        $math = $adapter->getMath();
155 3
        $context = $adapter->getContext();
156 3
        $privateKey = $this->getBinary(); // mod by reference
157 3
        $tweak = Buffer::int($tweak, 32, $math)->getBinary();
158 3
        $ret = \secp256k1_ec_privkey_tweak_mul(
159 3
            $context,
160
            $privateKey,
161
            $tweak
162 3
        );
163
164 3
        if ($ret !== 1) {
165
            throw new \RuntimeException('Secp256k1 privkey tweak mul: failed');
166
        }
167
168 3
        $secret = $math->hexDec(bin2hex($privateKey));
169 3
        return $adapter->getPrivateKey($secret, $this->compressed);
170
    }
171
172
    /**
173
     * @param NetworkInterface $network
174
     * @return string
175
     */
176 12
    public function toWif(NetworkInterface $network = null)
177
    {
178 12
        $network = $network ?: Bitcoin::getNetwork();
179 12
        $wifSerializer = new WifPrivateKeySerializer($this->ecAdapter->getMath(), new PrivateKeySerializer($this->ecAdapter));
180 12
        return $wifSerializer->serialize($network, $this);
181
    }
182
183
    /**
184
     * @return BufferInterface
185
     */
186 228
    public function getBuffer()
187
    {
188 228
        return (new PrivateKeySerializer($this->ecAdapter))->serialize($this);
189
    }
190
}
191