Why and How Digital Signatures Work in Bitcoin

By Kurt Wuckert Jr.

Bitcoin Transactions as Data and Money

Bitcoin combines two big ideas: money and structured data. The coin is the part everyone talks about, but the real power comes from the way Bitcoin records events as data in a global, append-only log.

Every event, whether it is a payment, a KYC record, a supply chain update or something from an app, is written as a transaction. Transactions are grouped into blocks, which are timestamped bundles of events that happened in a certain window of time.

A Bitcoin transaction is a data structure with several fields, such as:

  • Version

  • nLockTime

  • Transaction Inputs

  • Transaction Outputs

For what we are doing here, the important pieces are the inputs and outputs.

Inputs, Outputs, and the Flow of Funds

A transaction can have many inputs and many outputs, each with an index. Conceptually:

  • Inputs point back to previous transactions and include an unlocking script that proves those earlier outputs can now be spent.

  • Outputs specify how much value is being assigned and include a locking script that sets the conditions for who can spend it next.

You can think of it like a bank transfer:

  • The “debited from” side is like the inputs.

  • The “credited to” side is like the outputs.

The difference is that inputs explicitly reference the earlier transaction where those funds were assigned. So if Bob pays Carol in transaction T2, the input of T2 references the output Bob received from Alice in transaction T1.

In the example:

  • T1: Alice “sends” 50 coins to Bob.

  • T2: Bob “sends” 49 coins to Carol.

  • T3: Carol “sends” 48 coins to Dave.

Technically, they are not pushing coins around. They are updating who controls which outputs. Ownership moves forward through the chain of transactions.

Each of them holds a private and public key pair, for example:

  • Alice: (k_prA, k_pubA)

  • Bob: (k_prB, k_pubB)

  • Carol: (k_prC, k_pubC)

  • Dave: (k_prD, k_pubD)

Those keys are what the scripts refer to.

Scripts: Locking and Unlocking

Both inputs and outputs carry a field called script. Script is a simple, stack based language that uses operands (data) and opcodes (operations).

  • The script in an output is called the locking script. It “locks” the value to specific conditions, usually tied to a public key or its hash.

  • The script in an input is called the unlocking script. It provides the data needed to satisfy that earlier locking script.

The key idea:

  • An input unlocks an output from a previous transaction.

  • An output locks value that may later be unlocked by a future transaction’s input.

In the Alice to Dave flow:

  • T1’s locking script locks value to Bob’s conditions.

  • T2’s unlocking script satisfies T1’s locking script, so Bob can spend those funds to Carol.

  • T2’s locking script then locks value to Carol.

  • T3’s unlocking script satisfies T2’s locking script, so Carol can move value to Dave.

Script Evaluation and Identity

You can think of a locking script as a puzzle and the unlocking script as the answer. If the puzzle is “5 3 SUB EQUAL,” the answer must be “2.” In Bitcoin Script it is expressed with opcodes and data rather than plain language, but the concept is the same.

When a transaction is broadcast, nodes evaluate scripts by:

  1. Taking the previous transaction’s locking script.

  2. Appending the new transaction’s unlocking script.

  3. Running the combined script.

If the result is True, the spend condition is satisfied and validation can continue. If it is False, the input is invalid.

This is where digital signatures and public keys come in. A common pattern is:

  • The locking script contains a public key hash or some function of a public key, which serves as the “identity” that will control that output.

  • The unlocking script supplies a public key and a signature built with the matching private key.

Because users can generate fresh key pairs as often as they like, they do not have to reuse the same public key. That makes it harder to track a person directly, which is where Bitcoin’s pseudonymity comes from.

Standard Transaction Templates (P2PKH)

Most transactions use standard script templates so that wallets and nodes can handle them simply and safely. The most common template is Pay to Public Key Hash (P2PKH).

In P2PKH:

  • Unlocking script (input):<Signature> <Public Key>

  • Locking script (output):OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

Here:

  • <Signature>, <Public Key>, and <Public Key Hash> are data values.

  • The other terms are opcodes that tell Script what to do.

OP_CHECKSIG is the crucial opcode for digital signatures. It takes the signature and public key, checks that they match the hashed transaction data, and returns True or False.

Keys and ECDSA in Bitcoin

Bitcoin uses the Elliptic Curve Digital Signature Algorithm (ECDSA) on the secp256k1 curve. The relationship between keys is:

Public key = Private key × Base Point

  • The private key is just a large random integer, 256 bits long.

  • The base point is a fixed point on the elliptic curve.

  • The public key is another point on that same curve, with x and y coordinates.

From the private key you can easily compute the public key, but going backwards from public key to private key is computationally infeasible.

Wallets handle this for users:

  • They generate private keys and usually encode them in Wallet Import Format (WIF) for storage.

  • They derive the public keys from those private keys.

Public keys can be stored in two formats:

  • Compressed: 33 bytes. First byte indicates whether y is odd or even, remaining 32 bytes are x.

  • Uncompressed: 65 bytes. First byte marks it as uncompressed, then 32 bytes x and 32 bytes y.

