Passed
Pull Request — master (#754)
by thomas
51:35 queued 12:34
created

DerSignatureSerializer::getOuterTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 6
ccs 5
cts 5
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Serializer\Signature;
6
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Adapter\EcAdapter;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Signature\Signature;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
12
use BitWasp\Bitcoin\Serializer\Types;
13
use BitWasp\Buffertools\Buffer;
14
use BitWasp\Buffertools\BufferInterface;
15
use BitWasp\Buffertools\Buffertools;
16
use BitWasp\Buffertools\Exceptions\ParserOutOfRange;
17
use BitWasp\Buffertools\Parser;
18
19
class DerSignatureSerializer implements DerSignatureSerializerInterface
20
{
21
    /**
22
     * @var EcAdapter
23
     */
24
    private $ecAdapter;
25
26
    /**
27
     * @var \BitWasp\Buffertools\Types\VarString
28
     */
29 2453
    private $varstring;
30
31 2453
    /**
32 2453
     * @param EcAdapter $adapter
33
     */
34
    public function __construct(EcAdapter $adapter)
35
    {
36
        $this->ecAdapter = $adapter;
37 244
        $this->varstring = Types::varstring();
38
    }
39 244
40
    /**
41
     * @return EcAdapterInterface
42
     */
43
    public function getEcAdapter(): EcAdapterInterface
44
    {
45 212
        return $this->ecAdapter;
46
    }
47 212
48 212
    /**
49 212
     * @param SignatureInterface $signature
50 212
     * @return BufferInterface
51 212
     * @throws \Exception
52 212
     */
53
    public function serialize(SignatureInterface $signature): BufferInterface
54
    {
55
        // Ensure that the R and S hex's are of even length
56
        $rBin = gmp_export($signature->getR(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
0 ignored issues
show
Bug introduced by
The method getR() does not exist on BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface. It seems like you code against a sub-type of BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface such as BitWasp\Bitcoin\Crypto\E...6k1\Signature\Signature or BitWasp\Bitcoin\Crypto\E...Ecc\Signature\Signature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

56
        $rBin = gmp_export($signature->/** @scrutinizer ignore-call */ getR(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
Loading history...
57
        $sBin = gmp_export($signature->getS(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
0 ignored issues
show
Bug introduced by
The method getS() does not exist on BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface. It seems like you code against a sub-type of BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface such as BitWasp\Bitcoin\Crypto\E...6k1\Signature\Signature or BitWasp\Bitcoin\Crypto\E...Ecc\Signature\Signature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

57
        $sBin = gmp_export($signature->/** @scrutinizer ignore-call */ getS(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
Loading history...
58 219
59
        // Pad R and S if their highest bit is flipped, ie,
60 219
        // they are negative.
61 219
        if ((ord($rBin[0]) & 0x80) === 0x80) {
62 219
            $rBin = "\x00$rBin";
63 219
        }
64
65
        if ((ord($sBin[0]) & 0x80) === 0x80) {
66
            $sBin = "\x00$sBin";
67
        }
68
69
        $inner = sprintf(
70
            "\x02%s%s\x02%s%s",
71 68
            Buffertools::numToVarIntBin(strlen($rBin)),
72
            $rBin,
73 68
            Buffertools::numToVarIntBin(strlen($sBin)),
74
            $sBin
75
        );
76 68
77 68
        return new Buffer(sprintf("\x30%s%s", Buffertools::numToVarIntBin(strlen($inner)), $inner));
78
    }
79
80
    /**
81 68
     * @param Parser $parser
82 68
     * @return SignatureInterface
83 40
     * @throws ParserOutOfRange
84
     */
85
    public function fromParser(Parser $parser): SignatureInterface
86 68
    {
87 68
        $prefix = $parser->readBytes(1);
88 2
        if ($prefix->getBinary() != "\x30") {
89
            throw new \RuntimeException("invalid signature");
90
        }
91 68
        $inner = $this->varstring->read($parser);
92 68
93 68
        try {
94 68
            $pinner = new Parser($inner);
95 68
96 68
            $rPref = $pinner->readBytes(1);
97 68
            if ($rPref->getBinary() != "\x02") {
98
                throw new \RuntimeException("invalid signature");
99
            }
100
            $r = $this->varstring->read($pinner);
101
102
            $sPref = $pinner->readBytes(1);
103
            if ($sPref->getBinary() != "\x02") {
104
                throw new \RuntimeException("invalid signature");
105
            }
106
            $s = $this->varstring->read($pinner);
107 208
        } catch (ParserOutOfRange $e) {
108
            throw new ParserOutOfRange('Failed to extract full signature from parser');
109
        }
110 208
111 201
        return new Signature($this->ecAdapter, $r->getGmp(), $s->getGmp());
112
    }
113
114
    /**
115 197
     * @param BufferInterface $derSignature
116 197
     * @return SignatureInterface
117 197
     * @throws ParserOutOfRange
118 195
     */
119
    public function parse(BufferInterface $derSignature): SignatureInterface
120 15
    {
121 11
        return $this->fromParser(new Parser($derSignature));
122
    }
123
}
124