Completed
Push — master ( 70da09...3502ce )
by thomas
122:11 queued 112:52
created

EcAdapter::doSignCompact()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3.2835
Metric Value
dl 0
loc 22
ccs 13
cts 19
cp 0.6842
rs 9.2
cc 3
eloc 14
nc 3
nop 2
crap 3.2835
1
<?php
2
3
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Adapter;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key\PublicKey;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key\PrivateKey;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\CompactSignature;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\Signature;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
12
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\CompactSignatureInterface;
13
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
14
use BitWasp\Bitcoin\Crypto\Random\RbgInterface;
15
use BitWasp\Bitcoin\Math\Math;
16
use BitWasp\Buffertools\Buffer;
17
use Mdanter\Ecc\Primitives\GeneratorPoint;
18
19
class EcAdapter implements EcAdapterInterface
20
{
21
    /**
22
     * @var Math
23
     */
24
    private $math;
25
26
    /**
27
     * @var GeneratorPoint
28
     */
29
    private $generator;
30
31
    /**
32
     * @var resource
33
     */
34
    private $context;
35
36
    /**
37
     * @param Math $math
38
     * @param GeneratorPoint $generator
39
     * @param resource $secp256k1_context_t
40
     */
41 33
    public function __construct(Math $math, GeneratorPoint $generator, $secp256k1_context_t)
42
    {
43 33
        if (!is_resource($secp256k1_context_t) || !get_resource_type($secp256k1_context_t) === SECP256K1_TYPE_CONTEXT) {
44
            throw new \InvalidArgumentException('Secp256k1: Must pass a secp256k1_context_t resource');
45
        }
46 33
        $this->math = $math;
47 33
        $this->generator = $generator;
48 33
        $this->context = $secp256k1_context_t;
49 33
    }
50
51
    /**
52
     * @return Math
53
     */
54 924
    public function getMath()
55
    {
56 924
        return $this->math;
57
    }
58
59
    /**
60
     * @return GeneratorPoint
61
     */
62 69
    public function getGenerator()
63
    {
64 69
        return $this->generator;
65
    }
66
67
    /**
68
     * @param Buffer $privateKey
69
     * @return bool
70
     */
71 234
    public function validatePrivateKey(Buffer $privateKey)
72
    {
73 234
        return (bool) secp256k1_ec_seckey_verify($this->context, $privateKey->getBinary());
74
    }
75
76
    /**
77
     * @param int|string $element
78
     * @param bool $half
79
     * @return bool
80
     */
81 12
    public function validateSignatureElement($element, $half = false)
82
    {
83 12
        $math = $this->getMath();
84 12
        $against = $this->getGenerator()->getOrder();
85 12
        if ($half) {
86 12
            $against = $math->rightShift($against, 1);
87 12
        }
88
89 12
        return $math->cmp($element, $against) < 0 && $math->cmp($element, 0) !== 0;
90
    }
91
92
    /**
93
     * @param int|string $int
94
     * @param bool|false $compressed
95
     * @return PrivateKey
96
     */
97 228
    public function getPrivateKey($int, $compressed = false)
98
    {
99 228
        return new PrivateKey($this, $int, $compressed);
100
    }
101
102
    /**
103
     * @return resource
104
     */
105 432
    public function getContext()
106
    {
107 432
        return $this->context;
108
    }
109
110
    /**
111
     * @param Buffer $msg32
112
     * @param PrivateKey $privateKey
113
     * @return Signature
114
     */
115 48
    private function doSign(Buffer $msg32, PrivateKey $privateKey)
116
    {
117
        /** @var resource $sig_t */
118 48
        $sig_t = '';
119 48
        if (1 !== secp256k1_ecdsa_sign($this->context, $msg32->getBinary(), $privateKey->getBinary(), $sig_t)) {
120
            throw new \RuntimeException('Secp256k1: failed to sign');
121
        }
122
123 48
        $derSig = '';
124 48
        secp256k1_ecdsa_signature_serialize_der($this->context, $sig_t, $derSig);
125
126 48
        $rL = ord($derSig[3]);
127 48
        $r = (new Buffer(substr($derSig, 4, $rL), $rL, $this->math))->getInt();
128
129 48
        $sL = ord($derSig[4+$rL + 1]);
130 48
        $s = (new Buffer(substr($derSig, 4 + $rL + 2, $sL), $rL, $this->math))->getInt();
131
132 48
        return new Signature($this, $r, $s, $sig_t);
133
    }
134
135
    /**
136
     * @param Buffer $msg32
137
     * @param PrivateKeyInterface $privateKey
138
     * @param RbgInterface|null $rbg
139
     * @return Signature
140
     */
141 48
    public function sign(Buffer $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
142
    {
143
        /** @var PrivateKey $privateKey */
144 48
        return $this->doSign($msg32, $privateKey);
145
    }
146
147
    /**
148
     * @param Buffer $msg32
149
     * @param PublicKey $publicKey
150
     * @param Signature $signature
151
     * @return bool
152
     */
153 18
    private function doVerify(Buffer $msg32, PublicKey $publicKey, Signature $signature)
154
    {
155 18
        return (bool) secp256k1_ecdsa_verify($this->context, $msg32->getBinary(), $signature->getResource(), $publicKey->getResource());
156
    }
157
158
    /**
159
     * @param Buffer $msg32
160
     * @param PublicKeyInterface $publicKey
161
     * @param SignatureInterface $signature
162
     * @return bool
163
     */
164 18
    public function verify(Buffer $msg32, PublicKeyInterface $publicKey, SignatureInterface $signature)
165
    {
166
        /** @var PublicKey $publicKey */
167
        /** @var Signature $signature */
168 18
        return $this->doVerify($msg32, $publicKey, $signature);
0 ignored issues
show
Compatibility introduced by
$publicKey of type object<BitWasp\Bitcoin\C...Key\PublicKeyInterface> is not a sub-type of object<BitWasp\Bitcoin\C...ecp256k1\Key\PublicKey>. It seems like you assume a concrete implementation of the interface BitWasp\Bitcoin\Crypto\E...\Key\PublicKeyInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
169
    }
170
171
    /**
172
     * @param Buffer $msg32
173
     * @param CompactSignature $compactSig
174
     * @return PublicKey
175
     */
176 21
    private function doRecover(Buffer $msg32, CompactSignature $compactSig)
177
    {
178 21
        $publicKey = '';
179
        /** @var resource $publicKey */
180 21
        $context = $this->context;
181 21
        $sig = $compactSig->getResource();
182 21
        if (1 !== secp256k1_ecdsa_recover($context, $msg32->getBinary(), $sig, $publicKey)) {
183
            throw new \RuntimeException('Unable to recover Public Key');
184
        }
185
186 21
        return new PublicKey($this, $publicKey, $compactSig->isCompressed());
187
    }
188
189
    /**
190
     * @param Buffer $msg32
191
     * @param CompactSignatureInterface $compactSig
192
     * @return PublicKey
193
     */
194 21
    public function recover(Buffer $msg32, CompactSignatureInterface $compactSig)
195
    {
196
        /** @var CompactSignature $compactSig */
197 21
        return $this->doRecover($msg32, $compactSig);
198
    }
199
200
    /**
201
     * @param Buffer $msg32
202
     * @param PrivateKey $privateKey
203
     * @return CompactSignature
204
     */
205 18
    private function doSignCompact(Buffer $msg32, PrivateKey $privateKey)
206
    {
207 18
        $sig_t = '';
208
        /** @var resource $sig_t */
209 18
        if (1 !== secp256k1_ecdsa_sign_recoverable($this->context, $msg32->getBinary(), $privateKey->getBinary(), $sig_t)) {
210
            throw new \RuntimeException('Secp256k1: failed to sign');
211
        }
212
213 18
        $recid = '';
214 18
        $ser = '';
215 18
        if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($this->context, $sig_t, $ser, $recid)) {
216
            throw new \RuntimeException('Failed to obtain recid');
217
        }
218
219 18
        unset($ser);
220 18
        return new CompactSignature(
221 18
            $this,
222 18
            $sig_t,
223 18
            $recid,
224 18
            $privateKey->isCompressed()
225 18
        );
226
    }
227
228
    /**
229
     * @param Buffer $msg32
230
     * @param PrivateKeyInterface $privateKey
231
     * @param RbgInterface|null $rbg
232
     * @return CompactSignatureInterface
233
     */
234 18
    public function signCompact(Buffer $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
235
    {
236
        /** @var PrivateKey $privateKey */
237 18
        return $this->doSignCompact($msg32, $privateKey);
238
    }
239
}
240