
Welcome to Base58'sBitcoin Developer Basics! Meet your host, @niftynei
Things you should already know:
- Python basics
- Bitcoin transactions (see part 1)
- Bitcoin script (see part 1)
- bitcoin core node
- Basic Algebra
We take a transaction from mempool dot space, break it into the different parts by hand (review of part 1 of Bitcoin Developer Basics: Transactions + Scripts)
What software do I need for this class? A: a python repl and bitcoind / bitcoin-cli.
There's a few ways to get access to this, see below videos for a few options!
How to setup bitcoind + bitcoin-cli from the terminal on a Mac.
Commands to codesign + remove from suspected virus whitelists:
codesign -s - $(pwd)/bitcoind
xattr -d com.apple.quarantine $(pwd)/bitcoind
Last video we downloaded bitcoind for a Mac. Let's walk through the process to verify it.
Using a brand new replit to get access to bitcoind + bitcoin-cli
Quick start: just use the Base58 replit with bitcoind.
nifty walks through Project 1A.
Let's explore mempool.space (light walk through)
What am I using in my setup?
Welcome to Base58's crash course in elliptic curve cryptography! We're going to learn about the underlying bitcoin 'cryptosystem': elliptic curves over finite fields, specifically the secp256k1 curve that bitcoin uses.
What is an 'elliptic curve'? We go through the general form of the elliptic curve equation that is used by most cryptographic elliptic curve cryptography (reduced Weierstrauss form).
@nifty does a very brief walk thru of a more in-depth article on Elliptic Curves, from brilliant.org. If you want a more in-depth understanding of elliptic curves, this is an ok starting place! Article requires some decent math chops.
What is a finite field? Let's first explore an 'infinite' field, and then move into how finite fields work in comparison.
Now that we have a basic intuition for how elliptic curves and finite fields work, what does an elliptic field over a finite field look like?
Bitcoin uses a specific elliptic curve over a finite field, called secp256k1. In this video, we'll find the parameters that the Standards for Elliptic Cryptography laid out in their 2010 research paper, and tie it back to the parameters we've already defined for elliptic curves (a, b) and finite fields (p).
What is a generator point? Let's talk about generator points and walk thru a quick example of how one works using a smaller curve set.
The SEC paper gives two different values for a generator point: one compressed and the other uncompressed. What do these mean? How do we translate this into a point on the cartesian plane?
We implement a small python function for finding the y value of a point on the secp256k1 curve, given the x-coordinate and parity byte value.
What does it mean to add two elliptic curve points together? Let's take a look at how we can 'define' an addition function for elliptic curves, that allows us to be able to add two points together and still stay on the curve.
Ok so we can add two separate points together using a line to find where it intersects the graph again, but what if we want to add a point to itself, like we do with G, the generator point?
Let's look at how to "multiply" a point by two (add it to itself).
In this section, we'll make our first bitcoin script that requires some cryptography to unlock! We'll pick our own private key and then make a public key from it. Then we'll lock some bitcoin up to it. Finally, we'll use bitcoin-cli to spend it.
Let's use a Python library, coincurve, to make public keys!
Use coincurve to build some public and private key utilities.
We walk through the Project 2A and how to solve it.
What's the point of using public and private keys? How does this make anything "safe"? Let's walk through what we're hoping to achieve with this.
Note: older style video
In this video, we lock up some bitcoin to a P2PK transaction.
The script we use is:
<pubkey> OP_CHECKSIG
The bitcoin-cli commands we use are:
bitcoin-cli listunspent # to find a spendable input. Make sure you've added bitcoin to your wallet. See Housekeeping for how to do this
bitcoin-cli decoderawtransaction # to verify the transaction is correct
bitcoin-cli signrawtransactionwithwallet # to sign an input from listinputs
bitcoin-cli sendrawtransaction # to broadcast a transaction we've signed.
In this video, we learn how to spend a compressed public key P2PK, using signtransactionwithkey and a WIF.
In this video, we walk thru solving the P2PK homework.
What is a digital signature? Let's take a look.
Before Taproot, all bitcoin signatures are made using something called ECDSA. Let's take a look at this signing algorithm.
We need to find 1/k, or the "multiplicative inverse" of k. What does that mean and how can we find it?
Let's implement the 'sign' part of ECDSA
Let's implement the 'verify' half of ECDSA, and use it to verify a message and signature!
@niftynei walks through the solution to the ECDSA project.
Once we've got an ECDSA signature, we need to format it correctly for bitcoin transactions. In this lecture, we learn about DER-encoding, which is the format we'll need to package ECDSA signatures up to in order to put them into transactions.
Let's walk through the DER encoding project.
Quick video explaining why we flip the s for any signature we find.
Note: Older style video
We need a 'digest' to sign, in order to produce a signature for ECDSA. How we do this in bitcoin is the topic of this and the next few sections.
Here we start the process of building one by hand; by the end of this section we'll have built a method that will do this for us.
More adventures in validating a signature on a bitcoin transaction.
In this video, we walk through building a transaction with three inputs, which are locked up to public keys that correspond to our three private keys: 666, 777, 888. We use fundrawtransaction.
Note that you can skip this video, if you want!
In this video we take the 3-input, 2-output transaction that we built in the last video, and compute the sighash for the first input, using the SIGHASH_ALL flag.
General steps:
- Add the sighash flag to the very bottom of the transaction
- Set the scriptSig to zero for every input
- For the input we're computing the digest of, set the scriptSig (now called the scriptCode) to the scriptPubKey of the output we're spending.
Let's make a second digest for our transaction, this time for the second input. We'll use SIGHASH_SINGLE.
The biggest difference here is that
- we'll set the sequence for any input we're not producing the digest for to all zeros
- we set the number of outputs equal to the input index
- any output that's not at the index we're signing, we'll set to "blank data" or delete it (if it's after the index we're signing).
Let's make a thrid digest for our transaction, this time for the third and final input. We'll use SIGHASH_NONE.
The biggest difference here is that
- we'll set the sequence for any input we're not producing the digest for to all zeros
- we set the number of outputs equal to zero
- we'll remove all the output data from the message.
Now that we've computed the digest for the inputs in our transaction, we're ready to use our secret keys and `make_sig` method we created in the last section to make valid signatures for this transaction.
In this video, we talk through a pretty bad edgecase with SIGHASH_SINGLE for legacy transactions.
We have one last sighash flag to implement! ACP or 'anyone can pay' is a sighash flag modifier that stack onto one of the other 'base' sighash flag options.
It's simple to implement. If the ACP options is flagged:
- Set the count of inputs to one
- Skip all inputs except for the one we're signing.
In this walk thru, we build a compute_sighash flag function, which we'll use to compute the signing digest for legacy (pre-Segwit) inputs in transactions.
Can you steal an input from another transaction? You don't know the secret keys, but there's bitcoin that is yours for the taking in this exercise.
In this walk through, we complete project 5b, stealing a faulty SIGHASH_SINGLE input!
Most legacy script transactions aren't locked up to P2PK scripts, but instead to P2PKH scripts. In this segment we learn what the P2PKH script is.
Let's take a private key; build a pubkey from it and then convert that pubkey into a P2PKH script.
In this video we take the P2PKH script, build a transaction to send funds to it, and then spend from that transaction where we've locked the funds up.
One key to spending P2PKH scripts is that the pubkey is now a part of the scriptSig data that you have to pass in, along with a signature.
A good rule of thumb for hashed data in bitcoin standard scripts is that it always is the last item in the scriptSig or witness data. So in this example, the pubkey is the last item behind the signature.
In this video, we make a fork of the Replit we did in the P2PKH script videos, and update it to work for the Native SegWit, Pay to Witness Public Key Hash script.
We're not able to spend it, however, as we need to learn how to compute a sighash digest for SegWit inputs first.
Let's make a sighash for a Segwit transaction.
Note that the videos in this section are a different style.
How the scriptcode field is formatted for BIP143 sighashes is quite different. Here we investigate.
We finish up the sighash digest calculation, sign it, add it to the transaction, and verify that it works!
Brief discussion of how the various sighash flags (NONE, SINGLE, ACP) are implemented in BIP143.
Why did we change the sighash algorithm? We discuss the O(n^2) hashing behavior of the legacy sigash algo.
Let's take a look at the where the SegWit sighash algorithm is defined, in BIP143 "Transaction Signature Verification for Version 0 Witness Program"
Let's walk through how @niftynei would solve project 6, to build a Segwit v0 sighash calculator.
We walk through finishing the exercise we started in the keyhashes section: spending a P2WPKH!
Intro to multisig, including a discussion of thresholds in multisigs.
Note: videos in this section were filmed at an earlier date, with different style/setup.
Here we build a multisig script and lock bitcoin up to it (baremultisig, P2SH, P2WSH versions)
Using the transaction where we locked up bitcoin to the multisig addresses, we now make a transaction that will spend all three new multisig outputs.
In this video, we spend all three multisig scripts (baremultisig, P2SH, P2WSH).
There's some small things to note about putting data into the Witness Stack (Segwit inputs) versus in a ScriptSig (legacy inputs). This video goes into a few of them!
How does op-checksig work? Let's walk through what's happening with this opcode, under the hood.
We covered a lot of ground in this class. Let's quickly review what you've learned.
- Elliptic Curves over Finite Fields
- secp256k1
- Pubkeys + Private keys
- P2PK scripts in bitcoin
- Implemented ECDSA from the 'spec' (wikipedia)
- Built a legacy + Segwit v0 sighash calculator
- P2PKH + P2WPKH scripts
- Spent a threshold multisig in bitcoin (legacy + Segwit v0)
Where to go next? More Base58 classes of course.
Check out our: Taproot, Lightning, or Wallets class next!
Thanks for showing up! ?
So you've heard about bitcoin? Ever wondered what's going on with the data in a transaction, or how bitcoin gets locked up and transferred from one holder to another?
This course by Base58 instructor niftynei, will take you on a deep dive of the fields, bytes, and scripts that make up the bitcoin blockchain data. In an software engineer focused manner, we'll go over everything you need to know to build your own bitcoin transaction parser, write your very own custom bitcoin locking scripts, and adapt your transactions to the modern SegWit format.
Step 1: Let's learn about Elliptic Curve Cryptogaphy
First we figure out what the building blocks for making digital signatures on blockchains are: elliptic curves! We'll do a very basic walk through of how these work and work through where Bitcoin's secp256k1 curve comes from. Finally we'll pick some private keys and learn how to find the public key version of it.
Topics: elliptic curves over finite fields, secp256k1, public and private keys
Step 2: P2PK, P2PKH: Locking Bitcoin up to Public Keys
Now that we've got some private and public keys, we're ready to learn about standard Bitcoin scripts with signatures. We'll write some P2PK, P2PKH, and P2WPKH scripts and lock bitcoin up to them (so we can unlock it later).
Topics: compressed keys, P2PK, P2PKH, P2WPKH
Step 3: Digital Signatures
Now that we've got Bitcoin locked up to some public keys, we need to learn how to make signatures to unlock it. We'll walk through how ECDSA works.
Topics: digital siganatures, ECDSA
Step 4: Sighashes
Now that we've got ECDSA under our belt, we're ready to make signatures to spend the bitcoin we locked to our public keys. Here we use sighashes to build the message to sign with ECDSA. Sighashes are how we commit to data in a transaction, to prevent anyone else from tampering with the data on its way into a block.
Topics: sighashes, SegWit, legacy, SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE
Step 5: Multisig
Finally, we'll take a look at how you can lock bitcoin up to threshold signatures using OP_CHECKMULTISIG.
Topics: multisigs, OP_CHECKMULTISIG, Script