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, ))
예제 #2
0
    def test_immutable_tx_creation_with_mutable_parts_specified(self):
        tx = CTransaction(
            vin=[CMutableTxIn(prevout=COutPoint(hash=b'a' * 32, n=0))],
            vout=[CMutableTxOut(nValue=1)],
            witness=CMutableTxWitness(
                [CMutableTxInWitness(CScriptWitness([CScript([0])]))]))

        def check_immutable_parts(tx):
            self.assertTrue(tx.vin[0].is_immutable())
            self.assertTrue(tx.vin[0].is_immutable())
            self.assertTrue(tx.vout[0].is_immutable())
            self.assertTrue(tx.wit.is_immutable())
            self.assertTrue(tx.wit.vtxinwit[0].is_immutable())

        check_immutable_parts(tx)

        # Test that if we deserialize with CTransaction,
        # all the parts are immutable
        tx = CTransaction.deserialize(tx.serialize())
        check_immutable_parts(tx)

        # Test some parts separately, because when created via
        # CMutableTransaction instantiation, they are created with from_*
        # methods, and not directly

        txin = CTxIn(prevout=CMutableOutPoint(hash=b'a' * 32, n=0))
        self.assertTrue(txin.prevout.is_immutable())

        wit = CTxWitness((CMutableTxInWitness(), ))
        self.assertTrue(wit.vtxinwit[0].is_immutable())
예제 #3
0
def VerifySignature(txFrom, txTo, inIdx):
    """Verify a scriptSig signature can spend a txout

    Verifies that the scriptSig in txTo.vin[inIdx] is a valid scriptSig for the
    corresponding COutPoint in transaction txFrom.
    """
    if inIdx < 0:
        raise VerifySignatureError("inIdx negative")
    if inIdx >= len(txTo.vin):
        raise VerifySignatureError("inIdx >= len(txTo.vin)")
    txin = txTo.vin[inIdx]

    if txin.prevout.n < 0:
        raise VerifySignatureError("txin prevout.n negative")
    if txin.prevout.n >= len(txFrom.vout):
        raise VerifySignatureError("txin prevout.n >= len(txFrom.vout)")
    txout = txFrom.vout[txin.prevout.n]

    if txin.prevout.hash != txFrom.GetTxid():
        raise VerifySignatureError("prevout hash does not match txFrom")

    witness = None
    if txTo.wit:
        witness = txTo.wit.vtxinwit[inIdx].scriptWitness

    VerifyScript(txin.scriptSig,
                 txout.scriptPubKey,
                 txTo,
                 inIdx,
                 amount=txout.nValue,
                 witness=witness or CScriptWitness([]))
예제 #4
0
    def test_repr(self):
        def T(txout, expected):
            actual = repr(txout)
            self.assertEqual(actual, expected)

        T(CMutableTxInWitness(CScriptWitness([1])),
          "CBitcoinMutableTxInWitness(CScriptWitness([x('01')]))")
예제 #5
0
    def test_repr(self) -> None:
        def T(txinwitness: CTxInWitness, expected: str) -> None:
            actual = repr(txinwitness)
            self.assertEqual(actual, expected)

        T(CMutableTxInWitness(CScriptWitness([1])),
          "CBitcoinMutableTxInWitness(CScriptWitness([x('01')]))")
예제 #6
0
def generate_transaction(amount, txin_txid, txin_vout, txout_addr,
                         redeem_list):
    txin = CMutableTxIn(COutPoint(txin_txid, txin_vout))
    txout = CMutableTxOut(amount * COIN, txout_addr.addr.to_scriptPubKey())
    witness_script = CScriptWitness(tuple(redeem_list))
    witness = CTxWitness(tuple([CTxInWitness(witness_script)]))
    tx = CMutableTransaction(vin=[txin], vout=[txout], witness=witness)
    return tx
