Completed
Pull Request — master (#525)
by thomas
26:53
created

Signer::sign()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 5
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\Factory;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\EcSerializer;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Key\PublicKeySerializerInterface;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
11
use BitWasp\Bitcoin\Serializer\Signature\TransactionSignatureSerializer;
12
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHash;
13
use BitWasp\Bitcoin\Transaction\TransactionFactory;
14
use BitWasp\Bitcoin\Transaction\TransactionInterface;
15
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
16
17
class Signer
18
{
19
    /**
20
     * @var EcAdapterInterface
21
     */
22
    private $ecAdapter;
23
24
    /**
25
     * @var TransactionInterface
26
     */
27
    private $tx;
28
29
    /**
30
     * @var TransactionSignatureSerializer
31
     */
32
    private $sigSerializer;
33
34
    /**
35
     * @var PublicKeySerializerInterface
36
     */
37
    private $pubKeySerializer;
38
39
    /**
40
     * @var bool
41
     */
42
    private $tolerateInvalidPublicKey = false;
43
44
    /**
45
     * @var bool
46
     */
47
    private $redeemBitcoinCash = false;
48
49
    /**
50
     * @var bool
51
     */
52
    private $padUnsignedMultisigs = false;
53
54
    /**
55
     * @var bool
56
     */
57
    private $allowComplexScripts = false;
58
59
    /**
60
     * @var InputSignerInterface[]
61
     */
62
    private $signatureCreator = [];
63
64
    /**
65
     * TxWitnessSigner constructor.
66
     * @param TransactionInterface $tx
67
     * @param EcAdapterInterface $ecAdapter
68
     */
69 130
    public function __construct(TransactionInterface $tx, EcAdapterInterface $ecAdapter = null)
70
    {
71 130
        $this->tx = $tx;
72 130
        $this->ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
73 130
        $this->sigSerializer = new TransactionSignatureSerializer(EcSerializer::getSerializer(DerSignatureSerializerInterface::class, true, $this->ecAdapter));
74 130
        $this->pubKeySerializer = EcSerializer::getSerializer(PublicKeySerializerInterface::class, true, $this->ecAdapter);
75 130
    }
76
77
    /**
78
     * @param bool $setting
79
     * @return $this
80
     */
81 2
    public function redeemBitcoinCash($setting)
82
    {
83 2
        if (!is_bool($setting)) {
84
            throw new \InvalidArgumentException("Boolean value expected");
85
        }
86
87 2
        $this->redeemBitcoinCash = $setting;
88 2
        return $this;
89
    }
90
91
    /**
92
     * @param bool $setting
93
     * @return $this
94
     */
95 28
    public function padUnsignedMultisigs($setting)
96
    {
97 28
        if (!is_bool($setting)) {
98
            throw new \InvalidArgumentException("Boolean value expected");
99
        }
100
101 28
        $this->padUnsignedMultisigs = $setting;
102 28
        return $this;
103
    }
104
105
    /**
106
     * @param bool $setting
107
     * @return $this
108
     */
109 2
    public function tolerateInvalidPublicKey($setting)
110
    {
111 2
        if (!is_bool($setting)) {
112
            throw new \InvalidArgumentException("Boolean value expected");
113
        }
114
115 2
        $this->tolerateInvalidPublicKey = $setting;
116 2
        return $this;
117
    }
118
119
    /**
120
     * @param bool $setting
121
     * @return $this
122
     */
123 36
    public function allowComplexScripts($setting)
124
    {
125 36
        if (!is_bool($setting)) {
126
            throw new \InvalidArgumentException("Boolean value expected");
127
        }
128
129 36
        $this->allowComplexScripts = $setting;
130
131 36
        return $this;
132
    }
133
134
    /**
135
     * @param int $nIn
136
     * @param PrivateKeyInterface $key
137
     * @param TransactionOutputInterface $txOut
138
     * @param SignData $signData
139
     * @param int $sigHashType
140
     * @return $this
141
     */
142 50
    public function sign($nIn, PrivateKeyInterface $key, TransactionOutputInterface $txOut, SignData $signData = null, $sigHashType = SigHash::ALL)
143
    {
144 50
        $input = $this->input($nIn, $txOut, $signData);
145 50
        foreach ($input->getSteps() as $idx => $step) {
146 50
            $input->sign($key, $sigHashType);
147
        }
148
149
150 50
        return $this;
151
    }
152
153
    /**
154
     * @param int $nIn
155
     * @param TransactionOutputInterface $txOut
156
     * @param SignData|null $signData
157
     * @return InputSignerInterface
158
     */
159 130
    public function input($nIn, TransactionOutputInterface $txOut, SignData $signData = null)
160
    {
161 130
        if (null === $signData) {
162 16
            $signData = new SignData();
163
        }
164
165 130
        if (!isset($this->signatureCreator[$nIn])) {
166 130
            $input = (new InputSigner($this->ecAdapter, $this->tx, $nIn, $txOut, $signData, $this->sigSerializer, $this->pubKeySerializer))
167 130
                ->padUnsignedMultisigs($this->padUnsignedMultisigs)
168 130
                ->tolerateInvalidPublicKey($this->tolerateInvalidPublicKey)
169 130
                ->redeemBitcoinCash($this->redeemBitcoinCash)
170 130
                ->allowComplexScripts($this->allowComplexScripts)
171 130
                ->extract();
172
173 126
            $this->signatureCreator[$nIn] = $input;
174
        }
175
176 126
        return $this->signatureCreator[$nIn];
177
    }
178
179
    /**
180
     * @return TransactionInterface
181
     */
182 116
    public function get()
183
    {
184 116
        $mutable = TransactionFactory::mutate($this->tx);
185 116
        $witnesses = [];
186 116
        foreach ($mutable->inputsMutator() as $idx => $input) {
187 116
            $sig = $this->signatureCreator[$idx]->serializeSignatures();
188 116
            $input->script($sig->getScriptSig());
189 116
            $witnesses[$idx] = $sig->getScriptWitness();
190
        }
191
192 116
        if (count($witnesses) > 0) {
193 116
            $mutable->witness($witnesses);
194
        }
195
196 116
        $new = $mutable->done();
197 116
        return $new;
198
    }
199
}
200