Completed
Pull Request — master (#239)
by thomas
31:39 queued 14:06
created

InputSigner::serializeSimpleSig()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9.0117

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 30
ccs 18
cts 19
cp 0.9474
rs 4.909
cc 9
eloc 17
nc 7
nop 2
crap 9.0117
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\Factory;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
8
use BitWasp\Bitcoin\Crypto\Hash;
9
use BitWasp\Bitcoin\Crypto\Random\Rfc6979;
10
use BitWasp\Bitcoin\Key\PublicKeyFactory;
11
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
12
use BitWasp\Bitcoin\Script\Opcodes;
13
use BitWasp\Bitcoin\Script\Parser\Operation;
14
use BitWasp\Bitcoin\Script\Script;
15
use BitWasp\Bitcoin\Script\ScriptFactory;
16
use BitWasp\Bitcoin\Script\ScriptInfo\Multisig;
17
use BitWasp\Bitcoin\Script\ScriptInterface;
18
use BitWasp\Bitcoin\Script\ScriptWitness;
19
use BitWasp\Bitcoin\Signature\SignatureSort;
20
use BitWasp\Bitcoin\Signature\TransactionSignature;
21
use BitWasp\Bitcoin\Signature\TransactionSignatureFactory;
22
use BitWasp\Bitcoin\Signature\TransactionSignatureInterface;
23
use BitWasp\Bitcoin\Transaction\SignatureHash\Hasher;
24
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHash;
25
use BitWasp\Bitcoin\Transaction\SignatureHash\V1Hasher;
26
use BitWasp\Bitcoin\Transaction\TransactionInterface;
27
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
28
use BitWasp\Buffertools\BufferInterface;
29
30
class InputSigner
31
{
32
    /**
33
     * @var EcAdapterInterface
34
     */
35
    private $ecAdapter;
36
37
    /**
38
     * @var ScriptInterface $redeemScript
39
     */
40
    private $redeemScript;
41
42
    /**
43
     * @var ScriptInterface $witnessScript
44
     */
45
    private $witnessScript;
46
47
    /**
48
     * @var TransactionInterface
49
     */
50
    private $tx;
51
52
    /**
53
     * @var int
54
     */
55
    private $nInput;
56
57
    /**
58
     * @var PublicKeyInterface[]
59
     */
60
    private $publicKeys = [];
61
62
    /**
63
     * @var int
64
     */
65
    private $sigHashType;
66
67
    /**
68
     * @var TransactionSignatureInterface[]
69
     */
70
    private $signatures = [];
71
72
    /**
73
     * @var int
74
     */
75
    private $requiredSigs = 0;
76
77
    /**
78
     * TxInputSigning constructor.
79
     * @param EcAdapterInterface $ecAdapter
80
     * @param TransactionInterface $tx
81
     * @param int $nInput
82
     * @param TransactionOutputInterface $txOut
83
     * @param int $sigHashType
84
     */
85 54
    public function __construct(EcAdapterInterface $ecAdapter, TransactionInterface $tx, $nInput, TransactionOutputInterface $txOut, $sigHashType = SigHash::ALL)
86
    {
87 54
        $this->ecAdapter = $ecAdapter;
88 54
        $this->tx = $tx;
89 54
        $this->nInput = $nInput;
90 54
        $this->txOut = $txOut;
0 ignored issues
show
Bug introduced by
The property txOut does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
91 54
        $this->sigHashType = $sigHashType;
92 54
        $this->publicKeys = [];
93 54
        $this->signatures = [];
94
95 54
        $this->extractSignatures();
96 54
    }
97
98
    /**
99
     * @param string $type
100
     * @param ScriptInterface $scriptCode
101
     * @param BufferInterface[] $stack
102
     * @param int $sigVersion
103
     * @return mixed
104
     */
105 54
    public function extractFromValues($type, ScriptInterface $scriptCode, array $stack, $sigVersion)
106
    {
107 48
        $size = count($stack);
108 48
        if ($type === OutputClassifier::PAYTOPUBKEYHASH) {
109 12
            $this->requiredSigs = 1;
110 12
            if ($size === 2) {
111 12
                $this->signatures = [TransactionSignatureFactory::fromHex($stack[0], $this->ecAdapter)];
0 ignored issues
show
Documentation introduced by
$stack[0] is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<BitWasp\Buffertools\Buffer>|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
112 12
                $this->publicKeys = [PublicKeyFactory::fromHex($stack[1], $this->ecAdapter)];
0 ignored issues
show
Documentation introduced by
$stack[1] is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<BitWasp\Buffertools\Buffer>|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
113 12
            }
114 12
        }
115
116 48
        if ($type === OutputClassifier::PAYTOPUBKEY) {
117 6
            $this->requiredSigs = 1;
118 6
            if ($size === 1) {
119 6
                $this->signatures = [TransactionSignatureFactory::fromHex($stack[0], $this->ecAdapter)];
0 ignored issues
show
Documentation introduced by
$stack[0] is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<BitWasp\Buffertools\Buffer>|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
120 6
            }
121 6
        }
122
123 48
        if ($type === OutputClassifier::MULTISIG) {
124 24
            $info = new Multisig($scriptCode);
125 24
            $this->requiredSigs = $info->getRequiredSigCount();
126 24
            $this->publicKeys = $info->getKeys();
127
128 24
            if ($size > 1) {
129 24
                if ($sigVersion === 1) {
130 12
                    $hasher = new V1Hasher($this->tx, $this->txOut->getValue());
131 12
                } else {
132 12
                    $hasher = new Hasher($this->tx);
133
                }
134
135 24
                $sigSort = new SignatureSort($this->ecAdapter);
136 24
                $sigs = new \SplObjectStorage;
137
138 24
                foreach (array_slice($stack, 1, -1) as $item) {
139
                    $txSig = TransactionSignatureFactory::fromHex($item, $this->ecAdapter);
0 ignored issues
show
Documentation introduced by
$item is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<BitWasp\Buffertools\Buffer>|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
140
                    $hash = $hasher->calculate($scriptCode, $this->nInput, $txSig->getHashType());
141
                    $linked = $sigSort->link([$txSig->getSignature()], $this->publicKeys, $hash);
142
143
                    foreach ($this->publicKeys as $key) {
144
                        if ($linked->contains($key)) {
145
                            $sigs[$key] = $txSig;
146
                        }
147
                    }
148 24
                }
149
150 24
                foreach ($this->publicKeys as $idx => $key) {
151 24
                    $this->signatures[$idx] = isset($sigs[$key]) ? $sigs[$key]->getBuffer() : null;
152 54
                }
153 24
            }
154 24
        }
155
156 48
        return $type;
157
    }
158
159
    /**
160
     * @return $this
161
     */
162 54
    public function extractSignatures()
163
    {
164 54
        $type = (new OutputClassifier($this->txOut->getScript()))->classify();
165 54
        $scriptPubKey = $this->txOut->getScript();
166 54
        $scriptSig = $this->tx->getInput($this->nInput)->getScript();
167
168 54
        if ($type === OutputClassifier::PAYTOPUBKEYHASH || $type === OutputClassifier::PAYTOPUBKEY || $type === OutputClassifier::MULTISIG) {
169 18
            $innerSig = array_map(function (Operation $o) {
170 18
                return $o->getData();
171 18
            }, $scriptSig->getScriptParser()->decode());
172
173 18
            $this->extractFromValues($type, $scriptPubKey, $innerSig, 0);
174 18
        }
175
176 54
        if ($type === OutputClassifier::PAYTOSCRIPTHASH) {
177 18
            $decodeSig = $scriptSig->getScriptParser()->decode();
178 18
            if (count($decodeSig) > 0) {
179 18
                $redeemScript = new Script(end($decodeSig)->getData());
180 18
                $p2shType = (new OutputClassifier($redeemScript))->classify();
181
182 18
                if (count($decodeSig) > 1) {
183 6
                    $decodeSig = array_slice($decodeSig, 0, -1);
184 6
                }
185
186 18
                $internalSig = [];
187 18
                foreach ($decodeSig as $operation) {
188 18
                    $internalSig[] = $operation->getData();
189 18
                }
190
191 18
                $this->redeemScript = $redeemScript;
192 18
                $this->extractFromValues($p2shType, $redeemScript, $internalSig, 0);
193
194 48
                $type = $p2shType;
195 18
            }
196 18
        }
197
198 54
        $witnesses = $this->tx->getWitnesses();
199 54
        if ($type === OutputClassifier::WITNESS_V0_KEYHASH) {
200 12
            $this->requiredSigs = 1;
201 12
            if (isset($witnesses[$this->nInput])) {
202 12
                $witness = $witnesses[$this->nInput];
203 12
                $this->signatures = [TransactionSignatureFactory::fromHex($witness[0], $this->ecAdapter)];
204 12
                $this->publicKeys = [PublicKeyFactory::fromHex($witness[1], $this->ecAdapter)];
205 12
            }
206
207 54
        } else if ($type === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
208 18
            if (isset($witnesses[$this->nInput])) {
209 18
                $witness = $witnesses[$this->nInput];
210 18
                $witCount = count($witnesses[$this->nInput]);
211 18
                if ($witCount > 0) {
212 18
                    $witnessScript = new Script($witness[$witCount - 1]);
213 18
                    $vWitness = $witness->all();
214 18
                    if (count($vWitness) > 1) {
215 18
                        $vWitness = array_slice($witness->all(), 0, -1);
216 18
                    }
217
218 18
                    $witnessType = (new OutputClassifier($witnessScript))->classify();
219 18
                    $this->extractFromValues($witnessType, $witnessScript, $vWitness, 1);
220 18
                    $this->witnessScript = $witnessScript;
221 18
                }
222 18
            }
223 18
        }
224
225 54
        return $this;
226
    }
227
228
    /**
229
     * @param PrivateKeyInterface $key
230
     * @param ScriptInterface $scriptCode
231
     * @param int $sigVersion
232
     * @return TransactionSignature
233
     */
234 54
    public function calculateSignature(PrivateKeyInterface $key, ScriptInterface $scriptCode, $sigVersion)
235
    {
236 54
        if ($sigVersion == 1) {
237 30
            $hasher = new V1Hasher($this->tx, $this->txOut->getValue());
238 30
        } else {
239 24
            $hasher = new Hasher($this->tx);
240
        }
241
242 54
        $hash = $hasher->calculate($scriptCode, $this->nInput, $this->sigHashType);
243
244 54
        return new TransactionSignature(
245 54
            $this->ecAdapter,
246 54
            $this->ecAdapter->sign(
247 54
                $hash,
248 54
                $key,
249 54
                new Rfc6979(
250 54
                    $this->ecAdapter,
251 54
                    $key,
252 54
                    $hash,
253
                    'sha256'
254 54
                )
255 54
            ),
256 54
            $this->sigHashType
257 54
        );
258
    }
259
260
    /**
261
     * @return int
262
     */
263 54
    public function isFullySigned()
264
    {
265 54
        return $this->requiredSigs !== 0 && $this->requiredSigs === count($this->signatures);
266
    }
267
268
    /**
269
     * The function only returns true when $scriptPubKey could be classified
270
     *
271
     * @param PrivateKeyInterface $key
272
     * @param ScriptInterface $scriptPubKey
273
     * @param int $outputType
274
     * @param BufferInterface[] $results
275
     * @param int $sigVersion
276
     * @return bool
277
     */
278 54
    private function doSignature(PrivateKeyInterface $key, ScriptInterface $scriptPubKey, &$outputType, array &$results, $sigVersion = 0)
279
    {
280 54
        $return = [];
281 54
        $outputType = (new OutputClassifier($scriptPubKey))->classify($return);
282 54
        if ($outputType === OutputClassifier::UNKNOWN) {
283
            throw new \RuntimeException('Cannot sign unknown script type');
284
        }
285
286 54
        if ($outputType === OutputClassifier::PAYTOPUBKEY) {
287 6
            $publicKeyBuffer = $return;
288 6
            $results[] = $publicKeyBuffer;
289 6
            $this->requiredSigs = 1;
290 6
            $publicKey = PublicKeyFactory::fromHex($publicKeyBuffer);
0 ignored issues
show
Documentation introduced by
$publicKeyBuffer is of type object<BitWasp\Buffertoo...\BufferInterface>>|null, but the function expects a object<BitWasp\Buffertools\Buffer>|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
291
292 6
            if ($publicKey->getBinary() === $key->getPublicKey()->getBinary()) {
293 6
                $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigVersion);
294 6
            }
295
296 6
            return true;
297
        }
298
299 48
        if ($outputType === OutputClassifier::PAYTOPUBKEYHASH) {
300
            /** @var BufferInterface $pubKeyHash */
301 24
            $pubKeyHash = $return;
302 24
            $results[] = $pubKeyHash;
303 24
            $this->requiredSigs = 1;
304 24
            if ($pubKeyHash->getBinary() === $key->getPublicKey()->getPubKeyHash()->getBinary()) {
305 18
                $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigVersion);
306 18
                $this->publicKeys[0] = $key->getPublicKey();
307 18
            }
308
309 24
            return true;
310
        }
311
312 42
        if ($outputType === OutputClassifier::MULTISIG) {
313 24
            $info = new Multisig($scriptPubKey);
314
315 24
            foreach ($info->getKeys() as $publicKey) {
316 24
                $results[] = $publicKey->getBuffer();
317 24
            }
318
319 24
            $this->publicKeys = $info->getKeys();
320 24
            $this->requiredSigs = $info->getKeyCount();
321
322 24
            foreach ($this->publicKeys as $keyIdx => $publicKey) {
323 24
                if ($publicKey->getBinary() == $key->getPublicKey()->getBinary()) {
324 24
                    $this->signatures[$keyIdx] = $this->calculateSignature($key, $scriptPubKey, $sigVersion);
325 24
                } else {
326
                    return false;
327
                }
328 24
            }
329
330 24
            return true;
331
        }
332
333 36
        if ($outputType === OutputClassifier::PAYTOSCRIPTHASH) {
334
            /** @var BufferInterface $scriptHash */
335 18
            $scriptHash = $return;
336 18
            $results[] = $scriptHash;
337 18
            return true;
338
        }
339
340 30
        if ($outputType === OutputClassifier::WITNESS_V0_KEYHASH) {
341
            /** @var BufferInterface $pubKeyHash */
342 12
            $pubKeyHash = $return;
343 12
            $results[] = $pubKeyHash;
344 12
            $this->requiredSigs = 1;
345
346 12
            if ($pubKeyHash->getBinary() === $key->getPublicKey()->getPubKeyHash()->getBinary()) {
347 12
                $script = ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
348 12
                $this->signatures[0] = $this->calculateSignature($key, $script, 1);
349 12
                $this->publicKeys[0] = $key->getPublicKey();
350 12
            }
351
352 12
            return true;
353
        }
354
355 18
        if ($outputType === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
356
            /** @var BufferInterface $scriptHash */
357 18
            $scriptHash = $return;
358 18
            $results[] = $scriptHash;
359
360 18
            return true;
361
        }
362
363
        return false;
364
    }