예제 #7
0
def create_btc_spend_tx(dst_addr,
                        txid,
                        vout_n,
                        btc_contract,
                        spend_key=None,
                        branch_condition=True):

    # In real application, the fees should not be static, of course
    out_amount = (coins_to_satoshi(pre_agreed_amount) -
                  coins_to_satoshi(fixed_fee_amount))

    tx = CMutableTransaction(
        vin=[CTxIn(prevout=COutPoint(hash=lx(txid), n=vout_n))],
        vout=[
            CTxOut(nValue=out_amount, scriptPubKey=dst_addr.to_scriptPubKey())
        ])

    if branch_condition is True:
        cond = b'\x01'
    else:
        tx.vin[0].nSequence = bitcoin_contract_timeout
        cond = b''

    in_amount = coins_to_satoshi(pre_agreed_amount)
    # We used P2WSHCoinAddress to create the address that we sent bitcoin to,
    # so we know that we need to use SIGVERSION_WITNESS_V0
    sighash = btc_contract.sighash(tx,
                                   0,
                                   SIGHASH_ALL,
                                   amount=in_amount,
                                   sigversion=SIGVERSION_WITNESS_V0)

    spend_sig = spend_key.sign(sighash) + bytes([SIGHASH_ALL])

    # This is script witness, not script. The condition for OP_IF
    # in our script is directly encoded as data in the witness.
    # We cannot use OP_TRUE/OP_FALSE here. We use DATA guard is to ensure that.
    witness = CScriptWitness([spend_sig, DATA(cond), btc_contract])

    # empty scriptSig, because segwit
    tx.vin[0].scriptSig = CBitcoinScript([])
    # all data to check the spend conditions is in the witness
    tx.wit.vtxinwit[0] = CTxInWitness(witness)

    # Cannot use VerifyScript for now,
    # because it does not support CHECKSEQUENCEVERIFY yet
    #
    # from_addr = P2WSHBitcoinAddress.from_redeemScript(btc_contract)
    # VerifyScript(tx.vin[0].scriptSig, from_addr.to_scriptPubKey(),
    #              tx, 0, amount=in_amount)

    return tx
예제 #8
0
def sign_transaction(tx, privkeys):
    witness_list = list(tx.witness.vtxinwit[0].scriptWitness.stack)
    sighash = SignatureHash(tx.witness, tx, 0, SIGHASH_ALL)
    signatures = []
    for privkey in privkeys:
        privkey = CBitcoinSecret.from_bytes(privkey)
    for privkey in privkeys:
        signatures.append(privkey.sign(sighash) + bytes([SIGHASH_ALL]))
    counter = 0
    for signature in signatures:
        witness_list.insert(counter, signature)
        counter = counter + 1
    witness_script = CScriptWitness(tuple(witness_list))
    tx.witness = CTxWitness(tuple([CTxInWitness(witness_script)]))
    return tx.serialize()
