MAS.S62 | Spring 2018 | Graduate

Cryptocurrency Engineering and Design

Assignments

Problem Sets

  1. Hash-based Signature Schemes
  2. Mine Your Name
  3. UTXOhunt

Final Projects

You may form groups of 1–4 students and prepare a presentation and a ~4 page paper on one of the following:

  1. Design and implement an application or system.
  2. Add a new feature to an existing system like Bitcoin, Ethereum, or another cryptocurrency or shared ledger implementation.
  3. Propose a formalization in this space for a topic that has not been formalized yet.
  4. Pose and solve an interesting problem.

In the first part of this problem set, you’ll implement Lamport signatures. In the second part, you’ll take advantage of incorrect usage to forge signatures.

Getting started

You’ll implement all labs in Go. The Go website contains a lot of useful information including a tutorial for learning Go if you’re not already familiar with it.

You will probably find it most convenient to install Go 1.9 on your own computer, but you can also use it remotely.

You can use a regular editor like vim / emacs / notepad.exe. There is also a go-specific open source IDE that Tadge recommends & uses, LiteIDE which may make things easier.

In order to submit your lab, you’ll need to use Git. You can read about Git here.

Collaboration Policy

You must write all of the code you hand in, except for what we give you with the assignment. You may discuss the assignments with other students, but you should not look at or copy each other’s code.

Part 1

In this problem set, you will build a hash-based signature system. It will be helpful to read about Lamport signatures.

Implement the GenerateKey(), Sign() and Verify() functions in main.go. When you have done so correctly, the program should print Verify worked? true. You can test this by doing the following:

$ go build
$ ./pset01

Hint: You will need to look at the bits in each byte in a hash. You can use bit operators in order to do so.

Make sure your code passes the tests by running:

$ go test

Part 2

There is a public key and 4 signatures provided in the signatures.go file. Given this data, you should be able to forge another signature of your choosing. Make the message which you sign have the word “forge” in it and also your name or email address. There is a forge_test.go file which will check for the term “forge” in the signed message.

Note that this may take a decent amount of CPU time even on a good computer. We’re not talking days or anything though; 4 signatures is enough to make it so that an efficient implementation is relatively quick.

To make sure you’re in the right ballpark: On an AMD Ryzen 7 1700 CPU, using 8 cores, my (adiabat / Tadge) implementation could create a forgery in about 3 minutes of real time. An equally efficient single core implementation would take about 25 minutes. On slower CPUs or with less efficient code it may take longer.

If you use CUDA or AVX-512 or AES-NI or something crazy like that and get it to run in 5 seconds, cool! It should still run in Go and pass the tests here, but note that you can do all the “work” in a different program and import the solution to this code if you want.

That’s certainly not necessary though as it shouldn’t take that long on most computers. A raspberry pi might be too slow though. If you get the forge_test.go test to pass, you’re probably all set! Just run

$ go test

and see what fun errors you get! :)

Testing and Timeouts

To run tests,

$ go test

will work, but by default it will give up after 10 minutes. If your functions need more time to complete, you can change the timeout by typing

$ go test -timeout 30m

to timeout after 30 minutes instead of 10.

Mine Your Name Into the Blockchain

This problem set will use a mock blockchain which you can mine blocks into.

Block Specifications

Blocks are ASCII strings, with a maximum length of 100 characters. The block format is:

prevhash name nonce

“prevhash” is the ascii hexadecimal representation of the previous block hash. It must be lowercase and in hex; do not use raw bytes. Example:

00000000c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b

“name” is the name you want to credit nameChain points to. It’s case sensitive. Example:

miner2049

“nonce” is a random nonce to satisfy the work requirement. Example:

TWFuI3GlzIGR

Note that names and nonces must be in the base64 character set:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

which is just caps, lowercase, numbers and + and /. Can’t have spaces; spaces separate the 3 different elements of the block. This is to make everything easy to run through terminals, let people use shell scripts, and so on.