Wallet Practices: Fresh Keys and HD Wallets

Two important practices affect how keys are actually used.

Security and privacyWallets should generate a new key pair for each transaction that receives funds. Reusing the same key pair causes two problems:

  • If one private key is exposed, all outputs secured by that key are exposed.

  • If one public key appears in many outputs, blockchain analysis can easily link those outputs together.

UsabilityIf you created a brand new key pair for every use and stored them individually, you would have to back up your wallet constantly. To avoid that, modern wallets use Hierarchical Deterministic (HD) key schemes:

  • All keys are derived from a single seed.

  • The seed is often encoded as a list of words that is easier for humans to manage.

  • You backup the seed once and can regenerate the entire key hierarchy from it.

This keeps the security and privacy benefits while making backups practical.

How Signatures Live Inside Transactions

In Bitcoin transactions, signatures are always part of the scripts.

  • Inputs have a scriptSig or “Txin-script,” which usually carries the signature and public key.

  • Outputs have a scriptPubKey or “Txout-script,” which usually contains a public key or a public key hash.

A public key hash is:

RIPEMD-160(SHA-256(public key))

That hash is then typically encoded in Base58 to form a Bitcoin address, which is what users share instead of raw keys.

When nodes verify a transaction, they combine the unlocking and locking scripts and evaluate them. The signature itself is verified inside the script, with opcodes like OP_CHECKSIG using the included public key and the hashed transaction data.

Signature Format: DER and SIGHASH Flags

In ECDSA, a signature is a pair of integers (r, s). Bitcoin transactions wrap this pair in a specific format:

  • DER (Distinguished Encoding Rules) for serialization into binary.

  • A following SIGHASH byte that tells nodes what part of the transaction was signed.

DER packages the signature into a sequence that includes simple headers and length fields, then the r and s values as big endian integers. The main point is that it standardizes how signatures are stored and transmitted.

SIGHASH flags give flexibility for more complex transactions. They specify which inputs and outputs the signature commits to. Common values include:

  • SIGHASH_ALL (0x01): sign all inputs and all outputs.

  • SIGHASH_NONE (0x02): sign all inputs, no outputs.

  • SIGHASH_SINGLE (0x03): sign all inputs and only the output with the same index as this input.

  • SIGHASH_ALL | ANYONECANPAY (0x81): sign this input only, and all outputs.

  • SIGHASH_NONE | ANYONECANPAY (0x82): sign this input only, no outputs.

  • SIGHASH_SINGLE | ANYONECANPAY (0x83): sign this input only and the output with the same index.

Most everyday transactions use SIGHASH_ALL. In this implementation, a SIGHASH_FORKID bit is also used, which adds 0x40 to the base SIGHASH value, so 0x01 becomes 0x41, and so on.

Before signing, the relevant parts of the transaction are hashed with SHA-256 (often twice), and that digest is what ECDSA signs.

Signing Arbitrary Messages

Bitcoin also defines a way to sign arbitrary messages with a Bitcoin private key. This is often used to prove control over a particular address.

The process:

  1. The message is prefixed with "Bitcoin Signed Message:\n" and its length.

  2. That string is hashed twice with SHA-256.

  3. The hash is signed with ECDSA, producing a 65-byte structure (i, r, s) where i is a 1 byte recovery indicator and r and s are 32 bytes each.

  4. The result is then Base64 encoded.

For verification:

  1. The verifier receives the address, the message and the signed message.

  2. They apply the same prefix and double SHA-256 to the message.

  3. They use the (i, r, s) signature to derive one or more candidate public keys.

  4. They test the signature verification with each candidate key. If one passes, they hash that public key as RIPEMD-160(SHA-256(pubkey)), encode it as a Base58 address, and compare it to the claimed address.

If the addresses match and the signature verifies, the signer has proven they control the private key for that address at the time of signing.

ELI5(ish...)

Think of a Bitcoin transaction like a chain of locked boxes being passed from one person to another.

  • Each output is a box with some coins inside and a lock on it. The lock is coded to a particular public key, which is like the shape of a keyhole.

  • Each input is someone showing up with the matching private key and a signature, which is like a one time key that proves “I own this box and I am allowed to open it.”

The script glued to the box says, “Only someone who can show this public key and a valid signature over the transaction details can open me.” When a node checks a transaction, it literally runs that little script by combining the lock and the attempted key and seeing if it returns “True.”

Behind the scenes:

  • Wallets generate private keys (big random numbers) and derive public keys from them using elliptic curve math.

  • Wallets try not to reuse keys, so your activity is harder to track and one leaked key does not ruin everything. HD wallets let you regenerate many keys from one master seed phrase so you do not have to back up constantly.

  • Signatures are stored in a standard format and tagged with SIGHASH flags that say which parts of the transaction are covered.

When you sign a message or transaction, you are proving, “I control the private key that matches this public key.” Anyone with your public key or your address can check your signature, without ever seeing your private key. It is the same idea as signing your name on a contract, except the math makes it far harder to forge and much easier for computers to check.