예제 #9
0
def VerifyScript(
        scriptSig,
        scriptPubKey,
        txTo,
        inIdx,  # noqa
        flags=None,
        amount=0,
        witness=None):
    """Verify a scriptSig satisfies a scriptPubKey

    scriptSig    - Signature

    scriptPubKey - PubKey

    txTo         - Spending transaction

    inIdx        - Index of the transaction input containing scriptSig

    Raises a ValidationError subclass if the validation fails.
    """

    assert isinstance(scriptSig, CScript)
    assert type(scriptSig) == type(scriptPubKey),\
        "scriptSig and scriptPubKey must be of the same script class"

    script_class = scriptSig.__class__

    if flags is None:
        flags = STANDARD_SCRIPT_VERIFY_FLAGS - UNHANDLED_SCRIPT_VERIFY_FLAGS
    else:
        flags = set(flags)  # might be passed as tuple

    if flags & UNHANDLED_SCRIPT_VERIFY_FLAGS:
        raise VerifyScriptError(
            "some of the flags cannot be handled by current code: {}".format(
                script_verify_flags_to_string(
                    flags & UNHANDLED_SCRIPT_VERIFY_FLAGS)))

    stack = []
    EvalScript(stack, scriptSig, txTo, inIdx, flags=flags)
    if SCRIPT_VERIFY_P2SH in flags:
        stackCopy = list(stack)
    EvalScript(stack, scriptPubKey, txTo, inIdx, flags=flags)
    if len(stack) == 0:
        raise VerifyScriptError("scriptPubKey left an empty stack")
    if not _CastToBool(stack[-1]):
        raise VerifyScriptError("scriptPubKey returned false")

    hadWitness = False
    if witness is None:
        witness = CScriptWitness([])

    if SCRIPT_VERIFY_WITNESS in flags and scriptPubKey.is_witness_scriptpubkey(
    ):
        hadWitness = True

        if scriptSig:
            raise VerifyScriptError("scriptSig is not empty")

        VerifyWitnessProgram(witness,
                             scriptPubKey.witness_version(),
                             scriptPubKey.witness_program(),
                             txTo,
                             inIdx,
                             flags=flags,
                             amount=amount,
                             script_class=script_class)

        # Bypass the cleanstack check at the end. The actual stack is obviously not clean
        # for witness programs.
        stack = stack[:1]

    # Additional validation for spend-to-script-hash transactions
    if SCRIPT_VERIFY_P2SH in flags and scriptPubKey.is_p2sh():
        if not scriptSig.is_push_only():
            raise VerifyScriptError("P2SH scriptSig not is_push_only()")

        # restore stack
        stack = stackCopy

        # stack cannot be empty here, because if it was the
        # P2SH  HASH <> EQUAL  scriptPubKey would be evaluated with
        # an empty stack and the EvalScript above would return false.
        assert len(stack)

        pubKey2 = script_class(stack.pop())

        EvalScript(stack, pubKey2, txTo, inIdx, flags=flags)

        if not len(stack):
            raise VerifyScriptError(
                "P2SH inner scriptPubKey left an empty stack")

        if not _CastToBool(stack[-1]):
            raise VerifyScriptError("P2SH inner scriptPubKey returned false")

        # P2SH witness program
        if SCRIPT_VERIFY_WITNESS in flags and pubKey2.is_witness_scriptpubkey(
        ):
            hadWitness = True

            if scriptSig != script_class([pubKey2]):
                raise VerifyScriptError(
                    "scriptSig is not exactly a single push of the redeemScript"
                )

            VerifyWitnessProgram(witness,
                                 pubKey2.witness_version(),
                                 pubKey2.witness_program(),
                                 txTo,
                                 inIdx,
                                 flags=flags,
                                 amount=amount,
                                 script_class=script_class)

            # Bypass the cleanstack check at the end. The actual stack is obviously not clean
            # for witness programs.
            stack = stack[:1]

    if SCRIPT_VERIFY_CLEANSTACK in flags:
        assert SCRIPT_VERIFY_P2SH in flags

        if len(stack) == 0:
            raise VerifyScriptError("scriptPubKey left an empty stack")
        elif len(stack) != 1:
            raise VerifyScriptError("scriptPubKey left extra items on stack")

    if SCRIPT_VERIFY_WITNESS in flags:
        # We can't check for correct unexpected witness data if P2SH was off, so require
        # that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be
        # possible, which is not a softfork.
        assert SCRIPT_VERIFY_P2SH in flags, "SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH"

        if not hadWitness and witness:
            raise VerifyScriptError("Unexpected witness")
예제 #10
0
    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()))
