diff --git a/2020/day13.go b/2020/day13.go
new file mode 100644
index 0000000..21d2c3b
--- /dev/null
+++ b/2020/day13.go
@@ -0,0 +1,122 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"math"
+	"math/big"
+	"os"
+	"strconv"
+	"strings"
+
+	"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
+)
+
+//
+// Begin code borrowed from https://golang.hotexamples.com/examples/math.big/Int/GCD/golang-int-gcd-method-examples.html
+//
+func crt(a, n []*big.Int) (*big.Int, error) {
+	one := new(big.Int).SetInt64(1)
+	p := new(big.Int).Set(n[0])
+	for _, n1 := range n[1:] {
+		p.Mul(p, n1)
+	}
+	var x, q, s, z big.Int
+	for i, n1 := range n {
+		q.Div(p, n1)
+		z.GCD(nil, &s, n1, &q)
+		if z.Cmp(one) != 0 {
+			return nil, fmt.Errorf("%d not coprime", n1)
+		}
+		x.Add(&x, s.Mul(a[i], s.Mul(&s, &q)))
+	}
+	return x.Mod(&x, p), nil
+}
+
+//
+// End borrowed code
+//
+
+func parseInput(input []string) (int, []int) {
+	earliest, err := strconv.Atoi(input[0])
+	if err != nil {
+		log.Panicf(err.Error())
+	}
+
+	busList := make([]int, 0)
+	for _, value := range strings.Split(input[1], ",") {
+		if value == "x" {
+			busList = append(busList, -1)
+			continue
+		}
+		x, err := strconv.Atoi(value)
+		if err != nil {
+			log.Panicf(err.Error())
+		}
+		busList = append(busList, x)
+	}
+
+	return earliest, busList
+}
+
+func findBus(busList []int, earliest int) (int, int) {
+	bestBus := -1
+	bestTime := -1
+
+	for _, bus := range busList {
+		if bus == -1 {
+			continue
+		}
+		time := int(math.Ceil(float64(earliest)/float64(bus))) * bus
+		if bestBus == -1 || time < bestTime {
+			bestBus = bus
+			bestTime = time
+		}
+	}
+
+	return bestBus, bestTime
+}
+
+// This uses the Chinese Remainder Theorem to calculate the answer.
+// I don't actually understand the underlying logic, I just found this
+// while looking around for modulus-related algorithms.
+func findTimestampWithCRT(busList []int) *big.Int {
+	bigBusList := make([]*big.Int, 0)
+	offsetList := make([]*big.Int, 0)
+
+	for i, bus := range busList {
+		if bus == -1 {
+			continue
+		}
+
+		bigBus := big.NewInt(int64(bus))
+		bigBusList = append(bigBusList, bigBus)
+
+		offset := big.NewInt(int64(i))
+		offset.Sub(bigBus, offset)
+		offsetList = append(offsetList, offset)
+	}
+
+	fmt.Println(offsetList)
+	fmt.Println(bigBusList)
+	value, err := crt(offsetList, bigBusList)
+	if err != nil {
+		log.Panicf(err.Error())
+	}
+	return value
+}
+
+func main() {
+	step := os.Args[1]
+	values := fileutils.InputParserStrings(os.Args[2])
+
+	earliest, busList := parseInput(values)
+
+	switch step {
+	case "1":
+		busId, departureTime := findBus(busList, earliest)
+		fmt.Println(busId * (departureTime - earliest))
+	case "2":
+		fmt.Println(findTimestampWithCRT(busList))
+	}
+}