Completed
Pull Request — master (#358)
by thomas
69:56
created

TransactionSignature::equals()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 5
ccs 2
cts 2
cp 1
crap 2
rs 9.4285
1
<?php
2
3
namespace BitWasp\Bitcoin\Signature;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\EcSerializer;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
9
use BitWasp\Bitcoin\Exceptions\SignatureNotCanonical;
10
use BitWasp\Bitcoin\Serializable;
11
use BitWasp\Bitcoin\Serializer\Signature\TransactionSignatureSerializer;
12
use BitWasp\Buffertools\BufferInterface;
13
14
class TransactionSignature extends Serializable implements TransactionSignatureInterface
15
{
16
    /**
17
     * @var EcAdapterInterface
18
     */
19
    private $ecAdapter;
20
21
    /**
22
     * @var SignatureInterface
23
     */
24
    private $signature;
25
26
    /**
27
     * @var int|string
28
     */
29
    private $hashType;
30
31
    /**
32
     * @param EcAdapterInterface $ecAdapter
33
     * @param SignatureInterface $signature
34
     * @param $hashType
35
     */
36 174
    public function __construct(EcAdapterInterface $ecAdapter, SignatureInterface $signature, $hashType)
37
    {
38 174
        $this->ecAdapter = $ecAdapter;
39 174
        $this->signature = $signature;
40 174
        $this->hashType = $hashType;
41 174
    }
42
43
    /**
44
     * @return SignatureInterface
45
     */
46 166
    public function getSignature()
47
    {
48 166
        return $this->signature;
49
    }
50
51
    /**
52
     * @return int|string
53
     */
54 166
    public function getHashType()
55
    {
56 166
        return $this->hashType;
57
    }
58
59
    /**
60
     * @param TransactionSignatureInterface $other
61
     * @return bool
62
     */
63
    public function equals(TransactionSignatureInterface $other)
64
    {
65
        return $this->signature->equals($other->getSignature())
66 125
            && $this->hashType === $other->getHashType();
67 97
    }
68 9
69
    /**
70 94
     * @param BufferInterface $sig
71 94
     * @return bool
72 9
     * @throws SignatureNotCanonical
73
     */
74 91
    public static function isDERSignature(BufferInterface $sig)
75 91
    {
76 91
        $checkVal = function ($fieldName, $start, $length, $binaryString) {
77 27
            if ($length === 0) {
78
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' length is zero');
79 76
            }
80 15
            $typePrefix = ord(substr($binaryString, $start - 2, 1));
81
            if ($typePrefix !== 0x02) {
82 125
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' value type mismatch');
83
            }
84 125
            $val = substr($binaryString, $start, $length);
85 125
            $vAnd = $val[0] & chr(0x80);
86 125
            if (ord($vAnd) === 128) {
87 14
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' value is negative');
88
            }
89
            if ($length > 1 && $val[0] === "\x00" && !ord(($val[1] & chr(0x80)))) {
90 114
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' value excessively padded');
91 6
            }
92
        };
93
94 111
        $bin = $sig->getBinary();
95 6
        $size = $sig->getSize();
96
        if ($size < 9) {
97
            throw new SignatureNotCanonical('Signature too short');
98 108
        }
99 8
100
        if ($size > 73) {
101
            throw new SignatureNotCanonical('Signature too long');
102 103
        }
103 103
104 103
        if (ord($bin[0]) !== 0x30) {
105 6
            throw new SignatureNotCanonical('Signature has wrong type');
106
        }
107
108 100
        if (ord($bin[1]) !== $size - 3) {
109 100
            throw new SignatureNotCanonical('Signature has wrong length marker');
110 100
        }
111 6
112
        $lenR = ord($bin[3]);
113
        $startR = 4;
114 97
        if (5 + $lenR >= $size) {
115 67
            throw new SignatureNotCanonical('Signature S length misplaced');
116
        }
117 52
118
        $lenS = ord($bin[5 + $lenR]);
119
        $startS = 4 + $lenR + 2;
120
        if (($lenR + $lenS + 7) !== $size) {
121
            throw new SignatureNotCanonical('Signature R+S length mismatch');
122
        }
123 48
124
        $checkVal('R', $startR, $lenR, $bin);
125 48
        $checkVal('S', $startS, $lenS, $bin);
126 48
127 32
        return true;
128
    }
129 48
130
    /**
131
     * @return BufferInterface
132
     */
133
    public function getBuffer()
134
    {
135
        $txSigSerializer = new TransactionSignatureSerializer(
136
            EcSerializer::getSerializer(DerSignatureSerializerInterface::class, true, $this->ecAdapter)
137
        );
138
139
        return $txSigSerializer->serialize($this);
140
    }
141
}
142