Client / Server Connections

This problem set has a server. It’s not a real decentralized system, as that’s too much work to deal with for this early assignment. There is a NameChain server which listens on a TCP port, and when a TCP connection is made to it, it sends the current blockchain tip. Connected clients can send a new block to it, which, if valid, will be appended to the end of the blockchain.

The required work is 2^33, which is twice as difficult as the initial target for the Bitcoin network. (But nowhere near as difficult as the current Bitcoin target.)

What To Do

A bunch are already written for you. The network functions are GetTipFromServer() and SendBlockToServer() and already implemented, so you don’t have to deal with TCP.

You need to write the Mine() function and then SendBlockToServer() once you have mined a block.

You may need to poll the server for new blocks occasionally so that you don’t submit “stale” blocks, where someone else submitted a block before you did with the same parent. To not DDoS our server, please keep requests to 1 per second maximum.

Using Go concurrency features is recommended for this problem set. The amount of work required to find a block is fairly high, and if you’re mining using only 1 CPU core you will be at a disadvantage compared to multi-threaded, multi-core miners.

Here is a simple tutorial on Go channels; they’re not too hard to use, even if you haven’t done multi-threaded programming before. They allow you to pass messages between functions which are running at the same time. There are also other possible methods like sync.WaitGroup, or, in fact, it’s quite possible to mine without any synchronization between threads at all.

There will be a “high score” ranking with the number of blocks in the chain made by each user. This is the same as getting more coins by mining more blocks. To get a high score, mine a bunch of blocks with the same name. We’re using names instead of public keys which is not as decentralized, but we know who you are already.

The entire current blockchain can be downloaded from the server at port 6299. Example code:

$ nc hubris.media.mit.edu 6299

00000000722a3b3cabaac078bd4e15ce361312895cfef0494c9ffc75bedb82db adiabat 19579781213

This is if you want to check how the blockchain is progressing.

In this assignment, we’re going to make some transactions on the Bitcoin test network using btcd for libraries, which is a bitcoin implementation written in golang. The goal is to understand how transactions are constructed and signed, and to become more familiar with the utxo model Bitcoin uses.

Testnet3 is a network for testing out Bitcoin. It works almost exactly like the regular Bitcoin network (small changes to addresses, the difficulty of proof of work) but everyone agrees that the testnet coins are not worth anything. This isn’t enforced by anything on the network, it’s just something people decide. The fact that it’s testnet3 indicates that this rule failed for testnets 1 and 2, when people started trading the testnet coins for mainnet coins.

In this problem set you’ll perform many of the functions of wallet software, by identifying outputs to spend, creating transactions, signing them, and broadcasting them to the network. Most wallet software does this all automatically, but this assignment is more manual so you can see how it works.

Setup

Get Bitcoin Core 0.16.0, available at the download section of the Bitcoin Core website.

To get on to the test network, make a bitcoin.conf file in your bitcoin folder (which is HOMEDIR/.bitcoin/bitcoin.conf or in linux  ~/.bitcoin/) and have the following line in the conf file:

testnet=1

and then run

$ bitcoind --daemon

so that it runs in the background. Syncing up to the testnet will require download of around 12 GB and will take a few hours depending on your computer’s speed. Some MIT guest wifi will block outgoing connections to different ports, so try using wired ethernet or another SSID if it doesn’t seem to download.

Once bitcoind is running, you can see what it’s doing by looking at the /.bitcoin/testnet3/debug.log file and issue commands with bitcoin-cli.

In this repo there are 4 files:

main.go

addrfrompriv.go

eztxbuilder.go

opreturn.go

Here’s what they do:

main.go

This is the main function which is called when you run ./utxohunt

Edit this file to call functions from other files when you run the program.

addrfrompriv.go

Creates a public key and bitcoin address from a private key. Addresses are copy&pastable encodings of public key hashes.

eztxbuilder.go

