Completed
Push — master ( 26690c...ea008d )
by thomas
177:34 queued 174:51
created

EcAdapter::doSignCompact()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.312

Importance

Changes 0
Metric Value
cc 3
eloc 14
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 22
ccs 9
cts 19
cp 0.4737
crap 4.312
rs 9.2
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 BitWasp\Buffertools\BufferInterface;
18
use Mdanter\Ecc\Primitives\GeneratorPoint;
19
20
class EcAdapter implements EcAdapterInterface
21
{
22
    /**
23
     * @var Math
24
     */
25
    private $math;
26
27
    /**
28
     * @var GeneratorPoint
29
     */
30
    private $generator;
31
32
    /**
33
     * @var resource
34
     */
35
    private $context;
36
37
    /**
38
     * @param Math $math
39
     * @param GeneratorPoint $generator
40
     * @param resource $secp256k1_context_t
41
     */
42 10
    public function __construct(Math $math, GeneratorPoint $generator, $secp256k1_context_t)
43
    {
44 10
        if (!is_resource($secp256k1_context_t) || !get_resource_type($secp256k1_context_t) === SECP256K1_TYPE_CONTEXT) {
45
            throw new \InvalidArgumentException('Secp256k1: Must pass a secp256k1_context_t resource');
46
        }
47 10
        $this->math = $math;
48 10
        $this->generator = $generator;
49 10
        $this->context = $secp256k1_context_t;
50 10
    }
51
52
    /**
53
     * @return Math
54
     */
55 360
    public function getMath()
56
    {
57 360
        return $this->math;
58
    }
59
60
    /**
61
     * @return GeneratorPoint
62
     */
63 48
    public function getGenerator()
64
    {
65 48
        return $this->generator;
66
    }
67
68
    /**
69
     * @param BufferInterface $privateKey
70
     * @return bool
71
     */
72 102
    public function validatePrivateKey(BufferInterface $privateKey)
73
    {
74 102
        return (bool) secp256k1_ec_seckey_verify($this->context, $privateKey->getBinary());
75
    }
76
77
    /**
78
     * @param \GMP $element
79
     * @param bool $half
80
     * @return bool
81
     */
82 8
    public function validateSignatureElement(\GMP $element, $half = false)
83
    {
84 8
        $math = $this->getMath();
85 8
        $against = $this->getGenerator()->getOrder();
86 8
        if ($half) {
87 8
            $against = $math->rightShift($against, 1);
88
        }
89
90 8
        return $math->cmp($element, $against) < 0 && $math->cmp($element, gmp_init(0)) !== 0;
91
    }
92
93
    /**
94
     * @param \GMP $int
95
     * @param bool|false $compressed
96
     * @return PrivateKey
97
     */
98 98
    public function getPrivateKey(\GMP $int, $compressed = false)
99
    {
100 98
        return new PrivateKey($this, $int, $compressed);
101
    }
102
103
    /**
104
     * @return resource
105
     */
106 256
    public function getContext()
107
    {
108 256
        return $this->context;
109
    }
110
111
    /**
112
     * @param BufferInterface $msg32
113
     * @param PrivateKey $privateKey
114
     * @return Signature
115
     */
116 34
    private function doSign(BufferInterface $msg32, PrivateKey $privateKey)
117
    {
118
        /** @var resource $sig_t */
119 34
        $sig_t = '';
120 34
        if (1 !== secp256k1_ecdsa_sign($this->context, $sig_t, $msg32->getBinary(), $privateKey->getBinary())) {
121
            throw new \RuntimeException('Secp256k1: failed to sign');
122
        }
123
124 34
        $derSig = '';
125 34
        secp256k1_ecdsa_signature_serialize_der($this->context, $derSig, $sig_t);
126
127 34
        $rL = ord($derSig[3]);
128 34
        $r = (new Buffer(substr($derSig, 4, $rL), $rL, $this->math))->getGmp();
129
130 34
        $sL = ord($derSig[4+$rL + 1]);
131 34
        $s = (new Buffer(substr($derSig, 4 + $rL + 2, $sL), $sL, $this->math))->getGmp();
132
133 34
        return new Signature($this, $r, $s, $sig_t);
134
    }
135
136
    /**
137
     * @param BufferInterface $msg32
138
     * @param PrivateKeyInterface $privateKey
139
     * @param RbgInterface|null $rbg
140
     * @return Signature
141
     */
142 34
    public function sign(BufferInterface $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
143
    {
144
        /** @var PrivateKey $privateKey */
145 34
        return $this->doSign($msg32, $privateKey);
146
    }
147
148
    /**
149
     * @param BufferInterface $msg32
150
     * @param PublicKey $publicKey
151
     * @param Signature $signature
152
     * @return bool
153
     */
154 25
    private function doVerify(BufferInterface $msg32, PublicKey $publicKey, Signature $signature)
155
    {
156 25
        return (bool) secp256k1_ecdsa_verify($this->context, $signature->getResource(), $msg32->getBinary(), $publicKey->getResource());
157
    }
158
159
    /**
160
     * @param BufferInterface $msg32
161
     * @param PublicKeyInterface $publicKey
162
     * @param SignatureInterface $signature
163
     * @return bool
164
     */
165 25
    public function verify(BufferInterface $msg32, PublicKeyInterface $publicKey, SignatureInterface $signature)
166
    {
167
        /** @var PublicKey $publicKey */
168
        /** @var Signature $signature */
169 25
        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...
170
    }
171
172
    /**
173
     * @param BufferInterface $msg32
174
     * @param CompactSignature $compactSig
175
     * @return PublicKey
176
     */
177 14
    private function doRecover(BufferInterface $msg32, CompactSignature $compactSig)
178
    {
179 14
        $publicKey = '';
180
        /** @var resource $publicKey */
181 14
        $context = $this->context;
182 14
        $sig = $compactSig->getResource();
183 14
        if (1 !== secp256k1_ecdsa_recover($context, $publicKey, $sig, $msg32->getBinary())) {
184
            throw new \RuntimeException('Unable to recover Public Key');
185
        }
186
187 14
        return new PublicKey($this, $publicKey, $compactSig->isCompressed());
188
    }
189
190
    /**
191
     * @param BufferInterface $msg32
192
     * @param CompactSignatureInterface $compactSig
193
     * @return PublicKey
194
     */
195 14
    public function recover(BufferInterface $msg32, CompactSignatureInterface $compactSig)
196
    {
197
        /** @var CompactSignature $compactSig */
198 14
        return $this->doRecover($msg32, $compactSig);
199
    }
200
201
    /**
202
     * @param BufferInterface $msg32
203
     * @param PrivateKey $privateKey
204
     * @return CompactSignature
205
     */
206 12
    private function doSignCompact(BufferInterface $msg32, PrivateKey $privateKey)
207
    {
208 12
        $sig_t = '';
209
        /** @var resource $sig_t */
210 12
        if (1 !== secp256k1_ecdsa_sign_recoverable($this->context, $sig_t, $msg32->getBinary(), $privateKey->getBinary())) {
211
            throw new \RuntimeException('Secp256k1: failed to sign');
212
        }
213
214 12
        $recid = '';
215 12
        $ser = '';
216 12
        if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($this->context, $sig_t, $ser, $recid)) {
217
            throw new \RuntimeException('Failed to obtain recid');
218
        }
219
220 12
        unset($ser);
221 12
        return new CompactSignature(
222
            $this,
223
            $sig_t,
224
            $recid,
225 12
            $privateKey->isCompressed()
226
        );
227
    }
228
229
    /**
230
     * @param BufferInterface $msg32
231
     * @param PrivateKeyInterface $privateKey
232
     * @param RbgInterface|null $rbg
233
     * @return CompactSignatureInterface
234
     */
235 12
    public function signCompact(BufferInterface $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
236
    {
237
        /** @var PrivateKey $privateKey */
238 12
        return $this->doSignCompact($msg32, $privateKey);
239
    }
240
}
241