/** * @return bool */ public function isMultisig() { if (count($this->decoded) < 3) { return false; } $final = end($this->decoded); if (!$final || !$final->isPush()) { return false; } $script = new Script($final->getData()); $decoded = $script->getScriptParser()->decode(); $count = count($decoded); $mOp = $decoded[0]; $nOp = $decoded[$count - 2]; if ($mOp->isPush() || $nOp->isPush()) { return false; } if ($mOp->getOp() < Opcodes::OP_0 || $nOp->getOp() > Opcodes::OP_16) { return false; } /** @var Operation[] $keys */ $keys = array_slice($decoded, 1, -2); $keysValid = true; foreach ($keys as $key) { $keysValid &= $key->isPush() && PublicKey::isCompressedOrUncompressed($key->getData()); } return $keysValid; }
/** * @return bool */ public function isMultisig() { if (count($this->evalScript) < 3) { return false; } $final = end($this->evalScript); if (!$final || !$final instanceof Buffer) { return false; } $script = new Script($final); $parsed = $script->getScriptParser()->parse(); $count = count($parsed); $opCodes = $script->getOpCodes(); $mOp = $parsed[0]; $nOp = $parsed[$count - 2]; $keys = array_slice($parsed, 1, -2); $keysValid = true; foreach ($keys as $key) { $keysValid &= $key instanceof Buffer && PublicKey::isCompressedOrUncompressed($key); } return $opCodes->cmp($opCodes->getOpByName($mOp), 'OP_0') >= 0 && $opCodes->cmp($opCodes->getOpByName($nOp), 'OP_16') <= 0 && $keysValid; }
/** * @param int|string $m * @param \BitWasp\Bitcoin\Key\PublicKeyInterface[] $keys */ public function __construct($m, array $keys) { parent::__construct(); $n = count($keys); if ($m > $n) { throw new \LogicException('Required number of sigs exceeds number of public keys'); } if ($n > 16) { throw new \LogicException('Number of public keys is greater than 16'); } $ops = $this->getOpCodes(); $opM = $ops->getOp($ops->getOpByName('OP_1') - 1 + $m); $opN = $ops->getOp($ops->getOpByName('OP_1') - 1 + $n); $this->op($opM); foreach ($keys as $key) { if (!$key instanceof PublicKeyInterface) { throw new \LogicException('Values in $keys[] must be a PublicKey'); } $this->keys[] = $key; $this->push($key->getBuffer()); } $this->op($opN)->op('OP_CHECKMULTISIG'); $this->m = $m; }
/** * P2shScript constructor. * @param ScriptInterface $script * @param Opcodes|null $opcodes */ public function __construct(ScriptInterface $script, Opcodes $opcodes = null) { parent::__construct($script->getBuffer(), $opcodes); $this->outputScript = ScriptFactory::scriptPubKey()->payToScriptHash($script); }
/** * @param ScriptInterface $scriptSig * @param ScriptWitnessInterface $scriptWitness * @param int $flags * @return int */ public function countWitnessSigOps(ScriptInterface $scriptSig, ScriptWitnessInterface $scriptWitness, $flags) { if ($flags & InterpreterInterface::VERIFY_WITNESS === 0) { return 0; } $program = null; if ($this->isWitness($program)) { /** @var WitnessProgram $program */ return $this->witnessSigOps($program, $scriptWitness); } if ((new OutputClassifier($this))->isPayToScriptHash()) { $parsed = $scriptSig->getScriptParser()->decode(); $subscript = new Script(end($parsed)->getData()); if ($subscript->isWitness($program)) { /** @var WitnessProgram $program */ return $this->witnessSigOps($program, $scriptWitness); } } return 0; }
/** * @param WitnessProgram $witnessProgram * @param ScriptWitness $scriptWitness * @param int $flags * @param Checker $checker * @return bool */ private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitness $scriptWitness, $flags, Checker $checker) { $witnessCount = count($scriptWitness); if ($witnessProgram->getVersion() == 0) { $buffer = $witnessProgram->getProgram(); if ($buffer->getSize() === 32) { // Version 0 segregated witness program: SHA256(Script) in program, Script + inputs in witness if ($witnessCount === 0) { // Must contain script at least return false; } $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]); $stackValues = $scriptWitness->slice(0, -1); $hashScriptPubKey = Hash::sha256($scriptPubKey->getBuffer()); if ($hashScriptPubKey == $buffer) { return false; } } elseif ($buffer->getSize() === 20) { // Version 0 special case for pay-to-pubkeyhash if ($witnessCount !== 2) { // 2 items in witness - <signature> <pubkey> return false; } $scriptPubKey = ScriptFactory::create()->sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $buffer, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG])->getScript(); $stackValues = $scriptWitness; } else { return false; } } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { return false; } else { return false; } $mainStack = new Stack(); foreach ($stackValues as $value) { $mainStack->push($value); } if (!$this->evaluate($scriptPubKey, $mainStack, 1, $flags, $checker)) { return false; } if ($mainStack->count() !== 1) { return false; } if (!$this->castToBool($mainStack->bottom())) { return false; } return true; }