Completed
Push — master ( b59571...1ee45e )
by thomas
55:12 queued 52:48
created

CompactSignatureSerializer::doSerialize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 10
ccs 0
cts 9
cp 0
crap 6
rs 9.4285
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
    public function __construct(EcAdapter $ecAdapter)
24
    {
25
        $this->ecAdapter = $ecAdapter;
26
    }
27
28
    /**
29
     * @param CompactSignature $signature
30
     * @return BufferInterface
31
     */
32
    private function doSerialize(CompactSignature $signature)
33
    {
34
        $sig_t = '';
35
        $recid = '';
36
        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
        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
    public function serialize(CompactSignatureInterface $signature)
48
    {
49
        /** @var CompactSignature $signature */
50
        return $this->doSerialize($signature);
51
    }
52
53
    /**
54
     * @param string|BufferInterface $data
55
     * @return CompactSignature
56
     */
57
    public function parse($data)
58
    {
59
        $math = $this->ecAdapter->getMath();
60
        $buffer = (new Parser($data, $math))->getBuffer();
61
62
        if ($buffer->getSize() !== 65) {
63
            throw new \RuntimeException('Compact Sig must be 65 bytes');
64
        }
65
66
        $byte = (int) $buffer->slice(0, 1)->getInt();
67
        $sig = $buffer->slice(1, 64);
68
69
        $recoveryFlags = $byte - 27;
70
        if ($recoveryFlags > 7) {
71
            throw new \RuntimeException('Invalid signature type');
72
        }
73
74
        $isCompressed = $math->cmp($math->bitwiseAnd(gmp_init($recoveryFlags), gmp_init(4)), gmp_init(0)) !== 0;
75
        $recoveryId = $recoveryFlags - ($isCompressed ? 4 : 0);
76
77
        $sig_t = '';
78
        /** @var resource $sig_t */
79
        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
        return new CompactSignature($this->ecAdapter, $sig_t, $recoveryId, $isCompressed);
84
    }
85
}
86