Puts a transaction together, signs it, and prints the tx hex to the screen. This can then be sent to the network with the pushrawtransaction command in bitcoin-cli or to your own bitcoin node with ./bitcoin-cli pushrawtransaction (tx hex).

opreturn.go

Similar to eztxbuilder.go, but creates a transaction with 1 input, and 2 outputs. 1 of the outputs is an “OP_RETURN” output which can contain arbitrary data. Use this to submit your results to the blockchain.

Task 1: Create a Bitcoin Address

First, look in utxohunt/main.go, and make a keypair. The AddressFromPrivateKey() function will help you. Put your own random string in to generate a private key. If you call the AddressFromPrivateKey() function, it will return that address as a string, as well as give you the compressed public key and pay to witness pubkey hash script.

Save this address (it starts with an “m”). You’ll need this to send the money to yourself.

Task 2: Find the First Treasure Hunt Transaction

A block explorer is a website which watches the blockchain and parses out information about blocks, addresses, and transactions. You can use this blockexplorer to see what’s happening on the Bitcoin testnet.

I’ve created a transaction with one 70 outputs. 1f497ac245eb25cd94157c290f62d042e3bdda1e57920b6d1d2c5cfa362c12da is the txid, or unique identifier of this transaction. (The txid is the hash of the serialized transaction.)

The outputs of this transaction are all have the same address, which determines how they can be spent. The private key for this pubkey-hash address is the double-sha256 of the string “mas.s62”.

Claim an unspent output in this transaction. Please be nice and leave the rest of the outputs for other classmates! :)

Task 3: Make a Transaction

Using EZTxBuilder(), make a transaction sending from the up-for-grabs transaction to your own address.

You will need to modify:

hashStr

outPoint (output index number)

sendToAddressString

prevAddressString (the address of the “BTC secret key” pubkey)

wire.NewTxOut (change the amount to less than the input amount. A few thousand less is enough of a fee)

When you modify the code, you need to re-compile the code. Run “go build” in that directory to compile.

You’ll get a long hex string which you can test by running the transaction though bitcoin-cli’s decoderawtransaction command ./bitcoin-cli decoderawtransaction (tx hex).

If you get an error, it might be for one of the following reasons:

  1. Someone has already claimed the output you are trying to get. Go back and look at the transaction’s page and see if the output is still available. It will say “inputs spent” or equivalent.
  2. 64: non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation). This means your signature was invalid. Often this is because the hash being signed was invalid. This could be because the previous output you signed and the one you indicted don’t match, the wrong amount is being sent to the WitnessScript function, or some other invalid data is in the transaction prior to signing. An invalid signature can also be caused by using the wrong key. In that case, you will usually get this error:
  3. 64: non-mandatory-script-verify-flag (Script failed an OP_EQUALVERIFY operation). This means you’re probably using the wrong key to sign with, as the public key used and public key hash in the previous output script don’t match.
  4. TX decode failed. That means you’re missing some characters, or the transaction is otherwise unintelligible to the bitcoin-cli parser.

If everything worked, the decoderawtransaction output will show you a json representation of the transaction you’ve created. You can then send it to the network with the command sendrawtransaction. If that works, it will return a txid. If that works and the transaction is confirmed (check with getrawtransaction), you’ve got some testnet coins! You can use the same EZTxBuilder() to send that money somewhere else.

Further Steps / Bonus Money

Try to get some more money. There are some coins stashed through the network, and we will add more over the week :)

The first output One has a private key which is the double-sha256 of the address from which you took the first coins.

To grab these coins, you will need to use AddressFromPrivateKey() to generate that address, search the blockchain for the txid, and try to send an output to yourself, the same way as with the first transaction you created.

Note that in many cases, someone else in the class may have grabbed the coins before you. That’s OK, just write down where you found the coins to be and the private key you would have used to take them.

Course Info

Instructors
As Taught In
Spring 2018
Level
Learning Resource Types
Lecture Videos
Problem Sets
Lecture Notes