365
366
    /**
367
     * @param PrivateKeyInterface $key
368
     * @param ScriptInterface|null $redeemScript
369
     * @param ScriptInterface|null $witnessScript
370
     * @return bool
371
     */
372 54
    public function sign(PrivateKeyInterface $key, ScriptInterface $redeemScript = null, ScriptInterface $witnessScript = null)
373
    {
374
        /** @var BufferInterface[] $return */
375 54
        $type = null;
376 54
        $return = [];
377 54
        $solved = $this->doSignature($key, $this->txOut->getScript(), $type, $return, 0);
378
379 54
        if ($solved && $type === OutputClassifier::PAYTOSCRIPTHASH) {
380 18
            $redeemScriptBuffer = $return[0];
381
382 18
            if (!$redeemScript instanceof ScriptInterface) {
383
                throw new \InvalidArgumentException('Must provide redeem script for P2SH');
384
            }
385
386 18
            if (!$redeemScript->getScriptHash()->getBinary() === $redeemScriptBuffer->getBinary()) {
387
                throw new \InvalidArgumentException("Incorrect redeem script - hash doesn't match");
388
            }
389
390 18
            $results = []; // ???
391 18
            $solved = $solved && $this->doSignature($key, $redeemScript, $type, $results, 0) && $type !== OutputClassifier::PAYTOSCRIPTHASH;
392 18
            if ($solved) {
393 18
                $this->redeemScript = $redeemScript;
394 18
            }
395 18
        }
396
397 54
        if ($solved && $type === OutputClassifier::WITNESS_V0_KEYHASH) {
398 12
            $pubKeyHash = $return[0];
399 12
            $witnessScript = ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
400 12
            $subType = null;
401 12
            $subResults = [];
402 12
            $solved = $solved && $this->doSignature($key, $witnessScript, $subType, $subResults, 1);
403 54
        } else if ($solved && $type === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
404 18
            $scriptHash = $return[0];
405
406 18
            if (!$witnessScript instanceof ScriptInterface) {
407
                throw new \InvalidArgumentException('Must provide witness script for witness v0 scripthash');
408
            }
409
410 18
            if (!Hash::sha256($witnessScript->getBuffer())->getBinary() === $scriptHash->getBinary()) {
411
                throw new \InvalidArgumentException("Incorrect witness script - hash doesn't match");
412
            }
413
414 18
            $subType = null;
415 18
            $subResults = [];
416
417 18
            $solved = $solved && $this->doSignature($key, $witnessScript, $subType, $subResults, 1)
418 18
                && $subType !== OutputClassifier::PAYTOSCRIPTHASH
419 18
                && $subType !== OutputClassifier::WITNESS_V0_SCRIPTHASH
420 18
                && $subType !== OutputClassifier::WITNESS_V0_KEYHASH;
421
422 18
            if ($solved) {
423 18
                $this->witnessScript = $witnessScript;
424 18
            }
425 18
        }
426
427 54
        return $solved;
428
    }
