CPSC 3640 / CPSC 5400

Decentralized Payments, Contracts, and Finance for Humans and AI

Take-Home Lab 1: Spend Your Bitcoin Before It's Gone

  • Released: Wednesday, September 16, 2026
  • Due: Wednesday, September 23, 2026 at 11:59 PM ET
  • You can collaborate (e.g., discuss) with another student, but each student should submit their own results.
  • Start early, and come to office hours if you need help.

We can implement a retractable coin using Bitcoin Script:

OP_IF <student_public_key>
OP_ELSE <nLockTime> OP_CHECKLOCKTIMEVERIFY OP_DROP <course_staff_public_key>
OP_ENDIF
OP_CHECKSIG

In this lab, you will be sent 0.0001 testnet BTC locked by the redeem script above.1 Beginning on Wednesday, September 23, 2026 at 11:59 PM EDT, course staff can retract any output that remains unspent.2 Your task is to spend your UTXO before then!

To make your life easier, I developed a Python program called timelock.py for creating and spending these outputs. Course staff use its create subcommand to construct the P2SH addresses, and you can use its spend subcommand to claim your coin. Your work is mainly to understand how to use timelock.py by reading its source code and documentation.

After a transaction has been sent to a P2SH output tailed to your public key, we will post the sender’s public key, funding transaction ID, and UTXO index (one for each student). You will need this information to run timelock.py, along with information you must obtain yourself, such as your secret key.

Sender’s public key: 03b1c5e8cd51e2a1a9e4057ea1afc5d21159ca2014f103aa0dd1cb71901b51b42e

NetID Public key prefix Funding transaction ID (txid) Output index (vout) Confirmed (ET)
ka699 0248ad13 80497f01ac1c30338318efe56e74891cd73342c7710e8c6dc035c5182e035975 0
drc62 02dd5946 83eb447e9d58f8572c5e098011c50b2ebfbb780759d0c6ed881e25f04beb6133 0
jc4458 025c958e 23b5940b1232fb8744b02abafcc94bc1c9984e69c9d505b1bd689ad3e44439dc 0
tg595 020599bf c085d24968d3d6e8e7738d30bd9558a5e2541cc5431021fad45b6d7119692321 0
hl2247 03e2ae7a 9552306a7379b2db8ca5f90d8a78dfec75ddbd635d9f36c98f331f5286bc1ad3 0
yl2926 029c693a 40c762dd676344709c2aaf06858eaabaab62eecaa21519ee0cd017223ef54382 1
yl2976 02205321 f7f14b267600f282110f0c565d086d44c5822ddd3cde43def499d8e9b35f28b6 1
nm962 02df9ac0 0d302600916b8ed5806f23b364fce3a6487f707183721dac0528727dce489327 1
dm2584 039be694 36acd44de83706e6652f797eda9fedbeb2d80065cc28e678b542a0f677ca273f 0
rnr7 02f6a2c9 9f8af14d9d2dd49920ec7bf70cd59315339a7a8be67cc7d70c99f82683679963 0
ys924 02923b28 7d0c0b7520b118554e5e2f7dafd5db334d43101275dd3a76eef3c45f7c89ef07 1
jt2443 031093cc fcbcb453696624c111bb307acfaf187c729077db58e2c78775a43472af912cc5 1
shy24 0279ccc2 2a10a453c40002af346a59a05a3084cb03fc4bff4b3bcfa5c961f5edfe3c910b 1
esz6 027b7731 62c3ae8d637c2c928d0a176fe13f5f4f6894860f8fb12c40e03db75ee43af9de 1
fz268 0201e314 792e388e8e34f0b712b4e7c0628fe72938802b19bd9fbfce3b97216e8a0251ea 1
hd447 03dffc0a 2925a4a71e2ab1ac48678f7bf65a90bcd82c318723db79b617dfc40b294a31bc 0 Pending
gy246 022fb85d af1cc257eef4546edfada456de5789903e0cab3180742f315d2f9c520e6cc829 0
sc3638 02499897 9c10fd690bc0679a9a312d382463894f9a19e603fecbdba36706d35c62f4222d 1 Pending
jm4488 03879315 09fcf23918d8f82c845ddb1885c1528f41831354c98e5c52b274abfe2ee5ea4c 0 Pending
jw3297 02a00c9e c5c903542da3823c6d577a769b071cf542d40dfd76af7984f9a7defdf9a2e4c6 0 Pending
mb3746 0327ef23 c67327bc7014edee2bccade2032a9fdba8e81a93fa88cc60c4bb6ec026f5bdb2 1 Pending
ana55 02acc228 88e6d84855a2ba9cd914e50ba0bb8748c5969a85c80a4d51caa3ea1593d9f6df 0 Pending
jw3322 032246d4 3af1d0111404f00d71cac54f3b86d3d3fe2157f2119682aaf6412957e503eec4 1 Pending

