diff --git a/proj2/proj2_screen.pdf b/proj2/proj2_screen.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..be6a05aaaf87f4e78040a20ee28ad65da5ecf834
Binary files /dev/null and b/proj2/proj2_screen.pdf differ
diff --git a/proj2/sample/proj2.go b/proj2/sample/proj2.go
new file mode 100644
index 0000000000000000000000000000000000000000..056275492242a99a020b69df920e8c7764823122
--- /dev/null
+++ b/proj2/sample/proj2.go
@@ -0,0 +1,188 @@
+package proj2
+
+// You MUST NOT change what you import.  If you add ANY additional
+// imports it will break the autograder, and we will be Very Upset.
+
+import (
+	// You neet to add with
+	// go get github.com/nweaver/cs161-p2/userlib
+	"github.com/nweaver/cs161-p2/userlib"
+
+	// Life is much easier with json:  You are
+	// going to want to use this so you can easily
+	// turn complex structures into strings etc...
+	"encoding/json"
+
+	// Likewise useful for debugging etc
+	"encoding/hex"
+
+	// UUIDs are generated right based on the crypto RNG
+	// so lets make life easier and use those too...
+	//
+	// You need to add with "go get github.com/google/uuid"
+	"github.com/google/uuid"
+
+	// Useful for debug messages, or string manipulation for datastore keys
+	"strings"
+
+	// Want to import errors
+	"errors"
+
+	// optional
+	// strconv
+
+	// if you are looking for fmt, we don't give you fmt, but you can use userlib.DebugMsg
+	// see someUsefulThings() below
+)
+
+// This serves two purposes: It shows you some useful primitives and
+// it suppresses warnings for items not being imported
+func someUsefulThings() {
+	// Creates a random UUID
+	f := uuid.New()
+	userlib.DebugMsg("UUID as string:%v", f.String())
+
+	// Example of writing over a byte of f
+	f[0] = 10
+	userlib.DebugMsg("UUID as string:%v", f.String())
+
+	// takes a sequence of bytes and renders as hex
+	h := hex.EncodeToString([]byte("fubar"))
+	userlib.DebugMsg("The hex: %v", h)
+
+	// Marshals data into a JSON representation
+	// Will actually work with go structures as well
+	d, _ := json.Marshal(f)
+	userlib.DebugMsg("The json data: %v", string(d))
+	var g uuid.UUID
+	json.Unmarshal(d, &g)
+	userlib.DebugMsg("Unmashaled data %v", g.String())
+
+	// This creates an error type
+	userlib.DebugMsg("Creation of error %v", errors.New(strings.ToTitle("This is an error")))
+
+	// And a random RSA key.  In this case, ignoring the error
+	// return value
+	var pk userlib.PKEEncKey
+        var sk userlib.PKEDecKey
+	pk, sk, _ = userlib.PKEKeyGen()
+	userlib.DebugMsg("Key is %v, %v", pk, sk)
+}
+
+// Helper function: Takes the first 16 bytes and
+// converts it into the UUID type
+func bytesToUUID(data []byte) (ret uuid.UUID) {
+	for x := range ret {
+		ret[x] = data[x]
+	}
+	return
+}
+
+// The structure definition for a file record
+type File struct {
+        Filename string
+        FileUUID uuid.UUID
+        FileKey []byte
+	FileSlice int
+}
+
+// The structure definition for a user record
+type User struct {
+	Username string
+
+	// You can add other fields here if you want...
+	// Note for JSON to marshal/unmarshal, the fields need to
+	// be public (start with a capital letter)
+}
+
+// This creates a user.  It will only be called once for a user
+// (unless the keystore and datastore are cleared during testing purposes)
+
+// It should store a copy of the userdata, suitably encrypted, in the
+// datastore and should store the user's public key in the keystore.
+
+// The datastore may corrupt or completely erase the stored
+// information, but nobody outside should be able to get at the stored
+// User data: the name used in the datastore should not be guessable
+// without also knowing the password and username.
+
+// You are not allowed to use any global storage other than the
+// keystore and the datastore functions in the userlib library.
+
+// You can assume the user has a STRONG password
+func InitUser(username string, password string) (userdataptr *User, err error) {
+	var userdata User
+	userdataptr = &userdata
+
+	return &userdata, nil
+}
+
+// This fetches the user information from the Datastore.  It should
+// fail with an error if the user/password is invalid, or if the user
+// data was corrupted, or if the user can't be found.
+func GetUser(username string, password string) (userdataptr *User, err error) {
+	var userdata User
+	userdataptr = &userdata
+
+	return userdataptr, nil
+}
+
+// This stores a file in the datastore.
+//
+// The name of the file should NOT be revealed to the datastore!
+func (userdata *User) StoreFile(filename string, data []byte) {
+	return
+}
+
+// This adds on to an existing file.
+//
+// Append should be efficient, you shouldn't rewrite or reencrypt the
+// existing file, but only whatever additional information and
+// metadata you need.
+
+func (userdata *User) AppendFile(filename string, data []byte) (err error) {
+	return
+}
+
+// This loads a file from the Datastore.
+//
+// It should give an error if the file is corrupted in any way.
+func (userdata *User) LoadFile(filename string) (data []byte, err error) {
+	return
+}
+
+// You may want to define what you actually want to pass as a
+// sharingRecord to serialized/deserialize in the data store.
+type sharingRecord struct {
+}
+
+// This creates a sharing record, which is a key pointing to something
+// in the datastore to share with the recipient.
+
+// This enables the recipient to access the encrypted file as well
+// for reading/appending.
+
+// Note that neither the recipient NOR the datastore should gain any
+// information about what the sender calls the file.  Only the
+// recipient can access the sharing record, and only the recipient
+// should be able to know the sender.
+
+func (userdata *User) ShareFile(filename string, recipient string) (
+	magic_string string, err error) {
+
+	return
+}
+
+// Note recipient's filename can be different from the sender's filename.
+// The recipient should not be able to discover the sender's view on
+// what the filename even is!  However, the recipient must ensure that
+// it is authentically from the sender.
+func (userdata *User) ReceiveFile(filename string, sender string,
+	magic_string string) error {
+	return nil
+}
+
+// Removes access for all others.
+func (userdata *User) RevokeFile(filename string) (err error) {
+	return
+}
diff --git a/proj2/sample/proj2_test.go b/proj2/sample/proj2_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b6dd92ec27fd453896759563c7e845226d8b1b01
--- /dev/null
+++ b/proj2/sample/proj2_test.go
@@ -0,0 +1,95 @@
+package proj2
+
+// You MUST NOT change what you import.  If you add ANY additional
+// imports it will break the autograder, and we will be Very Upset.
+
+import (
+	"testing"
+	"reflect"
+	"github.com/nweaver/cs161-p2/userlib"
+	"encoding/json"
+	"encoding/hex"
+	"github.com/google/uuid"
+	"strings"
+	"errors"
+)
+
+
+func TestInit(t *testing.T) {
+	t.Log("Initialization test")
+
+	// You may want to turn it off someday
+	userlib.SetDebugStatus(true)
+	someUsefulThings()
+	userlib.SetDebugStatus(false)
+	u, err := InitUser("alice", "fubar")
+	if err != nil {
+		// t.Error says the test fails
+		t.Error("Failed to initialize user", err)
+	}
+	// t.Log() only produces output if you run with "go test -v"
+	t.Log("Got user", u)
+	// If you want to comment the line above,
+	// write _ = u here to make the compiler happy
+	// You probably want many more tests here.
+}
+
+
+func TestStorage(t *testing.T) {
+	// And some more tests, because
+	u, err := GetUser("alice", "fubar")
+	if err != nil {
+		t.Error("Failed to reload user", err)
+		return
+	}
+	t.Log("Loaded user", u)
+
+	v := []byte("This is a test")
+	u.StoreFile("file1", v)
+
+
+	v2, err2 := u.LoadFile("file1")
+	if err2 != nil {
+		t.Error("Failed to upload and download", err2)
+	}
+	if !reflect.DeepEqual(v, v2) {
+		t.Error("Downloaded file is not the same", v, v2)
+	}
+}
+
+func TestShare(t *testing.T) {
+	u, err := GetUser("alice", "fubar")
+	if err != nil {
+		t.Error("Failed to reload user", err)
+	}
+	u2, err2 := InitUser("bob", "foobar")
+	if err2 != nil {
+		t.Error("Failed to initialize bob", err2)
+	}
+
+	var v, v2 []byte
+	var magic_string string
+
+	v, err = u.LoadFile("file1")
+	if err != nil {
+		t.Error("Failed to download the file from alice", err)
+	}
+
+	magic_string, err = u.ShareFile("file1", "bob")
+	if err != nil {
+		t.Error("Failed to share the a file", err)
+	}
+	err = u2.ReceiveFile("file2", "alice", magic_string)
+	if err != nil {
+		t.Error("Failed to receive the share message", err)
+	}
+
+	v2, err = u2.LoadFile("file2")
+	if err != nil {
+		t.Error("Failed to download the file after sharing", err)
+	}
+	if !reflect.DeepEqual(v, v2) {
+		t.Error("Shared file is not the same", v, v2)
+	}
+
+}
diff --git a/proj2/userlib/userlib.go b/proj2/userlib/userlib.go
new file mode 100644
index 0000000000000000000000000000000000000000..2187ebdf9175cff10ff15692bd88abc20212fb26
--- /dev/null
+++ b/proj2/userlib/userlib.go
@@ -0,0 +1,351 @@
+package userlib
+
+import (
+    "fmt"
+    "strings"
+    "time"
+    "errors"
+    "log"
+
+    "io"
+
+    "crypto"
+    "crypto/rsa"
+    "crypto/hmac"
+    "crypto/rand"
+    "crypto/sha512"
+    "crypto/aes"
+    "crypto/cipher"
+
+    "golang.org/x/crypto/argon2"
+    "github.com/google/uuid"
+)
+
+type UUID = uuid.UUID
+
+// RSA key size
+var RSAKeySize = 2048
+
+// AES block size and key size
+var AESBlockSize = aes.BlockSize
+var AESKeySize = 16
+
+// Hash and MAC size
+var HashSize = sha512.Size
+
+
+// Debug print true/false
+var DebugPrint = false
+
+// DebugMsg. Helper function: Does formatted printing to stderr if
+// the DebugPrint global is set.  All our testing ignores stderr,
+// so feel free to use this for any sort of testing you want.
+
+func SetDebugStatus(status bool){
+	DebugPrint = status
+}
+
+func DebugMsg(format string, args ...interface{}) {
+    if DebugPrint {
+        msg := fmt.Sprintf("%v ", time.Now().Format("15:04:05.00000"))
+        log.Printf(msg+strings.Trim(format, "\r\n ")+"\n", args...)
+    }
+}
+
+// RandomBytes. Helper function: Returns a byte slice of the specificed
+// size filled with random data
+func RandomBytes(bytes int) (data []byte) {
+    data = make([]byte, bytes)
+    if _, err := io.ReadFull(rand.Reader, data); err != nil {
+        panic(err)
+    }
+    return
+}
+
+type PublicKeyType struct {
+    KeyType string
+    PubKey rsa.PublicKey
+}
+
+type PrivateKeyType struct {
+    KeyType string
+    PrivKey rsa.PrivateKey
+}
+
+// Datastore and Keystore variables
+var datastore map[UUID][]byte = make(map[UUID][]byte)
+var keystore map[string]PublicKeyType = make(map[string]PublicKeyType)
+
+
+/*
+********************************************
+**           Datastore Functions          **
+**       DatastoreSet, DatastoreGet,      **
+**     DatastoreDelete, DatastoreClear    **
+********************************************
+*/
+
+// Sets the value in the datastore
+func DatastoreSet(key UUID, value []byte) {
+    foo := make([]byte, len(value))
+    copy(foo, value)
+
+    datastore[key] = foo
+}
+
+// Returns the value if it exists
+func DatastoreGet(key UUID) (value []byte, ok bool) {
+    value, ok = datastore[key]
+    if ok && value != nil {
+        foo := make([]byte, len(value))
+        copy(foo, value)
+        return foo, ok
+    }
+    return
+}
+
+// Deletes a key
+func DatastoreDelete(key UUID) {
+    delete(datastore, key)
+}
+
+// Use this in testing to reset the datastore to empty
+func DatastoreClear() {
+    datastore = make(map[UUID][]byte)
+}
+
+// Use this in testing to reset the keystore to empty
+func KeystoreClear() {
+    keystore = make(map[string]PublicKeyType)
+}
+
+// Sets the value in the keystore
+func KeystoreSet(key string, value PublicKeyType) error {
+    _, present := keystore[key]
+    if present != false {
+       return errors.New("That entry in the Keystore has been taken.")
+    }
+
+    keystore[key] = value
+    return nil
+}
+
+// Returns the value if it exists
+func KeystoreGet(key string) (value PublicKeyType, ok bool) {
+    value, ok = keystore[key]
+    return
+}
+
+// Use this in testing to get the underlying map if you want
+// to play with the datastore.
+func DatastoreGetMap() map[UUID][]byte {
+    return datastore
+}
+
+// Use this in testing to get the underlying map if you want 
+// to play with the keystore.
+func KeystoreGetMap() map[string]PublicKeyType {
+    return keystore
+}
+
+
+/*
+********************************************
+**         Public Key Encryption          **
+**       PKEKeyGen, PKEEnc, PKEDec        **
+********************************************
+*/
+
+// Four structs to help you manage your different keys
+// You should only have 1 of each struct
+// keyType should be either:
+//     "PKE": encryption
+//     "DS": authentication and integrity
+
+type PKEEncKey = PublicKeyType
+type PKEDecKey = PrivateKeyType
+
+type DSSignKey = PrivateKeyType
+type DSVerifyKey = PublicKeyType
+
+// Generates a key pair for public-key encryption via RSA
+func PKEKeyGen() (PKEEncKey, PKEDecKey, error) {
+    RSAPrivKey, err := rsa.GenerateKey(rand.Reader, RSAKeySize)
+    RSAPubKey := RSAPrivKey.PublicKey
+
+    var PKEEncKeyRes PKEEncKey
+    PKEEncKeyRes.KeyType = "PKE"
+    PKEEncKeyRes.PubKey = RSAPubKey
+
+    var PKEDecKeyRes PKEDecKey
+    PKEDecKeyRes.KeyType = "PKE"
+    PKEDecKeyRes.PrivKey = *RSAPrivKey
+
+    return PKEEncKeyRes, PKEDecKeyRes, err
+}
+
+// Encrypts a byte stream via RSA-OAEP with sha512 as hash
+func PKEEnc(ek PKEEncKey, plaintext []byte) ([]byte, error) {
+    RSAPubKey := &ek.PubKey
+
+    if ek.KeyType != "PKE" {
+        return nil, errors.New("Using a non-PKE key for PKE.")
+    }
+
+    ciphertext, err := rsa.EncryptOAEP(sha512.New(), rand.Reader, RSAPubKey, plaintext, nil)
+
+    return ciphertext, err
+}
+
+// Decrypts a byte stream encrypted with RSA-OAEP/sha512
+func PKEDec(dk PKEDecKey, ciphertext []byte) ([]byte, error) {
+    RSAPrivKey := &dk.PrivKey
+
+    if dk.KeyType != "PKE" {
+        return nil, errors.New("Using a non-PKE key for PKE.")
+    }
+
+    decryption, err := rsa.DecryptOAEP(sha512.New(), rand.Reader, RSAPrivKey, ciphertext, nil)
+
+    return decryption, err
+}
+
+
+/*
+********************************************
+**           Digital Signature            **
+**       DSKeyGen, DSSign, DSVerify       **
+********************************************
+*/
+
+// Generates a key pair for digital signature via RSA
+func DSKeyGen() (DSSignKey, DSVerifyKey, error) {
+    RSAPrivKey, err := rsa.GenerateKey(rand.Reader, RSAKeySize)
+    RSAPubKey := RSAPrivKey.PublicKey
+
+    var DSSignKeyRes DSSignKey
+    DSSignKeyRes.KeyType = "DS"
+    DSSignKeyRes.PrivKey = *RSAPrivKey
+
+    var DSVerifyKeyRes DSVerifyKey
+    DSVerifyKeyRes.KeyType = "DS"
+    DSVerifyKeyRes.PubKey = RSAPubKey
+
+    return DSSignKeyRes, DSVerifyKeyRes, err
+}
+
+// Signs a byte stream via SHA256 and PKCS1v15
+func DSSign(sk DSSignKey, msg []byte) ([]byte, error) {
+    RSAPrivKey := &sk.PrivKey
+
+    if sk.KeyType != "DS" {
+        return nil, errors.New("Using a non-DS key for DS.")
+    }
+
+    hashed := sha512.Sum512(msg)
+
+    sig, err := rsa.SignPKCS1v15(rand.Reader, RSAPrivKey, crypto.SHA512, hashed[:])
+
+    return sig, err
+}
+
+// Verifies a signature signed with SHA256 and PKCS1v15
+func DSVerify(vk DSVerifyKey, msg []byte, sig []byte) error {
+    RSAPubKey := &vk.PubKey
+
+    if vk.KeyType != "DS" {
+        return errors.New("Using a non-DS key for DS.")
+    }
+
+    hashed := sha512.Sum512(msg)
+
+    err := rsa.VerifyPKCS1v15(RSAPubKey, crypto.SHA512, hashed[:], sig)
+
+    return err
+}
+
+
+/*
+********************************************
+**                HMAC                    **
+**         HMACEval, HMACEqual            **
+********************************************
+*/
+
+// Evaluate the HMAC using sha512
+func HMACEval(key []byte, msg []byte) ([]byte, error) {
+    if len(key) != 16 && len(key) != 24 && len(key) != 32 {
+       panic(errors.New("The input as key for HMAC should be a 16-byte key."))
+    }
+
+    mac := hmac.New(sha512.New, key)
+    mac.Write(msg)
+    res := mac.Sum(nil)
+
+    return res, nil
+}
+
+// Equals comparison for hashes/MACs
+// Does NOT leak timing.
+func HMACEqual(a []byte, b []byte) bool {
+    return hmac.Equal(a, b)
+}
+
+
+/*
+********************************************
+**               KDF                      **
+**            Argon2Key                   **
+********************************************
+*/
+
+// Argon2:  Automatically choses a decent combination of iterations and memory
+// Use this to generate a key from a password
+func Argon2Key(password []byte, salt []byte, keyLen uint32) []byte {
+    return argon2.IDKey(password, salt, 1, 64*1024, 4, keyLen)
+}
+
+
+/*
+********************************************
+**        Symmetric Encryption            **
+**           SymEnc, SymDec               **
+********************************************
+*/
+
+// Encrypts a byte slice with AES-CTR
+// Length of iv should be == AESBlockSize
+func SymEnc(key []byte, iv []byte, plaintext []byte) []byte {
+    if len(iv) != AESBlockSize {
+        panic("IV length not equal to AESBlockSize")
+    }
+
+    block, err := aes.NewCipher(key)
+    if err != nil {
+        panic(err)
+    }
+
+    stream := cipher.NewCTR(block, iv)
+    ciphertext := make([]byte, AESBlockSize + len(plaintext))
+    copy(ciphertext[:AESBlockSize], iv)
+
+    stream.XORKeyStream(ciphertext[AESBlockSize:], plaintext)
+
+    return ciphertext
+}
+
+// Decrypts a ciphertext encrypted with AES-CTR
+func SymDec(key []byte, ciphertext []byte) []byte {
+    block, err := aes.NewCipher(key)
+    if err != nil {
+        panic(err)
+    }
+
+    iv := ciphertext[:AESBlockSize]
+    plaintext := make([]byte, len(ciphertext) - AESBlockSize)
+    stream := cipher.NewCTR(block, iv)
+
+    stream.XORKeyStream(plaintext, ciphertext[aes.BlockSize:])
+
+    return plaintext
+}
diff --git a/proj2/userlib/userlib_test.go b/proj2/userlib/userlib_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..71b9cc64c3596fda72a8cd99ffe7279b81fba67b
--- /dev/null
+++ b/proj2/userlib/userlib_test.go
@@ -0,0 +1,238 @@
+package userlib
+
+import "testing"
+import "bytes"
+import "encoding/hex"
+import "github.com/google/uuid"
+
+// Golang has a very powerful routine for building tests.
+
+// Run with "go test" to run the tests
+
+// And "go test -v" to run verbosely so you see all the logging and
+// what tests pass/fail individually.
+
+// And "go test -cover" to check your code coverage in your tests
+
+// Default test strings
+var key1 []byte = []byte("cs161teststring1")
+var key2 []byte = []byte("cs161teststring2")
+var key3 []byte = []byte("cs161teststring3")
+var key4 []byte = []byte("cs161teststring4")
+var key5 []byte = []byte("cs161teststring5")
+
+// Creates a UUID from the supplied bytes
+// Use for testing only!
+func UUIDFromBytes(t *testing.T, b []byte) (u UUID) {
+    u, err := uuid.FromBytes(b)
+    if err != nil {
+        t.Error("Got FromBytes error:", err)
+    }
+
+    return
+}
+
+func TestUUIDFromBytesDeterministic(t *testing.T) {
+    UUID1 := UUIDFromBytes(t, key1)
+    t.Log(UUID1)
+
+    UUID2 := UUIDFromBytes(t, key1)
+    t.Log(UUID2)
+
+    if UUID1 != UUID2 {
+        t.Error("UUID1 != UUID2")
+        t.Log("UUID1:", UUID1)
+        t.Log("UUID2:", UUID2)
+    }
+}
+
+func TestDatastore(t *testing.T) {
+    UUID1 := UUIDFromBytes(t, key1)
+    UUID2 := UUIDFromBytes(t, key2)
+    UUID3 := UUIDFromBytes(t, key3)
+
+    DatastoreSet(UUID1, []byte("foo"))
+
+    _, valid := DatastoreGet(UUID3)
+    if valid {
+        t.Error("Datastore fetched UUID3 when it wasn't supposed to")
+    }
+
+    data, valid := DatastoreGet(UUID1)
+    if !valid || string(data) != "foo" {
+        t.Error("Error with fetching 'foo' from UUID1")
+    }
+
+    _, valid = DatastoreGet(UUID3)
+    if valid {
+        t.Error("Returned when nothing, oops")
+    }
+
+    DatastoreSet(UUID2, []byte("bar"))
+
+    data, valid = DatastoreGet(UUID1)
+    if !valid || string(data) != "foo" {
+        t.Error("Error with fetching 'foo' from UUID1")
+    }
+
+    DatastoreDelete(UUID1)
+
+    _, valid = DatastoreGet(UUID1)
+    if valid {
+        t.Error("DatastoreGet succeeded even after deleting UUID1")
+    }
+
+    data, valid = DatastoreGet(UUID2)
+    if !valid || string(data) != "bar" {
+        t.Error("Error with fetching 'bar' from UUID2")
+    }
+
+    DatastoreClear()
+
+    _, valid = DatastoreGet(UUID2)
+    if valid {
+        t.Error("DatastoreGet succeeded even after DatastoreClear")
+    }
+
+    t.Log("Datastore fetch", data)
+    t.Log("Datastore map", DatastoreGetMap())
+    DatastoreClear()
+    t.Log("Datastore map", DatastoreGetMap())
+}
+
+func TestKeystore(t *testing.T) {
+    RSAPubKey, _, err1 := PKEKeyGen()
+    _, DSVerifyKey, err2 := DSKeyGen()
+
+    if err1 != nil || err2 != nil {
+        t.Error("PKEKeyGen() failed")
+    }
+
+    KeystoreSet("user1", RSAPubKey)
+    KeystoreSet("user2", DSVerifyKey)
+
+    _, valid := KeystoreGet("user3")
+    if valid {
+        t.Error("Keystore fetched UUID3 when it wasn't supposed to")
+    }
+
+    data, valid := KeystoreGet("user1")
+    if !valid {
+        t.Error("Key stored at UUID1 doesn't match")
+    }
+
+    data, valid = KeystoreGet("user2")
+    if !valid {
+        t.Error("Key stored at UUID2 doesn't match")
+    }
+
+    KeystoreClear()
+
+    _, valid = KeystoreGet("user1")
+    if valid {
+        t.Error("KeystoreGet succeeded even after KeystoreClear")
+    }
+
+    t.Log("Keystore fetch", data)
+    t.Log("Keystore map", KeystoreGetMap())
+    KeystoreClear()
+    t.Log("Keystore map", KeystoreGetMap())
+}
+
+func TestRSA(t *testing.T) {
+
+    // Test RSA Encrypt and Decrypt
+    RSAPubKey, RSAPrivKey, err := PKEKeyGen()
+    if err != nil {
+        t.Error("PKEKeyGen() failed", err)
+    }
+
+    t.Log(RSAPubKey)
+    ciphertext, err := PKEEnc(RSAPubKey, []byte("Squeamish Ossifrage"))
+    if err != nil {
+        t.Error("PKEEnc() error", err)
+    }
+
+    decryption, err := PKEDec(RSAPrivKey, ciphertext)
+    if err != nil || (string(decryption) != "Squeamish Ossifrage") {
+        t.Error("Decryption failed", err)
+    }
+
+    // Test RSA Sign and Verify
+    DSSignKey, DSVerifyKey, err := DSKeyGen()
+    if err != nil {
+        t.Error("DSKeyGen() failed", err)
+    }
+
+    sign, err := DSSign(DSSignKey, []byte("Squeamish Ossifrage"))
+    if err != nil {
+        t.Error("RSA sign failure")
+    }
+
+    err = DSVerify(DSVerifyKey, []byte("Squeamish Ossifrage"), sign)
+    if err != nil {
+        t.Error("RSA verification failure")
+    }
+
+    err = DSVerify(DSVerifyKey, []byte("foo"), sign)
+    if err == nil {
+        t.Error("RSA verification worked when it shouldn't")
+    }
+
+    t.Log("Error return", err)
+}
+
+func TestHMAC(t *testing.T) {
+    msga := []byte("foo")
+    msgb := []byte("bar")
+
+    hmac1a, _ := HMACEval(key1, msga)
+    hmac1b, _ := HMACEval(key1, msgb)
+    if HMACEqual(hmac1a, hmac1b) {
+        t.Error("HMACs are equal for different data")
+    }
+
+    hmac2a, _ := HMACEval(key2, msga)
+    if HMACEqual(hmac1a, hmac2a) {
+        t.Error("HMACs are equal for different key")
+    }
+
+    hmac1a2, _ := HMACEval(key1, msga)
+    if !HMACEqual(hmac1a, hmac1a2) {
+        t.Error("HMACs are not equal when they should be")
+    }
+}
+
+func TestArgon2(t *testing.T) {
+    val1 := Argon2Key([]byte("Password"), []byte("nosalt"), 32)
+    val2 := Argon2Key([]byte("Password"), []byte("nosalt"), 64)
+    val3 := Argon2Key([]byte("password"), []byte("nosalt"), 32)
+
+    equal := bytes.Equal
+
+    if equal(val1, val2) || equal(val1, val3) || equal(val2, val3) {
+        t.Error("Argon2 problem")
+    }
+    t.Log(hex.EncodeToString(val1))
+    t.Log(hex.EncodeToString(val2))
+    t.Log(hex.EncodeToString(val3))
+}
+
+func TestStreamCipher(t *testing.T) {
+    iv := RandomBytes(16)
+    t.Log("Random IV", iv)
+
+    ciphertext := SymEnc(key1, iv, []byte("foo"))
+    decryption := SymDec(key1, ciphertext)
+
+    t.Log("Decrypted messagege:", string(decryption))
+    if string(decryption) != "foo" {
+        t.Error("Symmetric decryption failure")
+    }
+}
+
+// Deliberate fail example
+// func TestFailure(t *testing.T){
+//	t.Log("This test will fail")
+//	t.Error("Test of failure")
+//}