def test_script(self) -> None: for t in load_test_vectors('script_tests.json'): (scriptSig, scriptPubKey, witness, nValue, flags, expected_result, comment, test_case) = t (txCredit, txSpend) = self.create_test_txs(scriptSig, scriptPubKey, witness, nValue) try: VerifyScript(scriptSig, scriptPubKey, txSpend, 0, flags, amount=nValue, witness=witness) except ValidationError as err: if expected_result == 'OK': self.fail( 'Script FAILED: %r %r %r with exception %r\n\nTest data: %r' % (scriptSig, scriptPubKey, comment, err, test_case)) continue if expected_result != 'OK': self.fail('Expected %r to fail (%s)' % (test_case, expected_result))
def sign_input(tx, input_index, utxo): """Sign an input of transaction. Single-signature signing with SIGHASH_ALL""" key = utxo['key'] src_addr = CCoinAddress(utxo['address']) script_for_sighash = CScript( [OP_DUP, OP_HASH160, Hash160(key.pub), OP_EQUALVERIFY, OP_CHECKSIG]) assert isinstance(src_addr, (P2PKHCoinAddress, P2SHCoinAddress, P2WPKHCoinAddress)),\ 'only p2pkh, p2wpkh and p2sh_p2wpkh addresses are supported' if isinstance(src_addr, P2PKHCoinAddress): sigversion = SIGVERSION_BASE else: sigversion = SIGVERSION_WITNESS_V0 if 'amountcommitment' in utxo: amountcommitment = CConfidentialValue(x(utxo['amountcommitment'])) else: amountcommitment = CConfidentialValue(coins_to_satoshi(utxo['amount'])) sighash = script_for_sighash.sighash(tx, input_index, SIGHASH_ALL, amount=amountcommitment, sigversion=sigversion) sig = key.sign(sighash) + bytes([SIGHASH_ALL]) if isinstance(src_addr, P2PKHCoinAddress): tx.vin[input_index].scriptSig = CScript( [CScript(sig), CScript(key.pub)]) scriptpubkey = src_addr.to_scriptPubKey() elif isinstance(src_addr, P2WPKHCoinAddress): tx.vin[input_index].scriptSig = CScript() tx.wit.vtxinwit[input_index] = CTxInWitness( CScriptWitness([CScript(sig), CScript(key.pub)])) scriptpubkey = src_addr.to_scriptPubKey() else: # Assume that this is p2sh-wrapped p2wpkh address inner_scriptPubKey = CScript([0, Hash160(key.pub)]) tx.vin[input_index].scriptSig = CScript([inner_scriptPubKey]) tx.wit.vtxinwit[input_index] = CTxInWitness( CScriptWitness([CScript(sig), CScript(key.pub)])) scriptpubkey = inner_scriptPubKey.to_p2sh_scriptPubKey() VerifyScript(tx.vin[input_index].scriptSig, scriptpubkey, tx, input_index, amount=amountcommitment, flags=(SCRIPT_VERIFY_P2SH, ))
def check_sign(self, blinded_tx: CTransaction, signed_tx: CTransaction, bundle: Dict[str, Any]) -> None: tx_to_sign = blinded_tx.to_mutable() for n, vin in enumerate(tx_to_sign.vin): utxo = bundle['vin_utxo'][n] amount = -1 if utxo['amount'] == -1 else coins_to_satoshi( utxo['amount']) scriptPubKey = CScript(x(utxo['scriptPubKey'])) a = CCoinAddress(utxo['address']) if 'privkey' in utxo: privkey = CCoinKey(utxo['privkey']) assert isinstance(a, P2PKHCoinAddress),\ "only P2PKH is supported for single-sig" assert a == P2PKHElementsAddress.from_pubkey(privkey.pub) assert scriptPubKey == a.to_scriptPubKey() sighash = SignatureHash(scriptPubKey, tx_to_sign, n, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_BASE) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) tx_to_sign.vin[n].scriptSig = CScript( [CScript(sig), CScript(privkey.pub)]) else: pk_list = [CCoinKey(pk) for pk in utxo['privkey_list']] redeem_script_data = [utxo['num_p2sh_participants']] redeem_script_data.extend([pk.pub for pk in pk_list]) redeem_script_data.extend([len(pk_list), OP_CHECKMULTISIG]) redeem_script = CScript(redeem_script_data) assert isinstance(a, P2SHCoinAddress),\ "only P2SH is supported for multi-sig." assert scriptPubKey == redeem_script.to_p2sh_scriptPubKey() assert a == P2SHElementsAddress.from_scriptPubKey( redeem_script.to_p2sh_scriptPubKey()) sighash = SignatureHash(redeem_script, tx_to_sign, n, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_BASE) sigs = [ pk.sign(sighash) + bytes([SIGHASH_ALL]) for pk in pk_list ] tx_to_sign.vin[n].scriptSig = CScript([b''] + sigs + [redeem_script]) VerifyScript(tx_to_sign.vin[n].scriptSig, scriptPubKey, tx_to_sign, n, amount=amount) self.assertEqual(tx_to_sign.serialize(), signed_tx.serialize())
def verify_tx_input(tx, i, scriptSig, scriptPubKey, amount=None, witness=None): flags = set([SCRIPT_VERIFY_STRICTENC]) if witness: # https://github.com/Simplexum/python-bitcointx/blob/648ad8f45ff853bf9923c6498bfa0648b3d7bcbd/bitcointx/core/scripteval.py#L1250-L1252 flags.add(SCRIPT_VERIFY_P2SH) flags.add(SCRIPT_VERIFY_WITNESS) try: VerifyScript(scriptSig, scriptPubKey, tx, i, flags=flags, amount=amount, witness=witness) except ValidationError as e: return False return True
def test_tx_invalid(self): for prevouts, tx, enforceP2SH in load_test_vectors('tx_invalid.json'): try: CheckTransaction(tx) except CheckTransactionError: continue with self.assertRaises(ValidationError): for i in range(len(tx.vin)): flags = set() if enforceP2SH: flags.add(SCRIPT_VERIFY_P2SH) VerifyScript(tx.vin[i].scriptSig, prevouts[tx.vin[i].prevout], tx, i, flags=flags)
def test_tx_valid(self): for prevouts, tx, enforceP2SH in load_test_vectors('tx_valid.json'): try: CheckTransaction(tx) except CheckTransactionError: self.fail('tx failed CheckTransaction(): ' \ + str((prevouts, b2x(tx.serialize()), enforceP2SH))) continue for i in range(len(tx.vin)): flags = set() if enforceP2SH: flags.add(SCRIPT_VERIFY_P2SH) VerifyScript(tx.vin[i].scriptSig, prevouts[tx.vin[i].prevout], tx, i, flags=flags)
def verify_tx_input(tx, i, scriptSig, scriptPubKey, amount=None, witness=None, native=False): flags = set([SCRIPT_VERIFY_STRICTENC]) if witness: flags.add(SCRIPT_VERIFY_P2SH) if native: flags.add(SCRIPT_VERIFY_WITNESS) try: VerifyScript(scriptSig, scriptPubKey, tx, i, flags=flags, amount=amount, witness=witness) except ValidationError as e: return False return True
def T(required: int, total: int, alt_total: Optional[int] = None) -> None: amount = 10000 keys = [ CKey.from_secret_bytes(os.urandom(32)) for _ in range(total) ] pubkeys = [k.pub for k in keys] if alt_total is not None: total = alt_total # for assertRaises checks redeem_script = standard_multisig_redeem_script(total=total, required=required, pubkeys=pubkeys) # Test with P2SH scriptPubKey = redeem_script.to_p2sh_scriptPubKey() (_, tx) = self.create_test_txs(CScript(), scriptPubKey, CScriptWitness([]), amount) tx = tx.to_mutable() sighash = redeem_script.sighash(tx, 0, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_BASE) sigs = [ k.sign(sighash) + bytes([SIGHASH_ALL]) for k in keys[:required] ] tx.vin[0].scriptSig = CScript( standard_multisig_witness_stack(sigs, redeem_script)) VerifyScript(tx.vin[0].scriptSig, scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH, )) # Test with P2WSH scriptPubKey = redeem_script.to_p2wsh_scriptPubKey() (_, tx) = self.create_test_txs(CScript(), scriptPubKey, CScriptWitness([]), amount) tx = tx.to_mutable() sighash = redeem_script.sighash(tx, 0, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) sigs = [ k.sign(sighash) + bytes([SIGHASH_ALL]) for k in keys[:required] ] witness_stack = standard_multisig_witness_stack( sigs, redeem_script) tx.vin[0].scriptSig = CScript([]) tx.wit.vtxinwit[0] = CTxInWitness( CScriptWitness(witness_stack)).to_mutable() VerifyScript(tx.vin[0].scriptSig, scriptPubKey, tx, 0, flags=(SCRIPT_VERIFY_WITNESS, SCRIPT_VERIFY_P2SH), amount=amount, witness=tx.wit.vtxinwit[0].scriptWitness) # Test with P2SH_P2WSH scriptPubKey = redeem_script.to_p2wsh_scriptPubKey() (_, tx) = self.create_test_txs(CScript(), scriptPubKey, CScriptWitness([]), amount) tx = tx.to_mutable() sighash = redeem_script.sighash(tx, 0, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) sigs = [ k.sign(sighash) + bytes([SIGHASH_ALL]) for k in keys[:required] ] witness_stack = standard_multisig_witness_stack( sigs, redeem_script) tx.vin[0].scriptSig = CScript([scriptPubKey]) tx.wit.vtxinwit[0] = CTxInWitness( CScriptWitness(witness_stack)).to_mutable() VerifyScript(tx.vin[0].scriptSig, scriptPubKey.to_p2sh_scriptPubKey(), tx, 0, flags=(SCRIPT_VERIFY_WITNESS, SCRIPT_VERIFY_P2SH), amount=amount, witness=tx.wit.vtxinwit[0].scriptWitness)
txin_scriptPubKey = \ P2PKHBitcoinAddress.from_pubkey(seckey.pub).to_scriptPubKey() # Create the txout. This time we create the scriptPubKey from a Bitcoin # address. txout = CMutableTxOut( 0.001 * COIN, CBitcoinAddress('1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8').to_scriptPubKey()) # Create the unsigned transaction. tx = CMutableTransaction([txin], [txout]) # Calculate the signature hash for that transaction. sighash = SignatureHash(txin_scriptPubKey, tx, 0, SIGHASH_ALL) # Now sign it. We have to append the type of signature we want to the end, in # this case the usual SIGHASH_ALL. sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) # Set the scriptSig of our transaction input appropriately. txin.scriptSig = CScript([sig, seckey.pub]) # Verify the signature worked. This calls EvalScript() and actually executes # the opcodes in the scripts to see if everything worked out. If it doesn't an # exception will be raised. VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0) # Done! Print the transaction to standard output with the bytes-to-hex # function. print(b2x(tx.serialize()))
def sign(tx, i, priv, hashcode=SIGHASH_ALL, amount=None, native=False): """ Given a transaction tx of type CMutableTransaction, an input index i, and a raw privkey in bytes, updates the CMutableTransaction to contain the newly appended signature. Only four scriptPubKey types supported: p2pkh, p2wpkh, p2sh-p2wpkh, p2wsh. Note that signing multisig must be done outside this function, using the wrapped library. If native is not the default (False), and if native != "p2wpkh", then native must be a CScript object containing the redeemscript needed to sign. Returns: (signature, "signing succeeded") or: (None, errormsg) in case of failure """ # script verification flags flags = set([SCRIPT_VERIFY_STRICTENC]) def return_err(e): return None, "Error in signing: " + repr(e) assert isinstance(tx, CMutableTransaction) pub = privkey_to_pubkey(priv) if not amount: # p2pkh only supported here: input_scriptPubKey = pubkey_to_p2pkh_script(pub) sighash = SignatureHash(input_scriptPubKey, tx, i, hashcode) try: sig = ecdsa_raw_sign(sighash, priv, rawmsg=True) + bytes( [hashcode]) except Exception as e: return return_err(e) tx.vin[i].scriptSig = CScript([sig, pub]) # Verify the signature worked. try: VerifyScript(tx.vin[i].scriptSig, input_scriptPubKey, tx, i, flags=flags) except Exception as e: return return_err(e) return sig, "signing succeeded" else: # segwit case; we currently support p2wpkh native or under p2sh. # https://github.com/Simplexum/python-bitcointx/blob/648ad8f45ff853bf9923c6498bfa0648b3d7bcbd/bitcointx/core/scripteval.py#L1250-L1252 flags.add(SCRIPT_VERIFY_P2SH) if native and native != "p2wpkh": scriptCode = native input_scriptPubKey = redeem_script_to_p2wsh_script(native) else: # this covers both p2wpkh and p2sh-p2wpkh case: input_scriptPubKey = pubkey_to_p2wpkh_script(pub) # only created for convenience access to scriptCode: input_address = P2WPKHCoinAddress.from_scriptPubKey( input_scriptPubKey) # function name is misleading here; redeemScript only applies to p2sh. scriptCode = input_address.to_redeemScript() sighash = SignatureHash(scriptCode, tx, i, hashcode, amount=amount, sigversion=SIGVERSION_WITNESS_V0) try: sig = ecdsa_raw_sign(sighash, priv, rawmsg=True) + bytes( [hashcode]) except Exception as e: return return_err(e) if native: flags.add(SCRIPT_VERIFY_WITNESS) else: tx.vin[i].scriptSig = CScript([input_scriptPubKey]) if native and native != "p2wpkh": witness = [sig, scriptCode] else: witness = [sig, pub] ctxwitness = CTxInWitness(CScriptWitness(witness)) tx.wit.vtxinwit[i] = ctxwitness # Verify the signature worked. try: VerifyScript(tx.vin[i].scriptSig, input_scriptPubKey, tx, i, flags=flags, amount=amount, witness=tx.wit.vtxinwit[i].scriptWitness) except ValidationError as e: return return_err(e) return sig, "signing succeeded"
[OP_DUP, OP_HASH160, Hash160(seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG]) # Create the txout. This time we create the scriptPubKey from a Bitcoin # address. txout = CMutableTxOut( 0.001 * COIN, CBitcoinAddress('1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8').to_scriptPubKey()) # Create the unsigned transaction. tx = CMutableTransaction([txin], [txout]) # Calculate the signature hash for that transaction. sighash = SignatureHash(txin_scriptPubKey, tx, 0, SIGHASH_ALL) # Now sign it. We have to append the type of signature we want to the end, in # this case the usual SIGHASH_ALL. sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) # Set the scriptSig of our transaction input appropriately. txin.scriptSig = CScript([sig, seckey.pub]) # Verify the signature worked. This calls EvalScript() and actually executes # the opcodes in the scripts to see if everything worked out. If it doesn't an # exception will be raised. VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH, )) # Done! Print the transaction to standard output with the bytes-to-hex # function. print(b2x(tx.serialize()))
script_for_sighash = CScript( [OP_DUP, OP_HASH160, Hash160(key.pub), OP_EQUALVERIFY, OP_CHECKSIG]) sighash = script_for_sighash.sighash(tx, input_index, SIGHASH_ALL, amount=utxo.nValue, sigversion=SIGVERSION_WITNESS_V0) sig = key.sign(sighash) + bytes([SIGHASH_ALL]) inner_scriptPubKey = CScript([0, Hash160(key.pub)]) tx.vin[input_index].scriptSig = CScript([inner_scriptPubKey]) tx.wit.vtxinwit[input_index] = CTxInWitness( CScriptWitness([CScript(sig), CScript(key.pub)])) scriptpubkey = inner_scriptPubKey.to_p2sh_scriptPubKey() VerifyScript(tx.vin[input_index].scriptSig, scriptpubkey, tx, input_index, amount=utxo.nValue, flags=(SCRIPT_VERIFY_P2SH, )) sys.stderr.write("Successfully signed\n") # Print out blinded and signed transaction, hex-encoded. print(b2x(tx.serialize()))