Learning LibraryBlockchain & DeFi LibraryTeens

Transactions: signed transfers you can verify

A transaction is a signed instruction: move this from here to there. The signature is what makes it trustworthy — anyone can verify it, but only the owner could have created it.

The big idea

A transaction records a transfer and carries a signature made from the sender's private key, which anyone can verify by recomputing it.

See it in code

1The basics

A transaction is really just a record of a transfer: who's sending, who's receiving, and how much. Here it is as a dictionary — the raw shape before any signing:

python
# A transaction is a record: move an amount from one owner to another.
tx = {"from": "Alice", "to": "Bob", "amount": 5}
print("Transaction:", tx["from"], "->", tx["to"], tx["amount"])
Run it — the bare transfer, three fields:
Transaction: Alice -> Bob 5

On its own this record proves nothing — anyone could type it. What makes it trustworthy is a signature that only Alice could create.

2A step further

So Alice signs it: hash her private key together with every field of the transfer. The result is a signature bound to this exact transaction:

python
import hashlib

def h(text):
    return hashlib.sha256(text.encode()).hexdigest()[:12]

private_key = "alice-secret"
tx = {"from": "Alice", "to": "Bob", "amount": 5}

# sign: hash the secret key together with every field
tx["signature"] = h(private_key + tx["from"] + tx["to"] + str(tx["amount"]))
print("Signature:", tx["signature"])
Run it — a signature computed from the key and all three fields:
Signature: 113bcdeec6dc

Because the signature folds in from, to, and amount, it commits to the whole transfer. Now anyone should be able to check it — that's the final step.

3In our world

A verifier recomputes the signature the exact same way and checks it matches — a green light without ever seeing the secret:

python
import hashlib

def h(text):
    return hashlib.sha256(text.encode()).hexdigest()[:12]

private_key = "alice-secret"

def sign(tx, key):
    return h(key + tx["from"] + tx["to"] + str(tx["amount"]))

tx = {"from": "Alice", "to": "Bob", "amount": 5}
tx["signature"] = sign(tx, private_key)

# a verifier recomputes the signature the same way
valid = tx["signature"] == sign(tx, private_key)
print("Transaction:", tx["from"], "->", tx["to"], tx["amount"])
print("Signature:", tx["signature"])
print("Valid?", valid)
Run it — a signed transfer that verifies as authentic:
Transaction: Alice -> Bob 5
Signature: 113bcdeec6dc
Valid? True

The signature depends on every field — sender, recipient, amount. Tamper with any of them and the recomputed signature won't match, so valid flips to False. That's how a network rejects forged or altered transfers before they ever reach a block.

The same idea, everywhere

Signing data to guarantee it wasn't altered is everywhere: signed API requests, tamper-proof receipts, verified email (DKIM), software you install. The recipe — hash the important fields with a secret, verify by recomputing — is a reusable pattern for authenticity.

Try it yourself

Change the amount after signing and re-check valid — watch it fail, proving tampering is caught. Then bundle several transactions into a list, the way a real block holds many transfers.

The common mistake

Signing only part of the data. If the signature doesn't cover the amount, an attacker could change 5 to 500 and it would still 'verify'. Always sign every field that matters — the signature must commit to the whole transaction.

What it unlocks

Transactions build on wallets and keys and hashing, get recorded in blocks and chains, and use dictionaries.