diff --git a/.travis.yml b/.travis.yml index ce00fd616..5dcf19297 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,6 +78,8 @@ before_script: - if [ "${COVERAGE}" != "true" ] && [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ "$TRAVIS_PHP_VERSION" != "nightly" ]; then phpenv config-rm xdebug.ini && echo "xdebug disabled"; fi script: + - vendor/bin/phpunit --filter 'TaprootTest::testScript#20' + - vendor/bin/phpunit --filter 'TaprootTest::testScript#21' - travis/run_secp256k1_tests.sh || exit 1 - if [ "$COVERAGE" = "true" ]; then pwd && vendor/bin/phpstan analyse src tests -l 1; fi - make phpunit-ci || exit 1 diff --git a/src/Script/Interpreter/CheckerBase.php b/src/Script/Interpreter/CheckerBase.php index e0ffe99a5..1d16a7712 100644 --- a/src/Script/Interpreter/CheckerBase.php +++ b/src/Script/Interpreter/CheckerBase.php @@ -284,9 +284,11 @@ public function getTaprootSigHash(int $sigHashType, int $sigVersion, ExecutionCo public function checkSigSchnorr(BufferInterface $sig64, BufferInterface $key32, int $sigVersion, ExecutionContext $execContext): bool { if ($sig64->getSize() === 0) { + echo "sig64 = 0\n"; return false; } if ($key32->getSize() !== 32) { + echo "key != 32\n"; return false; } @@ -294,12 +296,14 @@ public function checkSigSchnorr(BufferInterface $sig64, BufferInterface $key32, if ($sig64->getSize() === 65) { $hashType = (int) $sig64->slice(64, 1)->getInt(); if ($hashType === SigHash::TAPDEFAULT) { + echo "badsighash1\n"; return false; } $sig64 = $sig64->slice(0, 64); } if ($sig64->getSize() !== 64) { + echo "sig.size!=64\n"; return false; } @@ -309,6 +313,7 @@ public function checkSigSchnorr(BufferInterface $sig64, BufferInterface $key32, $sigHash = $this->getTaprootSigHash($hashType, $sigVersion, $execContext); return $pubKey->verifySchnorr($sigHash, $sig); } catch (\Exception $e) { + echo "checksigSchnorr exception: ". $e->getMessage().PHP_EOL; return false; } } diff --git a/src/Script/Interpreter/Interpreter.php b/src/Script/Interpreter/Interpreter.php index 4d35454b7..42157005c 100644 --- a/src/Script/Interpreter/Interpreter.php +++ b/src/Script/Interpreter/Interpreter.php @@ -295,10 +295,12 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn } if ($witnessCount === 0) { + echo "empty witness\n"; return false; } else if ($witnessCount >= 2 && $scriptWitness->bottom()->getSize() > 0 && ord($scriptWitness->bottom()->getBinary()[0]) === TaprootHasher::TAPROOT_ANNEX_BYTE) { $annex = $scriptWitness->bottom(); if (($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_ANNEX)) { + echo "uigradable annex\n"; return false; } $execContext->setAnnexHash(Hash::sha256($annex)); @@ -311,6 +313,7 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn // key spend path - doesn't use the interpreter, directly checks signature $signature = $scriptWitness[count($scriptWitness) - 1]; if (!$checker->checkSigSchnorr($signature, $witnessProgram->getProgram(), SigHash::TAPROOT, $execContext)) { + echo "invalid signature\n"; return false; } return true; @@ -329,11 +332,13 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn if ($control->getSize() < TAPROOT_CONTROL_BASE_SIZE || $control->getSize() > TAPROOT_CONTROL_MAX_SIZE || (($control->getSize() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_BRANCH_SIZE !== 0)) { + echo "invalid control size\n"; return false; } $leafHash = null; if (!$this->verifyTaprootCommitment($control, $witnessProgram->getProgram(), $scriptPubKey, $leafHash)) { + echo "invalid taproot commitment\n"; return false; } $execContext->setTapLeafHash($leafHash); @@ -344,11 +349,15 @@ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitn } // return true at this stage, need further work to proceed - return $this->executeWitnessProgram($scriptWitness, new Script($scriptPubKey), SigHash::TAPSCRIPT, $flags, $checker, $execContext); + $ret = $this->executeWitnessProgram($scriptWitness, new Script($scriptPubKey), SigHash::TAPSCRIPT, $flags, $checker, $execContext); + var_dump("witnessExec"); + var_dump($ret); + return $ret; } } if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { + echo "upgradable witness program\n"; return false; } @@ -520,17 +529,21 @@ private function evalChecksigTapscript(BufferInterface $sig, BufferInterface $ke assert($execContext->hasValidationWeightSet()); $execContext->setValidationWeightLeft($execContext->getValidationWeightLeft() - VALIDATION_WEIGHT_OFFSET); if ($execContext->getValidationWeightLeft() < 0) { + echo "validation weight failure\n"; return false; } } if ($key->getSize() === 0) { + echo "keysize=0\n"; return false; } else if ($key->getSize() === 32) { if ($success && !$checker->checkSigSchnorr($sig, $key, $sigVersion, $execContext)) { + echo "keysize = 32 and checksig failed\n"; return false; } } else { if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE) { + echo "upgradable keytype\n"; return false; } } @@ -614,9 +627,9 @@ public function evaluate(ScriptInterface $script, Stack $mainStack, int $sigVers } $mainStack->push($pushData); - // echo " - [pushed '" . $pushData->getHex() . "']\n"; + echo " - [pushed '" . $pushData->getHex() . "']\n"; } elseif ($fExec || (Opcodes::OP_IF <= $opCode && $opCode <= Opcodes::OP_ENDIF)) { - // echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n"; + echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n"; switch ($opCode) { case Opcodes::OP_1NEGATE: case Opcodes::OP_1: @@ -1081,9 +1094,11 @@ public function evaluate(ScriptInterface $script, Stack $mainStack, int $sigVers case Opcodes::OP_CHECKSIGADD: if ($sigVersion !== SigHash::TAPSCRIPT) { + echo "sigVersion != tapscript\n"; throw new \RuntimeException('Opcode not found'); } if ($mainStack->count() < 3) { + echo "mainStack count != 3\n"; return false; } $pubkey = $mainStack[-1]; @@ -1092,6 +1107,7 @@ public function evaluate(ScriptInterface $script, Stack $mainStack, int $sigVers $success = false; if (!$this->evalChecksig($sig, $pubkey, $script, $hashStartPos, $flags, $checker, $sigVersion, $execContext, $success)) { + echo "checksig add - evalChecksig false\n"; return false; } $push = Number::gmp($this->math->add($n->getGmp(), gmp_init($success ? 1 : 0, 10)), $this->math)->getBuffer(); @@ -1248,11 +1264,11 @@ public function evaluate(ScriptInterface $script, Stack $mainStack, int $sigVers return true; } catch (ScriptRuntimeException $e) { - // echo "\n Runtime: " . $e->getMessage() . "\n" . $e->getTraceAsString() . PHP_EOL; + echo "\n Runtime: " . $e->getMessage() . "\n" . $e->getTraceAsString() . PHP_EOL; // Failure due to script tags, can access flag: $e->getFailureFlag() return false; } catch (\Exception $e) { - // echo "\n General: " . $e->getMessage() . PHP_EOL . $e->getTraceAsString() . PHP_EOL; + echo "\n General: " . $e->getMessage() . PHP_EOL . $e->getTraceAsString() . PHP_EOL; return false; } }