1212use BitWasp \Bitcoin \Exceptions \ScriptRuntimeException ;
1313use BitWasp \Bitcoin \Exceptions \SignatureNotCanonical ;
1414use BitWasp \Bitcoin \Script \Classifier \OutputClassifier ;
15- use BitWasp \Bitcoin \Script \ExecutionContext ;
15+ use BitWasp \Bitcoin \Script \Interpreter \ ExecutionContext ;
1616use BitWasp \Bitcoin \Script \Opcodes ;
1717use BitWasp \Bitcoin \Script \Script ;
1818use BitWasp \Bitcoin \Script \ScriptFactory ;
@@ -196,7 +196,7 @@ private function verifyTaprootCommitment(BufferInterface $control, BufferInterfa
196196 }
197197 }
198198 $ 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 );
200200 }
201201
202202 /**
@@ -305,7 +305,6 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn
305305 $ witnessCount --;
306306 }
307307 $ execContext ->setAnnexCheckDone ();
308-
309308 if ($ witnessCount === 1 ) {
310309 // key spend path - doesn't use the interpreter, directly checks signature
311310 $ signature = $ scriptWitness [count ($ scriptWitness ) - 1 ];
@@ -343,7 +342,7 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn
343342 }
344343
345344 // 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 );
347346 }
348347 }
349348
@@ -502,6 +501,54 @@ public function checkExec(Stack $vfStack, bool $value): bool
502501 return (bool ) $ ret ;
503502 }
504503
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+
505552 /**
506553 * @param ScriptInterface $script
507554 * @param Stack $mainStack
@@ -513,6 +560,9 @@ public function checkExec(Stack $vfStack, bool $value): bool
513560 */
514561 public function evaluate (ScriptInterface $ script , Stack $ mainStack , int $ sigVersion , int $ flags , CheckerBase $ checker , ExecutionContext $ execContext = null ): bool
515562 {
563+ if ($ execContext === null ) {
564+ $ execContext = new ExecutionContext ();
565+ }
516566 $ hashStartPos = 0 ;
517567 $ opCount = 0 ;
518568 $ zero = gmp_init (0 , 10 );
@@ -1033,9 +1083,10 @@ public function evaluate(ScriptInterface $script, Stack $mainStack, int $sigVers
10331083 $ vchPubKey = $ mainStack [-1 ];
10341084 $ vchSig = $ mainStack [-2 ];
10351085
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+ }
10391090
10401091 $ mainStack ->pop ();
10411092 $ mainStack ->pop ();
0 commit comments