diff --git a/api/client_test.go b/api/client_test.go
index 01dff2c7cc9aec25427124273f00a2f7f7706e4a..56179e68a0da3c946754eb1684bc1c61f0929d86 100644
--- a/api/client_test.go
+++ b/api/client_test.go
@@ -11,6 +11,7 @@ import (
 	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/io"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/keyStore"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/storage"
@@ -129,7 +130,7 @@ func TestNewClient(t *testing.T) {
 func TestParse(t *testing.T) {
 	ms := parse.Message{}
 	ms.Body = []byte{0, 1, 2}
-	ms.MessageType = int32(cmixproto.Type_NO_TYPE)
+	ms.MessageType = int32(keyExchange.Type_NO_TYPE)
 	ms.Receiver = &id.ZeroUser
 	ms.Sender = &id.ZeroUser
 
diff --git a/api/mockserver.go b/api/mockserver.go
index 5405c8277631c7bb60c26ca5f99ae16790e970e1..9d0de5000345256ffa40f738169e258657d000ea 100644
--- a/api/mockserver.go
+++ b/api/mockserver.go
@@ -11,8 +11,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/parse"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/crypto/cyclic"
@@ -55,7 +55,7 @@ func (m APIMessage) GetPayload() []byte {
 }
 
 func (m APIMessage) GetMessageType() int32 {
-	return int32(cmixproto.Type_NO_TYPE)
+	return int32(keyExchange.Type_NO_TYPE)
 }
 
 func (m APIMessage) GetCryptoType() parse.CryptoType {
diff --git a/bindings/client_test.go b/bindings/client_test.go
index 90c0a01ba26efcb7431a1f894d2c3f95039c4a91..71975246acd7ebabb21c3c55538b3f338118a994 100644
--- a/bindings/client_test.go
+++ b/bindings/client_test.go
@@ -13,9 +13,9 @@ import (
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/io"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/user"
@@ -493,7 +493,7 @@ func TestListen(t *testing.T) {
 	}
 
 	listener := MockListener(false)
-	client.Listen(id.ZeroUser[:], int32(cmixproto.Type_NO_TYPE), &listener)
+	client.Listen(id.ZeroUser[:], int32(keyExchange.Type_NO_TYPE), &listener)
 	client.client.GetSwitchboard().Speak(&parse.Message{
 		TypedBody: parse.TypedBody{
 			MessageType: 0,
@@ -542,7 +542,7 @@ func TestStopListening(t *testing.T) {
 	}
 
 	listener := MockListener(false)
-	handle, err := client.Listen(id.ZeroUser[:], int32(cmixproto.Type_NO_TYPE), &listener)
+	handle, err := client.Listen(id.ZeroUser[:], int32(keyExchange.Type_NO_TYPE), &listener)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -582,7 +582,7 @@ func TestSetLogOutput(t *testing.T) {
 func TestParse(t *testing.T) {
 	ms := parse.Message{}
 	ms.Body = []byte{0, 1, 2}
-	ms.MessageType = int32(cmixproto.Type_NO_TYPE)
+	ms.MessageType = int32(keyExchange.Type_NO_TYPE)
 	ms.Receiver = &id.ZeroUser
 	ms.Sender = &id.ZeroUser
 
diff --git a/bots/bots.go b/bots/bots.go
index 8c49607787b9644cb884a35c98039d27e0a2046a..2af12fcee1cb7c33833a1f126e30ef03a6a7d066 100644
--- a/bots/bots.go
+++ b/bots/bots.go
@@ -4,6 +4,7 @@ import (
 	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/io"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/user"
@@ -81,13 +82,13 @@ func InitBots(s user.Session, s2 storage.Session, m io.Communications,
 
 	l := m.GetSwitchboard()
 
-	l.Register(&id.UDB, int32(cmixproto.Type_UDB_PUSH_KEY_RESPONSE),
+	l.Register(&id.UDB, int32(keyExchange.Type_UDB_PUSH_KEY_RESPONSE),
 		&pushKeyResponseListener)
-	l.Register(&id.UDB, int32(cmixproto.Type_UDB_GET_KEY_RESPONSE),
+	l.Register(&id.UDB, int32(keyExchange.Type_UDB_GET_KEY_RESPONSE),
 		&getKeyResponseListener)
-	l.Register(&id.UDB, int32(cmixproto.Type_UDB_REGISTER_RESPONSE),
+	l.Register(&id.UDB, int32(keyExchange.Type_UDB_REGISTER_RESPONSE),
 		&registerResponseListener)
-	l.Register(&id.UDB, int32(cmixproto.Type_UDB_SEARCH_RESPONSE),
+	l.Register(&id.UDB, int32(keyExchange.Type_UDB_SEARCH_RESPONSE),
 		&searchResponseListener)
 	l.Register(&id.ZeroUser,
 		int32(cmixproto.Type_NICKNAME_REQUEST), &nicknameRequestListener)
diff --git a/bots/userDiscovery.go b/bots/userDiscovery.go
index 74db2a4557429aa245052b9da78d39646c76ab71..bc474d92bf9594c67e1354160d5faa7d44975d26 100644
--- a/bots/userDiscovery.go
+++ b/bots/userDiscovery.go
@@ -13,8 +13,8 @@ import (
 	"encoding/base64"
 	"fmt"
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/crypto/hash"
@@ -77,7 +77,7 @@ func Register(valueType, value string, publicKey []byte, regStatus func(int), ti
 
 	//send the user information to udb
 	msgBody := parse.Pack(&parse.TypedBody{
-		MessageType: int32(cmixproto.Type_UDB_REGISTER),
+		MessageType: int32(keyExchange.Type_UDB_REGISTER),
 		Body:        []byte(fmt.Sprintf("%s %s %s", valueType, value, keyFP)),
 	})
 
@@ -131,7 +131,7 @@ func Search(valueType, value string, searchStatus func(int), timeout time.Durati
 	searchStatus(globals.UDB_SEARCH_LOOK)
 
 	msgBody := parse.Pack(&parse.TypedBody{
-		MessageType: int32(cmixproto.Type_UDB_SEARCH),
+		MessageType: int32(keyExchange.Type_UDB_SEARCH),
 		Body:        []byte(fmt.Sprintf("%s %s", valueType, value)),
 	})
 	err = sendCommand(&id.UDB, msgBody)
@@ -170,7 +170,7 @@ func Search(valueType, value string, searchStatus func(int), timeout time.Durati
 
 	// Get the full key and decode it
 	msgBody = parse.Pack(&parse.TypedBody{
-		MessageType: int32(cmixproto.Type_UDB_GET_KEY),
+		MessageType: int32(keyExchange.Type_UDB_GET_KEY),
 		Body:        []byte(keyFP),
 	})
 	err = sendCommand(&id.UDB, msgBody)
@@ -270,7 +270,7 @@ func pushKey(keyFP string, publicKey []byte) error {
 	pushKeyMsg := fmt.Sprintf("%s %s", keyFP, publicKeyString)
 
 	return sendCommand(&id.UDB, parse.Pack(&parse.TypedBody{
-		MessageType: int32(cmixproto.Type_UDB_PUSH_KEY),
+		MessageType: int32(keyExchange.Type_UDB_PUSH_KEY),
 		Body:        []byte(pushKeyMsg),
 	}))
 }
diff --git a/cmd/root.go b/cmd/root.go
index 8f6413d7fc4c26baf7336c95e789e0418bc8a1b7..928473fbe031959be6e6da372a6b98c3e0921c89 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -19,6 +19,7 @@ import (
 	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/io"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/user"
 	"gitlab.com/elixxir/client/userRegistry"
@@ -414,11 +415,11 @@ var rootCmd = &cobra.Command{
 		// the integration test
 		// Normal text messages
 		text := TextListener{}
-		client.Listen(&id.ZeroUser, int32(cmixproto.Type_TEXT_MESSAGE),
+		client.Listen(&id.ZeroUser, int32(keyExchange.Type_TEXT_MESSAGE),
 			&text)
 		// All other messages
 		fallback := FallbackListener{}
-		client.Listen(&id.ZeroUser, int32(cmixproto.Type_NO_TYPE),
+		client.Listen(&id.ZeroUser, int32(keyExchange.Type_NO_TYPE),
 			&fallback)
 
 		// Log the user in, for now using the first gateway specified
@@ -513,7 +514,7 @@ var rootCmd = &cobra.Command{
 					err := client.Send(&parse.Message{
 						Sender: userID,
 						TypedBody: parse.TypedBody{
-							MessageType: int32(cmixproto.Type_TEXT_MESSAGE),
+							MessageType: int32(keyExchange.Type_TEXT_MESSAGE),
 							Body:        wireOut,
 						},
 						InferredType: cryptoType,
diff --git a/cmixproto/generate.sh b/cmixproto/generate.sh
deleted file mode 100755
index 06e52ef847ad9a007c2ed67b9a3c9fce9cc68230..0000000000000000000000000000000000000000
--- a/cmixproto/generate.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-protoc --go_out=. types.proto
diff --git a/cmixproto/types.pb.go b/cmixproto/types.pb.go
deleted file mode 100644
index bfd3993996f5e065b82d61c18b785904f598ebdb..0000000000000000000000000000000000000000
--- a/cmixproto/types.pb.go
+++ /dev/null
@@ -1,304 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2018 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
-////////////////////////////////////////////////////////////////////////////////
-
-// Call ./generate.sh to generate the protocol buffer code
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        (unknown)
-// source: types.proto
-
-package cmixproto
-
-import (
-	proto "github.com/golang/protobuf/proto"
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	reflect "reflect"
-	sync "sync"
-)
-
-const (
-	// Verify that this generated code is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
-	// Verify that runtime/protoimpl is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
-type Type int32
-
-const (
-	// Used as a wildcard for listeners to listen to all existing types.
-	// Think of it as "No type in particular"
-	Type_NO_TYPE Type = 0
-	// See proto buf documentation below
-	Type_TEXT_MESSAGE Type = 1
-	// Second field is the key data itself. This should be 2048 bits long
-	// (according to the message length that our prime allows) and is
-	// base64-encoded.
-	Type_UDB_PUSH_KEY Type = 10
-	// The push key response message is a string. If the key push was a
-	// success, the UDB should respond with a message that starts with "PUSHKEY
-	// COMPLETE", followed by the fingerprint of the key that was pushed.
-	// If the response doesn't begin with "PUSHKEY COMPLETE", the message is
-	// an error message and should be shown to the user.
-	Type_UDB_PUSH_KEY_RESPONSE Type = 11
-	// The get key message includes a single string field with the key
-	// fingerprint of the key that needs gettin'. This is the same fingerprint
-	// you would have pushed.
-	Type_UDB_GET_KEY Type = 12
-	// The get key response message is a string. The first space-separated
-	// field should always be "GETKEY". The second field is the fingerprint of
-	// the key. The third field is "NOTFOUND" if the UDB didn't find the key,
-	// or the key itself, encoded in base64, otherwise.
-	Type_UDB_GET_KEY_RESPONSE Type = 13
-	// To wit: The first argument in the list of space-separated fields is
-	// the type of the registration. Currently the only allowed type is
-	// "EMAIL". The second argument is the value of the type you're registering
-	// with. In all currently acceptable registration types, this would be an
-	// email address. If you could register with your phone, it would be your
-	// phone number, and so on. Then, the key fingerprint of the user's key is
-	// the third argument. To register successfully, you must have already
-	// pushed the key with that fingerprint.
-	Type_UDB_REGISTER Type = 14
-	// The registration response is just a string. It will be either an error
-	// message to show to the user, or the message "REGISTRATION COMPLETE" if
-	// registration was successful.
-	Type_UDB_REGISTER_RESPONSE Type = 15
-	// The search message is just another space separated list. The first field
-	// will contain the type of registered user you're searching for, namely
-	// "EMAIL". The second field with contain the value of that type that
-	// you're searching for.
-	Type_UDB_SEARCH Type = 16
-	// The search response is a list of fields. The first is always "SEARCH".
-	// The second is always the value that the user searched for. The third is
-	// "FOUND" or "NOTFOUND" depending on whether the UDB found the user. If
-	// the user was FOUND, the last field will contain their key fingerprint,
-	// which you can use with GET_KEY to get the keys you need to talk with
-	// that user. Otherwise, this fourth field won't exist.
-	Type_UDB_SEARCH_RESPONSE Type = 17
-	// End to End Rekey message types
-	// Trigger a rekey, this message is used locally in client only
-	Type_REKEY_TRIGGER Type = 30
-	// Rekey confirmation message. Sent by partner to confirm completion of a rekey
-	Type_REKEY_CONFIRM Type = 31
-)
-
-// Enum value maps for Type.
-var (
-	Type_name = map[int32]string{
-		0:  "NO_TYPE",
-		1:  "TEXT_MESSAGE",
-		10: "UDB_PUSH_KEY",
-		11: "UDB_PUSH_KEY_RESPONSE",
-		12: "UDB_GET_KEY",
-		13: "UDB_GET_KEY_RESPONSE",
-		14: "UDB_REGISTER",
-		15: "UDB_REGISTER_RESPONSE",
-		16: "UDB_SEARCH",
-		17: "UDB_SEARCH_RESPONSE",
-		30: "REKEY_TRIGGER",
-		31: "REKEY_CONFIRM",
-	}
-	Type_value = map[string]int32{
-		"NO_TYPE":               0,
-		"TEXT_MESSAGE":          1,
-		"UDB_PUSH_KEY":          10,
-		"UDB_PUSH_KEY_RESPONSE": 11,
-		"UDB_GET_KEY":           12,
-		"UDB_GET_KEY_RESPONSE":  13,
-		"UDB_REGISTER":          14,
-		"UDB_REGISTER_RESPONSE": 15,
-		"UDB_SEARCH":            16,
-		"UDB_SEARCH_RESPONSE":   17,
-		"REKEY_TRIGGER":         30,
-		"REKEY_CONFIRM":         31,
-	}
-)
-
-func (x Type) Enum() *Type {
-	p := new(Type)
-	*p = x
-	return p
-}
-
-func (x Type) String() string {
-	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (Type) Descriptor() protoreflect.EnumDescriptor {
-	return file_types_proto_enumTypes[0].Descriptor()
-}
-
-func (Type) Type() protoreflect.EnumType {
-	return &file_types_proto_enumTypes[0]
-}
-
-func (x Type) Number() protoreflect.EnumNumber {
-	return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use Type.Descriptor instead.
-func (Type) EnumDescriptor() ([]byte, []int) {
-	return file_types_proto_rawDescGZIP(), []int{0}
-}
-
-type RekeyTrigger struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	// PublicKey used in the registration
-	PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"`
-	// ID of the session used to create this session
-	SessionID []byte `protobuf:"bytes,2,opt,name=SessionID,json=sessionID,proto3" json:"SessionID,omitempty"`
-}
-
-func (x *RekeyTrigger) Reset() {
-	*x = RekeyTrigger{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_types_proto_msgTypes[0]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *RekeyTrigger) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*RekeyTrigger) ProtoMessage() {}
-
-func (x *RekeyTrigger) ProtoReflect() protoreflect.Message {
-	mi := &file_types_proto_msgTypes[0]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use RekeyTrigger.ProtoReflect.Descriptor instead.
-func (*RekeyTrigger) Descriptor() ([]byte, []int) {
-	return file_types_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *RekeyTrigger) GetPublicKey() []byte {
-	if x != nil {
-		return x.PublicKey
-	}
-	return nil
-}
-
-func (x *RekeyTrigger) GetSessionID() []byte {
-	if x != nil {
-		return x.SessionID
-	}
-	return nil
-}
-
-var File_types_proto protoreflect.FileDescriptor
-
-var file_types_proto_rawDesc = []byte{
-	0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70,
-	0x61, 0x72, 0x73, 0x65, 0x22, 0x4a, 0x0a, 0x0c, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x54, 0x72, 0x69,
-	0x67, 0x67, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
-	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
-	0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44,
-	0x2a, 0xf9, 0x01, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x5f,
-	0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x45, 0x58, 0x54, 0x5f, 0x4d,
-	0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x44, 0x42, 0x5f,
-	0x50, 0x55, 0x53, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x0a, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x44,
-	0x42, 0x5f, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f,
-	0x4e, 0x53, 0x45, 0x10, 0x0b, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x44, 0x42, 0x5f, 0x47, 0x45, 0x54,
-	0x5f, 0x4b, 0x45, 0x59, 0x10, 0x0c, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x44, 0x42, 0x5f, 0x47, 0x45,
-	0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x0d,
-	0x12, 0x10, 0x0a, 0x0c, 0x55, 0x44, 0x42, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52,
-	0x10, 0x0e, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x44, 0x42, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54,
-	0x45, 0x52, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x0f, 0x12, 0x0e, 0x0a,
-	0x0a, 0x55, 0x44, 0x42, 0x5f, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x10, 0x10, 0x12, 0x17, 0x0a,
-	0x13, 0x55, 0x44, 0x42, 0x5f, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x52, 0x45, 0x53, 0x50,
-	0x4f, 0x4e, 0x53, 0x45, 0x10, 0x11, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4b, 0x45, 0x59, 0x5f,
-	0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x10, 0x1e, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4b,
-	0x45, 0x59, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x10, 0x1f, 0x42, 0x0b, 0x5a, 0x09,
-	0x63, 0x6d, 0x69, 0x78, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x33,
-}
-
-var (
-	file_types_proto_rawDescOnce sync.Once
-	file_types_proto_rawDescData = file_types_proto_rawDesc
-)
-
-func file_types_proto_rawDescGZIP() []byte {
-	file_types_proto_rawDescOnce.Do(func() {
-		file_types_proto_rawDescData = protoimpl.X.CompressGZIP(file_types_proto_rawDescData)
-	})
-	return file_types_proto_rawDescData
-}
-
-var file_types_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_types_proto_goTypes = []interface{}{
-	(Type)(0),            // 0: parse.Type
-	(*RekeyTrigger)(nil), // 1: parse.RekeyTrigger
-}
-var file_types_proto_depIdxs = []int32{
-	0, // [0:0] is the sub-list for method output_type
-	0, // [0:0] is the sub-list for method input_type
-	0, // [0:0] is the sub-list for extension type_name
-	0, // [0:0] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_types_proto_init() }
-func file_types_proto_init() {
-	if File_types_proto != nil {
-		return
-	}
-	if !protoimpl.UnsafeEnabled {
-		file_types_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*RekeyTrigger); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-	}
-	type x struct{}
-	out := protoimpl.TypeBuilder{
-		File: protoimpl.DescBuilder{
-			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_types_proto_rawDesc,
-			NumEnums:      1,
-			NumMessages:   1,
-			NumExtensions: 0,
-			NumServices:   0,
-		},
-		GoTypes:           file_types_proto_goTypes,
-		DependencyIndexes: file_types_proto_depIdxs,
-		EnumInfos:         file_types_proto_enumTypes,
-		MessageInfos:      file_types_proto_msgTypes,
-	}.Build()
-	File_types_proto = out.File
-	file_types_proto_rawDesc = nil
-	file_types_proto_goTypes = nil
-	file_types_proto_depIdxs = nil
-}
diff --git a/cmixproto/types.proto b/cmixproto/types.proto
deleted file mode 100644
index 57b5796e13641843d454bd8179882535bc87f0db..0000000000000000000000000000000000000000
--- a/cmixproto/types.proto
+++ /dev/null
@@ -1,114 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2018 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
-////////////////////////////////////////////////////////////////////////////////
-
-// Call ./generate.sh to generate the protocol buffer code
-
-syntax = "proto3";
-
-package parse;
-option go_package = "cmixproto";
-
-enum Type {
-    // Used as a wildcard for listeners to listen to all existing types.
-    // Think of it as "No type in particular"
-    NO_TYPE = 0;
-
-
-    // See proto buf documentation below
-    TEXT_MESSAGE = 1;
-
-    // None of the UDB message types are proto bufs because I haven't had time
-    // to migrate UDB fully to the new systems yet.
-
-    // I was considering migrating these types to proto bufs to make them more
-    // compact for transmission, but you would have to compress them to even
-    // have a chance of fitting the whole key in one Cmix message. In any case,
-    // I don't think the benefit is there for the time investment.
-
-    // The prefixes of the UDB response messages are made redundant by the
-    // message types in this very enumeration, so at some point we can remove
-    // them from the UDB code that generates the responses.
-
-
-    // The push key message includes two string fields, separated by a space.
-    
-    // First field is the key fingerprint, which the UDB uses as an key into
-    // the map of, uhh, the keys. This can be any string that doesn't have a
-    // space in it.
-    
-    // Second field is the key data itself. This should be 2048 bits long
-    // (according to the message length that our prime allows) and is
-    // base64-encoded.
-    UDB_PUSH_KEY = 10;
-    // The push key response message is a string. If the key push was a
-    // success, the UDB should respond with a message that starts with "PUSHKEY
-    // COMPLETE", followed by the fingerprint of the key that was pushed.
-    // If the response doesn't begin with "PUSHKEY COMPLETE", the message is
-    // an error message and should be shown to the user.
-    UDB_PUSH_KEY_RESPONSE = 11;
-    // The get key message includes a single string field with the key
-    // fingerprint of the key that needs gettin'. This is the same fingerprint
-    // you would have pushed.
-    UDB_GET_KEY = 12;
-    // The get key response message is a string. The first space-separated
-    // field should always be "GETKEY". The second field is the fingerprint of
-    // the key. The third field is "NOTFOUND" if the UDB didn't find the key,
-    // or the key itself, encoded in base64, otherwise.
-    UDB_GET_KEY_RESPONSE = 13;
-    // The register message is unchanged from the OG UDB code, except that
-    // the REGISTER command in front has been replaced with the type string
-    // corresponding to this entry in the enumeration.
-
-    // To wit: The first argument in the list of space-separated fields is
-    // the type of the registration. Currently the only allowed type is
-    // "EMAIL". The second argument is the value of the type you're registering
-    // with. In all currently acceptable registration types, this would be an
-    // email address. If you could register with your phone, it would be your
-    // phone number, and so on. Then, the key fingerprint of the user's key is
-    // the third argument. To register successfully, you must have already
-    // pushed the key with that fingerprint.
-    UDB_REGISTER = 14;
-    // The registration response is just a string. It will be either an error
-    // message to show to the user, or the message "REGISTRATION COMPLETE" if
-    // registration was successful.
-    UDB_REGISTER_RESPONSE = 15;
-    // The search message is just another space separated list. The first field
-    // will contain the type of registered user you're searching for, namely
-    // "EMAIL". The second field with contain the value of that type that
-    // you're searching for.
-    UDB_SEARCH = 16;
-    // The search response is a list of fields. The first is always "SEARCH".
-    // The second is always the value that the user searched for. The third is
-    // "FOUND" or "NOTFOUND" depending on whether the UDB found the user. If
-    // the user was FOUND, the last field will contain their key fingerprint,
-    // which you can use with GET_KEY to get the keys you need to talk with
-    // that user. Otherwise, this fourth field won't exist.
-    UDB_SEARCH_RESPONSE = 17;
-
-
-    // The client sends payment transaction messages to the payment bot to
-    // fund compound coins with seed coins. In the current implementation,
-    // there's one compound that gets funded that's from the payee. This comes
-    // across in a PAYMENT_INVOICE. And there's a second compound that contains
-    // the change from the seeds that the payer is using to fund the invoice.
-    // The rest are the seeds that are the source of the payment.
-
-    // All of the seeds and compounds are in an ordered list, and they get
-    // categorized and processed on the payment bot.
-
-    // End to End Rekey message types
-    // Trigger a rekey, this message is used locally in client only
-    REKEY_TRIGGER = 30;
-    // Rekey confirmation message. Sent by partner to confirm completion of a rekey
-    REKEY_CONFIRM = 31;
-}
-
-message RekeyTrigger {
-    // PublicKey used in the registration
-    bytes publicKey = 1;
-    // ID of the session used to create this session
-    bytes SessionID = 2;
-}
diff --git a/context/context.go b/context/context.go
index 0d50cdcd2c966f8743285d68f43232db2bd9ad93..c9de4b8781eed4f47c21c994bbae81027fe0f977 100644
--- a/context/context.go
+++ b/context/context.go
@@ -1,8 +1,8 @@
 package context
 
 import (
+	"gitlab.com/elixxir/client/context/switchboard"
 	"gitlab.com/elixxir/client/storage"
-	"gitlab.com/elixxir/primitives/switchboard"
 )
 
 type Context struct {
diff --git a/context/message/encryptionType.go b/context/message/encryptionType.go
new file mode 100644
index 0000000000000000000000000000000000000000..5afdd855a60f68dbf89a2e331edc05c3c7907384
--- /dev/null
+++ b/context/message/encryptionType.go
@@ -0,0 +1,8 @@
+package message
+
+type EncryptionType uint8
+
+const (
+	None EncryptionType = 0
+	E2E  EncryptionType = 1
+)
diff --git a/context/message/receiveMessage.go b/context/message/receiveMessage.go
new file mode 100644
index 0000000000000000000000000000000000000000..71fbca259e9e7d341fce76bce8968f79a5c03d6f
--- /dev/null
+++ b/context/message/receiveMessage.go
@@ -0,0 +1,15 @@
+package message
+
+import (
+	"gitlab.com/xx_network/primitives/id"
+	"time"
+)
+
+type Receive struct {
+	Recipient   *id.ID
+	Payload     []byte
+	MessageType Type
+	Sender      *id.ID
+	Timestamp   time.Time
+	Encryption  EncryptionType
+}
diff --git a/context/message/message.go b/context/message/sendMessage.go
similarity index 71%
rename from context/message/message.go
rename to context/message/sendMessage.go
index 604c5c162664dcfd6c6c93e865aa886d3faf9074..1e639669f607ba0b9dbc26918bca3e6b0617d5b9 100644
--- a/context/message/message.go
+++ b/context/message/sendMessage.go
@@ -2,8 +2,8 @@ package message
 
 import "gitlab.com/xx_network/primitives/id"
 
-type Message struct {
+type Send struct {
 	Recipient   *id.ID
 	Payload     []byte
-	MessageType int32
+	MessageType Type
 }
diff --git a/context/message/type.go b/context/message/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..a36645e3182f3dd1ee3bae408cc5233d95943441
--- /dev/null
+++ b/context/message/type.go
@@ -0,0 +1,97 @@
+package message
+
+const TypeLen = 4
+
+type Type uint32
+
+const (
+	// Used as a wildcard for listeners to listen to all existing types.
+	// Think of it as "No type in particular"
+	NoType Type = 0
+
+	//General text message, contains human readable text
+	Text Type = 1
+
+	// None of the UDB message types are proto bufs because I haven't had time
+	// to migrate UDB fully to the new systems yet.
+
+	// I was considering migrating these types to proto bufs to make them more
+	// compact for transmission, but you would have to compress them to even
+	// have a chance of fitting the whole key in one Cmix message. In any case,
+	// I don't think the benefit is there for the time investment.
+
+	// The prefixes of the UDB response messages are made redundant by the
+	// message types in this very enumeration, so at some point we can remove
+	// them from the UDB code that generates the responses.
+
+	// The push key message includes two string fields, separated by a space.
+
+	// First field is the key fingerprint, which the UDB uses as an key into
+	// the map of, uhh, the keys. This can be any string that doesn't have a
+	// space in it.
+
+	// Second field is the key data itself. This should be 2048 bits long
+	// (according to the message length that our prime allows) and is
+	// base64-encoded.
+	UdbPushKey = 10;
+	// The push key response message is a string. If the key push was a
+	// success, the UDB should respond with a message that starts with "PUSHKEY
+	// COMPLETE", followed by the fingerprint of the key that was pushed.
+	// If the response doesn't begin with "PUSHKEY COMPLETE", the message is
+	// an error message and should be shown to the user.
+	UdbPushKeyResponse = 11;
+	// The get key message includes a single string field with the key
+	// fingerprint of the key that needs gettin'. This is the same fingerprint
+	// you would have pushed.
+	UdbGetKey = 12;
+	// The get key response message is a string. The first space-separated
+	// field should always be "GETKEY". The second field is the fingerprint of
+	// the key. The third field is "NOTFOUND" if the UDB didn't find the key,
+	// or the key itself, encoded in base64, otherwise.
+	UdbGetKeyResponse = 13;
+	// The register message is unchanged from the OG UDB code, except that
+	// the REGISTER command in front has been replaced with the type string
+	// corresponding to this entry in the enumeration.
+
+	// To wit: The first argument in the list of space-separated fields is
+	// the type of the registration. Currently the only allowed type is
+	// "EMAIL". The second argument is the value of the type you're registering
+	// with. In all currently acceptable registration types, this would be an
+	// email address. If you could register with your phone, it would be your
+	// phone number, and so on. Then, the key fingerprint of the user's key is
+	// the third argument. To register successfully, you must have already
+	// pushed the key with that fingerprint.
+	UdbRegister = 14;
+	// The registration response is just a string. It will be either an error
+	// message to show to the user, or the message "REGISTRATION COMPLETE" if
+	// registration was successful.
+	UdbRegisterResponse = 15;
+	// The search message is just another space separated list. The first field
+	// will contain the type of registered user you're searching for, namely
+	// "EMAIL". The second field with contain the value of that type that
+	// you're searching for.
+	UdbSearch = 16;
+	// The search response is a list of fields. The first is always "SEARCH".
+	// The second is always the value that the user searched for. The third is
+	// "FOUND" or "NOTFOUND" depending on whether the UDB found the user. If
+	// the user was FOUND, the last field will contain their key fingerprint,
+	// which you can use with GET_KEY to get the keys you need to talk with
+	// that user. Otherwise, this fourth field won't exist.
+	UdbSearchResponse = 17;
+
+	// The client sends payment transaction messages to the payment bot to
+	// fund compound coins with seed coins. In the current implementation,
+	// there's one compound that gets funded that's from the payee. This comes
+	// across in a PAYMENT_INVOICE. And there's a second compound that contains
+	// the change from the seeds that the payer is using to fund the invoice.
+	// The rest are the seeds that are the source of the payment.
+
+	// All of the seeds and compounds are in an ordered list, and they get
+	// categorized and processed on the payment bot.
+
+	// End to End Rekey message types
+	// Trigger a rekey, this message is used locally in client only
+	KeyExchangeTrigger = 30;
+	// Rekey confirmation message. Sent by partner to confirm completion of a rekey
+	KeyExchangeConfirm = 31;
+)
diff --git a/context/networkManager.go b/context/networkManager.go
index 2287265152da53b01f6af7c6323da8f418db5e14..b585b946e668e780b9b5ea4832d62f9c967ab439 100644
--- a/context/networkManager.go
+++ b/context/networkManager.go
@@ -10,8 +10,8 @@ import (
 )
 
 type NetworkManager interface {
-	SendE2E(m message.Message, e2eP params.E2E, cmixP params.CMIX) ([]id.Round, error)
-	SendUnsafe(m message.Message) ([]id.Round, error)
+	SendE2E(m message.Send, e2eP params.E2E, cmixP params.CMIX) ([]id.Round, error)
+	SendUnsafe(m message.Send) ([]id.Round, error)
 	SendCMIX(message format.Message) (id.Round, error)
 	GetInstance() *network.Instance
 	Stoppable() stoppable.Stoppable
diff --git a/context/switchboard/any.go b/context/switchboard/any.go
new file mode 100644
index 0000000000000000000000000000000000000000..aef95e3780a5a917606cb0352a9bb44460977ea0
--- /dev/null
+++ b/context/switchboard/any.go
@@ -0,0 +1,14 @@
+package switchboard
+
+import (
+	"gitlab.com/elixxir/client/context/message"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// ID to respond to any message type
+const AnyType = message.NoType
+
+//ID to respond to any user
+func AnyUser() *id.ID {
+	return &id.ZeroUser
+}
diff --git a/context/switchboard/any_test.go b/context/switchboard/any_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..1f31bccd885ee97d19213812fb2b0cbfc1fd6a2a
--- /dev/null
+++ b/context/switchboard/any_test.go
@@ -0,0 +1,14 @@
+package switchboard
+
+import (
+	"gitlab.com/xx_network/primitives/id"
+	"testing"
+)
+
+//tests that AnyUser returns the correct user
+func TestAnyUser(t *testing.T) {
+	au := AnyUser()
+	if !au.Cmp(&id.ZeroUser) {
+		t.Errorf("Wrong user returned from AnyUser")
+	}
+}
diff --git a/context/switchboard/byID.go b/context/switchboard/byID.go
new file mode 100644
index 0000000000000000000000000000000000000000..ad7197452e80db9220a589f5c4a880caf15532e4
--- /dev/null
+++ b/context/switchboard/byID.go
@@ -0,0 +1,63 @@
+package switchboard
+
+import (
+	"github.com/golang-collections/collections/set"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type byId struct {
+	list    map[id.ID]*set.Set
+	generic *set.Set
+}
+
+// builds a new byID structure
+// registers an empty ID and the designated zero ID as generic
+func newById() *byId {
+	bi := &byId{
+		list:    make(map[id.ID]*set.Set),
+		generic: set.New(),
+	}
+
+	//make the zero IDs, which are defined as any, all point to the generic
+	bi.list[*AnyUser()] = bi.generic
+	bi.list[id.ID{}] = bi.generic
+
+	return bi
+}
+
+// returns a set associated with the passed ID unioned with the generic return
+func (bi *byId) Get(uid *id.ID) *set.Set {
+	lookup, ok := bi.list[*uid]
+	if !ok {
+		return bi.generic
+	} else {
+		return lookup.Union(bi.generic)
+	}
+}
+
+// adds a listener to a set for the given ID. Creates a new set to add it to if
+// the set does not exist
+func (bi *byId) Add(uid *id.ID, l Listener) *set.Set {
+	s, ok := bi.list[*uid]
+	if !ok {
+		s = set.New(l)
+		bi.list[*uid] = s
+	} else {
+		s.Insert(l)
+	}
+
+	return s
+}
+
+// Removes the passed listener from the set for UserID and
+// deletes the set if it is empty if the ID is not a generic one
+func (bi *byId) Remove(uid *id.ID, l Listener) {
+	s, ok := bi.list[*uid]
+	if ok {
+		s.Remove(l)
+
+		if s.Len() == 0 && !uid.Cmp(AnyUser()) && !uid.Cmp(&id.ID{}) {
+			delete(bi.list, *uid)
+		}
+	}
+}
diff --git a/context/switchboard/byID_test.go b/context/switchboard/byID_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..683a68f0a8ab3a10d989ba3425d87f9451e6c94b
--- /dev/null
+++ b/context/switchboard/byID_test.go
@@ -0,0 +1,308 @@
+package switchboard
+
+import (
+	"github.com/golang-collections/collections/set"
+	"gitlab.com/xx_network/primitives/id"
+	"testing"
+)
+
+// tests the newByID functions forms a properly constructed byId
+func TestById_newById(t *testing.T) {
+	nbi := newById()
+
+	if nbi.list == nil {
+		t.Errorf("No list created")
+	}
+
+	if nbi.generic == nil {
+		t.Errorf("No generic created")
+	}
+
+	if nbi.generic != nbi.list[id.ZeroUser] {
+		t.Errorf("zero user not registered as generic")
+	}
+
+	if nbi.generic != nbi.list[id.ID{}] {
+		t.Errorf("zero id not registered as generic")
+	}
+}
+
+// tests that when nothing has been added an empty set is returned
+func TestById_Get_Empty(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	s := nbi.Get(uid)
+
+	if s.Len() != 0 {
+		t.Errorf("Should not have returned a set")
+	}
+}
+
+//tests that getting a set for a specific ID returns that set
+func TestById_Get_Selected(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	set1 := set.New(0)
+
+	nbi.list[*uid] = set1
+
+	s := nbi.Get(uid)
+
+	if s.Len() == 0 {
+		t.Errorf("Should have returned a set")
+	}
+
+	if !s.SubsetOf(set1) || !set1.SubsetOf(s) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+// tests that when getting a specific ID which is not there returns the generic
+// set if is present
+func TestById_Get_Generic(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	nbi.generic.Insert(0)
+
+	s := nbi.Get(uid)
+
+	if s.Len() == 0 {
+		t.Errorf("Should have returned a set")
+	}
+
+	if !s.SubsetOf(nbi.generic) || !nbi.generic.SubsetOf(s) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+// tests that when getting a specific ID is there and there are elements
+// in the generic that the union of the two is returned
+func TestById_Get_GenericSelected(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	set1 := set.New(0)
+
+	nbi.list[*uid] = set1
+
+	nbi.generic.Insert(1)
+
+	s := nbi.Get(uid)
+
+	if s.Len() == 0 {
+		t.Errorf("Should have returned a set")
+	}
+
+	setUnion := set1.Union(nbi.generic)
+
+	if !s.SubsetOf(setUnion) || !setUnion.SubsetOf(s) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+// Tests that when adding to a set which does not exist, the set is created
+func TestById_Add_New(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	l := &funcListener{}
+
+	nbi.Add(uid, l)
+
+	s := nbi.list[*uid]
+
+	if s.Len() != 1 {
+		t.Errorf("Should a set of the wrong size")
+	}
+
+	if !s.Has(l) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+// Tests that when adding to a set which does exist, the set is retained and
+// added to
+func TestById_Add_Old(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	l1 := &funcListener{}
+	l2 := &funcListener{}
+
+	set1 := set.New(l1)
+
+	nbi.list[*uid] = set1
+
+	nbi.Add(uid, l2)
+
+	s := nbi.list[*uid]
+
+	if s.Len() != 2 {
+		t.Errorf("Should have returned a set")
+	}
+
+	if !s.Has(l1) {
+		t.Errorf("Set does not include the initial listener")
+	}
+
+	if !s.Has(l2) {
+		t.Errorf("Set does not include the new listener")
+	}
+}
+
+// Tests that when adding to a generic ID, the listener is added to the
+// generic set
+func TestById_Add_Generic(t *testing.T) {
+	nbi := newById()
+
+	l1 := &funcListener{}
+	l2 := &funcListener{}
+
+	nbi.Add(&id.ID{}, l1)
+	nbi.Add(AnyUser(), l2)
+
+	s := nbi.generic
+
+	if s.Len() != 2 {
+		t.Errorf("Should have returned a set of size 2")
+	}
+
+	if !s.Has(l1) {
+		t.Errorf("Set does not include the ZeroUser listener")
+	}
+
+	if !s.Has(l2) {
+		t.Errorf("Set does not include the empty user listener")
+	}
+}
+
+// Tests that removing a listener from a set with multiple listeners removes the
+// listener but maintains the set
+func TestById_Remove_ManyInSet(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	l1 := &funcListener{}
+	l2 := &funcListener{}
+
+	set1 := set.New(l1, l2)
+
+	nbi.list[*uid] = set1
+
+	nbi.Remove(uid, l1)
+
+	if _, ok := nbi.list[*uid]; !ok {
+		t.Errorf("Set removed when it should not have been")
+	}
+
+	if set1.Len() != 1 {
+		t.Errorf("Set is incorrect length after the remove call: %v",
+			set1.Len())
+	}
+
+	if set1.Has(l1) {
+		t.Errorf("Listener 1 still in set, it should not be")
+	}
+
+	if !set1.Has(l2) {
+		t.Errorf("Listener 2 not still in set, it should be")
+	}
+
+}
+
+// Tests that removing a listener from a set with a single listener removes the
+// listener and the set
+func TestById_Remove_SingleInSet(t *testing.T) {
+	nbi := newById()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	l1 := &funcListener{}
+
+	set1 := set.New(l1)
+
+	nbi.list[*uid] = set1
+
+	nbi.Remove(uid, l1)
+
+	if _, ok := nbi.list[*uid]; ok {
+		t.Errorf("Set not removed when it should have been")
+	}
+
+	if set1.Len() != 0 {
+		t.Errorf("Set is incorrect length after the remove call: %v",
+			set1.Len())
+	}
+
+	if set1.Has(l1) {
+		t.Errorf("Listener 1 still in set, it should not be")
+	}
+}
+
+// Tests that removing a listener from a set with a single listener removes the
+// listener and not the set when the ID iz ZeroUser
+func TestById_Remove_SingleInSet_ZeroUser(t *testing.T) {
+	nbi := newById()
+
+	uid := &id.ZeroUser
+
+	l1 := &funcListener{}
+
+	set1 := set.New(l1)
+
+	nbi.list[*uid] = set1
+
+	nbi.Remove(uid, l1)
+
+	if _, ok := nbi.list[*uid]; !ok {
+		t.Errorf("Set removed when it should not have been")
+	}
+
+	if set1.Len() != 0 {
+		t.Errorf("Set is incorrect length after the remove call: %v",
+			set1.Len())
+	}
+
+	if set1.Has(l1) {
+		t.Errorf("Listener 1 still in set, it should not be")
+	}
+}
+
+// Tests that removing a listener from a set with a single listener removes the
+// listener and not the set when the ID iz ZeroUser
+func TestById_Remove_SingleInSet_EmptyUser(t *testing.T) {
+	nbi := newById()
+
+	uid := &id.ID{}
+
+	l1 := &funcListener{}
+
+	set1 := set.New(l1)
+
+	nbi.list[*uid] = set1
+
+	nbi.Remove(uid, l1)
+
+	if _, ok := nbi.list[*uid]; !ok {
+		t.Errorf("Set removed when it should not have been")
+	}
+
+	if set1.Len() != 0 {
+		t.Errorf("Set is incorrect length after the remove call: %v",
+			set1.Len())
+	}
+
+	if set1.Has(l1) {
+		t.Errorf("Listener 1 still in set, it should not be")
+	}
+}
diff --git a/context/switchboard/byType.go b/context/switchboard/byType.go
new file mode 100644
index 0000000000000000000000000000000000000000..f9a7c6a273115c24499e15388a868459c1319e27
--- /dev/null
+++ b/context/switchboard/byType.go
@@ -0,0 +1,64 @@
+package switchboard
+
+import (
+	"github.com/golang-collections/collections/set"
+	"gitlab.com/elixxir/client/context/message"
+)
+
+type byType struct {
+	list    map[message.Type]*set.Set
+	generic *set.Set
+}
+
+// builds a new byType structure
+// registers an AnyType as generic
+func newByType() *byType {
+	bt := &byType{
+		list:    make(map[message.Type]*set.Set),
+		generic: set.New(),
+	}
+
+	// make the zero messages, which are defined as AnyType,
+	// point to the generic
+	bt.list[AnyType] = bt.generic
+
+	return bt
+}
+
+// returns a set associated with the passed messageType unioned with the
+// generic return
+func (bt *byType) Get(messageType message.Type) *set.Set {
+	lookup, ok := bt.list[messageType]
+	if !ok {
+		return bt.generic
+	} else {
+		return lookup.Union(bt.generic)
+	}
+}
+
+// adds a listener to a set for the given messageType. Creates a new set to add
+// it to if the set does not exist
+func (bt *byType) Add(messageType message.Type, r Listener) *set.Set {
+	s, ok := bt.list[messageType]
+	if !ok {
+		s = set.New(r)
+		bt.list[messageType] = s
+	} else {
+		s.Insert(r)
+	}
+
+	return s
+}
+
+// Removes the passed listener from the set for messageType and
+// deletes the set if it is empty and the type is not AnyType
+func (bt *byType) Remove(mt message.Type, l Listener) {
+	s, ok := bt.list[mt]
+	if ok {
+		s.Remove(l)
+
+		if s.Len() == 0 && mt != AnyType {
+			delete(bt.list, mt)
+		}
+	}
+}
diff --git a/context/switchboard/byType_test.go b/context/switchboard/byType_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..fb385195f1cf92a7babea8362af6d438d621aeb6
--- /dev/null
+++ b/context/switchboard/byType_test.go
@@ -0,0 +1,226 @@
+package switchboard
+
+import (
+	"github.com/golang-collections/collections/set"
+	"gitlab.com/elixxir/client/context/message"
+	"testing"
+)
+
+func TestByType_newByType(t *testing.T) {
+	nbt := newByType()
+
+	if nbt.list == nil {
+		t.Errorf("No list created")
+	}
+
+	if nbt.generic == nil {
+		t.Errorf("No generic created")
+	}
+
+	if nbt.generic != nbt.list[0] {
+		t.Errorf("zero message type not registered as generic")
+	}
+
+}
+
+func TestByType_Get_Empty(t *testing.T) {
+	nbt := newByType()
+
+	s := nbt.Get(42)
+
+	if s.Len() != 0 {
+		t.Errorf("Should not have returned a set")
+	}
+}
+
+func TestByType_Get_Selected(t *testing.T) {
+	nbt := newByType()
+
+	m := message.Type(42)
+
+	set1 := set.New(0)
+
+	nbt.list[m] = set1
+
+	s := nbt.Get(m)
+
+	if s.Len() == 0 {
+		t.Errorf("Should have returned a set")
+	}
+
+	if !s.SubsetOf(set1) || !set1.SubsetOf(s) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+func TestByType_Get_Generic(t *testing.T) {
+	nbt := newByType()
+
+	m := message.Type(42)
+
+	nbt.generic.Insert(0)
+
+	s := nbt.Get(m)
+
+	if s.Len() == 0 {
+		t.Errorf("Should have returned a set")
+	}
+
+	if !s.SubsetOf(nbt.generic) || !nbt.generic.SubsetOf(s) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+func TestByType_Get_GenericSelected(t *testing.T) {
+	nbt := newByType()
+
+	m := message.Type(42)
+
+	nbt.generic.Insert(1)
+
+	set1 := set.New(0)
+
+	nbt.list[m] = set1
+
+	s := nbt.Get(m)
+
+	if s.Len() == 0 {
+		t.Errorf("Should have returned a set")
+	}
+
+	setUnion := set1.Union(nbt.generic)
+
+	if !s.SubsetOf(setUnion) || !setUnion.SubsetOf(s) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+// Tests that when adding to a set which does not exist, the set is created
+func TestByType_Add_New(t *testing.T) {
+	nbt := newByType()
+
+	m := message.Type(42)
+
+	l := &funcListener{}
+
+	nbt.Add(m, l)
+
+	s := nbt.list[m]
+
+	if s.Len() != 1 {
+		t.Errorf("Should a set of the wrong size")
+	}
+
+	if !s.Has(l) {
+		t.Errorf("Wrong set returned")
+	}
+}
+
+// Tests that when adding to a set which does exist, the set is retained and
+// added to
+func TestByType_Add_Old(t *testing.T) {
+	nbt := newByType()
+
+	m := message.Type(42)
+
+	l1 := &funcListener{}
+	l2 := &funcListener{}
+
+	set1 := set.New(l1)
+
+	nbt.list[m] = set1
+
+	nbt.Add(m, l2)
+
+	s := nbt.list[m]
+
+	if s.Len() != 2 {
+		t.Errorf("Should have returned a set")
+	}
+
+	if !s.Has(l1) {
+		t.Errorf("Set does not include the initial listener")
+	}
+
+	if !s.Has(l2) {
+		t.Errorf("Set does not include the new listener")
+	}
+}
+
+// Tests that when adding to a generic ID, the listener is added to the
+// generic set
+func TestByType_Add_Generic(t *testing.T) {
+	nbt := newByType()
+
+	l1 := &funcListener{}
+
+	nbt.Add(AnyType, l1)
+
+	s := nbt.generic
+
+	if s.Len() != 1 {
+		t.Errorf("Should have returned a set of size 2")
+	}
+
+	if !s.Has(l1) {
+		t.Errorf("Set does not include the ZeroUser listener")
+	}
+}
+
+// Tests that removing a listener from a set with a single listener removes the
+// listener and the set
+func TestByType_Remove_SingleInSet(t *testing.T) {
+	nbt := newByType()
+
+	m := message.Type(42)
+
+	l1 := &funcListener{}
+
+	set1 := set.New(l1)
+
+	nbt.list[m] = set1
+
+	nbt.Remove(m, l1)
+
+	if _, ok := nbt.list[m]; ok {
+		t.Errorf("Set not removed when it should have been")
+	}
+
+	if set1.Len() != 0 {
+		t.Errorf("Set is incorrect length after the remove call: %v",
+			set1.Len())
+	}
+
+	if set1.Has(l1) {
+		t.Errorf("Listener 1 still in set, it should not be")
+	}
+}
+
+// Tests that removing a listener from a set with a single listener removes the
+// listener and not the set when the ID iz ZeroUser
+func TestByType_Remove_SingleInSet_AnyType(t *testing.T) {
+	nbt := newByType()
+
+	m := AnyType
+
+	l1 := &funcListener{}
+
+	set1 := set.New(l1)
+
+	nbt.list[m] = set1
+
+	nbt.Remove(m, l1)
+
+	if _, ok := nbt.list[m]; !ok {
+		t.Errorf("Set removed when it should not have been")
+	}
+
+	if set1.Len() != 0 {
+		t.Errorf("Set is incorrect length after the remove call: %v",
+			set1.Len())
+	}
+
+	if set1.Has(l1) {
+		t.Errorf("Listener 1 still in set, it should not be")
+	}
+}
diff --git a/context/switchboard/listener.go b/context/switchboard/listener.go
new file mode 100644
index 0000000000000000000000000000000000000000..abd6bea71c77d6c7e3afc7c3920ebe0bc381e9e4
--- /dev/null
+++ b/context/switchboard/listener.go
@@ -0,0 +1,112 @@
+////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                                       //
+//                                                                                        //
+// Use of this source code is governed by a license that can be found in the LICENSE file //
+////////////////////////////////////////////////////////////////////////////////////////////
+
+package switchboard
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/context/message"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+//interface for a listener adhere to
+type Listener interface {
+	// the Hear function is called to exercise the listener, passing in the
+	// data as an item
+	Hear(item message.Receive)
+	// Returns a name, used for debugging
+	Name() string
+}
+
+// This function type defines callbacks that get passed when the listener is
+// listened to. It will always be called in its own goroutine. It may be called
+// multiple times simultaneously
+type ListenerFunc func(item message.Receive)
+
+// id object returned when a listener is created and is used to delete it from
+// the system
+type ListenerID struct {
+	userID      *id.ID
+	messageType message.Type
+	listener    Listener
+}
+
+//getter for userID
+func (lid ListenerID) GetUserID() *id.ID {
+	return lid.userID
+}
+
+//getter for message type
+func (lid ListenerID) GetMessageType() message.Type {
+	return lid.messageType
+}
+
+//getter for name
+func (lid ListenerID) GetName() string {
+	return lid.listener.Name()
+}
+
+/*internal listener implementations*/
+
+//listener based off of a function
+type funcListener struct {
+	listener ListenerFunc
+	name     string
+}
+
+// creates a new FuncListener Adhereing to the listener interface out of the
+// passed function and name, returns a pointer to the result
+func newFuncListener(listener ListenerFunc, name string) *funcListener {
+	return &funcListener{
+		listener: listener,
+		name:     name,
+	}
+}
+
+// Adheres to the Hear function of the listener interface, calls the internal
+// function with the passed item
+func (fl *funcListener) Hear(item message.Receive) {
+	fl.listener(item)
+}
+
+// Adheres to the Name function of the listener interface, returns a name.
+// used for debugging
+func (fl *funcListener) Name() string {
+	return fl.name
+}
+
+//listener based off of a channel
+type chanListener struct {
+	listener chan message.Receive
+	name     string
+}
+
+// creates a new ChanListener Adhereing to the listener interface out of the
+// passed channel and name, returns a pointer to the result
+func newChanListener(listener chan message.Receive, name string) *chanListener {
+	return &chanListener{
+		listener: listener,
+		name:     name,
+	}
+}
+
+// Adheres to the Hear function of the listener interface, calls the passed the
+// heard item across the channel.  Drops the item if it cannot put it into the
+// channel immediately
+func (cl *chanListener) Hear(item message.Receive) {
+	select {
+	case cl.listener <- item:
+	default:
+		jww.WARN.Printf("Switchboard failed to speak on channel "+
+			"listener %s", cl.name)
+	}
+}
+
+// Adheres to the Name function of the listener interface, returns a name.
+// used for debugging
+func (cl *chanListener) Name() string {
+	return cl.name
+}
diff --git a/context/switchboard/listener_test.go b/context/switchboard/listener_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..295310bfbcd34fa8f62f1bbada9ad2c40c75f321
--- /dev/null
+++ b/context/switchboard/listener_test.go
@@ -0,0 +1,164 @@
+////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                                       //
+//                                                                                        //
+// Use of this source code is governed by a license that can be found in the LICENSE file //
+////////////////////////////////////////////////////////////////////////////////////////////
+
+package switchboard
+
+import (
+	"gitlab.com/elixxir/client/context/message"
+	"gitlab.com/xx_network/primitives/id"
+	"reflect"
+	"testing"
+	"time"
+)
+
+//verify func listener adheres to the listener interface
+var _ Listener = &funcListener{}
+
+//verify chan listener adheres to the listener interface
+var _ Listener = &chanListener{}
+
+//test listenerID returns the userID
+func TestListenerID_GetUserID(t *testing.T) {
+	lid := ListenerID{
+		userID:      id.NewIdFromUInt(42, id.User, t),
+		messageType: 42,
+		listener:    nil,
+	}
+
+	if !lid.GetUserID().Cmp(lid.userID) {
+		t.Errorf("Returned userID does not match")
+	}
+}
+
+//test listenerID returns the messageType
+func TestListenerID_GetMessageType(t *testing.T) {
+	lid := ListenerID{
+		userID:      id.NewIdFromUInt(42, id.User, t),
+		messageType: 42,
+		listener:    nil,
+	}
+
+	if lid.GetMessageType() != lid.messageType {
+		t.Errorf("Returned message type does not match")
+	}
+}
+
+//test listenerID returns the name
+func TestListenerID_GetName(t *testing.T) {
+	name := "test"
+
+	lid := ListenerID{
+		userID:      id.NewIdFromUInt(42, id.User, t),
+		messageType: 42,
+		listener:    newFuncListener(nil, name),
+	}
+
+	if lid.GetName() != name {
+		t.Errorf("Returned name type does not match")
+	}
+}
+
+//tests new function listener creates the funcListener properly
+func TestNewFuncListener(t *testing.T) {
+	f := func(item message.Receive) {}
+	name := "test"
+	listener := newFuncListener(f, name)
+
+	if listener.listener == nil {
+		t.Errorf("function is wrong")
+	}
+
+	if listener.name != name {
+		t.Errorf("name is wrong")
+	}
+}
+
+//tests FuncListener Hear works
+func TestFuncListener_Hear(t *testing.T) {
+	m := message.Receive{
+		Payload:     []byte{0, 1, 2, 3},
+		Sender:      id.NewIdFromUInt(42, id.User, t),
+		MessageType: 69,
+	}
+
+	heard := make(chan message.Receive, 1)
+
+	f := func(item message.Receive) {
+		heard <- item
+	}
+
+	listener := newFuncListener(f, "test")
+
+	listener.Hear(m)
+
+	select {
+	case item := <-heard:
+		if !reflect.DeepEqual(item, m) {
+			t.Errorf("Heard message did not match")
+		}
+	case <-time.After(5 * time.Millisecond):
+		t.Errorf("Did not hear")
+	}
+}
+
+// Test FuncListener returns the correct name
+func TestFuncListener_Name(t *testing.T) {
+	name := "test"
+	listener := newFuncListener(nil, name)
+
+	if listener.Name() != name {
+		t.Errorf("Name did not match")
+	}
+}
+
+//tests new chan listener creates the chanListener properly
+func TestNewChanListener(t *testing.T) {
+	c := make(chan message.Receive)
+	name := "test"
+	listener := newChanListener(c, name)
+
+	if listener.listener == nil {
+		t.Errorf("function is wrong")
+	}
+
+	if listener.name != name {
+		t.Errorf("name is wrong")
+	}
+}
+
+//tests ChanListener Hear works
+func TestChanListener_Hear(t *testing.T) {
+	m := message.Receive{
+		Payload:     []byte{0, 1, 2, 3},
+		Sender:      id.NewIdFromUInt(42, id.User, t),
+		MessageType: 69,
+	}
+
+	heard := make(chan message.Receive, 1)
+
+	listener := newChanListener(heard, "test")
+
+	listener.Hear(m)
+
+	select {
+	case item := <-heard:
+		if !reflect.DeepEqual(item, m) {
+			t.Errorf("Heard message did not match")
+		}
+	case <-time.After(5 * time.Millisecond):
+		t.Errorf("Did not hear")
+	}
+}
+
+// Test FuncListener returns the correct name
+func TestChanListener_Name(t *testing.T) {
+	name := "test"
+	listener := newChanListener(nil, name)
+
+	if listener.Name() != name {
+		t.Errorf("Name did not match")
+	}
+}
diff --git a/context/switchboard/switchboard.go b/context/switchboard/switchboard.go
new file mode 100644
index 0000000000000000000000000000000000000000..0053686c3a57bcd8c8ec69c08a7d9fd4f3e11045
--- /dev/null
+++ b/context/switchboard/switchboard.go
@@ -0,0 +1,166 @@
+package switchboard
+
+import (
+	"github.com/golang-collections/collections/set"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/context/message"
+	"gitlab.com/xx_network/primitives/id"
+	"sync"
+)
+
+type Switchboard struct {
+	id          *byId
+	messageType *byType
+
+	mux sync.RWMutex
+}
+
+// New generates and returns a new switchboard object.
+func New() *Switchboard {
+	return &Switchboard{
+		id:          newById(),
+		messageType: newByType(),
+	}
+}
+
+// Registers a new listener. Returns the ID of the new listener.
+// Keep this around if you want to be able to delete the listener later.
+//
+// name is used for debug printing and not checked for uniqueness
+//
+// user: 0 for all, or any user ID to listen for messages from a particular
+// user. 0 can be id.ZeroUser or id.ZeroID
+// messageType: 0 for all, or any message type to listen for messages of that
+// type. 0 can be switchboard.AnyType
+// newListener: something implementing the Listener interface. Do not
+// pass nil to this.
+//
+// If a message matches multiple listeners, all of them will hear the message.
+func (sw *Switchboard) RegisterListener(user *id.ID, messageType message.Type,
+	newListener Listener) ListenerID {
+
+	// check the input data is valid
+	if user == nil {
+		jww.FATAL.Panicf("cannot register listener to nil user")
+	}
+
+	if newListener == nil {
+		jww.FATAL.Panicf("cannot register nil listener")
+	}
+
+	//register the listener by both ID and messageType
+	sw.mux.Lock()
+
+	sw.id.Add(user, newListener)
+	sw.messageType.Add(messageType, newListener)
+
+	sw.mux.Unlock()
+
+	//return a ListenerID so it can be unregistered in the future
+	return ListenerID{
+		userID:      user,
+		messageType: messageType,
+		listener:    newListener,
+	}
+}
+
+// Registers a new listener built around the passed function.
+// Returns the ID of the new listener.
+// Keep this around if you want to be able to delete the listener later.
+//
+// name is used for debug printing and not checked for uniqueness
+//
+// user: 0 for all, or any user ID to listen for messages from a particular
+// user. 0 can be id.ZeroUser or id.ZeroID
+// messageType: 0 for all, or any message type to listen for messages of that
+// type. 0 can be switchboard.AnyType
+// newListener: a function implementing the ListenerFunc function type.
+// Do not pass nil to this.
+//
+// If a message matches multiple listeners, all of them will hear the message.
+func (sw *Switchboard) RegisterFunc(name string, user *id.ID,
+	messageType message.Type, newListener ListenerFunc) ListenerID {
+	// check that the input data is valid
+	if newListener == nil {
+		jww.FATAL.Panicf("cannot register function listener '%s' "+
+			"with nil func", name)
+	}
+
+	// generate a funcListener object adhering to the listener interface
+	fl := newFuncListener(newListener, name)
+
+	//register the listener and return the result
+	return sw.RegisterListener(user, messageType, fl)
+}
+
+// Registers a new listener built around the passed channel.
+// Returns the ID of the new listener.
+// Keep this around if you want to be able to delete the listener later.
+//
+// name is used for debug printing and not checked for uniqueness
+//
+// user: 0 for all, or any user ID to listen for messages from a particular
+// user. 0 can be id.ZeroUser or id.ZeroID
+// messageType: 0 for all, or any message type to listen for messages of that
+// type. 0 can be switchboard.AnyType
+// newListener: an item channel.
+// Do not pass nil to this.
+//
+// If a message matches multiple listeners, all of them will hear the message.
+func (sw *Switchboard) RegisterChannel(name string, user *id.ID,
+	messageType message.Type, newListener chan message.Receive) ListenerID {
+	// check that the input data is valid
+	if newListener == nil {
+		jww.FATAL.Panicf("cannot register channel listener '%s' with"+
+			" nil channel", name)
+	}
+
+	// generate a chanListener object adhering to the listener interface
+	cl := newChanListener(newListener, name)
+
+	//register the listener and return the result
+	return sw.RegisterListener(user, messageType, cl)
+}
+
+// Speak broadcasts a message to the appropriate listeners.
+// each is spoken to in their own goroutine
+func (sw *Switchboard) Speak(item message.Receive) {
+	sw.mux.RLock()
+	defer sw.mux.RUnlock()
+
+	// Matching listeners: include those that match all criteria perfectly, as
+	// well as those that do not care about certain criteria
+	matches := sw.matchListeners(item)
+
+	//Execute hear on all matched listeners in a new goroutine
+	matches.Do(func(i interface{}) {
+		r := i.(Listener)
+		go r.Hear(item)
+	})
+
+	// print to log if nothing was heard
+	if matches.Len() == 0 {
+		jww.ERROR.Printf(
+			"Message of type %v from user %q didn't match any listeners in"+
+				" the map", item.MessageType, item.Sender)
+	}
+}
+
+// Unregister removes the listener with the specified ID so it will no longer
+// get called
+func (sw *Switchboard) Unregister(listenerID ListenerID) {
+	sw.mux.Lock()
+
+	sw.id.Remove(listenerID.userID, listenerID.listener)
+	sw.messageType.Remove(listenerID.messageType, listenerID.listener)
+
+	sw.mux.Unlock()
+}
+
+// finds all listeners who match the items sender or ID, or have those fields
+// as generic
+func (sw *Switchboard) matchListeners(item message.Receive) *set.Set {
+	idSet := sw.id.Get(item.Sender)
+	typeSet := sw.messageType.Get(item.MessageType)
+	return idSet.Intersection(typeSet)
+}
diff --git a/context/switchboard/switchboard_test.go b/context/switchboard/switchboard_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5c54d2906a3a6558faa5123a7d9c2c36b9c05c64
--- /dev/null
+++ b/context/switchboard/switchboard_test.go
@@ -0,0 +1,343 @@
+package switchboard
+
+import (
+	"gitlab.com/elixxir/client/context/message"
+	"gitlab.com/xx_network/primitives/id"
+	"strings"
+	"testing"
+	"time"
+)
+
+// tests that New create a correctly structured switchboard
+func TestNew(t *testing.T) {
+	sw := New()
+
+	if sw.id == nil {
+		t.Errorf("did not create an id map")
+	}
+
+	if sw.messageType == nil {
+		t.Errorf("did not create a messageType map")
+	}
+}
+
+//Tests that register listener handles errors properly
+func TestSwitchboard_RegisterListener_Error_NilUserID(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil && !strings.Contains(r.(string),
+			"cannot register listener to nil user") {
+			t.Errorf("A nil userID caused the wrong error: %s", r)
+		}
+	}()
+
+	sw := New()
+	sw.RegisterListener(nil, 0, &funcListener{})
+
+	t.Errorf("A nil userID should have caused an panic")
+}
+
+//Tests that register listener handles errors properly
+func TestSwitchboard_RegisterListener_Error_NilListener(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil && !strings.Contains(r.(string),
+			"cannot register nil listener") {
+			t.Errorf("A nil listener caused the wrong error: %s", r)
+		}
+	}()
+
+	sw := New()
+	sw.RegisterListener(id.NewIdFromUInt(42, id.User, t), 0, nil)
+
+	t.Errorf("A nil listener should have caused an error")
+}
+
+//Tests that RegisterListener properly registers the listeners
+func TestSwitchboard_RegisterListener(t *testing.T) {
+	sw := New()
+
+	l := &funcListener{}
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	mt := message.Type(69)
+
+	lid := sw.RegisterListener(uid, mt, l)
+
+	if lid.messageType != mt {
+		t.Errorf("ListenerID message type is wrong")
+	}
+
+	if !lid.userID.Cmp(uid) {
+		t.Errorf("ListenerID userID is wrong")
+	}
+
+	if lid.listener != l {
+		t.Errorf("ListenerID listener is wrong")
+	}
+
+	//check that the listener is registered in the appropriate location
+	setID := sw.id.Get(uid)
+
+	if !setID.Has(l) {
+		t.Errorf("Listener is not registered by ID")
+	}
+
+	setType := sw.messageType.Get(mt)
+
+	if !setType.Has(l) {
+		t.Errorf("Listener is not registered by Message Type")
+	}
+
+}
+
+//Tests that register funcListener handles errors properly
+func TestSwitchboard_RegisterFunc_Error_NilUserID(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil && !strings.Contains(r.(string),
+			"cannot register listener to nil user") {
+			t.Errorf("A nil userID caused the wrong error: %s", r)
+		}
+	}()
+
+	sw := New()
+	sw.RegisterFunc("test", nil, 0, func(receive message.Receive) {})
+
+	t.Errorf("A nil user ID should have caused an error")
+}
+
+//Tests that register funcListener handles errors properly
+func TestSwitchboard_RegisterFunc_Error_NilFunc(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil && !strings.Contains(r.(string),
+			"cannot register function listener 'test' with nil func") {
+			t.Errorf("A nil func caused the wrong error: %s", r)
+		}
+	}()
+
+	sw := New()
+	sw.RegisterFunc("test", id.NewIdFromUInt(42, id.User, t), 0, nil)
+
+	t.Errorf("A nil listener func should have caused an error")
+}
+
+//Tests that RegisterFunc properly registers the listeners
+func TestSwitchboard_RegisterFunc(t *testing.T) {
+	sw := New()
+
+	heard := false
+
+	l := func(receive message.Receive) { heard = true }
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	mt := message.Type(69)
+
+	lid := sw.RegisterFunc("test", uid, mt, l)
+
+	if lid.messageType != mt {
+		t.Errorf("ListenerID message type is wrong")
+	}
+
+	if !lid.userID.Cmp(uid) {
+		t.Errorf("ListenerID userID is wrong")
+	}
+
+	//check that the listener is registered in the appropriate location
+	setID := sw.id.Get(uid)
+
+	if !setID.Has(lid.listener) {
+		t.Errorf("Listener is not registered by ID")
+	}
+
+	setType := sw.messageType.Get(mt)
+
+	if !setType.Has(lid.listener) {
+		t.Errorf("Listener is not registered by Message Type")
+	}
+
+	lid.listener.Hear(message.Receive{})
+	if !heard {
+		t.Errorf("Func listener not registered correctly")
+	}
+}
+
+//Tests that register chanListener handles errors properly
+func TestSwitchboard_RegisterChan_Error_NilUser(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil && !strings.Contains(r.(string),
+			"cannot register listener to nil user") {
+			t.Errorf("A nil user ID caused the wrong error: %s", r)
+		}
+	}()
+	sw := New()
+	sw.RegisterChannel("test", nil, 0,
+		make(chan message.Receive))
+
+	t.Errorf("A nil userID should have caused an error")
+}
+
+//Tests that register chanListener handles errors properly
+func TestSwitchboard_RegisterChan_Error_NilChan(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil && !strings.Contains(r.(string),
+			"cannot register channel listener 'test' with nil channel") {
+			t.Errorf("A nil channel caused the wrong error: %s", r)
+		}
+	}()
+	sw := New()
+	sw.RegisterChannel("test", &id.ID{}, 0, nil)
+
+	t.Errorf("A nil channel func should have caused an error")
+}
+
+//Tests that RegisterChan properly registers the listeners
+func TestSwitchboard_RegisterChan(t *testing.T) {
+	sw := New()
+
+	ch := make(chan message.Receive, 1)
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+
+	mt := message.Type(69)
+
+	lid := sw.RegisterChannel("test", uid, mt, ch)
+
+	//check the returns
+	if lid.messageType != mt {
+		t.Errorf("ListenerID message type is wrong")
+	}
+
+	if !lid.userID.Cmp(uid) {
+		t.Errorf("ListenerID userID is wrong")
+	}
+
+	//check that the listener is registered in the appropriate location
+	setID := sw.id.Get(uid)
+
+	if !setID.Has(lid.listener) {
+		t.Errorf("Listener is not registered by ID")
+	}
+
+	setType := sw.messageType.Get(mt)
+
+	if !setType.Has(lid.listener) {
+		t.Errorf("Listener is not registered by Message Type")
+	}
+
+	lid.listener.Hear(message.Receive{})
+	select {
+	case <-ch:
+	case <-time.After(5 * time.Millisecond):
+		t.Errorf("Chan listener not registered correctly")
+	}
+}
+
+//tests all combinations of hits and misses for speak
+func TestSwitchboard_Speak(t *testing.T) {
+
+	uids := []*id.ID{{}, AnyUser(), id.NewIdFromUInt(42, id.User, t), id.NewIdFromUInt(69, id.User, t)}
+	mts := []message.Type{AnyType, 42, 69}
+
+	for _, uidReg := range uids {
+		for _, mtReg := range mts {
+
+			//create the registrations
+			sw := New()
+			ch1 := make(chan message.Receive, 1)
+			ch2 := make(chan message.Receive, 1)
+
+			sw.RegisterChannel("test", uidReg, mtReg, ch1)
+			sw.RegisterChannel("test", uidReg, mtReg, ch2)
+
+			//send every possible message
+			for _, uid := range uids {
+				for _, mt := range mts {
+					if uid.Cmp(&id.ID{}) || mt == AnyType {
+						continue
+					}
+
+					m := message.Receive{
+						Payload:     []byte{0, 1, 2, 3},
+						Sender:      uid,
+						MessageType: mt,
+					}
+
+					sw.Speak(m)
+
+					shouldHear := (m.Sender.Cmp(uidReg) ||
+						uidReg.Cmp(&id.ID{}) || uidReg.Cmp(AnyUser())) &&
+						(m.MessageType == mtReg || mtReg == AnyType)
+
+					var heard1 bool
+
+					select {
+					case <-ch1:
+						heard1 = true
+					case <-time.After(5 * time.Millisecond):
+						heard1 = false
+					}
+
+					if shouldHear != heard1 {
+						t.Errorf("Correct operation not recorded "+
+							"for listener 1: Expected: %v, Occured: %v",
+							shouldHear, heard1)
+					}
+
+					var heard2 bool
+
+					select {
+					case <-ch2:
+						heard2 = true
+					case <-time.After(5 * time.Millisecond):
+						heard2 = false
+					}
+
+					if shouldHear != heard2 {
+						t.Errorf("Correct operation not recorded "+
+							"for listener 2: Expected: %v, Occured: %v",
+							shouldHear, heard2)
+					}
+				}
+			}
+		}
+	}
+}
+
+//tests that Unregister removes the listener and only the listener
+func TestSwitchboard_Unregister(t *testing.T) {
+	sw := New()
+
+	uid := id.NewIdFromUInt(42, id.User, t)
+	mt := message.Type(69)
+
+	l := func(receive message.Receive) {}
+
+	lid1 := sw.RegisterFunc("a", uid, mt, l)
+
+	lid2 := sw.RegisterFunc("a", uid, mt, l)
+
+	sw.Unregister(lid1)
+
+	//get sets to check
+	setID := sw.id.Get(uid)
+	setType := sw.messageType.Get(mt)
+
+	//check that the removed listener is not registered
+	if setID.Has(lid1.listener) {
+		t.Errorf("Removed Listener is registered by ID, should not be")
+	}
+
+	if setType.Has(lid1.listener) {
+		t.Errorf("Removed Listener not registered by Message Type, " +
+			"should not be")
+	}
+
+	//check that the not removed listener is still registered
+	if !setID.Has(lid2.listener) {
+		t.Errorf("Remaining Listener is not registered by ID")
+	}
+
+	if !setType.Has(lid2.listener) {
+		t.Errorf("Remaining Listener is not registered by Message Type")
+	}
+}
diff --git a/crypto/decrypt.go b/crypto/decrypt.go
deleted file mode 100644
index 9004d5aa028585d9ff05dd7894f6d9d80041ea32..0000000000000000000000000000000000000000
--- a/crypto/decrypt.go
+++ /dev/null
@@ -1,77 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2019 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
-////////////////////////////////////////////////////////////////////////////////
-
-package crypto
-
-import (
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/elixxir/crypto/hash"
-	"gitlab.com/elixxir/primitives/format"
-)
-
-// E2EDecrypt uses the E2E key to decrypt the message
-// It returns an error in case of HMAC verification failure
-// or in case of a decryption error (related to padding)
-// If it succeeds, it modifies the passed message
-func E2EDecrypt(grp *cyclic.Group, key *cyclic.Int,
-	msg *format.Message) error {
-	// First thing to do is check MAC
-	if !hash.VerifyHMAC(msg.Contents.Get(), msg.GetMAC(), key.Bytes()) {
-		return errors.New("HMAC verification failed for E2E message")
-	}
-	var iv [e2e.AESBlockSize]byte
-	fp := msg.GetKeyFP()
-	copy(iv[:], fp[:e2e.AESBlockSize])
-	// decrypt the timestamp in the associated data
-	decryptedTimestamp, err := e2e.DecryptAES256WithIV(
-		key.Bytes(), iv, msg.GetTimestamp())
-	if err != nil {
-		return errors.New("Timestamp decryption failed for E2E message: " + err.Error())
-	}
-	// TODO deserialize this somewhere along the line and provide methods
-	// to mobile developers on the bindings to interact with the timestamps
-	decryptedTimestamp = append(decryptedTimestamp, 0)
-	msg.SetTimestamp(decryptedTimestamp)
-	// Decrypt e2e
-	decryptedPayload, err := e2e.Decrypt(grp, key, msg.Contents.Get())
-
-	if err != nil {
-		return errors.New("Failed to decrypt E2E message: " + err.Error())
-	}
-	msg.Contents.SetRightAligned(decryptedPayload)
-	return nil
-}
-
-// E2EDecryptUnsafe uses the E2E key to decrypt the message
-// It returns an error in case of HMAC verification failure
-// It doesn't expect the payload to be padded
-// If it succeeds, it modifies the passed message
-func E2EDecryptUnsafe(grp *cyclic.Group, key *cyclic.Int,
-	msg *format.Message) error {
-	// First thing to do is check MAC
-	if !hash.VerifyHMAC(msg.Contents.Get(), msg.GetMAC(), key.Bytes()) {
-		return errors.New("HMAC verification failed for E2E message")
-	}
-	var iv [e2e.AESBlockSize]byte
-	fp := msg.GetKeyFP()
-	copy(iv[:], fp[:e2e.AESBlockSize])
-	// decrypt the timestamp in the associated data
-	decryptedTimestamp, err := e2e.DecryptAES256WithIV(
-		key.Bytes(), iv, msg.GetTimestamp())
-	if err != nil {
-		return errors.New("Timestamp decryption failed for E2E message: " + err.Error())
-	}
-	// TODO deserialize this somewhere along the line and provide methods
-	// to mobile developers on the bindings to interact with the timestamps
-	decryptedTimestamp = append(decryptedTimestamp, 0)
-	msg.SetTimestamp(decryptedTimestamp)
-	// Decrypt e2e
-	decryptedPayload := e2e.DecryptUnsafe(grp, key, msg.Contents.Get())
-	msg.Contents.Set(decryptedPayload)
-	return nil
-}
diff --git a/crypto/encrypt.go b/crypto/encrypt.go
deleted file mode 100644
index bb3fb592f4f6dfc89b5dc9a0a8af16378b0d5b67..0000000000000000000000000000000000000000
--- a/crypto/encrypt.go
+++ /dev/null
@@ -1,126 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2019 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
-////////////////////////////////////////////////////////////////////////////////
-
-package crypto
-
-import (
-	"gitlab.com/elixxir/client/globals"
-	"gitlab.com/elixxir/client/storage"
-	"gitlab.com/elixxir/client/user"
-	"gitlab.com/elixxir/crypto/cmix"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/elixxir/crypto/hash"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/comms/connect"
-)
-
-// TODO: REMOVE ME
-var SessionV2 *storage.Session
-
-// CMIX Encrypt performs the encryption
-// of the msg to a team of nodes
-// It returns a new msg
-func CMIXEncrypt(session user.Session, topology *connect.Circuit, salt []byte,
-	msg *format.Message) (*format.Message, [][]byte) {
-	// Generate the encryption key
-	nodeKeys, err := SessionV2.GetNodeKeysFromCircuit(topology)
-	if err != nil {
-		globals.Log.FATAL.Panicf("could not get nodeKeys: %+v", err)
-	}
-
-	baseKeys := make([]*cyclic.Int, len(nodeKeys))
-	for i, key := range nodeKeys {
-		globals.Log.WARN.Printf("NodeKey for %d: %v", i, key.TransmissionKey)
-		baseKeys[i] = key.TransmissionKey
-	}
-
-	userData, err := SessionV2.GetUserData()
-
-	if err != nil {
-		globals.Log.FATAL.Panicf("could not get userData: %+v", err)
-	}
-
-	ecrMsg := cmix.ClientEncrypt(userData.CmixGrp, msg, salt, baseKeys)
-
-	h, err := hash.NewCMixHash()
-	if err != nil {
-		globals.Log.ERROR.Printf("Cound not get hash for KMAC generation: %+v", h)
-	}
-
-	KMAC := cmix.GenerateKMACs(salt, baseKeys, h)
-
-	return ecrMsg, KMAC
-}
-
-// E2EEncrypt uses the E2E key to encrypt msg
-// to its intended recipient
-// It also properly populates the associated data
-// It modifies the passed msg instead of returning a new one
-func E2EEncrypt(grp *cyclic.Group,
-	key *cyclic.Int, keyFP format.Fingerprint,
-	msg *format.Message) {
-	msg.SetKeyFP(keyFP)
-
-	// Encrypt the timestamp using key
-	// Timestamp bytes were previously stored
-	// and GO only uses 15 bytes, so use those
-	var iv [e2e.AESBlockSize]byte
-	copy(iv[:], keyFP[:e2e.AESBlockSize])
-	encryptedTimestamp, err :=
-		e2e.EncryptAES256WithIV(key.Bytes(), iv,
-			msg.GetTimestamp()[:15])
-	if err != nil {
-		panic(err)
-	}
-	msg.SetTimestamp(encryptedTimestamp)
-
-	// E2E encrypt the msg
-	encPayload, err := e2e.Encrypt(grp, key, msg.Contents.GetRightAligned())
-	if err != nil {
-		globals.Log.ERROR.Panicf(err.Error())
-	}
-	msg.Contents.Set(encPayload)
-
-	// MAC is HMAC(key, ciphertext)
-	// Currently, the MAC doesn't include any of the associated data
-	MAC := hash.CreateHMAC(encPayload, key.Bytes())
-	msg.SetMAC(MAC)
-}
-
-// E2EEncryptUnsafe uses the E2E key to encrypt msg
-// to its intended recipient
-// It doesn't apply padding to the payload, so it can be unsafe
-// if the payload is small
-// It also properly populates the associated data
-// It modifies the passed msg instead of returning a new one
-func E2EEncryptUnsafe(grp *cyclic.Group,
-	key *cyclic.Int, keyFP format.Fingerprint,
-	msg *format.Message) {
-	msg.SetKeyFP(keyFP)
-
-	// Encrypt the timestamp using key
-	// Timestamp bytes were previously stored
-	// and GO only uses 15 bytes, so use those
-	var iv [e2e.AESBlockSize]byte
-	copy(iv[:], keyFP[:e2e.AESBlockSize])
-	encryptedTimestamp, err :=
-		e2e.EncryptAES256WithIV(key.Bytes(), iv,
-			msg.GetTimestamp()[:15])
-	if err != nil {
-		panic(err)
-	}
-	msg.SetTimestamp(encryptedTimestamp)
-
-	// E2E encrypt the msg
-	encPayload := e2e.EncryptUnsafe(grp, key, msg.Contents.Get())
-	msg.Contents.Set(encPayload)
-
-	// MAC is HMAC(key, ciphertext)
-	// Currently, the MAC doesn't include any of the associated data
-	MAC := hash.CreateHMAC(encPayload, key.Bytes())
-	msg.SetMAC(MAC)
-}
diff --git a/crypto/encryptdecrypt_test.go b/crypto/encryptdecrypt_test.go
deleted file mode 100644
index 0ed8c376f6be5e2b9d8171e72fa4661c551ab380..0000000000000000000000000000000000000000
--- a/crypto/encryptdecrypt_test.go
+++ /dev/null
@@ -1,411 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2019 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
-////////////////////////////////////////////////////////////////////////////////
-
-package crypto
-
-import (
-	"bytes"
-	"encoding/binary"
-	"fmt"
-	"gitlab.com/elixxir/client/storage"
-	user2 "gitlab.com/elixxir/client/storage/user"
-	"gitlab.com/elixxir/client/user"
-	"gitlab.com/elixxir/client/userRegistry"
-	pb "gitlab.com/elixxir/comms/mixmessages"
-	"gitlab.com/elixxir/crypto/cmix"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/hash"
-	"gitlab.com/elixxir/crypto/large"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/comms/connect"
-	"gitlab.com/xx_network/primitives/id"
-	"golang.org/x/crypto/blake2b"
-	"os"
-	"testing"
-	"time"
-)
-
-const numNodes = 5
-
-var salt = []byte(
-	"fdecfa52a8ad1688dbfa7d16df74ebf27e535903c469cefc007ebbe1ee895064")
-
-var session user.Session
-var serverPayloadAKey *cyclic.Int
-var serverPayloadBKey *cyclic.Int
-
-var topology *connect.Circuit
-
-func setup() {
-
-	cmixGrp, e2eGrp := getGroups()
-
-	userRegistry.InitUserRegistry(cmixGrp)
-
-	UID := new(id.ID)
-	binary.BigEndian.PutUint64(UID[:], 18)
-	UID.SetType(id.User)
-	u, ok := userRegistry.Users.GetUser(UID)
-	if !ok {
-		panic("Didn't get user 18 from registry")
-	}
-
-	var nodeSlice []*id.ID
-
-	//build topology
-	for i := 0; i < numNodes; i++ {
-		nodeId := new(id.ID)
-		nodeId[0] = byte(i)
-		nodeId.SetType(id.Node)
-		nodeSlice = append(nodeSlice, nodeId)
-	}
-
-	topology = connect.NewCircuit(nodeSlice)
-
-	tempKey := cmixGrp.NewInt(1)
-	serverPayloadAKey = cmixGrp.NewInt(1)
-	serverPayloadBKey = cmixGrp.NewInt(1)
-
-	h, _ := blake2b.New256(nil)
-
-	session = user.NewSession(nil, "password")
-
-	SessionV2, _ = storage.Init(".ekvcryptotest", "password")
-
-	userData := &user2.UserData{
-		ThisUser: u,
-		CmixGrp:  cmixGrp,
-		E2EGrp:   e2eGrp,
-	}
-	SessionV2.CommitUserData(userData)
-
-	for i := 0; i < numNodes; i++ {
-
-		nk := user.NodeKeys{}
-
-		h.Reset()
-		h.Write(salt)
-
-		nk.TransmissionKey = cmixGrp.NewInt(int64(2 + i))
-		cmix.NodeKeyGen(cmixGrp, salt, nk.TransmissionKey, tempKey)
-		cmixGrp.Mul(serverPayloadAKey, tempKey, serverPayloadAKey)
-
-		cmix.NodeKeyGen(cmixGrp, h.Sum(nil), nk.TransmissionKey, tempKey)
-		cmixGrp.Mul(serverPayloadBKey, tempKey, serverPayloadBKey)
-
-		SessionV2.PushNodeKey(topology.GetNodeAtIndex(i), nk)
-		fmt.Printf("Saved NodeKey: %s, %v", topology.GetNodeAtIndex(i),
-			nk.TransmissionKey)
-
-	}
-
-}
-
-func TestMain(m *testing.M) {
-	setup()
-	os.Exit(m.Run())
-}
-
-func TestFullEncryptDecrypt(t *testing.T) {
-	cmixGrp, e2eGrp := getGroups()
-
-	sender := id.NewIdFromUInt(38, id.User, t)
-	recipient := id.NewIdFromUInt(29, id.User, t)
-	msg := format.NewMessage()
-	msg.SetRecipient(recipient)
-	msgPayload := []byte("help me, i'm stuck in an" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory")
-	// Normally, msgPayload would be the right length due to padding
-	//msgPayload = append(msgPayload, make([]byte,
-	//	format.ContentsLen-len(msgPayload)-format.PadMinLen)...)
-	msg.Contents.SetRightAligned(msgPayload)
-	now := time.Now()
-	nowBytes, _ := now.MarshalBinary()
-	// Normally, nowBytes would be the right length due to AES encryption
-	nowBytes = append(nowBytes, make([]byte, format.TimestampLen-len(nowBytes))...)
-	msg.SetTimestamp(nowBytes)
-
-	key := e2eGrp.NewInt(42)
-	h, _ := hash.NewCMixHash()
-	h.Write(key.Bytes())
-	fp := format.Fingerprint{}
-	copy(fp[:], h.Sum(nil))
-
-	// E2E Encryption
-	E2EEncrypt(e2eGrp, key, fp, msg)
-
-	// CMIX Encryption
-	encMsg, _ := CMIXEncrypt(session, topology, salt, msg)
-
-	// Server will decrypt payload (which is OK because the payload is now e2e)
-	// This block imitates what the server does during the realtime
-	payloadA := cmixGrp.NewIntFromBytes(encMsg.GetPayloadA())
-	payloadB := cmixGrp.NewIntFromBytes(encMsg.GetPayloadB())
-	// Multiply payloadA and associated data by serverPayloadBkey
-	cmixGrp.Mul(payloadA, serverPayloadAKey, payloadA)
-	// Multiply payloadB data only by serverPayloadAkey
-	cmixGrp.Mul(payloadB, serverPayloadBKey, payloadB)
-
-	decMsg := format.NewMessage()
-	decMsg.SetPayloadA(payloadA.LeftpadBytes(uint64(format.PayloadLen)))
-	decMsg.SetDecryptedPayloadB(payloadB.LeftpadBytes(uint64(format.PayloadLen)))
-
-	// E2E Decryption
-	err := E2EDecrypt(e2eGrp, key, decMsg)
-
-	if err != nil {
-		t.Errorf("E2EDecrypt returned error: %v", err.Error())
-	}
-
-	decryptedRecipient, err := decMsg.GetRecipient()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !decryptedRecipient.Cmp(recipient) {
-		t.Errorf("Recipient differed from expected: Got %q, expected %q",
-			decryptedRecipient, sender)
-	}
-	if !bytes.Equal(decMsg.Contents.GetRightAligned(), msgPayload) {
-		t.Errorf("Decrypted payload differed from expected: Got %q, "+
-			"expected %q", decMsg.Contents.Get(), msgPayload)
-	}
-}
-
-// E2E unsafe functions should only be used when the payload
-// to be sent occupies the whole payload structure, i.e. 256 bytes
-func TestFullEncryptDecrypt_Unsafe(t *testing.T) {
-	cmixGrp, e2eGrp := getGroups()
-	sender := id.NewIdFromUInt(38, id.User, t)
-	recipient := id.NewIdFromUInt(29, id.User, t)
-	msg := format.NewMessage()
-	msg.SetRecipient(recipient)
-	msgPayload := []byte(
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-			" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-			" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-			" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-			" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-			" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-			" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory")
-	msg.Contents.Set(msgPayload[:format.ContentsLen])
-
-	msg.SetTimestamp(make([]byte, 16))
-
-	key := e2eGrp.NewInt(42)
-	h, _ := hash.NewCMixHash()
-	h.Write(key.Bytes())
-	fp := format.Fingerprint{}
-	copy(fp[:], h.Sum(nil))
-
-	// E2E Encryption without padding
-	E2EEncryptUnsafe(e2eGrp, key, fp, msg)
-
-	// CMIX Encryption
-	encMsg, _ := CMIXEncrypt(session, topology, salt, msg)
-
-	// Server will decrypt payload (which is OK because the payload is now e2e)
-	// This block imitates what the server does during the realtime
-	var encryptedNet *pb.Slot
-	{
-		payload := cmixGrp.NewIntFromBytes(encMsg.GetPayloadA())
-		assocData := cmixGrp.NewIntFromBytes(encMsg.GetPayloadB())
-		// Multiply payload and associated data by transmission key only
-		cmixGrp.Mul(payload, serverPayloadAKey, payload)
-		// Multiply associated data only by transmission key
-		cmixGrp.Mul(assocData, serverPayloadBKey, assocData)
-		encryptedNet = &pb.Slot{
-			SenderID: sender.Bytes(),
-			Salt:     salt,
-			PayloadA: payload.LeftpadBytes(uint64(format.PayloadLen)),
-			PayloadB: assocData.LeftpadBytes(uint64(format.PayloadLen)),
-		}
-	}
-
-	decMsg := format.NewMessage()
-	decMsg.SetPayloadA(encryptedNet.PayloadA)
-	decMsg.SetDecryptedPayloadB(encryptedNet.PayloadB)
-
-	// E2E Decryption
-	err := E2EDecryptUnsafe(e2eGrp, key, decMsg)
-
-	if err != nil {
-		t.Errorf("E2EDecryptUnsafe returned error: %v", err.Error())
-	}
-
-	decryptedRecipient, err := decMsg.GetRecipient()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !decryptedRecipient.Cmp(recipient) {
-		t.Errorf("Recipient differed from expected: Got %q, expected %q",
-			decryptedRecipient, sender)
-	}
-	if !bytes.Equal(decMsg.Contents.Get(), msgPayload[:format.ContentsLen]) {
-		t.Errorf("Decrypted payload differed from expected: Got %q, "+
-			"expected %q", decMsg.Contents.Get(), msgPayload[:format.ContentsLen])
-	}
-}
-
-// Test that E2EEncrypt panics if the payload is too big (can't be padded)
-func TestE2EEncrypt_Panic(t *testing.T) {
-	_, e2eGrp := getGroups()
-	recipient := id.NewIdFromUInt(29, id.User, t)
-	msg := format.NewMessage()
-	msg.SetRecipient(recipient)
-	msgPayload := []byte("help me, i'm stuck in an" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory" +
-		" EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory")
-	msgPayload = msgPayload[:format.ContentsLen]
-	msg.Contents.Set(msgPayload)
-	msg.SetTimestamp(make([]byte, 16))
-
-	key := e2eGrp.NewInt(42)
-	h, _ := hash.NewCMixHash()
-	h.Write(key.Bytes())
-	fp := format.Fingerprint{}
-	copy(fp[:], h.Sum(nil))
-
-	defer func() {
-		if r := recover(); r == nil {
-			t.Errorf("E2EEncrypt should panic on payload too large")
-		}
-	}()
-
-	// E2E Encryption Panics
-	E2EEncrypt(e2eGrp, key, fp, msg)
-}
-
-// Test that E2EDecrypt and E2EDecryptUnsafe handle errors correctly
-func TestE2EDecrypt_Errors(t *testing.T) {
-	_, e2eGrp := getGroups()
-	recipient := id.NewIdFromUInt(29, id.User, t)
-	msg := format.NewMessage()
-	msg.SetRecipient(recipient)
-	msgPayload := []byte("help me, i'm stuck in an EnterpriseTextLabelDescriptorSetPipelineStateFactoryBeanFactory ")
-	msg.Contents.SetRightAligned(msgPayload)
-	msg.SetTimestamp(make([]byte, 16))
-
-	key := e2eGrp.NewInt(42)
-	h, _ := hash.NewCMixHash()
-	h.Write(key.Bytes())
-	fp := format.Fingerprint{}
-	copy(fp[:], h.Sum(nil))
-
-	// E2E Encryption
-	E2EEncrypt(e2eGrp, key, fp, msg)
-
-	// Copy message
-	badMsg := format.NewMessage()
-	badMsg.SetPayloadA(msg.GetPayloadA())
-	badMsg.SetPayloadB(msg.GetPayloadB())
-
-	// Corrupt MAC to make decryption fail
-	badMsg.SetMAC([]byte("sakfaskfajskasfkkaskfanjffffjnaf"))
-
-	// E2E Decryption returns error
-	err := E2EDecrypt(e2eGrp, key, badMsg)
-
-	if err == nil {
-		t.Errorf("E2EDecrypt should have returned error")
-	} else {
-		t.Logf("E2EDecrypt error: %v", err.Error())
-	}
-
-	// Unsafe E2E Decryption returns error
-	err = E2EDecryptUnsafe(e2eGrp, key, badMsg)
-
-	if err == nil {
-		t.Errorf("E2EDecryptUnsafe should have returned error")
-	} else {
-		t.Logf("E2EDecryptUnsafe error: %v", err.Error())
-	}
-
-	// Set correct MAC again
-	badMsg.SetMAC(msg.GetMAC())
-
-	// Corrupt timestamp to make decryption fail
-	badMsg.SetTimestamp([]byte("ABCDEF1234567890"))
-
-	// E2E Decryption returns error
-	err = E2EDecrypt(e2eGrp, key, badMsg)
-
-	if err == nil {
-		t.Errorf("E2EDecrypt should have returned error")
-	} else {
-		t.Logf("E2EDecrypt error: %v", err.Error())
-	}
-
-	// Unsafe E2E Decryption returns error
-	err = E2EDecryptUnsafe(e2eGrp, key, badMsg)
-
-	if err == nil {
-		t.Errorf("E2EDecryptUnsafe should have returned error")
-	} else {
-		t.Logf("E2EDecryptUnsafe error: %v", err.Error())
-	}
-
-	// Set correct Timestamp again
-	badMsg.SetTimestamp(msg.GetTimestamp())
-
-	// Corrupt payload to make decryption fail
-	badMsg.Contents.SetRightAligned([]byte(
-		"sakomnsfjeiknheuijhgfyaistuajhfaiuojfkhufijsahufiaij"))
-
-	// Calculate new MAC to avoid failing on that verification again
-	newMAC := hash.CreateHMAC(badMsg.Contents.Get(), key.Bytes())
-	badMsg.SetMAC(newMAC)
-
-	// E2E Decryption returns error
-	err = E2EDecrypt(e2eGrp, key, badMsg)
-
-	if err == nil {
-		t.Errorf("E2EDecrypt should have returned error")
-	} else {
-		t.Logf("E2EDecrypt error: %v", err.Error())
-	}
-}
-
-func getGroups() (*cyclic.Group, *cyclic.Group) {
-
-	cmixGrp := cyclic.NewGroup(
-		large.NewIntFromString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"+
-			"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"+
-			"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"+
-			"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"+
-			"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"+
-			"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"+
-			"83655D23DCA3AD961C62F356208552BB9ED529077096966D"+
-			"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"+
-			"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"+
-			"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"+
-			"15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16),
-		large.NewIntFromString("2", 16))
-
-	e2eGrp := cyclic.NewGroup(
-		large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B"+
-			"7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE"+
-			"DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F"+
-			"8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041"+
-			"023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45"+
-			"3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209"+
-			"6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29"+
-			"A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E"+
-			"37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2"+
-			"78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696"+
-			"015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E"+
-			"6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873"+
-			"847AEF49F66E43873", 16),
-		large.NewIntFromString("2", 16))
-
-	return cmixGrp, e2eGrp
-
-}
diff --git a/io/collate/format.go b/io/collate/format.go
new file mode 100644
index 0000000000000000000000000000000000000000..65c1e2681357c5f2f8c31c1123b19d12d9cbcfd6
--- /dev/null
+++ b/io/collate/format.go
@@ -0,0 +1,6 @@
+package collate
+
+import (
+	"encoding/binary"
+	"gitlab.com/elixxir/client/context/message"
+)
diff --git a/io/keyExchange/generate.sh b/io/keyExchange/generate.sh
new file mode 100644
index 0000000000000000000000000000000000000000..08904d8b1a8ffa53f9247b4c5338fb948d65dc51
--- /dev/null
+++ b/io/keyExchange/generate.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+protoc --go_out=. xchange.proto
diff --git a/io/keyExchange/init.go b/io/keyExchange/init.go
index 7159d57803c07649e28612d4bf6b6dc9372593ae..854eb34f7b3ab26e2f84c3ec314baacae5b51774 100644
--- a/io/keyExchange/init.go
+++ b/io/keyExchange/init.go
@@ -1,15 +1,37 @@
 package keyExchange
 
 import (
+	"github.com/golang/protobuf/proto"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/context"
+	"gitlab.com/elixxir/client/context/message"
 	"gitlab.com/elixxir/client/context/stoppable"
-	"gitlab.com/elixxir/primitives/switchboard"
+	"gitlab.com/elixxir/client/storage/e2e"
+	"gitlab.com/xx_network/primitives/id"
 )
 
+const keyExchangeTriggerName = "KeyExchangeTrigger"
+
 func Init(ctx *context.Context) stoppable.Stoppable {
 
 	//register the rekey request thread
-	rekeyRequestCh := make(chan switchboard.Item, 10)
-	ctx.Switchboard.RegisterChannel()
+	rekeyRequestCh := make(chan message.Receive, 10)
+	ctx.Switchboard.RegisterChannel(keyExchangeTriggerName, &id.ID{},
+		message.KeyExchangeTrigger, rekeyRequestCh)
+
+	triggerStop := stoppable.NewSingle(keyExchangeTriggerName)
 
+	go func() {
+		for true {
+			select {
+			case <-triggerStop.Quit():
+				return
+			case request := <-rekeyRequestCh:
+				ctx.Session.request.Sender
+			}
+		}
+		()
+	}
 }
+
+
diff --git a/io/keyExchange/rekey.go b/io/keyExchange/rekey.go
index ea1dfcd8d96682032429d1fd6f95bc9aa3eafa28..5c3fcdf4bb500ea13b3d46d8bed12a2232865329 100644
--- a/io/keyExchange/rekey.go
+++ b/io/keyExchange/rekey.go
@@ -4,7 +4,6 @@ import (
 	"github.com/golang/protobuf/proto"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/context"
 	"gitlab.com/elixxir/client/context/message"
 	"gitlab.com/elixxir/client/context/params"
@@ -30,7 +29,7 @@ func CheckKeyExchanges(ctx *context.Context, manager *e2e.Manager) {
 // session while the latter on an extand
 func trigger(ctx *context.Context, manager *e2e.Manager, session *e2e.Session) {
 	var negotiatingSession *e2e.Session
-	switch session.ConfirmationStatus() {
+	switch session.NegotiationStatus() {
 	// If the passed session is triggering a negotiation on a new session to
 	// replace itself, then create the session
 	case e2e.NewSessionTriggered:
@@ -44,7 +43,7 @@ func trigger(ctx *context.Context, manager *e2e.Manager, session *e2e.Session) {
 		negotiatingSession = session
 	default:
 		jww.FATAL.Panicf("Session %s provided invalid e2e "+
-			"negotiating status: %s", session, session.ConfirmationStatus())
+			"negotiating status: %s", session, session.NegotiationStatus())
 	}
 
 	// send the rekey notification to the partner
@@ -65,22 +64,22 @@ func negotiate(ctx *context.Context, session *e2e.Session) error {
 		e2eStore.GetGroup())
 
 	//build the payload
-	payload, err := proto.Marshal(&cmixproto.RekeyTrigger{
+	payload, err := proto.Marshal(&RekeyTrigger{
 		PublicKey: pubKey.Bytes(),
-		SessionID: session.GetTrigger().Bytes(),
+		SessionID: session.GetTrigger().Marshal(),
 	})
 
 	//If the payload cannot be marshaled, panic
 	if err != nil {
 		jww.FATAL.Printf("Failed to marshal payload for Key "+
-			"Negotation with %s", session.GetPartner())
+			"Negotation Trigger with %s", session.GetPartner())
 	}
 
 	//send session
-	m := message.Message{
+	m := message.Send{
 		Recipient:   session.GetPartner(),
 		Payload:     payload,
-		MessageType: int32(cmixproto.Type_REKEY_TRIGGER),
+		MessageType: message.KeyExchangeTrigger,
 	}
 
 	//send the message under the key exchange
@@ -108,23 +107,18 @@ func negotiate(ctx *context.Context, session *e2e.Session) error {
 			states.COMPLETED, states.FAILED)
 	}
 
-	//Start the thread which will handle the outcome of the send
-	go trackNegotiationResult(sendResults, len(rounds), session)
-}
-
-func trackNegotiationResult(resultsCh chan ds.EventReturn, numResults int, session *e2e.Session) {
-	success, numTimeOut, numRoundFail := utility.TrackResults(resultsCh, numResults)
+	//Wait until the result tracking responds
+	success, numTimeOut, numRoundFail := utility.TrackResults(sendResults, len(rounds))
 
 	// If a single partition of the Key Negotiation request does not
 	// transmit, the partner cannot read the result. Log the error and set
 	// the session as unconfirmed so it will re-trigger the negotiation
 	if !success {
-		jww.ERROR.Printf("Key Negotiation for %s failed to "+
+		session.SetNegotiationStatus(e2e.Unconfirmed)
+		return errors.Errorf("Key Negotiation for %s failed to "+
 			"transmit %v/%v paritions: %v round failures, %v timeouts",
-			session, numRoundFail+numTimeOut, numResults, numRoundFail,
+			session, numRoundFail+numTimeOut, len(rounds), numRoundFail,
 			numTimeOut)
-		session.SetNegotiationStatus(e2e.Unconfirmed)
-		return
 	}
 
 	// otherwise, the transmission is a success and this should be denoted
@@ -132,5 +126,8 @@ func trackNegotiationResult(resultsCh chan ds.EventReturn, numResults int, sessi
 	jww.INFO.Printf("Key Negotiation transmission for %s sucesfull",
 		session)
 	session.SetNegotiationStatus(e2e.Sent)
+
+	return nil
 }
 
+
diff --git a/io/keyExchange/trigger.go b/io/keyExchange/trigger.go
new file mode 100644
index 0000000000000000000000000000000000000000..06dd4a682d240aef49e00f899a0f7098710e3219
--- /dev/null
+++ b/io/keyExchange/trigger.go
@@ -0,0 +1,110 @@
+package keyExchange
+
+import (
+	"github.com/golang/protobuf/proto"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/context"
+	"gitlab.com/elixxir/client/context/message"
+	"gitlab.com/elixxir/client/context/params"
+	"gitlab.com/elixxir/client/storage/e2e"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+func handleTrigger(ctx *context.Context, request message.Receive) {
+	//ensure the message was encrypted properly
+	if request.Encryption != message.E2E {
+		jww.ERROR.Printf("Received non-e2e encrypted Key Exchange "+
+			"Trigger from partner %s", request.Sender)
+		return
+	}
+
+	//Get the partner
+	partner, err := ctx.Session.E2e().GetPartner(request.Sender)
+	if err != nil {
+		jww.ERROR.Printf("Received Key Exchange Trigger with unknown "+
+			"partner %s", request.Sender)
+		return
+	}
+
+	//unmarshal the message
+	oldSessionID, PartnerPublicKey, err := unmarshalKeyExchangeTrigger(
+		ctx.Session.E2e().GetGroup(), request.Payload)
+	if err != nil {
+		jww.ERROR.Printf("Failed to unmarshal Key Exchange Trigger with "+
+			"partner %s: %s", request.Sender, err)
+		return
+	}
+
+	//get the old session which triggered the exchange
+	oldSession := partner.GetSendSession(oldSessionID)
+	if oldSession == nil {
+		jww.ERROR.Printf("Failed to find parent session %s for Key "+
+			"Exchange Trigger from partner %s: %s", oldSession, request.Sender,
+			err)
+		return
+	}
+
+	//create the new session
+	newSession, duplicate := partner.NewReceiveSession(PartnerPublicKey,
+		e2e.GetDefaultSessionParams(), oldSession)
+	// new session being nil means the session was a duplicate. This is possible
+	// in edge cases where the partner crashes during operation. The session
+	// creation in this case ignores the new session, but the confirmation
+	// message is still sent so the partner will know the session is confirmed
+	if duplicate {
+		jww.INFO.Printf("New session from Key Exchange Trigger to "+
+			"create session %s for partner %s is a duplicate, request ignored",
+			newSession.GetID(), request.Sender)
+	}
+
+	//Send the Confirmation Message
+	//build the payload
+	payload, err := proto.Marshal(&RekeyConfirm{
+		SessionID: newSession.GetTrigger().Marshal(),
+	})
+
+	//If the payload cannot be marshaled, panic
+	if err != nil {
+		jww.FATAL.Printf("Failed to marshal payload for Key "+
+			"Negotation Confirmation with %s", newSession.GetPartner())
+	}
+
+	//build the message
+	m := message.Send{
+		Recipient:   newSession.GetPartner(),
+		Payload:     payload,
+		MessageType: message.KeyExchangeConfirm,
+	}
+
+	//send the message under the key exchange
+	e2eParams := params.GetDefaultE2E()
+	cmixParams := params.GetDefaultCMIX()
+
+	rounds, err := ctx.Manager.SendE2E(m, e2eParams, cmixParams)
+
+}
+
+func unmarshalKeyExchangeTrigger(grp *cyclic.Group, payload []byte) (e2e.SessionID,
+	*cyclic.Int, error) {
+
+	msg := &RekeyTrigger{}
+	if err := proto.Unmarshal(payload, msg); err != nil {
+		return e2e.SessionID{}, nil, errors.Errorf("Failed to "+
+			"unmarshal payload: %s", err)
+	}
+
+	oldSessionID := e2e.SessionID{}
+	if err := oldSessionID.Unmarshal(msg.SessionID); err != nil {
+		return e2e.SessionID{}, nil, errors.Errorf("Failed to unmarshal"+
+			" sessionID: %s", err)
+	}
+
+	if !grp.BytesInside(msg.PublicKey) {
+		return e2e.SessionID{}, nil, errors.Errorf("Public key not in e2e group; PublicKey %v",
+			msg.PublicKey)
+	}
+
+	return oldSessionID, grp.NewIntFromBytes(msg.PublicKey), nil
+}
diff --git a/io/keyExchange/xchange.pb.go b/io/keyExchange/xchange.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..c7923f4730105260369b5a07635df6b6edae9d2d
--- /dev/null
+++ b/io/keyExchange/xchange.pb.go
@@ -0,0 +1,231 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2018 Privategrity Corporation                                   /
+//                                                                             /
+// All rights reserved.                                                        /
+////////////////////////////////////////////////////////////////////////////////
+
+// Call ./generate.sh to generate the protocol buffer code
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.25.0
+// 	protoc        (unknown)
+// source: xchange.proto
+
+package keyExchange
+
+import (
+	proto "github.com/golang/protobuf/proto"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// This is a compile-time assertion that a sufficiently up-to-date version
+// of the legacy proto package is being used.
+const _ = proto.ProtoPackageIsVersion4
+
+type RekeyTrigger struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// PublicKey used in the registration
+	PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"`
+	// ID of the session used to create this session
+	SessionID []byte `protobuf:"bytes,2,opt,name=sessionID,proto3" json:"sessionID,omitempty"`
+}
+
+func (x *RekeyTrigger) Reset() {
+	*x = RekeyTrigger{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_xchange_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RekeyTrigger) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RekeyTrigger) ProtoMessage() {}
+
+func (x *RekeyTrigger) ProtoReflect() protoreflect.Message {
+	mi := &file_xchange_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RekeyTrigger.ProtoReflect.Descriptor instead.
+func (*RekeyTrigger) Descriptor() ([]byte, []int) {
+	return file_xchange_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *RekeyTrigger) GetPublicKey() []byte {
+	if x != nil {
+		return x.PublicKey
+	}
+	return nil
+}
+
+func (x *RekeyTrigger) GetSessionID() []byte {
+	if x != nil {
+		return x.SessionID
+	}
+	return nil
+}
+
+type RekeyConfirm struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// ID of the session created
+	SessionID []byte `protobuf:"bytes,1,opt,name=sessionID,proto3" json:"sessionID,omitempty"`
+}
+
+func (x *RekeyConfirm) Reset() {
+	*x = RekeyConfirm{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_xchange_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RekeyConfirm) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RekeyConfirm) ProtoMessage() {}
+
+func (x *RekeyConfirm) ProtoReflect() protoreflect.Message {
+	mi := &file_xchange_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RekeyConfirm.ProtoReflect.Descriptor instead.
+func (*RekeyConfirm) Descriptor() ([]byte, []int) {
+	return file_xchange_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *RekeyConfirm) GetSessionID() []byte {
+	if x != nil {
+		return x.SessionID
+	}
+	return nil
+}
+
+var File_xchange_proto protoreflect.FileDescriptor
+
+var file_xchange_proto_rawDesc = []byte{
+	0x0a, 0x0d, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+	0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x22, 0x4a, 0x0a, 0x0c, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x54,
+	0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
+	0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69,
+	0x63, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49,
+	0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+	0x49, 0x44, 0x22, 0x2c, 0x0a, 0x0c, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x72, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44,
+	0x42, 0x0d, 0x5a, 0x0b, 0x6b, 0x65, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x62,
+	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_xchange_proto_rawDescOnce sync.Once
+	file_xchange_proto_rawDescData = file_xchange_proto_rawDesc
+)
+
+func file_xchange_proto_rawDescGZIP() []byte {
+	file_xchange_proto_rawDescOnce.Do(func() {
+		file_xchange_proto_rawDescData = protoimpl.X.CompressGZIP(file_xchange_proto_rawDescData)
+	})
+	return file_xchange_proto_rawDescData
+}
+
+var file_xchange_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_xchange_proto_goTypes = []interface{}{
+	(*RekeyTrigger)(nil), // 0: parse.RekeyTrigger
+	(*RekeyConfirm)(nil), // 1: parse.RekeyConfirm
+}
+var file_xchange_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_xchange_proto_init() }
+func file_xchange_proto_init() {
+	if File_xchange_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_xchange_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RekeyTrigger); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_xchange_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RekeyConfirm); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_xchange_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_xchange_proto_goTypes,
+		DependencyIndexes: file_xchange_proto_depIdxs,
+		MessageInfos:      file_xchange_proto_msgTypes,
+	}.Build()
+	File_xchange_proto = out.File
+	file_xchange_proto_rawDesc = nil
+	file_xchange_proto_goTypes = nil
+	file_xchange_proto_depIdxs = nil
+}
diff --git a/io/keyExchange/xchange.proto b/io/keyExchange/xchange.proto
new file mode 100644
index 0000000000000000000000000000000000000000..76dac5e960f539e95d56a56624c6f7eaff34cd5d
--- /dev/null
+++ b/io/keyExchange/xchange.proto
@@ -0,0 +1,24 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2018 Privategrity Corporation                                   /
+//                                                                             /
+// All rights reserved.                                                        /
+////////////////////////////////////////////////////////////////////////////////
+
+// Call ./generate.sh to generate the protocol buffer code
+
+syntax = "proto3";
+
+package parse;
+option go_package = "keyExchange";
+
+message RekeyTrigger {
+    // PublicKey used in the registration
+    bytes publicKey = 1;
+    // ID of the session used to create this session
+    bytes sessionID = 2;
+}
+
+message RekeyConfirm {
+    // ID of the session created
+    bytes sessionID = 1;
+}
diff --git a/io/receive.go b/io/receive.go
index fcfa34d229f8573cf97061927670fce7e58b3ade..af0d66fb53c84f81386965a58247d3b3d192ccc0 100644
--- a/io/receive.go
+++ b/io/receive.go
@@ -9,9 +9,9 @@ package io
 import (
 	"fmt"
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/crypto"
 	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/user"
@@ -176,7 +176,7 @@ func handleE2EReceiving(session user.Session, switchb *switchboard.Switchboard,
 		rekeyMsg := &parse.Message{
 			Sender: partner,
 			TypedBody: parse.TypedBody{
-				MessageType: int32(cmixproto.Type_NO_TYPE),
+				MessageType: int32(keyExchange.Type_NO_TYPE),
 				Body:        partnerPubKey,
 			},
 			InferredType: parse.Rekey,
diff --git a/io/send.go b/io/send.go
index 2a43bd387a091de5b0630cef7cdb2ef63ac4a278..80aa9d19a473c2aa469816a4ff4075ac9da97197 100644
--- a/io/send.go
+++ b/io/send.go
@@ -9,9 +9,9 @@ package io
 import (
 	"fmt"
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/crypto"
 	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/keyStore"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/user"
@@ -264,7 +264,7 @@ func handleE2ESending(session user.Session, switchb *switchboard.Switchboard,
 		rekeyMsg := &parse.Message{
 			Sender: userData.ThisUser.User,
 			TypedBody: parse.TypedBody{
-				MessageType: int32(cmixproto.Type_REKEY_TRIGGER),
+				MessageType: int32(keyExchange.Type_REKEY_TRIGGER),
 				Body:        []byte{},
 			},
 			InferredType: parse.None,
diff --git a/keyStore/action.go b/keyStore/action.go
deleted file mode 100644
index 52cdf7e389bf22821c4ca8ba6981f0cee82c7987..0000000000000000000000000000000000000000
--- a/keyStore/action.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package keyStore
-
-type Action uint8
-
-const (
-	None Action = iota
-	Rekey
-	Purge
-	Deleted
-)
-
-func (a Action) String() string {
-	var ret string
-	switch a {
-	case None:
-		ret = "None"
-	case Rekey:
-		ret = "Rekey"
-	case Purge:
-		ret = "Purge"
-	case Deleted:
-		ret = "Deleted"
-	}
-	return ret
-}
diff --git a/keyStore/action_test.go b/keyStore/action_test.go
deleted file mode 100644
index 76463d97e5281e3654b4f5be8834a045e5bec2fa..0000000000000000000000000000000000000000
--- a/keyStore/action_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package keyStore
-
-import "testing"
-
-// Test all outputs of String for coverage
-func TestAction_String(t *testing.T) {
-	expectedStr := "None"
-	action := None
-	if action.String() != expectedStr {
-		t.Errorf("String returned %s, expected %s",
-			action.String(),
-			expectedStr)
-	}
-
-	expectedStr = "Rekey"
-	action = Rekey
-	if action.String() != expectedStr {
-		t.Errorf("String returned %s, expected %s",
-			action.String(),
-			expectedStr)
-	}
-
-	expectedStr = "Purge"
-	action = Purge
-	if action.String() != expectedStr {
-		t.Errorf("String returned %s, expected %s",
-			action.String(),
-			expectedStr)
-	}
-
-	expectedStr = "Deleted"
-	action = Deleted
-	if action.String() != expectedStr {
-		t.Errorf("String returned %s, expected %s",
-			action.String(),
-			expectedStr)
-	}
-}
diff --git a/keyStore/e2eKey.go b/keyStore/e2eKey.go
deleted file mode 100644
index 3c6226477ab86bd3bc34d30786eea663abe00e29..0000000000000000000000000000000000000000
--- a/keyStore/e2eKey.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package keyStore
-
-import (
-	"gitlab.com/elixxir/client/parse"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/hash"
-	"gitlab.com/elixxir/primitives/format"
-)
-
-type E2EKey struct {
-	// Link to Manager
-	manager *KeyManager
-
-	// Key to be used
-	key *cyclic.Int
-
-	// Designation of crypto type
-	outer parse.CryptoType
-
-	// keyNum is needed by Key Manager
-	// to keep track of which receiving keys
-	// have been used
-	keyNum uint32
-}
-
-// Get key manager
-func (e2ekey *E2EKey) GetManager() *KeyManager {
-	return e2ekey.manager
-}
-
-// Get key value (cyclic.Int)
-func (e2ekey *E2EKey) GetKey() *cyclic.Int {
-	return e2ekey.key
-}
-
-// Get key type, E2E or Rekey
-func (e2ekey *E2EKey) GetOuterType() parse.CryptoType {
-	return e2ekey.outer
-}
-
-// Generate key fingerprint
-// NOTE: This function is not a getter,
-// it returns a new byte array on each call
-func (e2ekey *E2EKey) KeyFingerprint() format.Fingerprint {
-	h, _ := hash.NewCMixHash()
-	h.Write(e2ekey.key.Bytes())
-	fp := format.Fingerprint{}
-	copy(fp[:], h.Sum(nil))
-	return fp
-}
diff --git a/keyStore/e2eKey_test.go b/keyStore/e2eKey_test.go
deleted file mode 100644
index 19fa0b083b1a321eebe8428d56915d5913b883c7..0000000000000000000000000000000000000000
--- a/keyStore/e2eKey_test.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package keyStore
-
-import (
-	"bytes"
-	"encoding/hex"
-	"testing"
-)
-
-// Test key fingerprint for consistency
-func TestE2EKey_KeyFingerprint(t *testing.T) {
-	grp := initGroup()
-	key := new(E2EKey)
-	key.key = grp.NewInt(42)
-	keyFP := key.KeyFingerprint()
-	expectedFP, _ := hex.DecodeString(
-		"395a122eb1402bf256d86e3fa44764cf" +
-			"9acc559017a00b2b9ee12498e73ef2b5")
-
-	if !bytes.Equal(keyFP[:], expectedFP) {
-		t.Errorf("Key Fingerprint value is wrong. Expected %x"+
-			", got %x", expectedFP, keyFP[:])
-	}
-}
diff --git a/keyStore/keyManager.go b/keyStore/keyManager.go
deleted file mode 100644
index 92ce0f9fba6249bb73420c3ef824ea721faab53e..0000000000000000000000000000000000000000
--- a/keyStore/keyManager.go
+++ /dev/null
@@ -1,592 +0,0 @@
-package keyStore
-
-import (
-	"bytes"
-	"encoding/binary"
-	"encoding/gob"
-	"gitlab.com/elixxir/client/globals"
-	"gitlab.com/elixxir/client/parse"
-	"gitlab.com/elixxir/crypto/cyclic"
-	//"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"sync/atomic"
-)
-
-// The KeyManager keeps track of all keys used in a single E2E
-// uni-directional relationship between the user and a partner
-// It tracks usage of send Keys and ReKeys in an atomic sendState
-// OR
-// It tracks usage of receiving Keys and ReKeys in lists of
-// atomic "dirty bit" states
-// It also owns the send Keys and ReKeys stacks of keys
-// OR lists of receiving Keys and ReKeys fingerprints
-// All Key Managers can be stored in the session object, and
-// can be GOB encoded/decoded, preserving the state
-// When the GOB Decode is successful, GenerateKeys can be called
-// on the KeyManager to generate all keys that have not been used
-type KeyManager struct {
-	// Underlying key
-	baseKey *cyclic.Int
-	// Own Private Key
-	privKey *cyclic.Int
-	// Partner Public Key
-	pubKey *cyclic.Int
-
-	// Designates end-to-end partner
-	partner *id.ID
-
-	// True if key manager tracks send keys, false if receive keys
-	sendOrRecv bool
-
-	// State of Sending Keys and Rekeys, formatted as follows:
-	//                      Bits
-	// |    63   | 62 - 56 |   55 - 40   | 39 - 32 |  31 - 0   |
-	// | deleted |  empty  | rekey count |  empty  | key count |
-	// |  1 bit  |  7 bits |   16 bits   |  8 bits |   32 bits |
-	sendState *uint64
-
-	// Value of the counter at which a rekey is triggered
-	ttl uint16
-
-	// Total number of Keys
-	numKeys uint32
-	// Total number of Rekey keys
-	numReKeys uint16
-
-	// Received Keys dirty bits
-	// Each bit represents a single Receiving Key
-	recvKeysState [numStates]*uint64
-	// Received ReKeys dirty bits
-	// Each bit represents a single Receiving ReKey
-	recvReKeysState [numReStates]*uint64
-
-	// Send Keys Stack
-	sendKeys *KeyStack
-	// Send ReKeys Stack
-	sendReKeys *KeyStack
-	// Receive Keys fingerprint list
-	recvKeysFingerprint []format.Fingerprint
-	// Receive ReKeys fingerprint list
-	recvReKeysFingerprint []format.Fingerprint
-}
-
-// Creates a new KeyManager to manage E2E Keys between user and partner
-// Receives the baseKey, privKey, pubKey, partner userID, numKeys, ttl and numReKeys
-// All internal states are forced to 0 for safety purposes
-func NewManager(baseKey *cyclic.Int,
-	privKey *cyclic.Int, pubKey *cyclic.Int,
-	partner *id.ID, sendOrRecv bool,
-	numKeys uint32, ttl uint16, numReKeys uint16) *KeyManager {
-
-	km := new(KeyManager)
-	km.baseKey = baseKey
-	km.privKey = privKey
-	km.pubKey = pubKey
-	km.partner = partner
-	km.sendOrRecv = sendOrRecv
-	km.sendState = new(uint64)
-	*km.sendState = 0
-	km.ttl = ttl
-	km.numKeys = numKeys
-	km.numReKeys = numReKeys
-	for i := range km.recvKeysState {
-		km.recvKeysState[i] = new(uint64)
-		*km.recvKeysState[i] = 0
-	}
-	for i := range km.recvReKeysState {
-		km.recvReKeysState[i] = new(uint64)
-		*km.recvReKeysState[i] = 0
-	}
-	return km
-}
-
-// Get the base key from the Key Manager
-func (km *KeyManager) GetBaseKey() *cyclic.Int {
-	return km.baseKey
-}
-
-// Get the private key from the Key Manager
-func (km *KeyManager) GetPrivKey() *cyclic.Int {
-	return km.privKey
-}
-
-// Get the public key from the Key Manager
-func (km *KeyManager) GetPubKey() *cyclic.Int {
-	return km.pubKey
-}
-
-// Get the partner ID from the Key Manager
-func (km *KeyManager) GetPartner() *id.ID {
-	return km.partner
-}
-
-// Constants needed for access to sendState
-//                      Bits
-// |    63   | 62 - 56 |   55 - 40   | 39 - 32 |  31 - 0   |
-// | deleted |  empty  | rekey count |  empty  | key count |
-// |  1 bit  |  7 bits |   16 bits   |  8 bits |   32 bits |
-const (
-	// Delete is most significant bit
-	stateDeleteMask uint64 = 0x8000000000000000
-	// Key Counter is lowest 32 bits
-	stateKeyMask uint64 = 0x00000000FFFFFFFF
-	// ReKey Counter is bits 55 to 40 (0 indexed)
-	stateReKeyMask uint64 = 0x00FFFF0000000000
-	// ReKey Counter shift value is 40
-	stateReKeyShift uint64 = 40
-	// Delete Increment is 1 shifted by 63 bits
-	stateDeleteIncr uint64 = 1 << 63
-	// Key Counter increment is 1
-	stateKeyIncr uint64 = 1
-	// ReKey Counter increment is 1 << 40
-	stateReKeyIncr uint64 = 1 << stateReKeyShift
-)
-
-// Check if a Rekey should be triggered
-// Extract the Key counter from state and then
-// compare to passed val
-func checkRekey(state uint64, val uint16) bool {
-	keyCounter := uint32(state & stateKeyMask)
-	return keyCounter >= uint32(val)
-}
-
-// Check if a Purge should be triggered
-// Extract the ReKey counter from state and then
-// compare to passed val
-func checkPurge(state uint64, val uint16) bool {
-	reKeyCounter := uint16((state & stateReKeyMask) >> stateReKeyShift)
-	return reKeyCounter >= val
-}
-
-// UpdateState atomically updates internal state
-// of key manager for send Keys or ReKeys
-// Once the number of used keys reaches the TTL value
-// a Rekey Action is returned
-// Once the number of used ReKeys reaches the the NumReKeys
-// value, a Purge Action is returned, and the Key Manager
-// can be destroyed
-// When a Purge is returned, the state topmost bit is set,
-// indicating that the KeyManager is now Deleted
-// This means that if the caller doesn't destroy it
-// right away, any further send Keys obtained from the
-// global key map will have the action set to Deleted
-// which can be used to trigger an error
-func (km *KeyManager) updateState(rekey bool) Action {
-	var stateIncr uint64
-	// Choose the correct increment according to key type
-	if rekey {
-		stateIncr = stateReKeyIncr
-	} else {
-		stateIncr = stateKeyIncr
-	}
-
-	// Atomically increment the state and save result
-	result := atomic.AddUint64(km.sendState, stateIncr)
-
-	// Check if KeyManager is in Deleted state
-	if result&stateDeleteMask != 0 {
-		return Deleted
-	}
-
-	// Check if result should trigger a Purge
-	if rekey && checkPurge(result, km.numReKeys) {
-		// set delete bit
-		atomic.AddUint64(km.sendState, stateDeleteIncr)
-		return Purge
-		// Check if result should trigger a Rekey
-	} else if !rekey && checkRekey(result, km.ttl) {
-		return Rekey
-	}
-	return None
-}
-
-// UpdateRecvState atomically updates internal
-// receiving state of key manager
-// It sets the correct bit of state index based on keyNum
-// and rekey
-// The keyNum is used to select the correct state from the array
-// Since each state is an uint64, keyNum / 64 determines the index
-// and keyNum % 64 determines the bit that needs to be set
-// Rekey is used to select which state array to update:
-// recvReKeysState or recvKeysState
-// The state is atomically updated by adding a value of 1 shifted
-// to the determined bit
-func (km *KeyManager) updateRecvState(rekey bool, keyNum uint32) {
-	stateIdx := keyNum / 64
-	stateBit := uint64(1 << (keyNum % 64))
-
-	if rekey {
-		atomic.AddUint64(km.recvReKeysState[stateIdx], stateBit)
-	} else {
-		atomic.AddUint64(km.recvKeysState[stateIdx], stateBit)
-	}
-}
-
-// Return true if bit specified by keyNum is set, meaning
-// that a particular key or reKey has been used
-// The keyNum is used to select the correct state from the array
-// Since each state is an uint64, keyNum / 64 determines the index
-// and keyNum % 64 determines the bit that needs to be read
-// Rekey is used to select which state array to update:
-// recvReKeysState or recvKeysState
-// The state is atomically loaded and then the bit mask is applied
-// to check if the value is 0 or different
-func (km *KeyManager) checkRecvStateBit(rekey bool, keyNum uint32) bool {
-	stateIdx := keyNum / 64
-	stateBit := uint64(1 << (keyNum % 64))
-
-	var state uint64
-	if rekey {
-		state = atomic.LoadUint64(km.recvReKeysState[stateIdx])
-	} else {
-		state = atomic.LoadUint64(km.recvKeysState[stateIdx])
-	}
-
-	return (state & stateBit) != 0
-}
-
-// GenerateKeys will generate all previously unused keys based on
-// KeyManager states
-// Sending Keys and ReKeys are generated and then pushed to a stack,
-// meaning that they are used in a LIFO manner.
-// This makes it easier to generate all send keys from a pre-existing state
-// as the number of unused keys will be simply numKeys - usedKeys
-// where usedKeys is extracted from the KeyManager state
-// Receiving Keys and ReKeys are generated in order, but there is no
-// guarantee that they will be used in order, this is why KeyManager
-// keeps a list of fingerprint for all receiving keys
-// When generating receiving keys from pre-existing state, all bits
-// from receiving states are checked, and if the bit is set ("dirty")
-// the key is not added to the Reception Keys map and fingerprint list
-// This way, this function can be used to generate all keys when a new
-// E2E relationship is established, and also to generate all previously
-// unused keys based on KeyManager state, when reloading an user session
-// The function returns modifications that need to be independently made to the keystore.
-func (km *KeyManager) GenerateKeys(grp *cyclic.Group, userID *id.ID) []*E2EKey {
-	var recE2EKeys []*E2EKey
-
-	if km.sendOrRecv {
-		// Calculate how many unused send keys are needed
-		usedSendKeys := uint32(*km.sendState & stateKeyMask)
-		numGenSendKeys := uint(km.numKeys - usedSendKeys)
-		usedSendReKeys := uint16((*km.sendState & stateReKeyMask) >> stateReKeyShift)
-		numGenSendReKeys := uint(km.numReKeys - usedSendReKeys)
-
-		// Generate numGenSendKeys send keys
-		sendKeys := make([]*cyclic.Int, numGenSendKeys)
-		// Generate numGenSendReKeys send reKeys
-		sendReKeys := make([]*cyclic.Int, numGenSendReKeys)
-
-		// Create Send Keys Stack on keyManager
-		km.sendKeys = NewKeyStack()
-
-		// Create send E2E Keys and add to stack
-		for _, key := range sendKeys {
-			e2ekey := new(E2EKey)
-			e2ekey.key = key
-			e2ekey.manager = km
-			e2ekey.outer = parse.E2E
-			km.sendKeys.Push(e2ekey)
-		}
-
-		// Create Send ReKeys Stack on keyManager
-		km.sendReKeys = NewKeyStack()
-
-		// Create send E2E ReKeys and add to stack
-		for _, key := range sendReKeys {
-			e2ekey := new(E2EKey)
-			e2ekey.key = key
-			e2ekey.manager = km
-			e2ekey.outer = parse.Rekey
-			km.sendReKeys.Push(e2ekey)
-		}
-
-	} else {
-		// For receiving keys, generate all, and then only add to the map
-		// the unused ones based on recvStates
-		// Generate numKeys recv keys
-		recvKeys := make([]*cyclic.Int, 5)
-		// Generate numReKeys recv reKeys
-		recvReKeys := make([]*cyclic.Int, 5)
-
-		// Create Receive E2E Keys and put them into the E2eKeys obbj to return into the parent
-		// Skip keys that were already used as per recvStates
-		km.recvKeysFingerprint = make([]format.Fingerprint, 0)
-		for i, key := range recvKeys {
-			if !km.checkRecvStateBit(false, uint32(i)) {
-				e2ekey := new(E2EKey)
-				e2ekey.key = key
-				e2ekey.manager = km
-				e2ekey.outer = parse.E2E
-				e2ekey.keyNum = uint32(i)
-				recE2EKeys = append(recE2EKeys, e2ekey)
-				keyFP := e2ekey.KeyFingerprint()
-				km.recvKeysFingerprint = append(km.recvKeysFingerprint, keyFP)
-			}
-		}
-
-		// Create Receive E2E reKeys and add them into the E2ERekeys variable to return back to parent
-		// while keeping a list of the fingerprints
-		km.recvReKeysFingerprint = make([]format.Fingerprint, 0)
-		for i, key := range recvReKeys {
-			if !km.checkRecvStateBit(true, uint32(i)) {
-				e2ekey := new(E2EKey)
-				e2ekey.key = key
-				e2ekey.manager = km
-				e2ekey.outer = parse.Rekey
-				e2ekey.keyNum = uint32(i)
-				recE2EKeys = append(recE2EKeys, e2ekey)
-				keyFP := e2ekey.KeyFingerprint()
-				km.recvReKeysFingerprint = append(km.recvReKeysFingerprint, keyFP)
-			}
-		}
-	}
-	return recE2EKeys
-}
-
-// Pops first key from Send KeyStack of KeyManager
-// Atomically updates Key Manager Sending state
-// Returns *E2EKey and KeyAction
-func (km *KeyManager) PopKey() (*E2EKey, Action) {
-	// Pop key
-	e2eKey := km.sendKeys.Pop()
-	// Update Key Manager State
-	action := km.updateState(false)
-	return e2eKey, action
-}
-
-// Pops first rekey from Send ReKeyStack of KeyManager
-// Atomically updates Key Manager Sending state
-// Returns *E2EKey and KeyAction
-func (km *KeyManager) PopRekey() (*E2EKey, Action) {
-	// Pop key
-	e2eKey := km.sendReKeys.Pop()
-	// Update Key Manager State
-	action := km.updateState(true)
-	return e2eKey, action
-}
-
-// If the KeyManager is a sending one, destroy
-// will remove it from KeyStore map and then destroy it's key stacks
-// If it is a receiving one, destroy will remove it
-// from KeyStore map and then remove all keys from receiving key
-// map
-func (km *KeyManager) Destroy(ks *KeyStore) {
-	if km.sendOrRecv {
-		// Remove KeyManager from KeyStore
-		ks.DeleteSendManager(km.partner)
-		// Delete KeyStacks
-		km.sendKeys.Delete()
-		km.sendReKeys.Delete()
-	} else {
-		globals.Log.WARN.Println("This function no longer handles deleting of reception keys.")
-	}
-
-	// Hopefully when the function returns there
-	// will be no keys referencing this Manager left,
-	// so it will be garbage collected
-}
-
-// GobEncode the KeyManager so that it can be saved in
-// the session file
-func (km *KeyManager) GobEncode() ([]byte, error) {
-	// Anonymous structure that flattens nested structures
-	s := struct {
-		Partner        []byte
-		SendOrRecv     []byte
-		State          []byte
-		TTL            []byte
-		NumKeys        []byte
-		NumReKeys      []byte
-		RecvKeyState   []byte
-		RecvReKeyState []byte
-		BaseKey        []byte
-		PrivKey        []byte
-		PubKey         []byte
-	}{
-		km.partner.Bytes(),
-		make([]byte, 1),
-		make([]byte, 8),
-		make([]byte, 2),
-		make([]byte, 4),
-		make([]byte, 2),
-		make([]byte, 8*numStates),
-		make([]byte, 8*numReStates),
-		make([]byte, 0),
-		make([]byte, 0),
-		make([]byte, 0),
-	}
-
-	// Set send or receive
-	if km.sendOrRecv {
-		s.SendOrRecv[0] = 0xFF
-	} else {
-		s.SendOrRecv[0] = 0x00
-	}
-
-	// Convert all internal uints to bytes
-	binary.BigEndian.PutUint64(s.State, *km.sendState)
-	binary.BigEndian.PutUint16(s.TTL, km.ttl)
-	binary.BigEndian.PutUint32(s.NumKeys, km.numKeys)
-	binary.BigEndian.PutUint16(s.NumReKeys, km.numReKeys)
-	for i := 0; i < int(numStates); i++ {
-		binary.BigEndian.PutUint64(
-			s.RecvKeyState[i*8:(i+1)*8],
-			*km.recvKeysState[i])
-	}
-	for i := 0; i < int(numReStates); i++ {
-		binary.BigEndian.PutUint64(
-			s.RecvReKeyState[i*8:(i+1)*8],
-			*km.recvReKeysState[i])
-	}
-
-	// GobEncode baseKey
-	keyBytes, err := km.baseKey.GobEncode()
-
-	if err != nil {
-		return nil, err
-	}
-
-	// Add baseKey to struct
-	s.BaseKey = append(s.BaseKey, keyBytes...)
-
-	// GobEncode privKey
-	if km.privKey != nil {
-		keyBytes, err = km.privKey.GobEncode()
-
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	// Add privKey to struct
-	s.PrivKey = append(s.BaseKey, keyBytes...)
-
-	// GobEncode pubKey
-	if km.pubKey != nil {
-		keyBytes, err = km.pubKey.GobEncode()
-
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	// Add pubKey to struct
-	s.PubKey = append(s.BaseKey, keyBytes...)
-
-	var buf bytes.Buffer
-
-	// Create new encoder that will transmit the buffer
-	enc := gob.NewEncoder(&buf)
-
-	// Transmit the data
-	err = enc.Encode(s)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return buf.Bytes(), nil
-}
-
-// GobDecode bytes into a new Key Manager
-// It can be used to get Key Managers from the
-// store session file
-// GenerateKeys should then be run so that all
-// key maps are restored properly
-func (km *KeyManager) GobDecode(in []byte) error {
-	// Anonymous structure that flattens nested structures
-	s := struct {
-		Partner        []byte
-		SendOrRecv     []byte
-		State          []byte
-		TTL            []byte
-		NumKeys        []byte
-		NumReKeys      []byte
-		RecvKeyState   []byte
-		RecvReKeyState []byte
-		BaseKey        []byte
-		PrivKey        []byte
-		PubKey         []byte
-	}{
-		make([]byte, 32),
-		make([]byte, 1),
-		make([]byte, 8),
-		make([]byte, 2),
-		make([]byte, 4),
-		make([]byte, 2),
-		make([]byte, 8*numStates),
-		make([]byte, 8*numReStates),
-		[]byte{},
-		[]byte{},
-		[]byte{},
-	}
-
-	var buf bytes.Buffer
-
-	// Write bytes to the buffer
-	buf.Write(in)
-
-	// Create new decoder that reads from the buffer
-	dec := gob.NewDecoder(&buf)
-
-	// Receive and decode data
-	err := dec.Decode(&s)
-
-	if err != nil {
-		return err
-	}
-
-	partner, err := id.Unmarshal(s.Partner)
-	if err != nil {
-		return err
-	}
-	km.partner = partner
-
-	// Convert decoded bytes and put into key manager structure
-	km.baseKey = new(cyclic.Int)
-	err = km.baseKey.GobDecode(s.BaseKey)
-
-	if err != nil {
-		return err
-	}
-
-	km.privKey = new(cyclic.Int)
-	err = km.privKey.GobDecode(s.PrivKey)
-
-	if err != nil {
-		return err
-	}
-
-	km.pubKey = new(cyclic.Int)
-	err = km.pubKey.GobDecode(s.PubKey)
-
-	if err != nil {
-		return err
-	}
-
-	if s.SendOrRecv[0] == 0xFF {
-		km.sendOrRecv = true
-	} else {
-		km.sendOrRecv = false
-	}
-
-	km.sendState = new(uint64)
-	*km.sendState = binary.BigEndian.Uint64(s.State)
-	km.ttl = binary.BigEndian.Uint16(s.TTL)
-	km.numKeys = binary.BigEndian.Uint32(s.NumKeys)
-	km.numReKeys = binary.BigEndian.Uint16(s.NumReKeys)
-	for i := 0; i < int(numStates); i++ {
-		km.recvKeysState[i] = new(uint64)
-		*km.recvKeysState[i] = binary.BigEndian.Uint64(
-			s.RecvKeyState[i*8 : (i+1)*8])
-	}
-	for i := 0; i < int(numReStates); i++ {
-		km.recvReKeysState[i] = new(uint64)
-		*km.recvReKeysState[i] = binary.BigEndian.Uint64(
-			s.RecvReKeyState[i*8 : (i+1)*8])
-	}
-
-	return nil
-}
diff --git a/keyStore/keyManager_test.go b/keyStore/keyManager_test.go
deleted file mode 100644
index 1163b9185333e980f035c7b4497f2bcf7a5cfe9c..0000000000000000000000000000000000000000
--- a/keyStore/keyManager_test.go
+++ /dev/null
@@ -1,671 +0,0 @@
-package keyStore
-
-import (
-	"bytes"
-	"encoding/base64"
-	"encoding/gob"
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/elixxir/crypto/large"
-	"gitlab.com/xx_network/primitives/id"
-	"testing"
-)
-
-// initGroup sets up the cryptographic constants for cMix
-func initGroup() *cyclic.Group {
-
-	base := 16
-
-	pString := "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" +
-		"C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" +
-		"FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" +
-		"B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" +
-		"35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" +
-		"F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" +
-		"92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" +
-		"3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B"
-
-	gString := "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" +
-		"D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" +
-		"6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" +
-		"085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" +
-		"AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" +
-		"3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" +
-		"BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" +
-		"DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7"
-
-	p := large.NewIntFromString(pString, base)
-	g := large.NewIntFromString(gString, base)
-
-	grp := cyclic.NewGroup(p, g)
-
-	return grp
-}
-
-// Test creation of KeyManager
-func TestKeyManager_New(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, nil, nil,
-		partner, true, 12, 10, 10)
-
-	if km == nil {
-		t.Errorf("NewManager returned nil")
-	}
-}
-
-// Test KeyManager base key getter
-func TestKeyManager_GetBaseKey(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	result := km.GetBaseKey()
-
-	if result.Cmp(baseKey) != 0 {
-		t.Errorf("GetBaseKey returned wrong value, "+
-			"expected: %s, got: %s",
-			privKey.Text(10), result.Text(10))
-	}
-}
-
-// Test KeyManager private key getter
-func TestKeyManager_GetPrivKey(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	result := km.GetPrivKey()
-
-	if result.Cmp(privKey) != 0 {
-		t.Errorf("GetPrivKey returned wrong value, "+
-			"expected: %s, got: %s",
-			privKey.Text(10), result.Text(10))
-	}
-}
-
-// Test KeyManager public key getter
-func TestKeyManager_GetPubKey(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	result := km.GetPubKey()
-
-	if result.Cmp(pubKey) != 0 {
-		t.Errorf("GetPubKey returned wrong value, "+
-			"expected: %s, got: %s",
-			pubKey.Text(10), result.Text(10))
-	}
-}
-
-// Test KeyManager partner getter
-func TestKeyManager_GetPartner(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	result := km.GetPartner()
-
-	if *result != *partner {
-		t.Errorf("GetPartner returned wrong value, "+
-			"expected: %s, got: %s",
-			*partner, *result)
-	}
-}
-
-// Test rekey trigger
-func TestKeyManager_Rekey(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, nil, nil,
-		partner, true, 12, 10, 10)
-
-	var action Action
-	for i := 0; i < 9; i++ {
-		action = km.updateState(false)
-		if action != None {
-			t.Errorf("Expected 'None' action, got %s instead",
-				action)
-		}
-	}
-
-	action = km.updateState(false)
-	if action != Rekey {
-		t.Errorf("Expected 'Rekey' action, got %s instead",
-			action)
-	}
-}
-
-// Test purge trigger
-func TestKeyManager_Purge(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, nil, nil,
-		partner, true, 12, 10, 10)
-
-	var action Action
-	for i := 0; i < 9; i++ {
-		action = km.updateState(true)
-		if action != None {
-			t.Errorf("Expected 'None' action, got %s instead",
-				action)
-		}
-	}
-
-	action = km.updateState(true)
-	if action != Purge {
-		t.Errorf("Expected 'Purge' action, got %s instead",
-			action)
-	}
-
-	// Confirm that state is now deleted
-	action = km.updateState(false)
-	if action != Deleted {
-		t.Errorf("Expected 'Deleted' action, got %s instead",
-			action)
-	}
-}
-
-// Test receive state update
-func TestKeyManager_UpdateRecvState(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	km := NewManager(baseKey, nil, nil,
-		partner, false, 12, 10, 10)
-
-	expectedVal := uint64(0x0010000001000008)
-	// Mark some keys as used and confirm expected value
-	km.updateRecvState(false, 3)
-	km.updateRecvState(false, 24)
-	km.updateRecvState(false, 52)
-
-	if *km.recvKeysState[0] != expectedVal {
-		t.Errorf("UpdateRecvState failed for Key, expected"+
-			" %d, got %d", expectedVal, *km.recvKeysState[0])
-	}
-
-	expectedVal = uint64(0x0000080000040020)
-	// Mark some Rekeys as used and confirm expected value
-	km.updateRecvState(true, 5)
-	km.updateRecvState(true, 18)
-	km.updateRecvState(true, 43)
-
-	if *km.recvReKeysState[0] != expectedVal {
-		t.Errorf("UpdateRecvState failed for ReKey, expected"+
-			" %d, got %d", expectedVal, *km.recvReKeysState[0])
-	}
-}
-
-// Test KeyManager Key Generation
-func TestKeyManager_GenerateKeys(t *testing.T) {
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-
-	ks := NewStore()
-	kmSend := NewManager(baseKey, nil, nil,
-		partner, true, 12, 10, 10)
-
-	// Generate Send Keys
-	kmSend.GenerateKeys(grp, userID)
-	ks.AddSendManager(kmSend)
-
-	kmRecv := NewManager(baseKey, nil, nil,
-		partner, false, 12, 10, 10)
-
-	// Generate Receive Keys
-	e2ekeys := kmRecv.GenerateKeys(grp, userID)
-	ks.AddRecvManager(kmRecv)
-	ks.AddReceiveKeysByFingerprint(e2ekeys)
-
-	// Confirm Send KeyManager is stored correctly in KeyStore map
-	retKM := ks.GetSendManager(partner)
-	if retKM != kmSend {
-		t.Errorf("KeyManager stored in KeyStore is not the same")
-	}
-
-	// Confirm keys can be correctly pop'ed from KeyManager
-	actual, action := retKM.PopKey()
-
-	if actual == nil {
-		t.Errorf("KeyManager returned nil when poping key")
-	} else if action != None {
-		t.Errorf("Expected 'None' action, got %s instead",
-			action)
-	}
-
-	actual, action = retKM.PopRekey()
-
-	if actual == nil {
-		t.Errorf("KeyManager returned nil when poping rekey")
-	} else if action != None {
-		t.Errorf("Expected 'None' action, got %s instead",
-			action)
-	}
-
-	// Confirm Receive Keys can be obtained from KeyStore
-	actual = ks.GetRecvKey(kmRecv.recvKeysFingerprint[4])
-	if actual == nil {
-		t.Errorf("ReceptionKeys Map returned nil for Key")
-	}
-
-	actual = ks.GetRecvKey(e2ekeys[8].KeyFingerprint())
-
-	if actual == nil {
-		t.Errorf("ReceptionKeys Map returned nil for ReKey")
-	}
-}
-
-// Test KeyManager destroy
-func TestKeyManager_Destroy(t *testing.T) {
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-
-	ks := NewStore()
-	km := NewManager(baseKey, nil, nil,
-		partner, true, 12, 10, 10)
-
-	// Generate Send Keys
-	km.GenerateKeys(grp, userID)
-	ks.AddSendManager(km)
-
-	km2 := NewManager(baseKey, nil, nil,
-		partner, false, 12, 10, 10)
-
-	// Generate Receive Keys
-	e2ekeys := km2.GenerateKeys(grp, userID)
-	// TODO add ks keys here
-	ks.AddRecvManager(km2)
-	ks.AddReceiveKeysByFingerprint(e2ekeys)
-
-	// Confirm Send KeyManager is stored correctly in KeyStore map
-	retKM := ks.GetSendManager(partner)
-	if retKM != km {
-		t.Errorf("KeyManager stored in KeyStore is not the same")
-	}
-
-	// Confirm keys can be correctly pop'ed from KeyManager
-	actual, action := retKM.PopKey()
-
-	if actual == nil {
-		t.Errorf("KeyManager returned nil when poping key")
-	} else if action != None {
-		t.Errorf("Expected 'None' action, got %s instead",
-			action)
-	}
-
-	actual, action = retKM.PopRekey()
-
-	if actual == nil {
-		t.Errorf("KeyManager returned nil when poping rekey")
-	} else if action != None {
-		t.Errorf("Expected 'None' action, got %s instead",
-			action)
-	}
-
-	// Confirm Receive Keys can be obtained from KeyStore
-	actual = ks.GetRecvKey(km2.recvKeysFingerprint[4])
-
-	if actual == nil {
-		t.Errorf("ReceptionKeys Map returned nil for Key")
-	}
-
-	actual = ks.GetRecvKey(km2.recvReKeysFingerprint[8])
-	if actual == nil {
-		t.Errorf("ReceptionKeys Map returned nil for ReKey")
-	}
-
-	// Destroy KeyManager and confirm KeyManager is gone from map
-	km.Destroy(ks)
-
-	retKM = ks.GetSendManager(partner)
-	if retKM != nil {
-		t.Errorf("KeyManager was not properly removed from KeyStore")
-	}
-
-}
-
-// Test GOB Encode/Decode of KeyManager
-// and do a simple comparison after
-func TestKeyManager_GobSimple(t *testing.T) {
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-
-	var byteBuf bytes.Buffer
-
-	enc := gob.NewEncoder(&byteBuf)
-	dec := gob.NewDecoder(&byteBuf)
-
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	err := enc.Encode(km)
-
-	if err != nil {
-		t.Errorf("Error GOB Encoding KeyManager: %s", err)
-	}
-
-	outKm := &KeyManager{}
-
-	err = dec.Decode(&outKm)
-
-	if err != nil {
-		t.Errorf("Error GOB Decoding KeyManager: %s", err)
-	}
-
-	if km.baseKey.Cmp(outKm.baseKey) != 0 {
-		t.Errorf("GobEncoder/GobDecoder failed on BaseKey, "+
-			"Expected: %v; Recieved: %v ",
-			km.baseKey.TextVerbose(10, 12),
-			outKm.baseKey.TextVerbose(10, 12))
-	}
-
-	if *km.partner != *outKm.partner {
-		t.Errorf("GobEncoder/GobDecoder failed on Partner, "+
-			"Expected: %v; Recieved: %v ",
-			*km.partner,
-			*outKm.partner)
-	}
-
-	if *km.sendState != *outKm.sendState {
-		t.Errorf("GobEncoder/GobDecoder failed on State, "+
-			"Expected: %v; Recieved: %v ",
-			*km.sendState,
-			*outKm.sendState)
-	}
-
-	if km.ttl != outKm.ttl {
-		t.Errorf("GobEncoder/GobDecoder failed on TTL, "+
-			"Expected: %v; Recieved: %v ",
-			km.ttl,
-			outKm.ttl)
-	}
-
-	if km.numKeys != outKm.numKeys {
-		t.Errorf("GobEncoder/GobDecoder failed on NumKeys, "+
-			"Expected: %v; Recieved: %v ",
-			km.numKeys,
-			outKm.numKeys)
-	}
-
-	if km.numReKeys != outKm.numReKeys {
-		t.Errorf("GobEncoder/GobDecoder failed on NumReKeys, "+
-			"Expected: %v; Recieved: %v ",
-			km.numReKeys,
-			outKm.numReKeys)
-	}
-
-	for i := 0; i < int(numStates); i++ {
-		if *km.recvKeysState[i] != *outKm.recvKeysState[i] {
-			t.Errorf("GobEncoder/GobDecoder failed on RecvKeysState[%d], "+
-				"Expected: %v; Recieved: %v ",
-				i,
-				*km.recvKeysState[i],
-				*outKm.recvKeysState[i])
-		}
-	}
-
-	for i := 0; i < int(numReStates); i++ {
-		if *km.recvReKeysState[i] != *outKm.recvReKeysState[i] {
-			t.Errorf("GobEncoder/GobDecoder failed on RecvReKeysState[%d], "+
-				"Expected: %v; Recieved: %v ",
-				i,
-				*km.recvReKeysState[i],
-				*outKm.recvReKeysState[i])
-		}
-	}
-}
-
-// Tests that GobDecode() for Key Manager throws an error for a
-// malformed byte array
-func TestKeyManager_GobDecodeError(t *testing.T) {
-	km := KeyManager{}
-	err := km.GobDecode([]byte{})
-
-	if err.Error() != "EOF" {
-		t.Errorf("GobDecode() did not produce the expected error\n\treceived: %v"+
-			"\n\texpected: %v", err, errors.New("EOF"))
-	}
-}
-
-// Test that key maps are reconstructed correctly after
-// Key Manager GOB Encode/Decode
-func TestKeyManager_Gob(t *testing.T) {
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-
-	ks := NewStore()
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	// Generate Send Keys
-	km.GenerateKeys(grp, userID)
-	ks.AddSendManager(km)
-
-	km2 := NewManager(baseKey, privKey, pubKey,
-		partner, false, 12, 10, 10)
-
-	// Generate Receive Keys
-	e2ekeys := km2.GenerateKeys(grp, userID)
-	ks.AddRecvManager(km2)
-	ks.AddReceiveKeysByFingerprint(e2ekeys)
-
-	// Generate keys here to have a way to compare after
-	sendKeys := e2e.DeriveKeys(grp, baseKey, userID, uint(km.numKeys))
-	sendReKeys := e2e.DeriveEmergencyKeys(grp, baseKey, userID, uint(km.numReKeys))
-	recvKeys := e2e.DeriveKeys(grp, baseKey, partner, uint(km.numKeys))
-	recvReKeys := e2e.DeriveEmergencyKeys(grp, baseKey, partner, uint(km.numReKeys))
-
-	var expectedKeyMap = make(map[string]bool)
-
-	for _, key := range sendKeys {
-		expectedKeyMap[base64.StdEncoding.EncodeToString(key.Bytes())] = true
-	}
-
-	for _, key := range sendReKeys {
-		expectedKeyMap[base64.StdEncoding.EncodeToString(key.Bytes())] = true
-	}
-
-	for _, key := range recvKeys {
-		expectedKeyMap[base64.StdEncoding.EncodeToString(key.Bytes())] = true
-	}
-
-	for _, key := range recvReKeys {
-		expectedKeyMap[base64.StdEncoding.EncodeToString(key.Bytes())] = true
-	}
-
-	// Use some send keys and mark on expected map as used
-	retKM := ks.GetSendManager(partner)
-	if retKM != km {
-		t.Errorf("KeyManager stored in KeyStore is not the same")
-	}
-	key, _ := retKM.PopKey()
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	key, _ = retKM.PopKey()
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	key, _ = retKM.PopKey()
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	usedSendKeys := 3
-
-	key, _ = retKM.PopRekey()
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	key, _ = retKM.PopRekey()
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	usedSendReKeys := 2
-
-	// Use some receive keys and mark on expected map as used
-	key = ks.GetRecvKey(km2.recvKeysFingerprint[3])
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	key = ks.GetRecvKey(km2.recvKeysFingerprint[8])
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	key = ks.GetRecvKey(km2.recvKeysFingerprint[6])
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	key = ks.GetRecvKey(km2.recvKeysFingerprint[1])
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	usedRecvKeys := 4
-
-	key = ks.GetRecvKey(km2.recvReKeysFingerprint[4])
-	expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] = false
-	usedRecvReKeys := 1
-
-	// Now GOB Encode Key Manager
-	var byteBuf bytes.Buffer
-
-	enc := gob.NewEncoder(&byteBuf)
-	dec := gob.NewDecoder(&byteBuf)
-
-	err := enc.Encode(km)
-
-	if err != nil {
-		t.Errorf("Error GOB Encoding KeyManager: %s", err)
-	}
-
-	// Destroy KeyManager and confirm KeyManager is gone from map
-	km.Destroy(ks)
-
-	retKM = ks.GetSendManager(partner)
-	if retKM != nil {
-		t.Errorf("KeyManager was not properly removed from KeyStore")
-	}
-
-	// GOB Decode Key Manager
-	sendKm := &KeyManager{}
-	err = dec.Decode(&sendKm)
-
-	if err != nil {
-		t.Errorf("Error GOB Decoding KeyManager: %s", err)
-	}
-
-	err = enc.Encode(km2)
-
-	if err != nil {
-		t.Errorf("Error GOB Encoding KeyManager2: %s", err)
-	}
-
-	// Destroy Key Manager (and maps) and confirm no more receive keys exist
-	km2.Destroy(ks)
-
-	// GOB Decode Key Manager2
-	outKm2 := &KeyManager{}
-	err = dec.Decode(&outKm2)
-
-	if err != nil {
-		t.Errorf("Error GOB Decoding KeyManager2: %s", err)
-	}
-
-	// Generate Keys from decoded Key Managers
-	e2ekeys = sendKm.GenerateKeys(grp, userID)
-	ks.AddSendManager(sendKm)
-	//ks.AddReceiveKeysByFingerprint(e2ekeys)
-
-	e2ekeys = outKm2.GenerateKeys(grp, userID)
-	ks.AddRecvManager(km)
-	ks.AddReceiveKeysByFingerprint(e2ekeys)
-
-	// Confirm maps are the same as before delete
-
-	// First, check that len of send Stacks matches expected
-	if sendKm.sendKeys.keys.Len() != int(sendKm.numKeys)-usedSendKeys {
-		t.Errorf("SendKeys Stack contains more keys than expected after decode."+
-			" Expected: %d, Got: %d",
-			int(sendKm.numKeys)-usedSendKeys,
-			sendKm.sendKeys.keys.Len())
-	}
-
-	if sendKm.sendReKeys.keys.Len() != int(sendKm.numReKeys)-usedSendReKeys {
-		t.Errorf("SendReKeys Stack contains more keys than expected after decode."+
-			" Expected: %d, Got: %d",
-			int(sendKm.numReKeys)-usedSendReKeys,
-			sendKm.sendReKeys.keys.Len())
-	}
-
-	// Now confirm that all send keys are in the expected map
-	retKM = ks.GetSendManager(partner)
-	for i := 0; i < int(sendKm.numKeys)-usedSendKeys; i++ {
-		key, _ := retKM.PopKey()
-		if expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] != true {
-			t.Errorf("SendKey %v was used or didn't exist before",
-				key.KeyFingerprint())
-		}
-	}
-
-	for i := 0; i < int(sendKm.numReKeys)-usedSendReKeys; i++ {
-		key, _ := retKM.PopRekey()
-		if expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] != true {
-			t.Errorf("SendReKey %v was used or didn't exist before",
-				key.KeyFingerprint())
-		}
-	}
-
-	// Check that len of fingerprint lists matches expected
-	if len(outKm2.recvKeysFingerprint) != int(outKm2.numKeys)-usedRecvKeys {
-		t.Errorf("ReceiveKeys list contains more keys than expected after decode."+
-			" Expected: %d, Got: %d",
-			int(outKm2.numKeys)-usedRecvKeys,
-			len(outKm2.recvKeysFingerprint))
-	}
-
-	if len(outKm2.recvReKeysFingerprint) != int(outKm2.numReKeys)-usedRecvReKeys {
-		t.Errorf("ReceiveReKeys list contains more keys than expected after decode."+
-			" Expected: %d, Got: %d",
-			int(outKm2.numReKeys)-usedRecvReKeys,
-			len(outKm2.recvReKeysFingerprint))
-	}
-
-	// Now confirm that all receiving keys are in the expected map
-	for i := 0; i < int(outKm2.numKeys)-usedRecvKeys; i++ {
-		key := ks.GetRecvKey(outKm2.recvKeysFingerprint[i])
-		if expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] != true {
-			t.Errorf("ReceiveKey %v was used or didn't exist before",
-				key.KeyFingerprint())
-		}
-	}
-
-	for i := 0; i < int(outKm2.numReKeys)-usedRecvReKeys; i++ {
-		key := ks.GetRecvKey(outKm2.recvReKeysFingerprint[i])
-		if expectedKeyMap[base64.StdEncoding.EncodeToString(key.key.Bytes())] != true {
-			t.Errorf("ReceiveReKey %v was used or didn't exist before",
-				key.KeyFingerprint())
-		}
-	}
-}
diff --git a/keyStore/keyParams.go b/keyStore/keyParams.go
deleted file mode 100644
index 7af8bae62e12c51a7ca573d99fc39dfd3081551b..0000000000000000000000000000000000000000
--- a/keyStore/keyParams.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package keyStore
-
-import "gitlab.com/elixxir/crypto/e2e"
-
-// DEFAULT KEY GENERATION PARAMETERS
-// Hardcoded limits for keys
-// With 16 receiving states we can hold
-// 16*64=1024 dirty bits for receiving keys
-// With that limit, and setting maxKeys to 800,
-// we need a Threshold of 224, and a scalar
-// smaller than 1.28 to ensure we never generate
-// more than 1024 keys
-// With 1 receiving states for ReKeys we can hold
-// 64 Rekeys
-const (
-	numStates   uint16  = 16
-	numReStates uint16  = 1
-	minKeys     uint16  = 500
-	maxKeys     uint16  = 800
-	ttlScalar   float64 = 1.2 // generate 20% extra keys
-	threshold   uint16  = 224
-	numReKeys   uint16  = 64
-)
-
-type KeyParams struct {
-	MinKeys   uint16
-	MaxKeys   uint16
-	NumRekeys uint16
-	e2e.TTLParams
-}
diff --git a/keyStore/keyStack.go b/keyStore/keyStack.go
deleted file mode 100644
index 43bf3ae0d3f67dc5d6b96e8a63e74dc6fc17fc7f..0000000000000000000000000000000000000000
--- a/keyStore/keyStack.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package keyStore
-
-import (
-	"github.com/golang-collections/collections/stack"
-	"gitlab.com/elixxir/client/globals"
-	"sync"
-)
-
-// KeyStack contains a stack of E2E keys (or rekeys)
-// Also has a mutex for access control
-type KeyStack struct {
-	// List of Keys used for sending
-	// When a key is used it is deleted (pop'ed)
-	keys *stack.Stack
-	// Lock
-	sync.Mutex
-}
-
-// Create a new KeyStack
-// It creates the internal stack.Stack object
-func NewKeyStack() *KeyStack {
-	ks := new(KeyStack)
-	ks.keys = stack.New()
-	return ks
-}
-
-// Push an E2EKey into the stack
-func (ks *KeyStack) Push(key *E2EKey) {
-	ks.keys.Push(key)
-}
-
-// Returns the top key on the stack
-// Internally holds the lock when
-// running Pop on the internal stack.Stack object
-func (ks *KeyStack) Pop() *E2EKey {
-	var key *E2EKey
-
-	// Get the key
-	ks.Lock()
-	keyFace := ks.keys.Pop()
-	ks.Unlock()
-
-	// Check if the key exists and panic otherwise
-	if keyFace == nil {
-		globals.Log.WARN.Printf("E2E key stack is empty!")
-		key = nil
-	} else {
-		key = keyFace.(*E2EKey)
-	}
-
-	return key
-}
-
-// Deletes all keys from stack, i.e., pops all
-// Internally holds the lock
-func (ks *KeyStack) Delete() {
-	ks.Lock()
-	defer ks.Unlock()
-	length := ks.keys.Len()
-	for i := 0; i < length; i++ {
-		ks.keys.Pop()
-	}
-}
diff --git a/keyStore/keyStack_test.go b/keyStore/keyStack_test.go
deleted file mode 100644
index caecf8635b716de4ae7bf6639d8ba8264f34b35c..0000000000000000000000000000000000000000
--- a/keyStore/keyStack_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package keyStore
-
-import (
-	"gitlab.com/elixxir/client/parse"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/large"
-	"testing"
-	"time"
-)
-
-// Helper function to compare E2E Keys
-func E2EKeyCmp(a, b *E2EKey) bool {
-	if a.GetManager() != b.GetManager() {
-		return false
-	}
-	if a.GetOuterType() != b.GetOuterType() {
-		return false
-	}
-	if a.GetKey().Cmp(b.GetKey()) != 0 {
-		return false
-	}
-	return true
-}
-
-// Test KeyStack creation and push/pop
-func TestKeyStack(t *testing.T) {
-	ks := NewKeyStack()
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	expectedKeys := make([]*E2EKey, 100)
-
-	for i := 0; i < 100; i++ {
-		key := new(E2EKey)
-		key.outer = parse.E2E
-		key.key = grp.NewInt(int64(i + 2))
-		key.manager = nil
-		expectedKeys[99-i] = key
-		ks.Push(key)
-	}
-
-	for i := 0; i < 100; i++ {
-		actual := ks.Pop()
-		if !E2EKeyCmp(actual, expectedKeys[i]) {
-			t.Errorf("Pop'd key doesn't match with expected")
-		}
-	}
-}
-
-// Test that KeyStack panics on pop if empty
-func TestKeyStack_Panic(t *testing.T) {
-	ks := NewKeyStack()
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	expectedKeys := make([]*E2EKey, 10)
-
-	for i := 0; i < 10; i++ {
-		key := new(E2EKey)
-		key.outer = parse.E2E
-		key.key = grp.NewInt(int64(i + 2))
-		key.manager = nil
-		expectedKeys[9-i] = key
-		ks.Push(key)
-	}
-
-	defer func() {
-		if r := recover(); r == nil {
-			t.Errorf("Pop should panic when stack is empty")
-		}
-	}()
-
-	for i := 0; i < 11; i++ {
-		actual := ks.Pop()
-		if !E2EKeyCmp(actual, expectedKeys[i]) {
-			t.Errorf("Pop'd key doesn't match with expected")
-		}
-	}
-}
-
-// Test that delete correctly empties stack
-func TestKeyStack_Delete(t *testing.T) {
-	ks := NewKeyStack()
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	expectedKeys := make([]*E2EKey, 100)
-
-	for i := 0; i < 100; i++ {
-		key := new(E2EKey)
-		key.outer = parse.E2E
-		key.key = grp.NewInt(int64(i + 2))
-		key.manager = nil
-		expectedKeys[99-i] = key
-		ks.Push(key)
-	}
-
-	for i := 0; i < 50; i++ {
-		actual := ks.Pop()
-		if !E2EKeyCmp(actual, expectedKeys[i]) {
-			t.Errorf("Pop'd key doesn't match with expected")
-		}
-	}
-
-	ks.Delete()
-
-	k4 := ks.Pop()
-	if k4 != nil {
-		t.Errorf("Pop should return nil when stack is empty")
-	}
-}
-
-// Test concurrent access
-func TestKeyStack_Concurrent(t *testing.T) {
-	ks := NewKeyStack()
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	expectedKeys := make([]*E2EKey, 100)
-
-	for i := 0; i < 100; i++ {
-		key := new(E2EKey)
-		key.outer = parse.E2E
-		key.key = grp.NewInt(int64(i + 2))
-		key.manager = nil
-		expectedKeys[99-i] = key
-		ks.Push(key)
-	}
-
-	for i := 0; i < 100; i++ {
-		go func() {
-			ks.Pop()
-		}()
-	}
-
-	// wait for goroutines
-	time.Sleep(500 * time.Millisecond)
-
-	k4 := ks.Pop()
-	if k4 != nil {
-		t.Errorf("Pop should return nil when stack is empty")
-	}
-}
diff --git a/keyStore/keyStore.go b/keyStore/keyStore.go
deleted file mode 100644
index 8efba3a8ad03fd2ea32005d82318fdd7b1481ee4..0000000000000000000000000000000000000000
--- a/keyStore/keyStore.go
+++ /dev/null
@@ -1,353 +0,0 @@
-package keyStore
-
-import (
-	"bytes"
-	"encoding/gob"
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/parse"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"sync"
-)
-
-// Local types in order to implement functions that
-// return real types instead of interfaces
-type keyManMap sync.Map
-type inKeyMap sync.Map
-
-// Stores a KeyManager entry for given user
-func (m *keyManMap) Store(user *id.ID, km *KeyManager) {
-	(*sync.Map)(m).Store(*user, km)
-}
-
-// Loads a KeyManager entry for given user
-func (m *keyManMap) Load(user *id.ID) *KeyManager {
-	val, ok := (*sync.Map)(m).Load(*user)
-	if !ok {
-		return nil
-	} else {
-		return val.(*KeyManager)
-	}
-}
-
-// Deletes a KeyManager entry for given user
-func (m *keyManMap) Delete(user *id.ID) {
-	(*sync.Map)(m).Delete(*user)
-}
-
-// Internal helper function to get a list of all values
-// contained in a KeyManMap
-func (m *keyManMap) values() []*KeyManager {
-	valueList := make([]*KeyManager, 0)
-	(*sync.Map)(m).Range(func(key, value interface{}) bool {
-		valueList = append(valueList, value.(*KeyManager))
-		return true
-	})
-	return valueList
-}
-
-// Internal helper function to get a list of all keys
-// contained in a KeyManMap
-func (m *keyManMap) keys() []id.ID {
-	keyList := make([]id.ID, 0)
-	(*sync.Map)(m).Range(func(key, value interface{}) bool {
-		keyList = append(keyList, key.(id.ID))
-		return true
-	})
-	return keyList
-}
-
-// Stores an *E2EKey for given fingerprint
-func (m *inKeyMap) Store(fingerprint format.Fingerprint, key *E2EKey) {
-	(*sync.Map)(m).Store(fingerprint, key)
-}
-
-// Pops key for given fingerprint, i.e,
-// returns and deletes it from the map
-// Atomically updates Key Manager Receiving state
-// Returns nil if not found
-func (m *inKeyMap) Pop(fingerprint format.Fingerprint) *E2EKey {
-	val, ok := (*sync.Map)(m).Load(fingerprint)
-
-	var key *E2EKey
-	if !ok {
-		return nil
-	} else {
-		key = val.(*E2EKey)
-	}
-	// Delete key from map
-	m.Delete(fingerprint)
-	// Update Key Manager Receiving State
-	key.GetManager().updateRecvState(
-		key.GetOuterType() == parse.Rekey,
-		key.keyNum)
-	return key
-}
-
-// Deletes a key for given fingerprint
-func (m *inKeyMap) Delete(fingerprint format.Fingerprint) {
-	(*sync.Map)(m).Delete(fingerprint)
-}
-
-// Deletes keys from a given list of fingerprints
-func (m *inKeyMap) DeleteList(fingerprints []format.Fingerprint) {
-	for _, fp := range fingerprints {
-		m.Delete(fp)
-	}
-}
-
-// KeyStore contains the E2E key
-// and Key Managers maps
-// Send keys are obtained directly from the Key Manager
-// which is looked up in the sendKeyManagers map
-// Receiving keys are lookup up by fingerprint on
-// receptionKeys map
-// RecvKeyManagers map is needed in order to maintain
-// active Key Managers when the session is stored/loaded
-// It is not a sync.map since it won't be accessed
-// very often
-// It still contains a lock for multithreaded access
-type KeyStore struct {
-	// Key generation parameters
-	params *KeyParams
-
-	// Transmission Keys map
-	// Maps id.ID to *KeyManager
-	sendKeyManagers *keyManMap
-
-	// Reception Keys map
-	// Maps format.Fingerprint to *E2EKey
-	receptionKeys *inKeyMap
-
-	// Reception Key Managers map
-	recvKeyManagers map[id.ID]*ReceptionKeyManagerBuffer
-
-	lock sync.Mutex
-}
-
-func NewStore() *KeyStore {
-	ks := new(KeyStore)
-	ks.params = &KeyParams{
-		MinKeys:   minKeys,
-		MaxKeys:   maxKeys,
-		NumRekeys: numReKeys,
-		TTLParams: e2e.TTLParams{
-			TTLScalar:  ttlScalar,
-			MinNumKeys: threshold,
-		},
-	}
-	ks.sendKeyManagers = new(keyManMap)
-	ks.receptionKeys = new(inKeyMap)
-	ks.recvKeyManagers = make(map[id.ID]*ReceptionKeyManagerBuffer)
-	return ks
-}
-
-func (ks *KeyStore) DeleteContactKeys(id *id.ID) error {
-	ks.lock.Lock()
-	defer ks.lock.Unlock()
-
-	rkmb, ok := ks.recvKeyManagers[*id]
-	if ok {
-		for _, manager := range rkmb.managers {
-			if manager != nil {
-				keys := manager.recvKeysFingerprint
-				rekeys := manager.recvReKeysFingerprint
-				ks.receptionKeys.DeleteList(append(keys, rekeys...))
-			}
-		}
-	} else {
-		return errors.Errorf("User with id %+v not in map of key managers", id)
-	}
-	delete(ks.recvKeyManagers, *id)
-	ks.sendKeyManagers.Delete(id)
-	return nil
-}
-
-// Get Key generation parameters from KeyStore
-func (ks *KeyStore) GetKeyParams() *KeyParams {
-	return ks.params
-}
-
-// Add a Send KeyManager to respective map in KeyStore
-func (ks *KeyStore) AddSendManager(km *KeyManager) {
-	ks.sendKeyManagers.Store(km.GetPartner(), km)
-}
-
-// Get a Send KeyManager from respective map in KeyStore
-// based on partner ID
-func (ks *KeyStore) GetSendManager(partner *id.ID) *KeyManager {
-	return ks.sendKeyManagers.Load(partner)
-}
-
-// GetPartners returns the list of partners we have keys for
-func (ks *KeyStore) GetPartners() []id.ID {
-	return ks.sendKeyManagers.keys()
-}
-
-// Delete a Send KeyManager from respective map in KeyStore
-// based on partner ID
-func (ks *KeyStore) DeleteSendManager(partner *id.ID) {
-	ks.sendKeyManagers.Delete(partner)
-}
-
-// Add a Receiving E2EKey to the correct KeyStore map
-// based on its fingerprint
-func (ks *KeyStore) AddRecvKey(fingerprint format.Fingerprint,
-	key *E2EKey) {
-	ks.receptionKeys.Store(fingerprint, key)
-}
-
-// Get the Receiving Key stored in correct KeyStore map
-// based on the given fingerprint
-func (ks *KeyStore) GetRecvKey(fingerprint format.Fingerprint) *E2EKey {
-	return ks.receptionKeys.Pop(fingerprint)
-}
-
-// Add a Receive KeyManager to respective map in KeyStore
-func (ks *KeyStore) AddRecvManager(km *KeyManager) {
-	ks.lock.Lock()
-	defer ks.lock.Unlock()
-
-	//ks.recvKeyManagers = km
-	keys, ok := ks.recvKeyManagers[*km.partner]
-
-	if ok {
-		toBeDeleted := keys.push(km)
-		ks.DeleteReceiveKeysByFingerprint(toBeDeleted)
-	} else {
-		newBuffer := NewReceptionKeyManagerBuffer()
-		newBuffer.push(km)
-		ks.recvKeyManagers[*km.partner] = newBuffer
-	}
-}
-
-// Gets the Key manager at the current location on the ReceptionKeyManagerBuffer
-// based on partner ID
-func (ks *KeyStore) GetRecvManager(partner *id.ID) *KeyManager {
-	ks.lock.Lock()
-	defer ks.lock.Unlock()
-	return ks.recvKeyManagers[*partner].getCurrentReceptionKeyManager()
-}
-
-// Delete a Receive KeyManager based on partner ID from respective map in KeyStore
-func (ks *KeyStore) DeleteRecvManager(partner *id.ID) {
-	ks.lock.Lock()
-	defer ks.lock.Unlock()
-	delete(ks.recvKeyManagers, *partner)
-}
-
-// GobEncode the KeyStore
-func (ks *KeyStore) GobEncode() ([]byte, error) {
-	var buf bytes.Buffer
-
-	// Create new encoder that will transmit the buffer
-	enc := gob.NewEncoder(&buf)
-
-	// Transmit the Key Parameters
-	err := enc.Encode(ks.params)
-
-	if err != nil {
-		return nil, err
-	}
-
-	// Transmit the Send Key Managers
-	kmList := ks.sendKeyManagers.values()
-	err = enc.Encode(kmList)
-
-	if err != nil {
-		return nil, err
-	}
-
-	// Transmit the Receive Key Managers
-	err = enc.Encode(ks.recvKeyManagers)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return buf.Bytes(), nil
-}
-
-// GobDecode the KeyStore from bytes
-// NOTE: ReconstructKeys must be called after GobDecoding a KeyStore
-func (ks *KeyStore) GobDecode(in []byte) error {
-	var buf bytes.Buffer
-
-	// Write bytes to the buffer
-	buf.Write(in)
-
-	// Create new decoder that reads from the buffer
-	dec := gob.NewDecoder(&buf)
-
-	// Decode Key Parameters
-	err := dec.Decode(&ks.params)
-
-	if err != nil {
-		return err
-	}
-
-	// Decode Key Managers List
-	var kmList []*KeyManager
-	err = dec.Decode(&kmList)
-
-	if err != nil {
-		return err
-	}
-
-	// Decode Recv Key Managers map
-	err = dec.Decode(&ks.recvKeyManagers)
-
-	if err != nil {
-		return err
-	}
-
-	// Reconstruct Send Key Manager map
-	ks.sendKeyManagers = new(keyManMap)
-	ks.receptionKeys = new(inKeyMap)
-	for _, km := range kmList {
-		ks.AddSendManager(km)
-	}
-
-	return nil
-}
-
-// ReconstructKeys loops through all key managers and
-// calls GenerateKeys on each of them, in order to rebuild
-// the key maps
-func (ks *KeyStore) ReconstructKeys(grp *cyclic.Group, userID *id.ID) {
-
-	kmList := ks.sendKeyManagers.values()
-	for _, km := range kmList {
-		km.GenerateKeys(grp, userID)
-		ks.AddSendManager(km)
-	}
-
-	for _, kmb := range ks.recvKeyManagers {
-		for _, km := range kmb.managers {
-			if km != nil {
-				e2eKeys := km.GenerateKeys(grp, userID)
-				ks.AddReceiveKeysByFingerprint(e2eKeys)
-			}
-		}
-	}
-}
-
-func (ks *KeyStore) DeleteReceiveKeysByFingerprint(toBeDeleted []format.Fingerprint) {
-	if len(toBeDeleted) != 0 {
-		ks.receptionKeys.DeleteList(toBeDeleted)
-	}
-}
-
-func (ks *KeyStore) AddReceiveKeysByFingerprint(newKeys []*E2EKey) {
-	for _, key := range newKeys {
-		ks.AddRecvKey(key.KeyFingerprint(), key)
-	}
-}
-
-// Delete multiple Receiving E2EKeys from the correct KeyStore map
-// based on a list of fingerprints
-func (ks *KeyStore) DeleteRecvKeyList(fingerprints []format.Fingerprint) {
-	ks.receptionKeys.DeleteList(fingerprints)
-}
diff --git a/keyStore/keyStore_test.go b/keyStore/keyStore_test.go
deleted file mode 100644
index 53891da174ab1d284892c676f166e591e96a6b08..0000000000000000000000000000000000000000
--- a/keyStore/keyStore_test.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package keyStore
-
-import (
-	"bytes"
-	"encoding/gob"
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"testing"
-)
-
-// Test GetKeyParams and confirm default params are correct
-func TestKeyStore_GetKeyParams(t *testing.T) {
-	ks := NewStore()
-
-	params := ks.GetKeyParams()
-
-	if params.MinKeys != minKeys {
-		t.Errorf("KeyParams: MinKeys mismatch, expected %d, "+
-			"got %d", minKeys, params.MinKeys)
-	} else if params.MaxKeys != maxKeys {
-		t.Errorf("KeyParams: MaxKeys mismatch, expected %d, "+
-			"got %d", maxKeys, params.MaxKeys)
-	} else if params.NumRekeys != numReKeys {
-		t.Errorf("KeyParams: NumRekeys mismatch, expected %d, "+
-			"got %d", numReKeys, params.NumRekeys)
-	} else if params.TTLScalar != ttlScalar {
-		t.Errorf("KeyParams: TTLScalar mismatch, expected %f, "+
-			"got %f", ttlScalar, params.TTLScalar)
-	} else if params.MinNumKeys != threshold {
-		t.Errorf("KeyParams: MinNumKeys mismatch, expected %d, "+
-			"got %d", threshold, params.MinNumKeys)
-	}
-}
-
-// Test GOB Encode/Decode of KeyStore
-// and compare if all keys match originals
-func TestKeyStore_Gob(t *testing.T) {
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-
-	ks := NewStore()
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	// Generate Send Keys
-	e2ekeys := km.GenerateKeys(grp, userID)
-	ks.AddSendManager(km)
-
-	km2 := NewManager(baseKey, privKey, pubKey,
-		partner, false, 12, 10, 10)
-
-	// Generate Receive Keys
-	e2ekeys = km2.GenerateKeys(grp, userID)
-	ks.AddReceiveKeysByFingerprint(e2ekeys)
-	ks.AddRecvManager(km2)
-
-	// Now that some KeyManagers are in the keystore, Gob Encode it
-	var byteBuf bytes.Buffer
-
-	enc := gob.NewEncoder(&byteBuf)
-	dec := gob.NewDecoder(&byteBuf)
-
-	err := enc.Encode(ks)
-
-	if err != nil {
-		t.Errorf("Error GOB Encoding KeyStore: %s", err)
-	}
-
-	outKs := &KeyStore{}
-
-	err = dec.Decode(&outKs)
-
-	if err != nil {
-		t.Errorf("Error GOB Decoding KeyStore: %s", err)
-	}
-
-	// Need to reconstruct keys after decoding
-	outKs.ReconstructKeys(grp, userID)
-
-	// Get KeyManagers and compare keys
-	outKm := outKs.GetSendManager(partner)
-
-	for i := 0; i < 12; i++ {
-		origKey, _ := km.PopKey()
-		actualKey, _ := outKm.PopKey()
-
-		if origKey.GetOuterType() != actualKey.GetOuterType() {
-			t.Errorf("Send Key type mistmatch after GOB Encode/Decode")
-		} else if origKey.key.Cmp(actualKey.key) != 0 {
-			t.Errorf("Send Key mistmatch after GOB Encode/Decode")
-		}
-	}
-
-	for i := 0; i < 10; i++ {
-		origKey, _ := km.PopRekey()
-		actualKey, _ := outKm.PopRekey()
-
-		if origKey.GetOuterType() != actualKey.GetOuterType() {
-			t.Errorf("Send Key type mistmatch after GOB Encode/Decode")
-		} else if origKey.key.Cmp(actualKey.key) != 0 {
-			t.Errorf("Send Key mistmatch after GOB Encode/Decode")
-		}
-	}
-}
-
-// Tests that GobDecode() for Key Store throws an error for a
-// malformed byte array
-func TestKeyStore_GobDecodeErrors(t *testing.T) {
-	ksTest := KeyStore{}
-	err := ksTest.GobDecode([]byte{})
-
-	if err.Error() != "EOF" {
-		//if !reflect.DeepEqual(err, errors.New("EOF")) {
-		t.Errorf("GobDecode() did not produce the expected error\n\treceived: %v"+
-			"\n\texpected: %v", err, errors.New("EOF"))
-	}
-}
-
-func TestKeyStore_DeleteContactKeys(t *testing.T) {
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-
-	ks := NewStore()
-	km := NewManager(baseKey, privKey, pubKey,
-		partner, true, 12, 10, 10)
-
-	// Generate Send Keys
-	e2ekeys := km.GenerateKeys(grp, userID)
-	km.recvReKeysFingerprint = []format.Fingerprint{*format.NewFingerprint([]byte("testtesttesttesttesttesttesttest"))}
-	km.recvKeysFingerprint = []format.Fingerprint{*format.NewFingerprint([]byte("testtesttesttesttesttesttesttest"))}
-	ks.AddSendManager(km)
-	rkmb := NewReceptionKeyManagerBuffer()
-
-	km2 := NewManager(baseKey, privKey, pubKey,
-		partner, false, 12, 10, 10)
-
-	// Generate Receive Keys
-	e2ekeys = km2.GenerateKeys(grp, userID)
-	ks.AddReceiveKeysByFingerprint(e2ekeys)
-	km2.recvReKeysFingerprint = []format.Fingerprint{*format.NewFingerprint([]byte("testtesttesttesttesttesttesttest"))}
-	km2.recvKeysFingerprint = []format.Fingerprint{*format.NewFingerprint([]byte("testtesttesttesttesttesttesttest"))}
-	ks.AddRecvManager(km2)
-
-	rkmb.managers[0] = km
-	rkmb.managers[1] = km2
-	rkmb.managers[2] = km2
-	rkmb.managers[3] = km2
-	rkmb.managers[4] = km2
-	ks.recvKeyManagers[*partner] = rkmb
-
-	err := ks.DeleteContactKeys(partner)
-	if err != nil {
-		t.Errorf("Failed to delete contact keys: %+v", err)
-	}
-}
diff --git a/keyStore/recieveKeyManagerBuffer.go b/keyStore/recieveKeyManagerBuffer.go
deleted file mode 100644
index 334b5c795b7dc48e8583a31676918a0353a56cef..0000000000000000000000000000000000000000
--- a/keyStore/recieveKeyManagerBuffer.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package keyStore
-
-import (
-	"bytes"
-	"encoding/gob"
-	"fmt"
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/primitives/format"
-)
-
-const ReceptionKeyManagerBufferLength = 5
-
-//This creates a circular buffer and initializes all the keymanagers to be nil at location zero.
-func NewReceptionKeyManagerBuffer() *ReceptionKeyManagerBuffer {
-	newBuffer := ReceptionKeyManagerBuffer{}
-	newBuffer.loc = 0
-	return &newBuffer
-}
-
-type ReceptionKeyManagerBuffer struct {
-	managers [ReceptionKeyManagerBufferLength]*KeyManager
-	loc      int
-}
-
-// Push takes in a new keymanager obj, and adds it into our circular buffer of keymanagers,
-// the keymanager obj passed in overwrites the keymanager in the buffer, and we have to return the existing
-// keymanager if there is one back ot the parent so that the deletion can be handled.
-func (rkmb *ReceptionKeyManagerBuffer) push(km *KeyManager) []format.Fingerprint {
-	deadkm := &KeyManager{}
-	deadkm = nil
-	if rkmb.managers[0] != nil {
-		//Don't increment location if location 0 is empty first time around
-		rkmb.loc = (rkmb.loc + 1) % ReceptionKeyManagerBufferLength
-		deadkm = rkmb.managers[rkmb.loc]
-	} else {
-
-	}
-
-	rkmb.managers[rkmb.loc] = km
-
-	if deadkm == nil {
-		return []format.Fingerprint{}
-	} else {
-
-		return append(deadkm.recvKeysFingerprint, deadkm.recvReKeysFingerprint...)
-
-	}
-}
-
-func (rkmb *ReceptionKeyManagerBuffer) getCurrentReceptionKeyManager() *KeyManager {
-	return rkmb.managers[rkmb.loc]
-}
-
-func (rkmb *ReceptionKeyManagerBuffer) getCurrentLoc() int {
-	return rkmb.loc
-}
-
-func (rkmb *ReceptionKeyManagerBuffer) getReceptionKeyManagerAtLoc(n int) *KeyManager {
-	return rkmb.managers[n%ReceptionKeyManagerBufferLength]
-}
-
-func (rkmb *ReceptionKeyManagerBuffer) GobEncode() ([]byte, error) {
-
-	//get rid of nils for encoding
-	var bufferSlice []*KeyManager
-
-	for i := 0; i < len(rkmb.managers); i++ {
-		j := (rkmb.loc + i) % len(rkmb.managers)
-		if rkmb.managers[j] != nil {
-			bufferSlice = append(bufferSlice, rkmb.managers[j])
-		}
-
-	}
-
-	anon := struct {
-		Managers []*KeyManager
-		Loc      int
-	}{
-		bufferSlice,
-		rkmb.loc,
-	}
-
-	var encodeBytes bytes.Buffer
-
-	enc := gob.NewEncoder(&encodeBytes)
-
-	err := enc.Encode(anon)
-
-	if err != nil {
-		err = errors.New(fmt.Sprintf("Could not encode Reception Keymanager Buffer: %s",
-			err.Error()))
-		return nil, err
-	}
-	return encodeBytes.Bytes(), nil
-
-}
-
-func (rkmb *ReceptionKeyManagerBuffer) GobDecode(in []byte) error {
-
-	anon := struct {
-		Managers []*KeyManager
-		Loc      int
-	}{}
-
-	var buf bytes.Buffer
-
-	// Write bytes to the buffer
-	buf.Write(in)
-
-	dec := gob.NewDecoder(&buf)
-
-	err := dec.Decode(&anon)
-
-	if err != nil {
-		err = errors.New(fmt.Sprintf("Could not Decode Reception Keymanager Buffer: %s", err.Error()))
-		return err
-	}
-
-	rkmb.loc = anon.Loc
-
-	for i := 0; i < len(anon.Managers); i++ {
-		j := (anon.Loc + i) % len(rkmb.managers)
-		rkmb.managers[j] = anon.Managers[i]
-	}
-
-	return nil
-}
diff --git a/keyStore/recieveKeyManagerBuffer_test.go b/keyStore/recieveKeyManagerBuffer_test.go
deleted file mode 100644
index e4680eeb8a451b31ea42950a094eb78e5754b578..0000000000000000000000000000000000000000
--- a/keyStore/recieveKeyManagerBuffer_test.go
+++ /dev/null
@@ -1,140 +0,0 @@
-package keyStore
-
-import (
-	"bytes"
-	"encoding/gob"
-	"gitlab.com/xx_network/primitives/id"
-	"testing"
-)
-
-// Test that the buffer is recieving objects and that it is in fact circular
-func TestPush(t *testing.T) {
-	aBuffer := NewReceptionKeyManagerBuffer()
-
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-
-	//Generate twice the amount of keymanagers so we can test the circularness of the buffer as well
-	kmArray := []KeyManager{}
-	for i := 0; i < ReceptionKeyManagerBufferLength*2; i++ {
-		newKm := *NewManager(baseKey, nil, nil,
-			partner, false, 12, 10, 10)
-
-		newKm.GenerateKeys(grp, userID)
-		kmArray = append(kmArray, newKm)
-
-		toDelete := aBuffer.push(&newKm)
-		println("delete %v", toDelete)
-		if i < ReceptionKeyManagerBufferLength {
-			if len(toDelete) != 0 {
-				//ERROR should have something
-				t.Errorf("Error Nothing Should Be Returned to be deleted since" +
-					" keybuffer should be filling up from empty state")
-			}
-
-			if &newKm != aBuffer.getCurrentReceptionKeyManager() {
-				t.Errorf("Error incorrect Keymanager receieved from buffer.")
-			}
-
-		} else {
-			if len(toDelete) == 0 {
-				t.Errorf("Error not returning old keymanager to properly be disposed of")
-			}
-
-			if &newKm != aBuffer.getCurrentReceptionKeyManager() {
-				t.Errorf("Error incorrect Keymanager receieved from buffer after its been filled up.")
-			}
-		}
-
-	}
-
-	if &kmArray[0] == &kmArray[1] {
-		t.Errorf("Error tests fail because we are not creating a new Keymanager")
-	}
-
-}
-
-//test that loc is always circular and outputted value is what is expected
-func TestReceptionKeyManagerBuffer_getCurrentLoc(t *testing.T) {
-	aBuffer := NewReceptionKeyManagerBuffer()
-
-	if aBuffer.getCurrentLoc() != 0 {
-		// Error location is not initialized as zero
-		t.Errorf("Error ReceptionKeyManagerBuffer Loc not initialized to zero")
-	}
-
-	for i := 0; i < ReceptionKeyManagerBufferLength*2; i++ {
-
-		aBuffer.push(&KeyManager{})
-
-		if aBuffer.getCurrentLoc() != aBuffer.loc {
-			//error mismatch between actual loc and returned loc
-			t.Errorf("Error ReceptionKeyManagerBuffer Loc mismatch with Getfunction")
-		}
-
-		if aBuffer.loc > ReceptionKeyManagerBufferLength || aBuffer.loc < 0 {
-			//Error Buffer Out of bounds
-			t.Errorf("Error ReceptionKeyManagerBuffer Loc out of bounds error")
-		}
-
-		if aBuffer.loc != (i % ReceptionKeyManagerBufferLength) {
-			//Error location is not circular
-
-			t.Errorf("Error ReceptionKeyManagerBuffer Loc is not circular")
-		}
-	}
-
-}
-
-func TestReceptionKeyManagerBuffer_getCurrentReceptionKeyManager(t *testing.T) {
-	aBuffer := NewReceptionKeyManagerBuffer()
-	testManager := &KeyManager{}
-	aBuffer.push(testManager)
-
-	if aBuffer.getCurrentReceptionKeyManager() != testManager {
-		t.Errorf("Error this is not the same manager pushed in.")
-	}
-}
-
-func TestNewReceptionKeyManagerBuffer(t *testing.T) {
-	aBuffer := NewReceptionKeyManagerBuffer()
-
-	if aBuffer == nil {
-		t.Errorf("Error creating new reception keymanager buffer returning nil")
-	}
-}
-
-func TestReceptionKeyManagerBuffer_Gob(t *testing.T) {
-	aBuffer := NewReceptionKeyManagerBuffer()
-	grp := initGroup()
-	baseKey := grp.NewInt(57)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-
-	newKm := *NewManager(baseKey, nil,
-		nil, partner,
-		false, 12, 10, 10)
-
-	newKm.GenerateKeys(grp, userID)
-
-	aBuffer.push(&newKm)
-
-	var byteBuf bytes.Buffer
-
-	enc := gob.NewEncoder(&byteBuf)
-	dec := gob.NewDecoder(&byteBuf)
-
-	err := enc.Encode(aBuffer)
-
-	if err != nil {
-		t.Errorf("Failed to encode GOB KeyManagerBuffer: %s", err)
-	}
-
-	newBuffer := NewReceptionKeyManagerBuffer()
-	err = dec.Decode(&newBuffer)
-	if err != nil {
-		t.Errorf("Failed to decode GOB KeyManagerBuffer: %s", err)
-	}
-}
diff --git a/keyStore/rekeyManager.go b/keyStore/rekeyManager.go
deleted file mode 100644
index 64e87ef466dfde92e449a94b1a152d9c1d78f5b5..0000000000000000000000000000000000000000
--- a/keyStore/rekeyManager.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package keyStore
-
-import (
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/xx_network/primitives/id"
-	"sync"
-)
-
-type RekeyContext struct {
-	BaseKey *cyclic.Int
-	PrivKey *cyclic.Int
-	PubKey  *cyclic.Int
-}
-
-type RekeyKeys struct {
-	CurrPrivKey *cyclic.Int
-	CurrPubKey  *cyclic.Int
-	NewPrivKey  *cyclic.Int
-	NewPubKey   *cyclic.Int
-}
-
-func (k *RekeyKeys) RotateKeysIfReady() {
-	if k.NewPrivKey != nil && k.NewPubKey != nil {
-		k.CurrPrivKey = k.NewPrivKey
-		k.CurrPubKey = k.NewPubKey
-		k.NewPrivKey = nil
-		k.NewPubKey = nil
-	}
-}
-
-type RekeyManager struct {
-	Ctxs map[id.ID]*RekeyContext
-	Keys map[id.ID]*RekeyKeys
-	lock sync.Mutex
-}
-
-func NewRekeyManager() *RekeyManager {
-	return &RekeyManager{
-		Ctxs: make(map[id.ID]*RekeyContext),
-		Keys: make(map[id.ID]*RekeyKeys),
-	}
-}
-
-func (rkm *RekeyManager) AddCtx(partner *id.ID,
-	ctx *RekeyContext) {
-	rkm.lock.Lock()
-	defer rkm.lock.Unlock()
-	rkm.Ctxs[*partner] = ctx
-}
-
-func (rkm *RekeyManager) GetCtx(partner *id.ID) *RekeyContext {
-	rkm.lock.Lock()
-	defer rkm.lock.Unlock()
-	return rkm.Ctxs[*partner]
-}
-
-func (rkm *RekeyManager) DeleteCtx(partner *id.ID) {
-	rkm.lock.Lock()
-	defer rkm.lock.Unlock()
-	delete(rkm.Ctxs, *partner)
-}
-
-func (rkm *RekeyManager) AddKeys(partner *id.ID,
-	keys *RekeyKeys) {
-	rkm.lock.Lock()
-	defer rkm.lock.Unlock()
-	rkm.Keys[*partner] = keys
-}
-
-func (rkm *RekeyManager) GetKeys(partner *id.ID) *RekeyKeys {
-	rkm.lock.Lock()
-	defer rkm.lock.Unlock()
-	return rkm.Keys[*partner]
-}
-
-func (rkm *RekeyManager) DeleteKeys(partner *id.ID) {
-	rkm.lock.Lock()
-	defer rkm.lock.Unlock()
-	delete(rkm.Keys, *partner)
-}
diff --git a/keyStore/rekeyManager_test.go b/keyStore/rekeyManager_test.go
deleted file mode 100644
index a41a5ed5a2289b9ee3e80d817a76f298c6e29922..0000000000000000000000000000000000000000
--- a/keyStore/rekeyManager_test.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package keyStore
-
-import (
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/large"
-	"gitlab.com/xx_network/primitives/id"
-	"testing"
-)
-
-// Test creation of RekeyManager
-func TestRekeyManager_New(t *testing.T) {
-	rkm := NewRekeyManager()
-
-	if rkm == nil {
-		t.Errorf("NewRekeyManager returned nil")
-	}
-}
-
-// Test all Ctx related functions of RekeyManager
-func TestRekeyManager_Ctx(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	baseKey := grp.NewInt(57)
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-	rkm := NewRekeyManager()
-
-	val := &RekeyContext{
-		BaseKey: baseKey,
-		PrivKey: privKey,
-		PubKey:  pubKey,
-	}
-
-	// Add RekeyContext to map
-	rkm.AddCtx(partner, val)
-
-	// Confirm different partner returns nil
-	actual := rkm.GetCtx(userID)
-
-	if actual != nil {
-		t.Errorf("GetCtx returned something but expected nil")
-	}
-
-	// Get added value and compare
-	actual = rkm.GetCtx(partner)
-
-	if actual == nil {
-		t.Errorf("GetCtx returned nil")
-	} else if actual.BaseKey.Cmp(baseKey) != 0 {
-		t.Errorf("BaseKey doesn't match for RekeyContext added to Contexts map")
-	} else if actual.PrivKey.Cmp(privKey) != 0 {
-		t.Errorf("PrivKey doesn't match for RekeyContext added to Contexts map")
-	} else if actual.PubKey.Cmp(pubKey) != 0 {
-		t.Errorf("PubKey doesn't match for RekeyContext added to Contexts map")
-	}
-
-	// Delete value and confirm it's gone
-	rkm.DeleteCtx(partner)
-
-	actual = rkm.GetCtx(partner)
-
-	if actual != nil {
-		t.Errorf("GetCtx returned something but expected nil after deletion")
-	}
-}
-
-// Test all Keys related functions of RekeyManager
-func TestRekeyManager_Keys(t *testing.T) {
-	grp := cyclic.NewGroup(large.NewInt(107), large.NewInt(2))
-	privKey := grp.NewInt(5)
-	pubKey := grp.NewInt(42)
-	partner := id.NewIdFromUInt(14, id.User, t)
-	userID := id.NewIdFromUInt(18, id.User, t)
-	rkm := NewRekeyManager()
-
-	val := &RekeyKeys{
-		CurrPrivKey: privKey,
-		CurrPubKey:  pubKey,
-	}
-
-	// Add RekeyKeys to map
-	rkm.AddKeys(partner, val)
-
-	// Confirm different partner returns nil
-	actual := rkm.GetKeys(userID)
-
-	if actual != nil {
-		t.Errorf("GetNodeKeys returned something but expected nil")
-	}
-
-	// Get added value and compare
-	actual = rkm.GetKeys(partner)
-
-	if actual == nil {
-		t.Errorf("GetNodeKeys returned nil")
-	} else if actual.CurrPrivKey.Cmp(privKey) != 0 {
-		t.Errorf("CurrPrivKey doesn't match for RekeyKeys added to Keys map")
-	} else if actual.CurrPubKey.Cmp(pubKey) != 0 {
-		t.Errorf("CurrPubKey doesn't match for RekeyKeys added to Keys map")
-	}
-
-	// Delete value and confirm it's gone
-	rkm.DeleteKeys(partner)
-
-	actual = rkm.GetKeys(partner)
-
-	if actual != nil {
-		t.Errorf("GetNodeKeys returned something but expected nil after deletion")
-	}
-
-	// Confirm RekeyKeys behavior of key rotation
-	newPrivKey := grp.NewInt(7)
-	newPubKey := grp.NewInt(91)
-
-	// Add new PrivKey
-	val.NewPrivKey = newPrivKey
-
-	// Call rotate and confirm nothing changes
-	val.RotateKeysIfReady()
-
-	if val.CurrPrivKey.Cmp(privKey) != 0 {
-		t.Errorf("CurrPrivKey doesn't match for RekeyKeys after adding new PrivateKey")
-	} else if val.CurrPubKey.Cmp(pubKey) != 0 {
-		t.Errorf("CurrPubKey doesn't match for RekeyKeys after adding new PrivateKey")
-	}
-
-	// Add new PubKey, rotate, and confirm keys change
-	val.NewPubKey = newPubKey
-	val.RotateKeysIfReady()
-
-	if val.CurrPrivKey.Cmp(newPrivKey) != 0 {
-		t.Errorf("CurrPrivKey doesn't match for RekeyKeys after key rotation")
-	} else if val.CurrPubKey.Cmp(newPubKey) != 0 {
-		t.Errorf("CurrPubKey doesn't match for RekeyKeys after key rotation")
-	}
-}
diff --git a/rekey/rekey.go b/rekey/rekey.go
index fe5997a6db20a46ff737128ed5d542e606725e94..09554a0fe0370b1cde586fc75f85c6bae094448a 100644
--- a/rekey/rekey.go
+++ b/rekey/rekey.go
@@ -3,9 +3,9 @@ package rekey
 import (
 	"bytes"
 	"fmt"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/io"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/keyStore"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/storage"
@@ -112,7 +112,7 @@ func InitRekey(s user.Session, s2 storage.Session, m io.Communications,
 	}
 
 	l.Register(userData.ThisUser.User,
-		int32(cmixproto.Type_REKEY_TRIGGER),
+		int32(keyExchange.Type_REKEY_TRIGGER),
 		&rekeyTriggerList)
 	// TODO(nen) Wouldn't it be possible to register these listeners based
 	//  solely on the inner type? maybe the switchboard can rebroadcast
@@ -120,10 +120,10 @@ func InitRekey(s user.Session, s2 storage.Session, m io.Communications,
 	//  possible
 	// in short, switchboard should be the package that includes outer
 	l.Register(&id.ZeroUser,
-		int32(cmixproto.Type_NO_TYPE),
+		int32(keyExchange.Type_NO_TYPE),
 		&rekeyList)
 	l.Register(&id.ZeroUser,
-		int32(cmixproto.Type_REKEY_CONFIRM),
+		int32(keyExchange.Type_REKEY_CONFIRM),
 		&rekeyConfirmList)
 }
 
@@ -280,7 +280,7 @@ func rekeyProcess(rt rekeyType, partner *id.ID, data []byte) error {
 		h.Write(ctx.BaseKey.Bytes())
 		baseKeyHash := h.Sum(nil)
 		msg := parse.Pack(&parse.TypedBody{
-			MessageType: int32(cmixproto.Type_REKEY_CONFIRM),
+			MessageType: int32(keyExchange.Type_REKEY_CONFIRM),
 			Body:        baseKeyHash,
 		})
 		return comms.SendMessage(session, topology, partner, parse.None, msg, transmissionHost)
diff --git a/rekey/rekey_test.go b/rekey/rekey_test.go
index 6ed7ffc7515941af7817041bb613e95b9781f221..119ad6f5c2538c1da4729cda647b67fc19445a3c 100644
--- a/rekey/rekey_test.go
+++ b/rekey/rekey_test.go
@@ -4,8 +4,8 @@ import (
 	"bytes"
 	"encoding/binary"
 	"fmt"
-	"gitlab.com/elixxir/client/cmixproto"
 	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/io/keyExchange"
 	"gitlab.com/elixxir/client/keyStore"
 	"gitlab.com/elixxir/client/parse"
 	"gitlab.com/elixxir/client/storage"
@@ -170,7 +170,7 @@ func TestRekeyTrigger(t *testing.T) {
 	msg := &parse.Message{
 		Sender: userData.ThisUser.User,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_REKEY_TRIGGER),
+			MessageType: int32(keyExchange.Type_REKEY_TRIGGER),
 			Body:        partnerPubKey.Bytes(),
 		},
 		InferredType: parse.None,
@@ -203,7 +203,7 @@ func TestRekeyTrigger(t *testing.T) {
 	msg = &parse.Message{
 		Sender: userData.ThisUser.User,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_REKEY_TRIGGER),
+			MessageType: int32(keyExchange.Type_REKEY_TRIGGER),
 			Body:        partnerPubKey.Bytes(),
 		},
 		InferredType: parse.None,
@@ -229,7 +229,7 @@ func TestRekeyConfirm(t *testing.T) {
 	msg := &parse.Message{
 		Sender: partnerID,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_REKEY_CONFIRM),
+			MessageType: int32(keyExchange.Type_REKEY_CONFIRM),
 			Body:        baseKey.Bytes(),
 		},
 		InferredType: parse.None,
@@ -248,7 +248,7 @@ func TestRekeyConfirm(t *testing.T) {
 	msg = &parse.Message{
 		Sender: partnerID,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_REKEY_CONFIRM),
+			MessageType: int32(keyExchange.Type_REKEY_CONFIRM),
 			Body:        h.Sum(nil),
 		},
 		InferredType: parse.None,
@@ -274,7 +274,7 @@ func TestRekeyConfirm(t *testing.T) {
 	msg = &parse.Message{
 		Sender: partnerID,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_REKEY_CONFIRM),
+			MessageType: int32(keyExchange.Type_REKEY_CONFIRM),
 			Body:        h.Sum(nil),
 		},
 		InferredType: parse.None,
@@ -303,7 +303,7 @@ func TestRekey(t *testing.T) {
 	msg := &parse.Message{
 		Sender: partnerID,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_NO_TYPE),
+			MessageType: int32(keyExchange.Type_NO_TYPE),
 			Body:        pubKey.Bytes(),
 		},
 		InferredType: parse.Rekey,
@@ -364,7 +364,7 @@ func TestRekey_Errors(t *testing.T) {
 	msg := &parse.Message{
 		Sender: userData.ThisUser.User,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_REKEY_TRIGGER),
+			MessageType: int32(keyExchange.Type_REKEY_TRIGGER),
 			Body:        partnerPubKey.Bytes(),
 		},
 		InferredType: parse.None,
@@ -381,7 +381,7 @@ func TestRekey_Errors(t *testing.T) {
 	msg = &parse.Message{
 		Sender: partnerID,
 		TypedBody: parse.TypedBody{
-			MessageType: int32(cmixproto.Type_NO_TYPE),
+			MessageType: int32(keyExchange.Type_NO_TYPE),
 			Body:        []byte{},
 		},
 		InferredType: parse.Rekey,
diff --git a/storage/cmix/store_test.go b/storage/cmix/store_test.go
index 957ad418535d708cf87a424840531b8d9af9a4dc..49a00033697f42bdf0cf6eab5fd37331de7c25a8 100644
--- a/storage/cmix/store_test.go
+++ b/storage/cmix/store_test.go
@@ -43,21 +43,13 @@ func TestStore_AddRemove(t *testing.T) {
 	nodeId := id.NewIdFromString("test", id.Node, t)
 	key := testStore.grp.NewInt(5)
 
-	err := testStore.Add(nodeId, key)
-	if err != nil {
-		t.Errorf("Unable to add node key: %+v", err)
-		return
-	}
+	testStore.Add(nodeId, key)
 	if _, exists := testStore.nodes[*nodeId]; !exists {
 		t.Errorf("Failed to add node key")
 		return
 	}
 
-	err = testStore.Remove(nodeId)
-	if err != nil {
-		t.Errorf("Unable to remove node key: %+v", err)
-		return
-	}
+	testStore.Remove(nodeId)
 	if _, exists := testStore.nodes[*nodeId]; exists {
 		t.Errorf("Failed to remove node key")
 		return
@@ -66,8 +58,6 @@ func TestStore_AddRemove(t *testing.T) {
 
 // Missing keys path
 func TestStore_GetRoundKeys_Missing(t *testing.T) {
-	var err error
-
 	// Set up the circuit
 	numIds := 10
 	nodeIds := make([]*id.ID, numIds)
@@ -77,10 +67,7 @@ func TestStore_GetRoundKeys_Missing(t *testing.T) {
 
 		// Only add every other node so there are missing nodes
 		if i%2 == 0 {
-			err = testStore.Add(nodeIds[i], key)
-			if err != nil {
-				t.Errorf("Unable to add node key: %+v", err)
-			}
+			testStore.Add(nodeIds[i], key)
 		}
 	}
 
diff --git a/storage/collate/messagePart.go b/storage/collate/messagePart.go
new file mode 100644
index 0000000000000000000000000000000000000000..8a0686cf7ea81f4d3d5d2d51383ff32cd0bab099
--- /dev/null
+++ b/storage/collate/messagePart.go
@@ -0,0 +1,70 @@
+package collate
+
+import (
+	"encoding/binary"
+	"gitlab.com/elixxir/client/context/message"
+)
+
+const typeLen = message.TypeLen
+const idLen = 4
+const partLen = 1
+const numPartsLen = 1
+const headerLen = typeLen + idLen + partLen + numPartsLen
+
+type messagePart struct {
+	Data     []byte
+	Type     []byte
+	Id       []byte
+	Part     []byte
+	NumParts []byte
+	Contents []byte
+}
+
+func newMessage(mt message.Type, id uint32, part uint8, numParts uint8, contents []byte) messagePart {
+	data := make([]byte, len(contents)+headerLen)
+
+	m := Unmarshal(data)
+
+	binary.BigEndian.PutUint32(m.Type, uint32(mt))
+	binary.BigEndian.PutUint32(m.Id, id)
+	m.Part[0] = part
+	m.NumParts[0] = numParts
+	copy(m.Contents, contents)
+	return m
+}
+
+func Unmarshal(data []byte) messagePart {
+	m := messagePart{
+		Data:     data,
+		Type:     data[:typeLen],
+		Id:       data[typeLen : typeLen+idLen],
+		Part:     data[typeLen+idLen : typeLen+idLen+partLen],
+		NumParts: data[typeLen+idLen+partLen : typeLen+idLen+partLen+numPartsLen],
+		Contents: data[typeLen+idLen+partLen+numPartsLen:],
+	}
+	return m
+}
+
+func (m messagePart) GetType() message.Type {
+	return message.Type(binary.BigEndian.Uint32(m.Type))
+}
+
+func (m messagePart) GetID() uint32 {
+	return binary.BigEndian.Uint32(m.Id)
+}
+
+func (m messagePart) GetPart() uint8 {
+	return m.Part[0]
+}
+
+func (m messagePart) GetNumParts() uint8 {
+	return m.NumParts[0]
+}
+
+func (m messagePart) GetContents() []byte {
+	return m.Contents
+}
+
+func (m messagePart) Marshal() []byte {
+	return m.Data
+}
diff --git a/storage/collate/multiPartMessage.go b/storage/collate/multiPartMessage.go
new file mode 100644
index 0000000000000000000000000000000000000000..6dfc534230961925d2fabce7f8e03f6ad31cfa12
--- /dev/null
+++ b/storage/collate/multiPartMessage.go
@@ -0,0 +1,16 @@
+package collate
+
+import (
+	"gitlab.com/elixxir/client/context/message"
+	"time"
+)
+
+type multiPartMessage struct {
+	messageID    uint64
+	numParts     uint8
+	presentParts uint8
+	timestamp    time.Time
+	messageType  message.Type
+
+	parts [][]byte
+}
diff --git a/storage/collate/store.go b/storage/collate/store.go
new file mode 100644
index 0000000000000000000000000000000000000000..faf31b2c5330ac94d4c8c2d64da6428a7690b8de
--- /dev/null
+++ b/storage/collate/store.go
@@ -0,0 +1,19 @@
+package collate
+
+import (
+	"crypto/md5"
+	"encoding/binary"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type multiPartID [16]byte
+
+type Store struct {
+	multiparts map[multiPartID]multiPartMessage
+}
+
+func getMultiPartID(partner *id.ID, messageID uint64) multiPartID {
+	b := make([]byte, 8)
+	binary.BigEndian.PutUint64(b, messageID)
+	return md5.Sum(append(partner[:], b...))
+}
diff --git a/storage/conversation/partner.go b/storage/conversation/partner.go
new file mode 100644
index 0000000000000000000000000000000000000000..bae8aa98123df248b1a85d19499a48afc917b71e
--- /dev/null
+++ b/storage/conversation/partner.go
@@ -0,0 +1,174 @@
+package conversation
+
+import (
+	"encoding/json"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/id"
+	"math"
+	"strings"
+	"sync"
+	"time"
+)
+
+const conversationKeyPrefix = "conversation"
+const currentConversationVersion = 0
+const bottomRegion = math.MaxUint32 / 4
+const topRegion = bottomRegion * 3
+
+type Conversation struct {
+	// Public & stored data
+	lastReceivedID         uint32
+	numReceivedRevolutions uint32
+	nextSentID             uint64
+
+	// Private, unstored data
+	partner *id.ID
+	kv      *versioned.KV
+	mux     sync.Mutex
+}
+
+type conversationDisk struct {
+	// Public & stored data
+	LastReceivedID         uint32
+	NumReceivedRevolutions uint32
+	NextSendID             uint64
+}
+
+// Returns the Conversation if it can be found, otherwise returns a new partner
+func LoadOrMakeConversation(kv *versioned.KV, partner *id.ID) *Conversation {
+
+	c, err := loadConversation(kv, partner)
+	if err != nil && !strings.Contains(err.Error(), "Failed to Load conversation") {
+		jww.FATAL.Panicf("Failed to loadOrMakeConversation: %s", err)
+	}
+
+	if c == nil {
+		c = &Conversation{
+			lastReceivedID:         0,
+			numReceivedRevolutions: 0,
+			nextSentID:             0,
+			partner:                partner,
+			kv:                     kv,
+		}
+		if err = c.save(); err != nil {
+			jww.FATAL.Panicf("Failed to save new conversation: %s", err)
+		}
+	}
+
+	return c
+}
+
+// Finds the full 64 bit message ID and updates the internal last message ID if
+// the new ID is newer
+func (c *Conversation) ProcessReceivedMessageID(mid uint32, timestamp time.Time) uint64 {
+	c.mux.Lock()
+	defer c.mux.Unlock()
+	var high uint32
+	switch cmp(c.lastReceivedID, mid) {
+	case 1:
+		c.numReceivedRevolutions++
+		c.lastReceivedID = mid
+		if err := c.save(); err != nil {
+			jww.FATAL.Panicf("Failed to save after updating Last "+
+				"Received ID in a conversation: %s", err)
+		}
+		high = c.numReceivedRevolutions
+	case 0:
+		high = c.numReceivedRevolutions
+	case -1:
+		high = c.numReceivedRevolutions - 1
+	}
+
+	return (uint64(high) << 16) | uint64(mid)
+}
+
+func cmp(a, b uint32) int {
+	if a > topRegion && b < bottomRegion {
+		return 1
+	} else if a < bottomRegion && b > topRegion {
+		return -1
+	}
+	return 0
+}
+
+//returns the next sendID in both full and truncated formats
+func (c *Conversation) GetNextSendID() (uint64, uint32) {
+	c.mux.Lock()
+	old := c.nextSentID
+	c.nextSentID++
+	if err := c.save(); err != nil {
+		jww.FATAL.Panicf("Failed to save after incrementing the sendID: "+
+			"%s", err)
+	}
+	defer c.mux.Unlock()
+	return old, uint32(old & 0x00000000FFFFFFFF)
+}
+
+func loadConversation(kv *versioned.KV, partner *id.ID) (*Conversation, error) {
+	key := makeConversationKey(partner)
+
+	obj, err := kv.Get(key)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to Load conversation")
+	}
+
+	c := &Conversation{
+		partner: partner,
+		kv:      kv,
+	}
+
+	if err = c.unmarshal(obj.Data); err != nil {
+		return nil, errors.WithMessage(err, "Failed to Load conversation")
+	}
+
+	return c, nil
+}
+
+func (c *Conversation) save() error {
+	data, err := c.marshal()
+	if err != nil {
+		return err
+	}
+
+	obj := versioned.Object{
+		Version:   currentConversationVersion,
+		Timestamp: time.Now(),
+		Data:      data,
+	}
+
+	key := makeConversationKey(c.partner)
+	return c.kv.Set(key, &obj)
+}
+
+func (c *Conversation) unmarshal(b []byte) error {
+	cd := conversationDisk{}
+
+	if err := json.Unmarshal(b, &cd); err != nil {
+		return errors.Wrap(err, "Failed to Unmarshal Conversation")
+	}
+
+	c.lastReceivedID = cd.LastReceivedID
+	c.numReceivedRevolutions = cd.NumReceivedRevolutions
+	c.nextSentID = cd.NextSendID
+
+	return nil
+}
+
+func (c *Conversation) marshal() ([]byte, error) {
+	cd := conversationDisk{}
+	cd.LastReceivedID = c.lastReceivedID
+	cd.NumReceivedRevolutions = c.numReceivedRevolutions
+	cd.NextSendID = c.nextSentID
+
+	b, err := json.Marshal(&cd)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to unmarshal conversation")
+	}
+	return b, nil
+}
+
+func makeConversationKey(partner *id.ID) string {
+	return conversationKeyPrefix + ":" + partner.String()
+}
diff --git a/storage/conversation/store.go b/storage/conversation/store.go
new file mode 100644
index 0000000000000000000000000000000000000000..be33d73f464c6e40dd027dc928129217d8d2f250
--- /dev/null
+++ b/storage/conversation/store.go
@@ -0,0 +1,39 @@
+package conversation
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/id"
+	"sync"
+)
+
+type Store struct {
+	loadedConversations map[id.ID]*Conversation
+	kv                  *versioned.KV
+	mux                 sync.RWMutex
+}
+
+//Returns a new conversation store made off of the KV
+func NewStore(kv *versioned.KV) *Store {
+	return &Store{
+		loadedConversations: make(map[id.ID]*Conversation),
+		kv:                  kv,
+	}
+}
+
+// Gets the conversation with the partner from ram if it is there, otherwise
+// loads it from disk
+func (s *Store) Get(partner *id.ID) *Conversation {
+	s.mux.RLock()
+	c, ok := s.loadedConversations[*partner]
+	s.mux.RUnlock()
+	if !ok {
+		s.mux.Lock()
+		c, ok = s.loadedConversations[*partner]
+		if !ok {
+			c = LoadOrMakeConversation(s.kv, partner)
+			s.loadedConversations[*partner] = c
+		}
+		s.mux.Unlock()
+	}
+	return c
+}
diff --git a/storage/e2e/manager.go b/storage/e2e/manager.go
index a0938315b443c74d1f103212876a31914497b59c..c4dd2ce21437fb2095a57aa7749daad0d28dc15d 100644
--- a/storage/e2e/manager.go
+++ b/storage/e2e/manager.go
@@ -6,6 +6,7 @@ import (
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 	jww "github.com/spf13/jwalterweatherman"
+	dh "gitlab.com/elixxir/crypto/diffieHellman"
 )
 
 type Manager struct {
@@ -28,11 +29,13 @@ func newManager(ctx *context, partnerID *id.ID, myPrivKey *cyclic.Int,
 	m.send = NewSessionBuff(m, "send")
 	m.receive = NewSessionBuff(m, "receive")
 
-	sendSession := newSession(m, myPrivKey, partnerPubKey, sendParams, Send, SessionID{})
+	sendSession := newSession(m, myPrivKey, partnerPubKey, nil,
+		sendParams, Send, SessionID{})
 
 	m.send.AddSession(sendSession)
 
-	receiveSession := newSession(m, myPrivKey, partnerPubKey, receiveParams, Receive, SessionID{})
+	receiveSession := newSession(m, myPrivKey, partnerPubKey, nil,
+		receiveParams, Receive, SessionID{})
 
 	m.receive.AddSession(receiveSession)
 
@@ -73,17 +76,28 @@ func (m *Manager) GetPartnerID() *id.ID {
 
 // creates a new receive session using the latest private key this user has sent
 // and the new public key received from the partner.
-func (m *Manager) NewReceiveSession(partnerPubKey *cyclic.Int, params SessionParams, trigger SessionID) *Session {
-	//find your last confirmed private key
-	myPrivKey := m.send.GetNewestRekeyableSession().GetMyPrivKey()
+// If the session already exists, it will not be overwritten and the extant
+// session will be returned, with the bool set to true denoting a duplicate.
+// This is so duplicate key exchange triggering can be supported
+func (m *Manager) NewReceiveSession(partnerPubKey *cyclic.Int, params SessionParams,
+	trigger *Session) (*Session, bool) {
+
+	//check if the session already exists
+	baseKey := dh.GenerateSessionKey(trigger.myPrivKey, partnerPubKey, m.ctx.grp)
+	sessionID := getSessionIDFromBaseKey(baseKey)
+
+	if s := m.receive.GetByID(sessionID); s != nil {
+		return s, true
+	}
 
-	//create the session
-	session := newSession(m, myPrivKey, partnerPubKey, params, Receive, trigger)
+	//create the session but do not save
+	session := newSession(m, trigger.myPrivKey, partnerPubKey, baseKey, params, Receive,
+		trigger.GetID())
 
 	//add the session to the buffer
 	m.receive.AddSession(session)
 
-	return session
+	return session, false
 }
 
 // creates a new receive session using the latest public key received from the
@@ -95,7 +109,8 @@ func (m *Manager) NewSendSession(myPrivKey *cyclic.Int, params SessionParams, tr
 	partnerPubKey := m.receive.GetNewestRekeyableSession().partnerPubKey
 
 	//create the session
-	session := newSession(m, myPrivKey, partnerPubKey, params, Send, trigger)
+	session := newSession(m, myPrivKey, partnerPubKey, nil,
+		params, Send, trigger)
 
 	//add the session to the send session buffer and return
 	m.send.AddSession(session)
@@ -104,7 +119,7 @@ func (m *Manager) NewSendSession(myPrivKey *cyclic.Int, params SessionParams, tr
 }
 
 // gets the correct session to send with depending on the type of send
-func (m *Manager) GetSendingSession(st params.SendType) *Session {
+func (m *Manager) GetSessionForSending(st params.SendType) *Session {
 	switch st {
 	case params.Standard:
 		return m.send.GetSessionForSending()
@@ -118,6 +133,16 @@ func (m *Manager) GetSendingSession(st params.SendType) *Session {
 	return nil
 }
 
+// gets the send session of the passed ID. Returns nil if no session is found
+func (m *Manager) GetSendSession(sessionID SessionID) *Session {
+	return m.send.GetByID(sessionID)
+}
+
+// gets the receive session of the passed ID. Returns nil if no session is found
+func (m *Manager) GetReceiveSession(sessionID SessionID) *Session {
+	return m.receive.GetByID(sessionID)
+}
+
 // Confirms a send session is known about by the partner
 func (m *Manager) Confirm(sid SessionID) error {
 	return m.send.Confirm(sid)
diff --git a/storage/e2e/session.go b/storage/e2e/session.go
index f5d313170b05f75a1f25c69832989daada34bf64..43446a9867e3e9ae0cccf0e2c8211c7830a020cc 100644
--- a/storage/e2e/session.go
+++ b/storage/e2e/session.go
@@ -39,7 +39,6 @@ type Session struct {
 	// if a receive session
 	trigger SessionID
 
-
 	//denotes if the other party has confirmed this key
 	negotiationStatus Negotiation
 
@@ -81,22 +80,21 @@ type SessionDisk struct {
 
 /*CONSTRUCTORS*/
 //Generator which creates all keys and structures
-func newSession(manager *Manager, myPrivKey *cyclic.Int,
-	partnerPubKey *cyclic.Int, params SessionParams, t SessionType,
-	trigger SessionID) *Session {
+func newSession(manager *Manager, myPrivKey, partnerPubKey, baseKey *cyclic.Int,
+	params SessionParams, t SessionType, trigger SessionID) *Session {
 
 	confirmation := Unconfirmed
 	if t == Receive {
 		confirmation = Confirmed
 	}
 
-
 	session := &Session{
 		params:            params,
 		manager:           manager,
 		t:                 t,
 		myPrivKey:         myPrivKey,
 		partnerPubKey:     partnerPubKey,
+		baseKey:           baseKey,
 		negotiationStatus: confirmation,
 		trigger:           trigger,
 	}
@@ -201,16 +199,21 @@ func (s *Session) GetTrigger() SessionID {
 	return s.trigger
 }
 
-//Blake2B hash of base key used for storage
-func (s *Session) GetID() SessionID {
+//underlying definition of session id
+func getSessionIDFromBaseKey(baseKey *cyclic.Int) SessionID {
 	// no lock is needed because this cannot be edited
 	sid := SessionID{}
 	h, _ := hash.NewCMixHash()
-	h.Write(s.baseKey.Bytes())
+	h.Write(baseKey.Bytes())
 	copy(sid[:], h.Sum(nil))
 	return sid
 }
 
+//Blake2B hash of base key used for storage
+func (s *Session) GetID() SessionID {
+	return getSessionIDFromBaseKey(s.baseKey)
+}
+
 // returns the ID of the partner for this session
 func (s *Session) GetPartner() *id.ID {
 	return s.manager.partner
@@ -263,14 +266,12 @@ func (s *Session) unmarshal(b []byte) error {
 	s.ttl = sd.TTL
 	copy(s.trigger[:], sd.Trigger)
 
-
 	statesKey := makeStateVectorKey(keyEKVPrefix, s.GetID())
 	s.keyState, err = loadStateVector(s.manager.ctx, statesKey)
 	if err != nil {
 		return err
 	}
 
-
 	return nil
 }
 
@@ -322,6 +323,7 @@ func (s *Session) Status() Status {
 // Sets the negotiation status, this tracks the state of the key negotiation,
 // only certain movements are allowed
 //   Unconfirmed <--> Sending --> Sent --> Confirmed <--> NewSessionTriggered --> NewSessionCreated
+//				  -------------->
 //
 // Saves the session unless the status is sending so that on reload the rekey
 // will be redone if it was in the process of sending
@@ -335,7 +337,7 @@ var legalStateChanges = [][]bool{
 	{false, false, false, false, false, false},
 	{true, false, true, true, false, false},
 	{false, false, false, true, false, false},
-	{false, false, false, false, false, false},
+	{false, false, false, false, true, false},
 	{false, false, false, true, false, true},
 	{false, false, false, false, false, false},
 }
@@ -431,7 +433,7 @@ func (s *Session) triggerNegotiation() bool {
 }
 
 // checks if the session has been confirmed
-func (s *Session) ConfirmationStatus() Negotiation {
+func (s *Session) NegotiationStatus() Negotiation {
 	s.mux.RLock()
 	defer s.mux.RUnlock()
 	return s.negotiationStatus
@@ -439,7 +441,7 @@ func (s *Session) ConfirmationStatus() Negotiation {
 
 // checks if the session has been confirmed
 func (s *Session) IsConfirmed() bool {
-	c := s.ConfirmationStatus()
+	c := s.NegotiationStatus()
 	return c >= Confirmed
 }
 
@@ -464,8 +466,10 @@ func (s *Session) generate() {
 			csprng.NewSystemRNG())
 	}
 
-	// compute the base key
-	s.baseKey = dh.GenerateSessionKey(s.myPrivKey, s.partnerPubKey, grp)
+	// compute the base key if it is not already there
+	if s.baseKey != nil {
+		s.baseKey = dh.GenerateSessionKey(s.myPrivKey, s.partnerPubKey, grp)
+	}
 
 	//generate ttl and keying info
 	keysTTL, numKeys := e2e.GenerateKeyTTL(s.baseKey.GetLargeInt(),
diff --git a/storage/e2e/sessionID.go b/storage/e2e/sessionID.go
index c5837c2cc9ad5688d12a83b5888ed4e1c41982b6..a1e31bd25a22493e6dcd289c58429edc9edd405f 100644
--- a/storage/e2e/sessionID.go
+++ b/storage/e2e/sessionID.go
@@ -1,10 +1,15 @@
 package e2e
 
-import "encoding/base64"
+import (
+	"encoding/base64"
+	"github.com/pkg/errors"
+)
 
-type SessionID [32]byte
+const sessionIDLen = 32
 
-func (sid SessionID) Bytes() []byte {
+type SessionID [sessionIDLen]byte
+
+func (sid SessionID) Marshal() []byte {
 	return sid[:]
 }
 
@@ -12,7 +17,19 @@ func (sid SessionID) String() string {
 	return base64.StdEncoding.EncodeToString(sid[:])
 }
 
+func (sid SessionID) Unmarshal(b []byte) error {
+	if len(b) != sessionIDLen {
+		return errors.New("SessionID of invalid length received")
+	}
+
+	copy(sid[:], b)
+	return nil
+}
+
+
 //builds the
 func makeSessionKey(sid SessionID) string {
 	return sid.String()
 }
+
+
diff --git a/storage/e2e/session_test.go b/storage/e2e/session_test.go
index 9c7f69a76e4de260ce7ebd70594465cdc8641fd8..7c6ceab532164ad2cfdfebecc015fb4dcd0e4adb 100644
--- a/storage/e2e/session_test.go
+++ b/storage/e2e/session_test.go
@@ -372,7 +372,7 @@ func TestSession_GetBaseKey(t *testing.T) {
 func TestSession_GetID(t *testing.T) {
 	s, _ := makeTestSession(t)
 	id := s.GetID()
-	if len(id.Bytes()) == 0 {
+	if len(id.Marshal()) == 0 {
 		t.Error("Zero length for session ID!")
 	}
 }
diff --git a/storage/regStatus.go b/storage/regStatus.go
index b065e450a1389b513a33df004123b38f62bc2e54..2df2672ca81fcc51a457e21bd39ed9e1812f0f14 100644
--- a/storage/regStatus.go
+++ b/storage/regStatus.go
@@ -11,7 +11,6 @@ import (
 	"fmt"
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/storage/versioned"
-	"os"
 	"time"
 )
 
@@ -55,18 +54,32 @@ func (rs RegistrationStatus) marshalBinary() []byte {
 	return b
 }
 
-// loads the registration status from disk. If the status cannot be found, it
-// defaults to Not Started
-func (s *Session) loadOrCreateRegStatus() error {
+// creates a new registration status and stores it
+func (s *Session) newRegStatus() error {
+	s.regStatus = NotStarted
+
+	now := time.Now()
+
+	obj := versioned.Object{
+		Version:   currentRegistrationStatusVersion,
+		Timestamp: now,
+		Data:      s.regStatus.marshalBinary(),
+	}
+
+	err := s.Set(registrationStatusKey, &obj)
+	if err != nil {
+		return errors.WithMessagef(err, "Failed to store new "+
+			"registration status")
+	}
+
+	return nil
+}
+
+// loads registration status from disk.
+func (s *Session) loadRegStatus() error {
 	obj, err := s.Get(registrationStatusKey)
 	if err != nil {
-		if os.IsNotExist(err) {
-			// set at not started but do not save until it is updated
-			s.regStatus = NotStarted
-			return nil
-		} else {
-			return errors.WithMessagef(err, "Failed to load registration status")
-		}
+		return errors.WithMessage(err, "Failed to load registration status")
 	}
 	s.regStatus = regStatusUnmarshalBinary(obj.Data)
 	return nil
diff --git a/storage/session.go b/storage/session.go
index 497df93cca1c392f9ec10d3d08b753b52d952046..0d1ad47e245ae512af686c785753da9bad890f08 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -12,6 +12,7 @@ import (
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/storage/cmix"
+	"gitlab.com/elixxir/client/storage/conversation"
 	"gitlab.com/elixxir/client/storage/e2e"
 	"gitlab.com/elixxir/client/storage/user"
 	"gitlab.com/elixxir/client/storage/versioned"
@@ -31,15 +32,14 @@ type Session struct {
 	regStatus RegistrationStatus
 
 	//sub-stores
-	e2e  *e2e.Store
-	cmix *cmix.Store
-	user *user.User
-
-	loaded bool
+	e2e           *e2e.Store
+	cmix          *cmix.Store
+	user          *user.User
+	conversations *conversation.Store
 }
 
 // Initialize a new Session object
-func Init(baseDir, password string) (*Session, error) {
+func initStore(baseDir, password string) (*Session, error) {
 	fs, err := ekv.NewFilestore(baseDir, password)
 	var s *Session
 	if err != nil {
@@ -49,82 +49,77 @@ func Init(baseDir, password string) (*Session, error) {
 
 	s = &Session{
 		kv:     versioned.NewKV(fs),
-		loaded: false,
-	}
-
-	err = s.loadOrCreateRegStatus()
-	if err != nil {
-		return nil, errors.WithMessage(err,
-			"Failed to load or create registration status")
 	}
 
 	return s, nil
 }
 
 // Creates new UserData in the session
-func (s *Session) Create(uid *id.ID, salt []byte, rsaKey *rsa.PrivateKey,
+func New(baseDir, password string, uid *id.ID, salt []byte, rsaKey *rsa.PrivateKey,
 	isPrecanned bool, cmixDHPrivKey, e2eDHPrivKey *cyclic.Int, cmixGrp,
-	e2eGrp *cyclic.Group) error {
-	s.mux.Lock()
-	defer s.mux.Unlock()
-	if s.loaded {
-		return errors.New("Cannot create a session which already has one loaded")
+	e2eGrp *cyclic.Group) (*Session, error) {
+
+	s, err := initStore(baseDir, password)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to create session")
 	}
 
-	var err error
+	err = s.newRegStatus()
+	if err != nil {
+		return nil, errors.WithMessage(err,
+			"Create new session")
+	}
 
 	s.user, err = user.NewUser(s.kv, uid, salt, rsaKey, isPrecanned)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to create Session due "+
-			"to failed user creation")
+		return nil, errors.WithMessage(err, "Failed to create session")
 	}
 
 	s.cmix, err = cmix.NewStore(cmixGrp, s.kv, cmixDHPrivKey)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to create Session due "+
-			"to failed cmix keystore creation")
+		return nil, errors.WithMessage(err, "Failed to create session")
 	}
 
 	s.e2e, err = e2e.NewStore(e2eGrp, s.kv, e2eDHPrivKey)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to create Session due "+
-			"to failed e2e keystore creation")
+		return nil, errors.WithMessage(err, "Failed to create session")
 	}
 
-	s.loaded = true
-	return nil
+	s.conversations = conversation.NewStore(s.kv)
+
+	return s, nil
 }
 
 // Loads existing user data into the session
-func (s *Session) Load() error {
-	s.mux.Lock()
-	defer s.mux.Unlock()
-	if s.loaded {
-		return errors.New("Cannot load a session which already has one loaded")
+func Load(baseDir, password string) (*Session, error) {
+	s, err := initStore(baseDir, password)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to load Session")
 	}
 
-	var err error
+	err = s.loadRegStatus()
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to load Session")
+	}
 
 	s.user, err = user.LoadUser(s.kv)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to load Session due "+
-			"to failure to load user")
+		return nil, errors.WithMessage(err, "Failed to load Session")
 	}
 
 	s.cmix, err = cmix.LoadStore(s.kv)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to load Session due "+
-			"to failure to load cmix keystore")
+		return nil, errors.WithMessage(err, "Failed to load Session")
 	}
 
 	s.e2e, err = e2e.LoadStore(s.kv)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to load Session due "+
-			"to failure to load e2e keystore")
+		return nil, errors.WithMessage(err, "Failed to load Session")
 	}
 
-	s.loaded = true
-	return nil
+	s.conversations = conversation.NewStore(s.kv)
+
+	return s, nil
 }
 
 func (s *Session) User() *user.User {
@@ -145,6 +140,12 @@ func (s *Session) E2e() *e2e.Store {
 	return s.e2e
 }
 
+func (s *Session) Conversations() *conversation.Store {
+	s.mux.RLock()
+	defer s.mux.RUnlock()
+	return s.conversations
+}
+
 // Get an object from the session
 func (s *Session) Get(key string) (*versioned.Object, error) {
 	return s.kv.Get(key)
diff --git a/storage/user/cryptographic.go b/storage/user/cryptographic.go
index bc7eb730a3789295bdf661e1e44564e41fbb6f68..fe5d9b59ab979d6e5df20117ebdb43a129f6df31 100644
--- a/storage/user/cryptographic.go
+++ b/storage/user/cryptographic.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"encoding/gob"
 	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
@@ -21,13 +22,7 @@ type CryptographicIdentity struct {
 }
 
 func newCryptographicIdentity(uid *id.ID, salt []byte, rsaKey *rsa.PrivateKey,
-	isPrecanned bool, kv *versioned.KV) (*CryptographicIdentity, error) {
-
-	_, err := kv.Get(cryptographicIdentityKey)
-	if err == nil {
-		return nil, errors.New("cannot create cryptographic identity " +
-			"when one already exists")
-	}
+	isPrecanned bool, kv *versioned.KV) *CryptographicIdentity {
 
 	ci := &CryptographicIdentity{
 		userID:      uid,
@@ -36,7 +31,12 @@ func newCryptographicIdentity(uid *id.ID, salt []byte, rsaKey *rsa.PrivateKey,
 		isPrecanned: isPrecanned,
 	}
 
-	return ci, ci.save(kv)
+	if err := ci.save(kv); err != nil {
+		jww.FATAL.Panicf("Failed to store the new Cryptographic"+
+			" Identity: %s", err)
+	}
+
+	return ci
 }
 
 func loadCryptographicIdentity(kv *versioned.KV) (*CryptographicIdentity, error) {
diff --git a/storage/user/regValidationSig.go b/storage/user/regValidationSig.go
index 89593f40391c2a2d00f002c2b06071f2d7c9b5e4..0a736904d6d0fc7890795eae6d3391bba6634c4c 100644
--- a/storage/user/regValidationSig.go
+++ b/storage/user/regValidationSig.go
@@ -2,6 +2,7 @@ package user
 
 import (
 	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"time"
 )
@@ -29,13 +30,13 @@ func (u *User) loadRegistrationValidationSignature() {
 
 // Sets the Registration Validation Signature if it is not set and stores it in
 // the ekv
-func (u *User) SetRegistrationValidationSignature(b []byte) error {
+func (u *User) SetRegistrationValidationSignature(b []byte) {
 	u.rvsMux.Lock()
 	defer u.rvsMux.Unlock()
 
 	//check if the signature already exists
 	if u.regValidationSig != nil {
-		return errors.New("cannot overwrite existing Registration Validation Signature")
+		jww.FATAL.Panicf("cannot overwrite existing Registration Validation Signature")
 	}
 
 	obj := &versioned.Object{
@@ -46,11 +47,9 @@ func (u *User) SetRegistrationValidationSignature(b []byte) error {
 
 	err := u.kv.Set(regValidationSigKey, obj)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to store the "+
-			"Registration Validation Signature")
+		jww.FATAL.Panicf("Failed to store the Registration Validation "+
+			"Signature: %s", err)
 	}
 
 	u.regValidationSig = b
-
-	return nil
 }
diff --git a/storage/user/user.go b/storage/user/user.go
index 34e6f2e96b20a363b94db77700fb0dd26db1da67..7abd5f2e2962e4ec84be4d141c53472c27d9b135 100644
--- a/storage/user/user.go
+++ b/storage/user/user.go
@@ -24,11 +24,7 @@ type User struct {
 func NewUser(kv *versioned.KV, uid *id.ID, salt []byte, rsaKey *rsa.PrivateKey,
 	isPrecanned bool) (*User, error) {
 
-	ci, err := newCryptographicIdentity(uid, salt, rsaKey, isPrecanned, kv)
-	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to create user "+
-			"due to failure to create cryptographic identity")
-	}
+	ci := newCryptographicIdentity(uid, salt, rsaKey, isPrecanned, kv)
 
 	return &User{ci: ci, kv: kv}, nil
 }
diff --git a/storage/user/username.go b/storage/user/username.go
index 5d2052812009b02061ab52a1a0e377d433fd71a0..9127eae18731431b14cfaeec3149f5eb4d79e6b0 100644
--- a/storage/user/username.go
+++ b/storage/user/username.go
@@ -2,6 +2,7 @@ package user
 
 import (
 	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"time"
 )
@@ -33,7 +34,7 @@ func (u *User) SetUsername(username string) error {
 
 	err := u.kv.Set(usernameKey, obj)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to store the username")
+		jww.FATAL.Panicf("Failed to store the username: %s", err)
 	}
 
 	u.username = username