예제 #11
0
    script_for_sighash = CElementsScript(
        [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] = CElementsTxInWitness(
        CScriptWitness([CScript(sig), CScript(key.pub)])).to_mutable()
    scriptpubkey = inner_scriptPubKey.to_p2sh_scriptPubKey()

    # VerifyScript does not know about confidential values.
    # Somewhen we might have VerifyElementsScript.
    # but for now, ignore the type error.
    VerifyScript(
        tx.vin[input_index].scriptSig,
        scriptpubkey,
        tx,
        input_index,
        amount=utxo.nValue,  # type: ignore
        flags=(SCRIPT_VERIFY_P2SH, ))

    sys.stderr.write("Successfully signed\n")
예제 #12
0
 def test_immutable(self):
     wit = CTxInWitness(CScriptWitness([1]))
     with self.assertRaises(AttributeError):
         wit.scriptWitness = CScriptWitness()
예제 #13
0
 def test_clone(self):
     wit = CMutableTxWitness([CTxInWitness(CScriptWitness([1]))])
     self.assertEqual(wit.serialize(), wit.clone().serialize())
예제 #14
0
 def test_immutable(self):
     wit = CTxWitness([CTxInWitness(CScriptWitness([1]))])
     with self.assertRaises(AttributeError):
         wit.vtxinwit = []
예제 #15
0
    def _create_transaction(self, sources: List[Address],
                            recipients: List[Address], values, n_locktime,
                            n_sequence):
        # save cospends
        self.cospends.union_all([str(x.address) for x in sources])

        if not values:
            values = [recipient.value for recipient in recipients]
        tx_ins = [
            CMutableTxIn(COutPoint(source.txid, source.vout),
                         nSequence=n_sequence) for source in sources
        ]
        tx_outs = []

        cnt = 0
        for recipient, value in zip(recipients, values):
            if value == 0:
                self.log.warning("Creating output with 0 BTC")
            recipient.vout = cnt

            tx_outs.append(
                CMutableTxOut(
                    Coin(value).satoshi(),
                    recipient.address.to_scriptPubKey()))
            cnt += 1

        tx = CMutableTransaction(tx_ins, tx_outs, nLockTime=n_locktime)

        in_idx = 0
        witnesses = []
        for txin, source in zip(tx_ins, sources):
            key = source.key

            if source.type == 'p2pkh':
                script = source.address.to_redeemScript()
            elif source.type == 'p2sh':
                script = CScript([key.pub, OP_CHECKSIG])
            elif source.type == 'p2wpkh':
                script = source.address.to_redeemScript()
            elif source.type == 'p2wsh':
                script = source.witness_program
            else:
                raise UnsupportedAddressTypeError()

            # Create signature
            amount = Coin(source.value).satoshi()
            sig = self._sign(script, tx, in_idx, amount, key, source.type)

            # Add signature to input or witness
            if source.type == 'p2pkh':
                txin.scriptSig = CScript([sig, key.pub])
                witnesses.append(CTxInWitness())
            elif source.type == 'p2sh':
                txin.scriptSig = CScript([sig, script])
                witnesses.append(CTxInWitness())
            elif source.type == 'p2wpkh':
                txin.scriptSig = CScript()
                witnesses.append(CTxInWitness(CScriptWitness([sig, key.pub])))
            elif source.type == 'p2wsh':
                txin.scriptSig = CScript()
                witnesses.append(CTxInWitness(CScriptWitness([sig, script])))
            in_idx += 1

        tx.wit = CTxWitness(witnesses)
        return tx
예제 #16
0
        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)
예제 #17
0
def load_test_vectors(
    name: str,
    skip_fixme: bool = True
) -> Iterator[Tuple[CScript, CScript, CScriptWitness, int,
                    Set[ScriptVerifyFlag_Type], str, str, str]]:
    logging.basicConfig()
    log = logging.getLogger("Test_EvalScript")
    with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd:
        fixme_comment = None
        num_skipped = 0
        for test_case in json.load(fd):
            if len(test_case) == 1:
                continue  # comment

            if len(test_case) == 2:
                if not skip_fixme:
                    assert test_case[0].startswith('FIXME'),\
                        "we do not expect anything other than FIXME* here"
                    continue
                if test_case[0] == 'FIXME':
                    fixme_comment = test_case[1]
                    continue
                if test_case[0] == 'FIXME_END':
                    log.warning("SKIPPED {} tests: {}".format(
                        num_skipped, fixme_comment))
                    fixme_comment = None
                    num_skipped = 0
                    continue

            if fixme_comment:
                num_skipped += 1
                continue

            to_unpack = test_case.copy()

            witness = CScriptWitness()
            nValue = 0
            if isinstance(to_unpack[0], list):
                wdata = to_unpack.pop(0)
                stack = [CScript(x(d)) for d in wdata[:-1]]
                witness = CScriptWitness(stack)
                nValue = int(round(wdata[-1] * 1e8))

            if len(to_unpack) == 4:
                to_unpack.append('')  # add missing comment

            assert len(
                to_unpack) == 5, "unexpected test data format: {}".format(
                    to_unpack)

            scriptSig_str, scriptPubKey_str, flags, expected_result, comment = to_unpack

            scriptSig = parse_script(scriptSig_str)
            scriptPubKey = parse_script(scriptPubKey_str)

            flag_set = set()
            for flag in flags.split(','):
                if flag == '' or flag == 'NONE':
                    pass

                else:
                    try:
                        flag = SCRIPT_VERIFY_FLAGS_BY_NAME[flag]
                    except IndexError:
                        raise Exception('Unknown script verify flag %r' % flag)

                    flag_set.add(flag)

            yield (scriptSig, scriptPubKey, witness, nValue, flag_set,
                   expected_result, comment, test_case)

        if fixme_comment is not None:
            raise Exception('Unbalanced FIXME blocks in test data')
예제 #18
0
 def test_clone(self):
     txinwit = CMutableTxInWitness(CScriptWitness([1]))
     self.assertEqual(txinwit.serialize(), txinwit.clone().serialize())