-1

I am still a beginner in python and suddenly, I gave myself a project as a guideline and allowing me to improve. I opted for the creation of a wallet package, in order to be able to integrate it into another project, but I am stuck with the ecdsa library to generate the signature of a transaction. here is the error I get:

Traceback (most recent call last): File "Programs\Python\Python311\Lib\site-packages\ecdsa\keys.py", line 170, in from_public_point self.pubkey = ecdsa.Public_key( ^^^^^^^^^^^^^^^^^ File "Programs\Python\Python311\Lib\site-packages\ecdsa\ecdsa.py", line 155, in init raise InvalidPointError("Point does not lay on the curve") ecdsa.ecdsa.InvalidPointError: Point does not lay on the curve

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "xxx-wallet\index.py", line 33, in print("valid tx: ", validate_transaction(_tx, a_unspent_tx_outs)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:neon-wallet\neon_wallet\transaction\transactions.py", line 56, in validate_transaction [ File "C:neon-wallet\neon_wallet\transaction\transactions.py", line 57, in validate_tx_in(txIn, transaction, a_unspent_tx_outs) File "C:neon-wallet\neon_wallet\transaction\transactions.py", line 110, in validate_tx_in key = ecdsa.VerifyingKey.from_string( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:Programs\Python\Python311\Lib\site-packages\ecdsa\keys.py", line 281, in from_string return cls.from_public_point(point, curve, hashfunc, validate_point) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C: Programs\Python\Python311\Lib\site-packages\ecdsa\keys.py", line 174, in from_public_point raise MalformedPointError("Point does not lay on the curve") ecdsa.errors.MalformedPointError: Point does not lay on the curve

I tried to create one that validates each transaction, for this I need to validate the list of incoming transactions, but this function generates a problem with the ECDSA python library

# Define a function that commits a transaction based on unspent
# transaction outputs
def validate_transaction(
    transaction: Transaction, a_unspent_tx_outs: List[UnspentTxOut]
) -> bool:
    "validate transaction"
    # Check if transaction structure is valid
    if not is_valid_transaction_structure(transaction):
        return False

    # Check if transaction id matches
    # to the hash of the transaction contents
    if get_transaction_id(transaction) != transaction.id:
        print("invalid tx id: " + transaction.id)
        return False

    # Check if all transaction inputs are valid
    has_valid_tx_ins = all(
        [
            validate_tx_in(txIn, transaction, a_unspent_tx_outs)
            for txIn in transaction.tx_ins
        ]
    )

    if not has_valid_tx_ins:
        print("some of the txIns are invalid in tx: " + transaction.id)
        return False

    # Calculate sum of amounts of transaction inputs
    t_tx = [get_tx_in_amount(txIn, a_unspent_tx_outs) for txIn in transaction.tx_ins]
    total_tx_in_values = sum(t_tx)

    # Calculate sum of transaction output amounts
    total_tx_out_values = sum([txOut.amount for txOut in transaction.tx_outs])

    # Check if sums are equal
    if total_tx_out_values != total_tx_in_values:
        _id = transaction.id
        print(f"totalTxOutValues !== totalTxInValues in tx: {_id}")
        return False

    return True


# Define a function that validates a transaction input against
# unspent transaction outputs
def validate_tx_in(
    tx_in: TxIn,
    transaction: Transaction,
    a_unspent_tx_outs: List[UnspentTxOut],
) -> bool:
    """validate transaction in"""
    # Find the unspent transaction output that
    # matches transaction input
    referenced_uTx_out = next(
        (
            uTxO
            for uTxO in a_unspent_tx_outs
            if (uTxO.tx_out_id == tx_in.tx_out_id)
            and (uTxO.tx_out_index == tx_in.tx_out_index)
        ),
        None,
    )
    if referenced_uTx_out is None:
        print("referenced txOut not found: " + str(tx_in))
        return False

    # Extract address from unspent transaction output
    address = referenced_uTx_out.address
    print('ref address', address)

    # Create an ECDSA public key from the address
    key = ecdsa.VerifyingKey.from_string(
        bytes.fromhex(address),
        curve=ecdsa.SECP256k1,
    )

    # Check the signature of the transaction entry with the
    # public key and transaction id
    valid_signature = key.verify(
        bytes.fromhex(tx_in.signature), bytes.fromhex(transaction.id)
    )
    if not valid_signature:
        tx_s = tx_in.signature
        tx_id = transaction.id
        ref = referenced_uTx_out.address
        print(f"invalid txIn signature: {tx_s} txId: {tx_id} address: {ref}")
        return False

    return True
"""test index"""
from neon_wallet.transaction.transaction import Transaction
from neon_wallet.transaction.transactions import (
    get_transaction_id,
    validate_transaction,
)
from neon_wallet.transaction.tx_in import TxIn
from neon_wallet.transaction.tx_out import TxOut
from tests.transaction.helpers_tests import utxo1, utxo2, utxo3


_tx = Transaction(
    [
        TxIn("tx1", 0, "serges007"),
        TxIn("tx0", 1, "serges007"),
    ],
    [
        TxOut(
            "04b0bd634234abbbcc1ba1e986e884185c61cf43da82f5963a8c70171b1b200c006a8421997ac617d91d406e5fa52bbf4d16e2a069e6b9b668a3935dabaecbc403",
            50.0,
        ),
        TxOut(
            "04b0bd634234abbbdd1ba1e986e884185c61cf43da82f5963a8c70171b1b200c006a8421997ac617d91d406e5fa52bbf4d16e2a069e6b9b668a3935dabaecbc402",
            100.0,
        ),
    ],
)
a_unspent_tx_outs = [utxo1, utxo2, utxo3]
# Appeler la fonction à tester avec cet objet
TX_ID = get_transaction_id(_tx)
# Vérifier que le résultat est conforme à l'attendu
# print("id :", TX_ID)
print("valid tx: ", validate_transaction(_tx, a_unspent_tx_outs))

kaito shi
  • 18
  • 3
  • You don't say which of the thousands of blockchains or cryptocurrencies you are asking about, but I'll guess bitcoin because it's the most known. Some bitcoin outputs (TXOs) don't pay to a single address; for those that do, although a normal (P2PKH or P2WPKH) address is derived from a publickey, this is a one-way process and it is impossible to obtain the publickey from the address. Also some TXIs don't contain a signature and when they do it is not computed on the txid (either the old one or the new segwit one). Finally, total TXO values is almost always less than total TXI values due to fee. – dave_thompson_085 May 13 '23 at 23:32

1 Answers1

0

Hi thank you for your comment indeed, the problem was related to the private and public keys as well as the signature.to solve the problem I had to generate a private key with the ecdsa library like this:

import ecdsa
private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
public_key = private_key.get_verifying_key()

# Convert the public key to a hex string for the addressaddress = public_key.to_string().hex()

# Create an unspent exit belonging to this address
# with an arbitrary amount

unspent_tx_out = UnspentTxOut("1234", 0, address, 50)

# Create a list containing this unspent output
a_unspent_tx_outs = [unspent_tx_out]

# Create a transaction input that references this unspent output
# Create a transaction input that references this unspent output

tx_in = TxIn("1234", 0, "")

# Create a transaction input that references this unspent output
# Create a transaction input that references this unspent output

tx_2 = Transaction(
    [tx_in],
    [
        TxOut(
            "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a",
            50,
        )
    ],
)

# Sign the transaction entry with the private key and id of  transaction
tx_in.signature = private_key.sign(bytes.fromhex(tx_2.id)).hex()

result = validate_transaction(tx_2, a_unspent_tx_outs)

the result variable return True

kaito shi
  • 18
  • 3