429
430
    /**
431
     * @param $outputType
432
     * @param $answer
433
     * @return bool
434
     */
435 54
    private function serializeSimpleSig($outputType, &$answer)
436
    {
437 54
        if ($outputType === OutputClassifier::UNKNOWN) {
438
            throw new \RuntimeException('Cannot sign unknown script type');
439
        }
440
441 54
        if ($outputType === OutputClassifier::PAYTOPUBKEY && $this->isFullySigned()) {
442 6
            $answer = new SigValues(ScriptFactory::sequence([$this->signatures[0]->getBuffer()]), new ScriptWitness([]));
443 6
            return true;
444
        }
445
446 48
        if ($outputType === OutputClassifier::PAYTOPUBKEYHASH && $this->isFullySigned()) {
447 12
            $answer = new SigValues(ScriptFactory::sequence([$this->signatures[0]->getBuffer(), $this->publicKeys[0]->getBuffer()]), new ScriptWitness([]));
448 12
            return true;
449
        }
450
451 42
        if ($outputType === OutputClassifier::MULTISIG) {
452 24
            $sequence = [Opcodes::OP_0];
453 24
            for ($i = 0; $i < $this->requiredSigs; $i++) {
454 24
                if (isset($this->signatures[$i])) {
455 24
                    $sequence[] =  $this->signatures[$i]->getBuffer();
456 24
                }
457 24
            }
458
459 24
            $answer = new SigValues(ScriptFactory::sequence($sequence), new ScriptWitness([]));
460 24
            return true;
461
        }
462
463 36
        return false;
464
    }
