diff --git a/api/authenticatedChannel.go b/api/auth.go
similarity index 71%
rename from api/authenticatedChannel.go
rename to api/auth.go
index 4b9ef33192279c0d5a6d36c520e17ddddf77c35d..d7a5cc362ea49dc9108e220d05c5fd45eeb5586f 100644
--- a/api/authenticatedChannel.go
+++ b/api/auth.go
@@ -9,15 +9,13 @@ package api
 
 import (
 	"encoding/binary"
-	"gitlab.com/elixxir/client/catalog"
 	"math/rand"
 
 	"github.com/cloudflare/circl/dh/sidh"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/storage/edge"
+	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
 	util "gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
@@ -36,13 +34,12 @@ func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact,
 	message string) (id.Round, error) {
 	jww.INFO.Printf("RequestAuthenticatedChannel(%s)", recipient.ID)
 
-	if !c.network.GetHealthTracker().IsHealthy() {
+	if !c.network.IsHealthy() {
 		return 0, errors.New("Cannot request authenticated channel " +
 			"creation when the network is not healthy")
 	}
 
-	return auth.RequestAuth(recipient, me, c.rng.GetStream(),
-		c.storage, c.network)
+	return c.auth.Request(recipient, c.GetUser().GetContact().Facts)
 }
 
 // ResetSession resets an authenticate channel that already exists
@@ -50,18 +47,17 @@ func (c *Client) ResetSession(recipient, me contact.Contact,
 	message string) (id.Round, error) {
 	jww.INFO.Printf("ResetSession(%s)", recipient.ID)
 
-	if !c.network.GetHealthTracker().IsHealthy() {
+	if !c.network.IsHealthy() {
 		return 0, errors.New("Cannot request authenticated channel " +
 			"creation when the network is not healthy")
 	}
 
-	return auth.ResetSession(recipient, me, c.rng.GetStream(),
-		c.storage, c.network)
+	return c.auth.Reset(recipient)
 }
 
 // GetAuthRegistrar gets the object which allows the registration of auth
 // callbacks
-func (c *Client) GetAuthRegistrar() interfaces.Auth {
+func (c *Client) GetAuthRegistrar() auth.State {
 	jww.INFO.Printf("GetAuthRegistrar(...)")
 
 	return c.auth
@@ -72,7 +68,7 @@ func (c *Client) GetAuthRegistrar() interfaces.Auth {
 func (c *Client) GetAuthenticatedChannelRequest(partner *id.ID) (contact.Contact, error) {
 	jww.INFO.Printf("GetAuthenticatedChannelRequest(%s)", partner)
 
-	return c.storage.Auth().GetReceivedRequestData(partner)
+	return c.auth.GetReceivedRequest(partner)
 }
 
 // ConfirmAuthenticatedChannel creates an authenticated channel out of a valid
@@ -86,7 +82,7 @@ func (c *Client) GetAuthenticatedChannelRequest(partner *id.ID) (contact.Contact
 func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) (id.Round, error) {
 	jww.INFO.Printf("ConfirmAuthenticatedChannel(%s)", recipient.ID)
 
-	if !c.network.GetHealthTracker().IsHealthy() {
+	if !c.network.IsHealthy() {
 		return 0, errors.New("Cannot request authenticated channel " +
 			"creation when the network is not healthy")
 	}
@@ -99,18 +95,19 @@ func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) (id.Roun
 func (c *Client) VerifyOwnership(received, verified contact.Contact) bool {
 	jww.INFO.Printf("VerifyOwnership(%s)", received.ID)
 
-	return auth.VerifyOwnership(received, verified, c.storage)
+	return c.auth.VerifyOwnership(received, verified, c.e2e)
 }
 
 // HasAuthenticatedChannel returns true if an authenticated channel exists for
 // the partner
 func (c *Client) HasAuthenticatedChannel(partner *id.ID) bool {
-	m, err := c.storage.E2e().GetPartner(partner)
+	m, err := c.e2e.GetPartner(partner)
 	return m != nil && err == nil
 }
 
 // Create an insecure e2e relationship with a precanned user
-func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) (contact.Contact, error) {
+func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) (
+	contact.Contact, error) {
 
 	precan := c.MakePrecannedContact(precannedID)
 
@@ -135,49 +132,15 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) (contact.Co
 	mySIDHPrivKey.GeneratePublicKey(mySIDHPubKey)
 
 	// add the precanned user as a e2e contact
-	sesParam := c.parameters.E2EParams
-	err := c.storage.E2e().AddPartner(precan.ID, precan.DhPubKey,
-		c.storage.E2e().GetDHPrivateKey(), theirSIDHPubKey,
+	// FIXME: these params need to be threaded through...
+	sesParam := session.GetDefaultParams()
+	_, err := c.e2e.AddPartner(precan.ID, precan.DhPubKey,
+		c.e2e.GetHistoricalDHPrivkey(), theirSIDHPubKey,
 		mySIDHPrivKey, sesParam, sesParam)
 
 	// check garbled messages in case any messages arrived before creating
 	// the channel
-	c.network.CheckGarbledMessages()
-
-	//add the e2e and rekey firngeprints
-	//e2e
-	sessionPartner, err := c.storage.E2e().GetPartner(precan.ID)
-	if err != nil {
-		jww.FATAL.Panicf("Cannot find %s right after creating: %+v", precan.ID, err)
-	}
-	me := c.storage.GetUser().ReceptionID
-
-	c.storage.GetEdge().Add(edge.Preimage{
-		Data:   sessionPartner.GetE2EPreimage(),
-		Type:   catalog.E2e,
-		Source: precan.ID[:],
-	}, me)
-
-	// slient (rekey)
-	c.storage.GetEdge().Add(edge.Preimage{
-		Data:   sessionPartner.GetSilentPreimage(),
-		Type:   catalog.Silent,
-		Source: precan.ID[:],
-	}, me)
-
-	// File transfer end
-	c.storage.GetEdge().Add(edge.Preimage{
-		Data:   sessionPartner.GetFileTransferPreimage(),
-		Type:   catalog.EndFT,
-		Source: precan.ID[:],
-	}, me)
-
-	// group request
-	c.storage.GetEdge().Add(edge.Preimage{
-		Data:   sessionPartner.GetGroupRequestPreimage(),
-		Type:   catalog.GroupRq,
-		Source: precan.ID[:],
-	}, me)
+	c.network.CheckInProgressMessages()
 
 	return precan, err
 }
@@ -185,14 +148,14 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) (contact.Co
 // Create an insecure e2e contact object for a precanned user
 func (c *Client) MakePrecannedContact(precannedID uint) contact.Contact {
 
-	e2eGrp := c.storage.E2e().GetGroup()
+	e2eGrp := c.storage.GetE2EGroup()
 
-	// get the user definition
 	precanned := createPrecannedUser(precannedID, c.rng.GetStream(),
-		c.storage.Cmix().GetGroup(), e2eGrp)
+		c.storage.GetCmixGroup(), e2eGrp)
 
 	// compute their public e2e key
-	partnerPubKey := e2eGrp.ExpG(precanned.E2eDhPrivateKey, e2eGrp.NewInt(1))
+	partnerPubKey := e2eGrp.ExpG(precanned.E2eDhPrivateKey,
+		e2eGrp.NewInt(1))
 
 	return contact.Contact{
 		ID:             precanned.ReceptionID,
@@ -206,12 +169,14 @@ func (c *Client) MakePrecannedContact(precannedID uint) contact.Contact {
 // E2E relationship. An error is returned if no relationship with the partner
 // is found.
 func (c *Client) GetRelationshipFingerprint(partner *id.ID) (string, error) {
-	m, err := c.storage.E2e().GetPartner(partner)
+	m, err := c.e2e.GetPartner(partner)
 	if err != nil {
-		return "", errors.Errorf("could not get partner %s: %+v", partner, err)
+		return "", errors.Errorf("could not get partner %s: %+v",
+			partner, err)
 	} else if m == nil {
-		return "", errors.Errorf("manager for partner %s is nil.", partner)
+		return "", errors.Errorf("manager for partner %s is nil.",
+			partner)
 	}
 
-	return m.GetRelationshipFingerprint(), nil
+	return m.GetConnectionFingerprint(), nil
 }
diff --git a/api/client.go b/api/client.go
index 85894ca42f590f64843d820d50339a6d22d3ec32..458d4ed47196febd1f846ca8eaed29611c07f17f 100644
--- a/api/client.go
+++ b/api/client.go
@@ -9,20 +9,23 @@ package api
 
 import (
 	"encoding/json"
+	"math"
+	"time"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth"
-	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/backup"
 	"gitlab.com/elixxir/client/cmix"
-	keyExchange2 "gitlab.com/elixxir/client/e2e/rekey"
+	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/client/event"
 	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/user"
 	"gitlab.com/elixxir/client/registration"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage"
+	"gitlab.com/elixxir/client/storage/user"
 	"gitlab.com/elixxir/comms/client"
-	"gitlab.com/elixxir/crypto/backup"
+	cryptoBackup "gitlab.com/elixxir/crypto/backup"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/primitives/version"
@@ -33,8 +36,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
 	"gitlab.com/xx_network/primitives/region"
-	"math"
-	"time"
 )
 
 const followerStoppableName = "client"
@@ -44,20 +45,23 @@ type Client struct {
 	rng *fastRNG.StreamGenerator
 	// the storage session securely stores data to disk and memoizes as is
 	// appropriate
-	storage *storage.Session
+	storage storage.Session
+
+	// user state object
+	userState *user.User
+
 	//object used for communications
 	comms *client.Comms
-	// Network parameters
-	parameters cmix.Params
+	// Network parameters, note e2e params wrap CMIXParams
+	parameters e2e.Params
 
-	// note that the manager has a pointer to the context in many cases, but
-	// this interface allows it to be mocked for easy testing without the
-	// loop
-	network interfaces.NetworkManager
+	network cmix.Client
 	//object used to register and communicate with permissioning
 	permissioning *registration.Registration
 	//object containing auth interactions
-	auth *auth.State
+	auth auth.State
+
+	e2e e2e.Handler
 
 	//services system to track running threads
 	followerServices *services
@@ -68,7 +72,7 @@ type Client struct {
 	events *event.Manager
 
 	// Handles the triggering and delivery of backups
-	backup *interfaces.BackupContainer
+	backup *backup.Backup
 }
 
 // NewClient creates client storage, generates keys, connects, and registers
@@ -78,10 +82,9 @@ type Client struct {
 func NewClient(ndfJSON, storageDir string, password []byte,
 	registrationCode string) error {
 	jww.INFO.Printf("NewClient(dir: %s)", storageDir)
-	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
-	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG)
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024,
+		csprng.NewSystemRNG)
 
-	// Parse the NDF
 	def, err := parseNDF(ndfJSON)
 	if err != nil {
 		return err
@@ -90,10 +93,12 @@ func NewClient(ndfJSON, storageDir string, password []byte,
 	cmixGrp, e2eGrp := decodeGroups(def)
 	start := time.Now()
 	protoUser := createNewUser(rngStreamGen, cmixGrp, e2eGrp)
-	jww.DEBUG.Printf("PortableUserInfo generation took: %s", time.Now().Sub(start))
+	jww.DEBUG.Printf("PortableUserInfo generation took: %s",
+		time.Now().Sub(start))
 
-	_, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
-		cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
+	_, err = checkVersionAndSetupStorage(def, storageDir, password,
+		protoUser, cmixGrp, e2eGrp, rngStreamGen, false,
+		registrationCode)
 	if err != nil {
 		return err
 	}
@@ -102,29 +107,29 @@ func NewClient(ndfJSON, storageDir string, password []byte,
 	return nil
 }
 
-// NewPrecannedClient creates an insecure user with predetermined keys with nodes
-// It creates client storage, generates keys, connects, and registers
-// with the network. Note that this does not register a username/identity, but
-// merely creates a new cryptographic identity for adding such information
-// at a later date.
+// NewPrecannedClient creates an insecure user with predetermined keys
+// with nodes It creates client storage, generates keys, connects, and
+// registers with the network. Note that this does not register a
+// username/identity, but merely creates a new cryptographic identity
+// for adding such information at a later date.
 func NewPrecannedClient(precannedID uint, defJSON, storageDir string,
 	password []byte) error {
 	jww.INFO.Printf("NewPrecannedClient()")
-	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
-	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG)
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024,
+		csprng.NewSystemRNG)
 	rngStream := rngStreamGen.GetStream()
 
-	// Parse the NDF
 	def, err := parseNDF(defJSON)
 	if err != nil {
 		return err
 	}
 	cmixGrp, e2eGrp := decodeGroups(def)
 
-	protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp)
+	protoUser := createPrecannedUser(precannedID, rngStream,
+		cmixGrp, e2eGrp)
 
-	_, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
-		cmixGrp, e2eGrp, rngStreamGen, true, "")
+	_, err = checkVersionAndSetupStorage(def, storageDir, password,
+		protoUser, cmixGrp, e2eGrp, rngStreamGen, true, "")
 	if err != nil {
 		return err
 	}
@@ -132,29 +137,31 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string,
 	return nil
 }
 
-// NewVanityClient creates a user with a receptionID that starts with the supplied prefix
-// It creates client storage, generates keys, connects, and registers
-// with the network. Note that this does not register a username/identity, but
-// merely creates a new cryptographic identity for adding such information
-// at a later date.
+// NewVanityClient creates a user with a receptionID that starts with
+// the supplied prefix It creates client storage, generates keys,
+// connects, and registers with the network. Note that this does not
+// register a username/identity, but merely creates a new
+// cryptographic identity for adding such information at a later date.
 func NewVanityClient(ndfJSON, storageDir string, password []byte,
 	registrationCode string, userIdPrefix string) error {
 	jww.INFO.Printf("NewVanityClient()")
-	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
-	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG)
+
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024,
+		csprng.NewSystemRNG)
 	rngStream := rngStreamGen.GetStream()
 
-	// Parse the NDF
 	def, err := parseNDF(ndfJSON)
 	if err != nil {
 		return err
 	}
 	cmixGrp, e2eGrp := decodeGroups(def)
 
-	protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, userIdPrefix)
+	protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp,
+		userIdPrefix)
 
-	_, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
-		cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
+	_, err = checkVersionAndSetupStorage(def, storageDir, password,
+		protoUser, cmixGrp, e2eGrp, rngStreamGen, false,
+		registrationCode)
 	if err != nil {
 		return err
 	}
@@ -163,22 +170,24 @@ func NewVanityClient(ndfJSON, storageDir string, password []byte,
 	return nil
 }
 
-// NewClientFromBackup constructs a new Client from an encrypted backup. The backup
-// is decrypted using the backupPassphrase. On success a successful client creation,
-// the function will return a JSON encoded list of the E2E partners
-// contained in the backup and a json-encoded string containing parameters stored in the backup
+// NewClientFromBackup constructs a new Client from an encrypted
+// backup. The backup is decrypted using the backupPassphrase. On
+// success a successful client creation, the function will return a
+// JSON encoded list of the E2E partners contained in the backup and a
+// json-encoded string containing parameters stored in the backup
 func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword,
-	backupPassphrase []byte, backupFileContents []byte) ([]*id.ID, string, error) {
+	backupPassphrase []byte, backupFileContents []byte) ([]*id.ID,
+	string, error) {
 
-	backUp := &backup.Backup{}
+	backUp := &cryptoBackup.Backup{}
 	err := backUp.Decrypt(string(backupPassphrase), backupFileContents)
 	if err != nil {
-		return nil, "", errors.WithMessage(err, "Failed to unmarshal decrypted client contents.")
+		return nil, "", errors.WithMessage(err,
+			"Failed to unmarshal decrypted client contents.")
 	}
 
 	usr := user.NewUserFromBackup(backUp)
 
-	// Parse the NDF
 	def, err := parseNDF(ndfJSON)
 	if err != nil {
 		return nil, "", err
@@ -186,21 +195,23 @@ func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword,
 
 	cmixGrp, e2eGrp := decodeGroups(def)
 
-	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
 
-	// Create storage object.
-	// Note we do not need registration
-	storageSess, err := checkVersionAndSetupStorage(def, storageDir, []byte(sessionPassword), usr,
-		cmixGrp, e2eGrp, rngStreamGen, false, backUp.RegistrationCode)
+	// Note we do not need registration here
+	storageSess, err := checkVersionAndSetupStorage(def, storageDir,
+		[]byte(sessionPassword), usr, cmixGrp, e2eGrp, rngStreamGen,
+		false, backUp.RegistrationCode)
 
-	// Set registration values in storage
-	storageSess.User().SetReceptionRegistrationValidationSignature(backUp.ReceptionIdentity.RegistrarSignature)
-	storageSess.User().SetTransmissionRegistrationValidationSignature(backUp.TransmissionIdentity.RegistrarSignature)
-	storageSess.User().SetRegistrationTimestamp(backUp.RegistrationTimestamp)
+	storageSess.SetReceptionRegistrationValidationSignature(
+		backUp.ReceptionIdentity.RegistrarSignature)
+	storageSess.SetTransmissionRegistrationValidationSignature(
+		backUp.TransmissionIdentity.RegistrarSignature)
+	storageSess.SetRegistrationTimestamp(backUp.RegistrationTimestamp)
 
-	//move the registration state to indicate registered with registration on proto client
-	err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete)
+	//move the registration state to indicate registered with
+	// registration on proto client
+	err = storageSess.ForwardRegistrationStatus(
+		storage.PermissioningComplete)
 	if err != nil {
 		return nil, "", err
 	}
@@ -209,37 +220,36 @@ func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword,
 }
 
 // OpenClient session, but don't connect to the network or log in
-func OpenClient(storageDir string, password []byte, parameters params.Network) (*Client, error) {
+func OpenClient(storageDir string, password []byte,
+	parameters e2e.Params) (*Client, error) {
 	jww.INFO.Printf("OpenClient()")
-	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
-	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG)
 
-	// get current client version
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024,
+		csprng.NewSystemRNG)
+
 	currentVersion, err := version.ParseVersion(SEMVER)
 	if err != nil {
-		return nil, errors.WithMessage(err, "Could not parse version string.")
+		return nil, errors.WithMessage(err,
+			"Could not parse version string.")
 	}
 
-	// Load Storage
 	passwordStr := string(password)
-	storageSess, err := storage.Load(storageDir, passwordStr, currentVersion,
-		rngStreamGen)
+	storageSess, err := storage.Load(storageDir, passwordStr,
+		currentVersion)
 	if err != nil {
 		return nil, err
 	}
 
-	// Set up a new context
 	c := &Client{
 		storage:            storageSess,
-		switchboard:        switchboard.New(),
 		rng:                rngStreamGen,
 		comms:              nil,
 		network:            nil,
 		followerServices:   newServices(),
 		parameters:         parameters,
 		clientErrorChannel: make(chan interfaces.ClientError, 1000),
-		events:             event.newEventManager(),
-		backup:             &interfaces.BackupContainer{},
+		events:             event.NewEventManager(),
+		backup:             &backup.Backup{},
 	}
 
 	return c, nil
@@ -252,10 +262,8 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password,
 	protoClientJSON []byte) error {
 	jww.INFO.Printf("NewProtoClient_Unsafe")
 
-	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
 
-	// Parse the NDF
 	def, err := parseNDF(ndfJSON)
 	if err != nil {
 		return err
@@ -263,30 +271,31 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password,
 
 	cmixGrp, e2eGrp := decodeGroups(def)
 
-	// Pull the proto user from the JSON
 	protoUser := &user.Proto{}
 	err = json.Unmarshal(protoClientJSON, protoUser)
 	if err != nil {
 		return err
 	}
 
-	// Initialize a user object for storage set up
 	usr := user.NewUserFromProto(protoUser)
 
-	// Set up storage
-	storageSess, err := checkVersionAndSetupStorage(def, storageDir, password, usr,
-		cmixGrp, e2eGrp, rngStreamGen, false, protoUser.RegCode)
+	storageSess, err := checkVersionAndSetupStorage(def, storageDir,
+		password, usr, cmixGrp, e2eGrp, rngStreamGen, false,
+		protoUser.RegCode)
 	if err != nil {
 		return err
 	}
 
-	// Set registration values in storage
-	storageSess.User().SetReceptionRegistrationValidationSignature(protoUser.ReceptionRegValidationSig)
-	storageSess.User().SetTransmissionRegistrationValidationSignature(protoUser.TransmissionRegValidationSig)
-	storageSess.User().SetRegistrationTimestamp(protoUser.RegistrationTimestamp)
+	storageSess.SetReceptionRegistrationValidationSignature(
+		protoUser.ReceptionRegValidationSig)
+	storageSess.SetTransmissionRegistrationValidationSignature(
+		protoUser.TransmissionRegValidationSig)
+	storageSess.SetRegistrationTimestamp(protoUser.RegistrationTimestamp)
 
-	//move the registration state to indicate registered with registration on proto client
-	err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete)
+	// move the registration state to indicate registered with
+	// registration on proto client
+	err = storageSess.ForwardRegistrationStatus(
+		storage.PermissioningComplete)
 	if err != nil {
 		return err
 	}
@@ -295,26 +304,24 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password,
 }
 
 // Login initializes a client object from existing storage.
-func Login(storageDir string, password []byte, parameters params.Network) (*Client, error) {
+func Login(storageDir string, password []byte,
+	authCallbacks auth.Callbacks, parameters e2e.Params) (*Client, error) {
 	jww.INFO.Printf("Login()")
 
-	//Open the client
 	c, err := OpenClient(storageDir, password, parameters)
 	if err != nil {
 		return nil, err
 	}
 
-	u := c.storage.GetUser()
+	u := c.GetUser()
 	jww.INFO.Printf("Client Logged in: \n\tTransmisstionID: %s "+
 		"\n\tReceptionID: %s", u.TransmissionID, u.ReceptionID)
 
-	// initialize comms
 	err = c.initComms()
 	if err != nil {
 		return nil, err
 	}
 
-	//get the NDF to pass into registration and the network manager
 	def := c.storage.GetNDF()
 
 	//initialize registration
@@ -324,9 +331,9 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie
 			return nil, err
 		}
 	} else {
-		jww.WARN.Printf("Registration with permissioning skipped due to " +
-			"blank permissioning address. Client will not be able to register " +
-			"or track network.")
+		jww.WARN.Printf("Registration with permissioning skipped due " +
+			"to blank permissioning address. Client will not be " +
+			"able to register or track network.")
 	}
 
 	if def.Notification.Address != "" {
@@ -335,25 +342,38 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie
 		hp.KaClientOpts.Time = time.Duration(math.MaxInt64)
 		hp.AuthEnabled = false
 		hp.MaxRetries = 5
-		_, err = c.comms.AddHost(&id.NotificationBot, def.Notification.Address,
+		_, err = c.comms.AddHost(&id.NotificationBot,
+			def.Notification.Address,
 			[]byte(def.Notification.TlsCertificate), hp)
 		if err != nil {
-			jww.WARN.Printf("Failed adding host for notifications: %+v", err)
+			jww.WARN.Printf("Failed adding host for "+
+				"notifications: %+v", err)
 		}
 	}
 
-	// Initialize network and link it to context
-	c.network, err = cmix.NewClient(c.storage, c.switchboard, c.rng,
-		c.events, c.comms, parameters, def)
+	c.network, err = cmix.NewClient(parameters.Network, c.comms, c.storage,
+		c.storage.GetNDF(), c.rng, c.events)
+	if err != nil {
+		return nil, err
+	}
+
+	c.e2e, err = e2e.Load(c.storage.GetKV(), c.network,
+		c.GetUser().ReceptionID, c.storage.GetE2EGroup(),
+		c.rng, c.events)
 	if err != nil {
 		return nil, err
 	}
 
-	// initialize the auth tracker
-	c.auth = auth.NewManager(c.switchboard, c.storage, c.network, c.rng,
-		c.backup.TriggerBackup, parameters.ReplayRequests)
+	// FIXME: The callbacks need to be set, so I suppose we would need to
+	//        either set them via a special type or add them
+	//        to the login call?
+	authParams := auth.GetDefaultParams()
+	c.auth, err = auth.NewState(c.storage.GetKV(), c.network, c.e2e, c.rng,
+		c.events, authParams, authCallbacks, c.backup.TriggerBackup)
+	if err != nil {
+		return nil, err
+	}
 
-	// Add all processes to the followerServices
 	err = c.registerFollower()
 	if err != nil {
 		return nil, err
@@ -366,22 +386,20 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie
 // while replacing the base NDF.  This is designed for some specific deployment
 // procedures and is generally unsafe.
 func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
-	newBaseNdf string, parameters params.Network) (*Client, error) {
+	newBaseNdf string, authCallbacks auth.Callbacks,
+	parameters e2e.Params) (*Client, error) {
 	jww.INFO.Printf("LoginWithNewBaseNDF_UNSAFE()")
 
-	// Parse the NDF
 	def, err := parseNDF(newBaseNdf)
 	if err != nil {
 		return nil, err
 	}
 
-	//Open the client
 	c, err := OpenClient(storageDir, password, parameters)
 	if err != nil {
 		return nil, err
 	}
 
-	//initialize comms
 	err = c.initComms()
 	if err != nil {
 		return nil, err
@@ -390,28 +408,39 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
 	//store the updated base NDF
 	c.storage.SetNDF(def)
 
-	//initialize registration
 	if def.Registration.Address != "" {
 		err = c.initPermissioning(def)
 		if err != nil {
 			return nil, err
 		}
 	} else {
-		jww.WARN.Printf("Registration with permissioning skipped due to " +
-			"blank permissionign address. Client will not be able to register " +
-			"or track network.")
+		jww.WARN.Printf("Registration with permissioning skipped due " +
+			"to blank permissionign address. Client will not be " +
+			"able to register or track network.")
 	}
 
-	// Initialize network and link it to context
-	c.network, err = cmix.NewClient(c.storage, c.switchboard, c.rng,
-		c.events, c.comms, parameters, def)
+	c.network, err = cmix.NewClient(parameters.Network, c.comms, c.storage,
+		c.storage.GetNDF(), c.rng, c.events)
 	if err != nil {
 		return nil, err
 	}
 
-	// initialize the auth tracker
-	c.auth = auth.NewManager(c.switchboard, c.storage, c.network, c.rng,
-		c.backup.TriggerBackup, parameters.ReplayRequests)
+	c.e2e, err = e2e.Load(c.storage.GetKV(), c.network,
+		c.GetUser().ReceptionID, c.storage.GetE2EGroup(),
+		c.rng, c.events)
+	if err != nil {
+		return nil, err
+	}
+
+	// FIXME: The callbacks need to be set, so I suppose we would need to
+	//        either set them via a special type or add them
+	//        to the login call?
+	authParams := auth.GetDefaultParams()
+	c.auth, err = auth.NewState(c.storage.GetKV(), c.network, c.e2e, c.rng,
+		c.events, authParams, authCallbacks, c.backup.TriggerBackup)
+	if err != nil {
+		return nil, err
+	}
 
 	err = c.registerFollower()
 	if err != nil {
@@ -421,38 +450,35 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
 	return c, nil
 }
 
-// LoginWithProtoClient creates a client object with a protoclient JSON containing the
-// cryptographic primitives. This is designed for some specific deployment
-//// procedures and is generally unsafe.
-func LoginWithProtoClient(storageDir string, password []byte, protoClientJSON []byte,
-	newBaseNdf string, parameters params.Network) (*Client, error) {
+// LoginWithProtoClient creates a client object with a protoclient
+// JSON containing the cryptographic primitives. This is designed for
+// some specific deployment procedures and is generally unsafe.
+func LoginWithProtoClient(storageDir string, password []byte,
+	protoClientJSON []byte, newBaseNdf string, authCallbacks auth.Callbacks,
+	parameters e2e.Params) (*Client, error) {
 	jww.INFO.Printf("LoginWithProtoClient()")
 
-	// Parse the NDF
 	def, err := parseNDF(newBaseNdf)
 	if err != nil {
 		return nil, err
 	}
 
-	//Open the client
-	err = NewProtoClient_Unsafe(newBaseNdf, storageDir, password, protoClientJSON)
+	err = NewProtoClient_Unsafe(newBaseNdf, storageDir, password,
+		protoClientJSON)
 	if err != nil {
 		return nil, err
 	}
 
-	//Open the client
 	c, err := OpenClient(storageDir, password, parameters)
 	if err != nil {
 		return nil, err
 	}
 
-	//initialize comms
 	err = c.initComms()
 	if err != nil {
 		return nil, err
 	}
 
-	//store the updated base NDF
 	c.storage.SetNDF(def)
 
 	err = c.initPermissioning(def)
@@ -460,17 +486,28 @@ func LoginWithProtoClient(storageDir string, password []byte, protoClientJSON []
 		return nil, err
 	}
 
-	// Initialize network and link it to context
-	c.network, err = cmix.NewClient(c.storage, c.switchboard, c.rng,
-		c.events, c.comms, parameters, def)
+	c.network, err = cmix.NewClient(parameters.Network, c.comms, c.storage,
+		c.storage.GetNDF(), c.rng, c.events)
 	if err != nil {
 		return nil, err
 	}
 
-	// initialize the auth tracker
-	c.auth = auth.NewManager(c.switchboard, c.storage, c.network, c.rng,
-		c.backup.TriggerBackup, parameters.ReplayRequests)
+	c.e2e, err = e2e.Load(c.storage.GetKV(), c.network,
+		c.GetUser().ReceptionID, c.storage.GetE2EGroup(),
+		c.rng, c.events)
+	if err != nil {
+		return nil, err
+	}
 
+	// FIXME: The callbacks need to be set, so I suppose we would need to
+	//        either set them via a special type or add them
+	//        to the login call?
+	authParams := auth.GetDefaultParams()
+	c.auth, err = auth.NewState(c.storage.GetKV(), c.network, c.e2e, c.rng,
+		c.events, authParams, authCallbacks, c.backup.TriggerBackup)
+	if err != nil {
+		return nil, err
+	}
 	err = c.registerFollower()
 	if err != nil {
 		return nil, err
@@ -483,14 +520,16 @@ func (c *Client) initComms() error {
 	var err error
 
 	//get the user from session
-	u := c.storage.User()
-	cryptoUser := u.GetCryptographicIdentity()
+	u := c.userState
+	cryptoUser := u.CryptographicIdentity
+
+	privKey := cryptoUser.GetTransmissionRSA()
+	pubPEM := rsa.CreatePublicKeyPem(privKey.GetPublic())
+	privPEM := rsa.CreatePrivateKeyPem(privKey)
 
 	//start comms
 	c.comms, err = client.NewClientComms(cryptoUser.GetTransmissionID(),
-		rsa.CreatePublicKeyPem(cryptoUser.GetTransmissionRSA().GetPublic()),
-		rsa.CreatePrivateKeyPem(cryptoUser.GetTransmissionRSA()),
-		cryptoUser.GetTransmissionSalt())
+		pubPEM, privPEM, cryptoUser.GetTransmissionSalt())
 	if err != nil {
 		return errors.WithMessage(err, "failed to load client")
 	}
@@ -508,18 +547,22 @@ func (c *Client) initPermissioning(def *ndf.NetworkDefinition) error {
 
 	//register with registration if necessary
 	if c.storage.GetRegistrationStatus() == storage.KeyGenComplete {
-		jww.INFO.Printf("Client has not registered yet, attempting registration")
+		jww.INFO.Printf("Client has not registered yet, " +
+			"attempting registration")
 		err = c.registerWithPermissioning()
 		if err != nil {
-			jww.ERROR.Printf("Client has failed registration: %s", err)
+			jww.ERROR.Printf("Client has failed registration: %s",
+				err)
 			return errors.WithMessage(err, "failed to load client")
 		}
-		jww.INFO.Printf("Client successfully registered with the network")
+		jww.INFO.Printf("Client successfully registered " +
+			"with the network")
 	}
 	return nil
 }
 
-// registerFollower adds the follower processes to the client's follower service list.
+// registerFollower adds the follower processes to the client's
+// follower service list.
 // This should only ever be called once
 func (c *Client) registerFollower() error {
 	//build the error callback
@@ -531,11 +574,12 @@ func (c *Client) registerFollower() error {
 			Trace:   trace,
 		}:
 		default:
-			jww.WARN.Printf("Failed to notify about ClientError from %s: %s", source, message)
+			jww.WARN.Printf("Failed to notify about ClientError "+
+				"from %s: %s", source, message)
 		}
 	}
 
-	err := c.followerServices.add(c.events.eventService)
+	err := c.followerServices.add(c.events.EventService)
 	if err != nil {
 		return errors.WithMessage(err, "Couldn't start event reporting")
 	}
@@ -549,26 +593,14 @@ func (c *Client) registerFollower() error {
 			"the network")
 	}
 
-	//register the incremental key upgrade service
-	err = c.followerServices.add(c.auth.StartProcesses)
-	if err != nil {
-		return errors.WithMessage(err, "Failed to start following "+
-			"the network")
-	}
-
-	//register the key exchange service
-	keyXchange := func() (stoppable.Stoppable, error) {
-		return keyExchange2.Start(c.switchboard, c.storage, c.network, c.parameters.Rekey)
-	}
-	err = c.followerServices.add(keyXchange)
-
 	return nil
 }
 
 // ----- Client Functions -----
 
 // GetErrorsChannel returns a channel which passess errors from the
-// long running threads controlled by StartNetworkFollower and StopNetworkFollower
+// long running threads controlled by StartNetworkFollower and
+// StopNetworkFollower
 func (c *Client) GetErrorsChannel() <-chan interfaces.ClientError {
 	return c.clientErrorChannel
 }
@@ -584,16 +616,20 @@ func (c *Client) GetErrorsChannel() <-chan interfaces.ClientError {
 //   - Network Follower (/network/follow.go)
 //   	tracks the network events and hands them off to workers for handling
 //   - Historical Round Retrieval (/network/rounds/historical.go)
-//		Retrieves data about rounds which are too old to be stored by the client
+// 		Retrieves data about rounds which are too old to be
+// 		stored by the client
 //	 - Message Retrieval Worker Group (/network/rounds/retrieve.go)
-//		Requests all messages in a given round from the gateway of the last nodes
+//		Requests all messages in a given round from the
+//		gateway of the last nodes
 //	 - Message Handling Worker Group (/network/message/handle.go)
-//		Decrypts and partitions messages when signals via the Switchboard
+//		Decrypts and partitions messages when signals via the
+//		Switchboard
 //	 - health Tracker (/network/health)
 //		Via the network instance tracks the state of the network
 //	 - Garbled Messages (/network/message/garbled.go)
-//		Can be signaled to check all recent messages which could be be decoded
-//		Uses a message store on disk for persistence
+//		Can be signaled to check all recent messages which
+//		could be be decoded Uses a message store on disk for
+//		persistence
 //	 - Critical Messages (/network/message/critical.go)
 //		Ensures all protocol layer mandatory messages are sent
 //		Uses a message store on disk for persistence
@@ -640,20 +676,15 @@ func (c *Client) HasRunningProcessies() bool {
 // Returns the health tracker for registration and polling
 func (c *Client) GetHealth() interfaces.HealthTracker {
 	jww.INFO.Printf("GetHealth()")
-	return c.network.GetHealthTracker()
-}
-
-// Returns the switchboard for Registration
-func (c *Client) GetSwitchboard() interfaces.Switchboard {
-	jww.INFO.Printf("GetSwitchboard()")
-	return c.switchboard
+	return c.GetHealth()
 }
 
 // RegisterRoundEventsCb registers a callback for round
 // events.
 func (c *Client) GetRoundEvents() interfaces.RoundEvents {
 	jww.INFO.Printf("GetRoundEvents()")
-	jww.WARN.Printf("GetRoundEvents does not handle Client Errors edge case!")
+	jww.WARN.Printf("GetRoundEvents does not handle Client Errors " +
+		"edge case!")
 	return c.network.GetInstance().GetRoundEvents()
 }
 
@@ -667,7 +698,7 @@ func (c *Client) AddService(sp Service) error {
 // can be serialized into a byte stream for out-of-band sharing.
 func (c *Client) GetUser() user.Info {
 	jww.INFO.Printf("GetUser()")
-	return c.storage.GetUser()
+	return c.GetUser()
 }
 
 // GetComms returns the client comms object
@@ -681,28 +712,21 @@ func (c *Client) GetRng() *fastRNG.StreamGenerator {
 }
 
 // GetStorage returns the client storage object
-func (c *Client) GetStorage() *storage.Session {
+func (c *Client) GetStorage() storage.Session {
 	return c.storage
 }
 
 // GetNetworkInterface returns the client Network Interface
-func (c *Client) GetNetworkInterface() interfaces.NetworkManager {
+func (c *Client) GetNetworkInterface() cmix.Client {
 	return c.network
 }
 
 // GetBackup returns a pointer to the backup container so that the backup can be
 // set and triggered.
-func (c *Client) GetBackup() *interfaces.BackupContainer {
+func (c *Client) GetBackup() *backup.Backup {
 	return c.backup
 }
 
-// GetRateLimitParams retrieves the rate limiting parameters.
-func (c *Client) GetRateLimitParams() (uint32, uint32, int64) {
-	rateLimitParams := c.storage.GetBucketParams().Get()
-	return rateLimitParams.Capacity, rateLimitParams.LeakedTokens,
-		rateLimitParams.LeakDuration.Nanoseconds()
-}
-
 // GetNodeRegistrationStatus gets the current state of nodes registration. It
 // returns the total number of nodes in the NDF and the number of those which
 // are currently registers with. An error is returned if the network is not
@@ -710,27 +734,25 @@ func (c *Client) GetRateLimitParams() (uint32, uint32, int64) {
 func (c *Client) GetNodeRegistrationStatus() (int, int, error) {
 	// Return an error if the network is not healthy
 	if !c.GetHealth().IsHealthy() {
-		return 0, 0, errors.New("Cannot get number of nodes registrations when " +
-			"network is not healthy")
+		return 0, 0, errors.New("Cannot get number of nodes " +
+			"registrations when network is not healthy")
 	}
 
-	nodes := c.GetNetworkInterface().GetInstance().GetPartialNdf().Get().Nodes
-
-	cmixStore := c.storage.Cmix()
+	nodes := c.network.GetInstance().GetFullNdf().Get().Nodes
 
 	var numRegistered int
 	var numStale = 0
 	for i, n := range nodes {
 		nid, err := id.Unmarshal(n.ID)
 		if err != nil {
-			return 0, 0, errors.Errorf("Failed to unmarshal nodes ID %v "+
-				"(#%d): %s", n.ID, i, err.Error())
+			return 0, 0, errors.Errorf("Failed to unmarshal nodes "+
+				"ID %v (#%d): %s", n.ID, i, err.Error())
 		}
 		if n.Status == ndf.Stale {
 			numStale += 1
 			continue
 		}
-		if cmixStore.Has(nid) {
+		if c.network.HasNode(nid) {
 			numRegistered++
 		}
 	}
@@ -744,124 +766,50 @@ func (c *Client) GetNodeRegistrationStatus() (int, int, error) {
 // partner ID an error will be returned.
 func (c *Client) DeleteRequest(partnerId *id.ID) error {
 	jww.DEBUG.Printf("Deleting request for partner ID: %s", partnerId)
-	return c.GetStorage().Auth().DeleteRequest(partnerId)
+	return c.auth.DeleteRequest(partnerId)
 }
 
 // DeleteAllRequests clears all requests from client's auth storage.
 func (c *Client) DeleteAllRequests() error {
 	jww.DEBUG.Printf("Deleting all requests")
-	return c.GetStorage().Auth().DeleteAllRequests()
+	return c.auth.DeleteAllRequests()
 }
 
 // DeleteSentRequests clears sent requests from client's auth storage.
 func (c *Client) DeleteSentRequests() error {
 	jww.DEBUG.Printf("Deleting all sent requests")
-	return c.GetStorage().Auth().DeleteSentRequests()
+	return c.auth.DeleteSentRequests()
 }
 
 // DeleteReceiveRequests clears receive requests from client's auth storage.
 func (c *Client) DeleteReceiveRequests() error {
 	jww.DEBUG.Printf("Deleting all received requests")
-	return c.GetStorage().Auth().DeleteReceiveRequests()
+	return c.auth.DeleteReceiveRequests()
 }
 
 // DeleteContact is a function which removes a partner from Client's storage
 func (c *Client) DeleteContact(partnerId *id.ID) error {
 	jww.DEBUG.Printf("Deleting contact with ID %s", partnerId)
-	// get the partner so that they can be removed from preimage store
-	partner, err := c.storage.E2e().GetPartner(partnerId)
+
+	_, err := c.e2e.GetPartner(partnerId)
 	if err != nil {
 		return errors.WithMessagef(err, "Could not delete %s because "+
 			"they could not be found", partnerId)
 	}
-	e2ePreimage := partner.GetE2EPreimage()
-	rekeyPreimage := partner.GetSilentPreimage()
-	fileTransferPreimage := partner.GetFileTransferPreimage()
-	groupRequestPreimage := partner.GetGroupRequestPreimage()
 
-	//delete the partner
-	if err = c.storage.E2e().DeletePartner(partnerId); err != nil {
+	if err = c.e2e.DeletePartner(partnerId); err != nil {
 		return err
 	}
 
-	// Trigger backup
 	c.backup.TriggerBackup("contact deleted")
 
-	//delete the preimages
-	if err = c.storage.GetEdge().Remove(edge.Preimage{
-		Data:   e2ePreimage,
-		Type:   catalog.E2e,
-		Source: partnerId[:],
-	}, c.storage.GetUser().ReceptionID); err != nil {
-		jww.WARN.Printf("Failed delete the preimage for e2e "+
-			"from %s on contact deletion: %+v", partnerId, err)
-	}
-
-	if err = c.storage.GetEdge().Remove(edge.Preimage{
-		Data:   rekeyPreimage,
-		Type:   catalog.Silent,
-		Source: partnerId[:],
-	}, c.storage.GetUser().ReceptionID); err != nil {
-		jww.WARN.Printf("Failed delete the preimage for rekey "+
-			"from %s on contact deletion: %+v", partnerId, err)
-	}
-
-	if err = c.storage.GetEdge().Remove(edge.Preimage{
-		Data:   fileTransferPreimage,
-		Type:   catalog.EndFT,
-		Source: partnerId[:],
-	}, c.storage.GetUser().ReceptionID); err != nil {
-		jww.WARN.Printf("Failed delete the preimage for file transfer "+
-			"from %s on contact deletion: %+v", partnerId, err)
-	}
-
-	if err = c.storage.GetEdge().Remove(edge.Preimage{
-		Data:   groupRequestPreimage,
-		Type:   catalog.GroupRq,
-		Source: partnerId[:],
-	}, c.storage.GetUser().ReceptionID); err != nil {
-		jww.WARN.Printf("Failed delete the preimage for group request "+
-			"from %s on contact deletion: %+v", partnerId, err)
-	}
-
-	//delete conversations
-	c.storage.Conversations().Delete(partnerId)
+	// FIXME: Do we need this?
+	// c.e2e.Conversations().Delete(partnerId)
 
 	// call delete requests to make sure nothing is lingering.
 	// this is for saftey to ensure the contact can be readded
 	// in the future
-	_ = c.storage.Auth().Delete(partnerId)
-
-	return nil
-}
-
-// SetProxiedBins updates the host pool filter that filters out gateways that
-// are not in one of the specified bins.
-func (c *Client) SetProxiedBins(binStrings []string) error {
-	// Convert each region string into a region.GeoBin and place in a map for
-	// easy lookup
-	bins := make(map[region.GeoBin]bool, len(binStrings))
-	for i, binStr := range binStrings {
-		bin, err := region.GetRegion(binStr)
-		if err != nil {
-			return errors.Errorf("failed to parse geographic bin #%d: %+v", i, err)
-		}
-
-		bins[bin] = true
-	}
-
-	// Create filter func
-	f := func(m map[id.ID]int, netDef *ndf.NetworkDefinition) map[id.ID]int {
-		prunedList := make(map[id.ID]int, len(m))
-		for gwID, i := range m {
-			if bins[netDef.Gateways[i].Bin] {
-				prunedList[gwID] = i
-			}
-		}
-		return prunedList
-	}
-
-	c.network.SetPoolFilter(f)
+	_ = c.auth.DeleteRequest(partnerId)
 
 	return nil
 }
@@ -872,8 +820,8 @@ func (c *Client) GetPreferredBins(countryCode string) ([]string, error) {
 	// get the bin that the country is in
 	bin, exists := region.GetCountryBin(countryCode)
 	if !exists {
-		return nil, errors.Errorf("failed to find geographic bin for country %q",
-			countryCode)
+		return nil, errors.Errorf("failed to find geographic bin "+
+			"for country %q", countryCode)
 	}
 
 	// Add bin to list of geographic bins
@@ -884,17 +832,24 @@ func (c *Client) GetPreferredBins(countryCode string) ([]string, error) {
 	case region.SouthAndCentralAmerica:
 		bins = append(bins, region.NorthAmerica.String())
 	case region.MiddleEast:
-		bins = append(bins, region.EasternEurope.String(), region.CentralEurope.String(), region.WesternAsia.String())
+		bins = append(bins, region.EasternEurope.String(),
+			region.CentralEurope.String(),
+			region.WesternAsia.String())
 	case region.NorthernAfrica:
-		bins = append(bins, region.WesternEurope.String(), region.CentralEurope.String())
+		bins = append(bins, region.WesternEurope.String(),
+			region.CentralEurope.String())
 	case region.SouthernAfrica:
-		bins = append(bins, region.WesternEurope.String(), region.CentralEurope.String())
+		bins = append(bins, region.WesternEurope.String(),
+			region.CentralEurope.String())
 	case region.EasternAsia:
-		bins = append(bins, region.WesternAsia.String(), region.Oceania.String(), region.NorthAmerica.String())
+		bins = append(bins, region.WesternAsia.String(),
+			region.Oceania.String(), region.NorthAmerica.String())
 	case region.WesternAsia:
-		bins = append(bins, region.EasternAsia.String(), region.Russia.String(), region.MiddleEast.String())
+		bins = append(bins, region.EasternAsia.String(),
+			region.Russia.String(), region.MiddleEast.String())
 	case region.Oceania:
-		bins = append(bins, region.EasternAsia.String(), region.NorthAmerica.String())
+		bins = append(bins, region.EasternAsia.String(),
+			region.NorthAmerica.String())
 	}
 
 	return bins, nil
@@ -932,23 +887,25 @@ func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) {
 	return cmixGrp, e2eGrp
 }
 
-// checkVersionAndSetupStorage is common code shared by NewClient, NewPrecannedClient and NewVanityClient
-// it checks client version and creates a new storage for user data
+// checkVersionAndSetupStorage is common code shared by NewClient,
+// NewPrecannedClient and NewVanityClient it checks client version and
+// creates a new storage for user data
 func checkVersionAndSetupStorage(def *ndf.NetworkDefinition,
 	storageDir string, password []byte,
 	protoUser user.Info,
 	cmixGrp, e2eGrp *cyclic.Group, rngStreamGen *fastRNG.StreamGenerator,
-	isPrecanned bool, registrationCode string) (*storage.Session, error) {
+	isPrecanned bool, registrationCode string) (storage.Session, error) {
 	// get current client version
 	currentVersion, err := version.ParseVersion(SEMVER)
 	if err != nil {
-		return nil, errors.WithMessage(err, "Could not parse version string.")
+		return nil, errors.WithMessage(err,
+			"Could not parse version string.")
 	}
 
 	// Create Storage
 	passwordStr := string(password)
 	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
-		currentVersion, cmixGrp, e2eGrp, rngStreamGen, def.RateLimits)
+		currentVersion, cmixGrp, e2eGrp)
 	if err != nil {
 		return nil, err
 	}
@@ -960,19 +917,15 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition,
 		//store the registration code for later use
 		storageSess.SetRegCode(registrationCode)
 		//move the registration state to keys generated
-		err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
+		err = storageSess.ForwardRegistrationStatus(
+			storage.KeyGenComplete)
 	} else {
-		//move the registration state to indicate registered with registration
-		err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete)
+		//move the registration state to indicate registered
+		// with registration
+		err = storageSess.ForwardRegistrationStatus(
+			storage.PermissioningComplete)
 	}
 
-	//add the request preiamge
-	storageSess.GetEdge().Add(edge.Preimage{
-		Data:   preimage.GenerateRequest(protoUser.ReceptionID),
-		Type:   catalog.Request,
-		Source: protoUser.ReceptionID[:],
-	}, protoUser.ReceptionID)
-
 	if err != nil {
 		return nil, errors.WithMessage(err, "Failed to denote state "+
 			"change in session")
diff --git a/api/notifications.go b/api/notifications.go
index 58e97190e469a7d21d9175b9b84ddaff89b75e2c..60355a48034572902905c876591004e039b2b0b0 100644
--- a/api/notifications.go
+++ b/api/notifications.go
@@ -34,20 +34,26 @@ func (c *Client) RegisterForNotifications(token string) error {
 	if err != nil {
 		return err
 	}
+
+	privKey := c.userState.CryptographicIdentity.GetTransmissionRSA()
+	pubPEM := rsa.CreatePublicKeyPem(privKey.GetPublic())
+	regSig := c.userState.GetTransmissionRegistrationValidationSignature()
+	regTS := c.GetUser().RegistrationTimestamp
+
 	// Send the register message
 	_, err = c.comms.RegisterForNotifications(notificationBotHost,
 		&mixmessages.NotificationRegisterRequest{
 			Token:                 token,
 			IntermediaryId:        intermediaryReceptionID,
-			TransmissionRsa:       rsa.CreatePublicKeyPem(c.GetStorage().User().GetCryptographicIdentity().GetTransmissionRSA().GetPublic()),
+			TransmissionRsa:       pubPEM,
 			TransmissionSalt:      c.GetUser().TransmissionSalt,
-			TransmissionRsaSig:    c.GetStorage().User().GetTransmissionRegistrationValidationSignature(),
+			TransmissionRsaSig:    regSig,
 			IIDTransmissionRsaSig: sig,
-			RegistrationTimestamp: c.GetUser().RegistrationTimestamp,
+			RegistrationTimestamp: regTS,
 		})
 	if err != nil {
-		err := errors.Errorf(
-			"RegisterForNotifications: Unable to register for notifications! %s", err)
+		err := errors.Errorf("RegisterForNotifications: Unable to "+
+			"register for notifications! %s", err)
 		return err
 	}
 
@@ -96,7 +102,9 @@ func (c *Client) getIidAndSig() ([]byte, []byte, error) {
 
 	stream := c.rng.GetStream()
 	c.GetUser()
-	sig, err := rsa.Sign(stream, c.storage.User().GetCryptographicIdentity().GetTransmissionRSA(), hash.CMixHash, h.Sum(nil), nil)
+	sig, err := rsa.Sign(stream,
+		c.userState.GetTransmissionRSA(),
+		hash.CMixHash, h.Sum(nil), nil)
 	if err != nil {
 		return nil, nil, errors.WithMessage(err, "RegisterForNotifications: Failed to sign intermediary ID")
 	}
diff --git a/api/permissioning.go b/api/permissioning.go
index 2dd62ec87dd8a95f43bce9f93df31db105edc4ca..b4060d994c84622f3395193c145a1e257559c815 100644
--- a/api/permissioning.go
+++ b/api/permissioning.go
@@ -9,17 +9,18 @@ package api
 
 import (
 	"encoding/json"
+
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces/user"
 	"gitlab.com/elixxir/client/storage"
+	"gitlab.com/elixxir/client/storage/user"
 )
 
 // Returns an error if registration fails.
 func (c *Client) registerWithPermissioning() error {
-	userData := c.storage.User()
+	userData := c.userState.CryptographicIdentity
 	//get the users public key
-	transmissionPubKey := userData.GetCryptographicIdentity().GetTransmissionRSA().GetPublic()
-	receptionPubKey := userData.GetCryptographicIdentity().GetReceptionRSA().GetPublic()
+	transmissionPubKey := userData.GetTransmissionRSA().GetPublic()
+	receptionPubKey := userData.GetReceptionRSA().GetPublic()
 
 	//load the registration code
 	regCode, err := c.storage.GetRegCode()
@@ -30,16 +31,19 @@ func (c *Client) registerWithPermissioning() error {
 
 	//register with registration
 	transmissionRegValidationSignature, receptionRegValidationSignature,
-		registrationTimestamp, err := c.permissioning.Register(transmissionPubKey, receptionPubKey, regCode)
+		registrationTimestamp, err := c.permissioning.Register(
+		transmissionPubKey, receptionPubKey, regCode)
 	if err != nil {
 		return errors.WithMessage(err, "failed to register with "+
 			"permissioning")
 	}
 
 	//store the signature
-	userData.SetTransmissionRegistrationValidationSignature(transmissionRegValidationSignature)
-	userData.SetReceptionRegistrationValidationSignature(receptionRegValidationSignature)
-	userData.SetRegistrationTimestamp(registrationTimestamp)
+	c.storage.SetTransmissionRegistrationValidationSignature(
+		transmissionRegValidationSignature)
+	c.storage.SetReceptionRegistrationValidationSignature(
+		receptionRegValidationSignature)
+	c.storage.SetRegistrationTimestamp(registrationTimestamp)
 
 	//update the registration state
 	err = c.storage.ForwardRegistrationStatus(storage.PermissioningComplete)
@@ -50,9 +54,9 @@ func (c *Client) registerWithPermissioning() error {
 	return nil
 }
 
-// ConstructProtoUerFile is a helper function which is used for proto client testing.
-// This is used for development testing.
-func (c *Client) ConstructProtoUerFile() ([]byte, error) {
+// ConstructProtoUserFile is a helper function which is used for proto
+// client testing.  This is used for development testing.
+func (c *Client) ConstructProtoUserFile() ([]byte, error) {
 
 	//load the registration code
 	regCode, err := c.storage.GetRegCode()
@@ -71,10 +75,10 @@ func (c *Client) ConstructProtoUerFile() ([]byte, error) {
 		Precanned:                    c.GetUser().Precanned,
 		RegistrationTimestamp:        c.GetUser().RegistrationTimestamp,
 		RegCode:                      regCode,
-		TransmissionRegValidationSig: c.storage.User().GetTransmissionRegistrationValidationSignature(),
-		ReceptionRegValidationSig:    c.storage.User().GetReceptionRegistrationValidationSignature(),
-		E2eDhPrivateKey:              c.GetStorage().E2e().GetDHPrivateKey(),
-		E2eDhPublicKey:               c.GetStorage().E2e().GetDHPublicKey(),
+		TransmissionRegValidationSig: c.storage.GetTransmissionRegistrationValidationSignature(),
+		ReceptionRegValidationSig:    c.storage.GetReceptionRegistrationValidationSignature(),
+		E2eDhPrivateKey:              c.e2e.GetHistoricalDHPrivkey(),
+		E2eDhPublicKey:               c.e2e.GetHistoricalDHPubkey(),
 	}
 
 	jsonBytes, err := json.Marshal(Usr)
diff --git a/api/send.go b/api/send.go
index 5af5704d82b3696693997a7c6911fd08955440dc..5959d81946ada40f94d56f40b06f0ead130ae3d5 100644
--- a/api/send.go
+++ b/api/send.go
@@ -8,15 +8,18 @@
 package api
 
 import (
+	"time"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/interfaces/params"
-	"gitlab.com/elixxir/crypto/e2e"
+	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/e2e"
+	e2eCrypto "gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"time"
 )
 
 //This holds all functions to send messages over the network
@@ -24,11 +27,12 @@ import (
 // SendE2E sends an end-to-end payload to the provided recipient with
 // the provided msgType. Returns the list of rounds in which parts of
 // the message were sent or an error if it fails.
-func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round,
-	e2e.MessageID, time.Time, error) {
-	jww.INFO.Printf("SendE2E(%s, %d. %v)", m.Recipient,
-		m.MessageType, m.Payload)
-	return c.network.SendE2E(m, param, nil)
+func (c *Client) SendE2E(mt catalog.MessageType, recipient *id.ID,
+	payload []byte, param e2e.Params) ([]id.Round,
+	e2eCrypto.MessageID, time.Time, error) {
+	jww.INFO.Printf("SendE2E(%s, %d. %v)", recipient,
+		mt, payload)
+	return c.e2e.SendE2E(mt, recipient, payload, param)
 }
 
 // SendUnsafe sends an unencrypted payload to the provided recipient
@@ -36,11 +40,12 @@ func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round,
 // of the message were sent or an error if it fails.
 // NOTE: Do not use this function unless you know what you are doing.
 // This function always produces an error message in client logging.
-func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round,
+func (c *Client) SendUnsafe(mt catalog.MessageType, recipient *id.ID,
+	payload []byte, param e2e.Params) ([]id.Round, time.Time,
 	error) {
-	jww.INFO.Printf("SendUnsafe(%s, %d. %v)", m.Recipient,
-		m.MessageType, m.Payload)
-	return c.network.SendUnsafe(m, param)
+	jww.INFO.Printf("SendUnsafe(%s, %d. %v)", recipient,
+		mt, payload)
+	return c.e2e.SendUnsafe(mt, recipient, payload, param)
 }
 
 // SendCMIX sends a "raw" CMIX message payload to the provided
@@ -48,24 +53,26 @@ func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round,
 // Returns the round ID of the round the payload was sent or an error
 // if it fails.
 func (c *Client) SendCMIX(msg format.Message, recipientID *id.ID,
-	param params.CMIX) (id.Round, ephemeral.Id, error) {
+	param cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
 	jww.INFO.Printf("Send(%s)", string(msg.GetContents()))
-	return c.network.SendCMIX(msg, recipientID, param)
+	return c.network.Send(recipientID, msg.GetKeyFP(),
+		message.GetDefaultService(recipientID),
+		msg.GetContents(), msg.GetMac(), param)
 }
 
 // SendManyCMIX sends many "raw" CMIX message payloads to each of the
 // provided recipients. Used for group chat functionality. Returns the
 // round ID of the round the payload was sent or an error if it fails.
-func (c *Client) SendManyCMIX(messages []message.TargetedCmixMessage,
-	params params.CMIX) (id.Round, []ephemeral.Id, error) {
-	return c.network.SendManyCMIX(messages, params)
+func (c *Client) SendManyCMIX(messages []cmix.TargetedCmixMessage,
+	params cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
+	return c.network.SendMany(messages, params)
 }
 
 // NewCMIXMessage Creates a new cMix message with the right properties
 // for the current cMix network.
 // FIXME: this is weird and shouldn't be necessary, but it is.
 func (c *Client) NewCMIXMessage(contents []byte) (format.Message, error) {
-	primeSize := len(c.storage.Cmix().GetGroup().GetPBytes())
+	primeSize := len(c.storage.GetCmixGroup().GetPBytes())
 	msg := format.NewMessage(primeSize)
 	if len(contents) > msg.ContentsSize() {
 		return format.Message{}, errors.New("Contents to long for cmix")
diff --git a/api/user.go b/api/user.go
index 5b64f0b0a2df63408cf0b6f3baa0c2a391132caf..7ed520a0ffd2d19b12c1af772713273f7fbd7210 100644
--- a/api/user.go
+++ b/api/user.go
@@ -9,19 +9,20 @@ package api
 
 import (
 	"encoding/binary"
+	"math/rand"
+	"regexp"
+	"runtime"
+	"strings"
+	"sync"
+
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/user"
+	"gitlab.com/elixxir/client/storage/user"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/crypto/xx"
 	"gitlab.com/xx_network/primitives/id"
-	"math/rand"
-	"regexp"
-	"runtime"
-	"strings"
-	"sync"
 )
 
 const (
@@ -30,7 +31,8 @@ const (
 )
 
 // createNewUser generates an identity for cMix
-func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.Info {
+func createNewUser(rng *fastRNG.StreamGenerator, cmix,
+	e2e *cyclic.Group) user.Info {
 	// CMIX Keygen
 	var transmissionRsaKey, receptionRsaKey *rsa.PrivateKey
 
@@ -65,12 +67,14 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.I
 
 	stream.Close()
 
-	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
+	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(),
+		transmissionSalt, id.User)
 	if err != nil {
 		jww.FATAL.Panicf(err.Error())
 	}
 
-	receptionID, err := xx.NewID(receptionRsaKey.GetPublic(), receptionSalt, id.User)
+	receptionID, err := xx.NewID(receptionRsaKey.GetPublic(),
+		receptionSalt, id.User)
 	if err != nil {
 		jww.FATAL.Panicf(err.Error())
 	}
@@ -98,13 +102,12 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
 	go func() {
 		defer wg.Done()
 		var err error
-		// DH Keygen
-		// FIXME: Why 256 bits? -- this is spec but not explained, it has
-		// to do with optimizing operations on one side and still preserves
-		// decent security -- cite this. Why valid for BOTH e2e and cmix?
-		stream := rng.GetStream()
-		e2eKeyBytes, err = csprng.GenerateInGroup(e2e.GetPBytes(), 256, stream)
-		stream.Close()
+		rngStream := rng.GetStream()
+		prime := e2e.GetPBytes()
+		keyLen := len(prime)
+		e2eKeyBytes, err = csprng.GenerateInGroup(prime, keyLen,
+			rngStream)
+		rngStream.Close()
 		if err != nil {
 			jww.FATAL.Panicf(err.Error())
 		}
@@ -115,7 +118,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
 		defer wg.Done()
 		var err error
 		stream := rng.GetStream()
-		transmissionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen)
+		transmissionRsaKey, err = rsa.GenerateKey(stream,
+			rsa.DefaultRSABitLen)
 		stream.Close()
 		if err != nil {
 			jww.FATAL.Panicf(err.Error())
@@ -126,7 +130,8 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
 		defer wg.Done()
 		var err error
 		stream := rng.GetStream()
-		receptionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen)
+		receptionRsaKey, err = rsa.GenerateKey(stream,
+			rsa.DefaultRSABitLen)
 		stream.Close()
 		if err != nil {
 			jww.FATAL.Panicf(err.Error())
@@ -140,13 +145,13 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
 
 // TODO: Add precanned user code structures here.
 // creates a precanned user
-func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.Group) user.Info {
+func createPrecannedUser(precannedID uint, rng csprng.Source, cmix,
+	e2e *cyclic.Group) user.Info {
 	// DH Keygen
-	// FIXME: Why 256 bits? -- this is spec but not explained, it has
-	// to do with optimizing operations on one side and still preserves
-	// decent security -- cite this. Why valid for BOTH e2e and cmix?
 	prng := rand.New(rand.NewSource(int64(precannedID)))
-	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, prng)
+	prime := e2e.GetPBytes()
+	keyLen := len(prime)
+	e2eKeyBytes, err := csprng.GenerateInGroup(prime, keyLen, prng)
 	if err != nil {
 		jww.FATAL.Panicf(err.Error())
 	}
@@ -178,12 +183,12 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.
 
 // createNewVanityUser generates an identity for cMix
 // The identity's ReceptionID is not random but starts with the supplied prefix
-func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix string) user.Info {
+func createNewVanityUser(rng csprng.Source, cmix,
+	e2e *cyclic.Group, prefix string) user.Info {
 	// DH Keygen
-	// FIXME: Why 256 bits? -- this is spec but not explained, it has
-	// to do with optimizing operations on one side and still preserves
-	// decent security -- cite this. Why valid for BOTH e2e and cmix?
-	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, rng)
+	prime := e2e.GetPBytes()
+	keyLen := len(prime)
+	e2eKeyBytes, err := csprng.GenerateInGroup(prime, keyLen, rng)
 	if err != nil {
 		jww.FATAL.Panicf(err.Error())
 	}
@@ -203,7 +208,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
 	if n != SaltSize {
 		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
 	}
-	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
+	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(),
+		transmissionSalt, id.User)
 	if err != nil {
 		jww.FATAL.Panicf(err.Error())
 	}
@@ -213,7 +219,9 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
 		jww.FATAL.Panicf(err.Error())
 	}
 
-	var mu sync.Mutex // just in case more than one go routine tries to access receptionSalt and receptionID
+	// just in case more than one go routine tries to access
+	// receptionSalt and receptionID
+	var mu sync.Mutex
 	done := make(chan struct{})
 	found := make(chan bool)
 	wg := &sync.WaitGroup{}
@@ -234,7 +242,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
 	if match == false {
 		jww.FATAL.Panicf("Prefix contains non-Base64 characters")
 	}
-	jww.INFO.Printf("Vanity userID generation started. Prefix: %s Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores)
+	jww.INFO.Printf("Vanity userID generation started. Prefix: %s "+
+		"Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores)
 	for w := 0; w < cores; w++ {
 		wg.Add(1)
 		go func() {
@@ -245,14 +254,20 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
 					defer wg.Done()
 					return
 				default:
-					n, err = csprng.NewSystemRNG().Read(rSalt)
+					n, err = csprng.NewSystemRNG().Read(
+						rSalt)
 					if err != nil {
 						jww.FATAL.Panicf(err.Error())
 					}
 					if n != SaltSize {
-						jww.FATAL.Panicf("receptionSalt size too small: %d", n)
+						jww.FATAL.Panicf(
+							"receptionSalt size "+
+								"too small: %d",
+							n)
 					}
-					rID, err := xx.NewID(receptionRsaKey.GetPublic(), rSalt, id.User)
+					rID, err := xx.NewID(
+						receptionRsaKey.GetPublic(),
+						rSalt, id.User)
 					if err != nil {
 						jww.FATAL.Panicf(err.Error())
 					}
@@ -273,7 +288,8 @@ func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix stri
 			}
 		}()
 	}
-	// wait for a solution then close the done channel to signal the workers to exit
+	// wait for a solution then close the done channel to signal
+	// the workers to exit
 	<-found
 	close(done)
 	wg.Wait()
diff --git a/api/utilsInterfaces_test.go b/api/utilsInterfaces_test.go
index 29b5f8eb9abbc2217c1713cc25764472087701fa..617bce08b96810b920fb6ceb9aaf9ef3990f8757 100644
--- a/api/utilsInterfaces_test.go
+++ b/api/utilsInterfaces_test.go
@@ -7,21 +7,21 @@
 package api
 
 import (
+	"time"
+
+	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/gateway"
-	"gitlab.com/elixxir/client/event"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/interfaces/params"
+	"gitlab.com/elixxir/client/cmix/identity"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/stoppable"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/comms/network"
-	cE2e "gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"time"
 )
 
 // Mock comm struct which returns no historical round data
@@ -82,46 +82,45 @@ func (ht *historicalRounds) GetHost(hostId *id.ID) (*connect.Host, bool) {
 // Contains a test implementation of the networkManager interface.
 type testNetworkManagerGeneric struct {
 	instance *network.Instance
-	sender   *gateway.Sender
+	sender   gateway.Sender
 }
 type dummyEventMgr struct{}
 
 func (d *dummyEventMgr) Report(p int, a, b, c string) {}
-func (t *testNetworkManagerGeneric) GetEventManager() event.Manager {
-	return &dummyEventMgr{}
+func (d *dummyEventMgr) EventService() (stoppable.Stoppable, error) {
+	return nil, nil
 }
 
 /* Below methods built for interface adherence */
-func (t *testNetworkManagerGeneric) GetHealthTracker() interfaces.HealthTracker {
-	return nil
-}
-func (t *testNetworkManagerGeneric) Follow(report interfaces.ClientErrorReport) (stoppable.Stoppable, error) {
+func (t *testNetworkManagerGeneric) Follow(report cmix.ClientErrorReport) (stoppable.Stoppable, error) {
 	return nil, nil
 }
-func (t *testNetworkManagerGeneric) CheckGarbledMessages() {
+func (t *testNetworkManagerGeneric) GetMaxMessageLength() int { return 0 }
+
+func (t *testNetworkManagerGeneric) CheckInProgressMessages() {
 	return
 }
 func (t *testNetworkManagerGeneric) GetVerboseRounds() string {
 	return ""
 }
-func (t *testNetworkManagerGeneric) SendE2E(message.Send, params.E2E, *stoppable.Single) (
-	[]id.Round, cE2e.MessageID, time.Time, error) {
-	rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)}
-	return rounds, cE2e.MessageID{}, time.Time{}, nil
-}
-func (t *testNetworkManagerGeneric) SendUnsafe(m message.Send, p params.Unsafe) ([]id.Round, error) {
-	return nil, nil
+func (t *testNetworkManagerGeneric) AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, mp message.Processor) error {
+	return nil
 }
-func (t *testNetworkManagerGeneric) SendCMIX(message format.Message, rid *id.ID, p params.CMIX) (id.Round, ephemeral.Id, error) {
+
+func (t *testNetworkManagerGeneric) Send(*id.ID, format.Fingerprint,
+	message.Service, []byte, []byte, cmix.CMIXParams) (id.Round,
+	ephemeral.Id, error) {
 	return id.Round(0), ephemeral.Id{}, nil
 }
-func (t *testNetworkManagerGeneric) SendManyCMIX(messages []message.TargetedCmixMessage, p params.CMIX) (id.Round, []ephemeral.Id, error) {
+func (t *testNetworkManagerGeneric) SendMany(messages []cmix.TargetedCmixMessage,
+	p cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
 	return 0, []ephemeral.Id{}, nil
 }
 func (t *testNetworkManagerGeneric) GetInstance() *network.Instance {
 	return t.instance
 }
-func (t *testNetworkManagerGeneric) RegisterWithPermissioning(string) ([]byte, error) {
+func (t *testNetworkManagerGeneric) RegisterWithPermissioning(string) (
+	[]byte, error) {
 	return nil, nil
 }
 func (t *testNetworkManagerGeneric) GetRemoteVersion() (string, error) {
@@ -135,7 +134,7 @@ func (t *testNetworkManagerGeneric) InProgressRegistrations() int {
 	return 0
 }
 
-func (t *testNetworkManagerGeneric) GetSender() *gateway.Sender {
+func (t *testNetworkManagerGeneric) GetSender() gateway.Sender {
 	return t.sender
 }
 
@@ -147,3 +146,66 @@ func (t *testNetworkManagerGeneric) RegisterAddressSizeNotification(string) (cha
 
 func (t *testNetworkManagerGeneric) UnregisterAddressSizeNotification(string) {}
 func (t *testNetworkManagerGeneric) SetPoolFilter(gateway.Filter)             {}
+func (t *testNetworkManagerGeneric) AddHealthCallback(f func(bool)) uint64 {
+	return 0
+}
+func (t *testNetworkManagerGeneric) AddIdentity(id *id.ID,
+	validUntil time.Time, persistent bool) {
+}
+func (t *testNetworkManagerGeneric) RemoveIdentity(id *id.ID) {}
+func (t *testNetworkManagerGeneric) AddService(clientID *id.ID,
+	newService message.Service, response message.Processor) {
+}
+func (t *testNetworkManagerGeneric) DeleteService(clientID *id.ID,
+	toDelete message.Service, processor message.Processor) {
+}
+func (t *testNetworkManagerGeneric) DeleteClientService(clientID *id.ID) {
+}
+func (t *testNetworkManagerGeneric) DeleteFingerprint(identity *id.ID,
+	fingerprint format.Fingerprint) {
+}
+func (t *testNetworkManagerGeneric) DeleteClientFingerprints(identity *id.ID) {
+}
+func (t *testNetworkManagerGeneric) GetAddressSpace() uint8 { return 0 }
+func (t *testNetworkManagerGeneric) GetHostParams() connect.HostParams {
+	return connect.GetDefaultHostParams()
+}
+func (t *testNetworkManagerGeneric) GetIdentity(get *id.ID) (
+	identity.TrackedID, error) {
+	return identity.TrackedID{}, nil
+}
+func (t *testNetworkManagerGeneric) GetRoundResults(timeout time.Duration,
+	roundCallback cmix.RoundEventCallback, roundList ...id.Round) error {
+	return nil
+}
+func (t *testNetworkManagerGeneric) HasNode(nid *id.ID) bool { return false }
+func (t *testNetworkManagerGeneric) IsHealthy() bool         { return true }
+func (t *testNetworkManagerGeneric) WasHealthy() bool        { return true }
+func (t *testNetworkManagerGeneric) LookupHistoricalRound(rid id.Round,
+	callback rounds.RoundResultCallback) error {
+	return nil
+}
+func (t *testNetworkManagerGeneric) NumRegisteredNodes() int { return 0 }
+func (t *testNetworkManagerGeneric) RegisterAddressSpaceNotification(
+	tag string) (chan uint8, error) {
+	return nil, nil
+}
+func (t *testNetworkManagerGeneric) RemoveHealthCallback(uint64) {}
+func (t *testNetworkManagerGeneric) SendToAny(
+	sendFunc func(host *connect.Host) (interface{}, error),
+	stop *stoppable.Single) (interface{}, error) {
+	return nil, nil
+}
+func (t *testNetworkManagerGeneric) SendToPreferred(targets []*id.ID,
+	sendFunc gateway.SendToPreferredFunc, stop *stoppable.Single,
+	timeout time.Duration) (interface{}, error) {
+	return nil, nil
+}
+func (t *testNetworkManagerGeneric) SetGatewayFilter(f gateway.Filter) {}
+func (t *testNetworkManagerGeneric) TrackServices(
+	tracker message.ServicesTracker) {
+}
+func (t *testNetworkManagerGeneric) TriggerNodeRegistration(nid *id.ID) {}
+func (t *testNetworkManagerGeneric) UnregisterAddressSpaceNotification(
+	tag string) {
+}
diff --git a/api/utils_test.go b/api/utils_test.go
index 2171ee98fb7645daef91c2fa2cb27c378c6e98a6..4496905d51eab7344b8d2fcde840a2cd3c862d11 100644
--- a/api/utils_test.go
+++ b/api/utils_test.go
@@ -9,12 +9,13 @@ package api
 
 import (
 	"bytes"
-	"gitlab.com/elixxir/client/cmix/gateway"
 	"testing"
 
+	"gitlab.com/elixxir/client/cmix/gateway"
+	"gitlab.com/elixxir/client/e2e"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/params"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/comms/network"
 	"gitlab.com/elixxir/comms/testkeys"
@@ -32,7 +33,8 @@ func newTestingClient(face interface{}) (*Client, error) {
 	case *testing.T, *testing.M, *testing.B, *testing.PB:
 		break
 	default:
-		jww.FATAL.Panicf("InitTestingSession is restricted to testing only. Got %T", face)
+		jww.FATAL.Panicf("InitTestingSession is restricted to testing "+
+			"only. Got %T", face)
 	}
 
 	def := getNDF(face)
@@ -41,12 +43,14 @@ func newTestingClient(face interface{}) (*Client, error) {
 	password := []byte("hunter2")
 	err := NewClient(string(marshalledDef), storageDir, password, "AAAA")
 	if err != nil {
-		return nil, errors.Errorf("Could not construct a mock client: %v", err)
+		return nil, errors.Errorf(
+			"Could not construct a mock client: %v", err)
 	}
 
-	c, err := OpenClient(storageDir, password, params.GetDefaultNetwork())
+	c, err := OpenClient(storageDir, password, e2e.GetDefaultParams())
 	if err != nil {
-		return nil, errors.Errorf("Could not open a mock client: %v", err)
+		return nil, errors.Errorf("Could not open a mock client: %v",
+			err)
 	}
 
 	commsManager := connect.NewManagerTesting(face)
@@ -56,19 +60,22 @@ func newTestingClient(face interface{}) (*Client, error) {
 		jww.FATAL.Panicf("Failed to create new test instance: %v", err)
 	}
 
-	commsManager.AddHost(&id.Permissioning, "", cert, connect.GetDefaultHostParams())
+	commsManager.AddHost(&id.Permissioning, "", cert,
+		connect.GetDefaultHostParams())
 	instanceComms := &connect.ProtoComms{
 		Manager: commsManager,
 	}
 
-	thisInstance, err := network.NewInstanceTesting(instanceComms, def, def, nil, nil, face)
+	thisInstance, err := network.NewInstanceTesting(instanceComms, def,
+		def, nil, nil, face)
 	if err != nil {
 		return nil, err
 	}
 
 	p := gateway.DefaultPoolParams()
 	p.MaxPoolSize = 1
-	sender, err := gateway.NewSender(p, c.rng, def, commsManager, c.storage, nil)
+	sender, err := gateway.NewSender(p, c.rng, def, commsManager,
+		c.storage, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/auth/confirm.go b/auth/confirm.go
index e523715c74a421773354216c9e335a5d9157b2fa..fc6c5b69c90fa6c5533fd26e570ad31c10e8e4a6 100644
--- a/auth/confirm.go
+++ b/auth/confirm.go
@@ -9,6 +9,7 @@ package auth
 
 import (
 	"fmt"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth/store"
@@ -126,7 +127,7 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) (
 			s.event.Report(10, "Auth", "SendConfirmError", em)
 		}
 
-		//todo: s.backupTrigger("confirmed authenticated channel")
+		s.backupTrigger("confirmed authenticated channel")
 
 		jww.INFO.Printf("Confirming Auth from %s to %s, msgDigest: %s",
 			partner.ID, s.e2e.GetReceptionID(),
@@ -152,7 +153,7 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) (
 }
 
 func sendAuthConfirm(net cmixClient, partner *id.ID,
-	fp format.Fingerprint, payload, mac []byte, event event.Manager,
+	fp format.Fingerprint, payload, mac []byte, event event.Reporter,
 	serviceTag string) (
 	id.Round, error) {
 	svc := message.Service{
diff --git a/auth/interface.go b/auth/interface.go
index f44e221acf77e303b0e19559d5a3410335fa7a56..b8ea8865c78f89ba7ffacce3476e46aeb3ff0f7f 100644
--- a/auth/interface.go
+++ b/auth/interface.go
@@ -1,6 +1,7 @@
 package auth
 
 import (
+	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
@@ -60,4 +61,26 @@ type State interface {
 	// CallAllReceivedRequests will iterate through all pending contact requests
 	// and replay them on the callbacks.
 	CallAllReceivedRequests()
+
+	// DeleteRequest deletes sent or received requests for a
+	// specific partner ID.
+	DeleteRequest(partnerID *id.ID) error
+
+	// DeleteAllRequests clears all requests from client's auth storage.
+	DeleteAllRequests() error
+
+	// DeleteSentRequests clears all sent requests from client's auth
+	// storage.
+	DeleteSentRequests() error
+
+	// DeleteReceiveRequests clears all received requests from client's auth
+	// storage.
+	DeleteReceiveRequests() error
+
+	// GetReceivedRequest returns a contact if there's a received
+	// request for it.
+	GetReceivedRequest(partner *id.ID) (contact.Contact, error)
+
+	// VerifyOwnership checks if the received ownership proof is valid
+	VerifyOwnership(received, verified contact.Contact, e2e e2e.Handler) bool
 }
diff --git a/auth/receivedConfirm.go b/auth/receivedConfirm.go
index 1990fd5bdca5eeb826573b6c06c9151ce96ce25c..07e12df9beae5cb55889d9eadd29a3361b68b2b3 100644
--- a/auth/receivedConfirm.go
+++ b/auth/receivedConfirm.go
@@ -5,9 +5,9 @@ import (
 	"fmt"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth/store"
-	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
 	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
 	"gitlab.com/elixxir/crypto/contact"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
@@ -95,7 +95,7 @@ func (rcs *receivedConfirmService) Process(msg format.Message,
 			"%s : %+v", rcs.GetPartner(), receptionID.Source, err)
 	}
 
-	//todo: trigger backup
+	rcs.s.backupTrigger("received confirmation from request")
 
 	// remove the service used for notifications of the confirm
 	state.net.DeleteService(receptionID.Source, rcs.notificationsService, nil)
diff --git a/auth/request.go b/auth/request.go
index 3e6b8c874b8243c313182d39437aca0d1d412153..a37839fd8eb065258a61867bc45a671bc3b55dc7 100644
--- a/auth/request.go
+++ b/auth/request.go
@@ -9,11 +9,15 @@ package auth
 
 import (
 	"fmt"
+	"io"
+	"strings"
+
 	"github.com/cloudflare/circl/dh/sidh"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/client/e2e/ratchet"
 	util "gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/crypto/contact"
@@ -23,8 +27,6 @@ import (
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
-	"io"
-	"strings"
 )
 
 const terminator = ";"
@@ -199,3 +201,28 @@ func createRequestAuth(sender *id.ID, payload, ownership []byte, myDHPriv,
 
 	return &baseFmt, mac, nil
 }
+
+func (s *state) GetReceivedRequest(partner *id.ID) (contact.Contact, error) {
+	return s.store.GetReceivedRequest(partner)
+}
+
+func (s *state) VerifyOwnership(received, verified contact.Contact,
+	e2e e2e.Handler) bool {
+	return VerifyOwnership(received, verified, e2e)
+}
+
+func (s *state) DeleteRequest(partnerID *id.ID) error {
+	return s.store.DeleteRequest(partnerID)
+}
+
+func (s *state) DeleteAllRequests() error {
+	return s.store.DeleteAllRequests()
+}
+
+func (s *state) DeleteSentRequests() error {
+	return s.store.DeleteSentRequests()
+}
+
+func (s *state) DeleteReceiveRequests() error {
+	return s.store.DeleteReceiveRequests()
+}
diff --git a/auth/state.go b/auth/state.go
index 7ced7eb8d69ca96ef321fd5b3ac5faa625c6dab7..a3e3d59df1ff43bf8eb6ace2582a009aaedab191 100644
--- a/auth/state.go
+++ b/auth/state.go
@@ -9,6 +9,7 @@ package auth
 
 import (
 	"encoding/base64"
+
 	"github.com/cloudflare/circl/dh/sidh"
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/auth/store"
@@ -33,16 +34,16 @@ import (
 type state struct {
 	callbacks Callbacks
 
-	// net cmix.Client
 	net cmixClient
-	// e2e e2e.Handler
 	e2e e2eHandler
 	rng *fastRNG.StreamGenerator
 
 	store *store.Store
-	event event.Manager
+	event event.Reporter
 
 	params Param
+
+	backupTrigger func(reason string)
 }
 
 type cmixClient interface {
@@ -100,10 +101,11 @@ type Callbacks interface {
 //   with a memory only versioned.KV) as well as a memory only versioned.KV for
 //   NewState and use GetDefaultTemporaryParams() for the parameters
 func NewState(kv *versioned.KV, net cmix.Client, e2e e2e.Handler,
-	rng *fastRNG.StreamGenerator, event event.Manager, params Param,
-	callbacks Callbacks) (State, error) {
+	rng *fastRNG.StreamGenerator, event event.Reporter, params Param,
+	callbacks Callbacks, backupTrigger func(reason string)) (State, error) {
 	kv = kv.Prefix(makeStorePrefix(e2e.GetReceptionID()))
-	return NewStateLegacy(kv, net, e2e, rng, event, params, callbacks)
+	return NewStateLegacy(
+		kv, net, e2e, rng, event, params, callbacks, backupTrigger)
 }
 
 // NewStateLegacy loads the auth state or creates new auth state if one cannot be
@@ -112,18 +114,17 @@ func NewState(kv *versioned.KV, net cmix.Client, e2e e2e.Handler,
 // Does not modify the kv prefix for backwards compatibility
 // Otherwise, acts the same as NewState
 func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler,
-	rng *fastRNG.StreamGenerator, event event.Manager, params Param,
-	callbacks Callbacks) (State, error) {
+	rng *fastRNG.StreamGenerator, event event.Reporter, params Param,
+	callbacks Callbacks, backupTrigger func(reason string)) (State, error) {
 
 	s := &state{
-		callbacks: callbacks,
-
-		net: net,
-		e2e: e2e,
-		rng: rng,
-
-		params: params,
-		event:  event,
+		callbacks:     callbacks,
+		net:           net,
+		e2e:           e2e,
+		rng:           rng,
+		event:         event,
+		params:        params,
+		backupTrigger: backupTrigger,
 	}
 
 	// create the store
@@ -131,7 +132,7 @@ func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler,
 	s.store, err = store.NewOrLoadStore(kv, e2e.GetGroup(),
 		&sentRequestHandler{s: s})
 
-	//register services
+	// register services
 	net.AddService(e2e.GetReceptionID(), message.Service{
 		Identifier: e2e.GetReceptionID()[:],
 		Tag:        params.RequestTag,
diff --git a/backup/backup.go b/backup/backup.go
index ea9667c0391b495b6c1c814cf5cf27f19341002e..291348fa6aa3bbbee8b49e6937013c4ea77b51f6 100644
--- a/backup/backup.go
+++ b/backup/backup.go
@@ -5,34 +5,30 @@
 // LICENSE file                                                               //
 ////////////////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
-////////////////////////////////////////////////////////////////////////////////
-
 package backup
 
 import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/primitives/fact"
+	"gitlab.com/xx_network/primitives/id"
 	"sync"
+	"time"
 
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/crypto/backup"
 	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/xx_network/crypto/signature/rsa"
 )
 
 // Error messages.
 const (
-	// initializeBackup
+	// InitializeBackup
 	errSavePassword      = "failed to save password: %+v"
 	errSaveKeySaltParams = "failed to save key, salt, and params: %+v"
 
-	// resumeBackup
+	// ResumeBackup
 	errLoadPassword = "backup not initialized: load user password failed: %+v"
 
 	// Backup.StopBackup
@@ -46,15 +42,43 @@ type Backup struct {
 	// Callback that is called with the encrypted backup when triggered
 	updateBackupCb UpdateBackupFn
 
-	mux sync.RWMutex
+	container *Container
+
+	jsonParams string
 
 	// Client structures
-	client          *api.Client
-	store           *storage.Session
-	backupContainer *interfaces.BackupContainer
-	rng             *fastRNG.StreamGenerator
+	e2e     E2e
+	session Session
+	ud      UserDiscovery
+	kv      *versioned.KV
+	rng     *fastRNG.StreamGenerator
 
-	jsonParams string
+	mux sync.RWMutex
+}
+
+// E2e is a subset of functions from the interface e2e.Handler.
+type E2e interface {
+	GetAllPartnerIDs() []*id.ID
+	GetHistoricalDHPubkey() *cyclic.Int
+	GetHistoricalDHPrivkey() *cyclic.Int
+}
+
+// Session is a subset of functions from the interface storage.Session.
+type Session interface {
+	GetRegCode() (string, error)
+	GetTransmissionID() *id.ID
+	GetTransmissionSalt() []byte
+	GetReceptionID() *id.ID
+	GetReceptionSalt() []byte
+	GetReceptionRSA() *rsa.PrivateKey
+	GetTransmissionRSA() *rsa.PrivateKey
+	GetTransmissionRegistrationValidationSignature() []byte
+	GetReceptionRegistrationValidationSignature() []byte
+	GetRegistrationTimestamp() time.Time
+}
+
+type UserDiscovery interface {
+	GetFacts() fact.FactList
 }
 
 // UpdateBackupFn is the callback that encrypted backup data is returned on
@@ -68,27 +92,20 @@ type UpdateBackupFn func(encryptedBackup []byte)
 // Call this to turn on backups for the first time or to replace the user's
 // password.
 func InitializeBackup(password string, updateBackupCb UpdateBackupFn,
-	c *api.Client) (*Backup, error) {
-	return initializeBackup(
-		password, updateBackupCb, c, c.GetStorage(), c.GetBackup(), c.GetRng())
-}
-
-// initializeBackup is a helper function that takes in all the fields for Backup
-// as parameters for easier testing.
-func initializeBackup(password string, updateBackupCb UpdateBackupFn,
-	c *api.Client, store *storage.Session,
-	backupContainer *interfaces.BackupContainer, rng *fastRNG.StreamGenerator) (
-	*Backup, error) {
+	container *Container, e2e E2e, session Session, ud UserDiscovery,
+	kv *versioned.KV, rng *fastRNG.StreamGenerator) (*Backup, error) {
 	b := &Backup{
-		updateBackupCb:  updateBackupCb,
-		client:          c,
-		store:           store,
-		backupContainer: backupContainer,
-		rng:             rng,
+		updateBackupCb: updateBackupCb,
+		container:      container,
+		e2e:            e2e,
+		session:        session,
+		ud:             ud,
+		kv:             kv,
+		rng:            rng,
 	}
 
 	// Save password to storage
-	err := savePassword(password, b.store.GetKV())
+	err := savePassword(password, b.kv)
 	if err != nil {
 		return nil, errors.Errorf(errSavePassword, err)
 	}
@@ -105,15 +122,15 @@ func initializeBackup(password string, updateBackupCb UpdateBackupFn,
 	key := backup.DeriveKey(password, salt, params)
 
 	// Save key, salt, and parameters to storage
-	err = saveBackup(key, salt, params, b.store.GetKV())
+	err = saveBackup(key, salt, params, b.kv)
 	if err != nil {
 		return nil, errors.Errorf(errSaveKeySaltParams, err)
 	}
 
 	// Setting backup trigger in client
-	b.backupContainer.SetBackup(b.TriggerBackup)
+	b.container.SetBackup(b.TriggerBackup)
 
-	b.TriggerBackup("initializeBackup")
+	b.TriggerBackup("InitializeBackup")
 	jww.INFO.Print("Initialized backup with new user key.")
 
 	return b, nil
@@ -122,32 +139,27 @@ func initializeBackup(password string, updateBackupCb UpdateBackupFn,
 // ResumeBackup resumes a backup by restoring the Backup object and registering
 // a new callback. Call this to resume backups that have already been
 // initialized. Returns an error if backups have not already been initialized.
-func ResumeBackup(updateBackupCb UpdateBackupFn, c *api.Client) (*Backup, error) {
-	return resumeBackup(
-		updateBackupCb, c, c.GetStorage(), c.GetBackup(), c.GetRng())
-}
-
-// resumeBackup is a helper function that takes in all the fields for Backup as
-// parameters for easier testing.
-func resumeBackup(updateBackupCb UpdateBackupFn, c *api.Client,
-	store *storage.Session, backupContainer *interfaces.BackupContainer,
+func ResumeBackup(updateBackupCb UpdateBackupFn, container *Container,
+	e2e E2e, session Session, ud UserDiscovery, kv *versioned.KV,
 	rng *fastRNG.StreamGenerator) (*Backup, error) {
-	_, err := loadPassword(store.GetKV())
+	_, err := loadPassword(kv)
 	if err != nil {
 		return nil, errors.Errorf(errLoadPassword, err)
 	}
 
 	b := &Backup{
-		updateBackupCb:  updateBackupCb,
-		client:          c,
-		store:           store,
-		backupContainer: backupContainer,
-		rng:             rng,
-		jsonParams:      loadJson(store.GetKV()),
+		updateBackupCb: updateBackupCb,
+		container:      container,
+		jsonParams:     loadJson(kv),
+		e2e:            e2e,
+		session:        session,
+		ud:             ud,
+		kv:             kv,
+		rng:            rng,
 	}
 
 	// Setting backup trigger in client
-	b.backupContainer.SetBackup(b.TriggerBackup)
+	b.container.SetBackup(b.TriggerBackup)
 
 	jww.INFO.Print("Resumed backup with password loaded from storage.")
 
@@ -181,7 +193,7 @@ func (b *Backup) TriggerBackup(reason string) {
 	b.mux.RLock()
 	defer b.mux.RUnlock()
 
-	key, salt, params, err := loadBackup(b.store.GetKV())
+	key, salt, params, err := loadBackup(b.kv)
 	if err != nil {
 		jww.ERROR.Printf("Backup Failed: could not load key, salt, and "+
 			"parameters for encrypting backup from storage: %+v", err)
@@ -217,7 +229,7 @@ func (b *Backup) AddJson(newJson string) {
 
 	if newJson != b.jsonParams {
 		b.jsonParams = newJson
-		if err := storeJson(newJson, b.store.GetKV()); err != nil {
+		if err := storeJson(newJson, b.kv); err != nil {
 			jww.FATAL.Panicf("Failed to store json: %+v", err)
 		}
 		go b.TriggerBackup("New Json")
@@ -231,12 +243,12 @@ func (b *Backup) StopBackup() error {
 	defer b.mux.Unlock()
 	b.updateBackupCb = nil
 
-	err := deletePassword(b.store.GetKV())
+	err := deletePassword(b.kv)
 	if err != nil {
 		return errors.Errorf(errDeletePassword, err)
 	}
 
-	err = deleteBackup(b.store.GetKV())
+	err = deleteBackup(b.kv)
 	if err != nil {
 		return errors.Errorf(errDeleteCrypto, err)
 	}
@@ -268,42 +280,38 @@ func (b *Backup) assembleBackup() backup.Backup {
 		Contacts:                  backup.Contacts{},
 	}
 
-	// get user and storage user
-	u := b.store.GetUser()
-	su := b.store.User()
-
-	// get registration timestamp
-	bu.RegistrationTimestamp = u.RegistrationTimestamp
+	// Get registration timestamp
+	bu.RegistrationTimestamp = b.session.GetRegistrationTimestamp().UnixNano()
 
-	// get registration code; ignore the error because if there is no
+	// Get registration code; ignore the error because if there is no
 	// registration, then an empty string is returned
-	bu.RegistrationCode, _ = b.store.GetRegCode()
+	bu.RegistrationCode, _ = b.session.GetRegCode()
 
-	// get transmission identity
+	// Get transmission identity
 	bu.TransmissionIdentity = backup.TransmissionIdentity{
-		RSASigningPrivateKey: u.TransmissionRSA,
-		RegistrarSignature:   su.GetTransmissionRegistrationValidationSignature(),
-		Salt:                 u.TransmissionSalt,
-		ComputedID:           u.TransmissionID,
+		RSASigningPrivateKey: b.session.GetTransmissionRSA(),
+		RegistrarSignature:   b.session.GetTransmissionRegistrationValidationSignature(),
+		Salt:                 b.session.GetTransmissionSalt(),
+		ComputedID:           b.session.GetTransmissionID(),
 	}
 
-	// get reception identity
+	// Get reception identity
 	bu.ReceptionIdentity = backup.ReceptionIdentity{
-		RSASigningPrivateKey: u.ReceptionRSA,
-		RegistrarSignature:   su.GetReceptionRegistrationValidationSignature(),
-		Salt:                 u.ReceptionSalt,
-		ComputedID:           u.ReceptionID,
-		DHPrivateKey:         u.E2eDhPrivateKey,
-		DHPublicKey:          u.E2eDhPublicKey,
+		RSASigningPrivateKey: b.session.GetReceptionRSA(),
+		RegistrarSignature:   b.session.GetReceptionRegistrationValidationSignature(),
+		Salt:                 b.session.GetReceptionSalt(),
+		ComputedID:           b.session.GetReceptionID(),
+		DHPrivateKey:         b.e2e.GetHistoricalDHPrivkey(),
+		DHPublicKey:          b.e2e.GetHistoricalDHPubkey(),
 	}
 
-	// get facts
-	bu.UserDiscoveryRegistration.FactList = b.store.GetUd().GetFacts()
+	// Get facts
+	bu.UserDiscoveryRegistration.FactList = b.ud.GetFacts()
 
-	// get contacts
-	bu.Contacts.Identities = b.store.E2e().GetPartners()
+	// Get contacts
+	bu.Contacts.Identities = b.e2e.GetAllPartnerIDs()
 
-	//add the memoized json params
+	// Add the memoized json params
 	bu.JSONParams = b.jsonParams
 
 	return bu
diff --git a/backup/backup_test.go b/backup/backup_test.go
index 434c76e78665692524849952b599652be428600a..076fc2d8c7451dbe039d60fc1c8cd9edc85204e4 100644
--- a/backup/backup_test.go
+++ b/backup/backup_test.go
@@ -9,29 +9,30 @@ package backup
 
 import (
 	"bytes"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/ekv"
 	"reflect"
 	"strings"
 	"testing"
 	"time"
 
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/crypto/backup"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/crypto/csprng"
 )
 
-// Tests that Backup.initializeBackup returns a new Backup with a copy of the
+// Tests that Backup.InitializeBackup returns a new Backup with a copy of the
 // key and the callback.
-func Test_initializeBackup(t *testing.T) {
+func Test_InitializeBackup(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
 	cbChan := make(chan []byte, 2)
 	cb := func(encryptedBackup []byte) { cbChan <- encryptedBackup }
 	expectedPassword := "MySuperSecurePassword"
-	b, err := initializeBackup(expectedPassword, cb, nil,
-		storage.InitTestingSession(t), &interfaces.BackupContainer{},
-		fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG))
+	b, err := InitializeBackup(expectedPassword, cb, &Container{}, newMockE2e(t),
+		newMockSession(t), newMockUserDiscovery(), kv, rngGen)
 	if err != nil {
-		t.Errorf("initializeBackup returned an error: %+v", err)
+		t.Errorf("InitializeBackup returned an error: %+v", err)
 	}
 
 	select {
@@ -41,7 +42,7 @@ func Test_initializeBackup(t *testing.T) {
 	}
 
 	// Check that the correct password is in storage
-	loadedPassword, err := loadPassword(b.store.GetKV())
+	loadedPassword, err := loadPassword(b.kv)
 	if err != nil {
 		t.Errorf("Failed to load password: %+v", err)
 	}
@@ -51,7 +52,7 @@ func Test_initializeBackup(t *testing.T) {
 	}
 
 	// Check that the key, salt, and params were saved to storage
-	key, salt, p, err := loadBackup(b.store.GetKV())
+	key, salt, p, err := loadBackup(b.kv)
 	if err != nil {
 		t.Errorf("Failed to load key, salt, and params: %+v", err)
 	}
@@ -80,17 +81,17 @@ func Test_initializeBackup(t *testing.T) {
 	}
 }
 
-// Initialises a new backup and then tests that Backup.resumeBackup overwrites
-// the callback but keeps the password.
-func Test_resumeBackup(t *testing.T) {
+// Initialises a new backup and then tests that ResumeBackup overwrites the
+// callback but keeps the password.
+func Test_ResumeBackup(t *testing.T) {
 	// Start the first backup
+	kv := versioned.NewKV(make(ekv.Memstore))
+	rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
 	cbChan1 := make(chan []byte)
 	cb1 := func(encryptedBackup []byte) { cbChan1 <- encryptedBackup }
-	s := storage.InitTestingSession(t)
 	expectedPassword := "MySuperSecurePassword"
-	b, err := initializeBackup(expectedPassword, cb1, nil, s,
-		&interfaces.BackupContainer{},
-		fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG))
+	b, err := InitializeBackup(expectedPassword, cb1, &Container{},
+		newMockE2e(t), newMockSession(t), newMockUserDiscovery(), kv, rngGen)
 	if err != nil {
 		t.Errorf("Failed to initialize new Backup: %+v", err)
 	}
@@ -102,7 +103,7 @@ func Test_resumeBackup(t *testing.T) {
 	}
 
 	// get key and salt to compare to later
-	key1, salt1, _, err := loadBackup(b.store.GetKV())
+	key1, salt1, _, err := loadBackup(b.kv)
 	if err != nil {
 		t.Errorf("Failed to load key, salt, and params from newly "+
 			"initialized backup: %+v", err)
@@ -111,14 +112,14 @@ func Test_resumeBackup(t *testing.T) {
 	// Resume the backup with a new callback
 	cbChan2 := make(chan []byte)
 	cb2 := func(encryptedBackup []byte) { cbChan2 <- encryptedBackup }
-	b2, err := resumeBackup(cb2, nil, s, &interfaces.BackupContainer{},
-		fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG))
+	b2, err := ResumeBackup(cb2, &Container{}, newMockE2e(t), newMockSession(t),
+		newMockUserDiscovery(), kv, rngGen)
 	if err != nil {
-		t.Errorf("resumeBackup returned an error: %+v", err)
+		t.Errorf("ResumeBackup returned an error: %+v", err)
 	}
 
 	// Check that the correct password is in storage
-	loadedPassword, err := loadPassword(b.store.GetKV())
+	loadedPassword, err := loadPassword(b.kv)
 	if err != nil {
 		t.Errorf("Failed to load password: %+v", err)
 	}
@@ -128,7 +129,7 @@ func Test_resumeBackup(t *testing.T) {
 	}
 
 	// get key, salt, and parameters of resumed backup
-	key2, salt2, _, err := loadBackup(b.store.GetKV())
+	key2, salt2, _, err := loadBackup(b.kv)
 	if err != nil {
 		t.Errorf("Failed to load key, salt, and params from resumed "+
 			"backup: %+v", err)
@@ -158,14 +159,16 @@ func Test_resumeBackup(t *testing.T) {
 	}
 }
 
-// Error path: Tests that Backup.resumeBackup returns an error if no password is
+// Error path: Tests that ResumeBackup returns an error if no password is
 // present in storage.
-func Test_resumeBackup_NoKeyError(t *testing.T) {
+func Test_ResumeBackup_NoKeyError(t *testing.T) {
 	expectedErr := strings.Split(errLoadPassword, "%")[0]
-	s := storage.InitTestingSession(t)
-	_, err := resumeBackup(nil, nil, s, &interfaces.BackupContainer{}, nil)
+	kv := versioned.NewKV(make(ekv.Memstore))
+	rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
+	_, err := ResumeBackup(nil, &Container{}, newMockE2e(t), newMockSession(t),
+		newMockUserDiscovery(), kv, rngGen)
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
-		t.Errorf("resumeBackup did not return the expected error when no "+
+		t.Errorf("ResumeBackup did not return the expected error when no "+
 			"password is present.\nexpected: %s\nreceived: %+v", expectedErr, err)
 	}
 }
@@ -178,7 +181,7 @@ func TestBackup_TriggerBackup(t *testing.T) {
 	b := newTestBackup("MySuperSecurePassword", cb, t)
 
 	// get password
-	password, err := loadPassword(b.store.GetKV())
+	password, err := loadPassword(b.kv)
 	if err != nil {
 		t.Errorf("Failed to load password from storage: %+v", err)
 	}
@@ -215,7 +218,7 @@ func TestBackup_TriggerBackup_NoKey(t *testing.T) {
 		t.Errorf("backup not called")
 	}
 
-	err := deleteBackup(b.store.GetKV())
+	err := deleteBackup(b.kv)
 	if err != nil {
 		t.Errorf("Failed to delete key, salt, and params: %+v", err)
 	}
@@ -260,13 +263,13 @@ func TestBackup_StopBackup(t *testing.T) {
 	}
 
 	// Make sure password is deleted
-	password, err := loadPassword(b.store.GetKV())
+	password, err := loadPassword(b.kv)
 	if err == nil || len(password) != 0 {
 		t.Errorf("Loaded password that should be deleted: %q", password)
 	}
 
 	// Make sure key, salt, and params are deleted
-	key, salt, p, err := loadBackup(b.store.GetKV())
+	key, salt, p, err := loadBackup(b.kv)
 	if err == nil || len(key) != 0 || len(salt) != 0 || p != (backup.Params{}) {
 		t.Errorf("Loaded key, salt, and params that should be deleted.")
 	}
@@ -296,77 +299,79 @@ func TestBackup_IsBackupRunning(t *testing.T) {
 
 func TestBackup_AddJson(t *testing.T) {
 	b := newTestBackup("MySuperSecurePassword", nil, t)
-	s := b.store
+	s := b.session.(*mockSession)
+	e2e := b.e2e.(*mockE2e)
 	json := "{'data': {'one': 1}}"
 
-	expectedCollatedBackup := backup.Backup{
-		RegistrationTimestamp: s.GetUser().RegistrationTimestamp,
+	expected := backup.Backup{
+		RegistrationCode:      s.regCode,
+		RegistrationTimestamp: s.registrationTimestamp.UnixNano(),
 		TransmissionIdentity: backup.TransmissionIdentity{
-			RSASigningPrivateKey: s.GetUser().TransmissionRSA,
-			RegistrarSignature:   s.User().GetTransmissionRegistrationValidationSignature(),
-			Salt:                 s.GetUser().TransmissionSalt,
-			ComputedID:           s.GetUser().TransmissionID,
+			RSASigningPrivateKey: s.transmissionRSA,
+			RegistrarSignature:   s.transmissionRegistrationValidationSignature,
+			Salt:                 s.transmissionSalt,
+			ComputedID:           s.transmissionID,
 		},
 		ReceptionIdentity: backup.ReceptionIdentity{
-			RSASigningPrivateKey: s.GetUser().ReceptionRSA,
-			RegistrarSignature:   s.User().GetReceptionRegistrationValidationSignature(),
-			Salt:                 s.GetUser().ReceptionSalt,
-			ComputedID:           s.GetUser().ReceptionID,
-			DHPrivateKey:         s.GetUser().E2eDhPrivateKey,
-			DHPublicKey:          s.GetUser().E2eDhPublicKey,
+			RSASigningPrivateKey: s.receptionRSA,
+			RegistrarSignature:   s.receptionRegistrationValidationSignature,
+			Salt:                 s.receptionSalt,
+			ComputedID:           s.receptionID,
+			DHPrivateKey:         e2e.historicalDHPrivkey,
+			DHPublicKey:          e2e.historicalDHPubkey,
 		},
 		UserDiscoveryRegistration: backup.UserDiscoveryRegistration{
-			FactList: s.GetUd().GetFacts(),
+			FactList: b.ud.(*mockUserDiscovery).facts,
 		},
-		Contacts:   backup.Contacts{Identities: s.E2e().GetPartners()},
+		Contacts:   backup.Contacts{Identities: e2e.partnerIDs},
 		JSONParams: json,
 	}
 
 	b.AddJson(json)
 
 	collatedBackup := b.assembleBackup()
-	if !reflect.DeepEqual(expectedCollatedBackup, collatedBackup) {
+	if !reflect.DeepEqual(expected, collatedBackup) {
 		t.Errorf("Collated backup does not match expected."+
-			"\nexpected: %+v\nreceived: %+v",
-			expectedCollatedBackup, collatedBackup)
+			"\nexpected: %+v\nreceived: %+v", expected, collatedBackup)
 	}
 }
 
 func TestBackup_AddJson_badJson(t *testing.T) {
 	b := newTestBackup("MySuperSecurePassword", nil, t)
-	s := b.store
+	s := b.session.(*mockSession)
+	e2e := b.e2e.(*mockE2e)
 	json := "abc{'i'm a bad json: 'one': 1'''}}"
 
-	expectedCollatedBackup := backup.Backup{
-		RegistrationTimestamp: s.GetUser().RegistrationTimestamp,
+	expected := backup.Backup{
+		RegistrationCode:      s.regCode,
+		RegistrationTimestamp: s.registrationTimestamp.UnixNano(),
 		TransmissionIdentity: backup.TransmissionIdentity{
-			RSASigningPrivateKey: s.GetUser().TransmissionRSA,
-			RegistrarSignature:   s.User().GetTransmissionRegistrationValidationSignature(),
-			Salt:                 s.GetUser().TransmissionSalt,
-			ComputedID:           s.GetUser().TransmissionID,
+			RSASigningPrivateKey: s.transmissionRSA,
+			RegistrarSignature:   s.transmissionRegistrationValidationSignature,
+			Salt:                 s.transmissionSalt,
+			ComputedID:           s.transmissionID,
 		},
 		ReceptionIdentity: backup.ReceptionIdentity{
-			RSASigningPrivateKey: s.GetUser().ReceptionRSA,
-			RegistrarSignature:   s.User().GetReceptionRegistrationValidationSignature(),
-			Salt:                 s.GetUser().ReceptionSalt,
-			ComputedID:           s.GetUser().ReceptionID,
-			DHPrivateKey:         s.GetUser().E2eDhPrivateKey,
-			DHPublicKey:          s.GetUser().E2eDhPublicKey,
+			RSASigningPrivateKey: s.receptionRSA,
+			RegistrarSignature:   s.receptionRegistrationValidationSignature,
+			Salt:                 s.receptionSalt,
+			ComputedID:           s.receptionID,
+			DHPrivateKey:         e2e.historicalDHPrivkey,
+			DHPublicKey:          e2e.historicalDHPubkey,
 		},
 		UserDiscoveryRegistration: backup.UserDiscoveryRegistration{
-			FactList: s.GetUd().GetFacts(),
+			FactList: b.ud.(*mockUserDiscovery).facts,
 		},
-		Contacts:   backup.Contacts{Identities: s.E2e().GetPartners()},
+		Contacts:   backup.Contacts{Identities: e2e.partnerIDs},
 		JSONParams: json,
 	}
 
 	b.AddJson(json)
 
 	collatedBackup := b.assembleBackup()
-	if !reflect.DeepEqual(expectedCollatedBackup, collatedBackup) {
+	if !reflect.DeepEqual(expected, collatedBackup) {
 		t.Errorf("Collated backup does not match expected."+
-			"\nexpected: %+v\nreceived: %+v",
-			expectedCollatedBackup, collatedBackup)
+			"\nexpected: %+v\nreceived: %+v", expected, collatedBackup)
 	}
 }
 
@@ -374,47 +379,51 @@ func TestBackup_AddJson_badJson(t *testing.T) {
 // results.
 func TestBackup_assembleBackup(t *testing.T) {
 	b := newTestBackup("MySuperSecurePassword", nil, t)
-	s := b.store
+	s := b.session.(*mockSession)
+	e2e := b.e2e.(*mockE2e)
 
-	expectedCollatedBackup := backup.Backup{
-		RegistrationTimestamp: s.GetUser().RegistrationTimestamp,
+	expected := backup.Backup{
+		RegistrationCode:      s.regCode,
+		RegistrationTimestamp: s.registrationTimestamp.UnixNano(),
 		TransmissionIdentity: backup.TransmissionIdentity{
-			RSASigningPrivateKey: s.GetUser().TransmissionRSA,
-			RegistrarSignature:   s.User().GetTransmissionRegistrationValidationSignature(),
-			Salt:                 s.GetUser().TransmissionSalt,
-			ComputedID:           s.GetUser().TransmissionID,
+			RSASigningPrivateKey: s.transmissionRSA,
+			RegistrarSignature:   s.transmissionRegistrationValidationSignature,
+			Salt:                 s.transmissionSalt,
+			ComputedID:           s.transmissionID,
 		},
 		ReceptionIdentity: backup.ReceptionIdentity{
-			RSASigningPrivateKey: s.GetUser().ReceptionRSA,
-			RegistrarSignature:   s.User().GetReceptionRegistrationValidationSignature(),
-			Salt:                 s.GetUser().ReceptionSalt,
-			ComputedID:           s.GetUser().ReceptionID,
-			DHPrivateKey:         s.GetUser().E2eDhPrivateKey,
-			DHPublicKey:          s.GetUser().E2eDhPublicKey,
+			RSASigningPrivateKey: s.receptionRSA,
+			RegistrarSignature:   s.receptionRegistrationValidationSignature,
+			Salt:                 s.receptionSalt,
+			ComputedID:           s.receptionID,
+			DHPrivateKey:         e2e.historicalDHPrivkey,
+			DHPublicKey:          e2e.historicalDHPubkey,
 		},
 		UserDiscoveryRegistration: backup.UserDiscoveryRegistration{
-			FactList: s.GetUd().GetFacts(),
+			FactList: b.ud.(*mockUserDiscovery).facts,
 		},
-		Contacts: backup.Contacts{Identities: s.E2e().GetPartners()},
+		Contacts: backup.Contacts{Identities: e2e.partnerIDs},
 	}
 
 	collatedBackup := b.assembleBackup()
 
-	if !reflect.DeepEqual(expectedCollatedBackup, collatedBackup) {
+	if !reflect.DeepEqual(expected, collatedBackup) {
 		t.Errorf("Collated backup does not match expected."+
 			"\nexpected: %+v\nreceived: %+v",
-			expectedCollatedBackup, collatedBackup)
+			expected, collatedBackup)
 	}
 }
 
 // newTestBackup creates a new Backup for testing.
 func newTestBackup(password string, cb UpdateBackupFn, t *testing.T) *Backup {
-	b, err := initializeBackup(
+	b, err := InitializeBackup(
 		password,
 		cb,
-		nil,
-		storage.InitTestingSession(t),
-		&interfaces.BackupContainer{},
+		&Container{},
+		newMockE2e(t),
+		newMockSession(t),
+		newMockUserDiscovery(),
+		versioned.NewKV(make(ekv.Memstore)),
 		fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 	)
 	if err != nil {
diff --git a/interfaces/backup.go b/backup/container.go
similarity index 83%
rename from interfaces/backup.go
rename to backup/container.go
index 559b4b0f8756ee772aba9064757601d2ade417d6..fd456ea96c11337c4709991c97f6b84458adfe11 100644
--- a/interfaces/backup.go
+++ b/backup/container.go
@@ -5,14 +5,14 @@
 // LICENSE file                                                               //
 ////////////////////////////////////////////////////////////////////////////////
 
-package interfaces
+package backup
 
 import "sync"
 
 type TriggerBackup func(reason string)
 
-// BackupContainer contains the trigger to call to initiate a backup.
-type BackupContainer struct {
+// Container contains the trigger to call to initiate a backup.
+type Container struct {
 	triggerBackup TriggerBackup
 	mux           sync.RWMutex
 }
@@ -22,7 +22,7 @@ type BackupContainer struct {
 // should be in the paste tense. For example, if a contact is deleted, the
 // reason can be "contact deleted" and the log will show:
 //	Triggering backup: contact deleted
-func (bc *BackupContainer) TriggerBackup(reason string) {
+func (bc *Container) TriggerBackup(reason string) {
 	bc.mux.RLock()
 	defer bc.mux.RUnlock()
 	if bc.triggerBackup != nil {
@@ -32,7 +32,7 @@ func (bc *BackupContainer) TriggerBackup(reason string) {
 
 // SetBackup sets the backup trigger function which will cause a backup to start
 // on the next event that triggers is.
-func (bc *BackupContainer) SetBackup(triggerBackup TriggerBackup) {
+func (bc *Container) SetBackup(triggerBackup TriggerBackup) {
 	bc.mux.Lock()
 	defer bc.mux.Unlock()
 
diff --git a/backup/utils_test.go b/backup/utils_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..c16969ff89da1f08b29574dba9f20e9da2e4fb44
--- /dev/null
+++ b/backup/utils_test.go
@@ -0,0 +1,156 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                           //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package backup
+
+import (
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/primitives/fact"
+	"gitlab.com/xx_network/crypto/large"
+	"gitlab.com/xx_network/crypto/signature/rsa"
+	"gitlab.com/xx_network/primitives/id"
+	"testing"
+	"time"
+)
+
+// Adheres to the E2e interface.
+type mockE2e struct {
+	partnerIDs          []*id.ID
+	historicalDHPubkey  *cyclic.Int
+	historicalDHPrivkey *cyclic.Int
+}
+
+func newMockE2e(t *testing.T) *mockE2e {
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(0))
+	return &mockE2e{
+		partnerIDs: []*id.ID{
+			id.NewIdFromString("partner1", id.User, t),
+			id.NewIdFromString("partner2", id.User, t),
+			id.NewIdFromString("partner3", id.User, t),
+		},
+		historicalDHPubkey:  grp.NewInt(45),
+		historicalDHPrivkey: grp.NewInt(46),
+	}
+}
+func (m *mockE2e) GetAllPartnerIDs() []*id.ID          { return m.partnerIDs }
+func (m *mockE2e) GetHistoricalDHPubkey() *cyclic.Int  { return m.historicalDHPubkey }
+func (m *mockE2e) GetHistoricalDHPrivkey() *cyclic.Int { return m.historicalDHPrivkey }
+
+// Adheres to the Session interface.
+type mockSession struct {
+	regCode                                     string
+	transmissionID                              *id.ID
+	transmissionSalt                            []byte
+	receptionID                                 *id.ID
+	receptionSalt                               []byte
+	receptionRSA                                *rsa.PrivateKey
+	transmissionRSA                             *rsa.PrivateKey
+	transmissionRegistrationValidationSignature []byte
+	receptionRegistrationValidationSignature    []byte
+	registrationTimestamp                       time.Time
+}
+
+func newMockSession(t *testing.T) *mockSession {
+	receptionRSA, _ := rsa.LoadPrivateKeyFromPem([]byte(privKey))
+	transmissionRSA, _ := rsa.LoadPrivateKeyFromPem([]byte(privKey))
+
+	return &mockSession{
+		regCode:          "regCode",
+		transmissionID:   id.NewIdFromString("transmission", id.User, t),
+		transmissionSalt: []byte("transmissionSalt"),
+		receptionID:      id.NewIdFromString("reception", id.User, t),
+		receptionSalt:    []byte("receptionSalt"),
+		receptionRSA:     receptionRSA,
+		transmissionRSA:  transmissionRSA,
+		transmissionRegistrationValidationSignature: []byte("transmissionSig"),
+		receptionRegistrationValidationSignature:    []byte("receptionSig"),
+		registrationTimestamp:                       time.Date(2012, 12, 21, 22, 8, 41, 0, time.UTC),
+	}
+
+}
+func (m mockSession) GetRegCode() (string, error)         { return m.regCode, nil }
+func (m mockSession) GetTransmissionID() *id.ID           { return m.transmissionID }
+func (m mockSession) GetTransmissionSalt() []byte         { return m.transmissionSalt }
+func (m mockSession) GetReceptionID() *id.ID              { return m.receptionID }
+func (m mockSession) GetReceptionSalt() []byte            { return m.receptionSalt }
+func (m mockSession) GetReceptionRSA() *rsa.PrivateKey    { return m.receptionRSA }
+func (m mockSession) GetTransmissionRSA() *rsa.PrivateKey { return m.transmissionRSA }
+func (m mockSession) GetTransmissionRegistrationValidationSignature() []byte {
+	return m.transmissionRegistrationValidationSignature
+}
+func (m mockSession) GetReceptionRegistrationValidationSignature() []byte {
+	return m.receptionRegistrationValidationSignature
+}
+func (m mockSession) GetRegistrationTimestamp() time.Time { return m.registrationTimestamp }
+
+// Adheres to the UserDiscovery interface.
+type mockUserDiscovery struct {
+	facts fact.FactList
+}
+
+func newMockUserDiscovery() *mockUserDiscovery {
+	return &mockUserDiscovery{facts: fact.FactList{
+		{"myUserName", fact.Username},
+		{"hello@example.com", fact.Email},
+		{"6175555212", fact.Phone},
+		{"name", fact.Nickname},
+	}}
+}
+func (m mockUserDiscovery) GetFacts() fact.FactList { return m.facts }
+
+const privKey = `-----BEGIN PRIVATE KEY-----
+MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC7Dkb6VXFn4cdp
+U0xh6ji0nTDQUyT9DSNW9I3jVwBrWfqMc4ymJuonMZbuqK+cY2l+suS2eugevWZr
+tzujFPBRFp9O14Jl3fFLfvtjZvkrKbUMHDHFehascwzrp3tXNryiRMmCNQV55TfI
+TVCv8CLE0t1ibiyOGM9ZWYB2OjXt59j76lPARYww5qwC46vS6+3Cn2Yt9zkcrGes
+kWEFa2VttHqF910TP+DZk2R5C7koAh6wZYK6NQ4S83YQurdHAT51LKGrbGehFKXq
+6/OAXCU1JLi3kW2PovTb6MZuvxEiRmVAONsOcXKu7zWCmFjuZZwfRt2RhnpcSgzf
+rarmsGM0LZh6JY3MGJ9YdPcVGSz+Vs2E4zWbNW+ZQoqlcGeMKgsIiQ670g0xSjYI
+Cqldpt79gaET9PZsoXKEmKUaj6pq1d4qXDk7s63HRQazwVLGBdJQK8qX41eCdR8V
+MKbrCaOkzD5zgnEu0jBBAwdMtcigkMIk1GRv91j7HmqwryOBHryLi6NWBY3tjb4S
+o9AppDQB41SH3SwNenAbNO1CXeUqN0hHX6I1bE7OlbjqI7tXdrTllHAJTyVVjenP
+el2ApMXp+LVRdDbKtwBiuM6+n+z0I7YYerxN1gfvpYgcXm4uye8dfwotZj6H2J/u
+SALsU2v9UHBzprdrLSZk2YpozJb+CQIDAQABAoICAARjDFUYpeU6zVNyCauOM7BA
+s4FfQdHReg+zApTfWHosDQ04NIc9CGbM6e5E9IFlb3byORzyevkllf5WuMZVWmF8
+d1YBBeTftKYBn2Gwa42Ql9dl3eD0wQ1gUWBBeEoOVZQ0qskr9ynpr0o6TfciWZ5m
+F50UWmUmvc4ppDKhoNwogNU/pKEwwF3xOv2CW2hB8jyLQnk3gBZlELViX3UiFKni
+/rCfoYYvDFXt+ABCvx/qFNAsQUmerurQ3Ob9igjXRaC34D7F9xQ3CMEesYJEJvc9
+Gjvr5DbnKnjx152HS56TKhK8gp6vGHJz17xtWECXD3dIUS/1iG8bqXuhdg2c+2aW
+m3MFpa5jgpAawUWc7c32UnqbKKf+HI7/x8J1yqJyNeU5SySyYSB5qtwTShYzlBW/
+yCYD41edeJcmIp693nUcXzU+UAdtpt0hkXS59WSWlTrB/huWXy6kYXLNocNk9L7g
+iyx0cOmkuxREMHAvK0fovXdVyflQtJYC7OjJxkzj2rWO+QtHaOySXUyinkuTb5ev
+xNhs+ROWI/HAIE9buMqXQIpHx6MSgdKOL6P6AEbBan4RAktkYA6y5EtH/7x+9V5E
+QTIz4LrtI6abaKb4GUlZkEsc8pxrkNwCqOAE/aqEMNh91Na1TOj3f0/a6ckGYxYH
+pyrvwfP2Ouu6e5FhDcCBAoIBAQDcN8mK99jtrH3q3Q8vZAWFXHsOrVvnJXyHLz9V
+1Rx/7TnMUxvDX1PIVxhuJ/tmHtxrNIXOlps80FCZXGgxfET/YFrbf4H/BaMNJZNP
+ag1wBV5VQSnTPdTR+Ijice+/ak37S2NKHt8+ut6yoZjD7sf28qiO8bzNua/OYHkk
+V+RkRkk68Uk2tFMluQOSyEjdsrDNGbESvT+R1Eotupr0Vy/9JRY/TFMc4MwJwOoy
+s7wYr9SUCq/cYn7FIOBTI+PRaTx1WtpfkaErDc5O+nLLEp1yOrfktl4LhU/r61i7
+fdtafUACTKrXG2qxTd3w++mHwTwVl2MwhiMZfxvKDkx0L2gxAoIBAQDZcxKwyZOy
+s6Aw7igw1ftLny/dpjPaG0p6myaNpeJISjTOU7HKwLXmlTGLKAbeRFJpOHTTs63y
+gcmcuE+vGCpdBHQkaCev8cve1urpJRcxurura6+bYaENO6ua5VzF9BQlDYve0YwY
+lbJiRKmEWEAyULjbIebZW41Z4UqVG3MQI750PRWPW4WJ2kDhksFXN1gwSnaM46KR
+PmVA0SL+RCPcAp/VkImCv0eqv9exsglY0K/QiJfLy3zZ8QvAn0wYgZ3AvH3lr9rJ
+T7pg9WDb+OkfeEQ7INubqSthhaqCLd4zwbMRlpyvg1cMSq0zRvrFpwVlSY85lW4F
+g/tgjJ99W9VZAoIBAH3OYRVDAmrFYCoMn+AzA/RsIOEBqL8kaz/Pfh9K4D01CQ/x
+aqryiqqpFwvXS4fLmaClIMwkvgq/90ulvuCGXeSG52D+NwW58qxQCxgTPhoA9yM9
+VueXKz3I/mpfLNftox8sskxl1qO/nfnu15cXkqVBe4ouD+53ZjhAZPSeQZwHi05h
+CbJ20gl66M+yG+6LZvXE96P8+ZQV80qskFmGdaPozAzdTZ3xzp7D1wegJpTz3j20
+3ULKAiIb5guZNU0tEZz5ikeOqsQt3u6/pVTeDZR0dxnyFUf/oOjmSorSG75WT3sA
+0ZiR0SH5mhFR2Nf1TJ4JHmFaQDMQqo+EG6lEbAECggEAA7kGnuQ0lSCiI3RQV9Wy
+Aa9uAFtyE8/XzJWPaWlnoFk04jtoldIKyzHOsVU0GOYOiyKeTWmMFtTGANre8l51
+izYiTuVBmK+JD/2Z8/fgl8dcoyiqzvwy56kX3QUEO5dcKO48cMohneIiNbB7PnrM
+TpA3OfkwnJQGrX0/66GWrLYP8qmBDv1AIgYMilAa40VdSyZbNTpIdDgfP6bU9Ily
+G7gnyF47HHPt5Cx4ouArbMvV1rof7ytCrfCEhP21Lc46Ryxy81W5ZyzoQfSxfdKb
+GyDR+jkryVRyG69QJf5nCXfNewWbFR4ohVtZ78DNVkjvvLYvr4qxYYLK8PI3YMwL
+sQKCAQB9lo7JadzKVio+C18EfNikOzoriQOaIYowNaaGDw3/9KwIhRsKgoTs+K5O
+gt/gUoPRGd3M2z4hn5j4wgeuFi7HC1MdMWwvgat93h7R1YxiyaOoCTxH1klbB/3K
+4fskdQRxuM8McUebebrp0qT5E0xs2l+ABmt30Dtd3iRrQ5BBjnRc4V//sQiwS1aC
+Yi5eNYCQ96BSAEo1dxJh5RI/QxF2HEPUuoPM8iXrIJhyg9TEEpbrEJcxeagWk02y
+OMEoUbWbX07OzFVvu+aJaN/GlgiogMQhb6IiNTyMlryFUleF+9OBA8xGHqGWA6nR
+OaRA5ZbdE7g7vxKRV36jT3wvD7W+
+-----END PRIVATE KEY-----`
diff --git a/cmix/client.go b/cmix/client.go
index 76fd6377fdee71f9cbe2ffc6fcdb6fdcd8197640..1dd7cff35662ce48e696bd66e06c4ce4b8db4185 100644
--- a/cmix/client.go
+++ b/cmix/client.go
@@ -11,6 +11,11 @@ package cmix
 // and intra-client state are accessible through the context object.
 
 import (
+	"math"
+	"strconv"
+	"sync/atomic"
+	"time"
+
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/cmix/address"
 	"gitlab.com/elixxir/client/cmix/gateway"
@@ -30,10 +35,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
-	"math"
-	"strconv"
-	"sync/atomic"
-	"time"
 )
 
 // fakeIdentityRange indicates the range generated between 0 (most current) and
@@ -81,7 +82,7 @@ type client struct {
 	verboseRounds *RoundTracker
 
 	// Event reporting API
-	events event.Manager
+	events event.Reporter
 
 	// Storage of the max message length
 	maxMsgLen int
@@ -90,11 +91,12 @@ type client struct {
 // NewClient builds a new reception client object using inputted key fields.
 func NewClient(params Params, comms *commClient.Comms, session storage.Session,
 	ndf *ndf.NetworkDefinition, rng *fastRNG.StreamGenerator,
-	events event.Manager) (Client, error) {
+	events event.Reporter) (Client, error) {
 
 	// Start network instance
 	instance, err := commNetwork.NewInstance(
-		comms.ProtoComms, ndf, nil, nil, commNetwork.None, params.FastPolling)
+		comms.ProtoComms, ndf, nil, nil, commNetwork.None,
+		params.FastPolling)
 	if err != nil {
 		return nil, errors.WithMessage(
 			err, "failed to create network client")
diff --git a/cmix/message/pickup.go b/cmix/message/pickup.go
index acba1c0382c1190c8f7524dbdba40852dfa7e415..29fbb95951aea7f4cffbd1c96ba9919ab0d27ee0 100644
--- a/cmix/message/pickup.go
+++ b/cmix/message/pickup.go
@@ -8,11 +8,12 @@
 package message
 
 import (
+	"strconv"
+
 	"gitlab.com/elixxir/client/event"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
-	"strconv"
 
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/stoppable"
@@ -47,13 +48,13 @@ type handler struct {
 
 	inProcess *MeteredCmixMessageBuffer
 
-	events event.Manager
+	events event.Reporter
 
 	FingerprintsManager
 	ServicesManager
 }
 
-func NewHandler(param Params, kv *versioned.KV, events event.Manager,
+func NewHandler(param Params, kv *versioned.KV, events event.Reporter,
 	standardID *id.ID) Handler {
 
 	garbled, err := NewOrLoadMeteredCmixMessageBuffer(kv, inProcessKey)
diff --git a/cmix/nodes/register.go b/cmix/nodes/register.go
index 9cd4502f04a1e9fd16269df09c07f0eb31a1d727..af18976e4402845ea513aae0e8ae400f6683bbb5 100644
--- a/cmix/nodes/register.go
+++ b/cmix/nodes/register.go
@@ -10,6 +10,10 @@ package nodes
 import (
 	"crypto/sha256"
 	"encoding/hex"
+	"strconv"
+	"sync"
+	"time"
+
 	"github.com/golang/protobuf/proto"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
@@ -31,9 +35,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
 	"gitlab.com/xx_network/primitives/netTime"
-	"strconv"
-	"sync"
-	"time"
 )
 
 func registerNodes(r *registrar, s storage.Session, stop *stoppable.Single,
@@ -155,10 +156,9 @@ func requestKey(sender gateway.Sender, comms RegisterNodeCommsInterface,
 
 	grp := r.session.GetCmixGroup()
 
-	// FIXME: Why 256 bits? -- this is spec but not explained, it has to do with
-	//  optimizing operations on one side and still preserves decent security --
-	//  cite this.
-	dhPrivBytes, err := csprng.GenerateInGroup(grp.GetPBytes(), 256, rng)
+	prime := grp.GetPBytes()
+	keyLen := len(prime)
+	dhPrivBytes, err := csprng.GenerateInGroup(prime, keyLen, rng)
 	if err != nil {
 		return nil, nil, 0, err
 	}
diff --git a/cmix/params.go b/cmix/params.go
index bfd0cd1a5011fabd45c06d971da6ddd7112f7527..d823632e199e021606a3414bc2403babcc3d17b9 100644
--- a/cmix/params.go
+++ b/cmix/params.go
@@ -3,13 +3,14 @@ package cmix
 import (
 	"encoding/base64"
 	"encoding/json"
+	"time"
+
 	"gitlab.com/elixxir/client/cmix/message"
 	"gitlab.com/elixxir/client/cmix/pickup"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/primitives/excludedRounds"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
 )
 
 type Params struct {
diff --git a/cmix/rounds/historical.go b/cmix/rounds/historical.go
index 98522670faf6a2635e37d300f5df25db4c451b75..6b4ffbcd727c9b2e8c70b53769fb44c46761dca7 100644
--- a/cmix/rounds/historical.go
+++ b/cmix/rounds/historical.go
@@ -40,7 +40,7 @@ type manager struct {
 
 	comms  Comms
 	sender gateway.Sender
-	events event.Manager
+	events event.Reporter
 
 	c chan roundRequest
 }
@@ -63,7 +63,7 @@ type roundRequest struct {
 }
 
 func NewRetriever(param Params, comms Comms, sender gateway.Sender,
-	events event.Manager) Retriever {
+	events event.Reporter) Retriever {
 	return &manager{
 		params: param,
 		comms:  comms,
@@ -200,7 +200,7 @@ func (m *manager) processHistoricalRounds(comm Comms, stop *stoppable.Single) {
 }
 
 func processHistoricalRoundsResponse(response *pb.HistoricalRoundsResponse,
-	roundRequests []roundRequest, maxRetries uint, events event.Manager) (
+	roundRequests []roundRequest, maxRetries uint, events event.Reporter) (
 	[]uint64, []roundRequest) {
 	retries := make([]roundRequest, 0)
 	rids := make([]uint64, 0)
diff --git a/cmix/sendCmix.go b/cmix/sendCmix.go
index 409ac2dfb34d198c8c8077baf1a27e6b91ff0354..e7267460c916203c529387cb0d7ceb5eb59c4095 100644
--- a/cmix/sendCmix.go
+++ b/cmix/sendCmix.go
@@ -9,6 +9,9 @@ package cmix
 
 import (
 	"fmt"
+	"strings"
+	"time"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/cmix/gateway"
@@ -28,11 +31,9 @@ import (
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/netTime"
 	"gitlab.com/xx_network/primitives/rateLimiting"
-	"strings"
-	"time"
 )
 
-// SendCMIX sends a "raw" cMix message payload to the provided recipient.
+// Send sends a "raw" cMix message payload to the provided recipient.
 // Returns the round ID of the round the payload was sent or an error if it
 // fails.
 // This does not have end-to-end encryption on it and is used exclusively as
@@ -95,7 +96,7 @@ func (c *client) Send(recipient *id.ID, fingerprint format.Fingerprint,
 // status.
 func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID,
 	cmixParams CMIXParams, instance *network.Instance, grp *cyclic.Group,
-	nodes nodes.Registrar, rng *fastRNG.StreamGenerator, events event.Manager,
+	nodes nodes.Registrar, rng *fastRNG.StreamGenerator, events event.Reporter,
 	senderId *id.ID, comms SendCmixCommsInterface) (id.Round, ephemeral.Id, error) {
 
 	timeStart := netTime.Now()
diff --git a/cmix/sendManyCmix.go b/cmix/sendManyCmix.go
index 6e67eff24faa65b815b618d8c6cbef0d5a110b13..01e39d34e881167e224ae78fe65a8bbc18aacee0 100644
--- a/cmix/sendManyCmix.go
+++ b/cmix/sendManyCmix.go
@@ -9,6 +9,9 @@ package cmix
 
 import (
 	"fmt"
+	"strings"
+	"time"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/cmix/gateway"
@@ -27,8 +30,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/netTime"
-	"strings"
-	"time"
 )
 
 // TargetedCmixMessage defines a recipient target pair in a sendMany cMix
@@ -41,7 +42,7 @@ type TargetedCmixMessage struct {
 	Mac         []byte
 }
 
-// SendManyCMIX sends many "raw" cMix message payloads to the provided
+// SendMany sends many "raw" cMix message payloads to the provided
 // recipients all in the same round.
 // Returns the round ID of the round the payloads was sent or an error if it
 // fails.
@@ -110,7 +111,7 @@ type assembledCmixMessage struct {
 func sendManyCmixHelper(sender gateway.Sender,
 	msgs []assembledCmixMessage, param CMIXParams, instance *network.Instance,
 	grp *cyclic.Group, registrar nodes.Registrar,
-	rng *fastRNG.StreamGenerator, events event.Manager,
+	rng *fastRNG.StreamGenerator, events event.Reporter,
 	senderId *id.ID, comms SendCmixCommsInterface) (
 	id.Round, []ephemeral.Id, error) {
 
diff --git a/dummy/utils_test.go b/dummy/utils_test.go
index c6ecaf36b9906501bf1b1c8276c7dd464e2c85ef..73d3c5d0cc28b047ecea26d55e66f44c907069cb 100644
--- a/dummy/utils_test.go
+++ b/dummy/utils_test.go
@@ -8,6 +8,12 @@
 package dummy
 
 import (
+	"io"
+	"math/rand"
+	"sync"
+	"testing"
+	"time"
+
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/cmix/gateway"
 	"gitlab.com/elixxir/client/event"
@@ -25,11 +31,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
-	"io"
-	"math/rand"
-	"sync"
-	"testing"
-	"time"
 )
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -143,7 +144,7 @@ func (tnm *testNetworkManager) SendManyCMIX([]message.TargetedCmixMessage, param
 type dummyEventMgr struct{}
 
 func (d *dummyEventMgr) Report(int, string, string, string) {}
-func (tnm *testNetworkManager) GetEventManager() event.Manager {
+func (tnm *testNetworkManager) GetEventManager() event.Reporter {
 	return &dummyEventMgr{}
 }
 
diff --git a/e2e/manager.go b/e2e/manager.go
index 4fa9e46b21dec8359c5603d72b270410050ba1fc..853303bbe20633da76ff329ee6f6f4a99ec769e1 100644
--- a/e2e/manager.go
+++ b/e2e/manager.go
@@ -3,6 +3,7 @@ package e2e
 import (
 	"encoding/json"
 	"fmt"
+	"strings"
 	"time"
 
 	"github.com/pkg/errors"
@@ -29,7 +30,7 @@ type manager struct {
 	net         cmix.Client
 	myID        *id.ID
 	rng         *fastRNG.StreamGenerator
-	events      event.Manager
+	events      event.Reporter
 	grp         *cyclic.Group
 	crit        *critical
 	rekeyParams rekey.Params
@@ -69,7 +70,7 @@ func initE2E(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int,
 // You can use a memkv for an ephemeral e2e id
 func Load(kv *versioned.KV, net cmix.Client, myID *id.ID,
 	grp *cyclic.Group, rng *fastRNG.StreamGenerator,
-	events event.Manager) (Handler, error) {
+	events event.Reporter) (Handler, error) {
 	kv = kv.Prefix(makeE2ePrefix(myID))
 	return loadE2E(kv, net, myID, grp, rng, events)
 }
@@ -82,7 +83,7 @@ func Load(kv *versioned.KV, net cmix.Client, myID *id.ID,
 // You can use a memkv for an ephemeral e2e id
 func LoadLegacy(kv *versioned.KV, net cmix.Client, myID *id.ID,
 	grp *cyclic.Group, rng *fastRNG.StreamGenerator,
-	events event.Manager, params rekey.Params) (Handler, error) {
+	events event.Reporter, params rekey.Params) (Handler, error) {
 
 	// Marshal the passed params data
 	rekeyParamsData, err := json.Marshal(params)
@@ -93,7 +94,7 @@ func LoadLegacy(kv *versioned.KV, net cmix.Client, myID *id.ID,
 	// Check if values are already written. If they exist on disk/memory already,
 	// this would be a case where LoadLegacy is most likely not the correct
 	// code-path the caller should be following.
-	if _, err := kv.Get(e2eRekeyParamsKey, e2eRekeyParamsVer); err != nil {
+	if _, err := kv.Get(e2eRekeyParamsKey, e2eRekeyParamsVer); err != nil && !strings.Contains(err.Error(), "object not found") {
 		fmt.Printf("err: %v", err)
 		return nil, errors.New("E2E rekey params are already on disk, " +
 			"LoadLegacy should not be called")
@@ -113,7 +114,7 @@ func LoadLegacy(kv *versioned.KV, net cmix.Client, myID *id.ID,
 
 func loadE2E(kv *versioned.KV, net cmix.Client, myDefaultID *id.ID,
 	grp *cyclic.Group, rng *fastRNG.StreamGenerator,
-	events event.Manager) (Handler, error) {
+	events event.Reporter) (Handler, error) {
 
 	m := &manager{
 		Switchboard: receive.New(),
diff --git a/e2e/manager_test.go b/e2e/manager_test.go
index e040ddd8fab4e6bf08195fa168487a5e3bc48999..5367f9b3fd89dd7f562ada8fa2be9dbeb04b0999 100644
--- a/e2e/manager_test.go
+++ b/e2e/manager_test.go
@@ -3,6 +3,7 @@ package e2e
 import (
 	"bytes"
 	"github.com/cloudflare/circl/dh/sidh"
+	"gitlab.com/elixxir/client/e2e/ratchet"
 	"gitlab.com/elixxir/client/e2e/rekey"
 	util "gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/client/storage/versioned"
@@ -95,12 +96,17 @@ func TestLoadLegacy(t *testing.T) {
 	}
 
 	// Construct kv with legacy data
-	fs, err := ekv.NewFilestore("/home/josh/src/client/e2e/legacyEkv", "hello")
+	//fs, err := ekv.NewFilestore("/home/josh/src/client/e2e/legacyEkv", "hello")
+	//if err != nil {
+	//	t.Fatalf(
+	//		"Failed to create storage session: %+v", err)
+	//}
+	kv := versioned.NewKV(ekv.Memstore{})
+
+	err := ratchet.New(kv, myId, myPrivKey, grp)
 	if err != nil {
-		t.Fatalf(
-			"Failed to create storage session: %+v", err)
+		t.Errorf("Failed to init ratchet: %+v", err)
 	}
-	kv := versioned.NewKV(fs)
 
 	rng := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
 
diff --git a/e2e/params.go b/e2e/params.go
index ef54d50ee7cd1148a553055f04c53c4c2cbc9f92..52dd2d7b59f7ad6dffe999f56af84b75ed252bba 100644
--- a/e2e/params.go
+++ b/e2e/params.go
@@ -27,6 +27,9 @@ type Params struct {
 	// system within e2e will be used which preserves privacy
 	CMIX cmix.CMIXParams
 
+	// cMix network params
+	Network cmix.Params
+
 	//Authorizes the message to use a key reserved for rekeying. Do not use
 	//unless sending a rekey
 	Rekey bool
diff --git a/e2e/ratchet/partner/relationship_test.go b/e2e/ratchet/partner/relationship_test.go
index 911a5f711d43eb1af403872d65d6e4ad6a1d2ad7..9591ecea3193a0696b7910a64c130e537550a18c 100644
--- a/e2e/ratchet/partner/relationship_test.go
+++ b/e2e/ratchet/partner/relationship_test.go
@@ -75,7 +75,7 @@ func TestLoadRelationship(t *testing.T) {
 }
 
 // Shows that a deleted Relationship can no longer be pulled from store
-func TestDeleteRelationship(t *testing.T) {
+func Test_deleteRelationship(t *testing.T) {
 	mgr, kv := makeTestRelationshipManager(t)
 
 	// Generate send relationship
@@ -90,7 +90,7 @@ func TestDeleteRelationship(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	err := mgr.DeleteRelationship()
+	err := mgr.deleteRelationships()
 	if err != nil {
 		t.Fatalf("DeleteRelationship error: Could not delete manager: %v", err)
 	}
diff --git a/e2e/ratchet/partner/utils.go b/e2e/ratchet/partner/utils.go
new file mode 100644
index 0000000000000000000000000000000000000000..55a25ab9b2f9da82f655eed4dcf85b2331fffa9a
--- /dev/null
+++ b/e2e/ratchet/partner/utils.go
@@ -0,0 +1,113 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 Privategrity Corporation                                   /
+//                                                                             /
+// All rights reserved.                                                        /
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 Privategrity Corporation                                   /
+//                                                                             /
+// All rights reserved.                                                        /
+////////////////////////////////////////////////////////////////////////////////
+
+package partner
+
+import (
+	"github.com/cloudflare/circl/dh/sidh"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
+	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/xx_network/primitives/id"
+	"testing"
+)
+
+// Test implementation of the Manager interface
+type testManager struct {
+	partnerId                *id.ID
+	grp                      *cyclic.Group
+	partnerPubKey, myPrivKey *cyclic.Int
+}
+
+// NewTestManager allows creation of a Manager interface object for testing purposes
+// Backwards compatibility must be maintained if you make changes here
+// Currently used for: Group chat testing
+func NewTestManager(partnerId *id.ID, partnerPubKey, myPrivKey *cyclic.Int, t *testing.T) Manager {
+	return &testManager{partnerId: partnerId, partnerPubKey: partnerPubKey, myPrivKey: myPrivKey}
+}
+
+func (p *testManager) GetPartnerID() *id.ID {
+	return p.partnerId
+}
+
+func (p *testManager) GetMyID() *id.ID {
+	panic("implement me")
+}
+
+func (p *testManager) GetMyOriginPrivateKey() *cyclic.Int {
+	return p.myPrivKey
+}
+
+func (p *testManager) GetPartnerOriginPublicKey() *cyclic.Int {
+	return p.partnerPubKey
+}
+
+func (p *testManager) GetSendRelationshipFingerprint() []byte {
+	panic("implement me")
+}
+
+func (p *testManager) GetReceiveRelationshipFingerprint() []byte {
+	panic("implement me")
+}
+
+func (p *testManager) GetConnectionFingerprintBytes() []byte {
+	panic("implement me")
+}
+
+func (p *testManager) GetConnectionFingerprint() string {
+	panic("implement me")
+}
+
+func (p *testManager) GetContact() contact.Contact {
+	panic("implement me")
+}
+
+func (p *testManager) PopSendCypher() (*session.Cypher, error) {
+	panic("implement me")
+}
+
+func (p *testManager) PopRekeyCypher() (*session.Cypher, error) {
+	panic("implement me")
+}
+
+func (p *testManager) NewReceiveSession(partnerPubKey *cyclic.Int, partnerSIDHPubKey *sidh.PublicKey, e2eParams session.Params, source *session.Session) (*session.Session, bool) {
+	panic("implement me")
+}
+
+func (p *testManager) NewSendSession(myDHPrivKey *cyclic.Int, mySIDHPrivateKey *sidh.PrivateKey, e2eParams session.Params, source *session.Session) *session.Session {
+	panic("implement me")
+}
+
+func (p *testManager) GetSendSession(sid session.SessionID) *session.Session {
+	panic("implement me")
+}
+
+func (p *testManager) GetReceiveSession(sid session.SessionID) *session.Session {
+	panic("implement me")
+}
+
+func (p *testManager) Confirm(sid session.SessionID) error {
+	panic("implement me")
+}
+
+func (p *testManager) TriggerNegotiations() []*session.Session {
+	panic("implement me")
+}
+
+func (p *testManager) MakeService(tag string) message.Service {
+	panic("implement me")
+}
+
+func (p *testManager) Delete() error {
+	panic("implement me")
+}
diff --git a/e2e/rekey/rekey.go b/e2e/rekey/rekey.go
index 91209bd741f62d039fc9a46276d13ab7727a2a92..8de7ef2daff692cc41914f67c3d8ea7974bb84c9 100644
--- a/e2e/rekey/rekey.go
+++ b/e2e/rekey/rekey.go
@@ -27,7 +27,7 @@ import (
 )
 
 func CheckKeyExchanges(instance *commsNetwork.Instance, grp *cyclic.Group,
-	sendE2E E2eSender, events event.Manager, manager partner.Manager,
+	sendE2E E2eSender, events event.Reporter, manager partner.Manager,
 	param Params, sendTimeout time.Duration) {
 
 	//get all sessions that may need a key exchange
@@ -45,7 +45,7 @@ func CheckKeyExchanges(instance *commsNetwork.Instance, grp *cyclic.Group,
 // session. They run the same negotiation, the former does it on a newly created
 // session while the latter on an extant session
 func trigger(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSender,
-	events event.Manager, manager partner.Manager, inputSession *session.Session,
+	events event.Reporter, manager partner.Manager, inputSession *session.Session,
 	sendTimeout time.Duration, params Params) {
 
 	var negotiatingSession *session.Session
diff --git a/event/event.go b/event/event.go
index 4a15a56fb8aea3968f2d39ff1592d749f8427ee5..1b017009e991c089bd9b7be930759bd2a1d3ffec 100644
--- a/event/event.go
+++ b/event/event.go
@@ -9,10 +9,11 @@ package event
 
 import (
 	"fmt"
+	"sync"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/stoppable"
-	"sync"
 )
 
 // ReportableEvent is used to surface events to client users.
@@ -30,20 +31,20 @@ func (e reportableEvent) String() string {
 }
 
 // Holds state for the event reporting system
-type eventManager struct {
+type Manager struct {
 	eventCh  chan reportableEvent
 	eventCbs sync.Map
 }
 
-func newEventManager() *eventManager {
-	return &eventManager{
+func NewEventManager() *Manager {
+	return &Manager{
 		eventCh: make(chan reportableEvent, 1000),
 	}
 }
 
 // Report reports an event from the client to api users, providing a
 // priority, category, eventType, and details
-func (e *eventManager) Report(priority int, category, evtType, details string) {
+func (e *Manager) Report(priority int, category, evtType, details string) {
 	re := reportableEvent{
 		Priority:  priority,
 		Category:  category,
@@ -61,7 +62,7 @@ func (e *eventManager) Report(priority int, category, evtType, details string) {
 // RegisterEventCallback records the given function to receive
 // ReportableEvent objects. It returns the internal index
 // of the callback so that it can be deleted later.
-func (e *eventManager) RegisterEventCallback(name string,
+func (e *Manager) RegisterEventCallback(name string,
 	myFunc Callback) error {
 	_, existsAlready := e.eventCbs.LoadOrStore(name, myFunc)
 	if existsAlready {
@@ -73,18 +74,18 @@ func (e *eventManager) RegisterEventCallback(name string,
 
 // UnregisterEventCallback deletes the callback identified by the
 // index. It returns an error if it fails.
-func (e *eventManager) UnregisterEventCallback(name string) {
+func (e *Manager) UnregisterEventCallback(name string) {
 	e.eventCbs.Delete(name)
 }
 
-func (e *eventManager) eventService() (stoppable.Stoppable, error) {
+func (e *Manager) EventService() (stoppable.Stoppable, error) {
 	stop := stoppable.NewSingle("EventReporting")
 	go e.reportEventsHandler(stop)
 	return stop, nil
 }
 
 // reportEventsHandler reports events to every registered event callback
-func (e *eventManager) reportEventsHandler(stop *stoppable.Single) {
+func (e *Manager) reportEventsHandler(stop *stoppable.Single) {
 	jww.DEBUG.Print("reportEventsHandler routine started")
 	for {
 		select {
diff --git a/event/event_test.go b/event/event_test.go
index c960f1374b134f5635984a3571e154fb4e901291..d657206bac2cbf2ed761ab454e6728484931a6f6 100644
--- a/event/event_test.go
+++ b/event/event_test.go
@@ -25,8 +25,8 @@ func TestEventReporting(t *testing.T) {
 		evts = append(evts, evt)
 	}
 
-	evtMgr := newEventManager()
-	stop, _ := evtMgr.eventService()
+	evtMgr := NewEventManager()
+	stop, _ := evtMgr.EventService()
 	// Register a callback
 	err := evtMgr.RegisterEventCallback("test", myCb)
 	if err != nil {
diff --git a/event/interface.go b/event/interface.go
index 47e8d9795d7cc63d30b04715b92f0ec842479cf5..867e4dd9c11760474240c27a3661b910b8fe061d 100644
--- a/event/interface.go
+++ b/event/interface.go
@@ -10,7 +10,7 @@ package event
 // Callback defines the callback functions for client event reports
 type Callback func(priority int, category, evtType, details string)
 
-// Manager reporting api (used internally)
-type Manager interface {
+// Reporter reporting api (used internally)
+type Reporter interface {
 	Report(priority int, category, evtType, details string)
 }
diff --git a/groupChat/makeGroup.go b/groupChat/makeGroup.go
index d8f6dd8c32d3f01c97724d497c6b3beafcc44ee0..cc0d22da3119d16a05b7f5dade00cc928ff1cf58 100644
--- a/groupChat/makeGroup.go
+++ b/groupChat/makeGroup.go
@@ -29,7 +29,6 @@ const (
 	makeMembershipErr = "failed to assemble group chat membership: %+v"
 	newIdPreimageErr  = "failed to create group ID preimage: %+v"
 	newKeyPreimageErr = "failed to create group key preimage: %+v"
-	addGroupErr       = "failed to save new group: %+v"
 )
 
 // MaxInitMessageSize is the maximum allowable length of the initial message
@@ -81,16 +80,12 @@ func (m Manager) MakeGroup(membership []*id.ID, name, msg []byte) (gs.Group,
 	// Create new group and add to manager
 	g := gs.NewGroup(
 		name, groupID, groupKey, idPreimage, keyPreimage, msg, created, mem, dkl)
-	if err = m.gs.Add(g); err != nil {
-		return gs.Group{}, nil, NotSent, errors.Errorf(addGroupErr, err)
-	}
 
 	jww.DEBUG.Printf("Created new group %q with ID %s and %d members %s",
 		g.Name, g.ID, len(g.Members), g.Members)
 
 	// Send all group requests
 	roundIDs, status, err := m.sendRequests(g)
-
 	if err == nil {
 		err = m.JoinGroup(g)
 	}
diff --git a/groupChat/makeGroup_test.go b/groupChat/makeGroup_test.go
index eb0676859a739945e6dd2821a97ac4d31da64586..a9541b84471d9d35db12787731916d761f5294e7 100644
--- a/groupChat/makeGroup_test.go
+++ b/groupChat/makeGroup_test.go
@@ -121,7 +121,7 @@ func TestManager_MakeGroup_AddGroupError(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	m, _ := newTestManagerWithStore(prng, gs.MaxGroupChats, 0, nil, nil, t)
 	memberIDs, _, _ := addPartners(m, t)
-	expectedErr := strings.SplitN(addGroupErr, "%", 2)[0]
+	expectedErr := strings.SplitN(joinGroupErr, "%", 2)[0]
 
 	_, _, _, err := m.MakeGroup(memberIDs, []byte{}, []byte{})
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
diff --git a/groupChat/manager.go b/groupChat/manager.go
index c67aae9bcb9c677d05709634ae8aca95e000d95e..19c4de8bbca37c62fb7284e9c52701b865f7abba 100644
--- a/groupChat/manager.go
+++ b/groupChat/manager.go
@@ -44,6 +44,7 @@ type GroupCmix interface {
 		response message.Processor)
 	DeleteService(clientID *id.ID, toDelete message.Service,
 		processor message.Processor)
+	GetMaxMessageLength() int
 }
 
 // GroupE2e is a subset of the e2e.Handler interface containing only the methods needed by GroupChat
diff --git a/groupChat/manager_test.go b/groupChat/manager_test.go
index 9cf51c8bcded7fd73381fff79d05a2cf57027604..5a9c30cdc4db6e31d486bdd54a7a5243b846a30d 100644
--- a/groupChat/manager_test.go
+++ b/groupChat/manager_test.go
@@ -31,7 +31,7 @@ func Test_newManager(t *testing.T) {
 	requestFunc := func(g gs.Group) { requestChan <- g }
 	receiveChan := make(chan MessageReceive)
 	receiveFunc := func(msg MessageReceive) { receiveChan <- msg }
-	m, err := NewManager(nil, nil, user.ID, nil, nil, kv, requestFunc, receiveFunc)
+	m, err := NewManager(nil, newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, requestFunc, receiveFunc)
 	if err != nil {
 		t.Errorf("newManager() returned an error: %+v", err)
 	}
@@ -84,7 +84,7 @@ func Test_newManager_LoadStorage(t *testing.T) {
 		}
 	}
 
-	m, err := NewManager(nil, nil, user.ID, nil, nil, kv, nil, nil)
+	m, err := NewManager(newTestNetworkManager(0, t), newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, nil, nil)
 	if err != nil {
 		t.Errorf("newManager() returned an error: %+v", err)
 	}
@@ -118,7 +118,7 @@ func Test_newManager_LoadError(t *testing.T) {
 
 	expectedErr := strings.SplitN(newGroupStoreErr, "%", 2)[0]
 
-	_, err = NewManager(nil, nil, user.ID, nil, nil, kv, nil, nil)
+	_, err = NewManager(nil, newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, nil, nil)
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
 		t.Errorf("newManager() did not return the expected error."+
 			"\nexpected: %s\nreceived: %+v", expectedErr, err)
diff --git a/groupChat/receive.go b/groupChat/receive.go
index b559a0b0d4776cd70425f86c0744b3b6eac2b5f4..503a52fa79434510348680b442596c1a6b3dff5c 100644
--- a/groupChat/receive.go
+++ b/groupChat/receive.go
@@ -38,7 +38,6 @@ type receptionProcessor struct {
 // Process incoming group chat messages
 func (p *receptionProcessor) Process(message format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) {
 	jww.TRACE.Print("Group message reception received cMix message.")
-
 	// Attempt to read the message
 	roundTimestamp := round.Timestamps[states.QUEUED]
 
@@ -117,7 +116,6 @@ func getCryptKey(key group.Key, salt [group.SaltLen]byte, mac, payload []byte,
 
 	// Compute the current epoch
 	epoch := group.ComputeEpoch(roundTimestamp)
-
 	for _, dhKey := range dhKeys {
 
 		// Create a key with the correct epoch
diff --git a/groupChat/receiveRequest.go b/groupChat/receiveRequest.go
index 127cd9a37ad2297d931974936dc74e279fcf9a53..3a8741d6b0a7e494c137ac53c6f1f7de9834a389 100644
--- a/groupChat/receiveRequest.go
+++ b/groupChat/receiveRequest.go
@@ -89,7 +89,7 @@ func (m *Manager) readRequest(msg receive.Message) (gs.Group, error) {
 
 	// Generate the DH keys with each group member
 	privKey := partner.GetMyOriginPrivateKey()
-	dkl := gs.GenerateDhKeyList(m.gs.GetUser().ID, privKey, membership, m.grp)
+	dkl := gs.GenerateDhKeyList(m.receptionId, privKey, membership, m.grp)
 
 	// Restore the original public key for the leader so that the membership
 	// digest generated later is correct
diff --git a/groupChat/receiveRequest_test.go b/groupChat/receiveRequest_test.go
index 265309f6e92fe1057e495143029550b4f9360325..398de2f495a348b2f34323cadee1d060074834e0 100644
--- a/groupChat/receiveRequest_test.go
+++ b/groupChat/receiveRequest_test.go
@@ -66,7 +66,7 @@ func TestRequestListener_Hear(t *testing.T) {
 	_, _ = m.e2e.AddPartner(
 		g.Members[0].ID,
 		g.Members[0].DhKey,
-		m.grp.NewInt(2),
+		m.e2e.GetHistoricalDHPrivkey(),
 		theirSIDHPubKey, mySIDHPrivKey,
 		session.GetDefaultParams(),
 		session.GetDefaultParams(),
@@ -165,7 +165,7 @@ func TestManager_readRequest(t *testing.T) {
 	_, _ = m.e2e.AddPartner(
 		g.Members[0].ID,
 		g.Members[0].DhKey,
-		m.grp.NewInt(2),
+		m.e2e.GetHistoricalDHPrivkey(),
 		theirSIDHPubKey, mySIDHPrivKey,
 		session.GetDefaultParams(),
 		session.GetDefaultParams(),
diff --git a/groupChat/send.go b/groupChat/send.go
index dfcc522ef11627cd3ccb32648e8b7549f1a45858..64796dd35111424ff438b5ce2b6d7f721cb2083d 100644
--- a/groupChat/send.go
+++ b/groupChat/send.go
@@ -27,7 +27,6 @@ import (
 const (
 	newCmixMsgErr     = "failed to generate cMix messages for group chat: %+v"
 	sendManyCmixErr   = "failed to send group chat message from member %s to group %s: %+v"
-	newCmixErr        = "failed to generate cMix message for member %d with ID %s in group %s: %+v"
 	messageLenErr     = "message length %d is greater than maximum message space %d"
 	newNoGroupErr     = "failed to create message for group %s that cannot be found"
 	newKeyErr         = "failed to generate key for encrypting group payload"
@@ -94,7 +93,7 @@ func (m *Manager) newMessages(g gs.Group, msg []byte, timestamp time.Time) (
 		}
 
 		// Add cMix message to list
-		cMixMsg, err := newCmixMsg(g, msg, timestamp, member, rng, m.receptionId, m.grp)
+		cMixMsg, err := newCmixMsg(g, msg, timestamp, member, rng, m.receptionId, m.services.GetMaxMessageLength())
 		if err != nil {
 			return nil, err
 		}
@@ -106,7 +105,7 @@ func (m *Manager) newMessages(g gs.Group, msg []byte, timestamp time.Time) (
 
 // newCmixMsg generates a new cMix message to be sent to a group member.
 func newCmixMsg(g gs.Group, msg []byte, timestamp time.Time,
-	mem group.Member, rng io.Reader, senderId *id.ID, grp *cyclic.Group) (cmix.TargetedCmixMessage, error) {
+	mem group.Member, rng io.Reader, senderId *id.ID, maxCmixMessageSize int) (cmix.TargetedCmixMessage, error) {
 
 	// Initialize targeted message
 	cmixMsg := cmix.TargetedCmixMessage{
@@ -119,7 +118,7 @@ func newCmixMsg(g gs.Group, msg []byte, timestamp time.Time,
 	}
 
 	// Create three message layers
-	pubMsg, intlMsg, err := newMessageParts(grp.GetP().ByteLen())
+	pubMsg, intlMsg, err := newMessageParts(maxCmixMessageSize)
 	if err != nil {
 		return cmixMsg, err
 	}
diff --git a/groupChat/sendRequests.go b/groupChat/sendRequests.go
index f87b53bb9b3d3c761145897d2c70c2dcd01f02e0..3bc201d41ecd77df369a85ba44a47056c456e22d 100644
--- a/groupChat/sendRequests.go
+++ b/groupChat/sendRequests.go
@@ -118,7 +118,7 @@ func (m Manager) sendRequest(memberID *id.ID, request []byte) ([]id.Round, error
 	p.LastServiceTag = catalog.GroupRq
 	p.CMIX.DebugTag = "group.Request"
 
-	rounds, _, _, err := m.e2e.SendE2E(catalog.GroupCreationRequest, m.receptionId, request, p)
+	rounds, _, _, err := m.e2e.SendE2E(catalog.GroupCreationRequest, memberID, request, p)
 	if err != nil {
 		return nil, errors.Errorf(sendE2eErr, memberID, err)
 	}
diff --git a/groupChat/send_test.go b/groupChat/send_test.go
index ec257fd4e11dd2bbadc9f614fcb5b1afc12c4972..72d98232909c7d10f401e7805b0be4ef52393765 100644
--- a/groupChat/send_test.go
+++ b/groupChat/send_test.go
@@ -10,11 +10,12 @@ package groupChat
 import (
 	"bytes"
 	"encoding/base64"
-	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	gs "gitlab.com/elixxir/client/groupChat/groupStore"
 	"gitlab.com/elixxir/crypto/group"
 	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
@@ -50,8 +51,10 @@ func TestManager_Send(t *testing.T) {
 		t.Error("No group cMix messages received.")
 	}
 
+	timestamps := make(map[states.Round]time.Time)
+	timestamps[states.QUEUED] = netTime.Now().Round(0)
 	for _, msg := range messages {
-		reception.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{ID: roundId})
+		reception.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{ID: roundId, Timestamps: timestamps})
 		select {
 		case result := <-receiveChan:
 			if !result.SenderID.Cmp(m.receptionId) {
@@ -70,26 +73,13 @@ func TestManager_Send(t *testing.T) {
 	}
 }
 
-// Error path: an error is returned when Manager.neCmixMsg returns an error.
-func TestGroup_newMessages_NewCmixMsgError(t *testing.T) {
-	expectedErr := strings.SplitN(newCmixErr, "%", 2)[0]
-	prng := rand.New(rand.NewSource(42))
-	m, g := newTestManager(prng, t)
-
-	_, err := m.newMessages(g, make([]byte, 1000), netTime.Now())
-	if err == nil || !strings.Contains(err.Error(), expectedErr) {
-		t.Errorf("newMessages() failed to return the expected error."+
-			"\nexpected: %s\nreceived: %+v", expectedErr, err)
-	}
-}
-
 // Error path: reader returns an error.
 func TestGroup_newCmixMsg_SaltReaderError(t *testing.T) {
 	expectedErr := strings.SplitN(saltReadErr, "%", 2)[0]
-	m := &Manager{}
+	m, _ := newTestManager(rand.New(rand.NewSource(42)), t)
 
-	_, err := newCmixMsg(gs.Group{},
-		[]byte{}, time.Time{}, group.Member{}, strings.NewReader(""), m.receptionId, m.grp)
+	_, err := newCmixMsg(gs.Group{ID: id.NewIdFromString("test", id.User, t)},
+		[]byte{}, time.Time{}, group.Member{}, strings.NewReader(""), m.receptionId, m.services.GetMaxMessageLength())
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
 		t.Errorf("newCmixMsg() failed to return the expected error"+
 			"\nexpected: %s\nreceived: %+v", expectedErr, err)
@@ -102,15 +92,15 @@ func TestGroup_newCmixMsg_InternalMsgSizeError(t *testing.T) {
 
 	// Create new test Manager and Group
 	prng := rand.New(rand.NewSource(42))
-	m, g := newTestManager(prng, t)
+	m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t)
 
 	// Create test parameters
-	testMsg := make([]byte, 341)
+	testMsg := make([]byte, 1500)
 	mem := group.Member{ID: id.NewIdFromString("memberID", id.User, t)}
 
 	// Create cMix message
 	prng = rand.New(rand.NewSource(42))
-	_, err := newCmixMsg(g, testMsg, netTime.Now(), mem, prng, m.receptionId, m.grp)
+	_, err := newCmixMsg(g, testMsg, netTime.Now(), mem, prng, m.receptionId, m.services.GetMaxMessageLength())
 	if err == nil || !strings.Contains(err.Error(), expectedErr) {
 		t.Errorf("newCmixMsg() failed to return the expected error"+
 			"\nexpected: %s\nreceived: %+v", expectedErr, err)
diff --git a/groupChat/utils_test.go b/groupChat/utils_test.go
index 4854e56500b3964a01628475f8e9a17d69a86264..002dbb17f28fb5170d511b66126b926280beeb53 100644
--- a/groupChat/utils_test.go
+++ b/groupChat/utils_test.go
@@ -9,6 +9,11 @@ package groupChat
 
 import (
 	"encoding/base64"
+	"math/rand"
+	"sync"
+	"testing"
+	"time"
+
 	"github.com/cloudflare/circl/dh/sidh"
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/catalog"
@@ -34,10 +39,6 @@ import (
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
 	"gitlab.com/xx_network/primitives/netTime"
-	"math/rand"
-	"sync"
-	"testing"
-	"time"
 )
 
 // newTestManager creates a new Manager for testing.
@@ -47,19 +48,15 @@ func newTestManager(rng *rand.Rand, t *testing.T) (*Manager, gs.Group) {
 		rng:         fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 		grp:         getGroup(),
 		services:    newTestNetworkManager(0, t),
-		e2e: &testE2eManager{
-			e2eMessages: []testE2eMessage{},
-			errSkip:     0,
-			sendErr:     0,
-		},
+		e2e:         newTestE2eManager(randCycInt(rng)),
 	}
 	user := group.Member{
 		ID:    m.receptionId,
-		DhKey: randCycInt(rng),
+		DhKey: m.e2e.GetHistoricalDHPubkey(),
 	}
 
 	g := newTestGroupWithUser(m.grp, user.ID, user.DhKey,
-		randCycInt(rng), rng, t)
+		m.e2e.GetHistoricalDHPrivkey(), rng, t)
 	gStore, err := gs.NewStore(versioned.NewKV(make(ekv.Memstore)), user)
 	if err != nil {
 		t.Fatalf("Failed to create new group store: %+v", err)
@@ -84,14 +81,15 @@ func newTestManagerWithStore(rng *rand.Rand, numGroups int, sendErr int,
 		services:    newTestNetworkManager(sendErr, t),
 		e2e: &testE2eManager{
 			e2eMessages: []testE2eMessage{},
-			errSkip:     0,
 			sendErr:     sendErr,
+			grp:         getGroup(),
+			dhPubKey:    randCycInt(rng),
+			partners:    make(map[id.ID]partner.Manager),
 		},
 	}
-
 	user := group.Member{
 		ID:    m.receptionId,
-		DhKey: randCycInt(rng),
+		DhKey: m.e2e.GetHistoricalDHPubkey(),
 	}
 
 	gStore, err := gs.NewStore(versioned.NewKV(make(ekv.Memstore)), user)
@@ -111,6 +109,16 @@ func newTestManagerWithStore(rng *rand.Rand, numGroups int, sendErr int,
 	return m, g
 }
 
+func newTestE2eManager(dhPubKey *cyclic.Int) *testE2eManager {
+	return &testE2eManager{
+		e2eMessages: []testE2eMessage{},
+		errSkip:     0,
+		grp:         getGroup(),
+		dhPubKey:    dhPubKey,
+		partners:    make(map[id.ID]partner.Manager),
+	}
+}
+
 // getMembership returns a Membership with random members for testing.
 func getMembership(size int, uid *id.ID, pubKey *cyclic.Int, grp *cyclic.Group,
 	prng *rand.Rand, t *testing.T) group.Membership {
@@ -219,6 +227,7 @@ func newTestNetworkManager(sendErr int, t *testing.T) GroupCmix {
 	return &testNetworkManager{
 		receptionMessages: [][]format.Message{},
 		sendMessages:      [][]cmix.TargetedCmixMessage{},
+		grp:               getGroup(),
 		sendErr:           sendErr,
 	}
 }
@@ -226,8 +235,11 @@ func newTestNetworkManager(sendErr int, t *testing.T) GroupCmix {
 // testE2eManager is a test implementation of NetworkManager interface.
 type testE2eManager struct {
 	e2eMessages []testE2eMessage
+	partners    map[id.ID]partner.Manager
 	errSkip     int
 	sendErr     int
+	dhPubKey    *cyclic.Int
+	grp         *cyclic.Group
 	sync.RWMutex
 }
 
@@ -237,20 +249,27 @@ type testE2eMessage struct {
 }
 
 func (tnm *testE2eManager) AddPartner(partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.Int,
-	partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey, sendParams, receiveParams session.Params) (partner.Manager, error) {
-	return nil, nil
+	partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey,
+	sendParams, receiveParams session.Params) (partner.Manager, error) {
+
+	testPartner := partner.NewTestManager(partnerID, partnerPubKey, myPrivKey, &testing.T{})
+	tnm.partners[*partnerID] = testPartner
+	return testPartner, nil
 }
 
 func (tnm *testE2eManager) GetPartner(partnerID *id.ID) (partner.Manager, error) {
-	return nil, nil
+	if partner, ok := tnm.partners[*partnerID]; ok {
+		return partner, nil
+	}
+	return nil, errors.New("Unable to find partner")
 }
 
 func (tnm *testE2eManager) GetHistoricalDHPubkey() *cyclic.Int {
-	panic("implement me")
+	return tnm.dhPubKey
 }
 
 func (tnm *testE2eManager) GetHistoricalDHPrivkey() *cyclic.Int {
-	panic("implement me")
+	return tnm.dhPubKey
 }
 
 func (tnm *testE2eManager) SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, params clientE2E.Params) ([]id.Round, e2e.MessageID, time.Time, error) {
@@ -273,11 +292,11 @@ func (tnm *testE2eManager) SendE2E(mt catalog.MessageType, recipient *id.ID, pay
 }
 
 func (*testE2eManager) RegisterListener(user *id.ID, messageType catalog.MessageType, newListener receive.Listener) receive.ListenerID {
-	panic("implement me")
+	return receive.ListenerID{}
 }
 
 func (*testE2eManager) AddService(tag string, processor message.Processor) error {
-	panic("implement me")
+	return nil
 }
 
 func (*testE2eManager) GetDefaultHistoricalDHPubkey() *cyclic.Int {
@@ -300,9 +319,14 @@ type testNetworkManager struct {
 	sendMessages      [][]cmix.TargetedCmixMessage
 	errSkip           int
 	sendErr           int
+	grp               *cyclic.Group
 	sync.RWMutex
 }
 
+func (tnm *testNetworkManager) GetMaxMessageLength() int {
+	return format.NewMessage(tnm.grp.GetP().ByteLen()).ContentsSize()
+}
+
 func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
 	if tnm.sendErr == 1 {
 		return 0, nil, errors.New("SendManyCMIX error")
@@ -315,7 +339,7 @@ func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, p c
 
 	receiveMessages := []format.Message{}
 	for _, msg := range messages {
-		receiveMsg := format.Message{}
+		receiveMsg := format.NewMessage(tnm.grp.GetP().ByteLen())
 		receiveMsg.SetMac(msg.Mac)
 		receiveMsg.SetContents(msg.Payload)
 		receiveMsg.SetKeyFP(msg.Fingerprint)
@@ -326,17 +350,17 @@ func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, p c
 }
 
 func (*testNetworkManager) AddService(clientID *id.ID, newService message.Service, response message.Processor) {
-	panic("implement me")
+	return
 }
 
 func (*testNetworkManager) DeleteService(clientID *id.ID, toDelete message.Service, processor message.Processor) {
-	panic("implement me")
+	return
 }
 
 type dummyEventMgr struct{}
 
 func (d *dummyEventMgr) Report(int, string, string, string) {}
-func (tnm *testNetworkManager) GetEventManager() event.Manager {
+func (tnm *testNetworkManager) GetEventManager() event.Reporter {
 	return &dummyEventMgr{}
 }
 
diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go
index b5104d1018151632d4d1ae41767378333990d1bd..1315c7d710571d694f6ca77d7b0222e2e50aa0f9 100644
--- a/interfaces/networkManager.go
+++ b/interfaces/networkManager.go
@@ -8,13 +8,14 @@
 package interfaces
 
 import (
+	"time"
+
 	"gitlab.com/elixxir/comms/network"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/ndf"
-	"time"
 
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/interfaces/params"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/message"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/primitives/format"
@@ -29,24 +30,26 @@ type NetworkManager interface {
 	// Only one follower may run at a time.
 	Follow(report ClientErrorReport) (stoppable.Stoppable, error)
 
-	/*===Sending==============================================================*/
+	/*===Sending==========================================================*/
 
-	// SendCMIX sends a "raw" CMIX message payload to the provided recipient.
-	// Returns the round ID of the round the payload was sent or an error
-	// if it fails.
-	SendCMIX(message format.Message, recipient *id.ID, p params.CMIX) (
+	// SendCMIX sends a "raw" CMIX message payload to the provided
+	// recipient.  Returns the round ID of the round the payload
+	// was sent or an error if it fails.
+	SendCMIX(message format.Message, recipient *id.ID, p cmix.Params) (
 		id.Round, ephemeral.Id, error)
 
-	// SendManyCMIX sends many "raw" cMix message payloads to each of the provided
-	// recipients. Used to send messages in group chats. Metadata is NOT as well
-	// protected with this call and can leak data about yourself. Should be
-	// replaced with multiple uses of SendCmix in most cases. Returns the round
-	// ID of the round the payload was sent or an error if it fails.
+	// SendManyCMIX sends many "raw" cMix message payloads to each
+	// of the provided recipients. Used to send messages in group
+	// chats. Metadata is NOT as well protected with this call and
+	// can leak data about yourself. Should be replaced with
+	// multiple uses of SendCmix in most cases. Returns the round
+	// ID of the round the payload was sent or an error if it
+	// fails.
 	// WARNING: Potentially Unsafe
-	SendManyCMIX(messages []message.TargetedCmixMessage, p params.CMIX) (
+	SendManyCMIX(messages []cmix.TargetedCmixMessage, p cmix.Params) (
 		id.Round, []ephemeral.Id, error)
 
-	/*===Message Reception====================================================*/
+	/*===Message Reception================================================*/
 	/* Identities are all network identites which the client is currently
 	trying to pick up message on. An identity must be added
 	to receive messages, fake ones will be used to poll the network
@@ -60,23 +63,24 @@ type NetworkManager interface {
 	// RemoveIdentity removes a currently tracked identity.
 	RemoveIdentity(id *id.ID)
 
-	/* Fingerprints are the primary mechanism of identifying a picked up
-	message over cMix. They are a unique one time use 255 bit vector generally
-	associated with a specific encryption key, but can be used for an
-	alternative protocol.When registering a fingerprint, a MessageProcessor
-	is registered to handle the message.*/
+	/* Fingerprints are the primary mechanism of identifying a
+	picked up message over cMix. They are a unique one time use
+	255 bit vector generally associated with a specific encryption
+	key, but can be used for an alternative protocol.When
+	registering a fingerprint, a MessageProcessor is registered to
+	handle the message.*/
 
 	// AddFingerprint - Adds a fingerprint which will be handled by a
 	// specific processor for messages received by the given identity
 	AddFingerprint(identity *id.ID, fingerprint format.Fingerprint,
-		mp MessageProcessor) error
+		mp message.Processor) error
 
-	// DeleteFingerprint deletes a single fingerprint associated with the given
-	// identity if it exists
+	// DeleteFingerprint deletes a single fingerprint associated
+	// with the given identity if it exists
 
 	DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint)
-	// DeleteClientFingerprints deletes al fingerprint associated with the given
-	// identity if it exists
+	// DeleteClientFingerprints deletes al fingerprint associated
+	// with the given identity if it exists
 	DeleteClientFingerprints(identity *id.ID)
 
 	/* trigger - predefined hash based tags appended to all cMix messages
@@ -87,60 +91,72 @@ type NetworkManager interface {
 	notifications system, or can be used to implement custom non fingerprint
 	processing of payloads. I.E. key negotiation, broadcast negotiation
 
-	A tag is appended to the message of the format tag = H(H(messageContents),
-	preimage) and trial hashing is used to determine if a message adheres to a
-	tag.
-	WARNING: If a preimage is known by an adversary, they can determine which
-	messages are for the client on reception (which is normally hidden due to
-	collision between ephemeral IDs.
+	A tag is appended to the message of the format tag =
+	H(H(messageContents), preimage) and trial hashing is used to
+	determine if a message adheres to a tag.
 
-	Due to the extra overhead of trial hashing, triggers are processed after fingerprints.
-	If a fingerprint match occurs on the message, triggers will not be handled.
+	WARNING: If a preimage is known by an adversary, they can
+	determine which messages are for the client on reception
+	(which is normally hidden due to collision between ephemeral
+	IDs.
 
-	Triggers are address to the session. When starting a new client, all triggers must be
-	re-added before StartNetworkFollower is called.
+	Due to the extra overhead of trial hashing, triggers are
+	processed after fingerprints.  If a fingerprint match occurs
+	on the message, triggers will not be handled.
+
+	Triggers are address to the session. When starting a new
+	client, all triggers must be re-added before
+	StartNetworkFollower is called.
 	*/
 
-	// AddTrigger - Adds a trigger which can call a message handing function or
-	// be used for notifications. Multiple triggers can be registered for the
-	// same preimage.
+	// AddTrigger - Adds a trigger which can call a message
+	// handing function or be used for notifications. Multiple
+	// triggers can be registered for the same preimage.
 	//   preimage - the preimage which is triggered on
-	//   type - a descriptive string of the trigger. Generally used in notifications
-	//   source - a byte buffer of related data. Generally used in notifications.
+	//   type - a descriptive string of the trigger. Generally
+	//          used in notifications
+	//   source - a byte buffer of related data. Generally used in
+	//            notifications.
 	//     Example: Sender ID
-	AddTrigger(identity *id.ID, newTrigger Trigger, response MessageProcessor)
+	AddTrigger(identity *id.ID, newTrigger message.Service,
+		response message.Processor)
 
 	// DeleteTrigger - If only a single response is associated with the
 	// preimage, the entire preimage is removed. If there is more than one
 	// response, only the given response is removed if nil is passed in for
 	// response, all triggers for the preimage will be removed
-	DeleteTrigger(identity *id.ID, preimage Preimage, response MessageProcessor) error
+	DeleteTrigger(identity *id.ID, preimage Preimage,
+		response message.Processor) error
 
-	// DeleteClientTriggers - deletes all triggers assoseated with the given identity
+	// DeleteClientTriggers - deletes all triggers assoseated with
+	// the given identity
 	DeleteClientTriggers(identity *id.ID)
 
-	// TrackTriggers - Registers a callback which will get called every time triggers change.
+	// TrackTriggers - Registers a callback which will get called
+	// every time triggers change.
 	// It will receive the triggers list every time it is modified.
 	// Will only get callbacks while the Network Follower is running.
 	// Multiple trackTriggers can be registered
-	TrackTriggers(TriggerTracker)
+	TrackServices(message.ServicesTracker)
 
 	/* In inProcess */
-	// it is possible to receive a message over cMix before the fingerprints or
-	// triggers are registered. As a result, when handling fails, messages are
-	// put in the inProcess que for a set number of retries.
+	// it is possible to receive a message over cMix before the
+	// fingerprints or triggers are registered. As a result, when
+	// handling fails, messages are put in the inProcess que for a
+	// set number of retries.
 
 	// CheckInProgressMessages - retry processing all messages in check in
 	// progress messages. Call this after adding fingerprints or triggers
 	//while the follower is running.
 	CheckInProgressMessages()
 
-	/*===Nodes================================================================*/
-	/* Keys must be registed with nodes in order to send messages throug them.
-	this process is in general automatically handled by the Network Manager*/
+	/*===Nodes============================================================*/
+	/* Keys must be registed with nodes in order to send messages
+	throug them.  this process is in general automatically handled
+	by the Network Manager*/
 
-	// HasNode can be used to determine if a keying relationship exists with a
-	// node.
+	// HasNode can be used to determine if a keying relationship
+	// exists with a node.
 	HasNode(nid *id.ID) bool
 
 	// NumRegisteredNodes Returns the total number of nodes we have a keying
@@ -150,7 +166,7 @@ type NetworkManager interface {
 	// Triggers the generation of a keying relationship with a given node
 	TriggerNodeRegistration(nid *id.ID)
 
-	/*===Historical Rounds====================================================*/
+	/*===Historical Rounds================================================*/
 	/* A complete set of round info is not kept on the client, and sometimes
 	the network will need to be queried to get round info. Historical rounds
 	is the system internal to the Network Manager to do this.
@@ -158,52 +174,59 @@ type NetworkManager interface {
 
 	// LookupHistoricalRound - looks up the passed historical round on the
 	// network
-	LookupHistoricalRound(rid id.Round, callback func(info *mixmessages.RoundInfo,
-		success bool)) error
+	LookupHistoricalRound(rid id.Round,
+		callback func(info *mixmessages.RoundInfo,
+			success bool)) error
 
-	/*===Sender===============================================================*/
-	/* The sender handles sending comms to the network. It tracks connections to
-	gateways and handles proxying to gateways for targeted comms. It can be
-	used externally to contact gateway directly, bypassing the majority of
-	the network package*/
+	/*===Sender===========================================================*/
+	/* The sender handles sending comms to the network. It tracks
+	connections to gateways and handles proxying to gateways for
+	targeted comms. It can be used externally to contact gateway
+	directly, bypassing the majority of the network package*/
 
 	// SendToAny can be used to send the comm to any gateway in the network.
-	SendToAny(sendFunc func(host *connect.Host) (interface{}, error), stop *stoppable.Single) (interface{}, error)
+	SendToAny(sendFunc func(host *connect.Host) (interface{}, error),
+		stop *stoppable.Single) (interface{}, error)
 
 	// SendToPreferred sends to a specific gateway, doing so through another
 	// gateway as a proxy if not directly connected.
 	SendToPreferred(targets []*id.ID, sendFunc func(host *connect.Host,
 		target *id.ID, timeout time.Duration) (interface{}, error),
-		stop *stoppable.Single, timeout time.Duration) (interface{}, error)
+		stop *stoppable.Single, timeout time.Duration) (interface{},
+		error)
 
-	// SetGatewayFilter sets a function which will be used to filter gateways
-	// before connecting.
+	// SetGatewayFilter sets a function which will be used to
+	// filter gateways before connecting.
 	SetGatewayFilter(f func(map[id.ID]int,
 		*ndf.NetworkDefinition) map[id.ID]int)
 
-	// GetHostParams - returns the host params used when connectign to gateways
+	// GetHostParams - returns the host params used when
+	// connectign to gateways
 	GetHostParams() connect.HostParams
 
-	/*===Address Space========================================================*/
-	// The network compasses identities into a smaller address space to cause
-	// collisions and hide the actual recipient of messages. These functions
-	// allow for the tracking of this addresses space. In general, address space
-	// issues are completely handled by the network package
+	/*===Address Space====================================================*/
+	// The network compasses identities into a smaller address
+	// space to cause collisions and hide the actual recipient of
+	// messages. These functions allow for the tracking of this
+	// addresses space. In general, address space issues are
+	// completely handled by the network package
 
-	// GetAddressSpace GetAddressSize returns the current address size of IDs. Blocks until an
-	// address size is known.
+	// GetAddressSpace GetAddressSize returns the current address
+	// size of IDs. Blocks until an address size is known.
 	GetAddressSpace() uint8
 
-	// RegisterAddressSpaceNotification returns a channel that will trigger for
-	// every address space size update. The provided tag is the unique ID for
-	// the channel. Returns an error if the tag is already used.
+	// RegisterAddressSpaceNotification returns a channel that
+	// will trigger for every address space size update. The
+	// provided tag is the unique ID for the channel. Returns an
+	// error if the tag is already used.
 	RegisterAddressSpaceNotification(tag string) (chan uint8, error)
 
-	// UnregisterAddressSpaceNotification stops broadcasting address space size
-	// updates on the channel with the specified tag.
+	// UnregisterAddressSpaceNotification stops broadcasting
+	// address space size updates on the channel with the
+	// specified tag.
 	UnregisterAddressSpaceNotification(tag string)
 
-	/*===Accessors============================================================*/
+	/*===Accessors========================================================*/
 
 	// GetInstance returns the network instance object, which tracks the
 	// state of the network
@@ -218,8 +241,3 @@ type NetworkManager interface {
 }
 
 type Preimage [32]byte
-
-type ClientErrorReport func(source, message, trace string)
-
-//for use in key exchange which needs to be callable inside of network
-///type SendE2E func(m message.Send, p params.E2E, stop *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error)
diff --git a/interfaces/switchboard.go b/interfaces/switchboard.go
deleted file mode 100644
index 2566bfb51de98fe6f5ce6abf0b1038b752f78a74..0000000000000000000000000000000000000000
--- a/interfaces/switchboard.go
+++ /dev/null
@@ -1,75 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package interfaces
-
-import (
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/switchboard"
-	"gitlab.com/xx_network/primitives/id"
-)
-
-// public switchboard interface which only allows registration and does not
-// allow speaking messages
-type Switchboard interface {
-	// 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 Receive.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.
-	RegisterListener(user *id.ID, messageType message.Type,
-		newListener switchboard.Listener) switchboard.ListenerID
-
-	// 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 Receive.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.
-	RegisterFunc(name string, user *id.ID, messageType message.Type,
-		newListener switchboard.ListenerFunc) switchboard.ListenerID
-
-	// 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 Receive.AnyType
-	// newListener: an item channel.
-	// Do not pass nil to this.
-	//
-	// If a message matches multiple listeners, all of them will hear the
-	// message.
-	RegisterChannel(name string, user *id.ID, messageType message.Type,
-		newListener chan message.Receive) switchboard.ListenerID
-
-	// Unregister removes the listener with the specified ID so it will no
-	// longer get called
-	Unregister(listenerID switchboard.ListenerID)
-}
diff --git a/interfaces/user/proto.go b/interfaces/user/proto.go
deleted file mode 100644
index 657c2e714d70f06b88c6d0866ec2bbca5015f24e..0000000000000000000000000000000000000000
--- a/interfaces/user/proto.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package user
-
-import (
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
-)
-
-type Proto struct {
-	//General Identity
-	TransmissionID   *id.ID
-	TransmissionSalt []byte
-	TransmissionRSA  *rsa.PrivateKey
-	ReceptionID      *id.ID
-	ReceptionSalt    []byte
-	ReceptionRSA     *rsa.PrivateKey
-	Precanned        bool
-	// Timestamp in which user has registered with the network
-	RegistrationTimestamp int64
-
-	RegCode string
-
-	TransmissionRegValidationSig []byte
-	ReceptionRegValidationSig    []byte
-
-	//e2e Identity
-	E2eDhPrivateKey *cyclic.Int
-	E2eDhPublicKey  *cyclic.Int
-}
diff --git a/single/listener.go b/single/listener.go
index cf49e7868711c205a40fbdcc92be0b2507e30165..d2f17233abbe1985a6e89cc73add5818108a262e 100644
--- a/single/listener.go
+++ b/single/listener.go
@@ -32,6 +32,11 @@ type listener struct {
 	net       cmix.Client
 }
 
+// Listen allows a server to listen for single use requests. It will register
+// a service relative to the tag and myID as the identifier.  Only a single
+// listener can be active for a tag-myID pair, and error will return if that
+// is violated. When requests are receved, they will be called on the
+// Receiver interface.
 func Listen(tag string, myId *id.ID, privkey *cyclic.Int, net cmix.Client,
 	e2eGrp *cyclic.Group, cb Receiver) Listener {
 
diff --git a/single/message/request.go b/single/message/request.go
index a09d07223feb414fc63b792f9909cc61ebac62ae..60f372e8b3aa8deab89a315cd2f32b5d0e2044bd 100644
--- a/single/message/request.go
+++ b/single/message/request.go
@@ -55,6 +55,10 @@ func NewRequest(externalPayloadSize, pubKeySize int) Request {
 	return tm
 }
 
+func GetRequestPayloadSize(externalPayloadSize, pubKeySize int) uint {
+	return uint(externalPayloadSize - transmitMessageVersionSize - pubKeySize)
+}
+
 // mapRequest builds a message mapped to the passed in data. It is
 // mapped by reference; a copy is not made.
 func mapRequest(data []byte, pubKeySize int) Request {
@@ -160,6 +164,10 @@ func NewRequestPayload(payloadSize int, payload []byte, maxMsgs uint8) RequestPa
 	return mp
 }
 
+func GetRequestContentsSize(payloadSize uint) uint {
+	return payloadSize - transmitPlMinSize
+}
+
 // mapRequestPayload builds a message payload mapped to the passed in
 // data. It is mapped by reference; a copy is not made.
 func mapRequestPayload(data []byte) RequestPayload {
diff --git a/single/receivedRequest.go b/single/receivedRequest.go
index 7ac766881b991c84bb7b73e041e759d964a8827c..c425cc9dd2da4dd4f45d89b678778041d7a463d9 100644
--- a/single/receivedRequest.go
+++ b/single/receivedRequest.go
@@ -66,7 +66,10 @@ func (r Request) String() string {
 		r.dhKey.Text(10), r.tag, r.maxParts)
 }
 
-//
+// Respond is used to respond to the request. It sends a payload up to
+// r.GetMaxResponseLength(). It will chunk the message into multiple
+// cmix messages if it is too long for a single message. It will fail
+// If a single cmix message cannot be sent.
 func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams,
 	timeout time.Duration) ([]id.Round, error) {
 	// make sure this has only been run once
@@ -108,8 +111,6 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams,
 	failed := uint32(0)
 
 	for i := 0; i < len(parts); i++ {
-		// fixme: handle the case where a send fails, also on failures,
-		// unset use
 		go func(j int) {
 			defer wg.Done()
 			partFP, ecrPart, mac := cyphers[j].Encrypt(parts[j])
diff --git a/single/request.go b/single/request.go
index c464eec421366c72a44e0c462900458d2e21bdf3..cd8a5c04a27857730205bccdc7633238bf3264d0 100644
--- a/single/request.go
+++ b/single/request.go
@@ -21,20 +21,61 @@ import (
 	"time"
 )
 
+// Response interface allows for callbacks to
 type Response interface {
 	Callback(payload []byte, receptionID receptionID.EphemeralIdentity,
 		round rounds.Round, err error)
 }
 
 type RequestParams struct {
-	Timeout     time.Duration
-	MaxMessages uint8
-	CmixParam   cmix.CMIXParams
+	Timeout             time.Duration
+	MaxResponseMessages uint8
+	CmixParam           cmix.CMIXParams
 }
 
+func GetDefaultRequestParams() RequestParams {
+	return RequestParams{
+		Timeout:             30 * time.Second,
+		MaxResponseMessages: 255,
+		CmixParam:           cmix.GetDefaultCMIXParams(),
+	}
+}
+
+// GetMaxRequestSize returns the max size of a request payload
+func GetMaxRequestSize(net cmix.Client, e2eGrp *cyclic.Group) uint {
+	payloadSize := message.GetRequestPayloadSize(net.GetMaxMessageLength(),
+		e2eGrp.GetP().ByteLen())
+	return message.GetRequestContentsSize(payloadSize)
+}
+
+/* Single is a system which allows for an end to end encrypted anonymous
+   request to be sent to another cmix client, and for them to respond. The
+   system allows for communication over the mixnet without an interactive
+   key negotiation because the payload inherently carries the negotiation with
+   it. When sending a new request, a client create a new discreet log Dh keypair
+   as well as a new ID. As a result of the fact that the client never
+   identifies itself, the system allows the client to stay anonymous while
+   contacting the remote.
+*/
+
+// TransmitRequest Sends a request to the recipient with the given tag containing
+// the given payload. The request is identified as coming from a new user ID and
+// the recipient of the request responds to that address. As a result, this request
+// does not reveal the identity of the sender,
+// the current implementation only allows for a cing cmix request payload.
+// Because the request payload itself must include negotiation materials, it is
+// limited to just a few thousand bits of payload, and will return an error if
+// the payload is too large. GetMaxRequestSize() can be used to get this max
+// size
+// The network follower must be running and healthy to transmit
 func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 	callback Response, param RequestParams, net cmix.Client, rng csprng.Source,
 	e2eGrp *cyclic.Group) (id.Round, receptionID.EphemeralIdentity, error) {
+	if !net.IsHealthy() {
+		return 0, receptionID.EphemeralIdentity{}, errors.New("Cannot " +
+			"send singe use when network is not healthy")
+	}
+
 	// get address ID address space size; this blocks until the address space
 	// size is set for the first time
 	addressSize := net.GetAddressSpace()
@@ -50,7 +91,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 	request := message.NewRequest(net.GetMaxMessageLength(),
 		e2eGrp.GetP().ByteLen())
 	requestPayload := message.NewRequestPayload(request.GetPayloadSize(),
-		payload, param.MaxMessages)
+		payload, param.MaxResponseMessages)
 
 	// Generate new user ID and address ID
 	var sendingID receptionID.EphemeralIdentity
@@ -73,7 +114,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 	request.SetPayload(encryptedPayload)
 
 	//register the response pickup
-	collator := message.NewCollator(param.MaxMessages)
+	collator := message.NewCollator(param.MaxResponseMessages)
 	timeoutKillChan := make(chan bool)
 	callbackOnce := sync.Once{}
 	wrapper := func(payload []byte, receptionID receptionID.EphemeralIdentity,
@@ -88,9 +129,9 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 		})
 	}
 
-	cyphers := makeCyphers(dhKey, param.MaxMessages)
+	cyphers := makeCyphers(dhKey, param.MaxResponseMessages)
 
-	for i := uint8(0); i < param.MaxMessages; i++ {
+	for i := uint8(0); i < param.MaxResponseMessages; i++ {
 		processor := responceProcessor{
 			sendingID: sendingID,
 			c:         collator,
@@ -196,6 +237,8 @@ func makeIDs(msg message.RequestPayload, publicKey *cyclic.Int,
 	}, nil
 }
 
+// waitForTimeout is a long running thread which handles timing out a request.
+// It can be canceled by channel
 func waitForTimeout(kill chan bool, callback callbackWrapper, timeout time.Duration) {
 	timer := time.NewTimer(timeout)
 	select {
diff --git a/single/responseProcessor.go b/single/responseProcessor.go
index 9eb56ef2bf4ddb7ce14409962129a3f4fdf64188..7fca2e88bbcc979be0c8c9753f720cb5ad938ccd 100644
--- a/single/responseProcessor.go
+++ b/single/responseProcessor.go
@@ -12,7 +12,8 @@ import (
 type callbackWrapper func(payload []byte,
 	receptionID receptionID.EphemeralIdentity, round rounds.Round, err error)
 
-//by fingerprint
+// responceProcessor Message.Processor interface registered with cmix.Client.
+// One is registered for each potential fingerprint.
 type responceProcessor struct {
 	sendingID receptionID.EphemeralIdentity
 	c         *message.Collator
@@ -22,6 +23,8 @@ type responceProcessor struct {
 	recipient *contact.Contact
 }
 
+// Process decrypts a response part and adds it to the collator - returning
+// a full response to the callback when all parts are received.
 func (rsp *responceProcessor) Process(ecrMsg format.Message,
 	receptionID receptionID.EphemeralIdentity,
 	round rounds.Round) {
diff --git a/storage/ndf_test.go b/storage/ndf_test.go
index ece36461e5368cd110b0004d95fc09bf3f28837f..4d48ab2d28d7330511f8474a9a335ef023505eb6 100644
--- a/storage/ndf_test.go
+++ b/storage/ndf_test.go
@@ -17,10 +17,10 @@ func TestSession_SetGetNDF(t *testing.T) {
 	testNdf := getNDF()
 	sess.SetNDF(testNdf)
 
-	if !reflect.DeepEqual(testNdf, sess.ndf) {
+	if !reflect.DeepEqual(testNdf, sess.GetNDF()) {
 		t.Errorf("SetNDF error: "+
 			"Unexpected value after setting ndf:"+
-			"Expected: %v\n\tReceived: %v", testNdf, sess.ndf)
+			"Expected: %v\n\tReceived: %v", testNdf, sess.GetNDF())
 	}
 
 	receivedNdf := sess.GetNDF()
diff --git a/storage/session.go b/storage/session.go
index 2f2c543e8f3096c3875b4f553fc8df964213a003..e9bee8ae363597a4e43e6b4b4fb2a30cfc938ecf 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -10,15 +10,15 @@
 package storage
 
 import (
-	"gitlab.com/elixxir/client/storage/utility"
-	"gitlab.com/xx_network/crypto/large"
 	"sync"
 	"testing"
 	"time"
 
+	"gitlab.com/elixxir/client/storage/utility"
+	"gitlab.com/xx_network/crypto/large"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	userInterface "gitlab.com/elixxir/client/interfaces/user"
 	"gitlab.com/elixxir/client/storage/clientVersion"
 	"gitlab.com/elixxir/client/storage/user"
 	"gitlab.com/elixxir/client/storage/versioned"
@@ -60,7 +60,7 @@ type Session interface {
 	IsPrecanned() bool
 	SetUsername(username string) error
 	GetUsername() (string, error)
-	PortableUserInfo() userInterface.Info
+	PortableUserInfo() user.Info
 	GetTransmissionRegistrationValidationSignature() []byte
 	GetReceptionRegistrationValidationSignature() []byte
 	GetRegistrationTimestamp() time.Time
@@ -103,7 +103,7 @@ func initStore(baseDir, password string) (*session, error) {
 }
 
 // Creates new UserData in the session
-func New(baseDir, password string, u userInterface.Info,
+func New(baseDir, password string, u user.Info,
 	currentVersion version.Version, cmixGrp, e2eGrp *cyclic.Group) (Session, error) {
 
 	s, err := initStore(baseDir, password)
diff --git a/storage/user/Info.go b/storage/user/Info.go
deleted file mode 100644
index 8091bffe0c38791c93a944621639a1679b3d8895..0000000000000000000000000000000000000000
--- a/storage/user/Info.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package user
-
-import "gitlab.com/elixxir/client/interfaces/user"
-
-func (u *User) PortableUserInfo() user.Info {
-	ci := u.CryptographicIdentity
-	return user.Info{
-		TransmissionID:        ci.GetTransmissionID().DeepCopy(),
-		TransmissionSalt:      copySlice(ci.GetTransmissionSalt()),
-		TransmissionRSA:       ci.GetTransmissionRSA(),
-		ReceptionID:           ci.GetReceptionID().DeepCopy(),
-		RegistrationTimestamp: u.GetRegistrationTimestamp().UnixNano(),
-		ReceptionSalt:         copySlice(ci.GetReceptionSalt()),
-		ReceptionRSA:          ci.GetReceptionRSA(),
-		Precanned:             ci.IsPrecanned(),
-		//fixme: set these in the e2e layer, the command line layer
-		//needs more logical seperation so this can be removed
-		E2eDhPrivateKey: nil,
-		E2eDhPublicKey:  nil,
-	}
-
-}
-
-func copySlice(s []byte) []byte {
-	n := make([]byte, len(s))
-	copy(n, s)
-	return n
-}
diff --git a/interfaces/user/user.go b/storage/user/info.go
similarity index 66%
rename from interfaces/user/user.go
rename to storage/user/info.go
index 0e3c6ca0331756882b38ce9706c1ffdbbcf65e96..11d9381ef07cbad22a91dc49db8cff48d551fed8 100644
--- a/interfaces/user/user.go
+++ b/storage/user/info.go
@@ -16,6 +16,28 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 )
 
+type Proto struct {
+	//General Identity
+	TransmissionID   *id.ID
+	TransmissionSalt []byte
+	TransmissionRSA  *rsa.PrivateKey
+	ReceptionID      *id.ID
+	ReceptionSalt    []byte
+	ReceptionRSA     *rsa.PrivateKey
+	Precanned        bool
+	// Timestamp in which user has registered with the network
+	RegistrationTimestamp int64
+
+	RegCode string
+
+	TransmissionRegValidationSig []byte
+	ReceptionRegValidationSig    []byte
+
+	//e2e Identity
+	E2eDhPrivateKey *cyclic.Int
+	E2eDhPublicKey  *cyclic.Int
+}
+
 type Info struct {
 	//General Identity
 	TransmissionID   *id.ID
@@ -70,3 +92,28 @@ func NewUserFromBackup(backup *backup.Backup) Info {
 		E2eDhPublicKey:        backup.ReceptionIdentity.DHPublicKey,
 	}
 }
+
+func (u *User) PortableUserInfo() Info {
+	ci := u.CryptographicIdentity
+	return Info{
+		TransmissionID:        ci.GetTransmissionID().DeepCopy(),
+		TransmissionSalt:      copySlice(ci.GetTransmissionSalt()),
+		TransmissionRSA:       ci.GetTransmissionRSA(),
+		ReceptionID:           ci.GetReceptionID().DeepCopy(),
+		RegistrationTimestamp: u.GetRegistrationTimestamp().UnixNano(),
+		ReceptionSalt:         copySlice(ci.GetReceptionSalt()),
+		ReceptionRSA:          ci.GetReceptionRSA(),
+		Precanned:             ci.IsPrecanned(),
+		//fixme: set these in the e2e layer, the command line layer
+		//needs more logical seperation so this can be removed
+		E2eDhPrivateKey: nil,
+		E2eDhPublicKey:  nil,
+	}
+
+}
+
+func copySlice(s []byte) []byte {
+	n := make([]byte, len(s))
+	copy(n, s)
+	return n
+}
diff --git a/ud/utils_test.go b/ud/utils_test.go
index 425d22d9ae31775bc13b2efe6391037ba3a63f93..7d3b3626c3b479e0a14d87746ac707f970a7327e 100644
--- a/ud/utils_test.go
+++ b/ud/utils_test.go
@@ -15,6 +15,9 @@
 package ud
 
 import (
+	"testing"
+	"time"
+
 	"gitlab.com/elixxir/client/cmix/gateway"
 	"gitlab.com/elixxir/client/event"
 	"gitlab.com/elixxir/client/interfaces"
@@ -28,8 +31,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
-	"testing"
-	"time"
 )
 
 func newTestNetworkManager(t *testing.T) interfaces.NetworkManager {
@@ -76,7 +77,7 @@ func (tnm *testNetworkManager) SendManyCMIX([]message.TargetedCmixMessage, param
 type dummyEventMgr struct{}
 
 func (d *dummyEventMgr) Report(int, string, string, string) {}
-func (tnm *testNetworkManager) GetEventManager() event.Manager {
+func (tnm *testNetworkManager) GetEventManager() event.Reporter {
 	return &dummyEventMgr{}
 }