Completed
Pull Request — master (#324)
by thomas
18:01
created

CompactSignatureSerializer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1.0156

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 4
cp 0.75
crap 1.0156
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Serializer\Signature;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Adapter\EcAdapter;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\CompactSignature;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\CompactSignatureSerializerInterface;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\CompactSignatureInterface;
9
use BitWasp\Buffertools\Buffer;
10
use BitWasp\Buffertools\BufferInterface;
11
use BitWasp\Buffertools\Parser;
12
13
class CompactSignatureSerializer implements CompactSignatureSerializerInterface
14
{
15
    /**
16
     * @var EcAdapter
17
     */
18
    private $ecAdapter;
19
20
    /**
21
     * @param EcAdapter $ecAdapter
22
     */
23 11
    public function __construct(EcAdapter $ecAdapter)
24
    {
25 11
        $this->ecAdapter = $ecAdapter;
26 11
    }
27
28
    /**
29
     * @param CompactSignature $signature
30
     * @return BufferInterface
31
     */
32 6
    private function doSerialize(CompactSignature $signature)
33
    {
34 6
        $sig_t = '';
35 6
        $recid = '';
36 6
        if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($this->ecAdapter->getContext(), $signature->getResource(), $sig_t, $recid)) {
37
            throw new \RuntimeException('Secp256k1 serialize compact failure');
38
        }
39
40 6
        return new Buffer(chr((int)$signature->getFlags()) . $sig_t, 65, $this->ecAdapter->getMath());
41
    }
42
43
    /**
44
     * @param CompactSignatureInterface $signature
45
     * @return BufferInterface
46
     */
47 6
    public function serialize(CompactSignatureInterface $signature)
48
    {
49
        /** @var CompactSignature $signature */
50 6
        return $this->doSerialize($signature);
51
    }
52
53
    /**
54
     * @param string|BufferInterface $data
55
     * @return CompactSignature
56
     */
57 8
    public function parse($data)
58
    {
59 8
        $math = $this->ecAdapter->getMath();
60 8
        $buffer = (new Parser($data, $math))->getBuffer();
61
62 8
        if ($buffer->getSize() !== 65) {
63 1
            throw new \RuntimeException('Compact Sig must be 65 bytes');
64
        }
65
66 7
        $byte = (int) $buffer->slice(0, 1)->getInt();
67 7
        $sig = $buffer->slice(1, 64);
68
69 7
        $recoveryFlags = $byte - 27;
70 7
        if ($recoveryFlags > 7) {
71
            throw new \RuntimeException('Invalid signature type');
72
        }
73
74 7
        $isCompressed = $math->cmp($math->bitwiseAnd(gmp_init($recoveryFlags), gmp_init(4)), gmp_init(0)) !== 0;
75 7
        $recoveryId = $recoveryFlags - ($isCompressed ? 4 : 0);
76
77 7
        $sig_t = '';
78
        /** @var resource $sig_t */
79 7
        if (!secp256k1_ecdsa_recoverable_signature_parse_compact($this->ecAdapter->getContext(), $sig_t, $sig->getBinary(), $recoveryId)) {
80
            throw new \RuntimeException('Unable to parse compact signature');
81
        }
82
83 7
        return new CompactSignature($this->ecAdapter, $sig_t, $recoveryId, $isCompressed);
84
    }
85
}
86