465
466
    /**
467
     * @return SigValues
468
     */
469 54
    public function serializeSignatures()
470
    {
471 54
        static $emptyScript = null;
472 54
        static $emptyWitness = null;
473 54
        if (is_null($emptyScript) || is_null($emptyWitness)) {
474 6
            $emptyScript = new Script();
475 6
            $emptyWitness = new ScriptWitness([]);
476 6
        }
477
478
        /** @var BufferInterface[] $return */
479 54
        $outputType = (new OutputClassifier($this->txOut->getScript()))->classify();
480
481
        /** @var SigValues $answer */
482 54
        $answer = new SigValues($emptyScript, $emptyWitness);
483 54
        $serialized = $this->serializeSimpleSig($outputType, $answer);
484
485 54
        $p2sh = false;
486 54
        if (!$serialized && $outputType === OutputClassifier::PAYTOSCRIPTHASH) {
487 18
            $p2sh = true;
488 18
            $outputType = (new OutputClassifier($this->redeemScript))->classify();
489 18
            $serialized = $this->serializeSimpleSig($outputType, $answer);
490 18
        }
491
492 54
        if (!$serialized && $outputType === OutputClassifier::WITNESS_V0_KEYHASH) {
493 12
            $answer = new SigValues($emptyScript, new ScriptWitness([$this->signatures[0]->getBuffer(), $this->publicKeys[0]->getBuffer()]));
494
495 54
        } else if (!$serialized && $outputType === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
496 18
            $outputType = (new OutputClassifier($this->witnessScript))->classify();
497 18
            $serialized = $this->serializeSimpleSig($outputType, $answer);
498
499 18
            if ($serialized) {
500 18
                $data = [];
501 18
                foreach ($answer->getScriptSig()->getScriptParser()->decode() as $o) {
502 18
                    $data[] = $o->getData();
503 18
                }
504
505 18
                $data[] = $this->witnessScript->getBuffer();
506 18
                $answer = new SigValues($emptyScript, new ScriptWitness($data));
507 18
            }
508 18
        }
509
510 54
        if ($p2sh) {
511 18
            $answer = new SigValues(
512 18
                ScriptFactory::create($answer->getScriptSig()->getBuffer())->push($this->redeemScript->getBuffer())->getScript(),
513 18
                $answer->getScriptWitness()
514 18
            );
515 18
        }
516
517 54
        return $answer;
518
    }
519
}
520