Confirmation times are block timestamps in Eastern Time. This column refreshes from mempool.space when the page loads; if it cannot be reached, the last recorded values remain.

Recover your secret key

To use timelock.py, you need the secret key that corresponds to the public key you submitted during the Bitcoin hands-on component. There are multiple ways to do it; you can use the following script.

Set WALLET, ADDRESS, and PUBKEY at the top of the script to your own values:

import json
import shlex
import subprocess
import sys

import bitcoin
from bip32 import BIP32
from bitcoin.wallet import CBitcoinSecret

WALLET = "YOUR_WALLET_NAME"
ADDRESS = "YOUR_LEGACY_ADDRESS"
PUBKEY = "YOUR_PUBLIC_KEY"


def bitcoin_cli(*arguments):
    command = [
        "bitcoin-cli",
        "-testnet4",
        f"-rpcwallet={WALLET}",
        *arguments,
    ]
    print(f"+ {shlex.join(command)}", file=sys.stderr)
    return json.loads(subprocess.check_output(command, text=True))


bitcoin.SelectParams("testnet")

address_info = bitcoin_cli("getaddressinfo", ADDRESS)
hd_path = address_info["hdkeypath"]

if address_info["pubkey"].lower() != PUBKEY.lower():
    raise SystemExit("The address does not match the public key")

hd_keys = bitcoin_cli(
    "-named",
    "gethdkeys",
    "active_only=true",
    "private=true",
)

for hd_key in hd_keys:
    if "xprv" not in hd_key:
        continue

    private_key = CBitcoinSecret.from_secret_bytes(
        BIP32.from_xpriv(hd_key["xprv"]).get_privkey_from_path(hd_path)
    )
    if private_key.pub.hex().lower() == PUBKEY.lower():
        print(private_key)
        break
else:
    raise SystemExit("Could not find the secret key for this public key")
Tips on how to run Python scripts

To run this script, we recommend using a virtual environment. See Python’s documentation on virtual environments for more information.

On macOS or Linux, run:

python3 -m venv .venv
source .venv/bin/activate

On Windows PowerShell, run:

py -m venv .venv
.venv\Scripts\Activate.ps1

Then install the two Python packages used by the scripts:

python -m pip install bip32 python-bitcoinlib

Make sure Bitcoin Core is running and the wallet named in WALLET is loaded. Save the embedded script as get-secret-key.py, then run it:

python get-secret-key.py

The script verifies that the recovered secret key matches the public key before printing it.

What to Submit

Submit a PDF with your NetID, name, group members (if any), and answers to the following questions. Everyone must submit their own work, even if you are in a group. If you did not get a full answer, document partial progress.

  1. What scriptSig would course staff use to retract the output?
  2. What is the scriptPubKey of the assigned funding output?
  3. What is the txid of your spending transaction?
  4. What is the scriptSig of the input in your spending transaction?

You can use the LaTeX template for your PDF submission.


  1. This is why we need the public key you were asked to submit on Canvas. ↩︎

  2. The corresponding nLockTime is 1790222340, the Unix timestamp for the date and time above. ↩︎