12
12
use BitWasp \Bitcoin \Exceptions \ScriptRuntimeException ;
13
13
use BitWasp \Bitcoin \Exceptions \SignatureNotCanonical ;
14
14
use BitWasp \Bitcoin \Script \Classifier \OutputClassifier ;
15
- use BitWasp \Bitcoin \Script \ExecutionContext ;
15
+ use BitWasp \Bitcoin \Script \Interpreter \ ExecutionContext ;
16
16
use BitWasp \Bitcoin \Script \Opcodes ;
17
17
use BitWasp \Bitcoin \Script \Script ;
18
18
use BitWasp \Bitcoin \Script \ScriptFactory ;
@@ -196,7 +196,7 @@ private function verifyTaprootCommitment(BufferInterface $control, BufferInterfa
196
196
}
197
197
}
198
198
$ t = Hash::taggedSha256 ("TapTweak " , Buffertools::concat ($ p , $ k ));
199
- return $ Q ->checkPayToContract ($ P , $ t , ($ control ->getBinary ()[0 ] & 1 ) == 1 );
199
+ return $ Q ->checkPayToContract ($ P , $ t , (ord ( $ control ->getBinary ()[0 ]) & 1 ) == 1 );
200
200
}
201
201
202
202
/**
@@ -305,7 +305,6 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn
305
305
$ witnessCount --;
306
306
}
307
307
$ execContext ->setAnnexCheckDone ();
308
-
309
308
if ($ witnessCount === 1 ) {
310
309
// key spend path - doesn't use the interpreter, directly checks signature
311
310
$ signature = $ scriptWitness [count ($ scriptWitness ) - 1 ];
@@ -343,7 +342,7 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn
343
342
}
344
343
345
344
// return true at this stage, need further work to proceed
346
- return $ this ->executeWitnessProgram ($ scriptWitness , $ scriptPubKey , SigHash::TAPSCRIPT , $ flags , $ checker , $ execContext );
345
+ return $ this ->executeWitnessProgram ($ scriptWitness , new Script ( $ scriptPubKey) , SigHash::TAPSCRIPT , $ flags , $ checker , $ execContext );
347
346
}
348
347
}
349
348
@@ -502,6 +501,54 @@ public function checkExec(Stack $vfStack, bool $value): bool
502
501
return (bool ) $ ret ;
503
502
}
504
503
504
+ private function evalChecksigPreTapscript (BufferInterface $ sig , BufferInterface $ key , ScriptInterface $ scriptPubKey , int $ hashStartPos , int $ flags , CheckerBase $ checker , int $ sigVersion , bool &$ success ): bool
505
+ {
506
+ assert ($ sigVersion === SigHash::V0 || $ sigVersion === SigHash::V1 );
507
+ $ scriptCode = new Script ($ scriptPubKey ->getBuffer ()->slice ($ hashStartPos ));
508
+ // encoding is checked in checker
509
+ $ success = $ checker ->checkSig ($ scriptCode , $ sig , $ key , $ sigVersion , $ flags );
510
+ return true ;
511
+ }
512
+
513
+ private function evalChecksigTapscript (BufferInterface $ sig , BufferInterface $ key , int $ flags , CheckerBase $ checker , int $ sigVersion , ExecutionContext $ execContext , bool &$ success ): bool
514
+ {
515
+ assert ($ sigVersion === SigHash::TAPSCRIPT );
516
+ $ success = $ sig ->getSize () > 0 ;
517
+ if ($ success ) {
518
+ assert ($ execContext ->hasValidationWeightSet ());
519
+ $ execContext ->setValidationWeightLeft ($ execContext ->getValidationWeightLeft () - VALIDATION_WEIGHT_OFFSET );
520
+ if ($ execContext ->getValidationWeightLeft () < 0 ) {
521
+ return false ;
522
+ }
523
+ }
524
+ if ($ key ->getSize () === 0 ) {
525
+ return false ;
526
+ } else if ($ key ->getSize () === 32 ) {
527
+ if ($ success && !$ checker ->checkSigSchnorr ($ sig , $ key , $ sigVersion , $ execContext )) {
528
+ return false ;
529
+ }
530
+ } else {
531
+ if ($ flags & self ::VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE ) {
532
+ return false ;
533
+ }
534
+ }
535
+ return true ;
536
+ }
537
+
538
+ private function evalChecksig (BufferInterface $ sig , BufferInterface $ key , ScriptInterface $ scriptPubKey , int $ hashStartPos , int $ flags , CheckerBase $ checker , int $ sigVersion , ExecutionContext $ execContext , bool &$ success ): bool
539
+ {
540
+ switch ($ sigVersion ) {
541
+ case SigHash::V0 :
542
+ case SigHash::V1 :
543
+ return $ this ->evalChecksigPreTapscript ($ sig , $ key , $ scriptPubKey , $ hashStartPos , $ flags , $ checker , $ sigVersion , $ success );
544
+ case SigHash::TAPSCRIPT :
545
+ return $ this ->evalChecksigTapscript ($ sig , $ key , $ flags , $ checker , $ sigVersion , $ execContext , $ success );
546
+ case SigHash::TAPROOT :
547
+ break ;
548
+ };
549
+ assert (false );
550
+ }
551
+
505
552
/**
506
553
* @param ScriptInterface $script
507
554
* @param Stack $mainStack
@@ -513,6 +560,9 @@ public function checkExec(Stack $vfStack, bool $value): bool
513
560
*/
514
561
public function evaluate (ScriptInterface $ script , Stack $ mainStack , int $ sigVersion , int $ flags , CheckerBase $ checker , ExecutionContext $ execContext = null ): bool
515
562
{
563
+ if ($ execContext === null ) {
564
+ $ execContext = new ExecutionContext ();
565
+ }
516
566
$ hashStartPos = 0 ;
517
567
$ opCount = 0 ;
518
568
$ zero = gmp_init (0 , 10 );
@@ -1033,9 +1083,10 @@ public function evaluate(ScriptInterface $script, Stack $mainStack, int $sigVers
1033
1083
$ vchPubKey = $ mainStack [-1 ];
1034
1084
$ vchSig = $ mainStack [-2 ];
1035
1085
1036
- $ scriptCode = new Script ($ script ->getBuffer ()->slice ($ hashStartPos ));
1037
-
1038
- $ success = $ checker ->checkSig ($ scriptCode , $ vchSig , $ vchPubKey , $ sigVersion , $ flags , $ execContext );
1086
+ $ success = false ;
1087
+ if (!$ this ->evalChecksig ($ vchSig , $ vchPubKey , $ script , $ hashStartPos , $ flags , $ checker , $ sigVersion , $ execContext , $ success )) {
1088
+ return false ;
1089
+ }
1039
1090
1040
1091
$ mainStack ->pop ();
1041
1092
$ mainStack ->pop ();
0 commit comments