diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go
index 0debb583f3496b945f3601118a5940d69683a3bd..88682af983c107345b6415648bec9558f2eb4d6b 100644
--- a/api/authenticatedChannel.go
+++ b/api/authenticatedChannel.go
@@ -12,7 +12,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth"
 	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
 )
@@ -20,16 +20,17 @@ import (
 // RequestAuthenticatedChannel sends a request to another party to establish an
 // authenticated channel
 // It will not run if the network status is not healthy
-// An error will be returned if a channel already exists, if a request was
-// already received, or if a request was already sent
+// An error will be returned if a channel already exists or if a request was
+// already received
 // When a confirmation occurs, the channel will be created and the callback
 // will be called
+// Can be retried.
 func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact,
-	message string) error {
+	message string) (id.Round, error) {
 	jww.INFO.Printf("RequestAuthenticatedChannel(%s)", recipient.ID)
 
 	if !c.network.GetHealthTracker().IsHealthy() {
-		return errors.New("Cannot request authenticated channel " +
+		return 0, errors.New("Cannot request authenticated channel " +
 			"creation when the network is not healthy")
 	}
 
@@ -60,11 +61,12 @@ func (c *Client) GetAuthenticatedChannelRequest(partner *id.ID) (contact.Contact
 // An error will be returned if a channel already exists, if a request doest
 // exist, or if the passed in contact does not exactly match the received
 // request
-func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) error {
+// Can be retried.
+func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) (id.Round, error) {
 	jww.INFO.Printf("ConfirmAuthenticatedChannel(%s)", recipient.ID)
 
 	if !c.network.GetHealthTracker().IsHealthy() {
-		return errors.New("Cannot request authenticated channel " +
+		return 0, errors.New("Cannot request authenticated channel " +
 			"creation when the network is not healthy")
 	}
 
diff --git a/api/client.go b/api/client.go
index 31a81017e4d6825f5f3d64f79d4844685ef1b110..ae87fdc6dc36a974875f5a73ddea87ed52fbded1 100644
--- a/api/client.go
+++ b/api/client.go
@@ -8,6 +8,7 @@
 package api
 
 import (
+	"gitlab.com/xx_network/primitives/id"
 	"time"
 
 	"github.com/pkg/errors"
@@ -83,33 +84,12 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 
 	protoUser := createNewUser(rngStream, cmixGrp, e2eGrp)
 
-	// Get current client version
-	currentVersion, err := version.ParseVersion(SEMVER)
-	if err != nil {
-		return errors.WithMessage(err, "Could not parse version string.")
-	}
-
-	// Create Storage
-	passwordStr := string(password)
-	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
-		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
+	err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
+		cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
 	if err != nil {
 		return err
 	}
 
-	// Save NDF to be used in the future
-	storageSess.SetBaseNDF(def)
-
-	//store the registration code for later use
-	storageSess.SetRegCode(registrationCode)
-
-	//move the registration state to keys generated
-	err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
-	if err != nil {
-		return errors.WithMessage(err, "Failed to denote state "+
-			"change in session")
-	}
-
 	//TODO: close the session
 	return nil
 }
@@ -134,29 +114,39 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 
 	protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp)
 
-	// Get current client version
-	currentVersion, err := version.ParseVersion(SEMVER)
+	err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
+		cmixGrp, e2eGrp, rngStreamGen, true, "")
 	if err != nil {
-		return errors.WithMessage(err, "Could not parse version string.")
+		return err
 	}
+	//TODO: close the session
+	return nil
+}
 
-	// Create Storage
-	passwordStr := string(password)
-	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
-		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
+// 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, 3, csprng.NewSystemRNG)
+	rngStream := rngStreamGen.GetStream()
+
+	// Parse the NDF
+	def, err := parseNDF(ndfJSON)
 	if err != nil {
 		return err
 	}
+	cmixGrp, e2eGrp := decodeGroups(def)
 
-	// Save NDF to be used in the future
-	storageSess.SetBaseNDF(def)
+	protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, userIdPrefix)
 
-	//move the registration state to indicate registered with permissioning
-	err = storageSess.ForwardRegistrationStatus(
-		storage.PermissioningComplete)
+	err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
+		cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to denote state "+
-			"change in session")
+		return err
 	}
 
 	//TODO: close the session
@@ -204,11 +194,14 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie
 
 	//Open the client
 	c, err := OpenClient(storageDir, password, parameters)
-
 	if err != nil {
 		return nil, err
 	}
 
+	u := c.storage.GetUser()
+	jww.INFO.Printf("Client Logged in: \n\tTransmisstionID: %s " +
+		"\n\tReceptionID: %s", u.TransmissionID, u.ReceptionID)
+
 	//Attach the services interface
 	c.services = newServiceProcessiesList(c.runner)
 
@@ -387,7 +380,9 @@ func (c *Client) initPermissioning(def *ndf.NetworkDefinition) error {
 //   - Auth Callback (/auth/callback.go)
 //      Handles both auth confirm and requests
 func (c *Client) StartNetworkFollower() (<-chan interfaces.ClientError, error) {
-	jww.INFO.Printf("StartNetworkFollower()")
+	u := c.GetUser()
+	jww.INFO.Printf("StartNetworkFollower() \n\tTransmisstionID: %s " +
+		"\n\tReceptionID: %s", u.TransmissionID, u.ReceptionID)
 
 	c.clientErrorChannel = make(chan interfaces.ClientError, 1000)
 
@@ -440,7 +435,6 @@ func (c *Client) StopNetworkFollower(timeout time.Duration) error {
 	if err != nil {
 		return errors.WithMessage(err, "Failed to Stop the Network Follower")
 	}
-	close(c.clientErrorChannel)
 	err = c.runner.Close(timeout)
 	if err != nil {
 		return errors.WithMessage(err, "Failed to Stop the Network Follower")
@@ -517,9 +511,9 @@ func (c *Client) GetNetworkInterface() interfaces.NetworkManager {
 }
 
 // GetNodeRegistrationStatus gets the current status of node registration. It
-// returns the number of nodes that the client is registered and the number of
-// in progress node registrations. An error is returned if the network is not
-// healthy.
+// returns the 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 healthy.
 func (c *Client) GetNodeRegistrationStatus() (int, int, error) {
 	// Return an error if the network is not healthy
 	if !c.GetHealth().IsHealthy() {
@@ -527,13 +521,24 @@ func (c *Client) GetNodeRegistrationStatus() (int, int, error) {
 			"network is not healthy")
 	}
 
-	// Get the number of nodes that client is registered with
-	registeredNodes := c.storage.Cmix().Count()
+	nodes := c.GetNetworkInterface().GetInstance().GetPartialNdf().Get().Nodes
 
-	// Get the number of in progress node registrations
-	inProgress := c.network.InProgressRegistrations()
+	cmixStore := c.storage.Cmix()
 
-	return registeredNodes, inProgress, nil
+	var numRegistered int
+	for i, n := range nodes{
+		nid, err := id.Unmarshal(n.ID)
+		if err!=nil{
+			return 0,0, errors.Errorf("Failed to unmarshal node ID %v " +
+				"(#%d): %s", n.ID, i, err.Error())
+		}
+		if cmixStore.Has(nid){
+			numRegistered++
+		}
+	}
+
+	// Get the number of in progress node registrations
+	return numRegistered, len(nodes), nil
 }
 
 // ----- Utility Functions -----
@@ -567,3 +572,43 @@ 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
+func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string, password []byte,
+	protoUser user.User, cmixGrp, e2eGrp *cyclic.Group, rngStreamGen *fastRNG.StreamGenerator,
+	isPrecanned bool, registrationCode string) error {
+	// Get current client version
+	currentVersion, err := version.ParseVersion(SEMVER)
+	if err != nil {
+		return errors.WithMessage(err, "Could not parse version string.")
+	}
+
+	// Create Storage
+	passwordStr := string(password)
+	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
+		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
+	if err != nil {
+		return err
+	}
+
+	// Save NDF to be used in the future
+	storageSess.SetBaseNDF(def)
+
+	if !isPrecanned {
+		//store the registration code for later use
+		storageSess.SetRegCode(registrationCode)
+		//move the registration state to keys generated
+		err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
+	} else {
+		//move the registration state to indicate registered with permissioning
+		err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete)
+	}
+
+	if err != nil {
+		return errors.WithMessage(err, "Failed to denote state "+
+			"change in session")
+	}
+
+	return nil
+}
diff --git a/api/user.go b/api/user.go
index 892d84c63c8fb0e29001774c6c645f351b3d00b8..48d7f992dfa32b48a3905752c55459ddc710e701 100644
--- a/api/user.go
+++ b/api/user.go
@@ -17,6 +17,10 @@ import (
 	"gitlab.com/xx_network/crypto/xx"
 	"gitlab.com/xx_network/primitives/id"
 	"math/rand"
+	"regexp"
+	"runtime"
+	"strings"
+	"sync"
 )
 
 const (
@@ -134,3 +138,126 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.
 		ReceptionRSA:     rsaKey,
 	}
 }
+
+// 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.User {
+	// CMIX 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.
+	cMixKeyBytes, err := csprng.GenerateInGroup(cmix.GetPBytes(), 256, rng)
+	if err != nil {
+		jww.FATAL.Panicf(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?
+	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, rng)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// RSA Keygen (4096 bit defaults)
+	transmissionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// Salt, UID, etc gen
+	transmissionSalt := make([]byte, SaltSize)
+	n, err := csprng.NewSystemRNG().Read(transmissionSalt)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+	if n != SaltSize {
+		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
+	}
+	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	receptionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	var mu sync.Mutex // just in case more than one go routine tries to access receptionSalt and receptionID
+	done := make(chan struct{}) 
+	found:= make(chan bool)
+	wg:= &sync.WaitGroup{}
+	cores := runtime.NumCPU()
+
+	var receptionSalt []byte
+	var receptionID *id.ID 
+	
+	pref := prefix
+	ignoreCase := false
+	// check if case-insensitivity is enabled
+	if strings.HasPrefix(prefix, "(?i)") {
+		pref = strings.ToLower(pref[4:])
+		ignoreCase = true
+	}
+	// Check if prefix contains valid Base64 characters
+	match, _ := regexp.MatchString("^[A-Za-z0-9+/]+$", pref)
+	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)
+	for w := 0; w < cores; w++{
+		wg.Add(1)
+		go func() {
+			rSalt := make([]byte, SaltSize)
+			for {	
+				select {
+				case <- done:
+					defer wg.Done()
+					return
+				default:
+					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)
+					}
+					rID, err := xx.NewID(receptionRsaKey.GetPublic(), rSalt, id.User)
+					if err != nil {
+						jww.FATAL.Panicf(err.Error())
+					}
+					id := rID.String()
+					if ignoreCase {
+						id = strings.ToLower(id)
+					} 
+					if strings.HasPrefix(id, pref) {
+						mu.Lock()
+						receptionID = rID
+						receptionSalt = rSalt
+						mu.Unlock()
+						found <- true
+						defer wg.Done()
+						return
+					}
+				}	
+			}
+		}()
+	}
+	// wait for a solution then close the done channel to signal the workers to exit
+	<- found
+	close(done)
+	wg.Wait()
+	return user.User{
+		TransmissionID:   transmissionID.DeepCopy(),
+		TransmissionSalt: transmissionSalt,
+		TransmissionRSA:  transmissionRsaKey,
+		ReceptionID:      receptionID.DeepCopy(),
+		ReceptionSalt:    receptionSalt,
+		ReceptionRSA:     receptionRsaKey,
+		Precanned:        false,
+		CmixDhPrivateKey: cmix.NewIntFromBytes(cMixKeyBytes),
+		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
+	}
+}
diff --git a/api/version.go b/api/version.go
deleted file mode 100644
index 57d607b585497d1c4e73ef104536e19b8ab82ed2..0000000000000000000000000000000000000000
--- a/api/version.go
+++ /dev/null
@@ -1,42 +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 api
-
-/*
-func (c *Client) Version() version.Version {
-	v, err := version.ParseVersion(SEMVER)
-	if err != nil {
-		jww.FATAL.Panicf("Failed to parse the client version: %s", err)
-	}
-	return v
-}
-
-func (c *Client) checkVersion() error {
-	clientVersion := c.Version()
-	jww.INFO.Printf("Client Version: %s", clientVersion.String())
-
-	has, netVersion, err := c.permissioning.GetNetworkVersion()
-	if err != nil {
-		return errors.WithMessage(err, "failed to get check "+
-			"version compatibility")
-	}
-	if has {
-		jww.INFO.Printf("Minimum Network Version: %v", netVersion)
-		if !version.IsCompatible(netVersion, clientVersion) {
-			return errors.Errorf("Client and Minimum Network Version are "+
-				"incompatible\n"+
-				"\tMinimum Network: %s\n"+
-				"\tClient: %s", netVersion.String(), clientVersion.String())
-		}
-	} else {
-		jww.INFO.Printf("Network requires no minimum version")
-	}
-
-	return nil
-}
-*/
diff --git a/api/version_vars.go b/api/version_vars.go
index dc333c8a688faddebc96c5de0f589d9137801308..1a4ed3b5336c44eeed1cf474d589c1175808c16a 100644
--- a/api/version_vars.go
+++ b/api/version_vars.go
@@ -1,10 +1,10 @@
 // Code generated by go generate; DO NOT EDIT.
 // This file was generated by robots at
-// 2021-03-10 14:16:47.093264 -0800 PST m=+0.046129936
+// 2021-04-02 08:56:27.8657223 -0700 PDT m=+0.054483401
 package api
 
-const GITVERSION = `2096d6ae Merge branch 'Anne/v2' into 'release'`
-const SEMVER = "2.0.0"
+const GITVERSION = `6020ab79 removed an extranious print`
+const SEMVER = "2.3.0"
 const DEPENDENCIES = `module gitlab.com/elixxir/client
 
 go 1.13
@@ -13,10 +13,12 @@ require (
 	github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
 	github.com/golang/protobuf v1.4.3
 	github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
+	github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea
 	github.com/magiconair/properties v1.8.4 // indirect
 	github.com/mitchellh/mapstructure v1.4.0 // indirect
 	github.com/pelletier/go-toml v1.8.1 // indirect
 	github.com/pkg/errors v0.9.1
+	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/smartystreets/assertions v1.0.1 // indirect
 	github.com/spf13/afero v1.5.1 // indirect
 	github.com/spf13/cast v1.3.1 // indirect
@@ -24,19 +26,18 @@ require (
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/viper v1.7.1
 	gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228
-	gitlab.com/elixxir/comms v0.0.4-0.20210310191636-1bca0ddac665
-	gitlab.com/elixxir/crypto v0.0.7-0.20210309193114-8a6225c667e2
+	gitlab.com/elixxir/comms v0.0.4-0.20210401210158-6053ad2e224c
+	gitlab.com/elixxir/crypto v0.0.7-0.20210401210040-b7f1da24ef13
 	gitlab.com/elixxir/ekv v0.1.4
-	gitlab.com/elixxir/primitives v0.0.3-0.20210309193003-ef42ebb4800b
-	gitlab.com/xx_network/comms v0.0.4-0.20210309192940-6b7fb39b4d01
-	gitlab.com/xx_network/crypto v0.0.5-0.20210309192854-cf32117afb96
-	gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a
+	gitlab.com/elixxir/primitives v0.0.3-0.20210401175645-9b7b92f74ec4
+	gitlab.com/xx_network/comms v0.0.4-0.20210401160731-7b8890cdd8ad
+	gitlab.com/xx_network/crypto v0.0.5-0.20210401160648-4f06cace9123
+	gitlab.com/xx_network/primitives v0.0.4-0.20210331161816-ed23858bdb93
 	golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
 	golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
-	golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect
 	google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect
 	google.golang.org/grpc v1.34.0 // indirect
-	google.golang.org/protobuf v1.25.0
+	google.golang.org/protobuf v1.26.0-rc.1
 	gopkg.in/ini.v1 v1.62.0 // indirect
 )
 
diff --git a/auth/callback.go b/auth/callback.go
index a304905f4bef5e6177d04d1b9bb7693fe36be24d..ef21512f88a06c19322c03518bc262d7d2e94ebe 100644
--- a/auth/callback.go
+++ b/auth/callback.go
@@ -11,9 +11,10 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage/auth"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
@@ -25,48 +26,55 @@ import (
 func (m *Manager) StartProcessies() stoppable.Stoppable {
 
 	stop := stoppable.NewSingle("Auth")
-	authStore := m.storage.Auth()
-	grp := m.storage.E2e().GetGroup()
 
 	go func() {
-		select {
-		case <-stop.Quit():
-			return
-		case msg := <-m.rawMessages:
-			//lookup the message, check if it is an auth request
-			cmixMsg := format.Unmarshal(msg.Payload)
-			fp := cmixMsg.GetKeyFP()
-			jww.INFO.Printf("RAW AUTH FP: %v", fp)
-			// this takes the request lock if it is a specific fp,
-			// all exits after this need to call fail or delete if it is
-			// specific
-			fpType, sr, myHistoricalPrivKey, err := authStore.GetFingerprint(fp)
-			if err != nil {
-				jww.TRACE.Printf("FINGERPRINT FAILURE: %s", err.Error())
-				// if the lookup fails, ignore the message. It is likely
-				// garbled or for a different protocol
-				break
-			}
-
-			//denote that the message is not garbled
-			m.storage.GetGarbledMessages().Remove(cmixMsg)
-
-			switch fpType {
-			// if it is general, that means a new request has been received
-			case auth.General:
-				m.handleRequest(cmixMsg, myHistoricalPrivKey, grp)
-			// if it is specific, that means the original request was sent
-			// by this users and a confirmation has been received
-			case auth.Specific:
-				jww.INFO.Printf("Received AutConfirm from %s,"+
-					" msgDigest: %s", sr.GetPartner(), cmixMsg.Digest())
-				m.handleConfirm(cmixMsg, sr, grp)
+		for {
+			select {
+			case <-stop.Quit():
+				return
+			case msg := <-m.rawMessages:
+				m.processAuthMessage(msg)
 			}
 		}
 	}()
 	return stop
 }
 
+func (m *Manager) processAuthMessage(msg message.Receive) {
+	authStore := m.storage.Auth()
+	//lookup the message, check if it is an auth request
+	cmixMsg := format.Unmarshal(msg.Payload)
+	fp := cmixMsg.GetKeyFP()
+	jww.INFO.Printf("RAW AUTH FP: %v", fp)
+	// this takes the request lock if it is a specific fp, all
+	// exits after this need to call fail or delete if it is
+	// specific
+	fpType, sr, myHistoricalPrivKey, err := authStore.GetFingerprint(fp)
+	if err != nil {
+		jww.TRACE.Printf("FINGERPRINT FAILURE: %s", err.Error())
+		// if the lookup fails, ignore the message. It is
+		// likely garbled or for a different protocol
+		return
+	}
+
+	//denote that the message is not garbled
+	m.storage.GetGarbledMessages().Remove(cmixMsg)
+	grp := m.storage.E2e().GetGroup()
+
+	switch fpType {
+	case auth.General:
+		// if it is general, that means a new request has
+		// been received
+		m.handleRequest(cmixMsg, myHistoricalPrivKey, grp)
+	case auth.Specific:
+		// if it is specific, that means the original request was sent
+		// by this users and a confirmation has been received
+		jww.INFO.Printf("Received AutConfirm from %s, msgDigest: %s",
+			sr.GetPartner(), cmixMsg.Digest())
+		m.handleConfirm(cmixMsg, sr, grp)
+	}
+}
+
 func (m *Manager) handleRequest(cmixMsg format.Message,
 	myHistoricalPrivKey *cyclic.Int, grp *cyclic.Group) {
 	//decode the outer format
@@ -152,8 +160,8 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
 					" msgDigest: %s which has been requested, auto-confirming",
 					partnerID, cmixMsg.Digest())
 				// do the confirmation
-				if err := m.doConfirm(sr2, grp, partnerPubKey, myPubKey,
-					ecrFmt.GetOwnership()); err != nil {
+				if err := m.doConfirm(sr2, grp, partnerPubKey, m.storage.E2e().GetDHPrivateKey(),
+					sr2.GetPartnerHistoricalPubKey(), ecrFmt.GetOwnership()); err != nil {
 					jww.WARN.Printf("Auto Confirmation with %s failed: %s",
 						partnerID, err)
 				}
@@ -241,8 +249,8 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
 	}
 
 	// finalize the confirmation
-	if err := m.doConfirm(sr, grp, partnerPubKey, sr.GetPartnerHistoricalPubKey(),
-		ecrFmt.GetOwnership()); err != nil {
+	if err := m.doConfirm(sr, grp, partnerPubKey, sr.GetMyPrivKey(),
+		sr.GetPartnerHistoricalPubKey(), ecrFmt.GetOwnership()); err != nil {
 		jww.WARN.Printf("Confirmation failed: %s", err)
 		m.storage.Auth().Fail(sr.GetPartner())
 		return
@@ -250,10 +258,10 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
 }
 
 func (m *Manager) doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
-	partnerPubKey, myPubKeyOwnershipProof *cyclic.Int, ownershipProof []byte) error {
+	partnerPubKey, myPrivateKeyOwnershipProof, partnerPubKeyOwnershipProof *cyclic.Int, ownershipProof []byte) error {
 	// verify the message came from the intended recipient
-	if !cAuth.VerifyOwnershipProof(sr.GetMyPrivKey(),
-		myPubKeyOwnershipProof, grp, ownershipProof) {
+	if !cAuth.VerifyOwnershipProof(myPrivateKeyOwnershipProof,
+		partnerPubKeyOwnershipProof, grp, ownershipProof) {
 		return errors.Errorf("Failed authenticate identity for auth "+
 			"confirmation of %s", sr.GetPartner())
 	}
diff --git a/auth/confirm.go b/auth/confirm.go
index d1b88bf99d9a1fe2871850b5d7c810ea39f7f6a6..d91f81e33e9e1d52aac5136e620ec405842ccd24 100644
--- a/auth/confirm.go
+++ b/auth/confirm.go
@@ -11,27 +11,24 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/params"
-	"gitlab.com/elixxir/client/interfaces/utility"
 	"gitlab.com/elixxir/client/storage"
-	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/elixxir/primitives/states"
 	"io"
-	"time"
 )
 
 func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
-	storage *storage.Session, net interfaces.NetworkManager) error {
+	storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) {
 
 	/*edge checking*/
 
 	// check that messages can be sent over the network
 	if !net.GetHealthTracker().IsHealthy() {
-		return errors.New("Cannot confirm authenticated message " +
+		return 0, errors.New("Cannot confirm authenticated message " +
 			"when the network is not healthy")
 	}
 
@@ -40,14 +37,14 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 	// the lock
 	storedContact, err := storage.Auth().GetReceivedRequest(partner.ID)
 	if err != nil {
-		return errors.Errorf("failed to find a pending Auth Request: %s",
+		return 0, errors.Errorf("failed to find a pending Auth Request: %s",
 			err)
 	}
 
 	// verify the passed contact matches what is stored
 	if storedContact.DhPubKey.Cmp(partner.DhPubKey) != 0 {
 		storage.Auth().Fail(partner.ID)
-		return errors.WithMessage(err, "Pending Auth Request has different "+
+		return 0, errors.WithMessage(err, "Pending Auth Request has different "+
 			"pubkey than stored")
 	}
 
@@ -68,7 +65,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 	_, err = rng.Read(salt)
 	if err != nil {
 		storage.Auth().Fail(partner.ID)
-		return errors.Wrap(err, "Failed to generate salt for "+
+		return 0, errors.Wrap(err, "Failed to generate salt for "+
 			"confirmation")
 	}
 
@@ -108,21 +105,19 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 	if err := storage.E2e().AddPartner(partner.ID, partner.DhPubKey, newPrivKey,
 		p, p); err != nil {
 		storage.Auth().Fail(partner.ID)
-		return errors.Errorf("Failed to create channel with partner (%s) "+
+		return 0, errors.Errorf("Failed to create channel with partner (%s) "+
 			"on confirmation: %+v",
 			partner.ID, err)
 	}
 
 	// delete the in progress negotiation
 	// this unlocks the request lock
-	if err := storage.Auth().Delete(partner.ID); err != nil {
-		return errors.Errorf("UNRECOVERABLE! Failed to delete in "+
+	//fixme - do these deletes at a later date
+	/*if err := storage.Auth().Delete(partner.ID); err != nil {
+		return 0, errors.Errorf("UNRECOVERABLE! Failed to delete in "+
 			"progress negotiation with partner (%s) after creating confirmation: %+v",
 			partner.ID, err)
-	}
-
-	//store the message as a critical message so it will always be sent
-	storage.GetCriticalRawMessages().AddProcessing(cmixMsg, partner.ID)
+	}*/
 
 	jww.INFO.Printf("Confirming Auth with %s, msgDigest: %s",
 		partner.ID, cmixMsg.Digest())
@@ -134,39 +129,11 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 		// retried
 		jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+
 			"to transmit: %+v", partner.ID, cmixMsg.Digest(), err)
-		storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID)
-		return errors.WithMessage(err, "Auth Confirm Failed to transmit")
+		return 0, errors.WithMessage(err, "Auth Confirm Failed to transmit")
 	}
 
 	jww.INFO.Printf("Confirm Request with %s (msgDigest: %s) sent on round %d",
 		partner.ID, cmixMsg.Digest(), round)
 
-	/*check message delivery*/
-	sendResults := make(chan ds.EventReturn, 1)
-	roundEvents := net.GetInstance().GetRoundEvents()
-
-	roundEvents.AddRoundEventChan(round, sendResults, 1*time.Minute,
-		states.COMPLETED, states.FAILED)
-
-	success, numFailed, _ := utility.TrackResults(sendResults, 1)
-	if !success {
-		if numFailed > 0 {
-			jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+
-				"delivery due to round failure, will retry on reconnect",
-				partner.ID, cmixMsg.Digest())
-		} else {
-			jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+
-				"delivery due to timeout, will retry on reconnect",
-				partner.ID, cmixMsg.Digest())
-		}
-		jww.ERROR.Printf("auth confirm failed to transmit, will be " +
-			"handled on reconnect")
-		storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID)
-	} else {
-		jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) delivered "+
-			"sucesfully", partner.ID, cmixMsg.Digest())
-		storage.GetCriticalRawMessages().Succeeded(cmixMsg, partner.ID)
-	}
-
-	return nil
+	return round, nil
 }
diff --git a/auth/request.go b/auth/request.go
index 8e9c1c58e206bfb51ca952cbec66227497f593f7..c43707904f835b19d1e64ba53cb4ec9fe550355f 100644
--- a/auth/request.go
+++ b/auth/request.go
@@ -11,66 +11,60 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/params"
-	"gitlab.com/elixxir/client/interfaces/utility"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/storage/auth"
 	"gitlab.com/elixxir/client/storage/e2e"
-	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
 	"io"
 	"strings"
-	"time"
 )
 
 const terminator = ";"
 
 func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
-	storage *storage.Session, net interfaces.NetworkManager) error {
+	storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) {
 	/*edge checks generation*/
 
-	// check that messages can be sent over the network
-	if !net.GetHealthTracker().IsHealthy() {
-		return errors.New("Cannot create authenticated message " +
-			"when the network is not healthy")
-	}
-
 	// check that an authenticated channel does not already exists
 	if _, err := storage.E2e().GetPartner(partner.ID); err == nil ||
 		!strings.Contains(err.Error(), e2e.NoPartnerErrorStr) {
-		return errors.Errorf("Authenticated channel already " +
+		return 0, errors.Errorf("Authenticated channel already " +
 			"established with partner")
 	}
 
 	// check that the request is being sent from the proper ID
 	if !me.ID.Cmp(storage.GetUser().ReceptionID) {
-		return errors.Errorf("Authenticated channel request " +
+		return 0, errors.Errorf("Authenticated channel request " +
 			"can only be sent from user's identity")
 	}
 
 	// check that the message is properly formed
 	if strings.Contains(message, terminator) {
-		return errors.Errorf("Message cannot contain '%s'", terminator)
+		return 0, errors.Errorf("Message cannot contain '%s'", terminator)
 	}
 
+	//denote if this is a resend of an old request
+	resend := false
+
 	//lookup if an ongoing request is occurring
-	rqType, _, _, err := storage.Auth().GetRequest(partner.ID)
-	if err != nil && strings.Contains(err.Error(), auth.NoRequest) {
-		err = nil
-	}
-	if err != nil {
+	rqType, sr, _, err := storage.Auth().GetRequest(partner.ID)
+
+	if err != nil && !strings.Contains(err.Error(), auth.NoRequest){
 		if rqType == auth.Receive {
-			return errors.WithMessage(err,
-				"Cannot send a request after "+
-					"receiving a request")
+			return 0, errors.WithMessage(err,
+				"Cannot send a request after receiving a request")
 		} else if rqType == auth.Sent {
-			return errors.WithMessage(err,
-				"Cannot send a request after "+
-					"already sending one")
+			resend = true
+		}else{
+			return 0, errors.WithMessage(err,
+				"Cannot send a request after receiving unknown error " +
+				"on requesting contact status")
 		}
 	}
 
@@ -82,7 +76,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	ecrFmt := newEcrFormat(baseFmt.GetEcrPayloadLen())
 	requestFmt, err := newRequestFormat(ecrFmt)
 	if err != nil {
-		return errors.Errorf("failed to make request format: %+v", err)
+		return 0, errors.Errorf("failed to make request format: %+v", err)
 	}
 
 	//check the payload fits
@@ -91,7 +85,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	msgPayloadBytes := []byte(msgPayload)
 
 	if len(msgPayloadBytes) > requestFmt.MsgPayloadLen() {
-		return errors.Errorf("Combined message longer than space "+
+		return 0, errors.Errorf("Combined message longer than space "+
 			"available in payload; available: %v, length: %v",
 			requestFmt.MsgPayloadLen(), len(msgPayloadBytes))
 	}
@@ -101,17 +95,27 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	salt := make([]byte, saltSize)
 	_, err = rng.Read(salt)
 	if err != nil {
-		return errors.Wrap(err, "Failed to generate salt")
+		return 0, errors.Wrap(err, "Failed to generate salt")
+	}
+
+	var newPrivKey, newPubKey *cyclic.Int
+
+	// in this case we have an ongoing request so we can resend the extant
+	// request
+	if resend{
+		newPrivKey = sr.GetMyPrivKey()
+		newPubKey = sr.GetMyPubKey()
+	//in this case it is a new request and we must generate new keys
+	}else{
+		//generate new keypair
+		newPrivKey = diffieHellman.GeneratePrivateKey(256, grp, rng)
+		newPubKey = diffieHellman.GeneratePublicKey(newPrivKey, grp)
 	}
 
 	//generate ownership proof
 	ownership := cAuth.MakeOwnershipProof(storage.E2e().GetDHPrivateKey(),
 		partner.DhPubKey, storage.E2e().GetGroup())
 
-	//generate new keypair
-	newPrivKey := diffieHellman.GeneratePrivateKey(256, grp, rng)
-	newPubKey := diffieHellman.GeneratePublicKey(newPrivKey, grp)
-
 	jww.TRACE.Printf("RequestAuth MYPUBKEY: %v", newPubKey.Bytes())
 	jww.TRACE.Printf("RequestAuth THEIRPUBKEY: %v", partner.DhPubKey.Bytes())
 
@@ -136,56 +140,30 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	/*store state*/
 	//fixme: channel is bricked if the first store succedes but the second fails
 	//store the in progress auth
-	err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey,
-		newPrivKey, confirmFp)
-	if err != nil {
-		return errors.Errorf("Failed to store auth request: %s", err)
+	if !resend{
+		err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey,
+			newPrivKey, confirmFp)
+		if err != nil {
+			return 0, errors.Errorf("Failed to store auth request: %s", err)
+		}
 	}
 
-	//store the message as a critical message so it will always be sent
-	storage.GetCriticalRawMessages().AddProcessing(cmixMsg, partner.ID)
-
 	jww.INFO.Printf("Requesting Auth with %s, msgDigest: %s",
 		partner.ID, cmixMsg.Digest())
 
 	/*send message*/
-	round, _, err := net.SendCMIX(cmixMsg, partner.ID, params.GetDefaultCMIX())
+	round, _, err := net.SendCMIX(cmixMsg, partner.ID,
+		params.GetDefaultCMIX())
 	if err != nil {
-		// if the send fails just set it to failed, it will but automatically
-		// retried
-		jww.INFO.Printf("Auth Request with %s (msgDigest: %s) failed "+
-			"to transmit: %+v", partner.ID, cmixMsg.Digest(), err)
-		storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID)
-		return errors.WithMessage(err, "Auth Request Failed to transmit")
+		// if the send fails just set it to failed, it will
+		// but automatically retried
+		return 0, errors.WithMessagef(err, "Auth Request with %s " +
+			"(msgDigest: %s) failed to transmit: %+v", partner.ID,
+			cmixMsg.Digest(), err)
 	}
 
-	jww.INFO.Printf("Auth Request with %s (msgDigest: %s) sent on round %d",
-		partner.ID, cmixMsg.Digest(), round)
-
-	/*check message delivery*/
-	sendResults := make(chan ds.EventReturn, 1)
-	roundEvents := net.GetInstance().GetRoundEvents()
-
-	roundEvents.AddRoundEventChan(round, sendResults, 1*time.Minute,
-		states.COMPLETED, states.FAILED)
-
-	success, numFailed, _ := utility.TrackResults(sendResults, 1)
-	if !success {
-		if numFailed > 0 {
-			jww.INFO.Printf("Auth Request with %s (msgDigest: %s) failed "+
-				"delivery due to round failure, will retry on reconnect",
-				partner.ID, cmixMsg.Digest())
-		} else {
-			jww.INFO.Printf("Auth Request with %s (msgDigest: %s) failed "+
-				"delivery due to timeout, will retry on reconnect",
-				partner.ID, cmixMsg.Digest())
-		}
-		storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID)
-	} else {
-		jww.INFO.Printf("Auth Request with %s (msgDigest: %s) delivered "+
-			"sucesfully", partner.ID, cmixMsg.Digest())
-		storage.GetCriticalRawMessages().Succeeded(cmixMsg, partner.ID)
-	}
+	jww.INFO.Printf("Auth Request with %s (msgDigest: %s) sent"+
+		" on round %d", partner.ID, cmixMsg.Digest(), round)
 
-	return nil
+	return round, nil
 }
diff --git a/auth/verify.go b/auth/verify.go
index 76850a17dfc6728c10b5c7304e04d7f2437f2545..66a86df6f125bb0abe7c28be4ecbb408603b0a98 100644
--- a/auth/verify.go
+++ b/auth/verify.go
@@ -8,8 +8,8 @@
 package auth
 
 import (
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/storage"
+	"gitlab.com/elixxir/crypto/contact"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
 )
 
diff --git a/bindings/authenticatedChannels.go b/bindings/authenticatedChannels.go
index 70ff0285173740f5ef302e1a678ffe127318a002..30b12f0a1b3039fba5b18eafeff874cc7a438a60 100644
--- a/bindings/authenticatedChannels.go
+++ b/bindings/authenticatedChannels.go
@@ -10,7 +10,7 @@ package bindings
 import (
 	"errors"
 	"fmt"
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 )
 
 // Create an insecure e2e relationship with a precanned user
@@ -27,19 +27,20 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID int) (*Contact, e
 // authenticated channel
 // It will not run if the network status is not healthy
 // An error will be returned if a channel already exists, if a request was
-// already received, or if a request was already sent
+// already received.
 // When a confirmation occurs, the channel will be created and the callback
 // will be called
+// This can be called many times and retried.
 //
 // This function takes the marshaled send report to ensure a memory leak does
 // not occur as a result of both sides of the bindings holding a refrence to
 // the same pointer.
 func (c *Client) RequestAuthenticatedChannel(recipientMarshaled,
-	meMarshaled []byte, message string) error {
+	meMarshaled []byte, message string) (int, error) {
 	recipent, err := contact.Unmarshal(recipientMarshaled)
 
 	if err != nil {
-		return errors.New(fmt.Sprintf("Failed to "+
+		return 0, errors.New(fmt.Sprintf("Failed to "+
 			"RequestAuthenticatedChannel: Failed to Unmarshal Recipent: "+
 			"%+v", err))
 	}
@@ -47,11 +48,13 @@ func (c *Client) RequestAuthenticatedChannel(recipientMarshaled,
 	me, err := contact.Unmarshal(meMarshaled)
 
 	if err != nil {
-		return errors.New(fmt.Sprintf("Failed to "+
+		return 0, errors.New(fmt.Sprintf("Failed to "+
 			"RequestAuthenticatedChannel: Failed to Unmarshal Me: %+v", err))
 	}
 
-	return c.api.RequestAuthenticatedChannel(recipent, me, message)
+	rid, err := c.api.RequestAuthenticatedChannel(recipent, me, message)
+
+	return int(rid), err
 }
 
 // RegisterAuthCallbacks registers both callbacks for authenticated channels.
@@ -79,19 +82,26 @@ func (c *Client) RegisterAuthCallbacks(request AuthRequestCallback,
 // received request and sends a message to the requestor that the request has
 // been confirmed
 // It will not run if the network status is not healthy
-// An error will be returned if a channel already exists, if a request doest
+// An error will be returned if a request doest
 // exist, or if the passed in contact does not exactly match the received
-// request
-func (c *Client) ConfirmAuthenticatedChannel(recipientMarshaled []byte) error {
+// request.
+// This can be called many times and retried.
+//
+// This function takes the marshaled send report to ensure a memory leak does
+// not occur as a result of both sides of the bindings holding a refrence to
+// the same pointer.
+func (c *Client) ConfirmAuthenticatedChannel(recipientMarshaled []byte) (int, error) {
 	recipent, err := contact.Unmarshal(recipientMarshaled)
 
 	if err != nil {
-		return errors.New(fmt.Sprintf("Failed to "+
+		return 0, errors.New(fmt.Sprintf("Failed to "+
 			"ConfirmAuthenticatedChannel: Failed to Unmarshal Recipient: "+
 			"%+v", err))
 	}
 
-	return c.api.ConfirmAuthenticatedChannel(recipent)
+	rid, err := c.api.ConfirmAuthenticatedChannel(recipent)
+
+	return int(rid), err
 }
 
 // VerifyOwnership checks if the ownership proof on a passed contact matches the
diff --git a/bindings/callback.go b/bindings/callback.go
index 1237e7fcf981f763fcf8dcb3be233d37e48741fd..a14cb5151358933f2f0bd6af6cdb04156ff4ac37 100644
--- a/bindings/callback.go
+++ b/bindings/callback.go
@@ -31,12 +31,19 @@ type NetworkHealthCallback interface {
 	Callback(bool)
 }
 
-// RoundEventHandler handles round events happening on the cMix network.
+// RoundEventCallback handles waiting on the exact state of a round on
+// the cMix network.
 type RoundEventCallback interface {
 	EventCallback(rid, state int, timedOut bool)
 }
 
-// RoundEventHandler handles round events happening on the cMix network.
+// RoundCompletionCallback is returned when the completion of a round is known.
+type RoundCompletionCallback interface {
+	EventCallback(rid int, success, timedOut bool)
+}
+
+// MessageDeliveryCallback gets called on the determination if all events
+// related to a message send were successful.
 type MessageDeliveryCallback interface {
 	EventCallback(msgID []byte, delivered, timedOut bool, roundResults []byte)
 }
@@ -96,3 +103,17 @@ func newRoundListUnregister(rounds []id.Round, ec []*dataStructures.EventCallbac
 type ClientError interface {
 	Report(source, message, trace string)
 }
+
+
+type LogWriter interface{
+	Log(string)
+}
+
+type writerAdapter struct{
+	lw LogWriter
+}
+
+func (wa *writerAdapter)Write(p []byte) (n int, err error){
+	wa.lw.Log(string(p))
+	return len(p), nil
+}
diff --git a/bindings/client.go b/bindings/client.go
index 04e2eba6e55645dfe1cd9f7fb7a14378dde5486d..b2c94fa95f46926ae891a8e9a41cb794cbdb28c8 100644
--- a/bindings/client.go
+++ b/bindings/client.go
@@ -13,15 +13,19 @@ import (
 	"fmt"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/primitives/id"
+	"sync"
 	"time"
 )
 
+var extantClient bool
+var loginMux sync.Mutex
+
 // sets the log level
 func init() {
 	jww.SetLogThreshold(jww.LevelInfo)
@@ -75,6 +79,14 @@ func NewPrecannedClient(precannedID int, network, storageDir string, password []
 // Login does not block on network connection, and instead loads and
 // starts subprocesses to perform network operations.
 func Login(storageDir string, password []byte, parameters string) (*Client, error) {
+	loginMux.Lock()
+	defer loginMux.Unlock()
+
+	if extantClient {
+		return nil, errors.New("cannot login when another session " +
+			"already exists")
+	}
+	// check if a client is already logged in, refuse to login if one is
 	p, err := params.GetNetworkParameters(parameters)
 	if err != nil {
 		return nil, errors.New(fmt.Sprintf("Failed to login: %+v", err))
@@ -84,7 +96,8 @@ func Login(storageDir string, password []byte, parameters string) (*Client, erro
 	if err != nil {
 		return nil, errors.New(fmt.Sprintf("Failed to login: %+v", err))
 	}
-	return &Client{*client}, nil
+	extantClient = true
+	return &Client{api: *client}, nil
 }
 
 // sets level of logging. All logs the set level and above will be displayed
@@ -126,6 +139,11 @@ func LogLevel(level int) error {
 	return nil
 }
 
+//RegisterLogWriter registers a callback on which logs are written.
+func RegisterLogWriter(writer LogWriter) {
+	jww.SetLogOutput(&writerAdapter{lw: writer})
+}
+
 //Unmarshals a marshaled contact object, returns an error if it fails
 func UnmarshalContact(b []byte) (*Contact, error) {
 	c, err := contact.Unmarshal(b)
@@ -203,6 +221,20 @@ func (c *Client) StopNetworkFollower(timeoutMS int) error {
 	return nil
 }
 
+// WaitForNewtwork will block until either the network is healthy or the
+// passed timeout. It will return true if the network is healthy
+func (c *Client) WaitForNetwork(timeoutMS int) bool {
+	start := time.Now()
+	timeout := time.Duration(timeoutMS) * time.Millisecond
+	for time.Now().Sub(start) < timeout {
+		if c.api.GetHealth().IsHealthy() {
+			return true
+		}
+		time.Sleep(250 * time.Millisecond)
+	}
+	return false
+}
+
 // Gets the state of the network follower. Returns:
 // Stopped 	- 0
 // Starting - 1000
@@ -301,18 +333,35 @@ func (c *Client) RegisterRoundEventsHandler(rid int, cb RoundEventCallback,
 	return newRoundUnregister(roundID, ec, c.api.GetRoundEvents())
 }
 
-// RegisterMessageDeliveryCB allows the caller to get notified if the rounds a
-// message was sent in successfully completed. Under the hood, this uses the same
-// interface as RegisterRoundEventsHandler, but provides a convenient way to use
-// the interface in its most common form, looking up the result of message
-// retrieval
+// WaitForRoundCompletion allows the caller to get notified if a round
+// has completed (or failed). Under the hood, this uses an API which uses the internal
+// round data, network historical round lookup, and waiting on network events
+// to determine what has (or will) occur.
+//
+// The callbacks will return at timeoutMS if no state update occurs
+func (c *Client) WaitForRoundCompletion(roundID int,
+	rec RoundCompletionCallback, timeoutMS int) error {
+
+	f := func(allRoundsSucceeded, timedOut bool, rounds map[id.Round]api.RoundResult) {
+		rec.EventCallback(roundID, allRoundsSucceeded, timedOut)
+	}
+
+	timeout := time.Duration(timeoutMS) * time.Millisecond
+
+	return c.api.GetRoundResults([]id.Round{id.Round(roundID)}, timeout, f)
+}
+
+// WaitForMessageDelivery allows the caller to get notified if the rounds a
+// message was sent in successfully completed. Under the hood, this uses an API
+// which uses the internal round data, network historical round lookup, and
+// waiting on network events to determine what has (or will) occur.
 //
 // The callbacks will return at timeoutMS if no state update occurs
 //
 // This function takes the marshaled send report to ensure a memory leak does
 // not occur as a result of both sides of the bindings holding a reference to
 // the same pointer.
-func (c *Client) WaitForRoundCompletion(marshaledSendReport []byte,
+func (c *Client) WaitForMessageDelivery(marshaledSendReport []byte,
 	mdc MessageDeliveryCallback, timeoutMS int) error {
 
 	sr, err := UnmarshalSendReport(marshaledSendReport)
@@ -346,11 +395,11 @@ func (c *Client) GetUser() *User {
 }
 
 // GetNodeRegistrationStatus returns a struct with the number of nodes the
-// client is registered with and the number of in progress registrations.
+// client is registered with and the number total.
 func (c *Client) GetNodeRegistrationStatus() (*NodeRegistrationsStatus, error) {
-	registered, inProgress, err := c.api.GetNodeRegistrationStatus()
+	registered, total, err := c.api.GetNodeRegistrationStatus()
 
-	return &NodeRegistrationsStatus{registered, inProgress}, err
+	return &NodeRegistrationsStatus{registered, total}, err
 }
 
 /*
diff --git a/bindings/contact.go b/bindings/contact.go
index daa45aa357095fa243c1a8b699198265e027a7f8..47a7a7290e4fec3684523d54312d359643fc3dbb 100644
--- a/bindings/contact.go
+++ b/bindings/contact.go
@@ -8,7 +8,7 @@
 package bindings
 
 import (
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
 )
 
diff --git a/bindings/list.go b/bindings/list.go
index 3fc31382636507aa32ec8423c1ac04d7a4c13092..c44fb1679fc0e6492c7c711e7d610bab01198c78 100644
--- a/bindings/list.go
+++ b/bindings/list.go
@@ -9,7 +9,7 @@ package bindings
 
 import (
 	"errors"
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
 )
@@ -99,8 +99,8 @@ func (fl *FactList) Num() int {
 	return len(fl.c.Facts)
 }
 
-func (fl *FactList) Get(i int) Fact {
-	return Fact{f: &(fl.c.Facts)[i]}
+func (fl *FactList) Get(i int) *Fact {
+	return &Fact{f: &(fl.c.Facts)[i]}
 }
 
 func (fl *FactList) Add(factData string, factType int) error {
diff --git a/bindings/message.go b/bindings/message.go
index 978a62743dbd823062f1c4a961e20d74f386c496..efe899de839473e304a3d57d4bc149e8aba2df2f 100644
--- a/bindings/message.go
+++ b/bindings/message.go
@@ -37,7 +37,7 @@ func (m *Message) GetMessageType() int {
 
 // Returns the message's timestamp in ms
 func (m *Message) GetTimestampMS() int {
-	return int(m.r.Timestamp.Unix())
+	return int(m.r.Timestamp.UnixNano()/1000000)
 }
 
 func (m *Message) GetTimestampNano() int {
diff --git a/bindings/registrationStatus.go b/bindings/registrationStatus.go
index 22446376436a0a8145c97e20e868073e1984d0a0..5d33cbd6e2031b39455363e096153afcf6c38833 100644
--- a/bindings/registrationStatus.go
+++ b/bindings/registrationStatus.go
@@ -11,7 +11,7 @@ package bindings
 // for bindings.
 type NodeRegistrationsStatus struct {
 	registered int
-	inProgress int
+	total      int
 }
 
 // GetRegistered returns the number of nodes registered with the client.
@@ -19,7 +19,7 @@ func (nrs *NodeRegistrationsStatus) GetRegistered() int {
 	return nrs.registered
 }
 
-// GetInProgress return the number of nodes currently registering.
-func (nrs *NodeRegistrationsStatus) GetInProgress() int {
-	return nrs.inProgress
+// GetTotal return the total of nodes currently in the network.
+func (nrs *NodeRegistrationsStatus) GetTotal() int {
+	return nrs.total
 }
diff --git a/bindings/timeNow.go b/bindings/timeNow.go
new file mode 100644
index 0000000000000000000000000000000000000000..dbeda1696669f98b9a489990ced0f66f51c9757b
--- /dev/null
+++ b/bindings/timeNow.go
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"gitlab.com/xx_network/primitives/netTime"
+	"time"
+)
+
+type TimeSource interface {
+	NowMs() int
+}
+
+// SetTimeSource sets the network time to a custom source.
+func SetTimeSource(timeNow TimeSource) {
+	netTime.Now = func() time.Time {
+		return time.Unix(0, int64(timeNow.NowMs()*int(time.Millisecond)))
+	}
+}
diff --git a/bindings/ud.go b/bindings/ud.go
index a4c3cb5babca0236b546e5cb10fc74b10a98f0f3..91a700d3b5e94316418699396dccf2f68ab00d5a 100644
--- a/bindings/ud.go
+++ b/bindings/ud.go
@@ -9,9 +9,9 @@ package bindings
 
 import (
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/ud"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
 	"time"
diff --git a/cmd/getndf.go b/cmd/getndf.go
index e794fb4d38b6f3d7e0ca82b2b3a2576afef0d6d6..7ac150020c911d695f646993e3a409c18d6cb8da 100644
--- a/cmd/getndf.go
+++ b/cmd/getndf.go
@@ -13,16 +13,18 @@ import (
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
-	// "gitlab.com/elixxir/client/interfaces/contact"
+	// "gitlab.com/elixxir/crypto/contact"
 	// "gitlab.com/elixxir/client/interfaces/message"
 	// "gitlab.com/elixxir/client/switchboard"
 	// "gitlab.com/elixxir/client/ud"
 	// "gitlab.com/elixxir/primitives/fact"
+	"gitlab.com/elixxir/client/api"
 	"gitlab.com/elixxir/comms/client"
 	"gitlab.com/xx_network/comms/connect"
 	//"time"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/utils"
 )
 
@@ -63,12 +65,14 @@ var getNDFCmd = &cobra.Command{
 		if gwHost != "" {
 			host, _ := connect.NewHost(&id.TempGateway, gwHost,
 				cert, params)
+			dummyID := ephemeral.ReservedIDs[0]
 			pollMsg := &pb.GatewayPoll{
 				Partial: &pb.NDFHash{
 					Hash: nil,
 				},
 				LastUpdate:  uint64(0),
-				ReceptionID: id.DummyUser.Marshal(),
+				ReceptionID: dummyID[:],
+				ClientVersion: []byte(api.SEMVER),
 			}
 			resp, err := comms.SendPoll(host, pollMsg)
 			if err != nil {
diff --git a/cmd/init.go b/cmd/init.go
index cf19521f066d1e9e878524a7ee75fd3471cf6b7c..b00f215475bfba0c513752b1d2fd01fd13cea5c8 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -11,6 +11,7 @@ package cmd
 import (
 	"fmt"
 	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
 	jww "github.com/spf13/jwalterweatherman"
 )
 
@@ -29,5 +30,9 @@ var initCmd = &cobra.Command{
 }
 
 func init() {
+	initCmd.Flags().StringP("userid-prefix", "", "",
+	"Desired prefix of userID to brute force when running init command. Prepend (?i) for case-insensitive. Only Base64 characters are valid.")
+	_ = viper.BindPFlag("userid-prefix", initCmd.Flags().Lookup("userid-prefix"))
+
 	rootCmd.AddCommand(initCmd)
 }
diff --git a/cmd/root.go b/cmd/root.go
index fb1efae75e8475ef671c9fbddd5b94bba61f0d9f..9ff887dad0dbb4d3d6e22a649f4ca43e5039a32e 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -17,10 +17,10 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
 	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/switchboard"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/id"
 	"io/ioutil"
 	"os"
@@ -52,6 +52,24 @@ var rootCmd = &cobra.Command{
 		jww.INFO.Printf("User: %s", user.ReceptionID)
 		writeContact(user.GetContact())
 
+		// Get Recipient and/or set it to myself
+		isPrecanPartner := false
+		recipientContact := readContact()
+		recipientID := recipientContact.ID
+
+		// Try to get recipientID from destid
+		if recipientID == nil {
+			recipientID, isPrecanPartner = parseRecipient(
+				viper.GetString("destid"))
+		}
+
+		// Set it to myself
+		if recipientID == nil {
+			jww.INFO.Printf("sending message to self")
+			recipientID = user.ReceptionID
+			recipientContact = user.GetContact()
+		}
+
 		// Set up reception handler
 		swboard := client.GetSwitchboard()
 		recvCh := make(chan message.Receive, 10000)
@@ -65,24 +83,25 @@ var rootCmd = &cobra.Command{
 		authMgr.AddGeneralRequestCallback(printChanRequest)
 
 		// If unsafe channels, add auto-acceptor
-		num_channels_confirmed := 0
+		authConfirmed := false
 		authMgr.AddGeneralConfirmCallback(func(
 			partner contact.Contact) {
 			jww.INFO.Printf("Channel Confirmed: %s",
 				partner.ID)
-			num_channels_confirmed++
+			authConfirmed = recipientID.Cmp(partner.ID)
 		})
 		if viper.GetBool("unsafe-channel-creation") {
 			authMgr.AddGeneralRequestCallback(func(
 				requestor contact.Contact, message string) {
 				jww.INFO.Printf("Channel Request: %s",
 					requestor.ID)
-				err := client.ConfirmAuthenticatedChannel(
+				_, err := client.ConfirmAuthenticatedChannel(
 					requestor)
 				if err != nil {
 					jww.FATAL.Panicf("%+v", err)
 				}
-				num_channels_confirmed++
+				authConfirmed = recipientID.Cmp(
+					requestor.ID)
 			})
 		}
 
@@ -99,53 +118,67 @@ var rootCmd = &cobra.Command{
 		// After connection, make sure we have registered with at least
 		// 85% of the nodes
 		numReg := 1
-		numNotReg := 100
-		for numReg < 3*numNotReg {
+		total := 100
+		for numReg < (total*3)/4 {
 			time.Sleep(1 * time.Second)
-			numReg, numNotReg, err = client.GetNodeRegistrationStatus()
+			numReg, total, err = client.GetNodeRegistrationStatus()
 			if err != nil {
 				jww.FATAL.Panicf("%+v", err)
 			}
 			jww.INFO.Printf("Registering with nodes (%d/%d)...",
-				numReg, (numReg + numNotReg))
+				numReg, total)
 		}
 
 		// Send Messages
 		msgBody := viper.GetString("message")
 
-		isPrecanPartner := false
-		recipientContact := readContact()
-		recipientID := recipientContact.ID
-
-		// Try to get recipientID from destid
-		if recipientID == nil {
-			recipientID, isPrecanPartner = parseRecipient(
-				viper.GetString("destid"))
-		}
-
-		// Set it to myself
-		if recipientID == nil {
-			jww.INFO.Printf("sending message to self")
-			recipientID = user.ReceptionID
-			recipientContact = user.GetContact()
-		}
-
 		time.Sleep(10 * time.Second)
 
 		// Accept auth request for this recipient
 		if viper.GetBool("accept-channel") {
 			acceptChannel(client, recipientID)
+			// Do not wait for channel confirmations if we
+			// accepted one
+			authConfirmed = true
+		}
+
+		if client.HasAuthenticatedChannel(recipientID) {
+			jww.INFO.Printf("Authenticated channel already in "+
+				"place for %s", recipientID)
+			authConfirmed = true
 		}
 
 		// Send unsafe messages or not?
 		unsafe := viper.GetBool("unsafe")
-		assumeAuth := viper.GetBool("assume-auth-channel")
-		if !unsafe && !assumeAuth {
+
+		sendAuthReq := viper.GetBool("send-auth-request")
+		if !unsafe && !authConfirmed && !isPrecanPartner &&
+			sendAuthReq {
 			addAuthenticatedChannel(client, recipientID,
-				recipientContact, isPrecanPartner)
-			// Do not wait for channel confirmations if we
-			// tried to add a channel
-			num_channels_confirmed++
+				recipientContact)
+		} else if !unsafe && !authConfirmed && isPrecanPartner {
+			addPrecanAuthenticatedChannel(client,
+				recipientID, recipientContact)
+			authConfirmed = true
+		}
+
+		if !unsafe && !authConfirmed {
+			jww.INFO.Printf("Waiting for authentication channel "+
+				" confirmation with partner %s", recipientID)
+			scnt := uint(0)
+			waitSecs := viper.GetUint("auth-timeout")
+			for !authConfirmed && scnt < waitSecs {
+				time.Sleep(1 * time.Second)
+				scnt++
+			}
+			if scnt == waitSecs {
+				jww.FATAL.Panicf("Could not confirm "+
+					"authentication channel for %s, "+
+					"waited %d seconds.", recipientID,
+					waitSecs)
+			}
+			jww.INFO.Printf("Authentication channel confirmation"+
+				" took %d seconds", scnt)
 		}
 
 		msg := message.Send{
@@ -187,7 +220,6 @@ var rootCmd = &cobra.Command{
 				jww.FATAL.Panicf("%+v", err)
 			}
 
-			jww.INFO.Printf("RoundIDs: %+v\n", roundIDs)
 			time.Sleep(sendDelay * time.Millisecond)
 		}
 
@@ -197,9 +229,9 @@ var rootCmd = &cobra.Command{
 		receiveCnt := uint(0)
 		waitSecs := viper.GetUint("waitTimeout")
 		waitTimeout := time.Duration(waitSecs)
-		timeoutTimer := time.NewTimer(waitTimeout * time.Second)
 		done := false
 		for !done && expectedCnt != 0 {
+			timeoutTimer := time.NewTimer(waitTimeout * time.Second)
 			select {
 			case <-timeoutTimer.C:
 				fmt.Println("Timed out!")
@@ -217,13 +249,6 @@ var rootCmd = &cobra.Command{
 			}
 		}
 		fmt.Printf("Received %d\n", receiveCnt)
-		if receiveCnt == 0 && sendCnt == 0 {
-			scnt := uint(0)
-			for num_channels_confirmed == 0 && scnt < waitSecs {
-				time.Sleep(1 * time.Second)
-				scnt++
-			}
-		}
 		err = client.StopNetworkFollower(5 * time.Second)
 		if err != nil {
 			jww.WARN.Printf(
@@ -281,7 +306,7 @@ func createClient() *api.Client {
 	storeDir := viper.GetString("session")
 	regCode := viper.GetString("regcode")
 	precannedID := viper.GetUint("sendid")
-
+	userIDprefix := viper.GetString("userid-prefix")
 	//create a new client if none exist
 	if _, err := os.Stat(storeDir); os.IsNotExist(err) {
 		// Load NDF
@@ -295,8 +320,14 @@ func createClient() *api.Client {
 			err = api.NewPrecannedClient(precannedID,
 				string(ndfJSON), storeDir, []byte(pass))
 		} else {
-			err = api.NewClient(string(ndfJSON), storeDir,
+			if userIDprefix != "" {
+				err = api.NewVanityClient(string(ndfJSON), storeDir,
+				[]byte(pass), regCode, userIDprefix)
+			} else {
+				err = api.NewClient(string(ndfJSON), storeDir,
 				[]byte(pass), regCode)
+			}
+			
 		}
 
 		if err != nil {
@@ -374,7 +405,7 @@ func acceptChannel(client *api.Client, recipientID *id.ID) {
 	if err != nil {
 		jww.FATAL.Panicf("%+v", err)
 	}
-	err = client.ConfirmAuthenticatedChannel(
+	_, err = client.ConfirmAuthenticatedChannel(
 		recipientContact)
 	if err != nil {
 		jww.FATAL.Panicf("%+v", err)
@@ -391,14 +422,27 @@ func printChanRequest(requestor contact.Contact, message string) {
 	//fmt.Printf(msg)
 }
 
-func addAuthenticatedChannel(client *api.Client, recipientID *id.ID,
-	recipient contact.Contact, isPrecanPartner bool) {
-	if client.HasAuthenticatedChannel(recipientID) {
-		jww.INFO.Printf("Authenticated channel already in place for %s",
-			recipientID)
-		return
+func addPrecanAuthenticatedChannel(client *api.Client, recipientID *id.ID,
+	recipient contact.Contact) {
+	jww.WARN.Printf("Precanned user id detected: %s", recipientID)
+	preUsr, err := client.MakePrecannedAuthenticatedChannel(
+		getPrecanID(recipientID))
+	if err != nil {
+		jww.FATAL.Panicf("%+v", err)
+	}
+	// Sanity check, make sure user id's haven't changed
+	preBytes := preUsr.ID.Bytes()
+	idBytes := recipientID.Bytes()
+	for i := 0; i < len(preBytes); i++ {
+		if idBytes[i] != preBytes[i] {
+			jww.FATAL.Panicf("no id match: %v %v",
+				preBytes, idBytes)
+		}
 	}
+}
 
+func addAuthenticatedChannel(client *api.Client, recipientID *id.ID,
+	recipient contact.Contact) {
 	var allowed bool
 	if viper.GetBool("unsafe-channel-creation") {
 		msg := "unsafe channel creation enabled\n"
@@ -419,28 +463,11 @@ func addAuthenticatedChannel(client *api.Client, recipientID *id.ID,
 
 	recipientContact := recipient
 
-	if isPrecanPartner {
-		jww.WARN.Printf("Precanned user id detected: %s",
-			recipientID)
-		preUsr, err := client.MakePrecannedAuthenticatedChannel(
-			getPrecanID(recipientID))
-		if err != nil {
-			jww.FATAL.Panicf("%+v", err)
-		}
-		// Sanity check, make sure user id's haven't changed
-		preBytes := preUsr.ID.Bytes()
-		idBytes := recipientID.Bytes()
-		for i := 0; i < len(preBytes); i++ {
-			if idBytes[i] != preBytes[i] {
-				jww.FATAL.Panicf("no id match: %v %v",
-					preBytes, idBytes)
-			}
-		}
-	} else if recipientContact.ID != nil && recipientContact.DhPubKey != nil {
+	if recipientContact.ID != nil && recipientContact.DhPubKey != nil {
 		me := client.GetUser().GetContact()
 		jww.INFO.Printf("Requesting auth channel from: %s",
 			recipientID)
-		err := client.RequestAuthenticatedChannel(recipientContact,
+		_, err := client.RequestAuthenticatedChannel(recipientContact,
 			me, msg)
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
@@ -708,16 +735,22 @@ func init() {
 	viper.BindPFlag("unsafe-channel-creation",
 		rootCmd.Flags().Lookup("unsafe-channel-creation"))
 
-	rootCmd.Flags().BoolP("assume-auth-channel", "", false,
-		"Do not check for an authentication channel for this user")
-	viper.BindPFlag("assume-auth-channel",
-		rootCmd.Flags().Lookup("assume-auth-channel"))
-
 	rootCmd.Flags().BoolP("accept-channel", "", false,
 		"Accept the channel request for the corresponding recipient ID")
 	viper.BindPFlag("accept-channel",
 		rootCmd.Flags().Lookup("accept-channel"))
 
+	rootCmd.Flags().BoolP("send-auth-request", "", false,
+		"Send an auth request to the specified destination and wait"+
+			"for confirmation")
+	viper.BindPFlag("send-auth-request",
+		rootCmd.Flags().Lookup("send-auth-request"))
+	rootCmd.Flags().UintP("auth-timeout", "", 120,
+		"The number of seconds to wait for an authentication channel"+
+			"to confirm")
+	viper.BindPFlag("auth-timeout",
+		rootCmd.Flags().Lookup("auth-timeout"))
+
 	rootCmd.Flags().BoolP("forceHistoricalRounds", "", false,
 		"Force all rounds to be sent to historical round retrieval")
 	viper.BindPFlag("forceHistoricalRounds",
diff --git a/cmd/single.go b/cmd/single.go
index cf2b07f78cdc6cbcd64181d84f4bc63dd53a4f67..15f803b11bec0f775845fdfdfb9f8292c75ea2a7 100644
--- a/cmd/single.go
+++ b/cmd/single.go
@@ -14,10 +14,10 @@ import (
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/switchboard"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/utils"
 	"time"
 )
@@ -55,7 +55,7 @@ var singleCmd = &cobra.Command{
 			authMgr.AddGeneralRequestCallback(func(
 				requester contact.Contact, message string) {
 				jww.INFO.Printf("Got request: %s", requester.ID)
-				err := client.ConfirmAuthenticatedChannel(requester)
+				_, err := client.ConfirmAuthenticatedChannel(requester)
 				if err != nil {
 					jww.FATAL.Panicf("%+v", err)
 				}
@@ -75,12 +75,15 @@ var singleCmd = &cobra.Command{
 		// Make single-use manager and start receiving process
 		singleMng := single.NewManager(client)
 
+		// Get the tag
+		tag := viper.GetString("tag")
+
 		// Register the callback
 		callbackChan := make(chan responseCallbackChan)
 		callback := func(payload []byte, c single.Contact) {
 			callbackChan <- responseCallbackChan{payload, c}
 		}
-		singleMng.RegisterCallback("tag", callback)
+		singleMng.RegisterCallback(tag, callback)
 		client.AddService(singleMng.StartProcesses)
 
 		timeout := viper.GetDuration("timeout")
@@ -92,7 +95,7 @@ var singleCmd = &cobra.Command{
 			partner := readSingleUseContact("contact")
 			maxMessages := uint8(viper.GetUint("maxMessages"))
 
-			sendSingleUse(singleMng, partner, payload, maxMessages, timeout)
+			sendSingleUse(singleMng, partner, payload, maxMessages, timeout, tag)
 		}
 
 		// If the reply flag is set, then start waiting for a message and reply
@@ -117,6 +120,10 @@ func init() {
 		"Path to contact file to send message to.")
 	_ = viper.BindPFlag("contact", singleCmd.Flags().Lookup("contact"))
 
+	singleCmd.Flags().StringP("tag", "", "testTag",
+		"The tag that specifies the callback to trigger on reception.")
+	_ = viper.BindPFlag("tag", singleCmd.Flags().Lookup("tag"))
+
 	singleCmd.Flags().Uint8("maxMessages", 1,
 		"The max number of single-use response messages.")
 	_ = viper.BindPFlag("maxMessages", singleCmd.Flags().Lookup("maxMessages"))
@@ -130,7 +137,7 @@ func init() {
 
 // sendSingleUse sends a single use message.
 func sendSingleUse(m *single.Manager, partner contact.Contact, payload []byte,
-	maxMessages uint8, timeout time.Duration) {
+	maxMessages uint8, timeout time.Duration, tag string) {
 	// Construct callback
 	callbackChan := make(chan struct {
 		payload []byte
@@ -151,7 +158,7 @@ func sendSingleUse(m *single.Manager, partner contact.Contact, payload []byte,
 	// Send single-use message
 	fmt.Printf("Sending single-use transmission message: %s\n", payload)
 	jww.DEBUG.Printf("Sending single-use transmission to %s: %s", partner.ID, payload)
-	err := m.TransmitSingleUse(partner, payload, "tag", maxMessages, callback, timeout)
+	err := m.TransmitSingleUse(partner, payload, tag, maxMessages, callback, timeout)
 	if err != nil {
 		jww.FATAL.Panicf("Failed to transmit single-use message: %+v", err)
 	}
diff --git a/cmd/ud.go b/cmd/ud.go
index fb9603dd52b18eb096bd3699c87b398dbcc8a7a5..38cbecb2cd1c6572cd140b158f435fe4291500cd 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -13,11 +13,11 @@ import (
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/elixxir/client/ud"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
 	"time"
 )
@@ -55,7 +55,7 @@ var udCmd = &cobra.Command{
 			authMgr.AddGeneralRequestCallback(func(
 				requester contact.Contact, message string) {
 				jww.INFO.Printf("Got Request: %s", requester.ID)
-				err := client.ConfirmAuthenticatedChannel(requester)
+				_, err := client.ConfirmAuthenticatedChannel(requester)
 				if err != nil {
 					jww.FATAL.Panicf("%+v", err)
 				}
diff --git a/cmd/version.go b/cmd/version.go
index 99af5a4c68449110c4b9281285596caf305b2e78..2a7eca16517f8e7f3d5c547ea35dbc472d4607c5 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -18,7 +18,7 @@ import (
 )
 
 // Change this value to set the version for this build
-const currentVersion = "2.0.0"
+const currentVersion = "2.3.0"
 
 func Version() string {
 	out := fmt.Sprintf("Elixxir Client v%s -- %s\n\n", api.SEMVER,
diff --git a/go.mod b/go.mod
index cbd7c3d26f28e77fded7b281126283cacffa2857..c0ce181a7926d457116daa6b0a14bef1801bed98 100644
--- a/go.mod
+++ b/go.mod
@@ -17,19 +17,18 @@ require (
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/viper v1.7.1
 	gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228
-	gitlab.com/elixxir/comms v0.0.4-0.20210311180506-28ae742c5e35
-	gitlab.com/elixxir/crypto v0.0.7-0.20210309193114-8a6225c667e2
-	gitlab.com/elixxir/ekv v0.1.4
-	gitlab.com/elixxir/primitives v0.0.3-0.20210309193003-ef42ebb4800b
-	gitlab.com/xx_network/comms v0.0.4-0.20210309192940-6b7fb39b4d01
-	gitlab.com/xx_network/crypto v0.0.5-0.20210309192854-cf32117afb96
-	gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a
-	golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
-	golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
-	golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect
+	gitlab.com/elixxir/comms v0.0.4-0.20210413160356-853e51fc18e5
+	gitlab.com/elixxir/crypto v0.0.7-0.20210412231025-6f75c577f803
+	gitlab.com/elixxir/ekv v0.1.5
+	gitlab.com/elixxir/primitives v0.0.3-0.20210409190923-7bf3cd8d97e7
+	gitlab.com/xx_network/comms v0.0.4-0.20210409202820-eb3dca6571d3
+	gitlab.com/xx_network/crypto v0.0.5-0.20210405224157-2b1f387b42c1
+	gitlab.com/xx_network/primitives v0.0.4-0.20210402222416-37c1c4d3fac4
+	golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
+	golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
 	google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 // indirect
 	google.golang.org/grpc v1.34.0 // indirect
-	google.golang.org/protobuf v1.25.0
+	google.golang.org/protobuf v1.26.0-rc.1
 	gopkg.in/ini.v1 v1.62.0 // indirect
 )
 
diff --git a/go.sum b/go.sum
index 15bdda0ba26fa5f23d7aa3c5993d95b458cf8a7d..2c9ea3fd15a1237eb861a5d9eda5b25d0d4a42db 100644
--- a/go.sum
+++ b/go.sum
@@ -84,10 +84,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -144,6 +142,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea h1:uyJ13zfy6l79CM3HnVhDalIyZ4RJAyVfDrbnfFeJoC4=
+github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea/go.mod h1:w4pGU9PkiX2hAWyF0yuHEHmYTQFAd6WHzp6+IY7JVjE=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
@@ -201,6 +201,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
 github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
@@ -243,52 +245,56 @@ github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
 github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
 github.com/zeebo/blake3 v0.0.4 h1:vtZ4X8B2lKXZFg2Xyg6Wo36mvmnJvc2VQYTtA4RDCkI=
 github.com/zeebo/blake3 v0.0.4/go.mod h1:YOZo8A49yNqM0X/Y+JmDUZshJWLt1laHsNSn5ny2i34=
-github.com/zeebo/blake3 v0.1.0 h1:sP3n5SxSbzU8x4Svc4ZcQv7SmQOqCkiKBeAZWP+hePo=
-github.com/zeebo/blake3 v0.1.0/go.mod h1:YOZo8A49yNqM0X/Y+JmDUZshJWLt1laHsNSn5ny2i34=
+github.com/zeebo/blake3 v0.1.1 h1:Nbsts7DdKThRHHd+YNlqiGlRqGEF2bE2eXN+xQ1hsEs=
+github.com/zeebo/blake3 v0.1.1/go.mod h1:G9pM4qQwjRzF1/v7+vabMj/c5mWpGZ2Wzo3Eb4z0pb4=
 github.com/zeebo/pcg v0.0.0-20181207190024-3cdc6b625a05 h1:4pW5fMvVkrgkMXdvIsVRRTs69DWYA8uNNQsu1stfVKU=
 github.com/zeebo/pcg v0.0.0-20181207190024-3cdc6b625a05/go.mod h1:Gr+78ptB0MwXxm//LBaEvBiaXY7hXJ6KGe2V32X2F6E=
 github.com/zeebo/pcg v1.0.0 h1:dt+dx+HvX8g7Un32rY9XWoYnd0NmKmrIzpHF7qiTDj0=
 github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 h1:Gi6rj4mAlK0BJIk1HIzBVMjWNjIUfstrsXC2VqLYPcA=
 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k=
-gitlab.com/elixxir/comms v0.0.4-0.20210310191320-05cba0d1a468 h1:EnfzSAdV+3WwWJ6cGY5xENrHwafy8tIUtz5qvDEZ4sw=
-gitlab.com/elixxir/comms v0.0.4-0.20210310191320-05cba0d1a468/go.mod h1:96cMuVVlarB+I6nuFKdq4zCagQkbhVK/MUzRk3yOymI=
-gitlab.com/elixxir/comms v0.0.4-0.20210310191636-1bca0ddac665 h1:2tWjyhX21DBXeAjiHJTFL/MCpb9L9mg7NE09sS8tb2k=
-gitlab.com/elixxir/comms v0.0.4-0.20210310191636-1bca0ddac665/go.mod h1:96cMuVVlarB+I6nuFKdq4zCagQkbhVK/MUzRk3yOymI=
-gitlab.com/elixxir/comms v0.0.4-0.20210310223853-60622bd841a8 h1:jhka79rXEc7hHn6uDbAjY7NhhKYWwtQ+iHtsa/Jfw1w=
-gitlab.com/elixxir/comms v0.0.4-0.20210310223853-60622bd841a8/go.mod h1:96cMuVVlarB+I6nuFKdq4zCagQkbhVK/MUzRk3yOymI=
-gitlab.com/elixxir/comms v0.0.4-0.20210311180506-28ae742c5e35 h1:t/ILeoWel5Im+zLQUX2FIroZvrfAkxOaL3DCA8enKcE=
-gitlab.com/elixxir/comms v0.0.4-0.20210311180506-28ae742c5e35/go.mod h1:96cMuVVlarB+I6nuFKdq4zCagQkbhVK/MUzRk3yOymI=
+gitlab.com/elixxir/comms v0.0.4-0.20210409192302-249b5af3dbc8 h1:k9BLWNw7CHwH4H3gNWA0Q/BXNg7923AFflWJtYZr5z4=
+gitlab.com/elixxir/comms v0.0.4-0.20210409192302-249b5af3dbc8/go.mod h1:/y5QIivolXMa6TO+ZqFWAV49wxlXXxUCqZH9Zi82kXU=
+gitlab.com/elixxir/comms v0.0.4-0.20210413160356-853e51fc18e5 h1:Q/+lhZpIDQdIKy9aXNCLkCk8AavFE7HAuaila0sv5mw=
+gitlab.com/elixxir/comms v0.0.4-0.20210413160356-853e51fc18e5/go.mod h1:0XsJ63n7knUeSX9BDKQG7xGtX6w0l5WsfplSsMbP9iM=
 gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4 h1:28ftZDeYEko7xptCZzeFWS1Iam95dj46TWFVVlKmw6A=
 gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c=
 gitlab.com/elixxir/crypto v0.0.3 h1:znCt/x2bL4y8czTPaaFkwzdgSgW3BJc/1+dxyf1jqVw=
 gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA=
-gitlab.com/elixxir/crypto v0.0.7-0.20210309193114-8a6225c667e2 h1:JMbUxcOjFpdCBUMZS5g8CWfNdPJ6pP8xsAZbnLj66jc=
-gitlab.com/elixxir/crypto v0.0.7-0.20210309193114-8a6225c667e2/go.mod h1:TMZMB24OsjF6y3LCyBMzDucbOx1cGQCCeuKV9lJA/DU=
-gitlab.com/elixxir/ekv v0.1.4 h1:NLVMwsFEKArWcsDHu2DbXlm9374iSgn7oIA3rVSsvjc=
-gitlab.com/elixxir/ekv v0.1.4/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4=
+gitlab.com/elixxir/crypto v0.0.7-0.20210409192145-eab67f2f8931 h1:kY/qBfjrZTFHJnvM1IcxB03+ZQL4+ESUjV4I4kCxoE8=
+gitlab.com/elixxir/crypto v0.0.7-0.20210409192145-eab67f2f8931/go.mod h1:ZktO3MT3oNo+g2Nq0GuC3ebJWJphh7t5KwwDDGBegnY=
+gitlab.com/elixxir/crypto v0.0.7-0.20210412193049-f3718fa4facb h1:9CT5f+nV4sisutLx8Z3BAEiqjktcCL2ZpEqcpmgzyqA=
+gitlab.com/elixxir/crypto v0.0.7-0.20210412193049-f3718fa4facb/go.mod h1:ZktO3MT3oNo+g2Nq0GuC3ebJWJphh7t5KwwDDGBegnY=
+gitlab.com/elixxir/crypto v0.0.7-0.20210412195114-be927031747a h1:DSYIXSCWrwkyHUs2fJMliI4+Bd9h+WA5PXI78uvhCj4=
+gitlab.com/elixxir/crypto v0.0.7-0.20210412195114-be927031747a/go.mod h1:HMMRBuv/yMqB5c31G9OPlOAifOOqGypCyD5v6py+4vo=
+gitlab.com/elixxir/crypto v0.0.7-0.20210412231025-6f75c577f803 h1:8sLODlAYRT0Y9NA+uoMoF1qBrBRrW5TikyKAOvyCd+E=
+gitlab.com/elixxir/crypto v0.0.7-0.20210412231025-6f75c577f803/go.mod h1:HMMRBuv/yMqB5c31G9OPlOAifOOqGypCyD5v6py+4vo=
+gitlab.com/elixxir/ekv v0.1.5 h1:R8M1PA5zRU1HVnTyrtwybdABh7gUJSCvt1JZwUSeTzk=
+gitlab.com/elixxir/ekv v0.1.5/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4=
 gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg=
 gitlab.com/elixxir/primitives v0.0.0-20200804170709-a1896d262cd9/go.mod h1:p0VelQda72OzoUckr1O+vPW0AiFe0nyKQ6gYcmFSuF8=
 gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc=
 gitlab.com/elixxir/primitives v0.0.1 h1:q61anawANlNAExfkeQEE1NCsNih6vNV1FFLoUQX6txQ=
 gitlab.com/elixxir/primitives v0.0.1/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
-gitlab.com/elixxir/primitives v0.0.3-0.20210309193003-ef42ebb4800b h1:TswWfqiZqsdPLeWsfe7VJHMlV01W792kRHGYfYwb2Lk=
-gitlab.com/elixxir/primitives v0.0.3-0.20210309193003-ef42ebb4800b/go.mod h1:/e3a4KPqmA9V22qKSZ9prfYYNzIzvLI8xh7noVV091w=
+gitlab.com/elixxir/primitives v0.0.3-0.20210409190923-7bf3cd8d97e7 h1:q3cw7WVtD6hDqTi8ydky+yiqJ4RkWp/hkTSNirr9Z6Y=
+gitlab.com/elixxir/primitives v0.0.3-0.20210409190923-7bf3cd8d97e7/go.mod h1:h0QHrjrixLNaP24ZXAgDOZXP4eegrQ24BCZPGitg8Jg=
 gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
-gitlab.com/xx_network/comms v0.0.4-0.20210309192940-6b7fb39b4d01 h1:f93iz7mTHt3r37O97vaQD8otohihLN3OnAEEbDGQdVs=
-gitlab.com/xx_network/comms v0.0.4-0.20210309192940-6b7fb39b4d01/go.mod h1:aNPRHmPssXc1JMJ83DAknT2C2iMgKL1wH3//AqQrhQc=
+gitlab.com/xx_network/comms v0.0.4-0.20210406210737-45d1e87d294a h1:r0mvBjHPBCYEVmhEe6JhLQDc0+dCORf1ejtuZ8IbyKY=
+gitlab.com/xx_network/comms v0.0.4-0.20210406210737-45d1e87d294a/go.mod h1:7ciuA+LTE0GC7upviGbyyb2hrpJG9Pnq2cc5oz2N5Ss=
+gitlab.com/xx_network/comms v0.0.4-0.20210409202820-eb3dca6571d3 h1:0o9kveRSEQ9ykRh/hd+z9Iq53YNvFArW1RQ6ICdAG5g=
+gitlab.com/xx_network/comms v0.0.4-0.20210409202820-eb3dca6571d3/go.mod h1:7ciuA+LTE0GC7upviGbyyb2hrpJG9Pnq2cc5oz2N5Ss=
 gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE=
 gitlab.com/xx_network/crypto v0.0.4 h1:lpKOL5mTJ2awWMfgBy30oD/UvJVrWZzUimSHlOdZZxo=
 gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk=
-gitlab.com/xx_network/crypto v0.0.5-0.20210309192854-cf32117afb96 h1:VZGJNhuU6YunKyK4MbNZf25UxQsmU1bH5SnbK93tI7Q=
-gitlab.com/xx_network/crypto v0.0.5-0.20210309192854-cf32117afb96/go.mod h1:TtaHpuX0lcuTTtcq+pz+lMusjyTgvSohIHFOlVwN1uU=
+gitlab.com/xx_network/crypto v0.0.5-0.20210405224157-2b1f387b42c1 h1:4Hrphjtqn3vO8LI872YwVKy5dCFJdD5u0dE4O2QCZqU=
+gitlab.com/xx_network/crypto v0.0.5-0.20210405224157-2b1f387b42c1/go.mod h1:CUhRpioyLaKIylg+LIyZX1rhOmFaEXQQ6esNycx9dcA=
 gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA=
 gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da h1:CCVslUwNC7Ul7NG5nu3ThGTSVUt1TxNRX+47f5TUwnk=
 gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug=
 gitlab.com/xx_network/primitives v0.0.2 h1:r45yKenJ9e7PylI1ZXJ1Es09oYNaYXjxVy9+uYlwo7Y=
 gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc=
-gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a h1:Ume9QbJ4GoJh7v5yg/YVDjowJHx/VFeOC/A4PJZUm9g=
-gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE=
+gitlab.com/xx_network/primitives v0.0.4-0.20210402222416-37c1c4d3fac4 h1:YPYTKF0zQf08y0eQrjQP01C/EWQTypdqawjZPr5c6rc=
+gitlab.com/xx_network/primitives v0.0.4-0.20210402222416-37c1c4d3fac4/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE=
 gitlab.com/xx_network/ring v0.0.2 h1:TlPjlbFdhtJrwvRgIg4ScdngMTaynx/ByHBRZiXCoL0=
 gitlab.com/xx_network/ring v0.0.2/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -314,6 +320,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rB
 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -347,8 +355,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -376,10 +384,12 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7
 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 h1:/dSxr6gT0FNI1MO5WLJo8mTmItROeOKTkDn+7OwWBos=
-golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d h1:jbzgAvDZn8aEnytae+4ou0J0GwFZoHR0hOrTg4qH8GA=
+golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -431,7 +441,6 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 h1:Zk6zlGXdtYdcY5TL+VrbTfmifvk3VvsXopCpszsHPBA=
 google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -446,8 +455,8 @@ google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyz
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/interfaces/auth.go b/interfaces/auth.go
index 68e18be6fc51bb90a67b082f396582bb79b88625..bb3cae74d0a37f0fda2c34e8ce0623af6f8a789f 100644
--- a/interfaces/auth.go
+++ b/interfaces/auth.go
@@ -8,7 +8,7 @@
 package interfaces
 
 import (
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/interfaces/contact/contact.go b/interfaces/contact/contact.go
deleted file mode 100644
index 498500b039a72da3ba9336e2815d34706bf86dbd..0000000000000000000000000000000000000000
--- a/interfaces/contact/contact.go
+++ /dev/null
@@ -1,160 +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 contact
-
-import (
-	"bytes"
-	"crypto"
-	"encoding/base64"
-	"encoding/binary"
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/primitives/fact"
-	"gitlab.com/xx_network/primitives/id"
-)
-
-const sizeByteLength = 2
-const fingerprintLength = 15
-
-// Contact implements the Contact interface defined in interface/contact.go,
-// in go, the structure is meant to be edited directly, the functions are for
-// bindings compatibility
-type Contact struct {
-	ID             *id.ID
-	DhPubKey       *cyclic.Int
-	OwnershipProof []byte
-	Facts          fact.FactList
-}
-
-// Marshal saves the Contact in a compact byte slice. The byte slice has
-// the following structure (not to scale).
-//
-// +----------+----------------+---------+----------+----------+----------------+----------+
-// | DhPubKey | OwnershipProof |  Facts  |    ID    |          |                |          |
-// |   size   |      size      |   size  |          | DhPubKey | OwnershipProof | FactList |
-// |  2 bytes |     2 bytes    | 2 bytes | 33 bytes |          |                |          |
-// +----------+----------------+---------+----------+----------+----------------+----------+
-func (c Contact) Marshal() []byte {
-	var buff bytes.Buffer
-	b := make([]byte, sizeByteLength)
-
-	// Write size of DhPubKey
-	var dhPubKey []byte
-	if c.DhPubKey != nil {
-		dhPubKey = c.DhPubKey.BinaryEncode()
-		binary.PutVarint(b, int64(len(dhPubKey)))
-	}
-	buff.Write(b)
-
-	// Write size of OwnershipProof
-	binary.PutVarint(b, int64(len(c.OwnershipProof)))
-	buff.Write(b)
-
-	// Write length of Facts
-	factList := c.Facts.Stringify()
-	binary.PutVarint(b, int64(len(factList)))
-	buff.Write(b)
-
-	// Write ID
-	if c.ID != nil {
-		buff.Write(c.ID.Marshal())
-	} else {
-		// Handle nil ID
-		buff.Write(make([]byte, id.ArrIDLen))
-	}
-
-	// Write DhPubKey
-	buff.Write(dhPubKey)
-
-	// Write OwnershipProof
-	buff.Write(c.OwnershipProof)
-
-	// Write fact list
-	buff.Write([]byte(factList))
-
-	return buff.Bytes()
-}
-
-// Unmarshal decodes the byte slice produced by Contact.Marshal into a Contact.
-func Unmarshal(b []byte) (Contact, error) {
-	if len(b) < sizeByteLength*3+id.ArrIDLen {
-		return Contact{}, errors.Errorf("Length of provided buffer (%d) too "+
-			"short; length must be at least %d.",
-			len(b), sizeByteLength*3+id.ArrIDLen)
-	}
-
-	c := Contact{DhPubKey: &cyclic.Int{}}
-	var err error
-	buff := bytes.NewBuffer(b)
-
-	// Get size of each field
-	dhPubKeySize, _ := binary.Varint(buff.Next(sizeByteLength))
-	ownershipProofSize, _ := binary.Varint(buff.Next(sizeByteLength))
-	factsSize, _ := binary.Varint(buff.Next(sizeByteLength))
-
-	// Get and unmarshal ID
-	c.ID, err = id.Unmarshal(buff.Next(id.ArrIDLen))
-	if err != nil {
-		return Contact{}, errors.Errorf("Failed to unmarshal Contact ID: %+v", err)
-	}
-
-	// Handle nil ID
-	if bytes.Equal(c.ID.Marshal(), make([]byte, id.ArrIDLen)) {
-		c.ID = nil
-	}
-
-	// Get and decode DhPubKey
-	if dhPubKeySize == 0 {
-		// Handle nil key
-		c.DhPubKey = nil
-	} else {
-		if err = c.DhPubKey.BinaryDecode(buff.Next(int(dhPubKeySize))); err != nil {
-			return Contact{}, errors.Errorf("Failed to binary decode Contact DhPubKey: %+v", err)
-		}
-	}
-
-	// Get OwnershipProof
-	if ownershipProofSize == 0 {
-		// Handle nil OwnershipProof
-		c.OwnershipProof = nil
-	} else {
-		c.OwnershipProof = buff.Next(int(ownershipProofSize))
-	}
-
-	// Get and unstringify fact list
-	c.Facts, _, err = fact.UnstringifyFactList(string(buff.Next(int(factsSize))))
-	if err != nil {
-		return Contact{}, errors.Errorf("Failed to unstringify Contact fact list: %+v", err)
-	}
-
-	return c, nil
-}
-
-// GetFingerprint creates a 15 character long fingerprint of the contact off of
-// the ID and DH public key.
-func (c Contact) GetFingerprint() string {
-	// Generate hash
-	sha := crypto.SHA256
-	h := sha.New()
-
-	// Hash ID and DH public key
-	h.Write(c.ID.Bytes())
-	h.Write(c.DhPubKey.Bytes())
-	data := h.Sum(nil)
-
-	// Base64 encode hash and truncate it
-	return base64.StdEncoding.EncodeToString(data)[:fingerprintLength]
-}
-
-// Equal determines if the two contacts have the same values.
-func Equal(a, b Contact) bool {
-	return a.ID.Cmp(b.ID) &&
-		a.DhPubKey.Cmp(b.DhPubKey) == 0 &&
-		bytes.Equal(a.OwnershipProof, b.OwnershipProof) &&
-		a.Facts.Stringify() == b.Facts.Stringify()
-}
diff --git a/interfaces/contact/contact_test.go b/interfaces/contact/contact_test.go
deleted file mode 100644
index 2d43f1818986c26f81ad5f389dce028e88ec10cd..0000000000000000000000000000000000000000
--- a/interfaces/contact/contact_test.go
+++ /dev/null
@@ -1,232 +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 contact
-
-import (
-	"crypto"
-	"encoding/base64"
-	"encoding/json"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/primitives/fact"
-	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/large"
-	"gitlab.com/xx_network/primitives/id"
-	"math/rand"
-	"reflect"
-	"strings"
-	"testing"
-)
-
-// Tests marshaling and unmarshalling of a common Contact.
-func TestContact_Marshal_Unmarshal(t *testing.T) {
-	expectedContact := Contact{
-		ID:       id.NewIdFromUInt(rand.Uint64(), id.User, t),
-		DhPubKey: getCycInt(256),
-		Facts: fact.FactList{
-			{Fact: "myUsername", T: fact.Username},
-			{Fact: "devinputvalidation@elixxir.io", T: fact.Email},
-			{Fact: "6502530000US", T: fact.Phone},
-			{Fact: "6502530001US", T: fact.Phone},
-		},
-	}
-
-	buff := expectedContact.Marshal()
-
-	testContact, err := Unmarshal(buff)
-	if err != nil {
-		t.Errorf("Unmarshal() produced an error: %+v", err)
-	}
-
-	if !reflect.DeepEqual(expectedContact, testContact) {
-		t.Errorf("Unmarshaled Contact does not match expected."+
-			"\nexpected: %#v\nreceived: %#v", expectedContact, testContact)
-	}
-}
-
-// Tests marshaling and unmarshalling of a Contact with nil fields.
-func TestContact_Marshal_Unmarshal_Nil(t *testing.T) {
-	expectedContact := Contact{}
-
-	buff := expectedContact.Marshal()
-
-	testContact, err := Unmarshal(buff)
-	if err != nil {
-		t.Errorf("Unmarshal() produced an error: %+v", err)
-	}
-
-	if !reflect.DeepEqual(expectedContact, testContact) {
-		t.Errorf("Unmarshaled Contact does not match expected."+
-			"\nexpected: %#v\nreceived: %#v", expectedContact, testContact)
-	}
-}
-
-// Tests the size of marshaling and JSON marshaling of a Contact with a large
-// amount of data.
-func TestContact_Marshal_Size(t *testing.T) {
-	expectedContact := Contact{
-		ID:             id.NewIdFromUInt(rand.Uint64(), id.User, t),
-		DhPubKey:       getCycInt(512),
-		OwnershipProof: make([]byte, 1024),
-		Facts: fact.FactList{
-			{Fact: "myVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongUsername", T: fact.Username},
-			{Fact: "myVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongEmail@elixxir.io", T: fact.Email},
-			{Fact: "6502530000US", T: fact.Phone},
-		},
-	}
-	rand.Read(expectedContact.OwnershipProof)
-
-	buff := expectedContact.Marshal()
-
-	marshalBuff, err := json.Marshal(expectedContact)
-	if err != nil {
-		t.Errorf("Marshal() produced an error: %+v", err)
-	}
-
-	t.Logf("size of buff:        %d", len(buff))
-	t.Logf("size of marshalBuff: %d", len(marshalBuff))
-	t.Logf("ratio: %.2f%%", float32(len(buff))/float32(len(marshalBuff))*100)
-	t.Logf("%s", marshalBuff)
-
-	if len(marshalBuff) < len(buff) {
-		t.Errorf("JSON Contact smaller than marshaled contact."+
-			"\nJSON:    %d\nmarshal: %d", len(marshalBuff), len(buff))
-	}
-}
-
-// Unit test of GetFingerprint.
-func TestContact_GetFingerprint(t *testing.T) {
-	c := Contact{
-		ID:       id.NewIdFromString("Samwise", id.User, t),
-		DhPubKey: getCycInt(512),
-	}
-
-	testFP := c.GetFingerprint()
-	if len(testFP) != fingerprintLength {
-		t.Errorf("GetFingerprint() returned fingerprint with unexpected length."+
-			"\nexpected length: %d\nreceived length: %d",
-			fingerprintLength, len(testFP))
-	}
-
-	// Generate expected fingerprint
-	h := crypto.SHA256.New()
-	h.Write(c.ID.Bytes())
-	h.Write(c.DhPubKey.Bytes())
-	expectedFP := base64.StdEncoding.EncodeToString(h.Sum(nil))[:fingerprintLength]
-
-	if strings.Compare(expectedFP, testFP) != 0 {
-		t.Errorf("GetFingerprint() returned expected fingerprint."+
-			"\nexpected: %s\nreceived: %s", expectedFP, testFP)
-	}
-
-}
-
-// Consistency test for changes in underlying dependencies.
-func TestContact_GetFingerprint_Consistency(t *testing.T) {
-	expected := []string{
-		"rBUw1n4jtH4uEYq", "Z/Jm1OUwDaql5cd", "+vHLzY+yH96zAiy",
-		"cZm5Iz78ViOIlnh", "9LqrcbFEIV4C4LX", "ll4eykGpMWYlxw+",
-		"6YQshWJhdPL6ajx", "Y6gTPVEzow4IHOm", "6f/rT2vWxDC9tdt",
-		"rwqbDT+PoeA6Iww", "YN4IFijP/GZ172O", "ScbHVQc2T9SXQ2m",
-		"50mfbCXQ+LIqiZn", "cyRYdMKXByiFdtC", "7g6ujy7iIbJVl4F",
-	}
-
-	for i := range expected {
-		c := Contact{
-			ID:       id.NewIdFromUInt(uint64(i), id.User, t),
-			DhPubKey: getGroup().NewInt(25),
-		}
-
-		fp := c.GetFingerprint()
-		if expected[i] != fp {
-			t.Errorf("GetFingerprint() did not output the expected fingerprint (%d)."+
-				"\nexpected: %s\nreceived: %s", i, expected[i], fp)
-		}
-	}
-}
-
-// Happy path.
-func TestEqual(t *testing.T) {
-	a := Contact{
-		ID:             id.NewIdFromUInt(rand.Uint64(), id.User, t),
-		DhPubKey:       getCycInt(512),
-		OwnershipProof: make([]byte, 1024),
-		Facts: fact.FactList{
-			{Fact: "myUsername", T: fact.Username},
-			{Fact: "devinputvalidation@elixxir.io", T: fact.Email},
-		},
-	}
-	rand.Read(a.OwnershipProof)
-	b := Contact{
-		ID:             a.ID,
-		DhPubKey:       a.DhPubKey,
-		OwnershipProof: a.OwnershipProof,
-		Facts:          a.Facts,
-	}
-	c := Contact{
-		ID:             id.NewIdFromUInt(rand.Uint64(), id.User, t),
-		DhPubKey:       getCycInt(512),
-		OwnershipProof: make([]byte, 1024),
-	}
-
-	if !Equal(a, b) {
-		t.Errorf("Equal reported two equal contacts as different."+
-			"\na: %+v\nb: +%v", a, b)
-	}
-
-	if Equal(a, c) {
-		t.Errorf("Equal reported two unequal contacts as the same."+
-			"\na: %+v\nc: +%v", a, c)
-	}
-}
-
-func getCycInt(size int) *cyclic.Int {
-	var primeString = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E0" +
-		"88A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F" +
-		"14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDE" +
-		"E386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48" +
-		"361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED52907709" +
-		"6966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E8603" +
-		"9B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D22" +
-		"61898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458" +
-		"DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619" +
-		"DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE1" +
-		"17577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A" +
-		"92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150B" +
-		"DA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B" +
-		"2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" +
-		"D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFF" +
-		"FFF"
-
-	buff, err := csprng.GenerateInGroup([]byte(primeString), size, csprng.NewSystemRNG())
-	if err != nil {
-		panic(err)
-	}
-
-	grp := cyclic.NewGroup(large.NewIntFromString(primeString, 16),
-		large.NewInt(2)).NewIntFromBytes(buff)
-
-	return grp
-}
-
-func getGroup() *cyclic.Group {
-	return cyclic.NewGroup(
-		large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D4941"+
-			"3394C049B7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688"+
-			"B55B3DD2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861"+
-			"575E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC"+
-			"718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FF"+
-			"B1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBC"+
-			"A23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD"+
-			"161C7738F32BF29A841698978825B4111B4BC3E1E198455095958333D776D8B2B"+
-			"EEED3A1A1A221A6E37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C"+
-			"4F50D7D7803D2D4F278DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F"+
-			"1390B5D3FEACAF1696015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F"+
-			"96789C38E89D796138E6319BE62E35D87B1048CA28BE389B575E994DCA7554715"+
-			"84A09EC723742DC35873847AEF49F66E43873", 16),
-		large.NewIntFromString("2", 16))
-}
diff --git a/interfaces/params/network.go b/interfaces/params/network.go
index b73efc7a3ee56c5d2f24d18643194a22852dbc92..b84c38a09310f13d13a5cd74d4ddfb83c62fc717 100644
--- a/interfaces/params/network.go
+++ b/interfaces/params/network.go
@@ -23,6 +23,8 @@ type Network struct {
 	NetworkHealthTimeout time.Duration
 	//Number of parallel node registration the client is capable of
 	ParallelNodeRegistrations uint
+	//How far back in rounds the network should actually check
+	KnownRoundsThreshold uint
 
 	Rounds
 	Messages
@@ -39,6 +41,7 @@ func GetDefaultNetwork() Network {
 		NetworkHealthTimeout: 30 * time.Second,
 		E2EParams:            GetDefaultE2ESessionParams(),
 		ParallelNodeRegistrations: 8,
+		KnownRoundsThreshold: 1500, //5 rounds/sec * 60 sec/min * 5 min
 	}
 	n.Rounds = GetDefaultRounds()
 	n.Messages = GetDefaultMessage()
diff --git a/interfaces/params/rounds.go b/interfaces/params/rounds.go
index dbf0d5a00fdbb07ad813244f75f84eda34ddcd57..87fa53fc04517b8262ffbc8be624b3989dddeb91 100644
--- a/interfaces/params/rounds.go
+++ b/interfaces/params/rounds.go
@@ -12,9 +12,6 @@ import (
 )
 
 type Rounds struct {
-	// Maximum number of times to attempt to retrieve a round from a gateway
-	// before giving up on it
-	MaxAttemptsCheckingARound uint
 	// Number of historical rounds required to automatically send a historical
 	// rounds query
 	MaxHistoricalRounds uint
@@ -31,11 +28,13 @@ type Rounds struct {
 
 	// Toggles if historical rounds should always be used
 	ForceHistoricalRounds bool
+
+	// Maximum number of times a historical round lookup will be attempted
+	MaxHistoricalRoundsRetries uint
 }
 
 func GetDefaultRounds() Rounds {
 	return Rounds{
-		MaxAttemptsCheckingARound:  5,
 		MaxHistoricalRounds:        100,
 		HistoricalRoundsPeriod:     100 * time.Millisecond,
 		NumMessageRetrievalWorkers: 8,
@@ -43,5 +42,6 @@ func GetDefaultRounds() Rounds {
 		HistoricalRoundsBufferLen: 1000,
 		LookupRoundsBufferLen:     2000,
 		ForceHistoricalRounds:     false,
+		MaxHistoricalRoundsRetries: 3,
 	}
 }
diff --git a/interfaces/user/user.go b/interfaces/user/user.go
index 1aaea8a31d67d0dd1facb50cbb7170a0055abf92..7d480700e0e1c048b4ac9fcd98edb6fb25112b51 100644
--- a/interfaces/user/user.go
+++ b/interfaces/user/user.go
@@ -8,7 +8,7 @@
 package user
 
 import (
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/crypto/signature/rsa"
diff --git a/keyExchange/confirm.go b/keyExchange/confirm.go
index ce31c0c6fa933b3fccd203bf6b0bfdbd968818c5..01c43c5d42dd602fb314815d993b20ab7d16e401 100644
--- a/keyExchange/confirm.go
+++ b/keyExchange/confirm.go
@@ -18,10 +18,11 @@ import (
 )
 
 func startConfirm(sess *storage.Session, c chan message.Receive,
-	stop *stoppable.Single) {
+	stop *stoppable.Single, cleanup func()) {
 	for true {
 		select {
 		case <-stop.Quit():
+			cleanup()
 			return
 		case confirmation := <-c:
 			handleConfirm(sess, confirmation)
diff --git a/keyExchange/confirm_test.go b/keyExchange/confirm_test.go
index b2e619c684c0985ded4887178113ade1d489af1d..8cef6f6f60488568614208f751914332ca5267f9 100644
--- a/keyExchange/confirm_test.go
+++ b/keyExchange/confirm_test.go
@@ -13,8 +13,8 @@ import (
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/storage/e2e"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"testing"
-	"time"
 )
 
 // Smoke test for handleTrigger
@@ -57,7 +57,7 @@ func TestHandleConfirm(t *testing.T) {
 		Payload:     rekey,
 		MessageType: message.KeyExchangeConfirm,
 		Sender:      bobID,
-		Timestamp:   time.Now(),
+		Timestamp:   netTime.Now(),
 		Encryption:  message.E2E,
 	}
 
diff --git a/keyExchange/exchange.go b/keyExchange/exchange.go
index caf7c7a596762c95ea9da22e1cb5825dc80d566f..d94e8800f60d440c3c0c8b41564c04f4ada32ba7 100644
--- a/keyExchange/exchange.go
+++ b/keyExchange/exchange.go
@@ -15,7 +15,6 @@ import (
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
 )
 
 const keyExchangeTriggerName = "KeyExchangeTrigger"
@@ -32,14 +31,13 @@ func Start(switchboard *switchboard.Switchboard, sess *storage.Session, net inte
 
 	// create the trigger stoppable
 	triggerStop := stoppable.NewSingle(keyExchangeTriggerName)
-	triggerStopCleanup := stoppable.NewCleanup(triggerStop,
-		func(duration time.Duration) error {
-			switchboard.Unregister(triggerID)
-			return nil
-		})
+
+	cleanupTrigger := func(){
+		switchboard.Unregister(triggerID)
+	}
 
 	// start the trigger thread
-	go startTrigger(sess, net, triggerCh, triggerStop.Quit(), params)
+	go startTrigger(sess, net, triggerCh, triggerStop, params, cleanupTrigger)
 
 	//register the rekey confirm thread
 	confirmCh := make(chan message.Receive, 100)
@@ -48,18 +46,16 @@ func Start(switchboard *switchboard.Switchboard, sess *storage.Session, net inte
 
 	// register the confirm stoppable
 	confirmStop := stoppable.NewSingle(keyExchangeConfirmName)
-	confirmStopCleanup := stoppable.NewCleanup(confirmStop,
-		func(duration time.Duration) error {
-			switchboard.Unregister(confirmID)
-			return nil
-		})
+	cleanupConfirm := func(){
+		switchboard.Unregister(confirmID)
+	}
 
 	// start the confirm thread
-	go startConfirm(sess, confirmCh, confirmStop)
+	go startConfirm(sess, confirmCh, confirmStop, cleanupConfirm)
 
 	//bundle the stoppables and return
 	exchangeStop := stoppable.NewMulti(keyExchangeMulti)
-	exchangeStop.Add(triggerStopCleanup)
-	exchangeStop.Add(confirmStopCleanup)
+	exchangeStop.Add(triggerStop)
+	exchangeStop.Add(confirmStop)
 	return exchangeStop
 }
diff --git a/keyExchange/exchange_test.go b/keyExchange/exchange_test.go
index 2c1729995c28d528c19ffe88a92ae425d2b57e0d..4fd98b3e650a191d6facf40d0e1321bfdc84a031 100644
--- a/keyExchange/exchange_test.go
+++ b/keyExchange/exchange_test.go
@@ -19,6 +19,7 @@ import (
 	dh "gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"testing"
 	"time"
 )
@@ -74,7 +75,7 @@ func TestFullExchange(t *testing.T) {
 		Payload:     rekeyTrigger,
 		MessageType: message.KeyExchangeTrigger,
 		Sender:      exchangeBobId,
-		Timestamp:   time.Now(),
+		Timestamp:   netTime.Now(),
 		Encryption:  message.E2E,
 	}
 
diff --git a/keyExchange/trigger.go b/keyExchange/trigger.go
index 544cde8eee82c1979568f639cc0d454f6d205d06..a72da7b110c92e0065a5f9acaf79698565f8815c 100644
--- a/keyExchange/trigger.go
+++ b/keyExchange/trigger.go
@@ -16,6 +16,7 @@ import (
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/interfaces/utility"
+	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/storage/e2e"
 	ds "gitlab.com/elixxir/comms/network/dataStructures"
@@ -26,20 +27,23 @@ import (
 const (
 	errBadTrigger = "non-e2e trigger from partner %s"
 	errUnknown    = "unknown trigger from partner %s"
+	errFailed     = "Failed to handle rekey trigger: %s"
 )
 
 func startTrigger(sess *storage.Session, net interfaces.NetworkManager,
-	c chan message.Receive, quitCh <-chan struct{}, params params.Rekey) {
+	c chan message.Receive, stop *stoppable.Single, params params.Rekey, cleanup func()) {
 	for true {
 		select {
-		case <-quitCh:
+		case <-stop.Quit():
+			cleanup()
 			return
 		case request := <-c:
-			err := handleTrigger(sess, net, request, params)
-			if err != nil {
-				jww.ERROR.Printf("Failed to handle rekey trigger: %s",
-					err)
-			}
+			go func() {
+				err := handleTrigger(sess, net, request, params)
+				if err != nil {
+					jww.ERROR.Printf(errFailed, err)
+				}
+			}()
 		}
 	}
 }
diff --git a/keyExchange/trigger_test.go b/keyExchange/trigger_test.go
index c69e09562bd10bbe998855c33f3c765b7f0ed085..430bba91a0ba734541b03a61260493caa03237e0 100644
--- a/keyExchange/trigger_test.go
+++ b/keyExchange/trigger_test.go
@@ -14,6 +14,7 @@ import (
 	dh "gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"google.golang.org/protobuf/proto"
 	"testing"
 	"time"
@@ -54,7 +55,7 @@ func TestHandleTrigger(t *testing.T) {
 		Payload:     rekey,
 		MessageType: message.NoType,
 		Sender:      bobID,
-		Timestamp:   time.Now(),
+		Timestamp:   netTime.Now(),
 		Encryption:  message.E2E,
 	}
 
diff --git a/keyExchange/utils_test.go b/keyExchange/utils_test.go
index 162db4728cec9ddfa0b91d0f0ae3acc6e0c7c522..a1447b990744f92b063420888ea1c96e1d9fb5dd 100644
--- a/keyExchange/utils_test.go
+++ b/keyExchange/utils_test.go
@@ -8,9 +8,6 @@
 package keyExchange
 
 import (
-	"testing"
-	"time"
-
 	"github.com/golang/protobuf/proto"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces"
@@ -31,6 +28,8 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
+	"gitlab.com/xx_network/primitives/netTime"
+	"testing"
 )
 
 // Generate partner ID for two people, used for smoke tests
@@ -170,7 +169,7 @@ func (t *testNetworkManagerFullExchange) SendE2E(m message.Send, p params.E2E) (
 		Payload:     payload,
 		MessageType: message.KeyExchangeConfirm,
 		Sender:      exchangeAliceId,
-		Timestamp:   time.Now(),
+		Timestamp:   netTime.Now(),
 		Encryption:  message.E2E,
 	}
 
diff --git a/network/checkedRounds.go b/network/checkedRounds.go
new file mode 100644
index 0000000000000000000000000000000000000000..8ffa9ba39804fd70017123859cf60137f12f8e78
--- /dev/null
+++ b/network/checkedRounds.go
@@ -0,0 +1,75 @@
+package network
+
+import (
+	"container/list"
+	"crypto/md5"
+	"gitlab.com/elixxir/client/storage/reception"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+
+type idFingerprint [16]byte
+
+type checkedRounds struct{
+	lookup map[idFingerprint]*checklist
+}
+
+type checklist struct{
+	m map[id.Round]interface{}
+	l *list.List
+}
+
+func newCheckedRounds()*checkedRounds{
+	return &checkedRounds{
+		lookup: make(map[idFingerprint]*checklist),
+	}
+}
+
+func (cr *checkedRounds)Check(identity reception.IdentityUse, rid id.Round)bool{
+	idFp := getIdFingerprint(identity)
+	cl, exists := cr.lookup[idFp]
+	if !exists{
+		cl = &checklist{
+			m: make(map[id.Round]interface{}),
+			l: list.New().Init(),
+		}
+		cr.lookup[idFp]=cl
+	}
+
+	if _, exists := cl.m[rid]; !exists{
+		cl.m[rid] = nil
+		cl.l.PushBack(rid)
+		return true
+	}
+	return false
+}
+
+func (cr *checkedRounds)Prune(identity reception.IdentityUse, earliestAllowed id.Round){
+	idFp := getIdFingerprint(identity)
+	cl, exists := cr.lookup[idFp]
+	if !exists {
+		return
+	}
+
+	e := cl.l.Front()
+	for e!=nil {
+		if  e.Value.(id.Round)<earliestAllowed{
+			delete(cl.m,e.Value.(id.Round))
+			lastE := e
+			e = e.Next()
+			cl.l.Remove(lastE)
+		}else{
+			break
+		}
+	}
+}
+
+func getIdFingerprint(identity reception.IdentityUse)idFingerprint{
+	h := md5.New()
+	h.Write(identity.EphId[:])
+	h.Write(identity.Source[:])
+
+	fp := idFingerprint{}
+	copy(fp[:], h.Sum(nil))
+	return fp
+}
\ No newline at end of file
diff --git a/network/ephemeral/tracker.go b/network/ephemeral/tracker.go
index f158e337521ffddb5bcd6267e69e0e048e89f9de..2f19604c49faea57cb58b5cf7caf3476af4d9eab 100644
--- a/network/ephemeral/tracker.go
+++ b/network/ephemeral/tracker.go
@@ -16,6 +16,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"time"
 )
 
@@ -59,7 +60,7 @@ func track(session *storage.Session, ourId *id.ID, stop *stoppable.Single) {
 	receptionStore.WaitForIdSizeUpdate()
 
 	for true {
-		now := time.Now()
+		now := netTime.Now()
 		// Generates the IDs since the last track
 		protoIds, err := ephemeral.GetIdsByRange(ourId, receptionStore.GetIDSize(),
 			now, now.Sub(lastCheck))
@@ -148,7 +149,7 @@ func checkTimestampStore(session *storage.Session) error {
 	if _, err := session.Get(TimestampKey); err != nil {
 		// only generate from the last hour because this is a new id, it
 		// couldn't receive messages yet
-		now, err := marshalTimestamp(time.Now().Add(-1 * time.Hour))
+		now, err := marshalTimestamp(netTime.Now().Add(-1 * time.Hour))
 		if err != nil {
 			return errors.Errorf("Could not marshal new timestamp for storage: %v", err)
 		}
@@ -161,7 +162,7 @@ func checkTimestampStore(session *storage.Session) error {
 // Takes the stored timestamp and unmarshal into a time object
 func unmarshalTimestamp(lastTimestampObj *versioned.Object) (time.Time, error) {
 	if lastTimestampObj == nil || lastTimestampObj.Data == nil {
-		return time.Now(), nil
+		return netTime.Now(), nil
 	}
 
 	lastTimestamp := time.Time{}
@@ -175,7 +176,7 @@ func marshalTimestamp(timeToStore time.Time) (*versioned.Object, error) {
 
 	return &versioned.Object{
 		Version:   0,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      data,
 	}, err
 }
diff --git a/network/ephemeral/tracker_test.go b/network/ephemeral/tracker_test.go
index 1d01511f5b03be3b08a2084b92548cae62f84ff7..aa4589ebe7650ab55d4d04ab97fb98cfb9d1c008 100644
--- a/network/ephemeral/tracker_test.go
+++ b/network/ephemeral/tracker_test.go
@@ -17,6 +17,7 @@ import (
 	"gitlab.com/xx_network/comms/signature"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"gitlab.com/xx_network/primitives/utils"
 	"testing"
 	"time"
@@ -31,7 +32,7 @@ func TestCheck(t *testing.T) {
 	}
 
 	/// Store a mock initial timestamp the store
-	now := time.Now()
+	now := netTime.Now()
 	twoDaysAgo := now.Add(-2 * 24 * time.Hour)
 	twoDaysTimestamp, err := marshalTimestamp(twoDaysAgo)
 	if err != nil {
@@ -65,7 +66,7 @@ func TestCheck_Thread(t *testing.T) {
 	stop := stoppable.NewSingle(ephemeralStoppable)
 
 	/// Store a mock initial timestamp the store
-	now := time.Now()
+	now := netTime.Now()
 	yesterday := now.Add(-24 * time.Hour)
 	yesterdayTimestamp, err := marshalTimestamp(yesterday)
 	if err != nil {
diff --git a/network/follow.go b/network/follow.go
index 7ac859229780c4c80396eb28b0e18d4352e2bf48..752476ea1e7b821d942ca88d3b36dba19d87c5a0 100644
--- a/network/follow.go
+++ b/network/follow.go
@@ -41,7 +41,6 @@ import (
 )
 
 const debugTrackPeriod = 1 * time.Minute
-const maxChecked = 100000
 
 //comms interface makes testing easier
 type followNetworkComms interface {
@@ -187,7 +186,15 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source,
 					// FIXME: without mutating the RoundInfo. Signature also needs verified
 					// FIXME: before keys are deleted
 					update.State = uint32(states.FAILED)
-					m.Instance.GetRoundEvents().TriggerRoundEvent(update)
+					rnd, err := m.Instance.GetWrappedRound(id.Round(update.ID))
+					if err != nil {
+						jww.ERROR.Printf("Failed to report client error: " +
+							"Could not get round for event triggering: " +
+							"Unable to get round %d from instance: %+v",
+							id.Round(update.ID), err)
+						break
+					}
+					m.Instance.GetRoundEvents().TriggerRoundEvent(rnd)
 
 					// delete all existing keys and trigger a re-registration with the relevant Node
 					m.Session.Cmix().Remove(nid)
@@ -238,28 +245,53 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source,
 	// are messages waiting in rounds and then sends signals to the appropriate
 	// handling threads
 	roundChecker := func(rid id.Round) bool {
-		return m.round.Checker(rid, filterList, identity)
+		return rounds.Checker(rid, filterList)
 	}
 
 	// move the earliest unknown round tracker forward to the earliest
 	// tracked round if it is behind
 	earliestTrackedRound := id.Round(pollResp.EarliestRound)
-	updated := identity.UR.Set(earliestTrackedRound)
-
+	updated, _ := identity.ER.Set(earliestTrackedRound)
 
 	// loop through all rounds the client does not know about and the gateway
 	// does, checking the bloom filter for the user to see if there are
 	// messages for the user (bloom not implemented yet)
-	earliestRemaining := gwRoundsState.RangeUnchecked(updated,
-		maxChecked, roundChecker)
-	identity.UR.Set(earliestRemaining)
-	jww.INFO.Printf("Earliest Remaining: %d", earliestRemaining)
+	//threshold is the earliest round that will not be excluded from earliest remaining
+	earliestRemaining, roundsWithMessages, roundsUnknown := gwRoundsState.RangeUnchecked(updated,
+		m.param.KnownRoundsThreshold, roundChecker)
+	_, changed := identity.ER.Set(earliestRemaining)
+	if changed{
+		jww.TRACE.Printf("External returns of RangeUnchecked: %d, %v, %v", earliestRemaining, roundsWithMessages, roundsUnknown)
+		jww.DEBUG.Printf("New Earliest Remaining: %d", earliestRemaining)
+	}
 
+	roundsWithMessages2 := identity.UR.Iterate(func(rid id.Round)bool{
+		if gwRoundsState.Checked(rid){
+			return rounds.Checker(rid, filterList)
+		}
+		return false
+	}, roundsUnknown)
 
-	//delete any old rounds from processing
-	if earliestRemaining>updated{
-		for i:=updated;i<=earliestRemaining;i++{
-			m.round.DeleteProcessingRoundDelete(i, identity.EphId, identity.Source)
+	for _, rid := range roundsWithMessages{
+		if m.checked.Check(identity, rid){
+			m.round.GetMessagesFromRound(rid, identity)
 		}
 	}
+	for _, rid := range roundsWithMessages2{
+		m.round.GetMessagesFromRound(rid, identity)
+	}
+
+	earliestToKeep := getEarliestToKeep(m.param.KnownRoundsThreshold,
+		gwRoundsState.GetLastChecked())
+
+	m.checked.Prune(identity, earliestToKeep)
+
+}
+
+
+func getEarliestToKeep(delta uint, lastchecked id.Round)id.Round{
+	if uint(lastchecked)<delta{
+		return 0
+	}
+	return  lastchecked - id.Round(delta)
 }
diff --git a/network/health/tracker.go b/network/health/tracker.go
index 8e9837165a33982f6dcf7387e7c42388b4c276bd..ff53904f2015fe81af4938efd9ca8222fd68eba1 100644
--- a/network/health/tracker.go
+++ b/network/health/tracker.go
@@ -103,7 +103,6 @@ func (t *Tracker) setHealth(h bool) {
 
 func (t *Tracker) Start() (stoppable.Stoppable, error) {
 	t.mux.Lock()
-	defer t.mux.Unlock()
 	if t.running {
 		return nil, errors.New("cannot start Health tracker threads, " +
 			"they are already running")
@@ -111,20 +110,13 @@ func (t *Tracker) Start() (stoppable.Stoppable, error) {
 	t.running = true
 
 	t.isHealthy = false
+	t.mux.Unlock()
 
 	stop := stoppable.NewSingle("Health Tracker")
-	stopCleanup := stoppable.NewCleanup(stop, func(duration time.Duration) error {
-		t.mux.Lock()
-		defer t.mux.Unlock()
-		t.isHealthy = false
-		t.transmit(false)
-		t.running = false
-		return nil
-	})
 
 	go t.start(stop.Quit())
 
-	return stopCleanup, nil
+	return stop, nil
 }
 
 // Long-running thread used to monitor and report on network health
@@ -135,7 +127,11 @@ func (t *Tracker) start(quitCh <-chan struct{}) {
 		var heartbeat network.Heartbeat
 		select {
 		case <-quitCh:
-			// Handle thread kill
+			t.mux.Lock()
+			t.isHealthy = false
+			t.running = false
+			t.mux.Unlock()
+			t.transmit(false)
 			break
 		case heartbeat = <-t.heartbeat:
 			if healthy(heartbeat) {
@@ -163,7 +159,7 @@ func (t *Tracker) transmit(health bool) {
 		select {
 		case c <- health:
 		default:
-			jww.WARN.Printf("Unable to send Health event")
+			jww.DEBUG.Printf("Unable to send Health event")
 		}
 	}
 
diff --git a/network/manager.go b/network/manager.go
index 9cdb4bb33a063cc53168dbae553e81e506b8c7c7..b62bb1d007953db87ea63c010f4090c081c9e4b7 100644
--- a/network/manager.go
+++ b/network/manager.go
@@ -11,10 +11,6 @@ package network
 // and intraclient state are accessible through the context object.
 
 import (
-	"sync/atomic"
-
-	"time"
-
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/params"
@@ -46,11 +42,12 @@ type manager struct {
 	//sub-managers
 	round   *rounds.Manager
 	message *message.Manager
-	//atomic denotes if the network is running
-	running *uint32
 
 	//map of polls for debugging
 	tracker *pollTracker
+
+	//tracks already checked rounds
+	checked *checkedRounds
 }
 
 // NewManager builds a new reception manager object using inputted key fields
@@ -59,14 +56,12 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard,
 	params params.Network, ndf *ndf.NetworkDefinition) (interfaces.NetworkManager, error) {
 
 	//start network instance
-	instance, err := network.NewInstance(comms.ProtoComms, ndf, nil, nil)
+	instance, err := network.NewInstance(comms.ProtoComms, ndf, nil, nil, network.None)
 	if err != nil {
 		return nil, errors.WithMessage(err, "failed to create"+
 			" client network manager")
 	}
 
-	running := uint32(0)
-
 	// Note: These are not loaded/stored in E2E Store, but the
 	// E2E Session Params are a part of the network parameters, so we
 	// set them here when they are needed on startup
@@ -74,9 +69,9 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard,
 
 	//create manager object
 	m := manager{
-		param:         params,
-		running:       &running,
-		tracker:       newPollTracker(),
+		param:   params,
+		tracker: newPollTracker(),
+		checked: newCheckedRounds(),
 	}
 
 	m.Internal = internal.Internal{
@@ -113,10 +108,6 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard,
 //	 - Critical Messages (/network/message/critical.go)
 //   - Ephemeral ID tracking (network/ephemeral/tracker.go)
 func (m *manager) Follow(report interfaces.ClientErrorReport) (stoppable.Stoppable, error) {
-	if !atomic.CompareAndSwapUint32(m.running, 0, 1) {
-		return nil, errors.Errorf("network routines are already running")
-	}
-
 	multi := stoppable.NewMulti("networkManager")
 
 	// health tracker
@@ -145,15 +136,7 @@ func (m *manager) Follow(report interfaces.ClientErrorReport) (stoppable.Stoppab
 
 	multi.Add(ephemeral.Track(m.Session, m.ReceptionID))
 
-	//set the running status back to 0 so it can be started again
-	closer := stoppable.NewCleanup(multi, func(time.Duration) error {
-		if !atomic.CompareAndSwapUint32(m.running, 1, 0) {
-			return errors.Errorf("network routines are already stopped")
-		}
-		return nil
-	})
-
-	return closer, nil
+	return multi, nil
 }
 
 // GetHealthTracker returns the health tracker
diff --git a/network/message/garbled.go b/network/message/garbled.go
index 70bab27f42eab90b759494ce2912d3d13a864660..d9e1ac6be427f2ca0e9c8e89572fb6eed2285483 100644
--- a/network/message/garbled.go
+++ b/network/message/garbled.go
@@ -27,6 +27,8 @@ func (m *Manager) CheckGarbledMessages() {
 	select {
 	case m.triggerGarbled <- struct{}{}:
 	default:
+		jww.WARN.Println("Failed to check garbled messages " +
+			"due to full channel")
 	}
 }
 
diff --git a/network/message/garbled_test.go b/network/message/garbled_test.go
index 21098b72bef9a6408c6131c275c021471e79565d..0f5c3a074641af02ef3e156372bd7957eedba5aa 100644
--- a/network/message/garbled_test.go
+++ b/network/message/garbled_test.go
@@ -12,6 +12,7 @@ import (
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"testing"
 	"time"
@@ -102,7 +103,7 @@ func TestManager_CheckGarbledMessages(t *testing.T) {
 	fmp.NumParts[0] = uint8(1)
 	binary.BigEndian.PutUint16(fmp.Len, 256)
 	fmp.Part[0] = 0
-	ts, err := time.Now().MarshalBinary()
+	ts, err := netTime.Now().MarshalBinary()
 	if err != nil {
 		t.Errorf("failed to martial ts: %+v", err)
 	}
diff --git a/network/message/handler.go b/network/message/handler.go
index 95606c8a7a204afe27d67903af41e511a2b102a1..88484e6fb98672520bf3e39af0cd3175597b53b4 100644
--- a/network/message/handler.go
+++ b/network/message/handler.go
@@ -37,6 +37,7 @@ func (m *Manager) handleMessages(quitCh <-chan struct{}) {
 func (m *Manager) handleMessage(ecrMsg format.Message, identity reception.IdentityUse) {
 	// We've done all the networking, now process the message
 	fingerprint := ecrMsg.GetKeyFP()
+	msgDigest := ecrMsg.Digest()
 
 	e2eKv := m.Session.E2e()
 
@@ -113,7 +114,7 @@ func (m *Manager) handleMessage(ecrMsg format.Message, identity reception.Identi
 	}
 
 	jww.INFO.Printf("Received message of type %s from %s,"+
-		" msgDigest: %s", encTy, sender, ecrMsg.Digest())
+		" msgDigest: %s", encTy, sender, msgDigest)
 
 	// Process the decrypted/unencrypted message partition, to see if
 	// we get a full message
diff --git a/network/message/manager.go b/network/message/manager.go
index ca4a1c0f40bbc57e54925b0c742063df59f34218..807ccc07066cf2281e557b6e07d09dd4180d3c15 100644
--- a/network/message/manager.go
+++ b/network/message/manager.go
@@ -36,7 +36,7 @@ func NewManager(internal internal.Internal, param params.Messages,
 		partitioner:      parse.NewPartitioner(dummyMessage.ContentsSize(), internal.Session),
 		messageReception: make(chan Bundle, param.MessageReceptionBuffLen),
 		networkIsHealthy: make(chan bool, 1),
-		triggerGarbled:   make(chan struct{}, 1),
+		triggerGarbled:   make(chan struct{}, 100),
 		nodeRegistration: nodeRegistration,
 	}
 	m.Internal = internal
diff --git a/network/message/parse/partition_test.go b/network/message/parse/partition_test.go
index 59963cfefc57ab70d8d76e07fd384d8aae293a40..933db1a01d4e95605d44d7cf5f5dce4429f2a9b5 100644
--- a/network/message/parse/partition_test.go
+++ b/network/message/parse/partition_test.go
@@ -11,8 +11,8 @@ import (
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"testing"
-	"time"
 )
 
 var ipsumTestStr = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet euismod est. Donec dolor " +
@@ -67,7 +67,7 @@ func TestPartitioner_Partition(t *testing.T) {
 	p := NewPartitioner(len(ipsumTestStr), storeSession)
 
 	_, _, err := p.Partition(&id.DummyUser, message.Text,
-		time.Now(), []byte(ipsumTestStr))
+		netTime.Now(), []byte(ipsumTestStr))
 	if err != nil {
 		t.Error(err)
 	}
@@ -94,7 +94,7 @@ func TestPartitioner_HandleFirstPartition(t *testing.T) {
 	storeSession := storage.InitTestingSession(t)
 	p := NewPartitioner(len(ipsumTestStr), storeSession)
 
-	m := newFirstMessagePart(message.Text, 1107, 1, time.Now(), []byte(ipsumTestStr))
+	m := newFirstMessagePart(message.Text, 1107, 1, netTime.Now(), []byte(ipsumTestStr))
 
 	_, _ = p.HandlePartition(
 		&id.DummyUser,
diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go
index 2a5892da077268b3ca9b5881e037fad7842480e3..1aced6efe44eaef52f17a08392d4c52a8d6eae7c 100644
--- a/network/message/sendCmix.go
+++ b/network/message/sendCmix.go
@@ -22,6 +22,7 @@ import (
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"strings"
 	"time"
 )
@@ -32,12 +33,14 @@ type sendCmixCommsInterface interface {
 	SendPutMessage(host *connect.Host, message *pb.GatewaySlot) (*pb.GatewaySlotResponse, error)
 }
 
-const sendTimeBuffer = 100 * time.Millisecond
+// 1.5 seconds
+const sendTimeBuffer = 2500 * time.Millisecond
 
 // WARNING: Potentially Unsafe
 // Public manager function to send a message over CMIX
 func (m *Manager) SendCMIX(msg format.Message, recipient *id.ID, param params.CMIX) (id.Round, ephemeral.Id, error) {
-	return sendCmixHelper(msg, recipient, param, m.Instance, m.Session, m.nodeRegistration, m.Rng, m.TransmissionID, m.Comms)
+	msgCopy := msg.Copy()
+	return sendCmixHelper(msgCopy, recipient, param, m.Instance, m.Session, m.nodeRegistration, m.Rng, m.TransmissionID, m.Comms)
 }
 
 // Payloads send are not End to End encrypted, MetaData is NOT protected with
@@ -52,14 +55,14 @@ func sendCmixHelper(msg format.Message, recipient *id.ID, param params.CMIX, ins
 	session *storage.Session, nodeRegistration chan network.NodeGateway, rng *fastRNG.StreamGenerator, senderId *id.ID,
 	comms sendCmixCommsInterface) (id.Round, ephemeral.Id, error) {
 
-	timeStart := time.Now()
+	timeStart := netTime.Now()
 	attempted := set.New()
 
 	jww.INFO.Printf("Looking for round to send cMix message to %s "+
 		"(msgDigest: %s)", recipient, msg.Digest())
 
 	for numRoundTries := uint(0); numRoundTries < param.RoundTries; numRoundTries++ {
-		elapsed := time.Now().Sub(timeStart)
+		elapsed := netTime.Now().Sub(timeStart)
 
 		if elapsed > param.Timeout {
 			jww.INFO.Printf("No rounds to send to %s (msgDigest: %s) "+
@@ -75,7 +78,7 @@ func sendCmixHelper(msg format.Message, recipient *id.ID, param params.CMIX, ins
 
 		remainingTime := param.Timeout - elapsed
 		//find the best round to send to, excluding attempted rounds
-		bestRound, _ := instance.GetWaitingRounds().GetUpcomingRealtime(remainingTime, attempted)
+		bestRound, _ := instance.GetWaitingRounds().GetUpcomingRealtime(remainingTime, attempted, sendTimeBuffer)
 		if bestRound == nil {
 			continue
 		}
@@ -83,23 +86,6 @@ func sendCmixHelper(msg format.Message, recipient *id.ID, param params.CMIX, ins
 		//add the round on to the list of attempted so it is not tried again
 		attempted.Insert(bestRound)
 
-		//compute if the round is too close to send to
-		roundCutoffTime := time.Unix(0,
-			int64(bestRound.Timestamps[states.QUEUED]))
-		roundCutoffTime.Add(sendTimeBuffer)
-		now := time.Now()
-
-		jww.DEBUG.Printf("Found round %d to send to %s (msgDigest: %s)",
-			bestRound.ID, recipient, msg.Digest())
-
-		if now.After(roundCutoffTime) {
-			jww.WARN.Printf("Round %d for sending to %s (msgDigest: %s) "+
-				"received which has already started realtime: \n\t started: "+
-				"%s \n\t now: %s", bestRound.ID, recipient, msg.Digest(),
-				roundCutoffTime, now)
-			continue
-		}
-
 		//set the ephemeral ID
 		ephID, _, _, err := ephemeral.GetId(recipient,
 			uint(bestRound.AddressSpaceSize),
@@ -213,9 +199,9 @@ func sendCmixHelper(msg format.Message, recipient *id.ID, param params.CMIX, ins
 					"due to round error with round %d, retrying: %+v",
 					recipient, msg.Digest(), bestRound.ID, err)
 				continue
-			}else if strings.Contains(err.Error(),
-				"Could not authenticate client. Is the client registered " +
-				"with this node?"){
+			} else if strings.Contains(err.Error(),
+				"Could not authenticate client. Is the client registered "+
+					"with this node?") {
 				jww.WARN.Printf("Failed to send to %s (msgDigest: %s) "+
 					"via %s due to failed authentication: %s",
 					recipient, msg.Digest(), transmitGateway.GetId(), err)
diff --git a/network/message/sendCmix_test.go b/network/message/sendCmix_test.go
index 7ea83223a809ed5e58a1e5a4e1ec6961b1755776..82b3ebcb2c3cfa87a72f62519f68541ae78bd06d 100644
--- a/network/message/sendCmix_test.go
+++ b/network/message/sendCmix_test.go
@@ -9,6 +9,8 @@ import (
 	"gitlab.com/elixxir/comms/client"
 	"gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/comms/network"
+	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	"gitlab.com/elixxir/comms/testutils"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
@@ -19,6 +21,7 @@ import (
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
+	"gitlab.com/xx_network/primitives/netTime"
 	"testing"
 	"time"
 )
@@ -62,7 +65,7 @@ func Test_attemptSendCmix(t *testing.T) {
 	if err != nil {
 		t.Errorf("Failed to start instance: %+v", err)
 	}
-	now := time.Now()
+	now := netTime.Now()
 	nid1 := id.NewIdFromString("zezima", id.Node, t)
 	nid2 := id.NewIdFromString("jakexx360", id.Node, t)
 	nid3 := id.NewIdFromString("westparkhome", id.Node, t)
@@ -78,7 +81,7 @@ func Test_attemptSendCmix(t *testing.T) {
 		uint64(now.Add(5 * time.Second).UnixNano()),   //QUEUED
 		0} //REALTIME
 
-	inst.GetWaitingRounds().Insert(&mixmessages.RoundInfo{
+	ri := &mixmessages.RoundInfo{
 		ID:                         3,
 		UpdateID:                   0,
 		State:                      uint32(states.QUEUED),
@@ -90,7 +93,18 @@ func Test_attemptSendCmix(t *testing.T) {
 		ResourceQueueTimeoutMillis: 0,
 		Signature:                  nil,
 		AddressSpaceSize:           4,
-	})
+	}
+
+	if err = testutils.SignRoundInfo(ri, t); err != nil {
+		t.Errorf("Failed to sign mock round info: %v", err)
+	}
+
+	pubKey, err := testutils.LoadPublicKeyTesting(t)
+	if err != nil {
+		t.Errorf("Failed to load a key for testing: %v", err)
+	}
+	rnd := ds.NewRound(ri, pubKey)
+	inst.GetWaitingRounds().Insert(rnd)
 	i := internal.Internal{
 		Session:          sess1,
 		Switchboard:      sw,
diff --git a/network/message/sendE2E.go b/network/message/sendE2E.go
index 14e6708cf83d05268ad27d738598b4f76d002229..78061232830f167adf91d21f5805fa2e00b58916 100644
--- a/network/message/sendE2E.go
+++ b/network/message/sendE2E.go
@@ -16,6 +16,7 @@ import (
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
 	"time"
 )
@@ -26,7 +27,7 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, e2e.M
 			"message type", msg.MessageType)
 	}
 	//timestamp the message
-	ts := time.Now()
+	ts := netTime.Now()
 
 	//partition the message
 	partitions, internalMsgId, err := m.partitioner.Partition(msg.Recipient, msg.MessageType, ts,
@@ -42,8 +43,9 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, e2e.M
 	// get the key manager for the partner
 	partner, err := m.Session.E2e().GetPartner(msg.Recipient)
 	if err != nil {
-		return nil, e2e.MessageID{}, errors.WithMessagef(err, "Could not send End to End encrypted "+
-			"message, no relationship found with %s", msg.Recipient)
+		return nil, e2e.MessageID{}, errors.WithMessagef(err,
+			"Could not send End to End encrypted "+
+				"message, no relationship found with %s", msg.Recipient)
 	}
 
 	wg := sync.WaitGroup{}
@@ -52,8 +54,16 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, e2e.M
 		len(partitions), msg.Recipient)
 
 	for i, p := range partitions {
+
+		if msg.MessageType != message.KeyExchangeTrigger {
+			// check if any rekeys need to happen and trigger them
+			keyExchange.CheckKeyExchanges(m.Instance, m.SendE2E,
+				m.Session, partner, 1*time.Minute)
+		}
+
 		//create the cmix message
-		msgCmix := format.NewMessage(m.Session.Cmix().GetGroup().GetP().ByteLen())
+		msgLen := m.Session.Cmix().GetGroup().GetP().ByteLen()
+		msgCmix := format.NewMessage(msgLen)
 		msgCmix.SetContents(p)
 
 		//get a key to end to end encrypt
@@ -71,8 +81,8 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, e2e.M
 			key, err = partner.GetKeyForSending(param.Type)
 		}
 		if err != nil {
-			return nil, e2e.MessageID{}, errors.WithMessagef(err, "Failed to get key "+
-				"for end to end encryption")
+			return nil, e2e.MessageID{}, errors.WithMessagef(err,
+				"Failed to get key for end to end encryption")
 		}
 
 		//end to end encrypt the cmix message
@@ -85,7 +95,8 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, e2e.M
 		wg.Add(1)
 		go func(i int) {
 			var err error
-			roundIds[i], _, err = m.SendCMIX(msgEnc, msg.Recipient, param.CMIX)
+			roundIds[i], _, err = m.SendCMIX(msgEnc, msg.Recipient,
+				param.CMIX)
 			if err != nil {
 				errCh <- err
 			}
@@ -93,11 +104,6 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E) ([]id.Round, e2e.M
 		}(i)
 	}
 
-	// while waiting check if any rekeys need to happen and trigger them. This
-	// can happen now because the key popping happens in this thread,
-	// only the sending is parallelized
-	keyExchange.CheckKeyExchanges(m.Instance, m.SendE2E, m.Session, partner, 1*time.Minute)
-
 	wg.Wait()
 
 	//see if any parts failed to send
diff --git a/network/message/sendUnsafe.go b/network/message/sendUnsafe.go
index d039b18724af24efbf3c60c711e55092b1fe40b8..ef28cf2d789d1f5f0a097413046b5a0c50b0a230 100644
--- a/network/message/sendUnsafe.go
+++ b/network/message/sendUnsafe.go
@@ -14,8 +14,8 @@ import (
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 // WARNING: Unsafe
@@ -33,7 +33,7 @@ func (m *Manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round,
 			msg.MessageType)
 	}
 	//timestamp the message
-	ts := time.Now()
+	ts := netTime.Now()
 
 	//partition the message
 	partitions, _, err := m.partitioner.Partition(msg.Recipient, msg.MessageType, ts,
diff --git a/network/polltracker.go b/network/polltracker.go
index 497539e94ec9d6aa8cb013bd0ee40678e1360731..48574c7d8e19eb4e1d73090af0c017e3c9b8187b 100644
--- a/network/polltracker.go
+++ b/network/polltracker.go
@@ -17,9 +17,9 @@ func newPollTracker() *pollTracker {
 func (pt *pollTracker) Track(ephID ephemeral.Id, source *id.ID) {
 	if _, exists := (*pt)[*source]; !exists {
 		(*pt)[*source] = make(map[int64]uint)
-		(*pt)[*source][ephID.Int64()] = 0
+		(*pt)[*source][ephID.Int64()] = 1
 	} else if _, exists := (*pt)[*source][ephID.Int64()]; !exists {
-		(*pt)[*source][ephID.Int64()] = 0
+		(*pt)[*source][ephID.Int64()] = 1
 	} else {
 		(*pt)[*source][ephID.Int64()] = (*pt)[*source][ephID.Int64()] + 1
 	}
diff --git a/network/rounds/check.go b/network/rounds/check.go
index f8b1c64dd419bc8d349c04bc69db39c61637cbbd..9deb3ec6c16fb227a6406c9fd6181ffcf6e4d8b1 100644
--- a/network/rounds/check.go
+++ b/network/rounds/check.go
@@ -25,53 +25,31 @@ import (
 // if the information about that round is already present, if it is the data is
 // sent to Message Retrieval Workers, otherwise it is sent to Historical Round
 // Retrieval
-func (m *Manager) Checker(roundID id.Round, filters []*RemoteFilter, identity reception.IdentityUse) bool {
-	// Set round to processing, if we can
-	status, count := m.p.Process(roundID, identity.EphId, identity.Source)
-	jww.INFO.Printf("checking: %d, status: %s", roundID, status)
-
-	switch status{
-	case Processing:
-		return false
-	case Done:
-		return true
-	}
-
-	//if the number of times the round has been checked has hit the max, drop it
-	if count == m.params.MaxAttemptsCheckingARound {
-		jww.ERROR.Printf("Looking up Round %v for %d (%s) failed "+
-			"the maximum number of times (%v), stopping retrval attempt",
-			roundID, identity.EphId, identity.Source,
-			m.params.MaxAttemptsCheckingARound)
-		m.p.Done(roundID, identity.EphId, identity.Source)
-		return true
-	}
-
-	hasRound := false
+// false: no message
+// true: message
+func Checker(roundID id.Round, filters []*RemoteFilter) bool {
 	//find filters that could have the round and check them
 	serialRid := serializeRound(roundID)
 	for _, filter := range filters {
 		if filter != nil && filter.FirstRound() <= roundID &&
 			filter.LastRound() >= roundID {
 			if filter.GetFilter().Test(serialRid) {
-				hasRound = true
-				break
+				return true
 			}
 		}
 	}
+	return false
+}
 
-	//if it is not present, set the round as checked
-	//that means no messages are available for the user in the round
-	if !hasRound {
-		jww.DEBUG.Printf("No messages found for %d (%s) in round %d, "+
-			"will not check again", identity.EphId.Int64(), identity.Source, roundID)
-		m.p.Done(roundID, identity.EphId, identity.Source)
-		return true
-	}
+func serializeRound(roundId id.Round) []byte {
+	b := make([]byte, 8)
+	binary.LittleEndian.PutUint64(b, uint64(roundId))
+	return b
+}
 
-	// Go get the round from the round infos, if it exists
+func (m *Manager) GetMessagesFromRound(roundID id.Round, identity reception.IdentityUse){
 	ri, err := m.Instance.GetRound(roundID)
-	if err != nil || m.params.ForceHistoricalRounds {
+	if err !=nil || m.params.ForceHistoricalRounds {
 		if m.params.ForceHistoricalRounds {
 			jww.WARN.Printf("Forcing use of historical rounds for round ID %d.",
 				roundID)
@@ -83,9 +61,10 @@ func (m *Manager) Checker(roundID id.Round, filters []*RemoteFilter, identity re
 		m.historicalRounds <- historicalRoundRequest{
 			rid:      roundID,
 			identity: identity,
+			numAttempts: 0,
 		}
 	} else {
-		jww.INFO.Printf("Messages found in round %d for %d (%s), looking " +
+		jww.INFO.Printf("Messages found in round %d for %d (%s), looking "+
 			"up messages via in ram lookup", roundID, identity.EphId.Int64(),
 			identity.Source)
 		// If found, send to Message Retrieval Workers
@@ -95,11 +74,4 @@ func (m *Manager) Checker(roundID id.Round, filters []*RemoteFilter, identity re
 		}
 	}
 
-	return false
-}
-
-func serializeRound(roundId id.Round) []byte {
-	b := make([]byte, 8)
-	binary.LittleEndian.PutUint64(b, uint64(roundId))
-	return b
-}
+}
\ No newline at end of file
diff --git a/network/rounds/historical.go b/network/rounds/historical.go
index 1a0f5c100697044ebdbdaf7975b5019e87be0356..d5451989c4f3092652943d308d37c4a21bbf0524 100644
--- a/network/rounds/historical.go
+++ b/network/rounds/historical.go
@@ -36,6 +36,7 @@ type historicalRoundsComms interface {
 type historicalRoundRequest struct {
 	rid      id.Round
 	identity reception.IdentityUse
+	numAttempts uint
 }
 
 // Long running thread which process historical rounds
@@ -62,7 +63,6 @@ func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-c
 				select {
 				case m.historicalRounds <- r:
 				default:
-					m.p.NotProcessing(r.rid, r.identity.EphId, r.identity.Source)
 				}
 			}
 			done = true
@@ -123,9 +123,23 @@ func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-c
 			// need be be removes as processing so the network follower will
 			// pick them up in the future.
 			if roundInfo == nil {
-				jww.ERROR.Printf("Failed to retreive "+
-					"historical round %d", roundRequests[i].rid)
-				m.p.Fail(roundRequests[i].rid, roundRequests[i].identity.EphId, roundRequests[i].identity.Source)
+				roundRequests[i].numAttempts++
+				if roundRequests[i].numAttempts==m.params.MaxHistoricalRoundsRetries{
+					jww.ERROR.Printf("Failed to retreive historical " +
+						"round %d on last attempt, will not try again",
+						roundRequests[i].rid)
+				}else{
+					select {
+					case m.historicalRounds <-roundRequests[i]:
+						jww.WARN.Printf("Failed to retreive historical " +
+							"round %d, will try up to %d more times",
+							roundRequests[i].rid, m.params.MaxHistoricalRoundsRetries-roundRequests[i].numAttempts)
+					default:
+						jww.WARN.Printf("Failed to retreive historical " +
+							"round %d, failed to try again, round will not be " +
+							"retreived", roundRequests[i].rid)
+					}
+				}
 				continue
 			}
 			// Successfully retrieved roundRequests are sent to the Message
diff --git a/network/rounds/manager.go b/network/rounds/manager.go
index c2a3a37b2acf611d73d7e190525bf4d25fd84620..177c1c318b4807be0f17ccbb36bbe8720104deb4 100644
--- a/network/rounds/manager.go
+++ b/network/rounds/manager.go
@@ -13,15 +13,11 @@ import (
 	"gitlab.com/elixxir/client/network/internal"
 	"gitlab.com/elixxir/client/network/message"
 	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
 )
 
 type Manager struct {
 	params params.Rounds
 
-	p *processing
-
 	internal.Internal
 
 	historicalRounds    chan historicalRoundRequest
@@ -33,7 +29,6 @@ func NewManager(internal internal.Internal, params params.Rounds,
 	bundles chan<- message.Bundle) *Manager {
 	m := &Manager{
 		params: params,
-		p:      newProcessingRounds(),
 
 		historicalRounds:    make(chan historicalRoundRequest, params.HistoricalRoundsBufferLen),
 		lookupRoundMessages: make(chan roundLookup, params.LookupRoundsBufferLen),
@@ -60,9 +55,4 @@ func (m *Manager) StartProcessors() stoppable.Stoppable {
 		multi.Add(stopper)
 	}
 	return multi
-}
-
-func (m *Manager) DeleteProcessingRoundDelete(round id.Round, eph ephemeral.Id, source *id.ID) {
-
-	m.p.Delete(round, eph, source)
-}
+}
\ No newline at end of file
diff --git a/network/rounds/processingRounds.go b/network/rounds/processingRounds.go
deleted file mode 100644
index 954773201bcf7f270d9bab1674320be6da860a3b..0000000000000000000000000000000000000000
--- a/network/rounds/processingRounds.go
+++ /dev/null
@@ -1,156 +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 rounds
-
-// File for storing info about which rounds are processing
-
-import (
-	"crypto/md5"
-	"encoding/binary"
-	"fmt"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"sync"
-)
-
-type Status uint8
-
-const (
-	NotProcessing Status = iota
-	Processing
-	Done
-)
-
-func (s Status)String()string{
-	switch s{
-	case NotProcessing:
-		return "NotProcessing"
-	case Processing:
-		return "Processing"
-	case Done:
-		return "Done"
-	default:
-		return fmt.Sprintf("Unknown Status: %d", s)
-	}
-}
-
-
-type status struct {
-	failCount  uint
-	Status
-}
-
-// processing struct with a lock so it can be managed with concurrent threads.
-type processing struct {
-	rounds map[hashID]*status
-	sync.RWMutex
-}
-
-type hashID [16]byte
-
-func makeHashID(round id.Round, eph ephemeral.Id, source *id.ID) hashID {
-	h := md5.New()
-	ridbytes := make([]byte, 8)
-	binary.BigEndian.PutUint64(ridbytes, uint64(round))
-	h.Write(ridbytes)
-	h.Write(eph[:])
-	h.Write(source.Bytes())
-
-	hBytes := h.Sum(nil)
-	hid := hashID{}
-	copy(hid[:], hBytes)
-	return hid
-}
-
-// newProcessingRounds returns a new processing rounds object.
-func newProcessingRounds() *processing {
-	return &processing{
-		rounds: make(map[hashID]*status),
-	}
-}
-
-// Process adds a round to the list of processing rounds. The returned boolean
-// is true when the round changes from "not processing" to "processing". The
-// returned count is the number of times the round has been processed.
-func (pr *processing) Process(round id.Round, eph ephemeral.Id, source *id.ID) (Status, uint) {
-	hid := makeHashID(round, eph, source)
-
-	pr.Lock()
-	defer pr.Unlock()
-
-	var rs *status
-	var ok bool
-
-	if rs, ok = pr.rounds[hid]; ok && rs.Status == NotProcessing {
-		rs.Status = Processing
-		return NotProcessing, rs.failCount
-	}else if !ok{
-		rs = &status{
-			failCount: 0,
-			Status:    Processing,
-		}
-		pr.rounds[hid] = rs
-		return NotProcessing, rs.failCount
-	}
-
-	return rs.Status, rs.failCount
-}
-
-// IsProcessing determines if a round ID is marked as processing.
-func (pr *processing) IsProcessing(round id.Round, eph ephemeral.Id, source *id.ID) bool {
-	hid := makeHashID(round, eph, source)
-	pr.RLock()
-	defer pr.RUnlock()
-
-	if rs, ok := pr.rounds[hid]; ok {
-		return rs.Status == Processing
-	}
-
-	return false
-}
-
-// Fail sets a round's processing status to failed and increments its fail
-// counter so that it can be retried.
-func (pr *processing) Fail(round id.Round, eph ephemeral.Id, source *id.ID) {
-	hid := makeHashID(round, eph, source)
-	pr.Lock()
-	defer pr.Unlock()
-	if rs, ok := pr.rounds[hid]; ok {
-		rs.Status = NotProcessing
-		rs.failCount++
-	}
-}
-
-// Done deletes a round from the processing list.
-func (pr *processing) Done(round id.Round, eph ephemeral.Id, source *id.ID) {
-	hid := makeHashID(round, eph, source)
-	pr.Lock()
-	defer pr.Unlock()
-	if rs, ok := pr.rounds[hid]; ok {
-		rs.Status = Done
-	}
-}
-
-// NotProcessing sets a round's processing status to failed so that it can be
-// retried but does not increment its fail counter.
-func (pr *processing) NotProcessing(round id.Round, eph ephemeral.Id, source *id.ID) {
-	hid := makeHashID(round, eph, source)
-	pr.Lock()
-	defer pr.Unlock()
-	if rs, ok := pr.rounds[hid]; ok {
-		rs.Status = NotProcessing
-	}
-}
-
-// Done deletes a round from the processing list.
-func (pr *processing) Delete(round id.Round, eph ephemeral.Id, source *id.ID) {
-	hid := makeHashID(round, eph, source)
-	pr.Lock()
-	defer pr.Unlock()
-	delete(pr.rounds, hid)
-}
diff --git a/network/rounds/processingRounds_test.go b/network/rounds/processingRounds_test.go
deleted file mode 100644
index ce186dfbedb0ea84b55fca15b1109d49349fc1b3..0000000000000000000000000000000000000000
--- a/network/rounds/processingRounds_test.go
+++ /dev/null
@@ -1,124 +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 rounds
-
-import (
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"reflect"
-	"testing"
-)
-
-// Testing functions for Processing Round structure
-
-// Tests happy path of newProcessingRounds.
-func Test_newProcessingRounds(t *testing.T) {
-	expectedPr := &processing{
-		rounds: make(map[hashID]*status),
-	}
-
-	pr := newProcessingRounds()
-
-	if !reflect.DeepEqual(expectedPr, pr) {
-		t.Errorf("Did not get expected processing."+
-			"\n\texpected: %v\n\trecieved: %v", expectedPr, pr)
-	}
-}
-
-// Tests happy path of Process.
-func TestProcessing_Process(t *testing.T) {
-	pr := newProcessingRounds()
-
-	ephID := ephemeral.Id{}
-	source := &id.ID{}
-
-	testData := []struct {
-		rid    id.Round
-		status Status
-		count  uint
-	}{
-		{10, NotProcessing, 0},
-		{10, NotProcessing, 0},
-		{10, Processing, 0},
-		{100, NotProcessing, 0},
-		{100, NotProcessing, 0},
-		{100, Processing, 0},
-	}
-
-	for i, d := range testData {
-		hid := makeHashID(d.rid, ephID, source)
-		if _, exists := pr.rounds[hid]; exists {
-			pr.rounds[hid].Status = d.status
-		}
-		status, count := pr.Process(d.rid, ephID, source)
-		if status != d.status {
-			t.Errorf("Process() did not return the correct boolean for round "+
-				"ID %d (%d).\nexpected: %s\nrecieved: %s",
-				d.rid, i, d.status, status)
-		}
-		if count != d.count {
-			t.Errorf("Process did not return the expected count for round ID "+
-				"%d (%d).\n\texpected: %d\n\trecieved: %d",
-				d.rid, i, d.count, count)
-		}
-
-		if _, ok := pr.rounds[hid]; !ok {
-			t.Errorf("Process() did not add round ID %d to the map (%d).",
-				d.rid, i)
-		}
-	}
-
-}
-
-// Tests happy path of IsProcessing.
-func TestProcessing_IsProcessing(t *testing.T) {
-	pr := newProcessingRounds()
-	ephID := ephemeral.Id{}
-	source := &id.ID{}
-	rid := id.Round(10)
-	hid := makeHashID(rid, ephID, source)
-	pr.rounds[hid] = &status{0, Processing}
-	if !pr.IsProcessing(rid, ephID, source) {
-		t.Errorf("IsProcessing() should have returned %s for round ID %d.", Processing, rid)
-	}
-	pr.rounds[hid].Status = NotProcessing
-	if pr.IsProcessing(rid, ephID, source) {
-		t.Errorf("IsProcessing() should have returned %s for round ID %d.", NotProcessing, rid)
-	}
-}
-
-// Tests happy path of Fail.
-func TestProcessing_Fail(t *testing.T) {
-	pr := newProcessingRounds()
-	rid := id.Round(10)
-	ephID := ephemeral.Id{}
-	source := &id.ID{}
-	hid := makeHashID(rid, ephID, source)
-	pr.rounds[hid] = &status{0, Processing}
-	pr.Fail(rid, ephID, source)
-	if pr.rounds[hid].Status == Processing {
-		t.Errorf("Fail() did not mark processing as false for round id %d.", rid)
-	}
-	if pr.rounds[hid].failCount != 1 {
-		t.Errorf("Fail() did not increment the fail count of round id %d.", rid)
-	}
-}
-
-// Tests happy path of Done.
-func TestProcessing_Done(t *testing.T) {
-	pr := newProcessingRounds()
-	rid := id.Round(10)
-	ephID := ephemeral.Id{}
-	source := &id.ID{}
-	hid := makeHashID(rid, ephID, source)
-	pr.rounds[hid] = &status{0, Processing}
-	pr.Done(rid, ephID, source)
-	if s, _ := pr.rounds[hid]; s.Status != Done {
-		t.Errorf("Done() failed to flag round ID %d.", rid)
-	}
-}
diff --git a/network/rounds/retrieve.go b/network/rounds/retrieve.go
index 5269357776e9be37984cacfbe31a2208dda912d2..effd66b7fcac84db95255cc458c997a36d134f2b 100644
--- a/network/rounds/retrieve.go
+++ b/network/rounds/retrieve.go
@@ -82,7 +82,6 @@ func (m *Manager) processMessageRetrieval(comms messageRetrievalComms,
 			// After trying all gateways, if none returned we mark the round as a
 			// failure and print out the last error
 			if err != nil {
-				m.p.Fail(id.Round(ri.ID), rl.identity.EphId, rl.identity.Source)
 				jww.ERROR.Printf("Failed to get pickup round %d "+
 					"from all gateways (%v): final gateway %s returned : %s",
 					id.Round(ri.ID), gwIDs, gwHosts[len(gwHosts)-1].GetId(), err)
@@ -116,7 +115,6 @@ func (m *Manager) getMessagesFromGateway(roundID id.Round, identity reception.Id
 	}
 	// if the gateway doesnt have the round, return an error
 	if !msgResp.GetHasRound() {
-		m.p.Done(roundID, identity.EphId, identity.Source)
 		return message.Bundle{}, errors.Errorf(noRoundError)
 	}
 
@@ -139,7 +137,7 @@ func (m *Manager) getMessagesFromGateway(roundID id.Round, identity reception.Id
 		Round:    roundID,
 		Messages: make([]format.Message, len(msgs)),
 		Finish: func() {
-			m.p.Done(roundID, identity.EphId, identity.Source)
+			return
 		},
 	}
 
diff --git a/network/rounds/utils_test.go b/network/rounds/utils_test.go
index f8f14e32778574850519b02fcd73da6d2171e2e5..69c5925ed5e5b787f2440169d5da9a24d373b219 100644
--- a/network/rounds/utils_test.go
+++ b/network/rounds/utils_test.go
@@ -23,7 +23,6 @@ func newManager(face interface{}) *Manager {
 	testManager := &Manager{
 		lookupRoundMessages: make(chan roundLookup),
 		messageBundles:      make(chan message.Bundle),
-		p:                   newProcessingRounds(),
 		Internal: internal.Internal{
 			Session:        sess1,
 			TransmissionID: sess1.GetUser().TransmissionID,
diff --git a/single/manager_test.go b/single/manager_test.go
index ff09e8ecd8ed9faa67f3339c283ea365c7899c5c..5ee50ed606ff203253729aae941e248c224df533 100644
--- a/single/manager_test.go
+++ b/single/manager_test.go
@@ -12,7 +12,6 @@ import (
 	"errors"
 	"gitlab.com/elixxir/client/api"
 	"gitlab.com/elixxir/client/interfaces"
-	contact2 "gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/stoppable"
@@ -21,6 +20,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/elixxir/comms/network"
+	contact2 "gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/e2e/singleUse"
 	"gitlab.com/elixxir/crypto/fastRNG"
@@ -31,6 +31,7 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"sync"
@@ -67,7 +68,7 @@ func TestManager_StartProcesses(t *testing.T) {
 	callback, callbackChan := createReceiveComm()
 
 	transmitMsg, _, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, 8, 32, 30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		tag, 8, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
 	}
@@ -107,7 +108,7 @@ func TestManager_StartProcesses(t *testing.T) {
 	m.p.Lock()
 	m.p.singleUse[*rid] = newState(sender.dhKey, sender.maxParts, callbackFunc)
 	m.p.Unlock()
-	eid, _, _, _ := ephemeral.GetId(partner.ID, id.ArrIDLen, time.Now().UnixNano())
+	eid, _, _, _ := ephemeral.GetId(partner.ID, id.ArrIDLen, netTime.Now().UnixNano())
 	replyMsg := message.Receive{
 		Payload:     replyMsgs[0].Marshal(),
 		MessageType: message.Raw,
@@ -153,7 +154,7 @@ func TestManager_StartProcesses_Stop(t *testing.T) {
 	callback, callbackChan := createReceiveComm()
 
 	transmitMsg, _, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, 8, 32, 30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		tag, 8, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
 	}
@@ -199,7 +200,7 @@ func TestManager_StartProcesses_Stop(t *testing.T) {
 	m.p.Lock()
 	m.p.singleUse[*rid] = newState(sender.dhKey, sender.maxParts, callbackFunc)
 	m.p.Unlock()
-	eid, _, _, _ := ephemeral.GetId(partner.ID, id.ArrIDLen, time.Now().UnixNano())
+	eid, _, _, _ := ephemeral.GetId(partner.ID, id.ArrIDLen, netTime.Now().UnixNano())
 	replyMsg := message.Receive{
 		Payload:     replyMsgs[0].Marshal(),
 		MessageType: message.Raw,
diff --git a/single/receiveResponse_test.go b/single/receiveResponse_test.go
index 2782bc6fc1ad6d74eab2c0c2d51bf9988066734d..4e7e8c352e8196f0ff24d5a0d60633f78439e8dd 100644
--- a/single/receiveResponse_test.go
+++ b/single/receiveResponse_test.go
@@ -15,6 +15,7 @@ import (
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"strings"
 	"testing"
@@ -29,7 +30,7 @@ func TestManager_ReceiveResponseHandler(t *testing.T) {
 	partner := NewContact(id.NewIdFromString("recipientID", id.User, t),
 		m.store.E2e().GetGroup().NewInt(43), m.store.E2e().GetGroup().NewInt(42),
 		singleUse.TagFP{}, 8)
-	ephID, _, _, err := ephemeral.GetId(partner.partner, id.ArrIDLen, time.Now().UnixNano())
+	ephID, _, _, err := ephemeral.GetId(partner.partner, id.ArrIDLen, netTime.Now().UnixNano())
 	payload := make([]byte, 2000)
 	rand.New(rand.NewSource(42)).Read(payload)
 	callback, callbackChan := createReplyComm()
@@ -88,7 +89,7 @@ func TestManager_ReceiveResponseHandler_CmixMessageError(t *testing.T) {
 	partner := NewContact(id.NewIdFromString("recipientID", id.User, t),
 		m.store.E2e().GetGroup().NewInt(43), m.store.E2e().GetGroup().NewInt(42),
 		singleUse.TagFP{}, 8)
-	ephID, _, _, _ := ephemeral.GetId(partner.partner, id.ArrIDLen, time.Now().UnixNano())
+	ephID, _, _, _ := ephemeral.GetId(partner.partner, id.ArrIDLen, netTime.Now().UnixNano())
 	payload := make([]byte, 2000)
 	rand.New(rand.NewSource(42)).Read(payload)
 	callback, callbackChan := createReplyComm()
@@ -130,7 +131,7 @@ func TestManager_ReceiveResponseHandler_CmixMessageError(t *testing.T) {
 func TestManager_processesResponse(t *testing.T) {
 	m := newTestManager(0, false, t)
 	rid := id.NewIdFromString("test RID", id.User, t)
-	ephID, _, _, err := ephemeral.GetId(rid, id.ArrIDLen, time.Now().UnixNano())
+	ephID, _, _, err := ephemeral.GetId(rid, id.ArrIDLen, netTime.Now().UnixNano())
 	if err != nil {
 		t.Fatalf("Failed to create ephemeral ID: %+v", err)
 	}
diff --git a/single/reception_test.go b/single/reception_test.go
index 6989406621f2300e2f78c057defaf55d2e5858e1..3266d9904b2fb51dd592c766b61a9c40409e0925 100644
--- a/single/reception_test.go
+++ b/single/reception_test.go
@@ -2,11 +2,12 @@ package single
 
 import (
 	"bytes"
-	contact2 "gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/message"
+	contact2 "gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/e2e/singleUse"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"testing"
 	"time"
@@ -27,7 +28,7 @@ func TestManager_receiveTransmissionHandler(t *testing.T) {
 	callback, callbackChan := createReceiveComm()
 
 	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
 	}
@@ -92,7 +93,7 @@ func TestManager_receiveTransmissionHandler_FingerPrintError(t *testing.T) {
 	callback, callbackChan := createReceiveComm()
 
 	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
 	}
@@ -129,7 +130,7 @@ func TestManager_receiveTransmissionHandler_ProcessMessageError(t *testing.T) {
 	callback, callbackChan := createReceiveComm()
 
 	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
 	}
@@ -167,7 +168,7 @@ func TestManager_receiveTransmissionHandler_TagFpError(t *testing.T) {
 	rand.New(rand.NewSource(42)).Read(payload)
 
 	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
 	}
@@ -189,7 +190,7 @@ func TestManager_processTransmission(t *testing.T) {
 	payload := []byte("This is the payload.")
 	maxMsgs := uint8(6)
 	cmixMsg, dhKey, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, maxMsgs, 32, 30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		tag, maxMsgs, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to generate expected CMIX message: %+v", err)
 	}
@@ -240,7 +241,7 @@ func TestManager_processTransmission_MacVerifyError(t *testing.T) {
 		DhPubKey: m.store.E2e().GetDHPublicKey(),
 	}
 	cmixMsg, _, _, _, err := m.makeTransmitCmixMessage(partner, []byte{}, "", 6,
-		32, 30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to generate expected CMIX message: %+v", err)
 	}
diff --git a/single/transmission.go b/single/transmission.go
index 13abe66dbd753c5f1b2e6a3036c0c6efa8f0c9b4..d5289f339b1120c87256228d87fd7b7514c0a9d7 100644
--- a/single/transmission.go
+++ b/single/transmission.go
@@ -11,11 +11,11 @@ import (
 	"fmt"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	contact2 "gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/interfaces/utility"
 	"gitlab.com/elixxir/client/storage/reception"
 	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	contact2 "gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/crypto/e2e/singleUse"
@@ -24,6 +24,7 @@ import (
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"io"
 	"sync/atomic"
 	"time"
@@ -72,7 +73,7 @@ func (m *Manager) transmitSingleUse(partner contact2.Contact, payload []byte,
 
 	// Create new CMIX message containing the transmission payload
 	cmixMsg, dhKey, rid, ephID, err := m.makeTransmitCmixMessage(partner,
-		payload, tag, MaxMsgs, addressSize, timeout, time.Now(), rng)
+		payload, tag, MaxMsgs, addressSize, timeout, netTime.Now(), rng)
 	if err != nil {
 		return errors.Errorf("failed to create new CMIX message: %+v", err)
 	}
@@ -80,7 +81,7 @@ func (m *Manager) transmitSingleUse(partner contact2.Contact, payload []byte,
 	jww.DEBUG.Printf("Created single-use transmission CMIX message with new ID "+
 		"%s and ephemeral ID %d", rid, ephID.Int64())
 
-	timeStart := time.Now()
+	timeStart := netTime.Now()
 
 	// Add message state to map
 	quitChan, quit, err := m.p.addState(rid, dhKey, MaxMsgs, callback, timeout)
@@ -139,7 +140,7 @@ func (m *Manager) transmitSingleUse(partner contact2.Contact, payload []byte,
 		}
 
 		// Update the timeout for the elapsed time
-		roundEventTimeout := timeout - time.Now().Sub(timeStart) - time.Millisecond
+		roundEventTimeout := timeout - netTime.Now().Sub(timeStart) - time.Millisecond
 
 		// Check message delivery
 		sendResults := make(chan ds.EventReturn, 1)
diff --git a/single/transmission_test.go b/single/transmission_test.go
index fe6df60ba188ef5abe88e06ab4434c0d289618b5..367a8b3bfa4bd07df0e266045281624934ea3ee3 100644
--- a/single/transmission_test.go
+++ b/single/transmission_test.go
@@ -2,9 +2,9 @@ package single
 
 import (
 	"bytes"
-	contact2 "gitlab.com/elixxir/client/interfaces/contact"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	contact2 "gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/crypto/e2e/singleUse"
@@ -12,6 +12,7 @@ import (
 	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"strings"
@@ -60,7 +61,7 @@ func TestManager_transmitSingleUse(t *testing.T) {
 	}
 
 	expectedMsg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, maxMsgs, 32, 30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		tag, maxMsgs, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to make expected message: %+v", err)
 	}
@@ -204,7 +205,7 @@ func TestManager_transmitSingleUse_AddStateError(t *testing.T) {
 
 	// Create new CMIX and add a state
 	_, dhKey, rid, _, err := m.makeTransmitCmixMessage(partner, payload, tag,
-		maxMsgs, 32, 30*time.Second, time.Now(), rand.New(rand.NewSource(42)))
+		maxMsgs, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
 	if err != nil {
 		t.Fatalf("Failed to create new CMIX message: %+v", err)
 	}
@@ -262,7 +263,7 @@ func TestManager_makeTransmitCmixMessage(t *testing.T) {
 	payload := make([]byte, 132)
 	rand.New(rand.NewSource(42)).Read(payload)
 	maxMsgs := uint8(8)
-	timeNow := time.Now()
+	timeNow := netTime.Now()
 
 	msg, dhKey, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
 		tag, maxMsgs, 32, 30*time.Second, timeNow, prng)
@@ -325,7 +326,7 @@ func TestManager_makeTransmitCmixMessage_PayloadTooLargeError(t *testing.T) {
 	rand.New(rand.NewSource(42)).Read(payload)
 
 	_, _, _, _, err := m.makeTransmitCmixMessage(contact2.Contact{}, payload, "", 8, 32,
-		30*time.Second, time.Now(), prng)
+		30*time.Second, netTime.Now(), prng)
 
 	if !check(err, "too long for message payload capacity") {
 		t.Errorf("makeTransmitCmixMessage() failed to error when the payload is too "+
@@ -343,7 +344,7 @@ func TestManager_makeTransmitCmixMessage_KeyGenerationError(t *testing.T) {
 	}
 
 	_, _, _, _, err := m.makeTransmitCmixMessage(partner, nil, "", 8, 32,
-		30*time.Second, time.Now(), prng)
+		30*time.Second, netTime.Now(), prng)
 
 	if !check(err, "failed to generate key in group") {
 		t.Errorf("makeTransmitCmixMessage() failed to error when key "+
@@ -377,7 +378,7 @@ func Test_makeIDs_Consistency(t *testing.T) {
 		t.Fatalf("Failed to set nonce: %+v", err)
 	}
 
-	timeNow := time.Now()
+	timeNow := netTime.Now()
 
 	rid, ephID, err := makeIDs(&msgPayload, publicKey, addressSize,
 		30*time.Second, timeNow, rand.New(rand.NewSource(42)))
@@ -412,7 +413,7 @@ func Test_makeIDs_NonceError(t *testing.T) {
 	msgPayload := newTransmitMessagePayload(transmitPlMinSize)
 
 	_, _, err := makeIDs(&msgPayload, &cyclic.Int{}, 32, 30*time.Second,
-		time.Now(), strings.NewReader(""))
+		netTime.Now(), strings.NewReader(""))
 	if !check(err, "failed to generate nonce") {
 		t.Errorf("makeIDs() did not return an error when failing to make nonce: %+v", err)
 	}
diff --git a/stoppable/cleanup.go b/stoppable/cleanup.go
index c721f3605aa6d5ef1323a9e01dc2b80b7cb3684c..8111abe206492d4e22cfaffe31195acab58b77c5 100644
--- a/stoppable/cleanup.go
+++ b/stoppable/cleanup.go
@@ -9,6 +9,8 @@ package stoppable
 
 import (
 	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -55,7 +57,7 @@ func (c *Cleanup) Close(timeout time.Duration) error {
 	c.once.Do(
 		func() {
 			defer atomic.StoreUint32(&c.running, 0)
-			start := time.Now()
+			start := netTime.Now()
 
 			// Run the stoppable
 			if err := c.stop.Close(timeout); err != nil {
@@ -85,5 +87,9 @@ func (c *Cleanup) Close(timeout time.Duration) error {
 			}
 		})
 
+	if err!=nil{
+		jww.ERROR.Printf(err.Error())
+	}
+
 	return err
 }
diff --git a/storage/auth/request.go b/storage/auth/request.go
index c33d9b02cbe2477725438903052102fdf18d11ff..b6088352d29a3d0dc584f635ac7d0d26db021bad 100644
--- a/storage/auth/request.go
+++ b/storage/auth/request.go
@@ -8,7 +8,7 @@
 package auth
 
 import (
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"sync"
 )
 
diff --git a/storage/auth/sentRequest.go b/storage/auth/sentRequest.go
index 09251401cbe1433d917a6d3912ab68aaf2873002..77901412056ca674b8756d9e661edff7bd4d8076 100644
--- a/storage/auth/sentRequest.go
+++ b/storage/auth/sentRequest.go
@@ -14,7 +14,7 @@ import (
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentSentRequestVersion = 0
@@ -112,7 +112,7 @@ func (sr *SentRequest) save() error {
 
 	obj := versioned.Object{
 		Version:   currentSentRequestVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      data,
 	}
 
diff --git a/storage/auth/store.go b/storage/auth/store.go
index 1d8f074436461f7c7a3e198bbbbc772d54804388..a03dee9eaced47223f597f14d78c6c093ede6cfd 100644
--- a/storage/auth/store.go
+++ b/storage/auth/store.go
@@ -11,15 +11,15 @@ import (
 	"encoding/json"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 const NoRequest = "Request Not Found"
@@ -161,7 +161,7 @@ func (s *Store) save() error {
 
 	obj := versioned.Object{
 		Version:   requestMapVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      data,
 	}
 
@@ -405,6 +405,5 @@ func (s *Store) Delete(partner *id.ID) error {
 			"deletion: %+v", err)
 	}
 
-	r.mux.Unlock()
 	return nil
 }
diff --git a/storage/auth/store_test.go b/storage/auth/store_test.go
index 591cc31b483e05fcee8bb8084416d3dc71b61c0d..94d0318f3d702cd7f9fb58860ada31a1b6f54b17 100644
--- a/storage/auth/store_test.go
+++ b/storage/auth/store_test.go
@@ -8,8 +8,8 @@
 package auth
 
 import (
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/ekv"
diff --git a/storage/clientVersion/store.go b/storage/clientVersion/store.go
index 3f1eca48aca688113ba8c240ad8e747029947a90..5b6e951ef6c0bf5b86049b636606fa015f9d4062 100644
--- a/storage/clientVersion/store.go
+++ b/storage/clientVersion/store.go
@@ -12,8 +12,8 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/version"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 const (
@@ -105,7 +105,7 @@ func (s *Store) update(newVersion version.Version) error {
 // save stores the clientVersion store. Note that this function does not take
 // a lock.
 func (s *Store) save() error {
-	timeNow := time.Now()
+	timeNow := netTime.Now()
 
 	obj := versioned.Object{
 		Version:   storeVersion,
diff --git a/storage/clientVersion/store_test.go b/storage/clientVersion/store_test.go
index 22da1257c04f0b7780d63b46c0cf28a86bd6143d..72098cffa061ac63ac375f92e533312272e5d3bf 100644
--- a/storage/clientVersion/store_test.go
+++ b/storage/clientVersion/store_test.go
@@ -11,10 +11,10 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/version"
+	"gitlab.com/xx_network/primitives/netTime"
 	"reflect"
 	"strings"
 	"testing"
-	"time"
 )
 
 // Happy path.
@@ -67,7 +67,7 @@ func TestLoadStore_ParseVersionError(t *testing.T) {
 	kv := versioned.NewKV(make(ekv.Memstore))
 	obj := versioned.Object{
 		Version:   storeVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte("invalid version"),
 	}
 
diff --git a/storage/cmix/key.go b/storage/cmix/key.go
index 3a7f6400e238f84a481a08449aaa05c02374a48a..3ab6fc084cff007e879cd541afc44dbf910ea10d 100644
--- a/storage/cmix/key.go
+++ b/storage/cmix/key.go
@@ -12,7 +12,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentKeyVersion = 0
@@ -65,7 +65,7 @@ func loadKey(kv *versioned.KV, id *id.ID) (*key, error) {
 
 // saves the key as the key for the given node ID in the passed keystore
 func (k *key) save() error {
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := k.marshal()
 	if err != nil {
diff --git a/storage/cmix/roundKeys_test.go b/storage/cmix/roundKeys_test.go
index de839aa2a382d7713fd72ddb8873aa05eae1a583..6f69bd6628cdbe2e7bbda3a58b42adcdc01f2bce 100644
--- a/storage/cmix/roundKeys_test.go
+++ b/storage/cmix/roundKeys_test.go
@@ -58,23 +58,21 @@ func TestRoundKeys_Encrypt_Consistency(t *testing.T) {
 		208, 149, 24, 135, 165, 106, 249, 164, 122, 139, 169, 193, 39, 209, 132,
 		238, 23, 153, 115, 200, 104, 31}
 
-
-		expectedKmacs := [][]byte{{110, 235, 79, 128, 16, 94, 181, 95, 101,
-				152, 187, 204, 87, 236, 211, 102, 88, 130, 191, 103, 23, 229,
-				48, 142, 155, 167, 200, 108, 66, 172, 178, 209},
-			{48, 74, 148, 205, 235, 46, 172, 128, 28, 42, 116, 27, 64, 83, 122,
-				5, 51, 162, 200, 198, 234, 92, 77, 131, 136, 108, 57, 97, 193,
-				208, 148, 217},
-			{202, 163, 19, 179, 175, 100, 71, 176, 241, 80, 85, 174, 120, 45,
-				152, 117, 82, 193, 203, 188, 158, 60, 111, 217, 64, 47, 219,
-				169, 100, 177, 42, 159},
-			{66, 121, 20, 21, 206, 142, 3, 75, 229, 94, 197, 4, 117, 223, 245,
-				117, 14, 17, 158, 138, 176, 106, 93, 55, 247, 155, 250, 232,
-				41, 169, 197, 150},
-			{65, 74, 222, 172, 217, 13, 56, 208, 111, 98, 199, 205, 74, 141, 30,
-				109, 51, 20, 186, 9, 234, 197, 6, 200, 139, 86, 139, 130, 8, 15,
-				32, 209}}
-
+	expectedKmacs := [][]byte{{110, 235, 79, 128, 16, 94, 181, 95, 101,
+		152, 187, 204, 87, 236, 211, 102, 88, 130, 191, 103, 23, 229,
+		48, 142, 155, 167, 200, 108, 66, 172, 178, 209},
+		{48, 74, 148, 205, 235, 46, 172, 128, 28, 42, 116, 27, 64, 83, 122,
+			5, 51, 162, 200, 198, 234, 92, 77, 131, 136, 108, 57, 97, 193,
+			208, 148, 217},
+		{202, 163, 19, 179, 175, 100, 71, 176, 241, 80, 85, 174, 120, 45,
+			152, 117, 82, 193, 203, 188, 158, 60, 111, 217, 64, 47, 219,
+			169, 100, 177, 42, 159},
+		{66, 121, 20, 21, 206, 142, 3, 75, 229, 94, 197, 4, 117, 223, 245,
+			117, 14, 17, 158, 138, 176, 106, 93, 55, 247, 155, 250, 232,
+			41, 169, 197, 150},
+		{65, 74, 222, 172, 217, 13, 56, 208, 111, 98, 199, 205, 74, 141, 30,
+			109, 51, 20, 186, 9, 234, 197, 6, 200, 139, 86, 139, 130, 8, 15,
+			32, 209}}
 
 	cmixGrp := cyclic.NewGroup(
 		large.NewIntFromString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"+
diff --git a/storage/cmix/store.go b/storage/cmix/store.go
index ad0a10cd0995abca38207dd1ea77ff5d0dc905ae..95a67d7789c3f8f35642e96ef9d81cc864f4b0cb 100644
--- a/storage/cmix/store.go
+++ b/storage/cmix/store.go
@@ -17,8 +17,8 @@ import (
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 const prefix = "cmix"
@@ -110,6 +110,14 @@ func (s *Store) Add(nid *id.ID, k *cyclic.Int) {
 	}
 }
 
+// Returns if the store has the node
+func (s *Store) Has(nid *id.ID) bool {
+	s.mux.RLock()
+	_, exists := s.nodes[*nid]
+	s.mux.RUnlock()
+	return exists
+}
+
 // Remove removes a node key from the nodes map and saves.
 func (s *Store) Remove(nid *id.ID) {
 	s.mux.Lock()
@@ -194,7 +202,7 @@ func (s *Store) Count() int {
 
 // save stores the cMix store.
 func (s *Store) save() error {
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := s.marshal()
 	if err != nil {
diff --git a/storage/cmix/store_test.go b/storage/cmix/store_test.go
index 8e05e0c39438f1b22b63ea6ff1d3f3b3648b2b73..f4dfc3a7af59ee29511a2172779c6b919ef6ec6b 100644
--- a/storage/cmix/store_test.go
+++ b/storage/cmix/store_test.go
@@ -70,6 +70,41 @@ func TestStore_AddRemove(t *testing.T) {
 	}
 }
 
+
+// Happy path Add/Has test
+func TestStore_AddHas(t *testing.T) {
+	// Uncomment to print keys that Set and Get are called on
+	// jww.SetStdoutThreshold(jww.LevelTrace)
+
+	testStore, _ := makeTestStore()
+
+	nodeId := id.NewIdFromString("test", id.Node, t)
+	key := testStore.grp.NewInt(5)
+
+	testStore.Add(nodeId, key)
+	if _, exists := testStore.nodes[*nodeId]; !exists {
+		t.Fatal("Failed to add node key")
+	}
+
+	if !testStore.Has(nodeId) {
+		t.Fatal("cannot find the node id that that was added")
+	}
+}
+
+// Tests that has returns false when it doesnt have
+func TestStore_DoesntHave(t *testing.T) {
+	// Uncomment to print keys that Set and Get are called on
+	// jww.SetStdoutThreshold(jww.LevelTrace)
+
+	testStore, _ := makeTestStore()
+
+	nodeId := id.NewIdFromString("test", id.Node, t)
+
+	if testStore.Has(nodeId) {
+		t.Fatal("found the node when it shouldnt have been found")
+	}
+}
+
 // Happy path
 func TestLoadStore(t *testing.T) {
 	// Uncomment to print keys that Set and Get are called on
diff --git a/storage/conversation/partner.go b/storage/conversation/partner.go
index 0fef58be68864181ccd18a7282f6be627b26c29f..8bad184d3c1791d2751003f692651ae7112b0854 100644
--- a/storage/conversation/partner.go
+++ b/storage/conversation/partner.go
@@ -13,10 +13,10 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math"
 	"strings"
 	"sync"
-	"time"
 )
 
 const (
@@ -159,7 +159,7 @@ func (c *Conversation) save() error {
 
 	obj := versioned.Object{
 		Version:   currentConversationVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      data,
 	}
 
diff --git a/storage/e2e/key_test.go b/storage/e2e/key_test.go
index d74f53e174685483666c37150be86aef2d3a69a9..0f93e69a2818967cbfd53caaf26d034a8c224296 100644
--- a/storage/e2e/key_test.go
+++ b/storage/e2e/key_test.go
@@ -17,10 +17,10 @@ import (
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/crypto/large"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"testing"
-	"time"
 )
 
 // Happy path of newKey().
@@ -212,7 +212,7 @@ func getSession(t *testing.T) *Session {
 }
 
 func getFingerprint() *format.Fingerprint {
-	rand.Seed(time.Now().UnixNano())
+	rand.Seed(netTime.Now().UnixNano())
 	fp := format.Fingerprint{}
 	rand.Read(fp[:])
 
diff --git a/storage/e2e/manager.go b/storage/e2e/manager.go
index b1feb294761730105b5fa70fa9f27b669c79f78a..802e81ebe2329f5bd3714500e0229071eaea3bd3 100644
--- a/storage/e2e/manager.go
+++ b/storage/e2e/manager.go
@@ -159,8 +159,7 @@ func (m *Manager) GetKeyForSending(st params.SendType) (*Key, error) {
 
 // GetPartnerID returns a copy of the ID of the partner.
 func (m *Manager) GetPartnerID() *id.ID {
-	p := m.partner
-	return p
+	return m.partner.DeepCopy()
 }
 
 // GetSendSession gets the Send session of the passed ID. Returns nil if no
diff --git a/storage/e2e/manager_test.go b/storage/e2e/manager_test.go
index 58b0ca6bb6c5b846abc994b8c5f43e90819be664..907bbff91b561d2267b71371356ae7bf6f332b86 100644
--- a/storage/e2e/manager_test.go
+++ b/storage/e2e/manager_test.go
@@ -14,10 +14,10 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"testing"
-	"time"
 )
 
 // Tests happy path of newManager.
@@ -234,7 +234,7 @@ func TestManager_TriggerNegotiations(t *testing.T) {
 
 // newTestManager returns a new relationship for testing.
 func newTestManager(t *testing.T) (*Manager, *versioned.KV) {
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	s, ctx := makeTestSession()
 	kv := versioned.NewKV(make(ekv.Memstore))
 	partnerID := id.NewIdFromUInts([4]uint64{prng.Uint64(), prng.Uint64(),
diff --git a/storage/e2e/relationship.go b/storage/e2e/relationship.go
index 0ff938ab6431084f70f26ba2689ed8f928f46660..6efd7081b133fae3845c83e1fbc5ecf3997da1ae 100644
--- a/storage/e2e/relationship.go
+++ b/storage/e2e/relationship.go
@@ -14,8 +14,8 @@ import (
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 const maxUnconfirmed uint = 3
@@ -111,7 +111,7 @@ func LoadRelationship(manager *Manager, t RelationshipType) (*relationship, erro
 
 func (r *relationship) save() error {
 
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := r.marshal()
 	if err != nil {
@@ -219,9 +219,13 @@ func (r *relationship) getSessionForSending() *Session {
 	var unconfirmedActive []*Session
 	var unconfirmedRekey []*Session
 
+	jww.TRACE.Printf("[REKEY] Sessions Available: %d", len(sessions))
+
 	for _, s := range sessions {
 		status := s.Status()
 		confirmed := s.IsConfirmed()
+		jww.TRACE.Printf("[REKEY] Session Status/Confirmed: %v, %v",
+			status, confirmed)
 		if status == Active && confirmed {
 			//always return the first confirmed active, happy path
 			return s
@@ -243,12 +247,13 @@ func (r *relationship) getSessionForSending() *Session {
 		return unconfirmedRekey[0]
 	}
 
-	jww.INFO.Printf("Details about %v sessions which are invalid:", len(sessions))
+	jww.INFO.Printf("[REKEY] Details about %v sessions which are invalid:", len(sessions))
 	for i, s := range sessions {
 		if s == nil {
-			jww.INFO.Printf("\tSession %v is nil", i)
+			jww.INFO.Printf("[REKEY]\tSession %v is nil", i)
 		} else {
-			jww.INFO.Printf("\tSession %v: status: %v, confimred: %v", i, s.Status(), s.IsConfirmed())
+			jww.INFO.Printf("[REKEY]\tSession %v: status: %v,"+
+				" confirmed: %v", i, s.Status(), s.IsConfirmed())
 		}
 	}
 
@@ -288,17 +293,24 @@ func (r *relationship) getNewestRekeyableSession() *Session {
 	if len(sessions) == 0 {
 		return nil
 	}
+
+	var unconfirmed *Session
+
 	for _, s := range r.sessions {
 		//fmt.Println(i)
 		// This looks like it might not be thread safe, I think it is because
 		// the failure mode is it skips to a lower key to rekey with, which is
 		// always valid. It isn't clear it can fail though because we are
 		// accessing the data in the same order it would be written (i think)
-		if s.Status() != RekeyEmpty && s.IsConfirmed() {
-			return s
+		if s.Status() != RekeyEmpty {
+			if s.IsConfirmed(){
+				return s
+			}else if unconfirmed == nil{
+				unconfirmed = s
+			}
 		}
 	}
-	return nil
+	return unconfirmed
 }
 
 func (r *relationship) GetByID(id SessionID) *Session {
diff --git a/storage/e2e/relationshipFingerprint.go b/storage/e2e/relationshipFingerprint.go
index f071e5ffb0dcf4e90e40e461338eedbf9c78fc51..a3702655319ccf0f14323d31f5b32b3fe59cb825 100644
--- a/storage/e2e/relationshipFingerprint.go
+++ b/storage/e2e/relationshipFingerprint.go
@@ -13,7 +13,7 @@ import (
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 func makeRelationshipFingerprint(t RelationshipType, grp *cyclic.Group,
@@ -36,7 +36,7 @@ func makeRelationshipFingerprint(t RelationshipType, grp *cyclic.Group,
 }
 
 func storeRelationshipFingerprint(fp []byte, kv *versioned.KV) error {
-	now := time.Now()
+	now := netTime.Now()
 	obj := versioned.Object{
 		Version:   currentRelationshipFingerprintVersion,
 		Timestamp: now,
diff --git a/storage/e2e/relationship_test.go b/storage/e2e/relationship_test.go
index df9e7be0ecc120ab445ab055808e05dcc4cbc884..49fa51de4abe7df24421ae8c91b24c09f8c10b45 100644
--- a/storage/e2e/relationship_test.go
+++ b/storage/e2e/relationship_test.go
@@ -14,6 +14,7 @@ import (
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
 	"reflect"
+	"sync"
 	"testing"
 )
 
@@ -196,8 +197,8 @@ func TestRelationship_GetNewestRekeyableSession(t *testing.T) {
 	sb.sessions[0].negotiationStatus = Unconfirmed
 	// no available rekeyable sessions: nil
 	session2 := sb.getNewestRekeyableSession()
-	if session2 != nil {
-		t.Error("newest rekeyable session should be nil")
+	if session2 != sb.sessions[0] {
+		t.Error("newest rekeyable session should be the unconfired session")
 	}
 
 	// add a rekeyable session: that session
@@ -534,3 +535,40 @@ func relationshipsEqual(buff *relationship, buff2 *relationship) bool {
 	}
 	return true
 }
+
+func Test_relationship_getNewestRekeyableSession(t *testing.T) {
+	type fields struct {
+		manager     *Manager
+		t           RelationshipType
+		kv          *versioned.KV
+		sessions    []*Session
+		sessionByID map[SessionID]*Session
+		fingerprint []byte
+		mux         sync.RWMutex
+		sendMux     sync.Mutex
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   *Session
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			r := &relationship{
+				manager:     tt.fields.manager,
+				t:           tt.fields.t,
+				kv:          tt.fields.kv,
+				sessions:    tt.fields.sessions,
+				sessionByID: tt.fields.sessionByID,
+				fingerprint: tt.fields.fingerprint,
+				mux:         tt.fields.mux,
+				sendMux:     tt.fields.sendMux,
+			}
+			if got := r.getNewestRekeyableSession(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("getNewestRekeyableSession() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
\ No newline at end of file
diff --git a/storage/e2e/session.go b/storage/e2e/session.go
index 76c614861f663ff834e22cc53e7e54c72f58d3ff..5f0344378ae7f106edd4c447904dd89cb2b6ca94 100644
--- a/storage/e2e/session.go
+++ b/storage/e2e/session.go
@@ -10,11 +10,6 @@ package e2e
 import (
 	"encoding/json"
 	"fmt"
-	"math/big"
-	"sync"
-	"testing"
-	"time"
-
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces/params"
@@ -24,6 +19,10 @@ import (
 	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/crypto/randomness"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+	"math/big"
+	"sync"
+	"testing"
 )
 
 const currentSessionVersion = 0
@@ -38,6 +37,8 @@ type Session struct {
 	//params
 	e2eParams params.E2ESessionParams
 
+	partner *id.ID
+
 	//type
 	t RelationshipType
 
@@ -93,6 +94,8 @@ type SessionDisk struct {
 
 	// Number of keys usable before rekey
 	RekeyThreshold uint32
+
+	Partner []byte
 }
 
 /*CONSTRUCTORS*/
@@ -116,6 +119,7 @@ func newSession(ship *relationship, t RelationshipType, myPrivKey, partnerPubKey
 		relationshipFingerprint: relationshipFingerprint,
 		negotiationStatus:       negotiationStatus,
 		partnerSource:           trigger,
+		partner: 				 ship.manager.partner.DeepCopy(),
 	}
 
 	session.kv = session.generate(ship.kv)
@@ -169,12 +173,17 @@ func loadSession(ship *relationship, kv *versioned.KV,
 	}
 	session.relationshipFingerprint = relationshipFingerprint
 
+	if !session.partner.Cmp(ship.manager.partner){
+		return nil, errors.Errorf("Stored partner (%s) did not match " +
+			"relationship partner (%s)", session.partner, ship.manager.partner)
+	}
+
 	return &session, nil
 }
 
 func (s *Session) save() error {
 
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := s.marshal()
 	if err != nil {
@@ -263,7 +272,7 @@ func (s *Session) GetID() SessionID {
 // returns the ID of the partner for this session
 func (s *Session) GetPartner() *id.ID {
 	if s.relationship != nil {
-		return s.relationship.manager.partner
+		return s.relationship.manager.partner.DeepCopy()
 	} else {
 		return nil
 	}
@@ -280,6 +289,7 @@ func (s *Session) marshal() ([]byte, error) {
 	sd.PartnerPubKey = s.partnerPubKey.Bytes()
 	sd.Trigger = s.partnerSource[:]
 	sd.RelationshipFingerprint = s.relationshipFingerprint
+	sd.Partner = s.partner.Bytes()
 
 	// assume in progress confirmations and session creations have failed on
 	// reset, therefore do not store their pending progress
@@ -316,6 +326,7 @@ func (s *Session) unmarshal(b []byte) error {
 	s.negotiationStatus = Negotiation(sd.Confirmation)
 	s.rekeyThreshold = sd.RekeyThreshold
 	s.relationshipFingerprint = sd.RelationshipFingerprint
+	s.partner, _ = id.Unmarshal(sd.Partner)
 	copy(s.partnerSource[:], sd.Trigger)
 
 	s.keyState, err = loadStateVector(s.kv, "")
@@ -390,12 +401,13 @@ func (s *Session) Status() Status {
 // from this function
 
 var legalStateChanges = [][]bool{
-	{false, false, false, false, false, false},
-	{true, false, true, true, false, false},
-	{false, false, false, true, false, false},
-	{false, false, false, false, true, false},
-	{false, false, false, true, false, true},
-	{false, false, false, false, false, false},
+	// Unconf  Sending  Sent   Confi  NewTrig  NewCreat
+	{false, false, false, false, false, false}, // Unc
+	{true, false, true, true, false, false},    // Sending
+	{false, false, false, true, false, false},  // Sent
+	{false, false, false, false, true, false},  // Confi
+	{false, false, false, true, false, true},   // NewTrig
+	{false, false, true, false, false, false},  // NewCreat
 }
 
 func (s *Session) SetNegotiationStatus(status Negotiation) {
@@ -455,10 +467,12 @@ func (s *Session) triggerNegotiation() bool {
 	// the checked cases will turn out to be false.
 	s.mux.RLock()
 	// If we've used more keys than the RekeyThreshold, it's time for a rekey
-	if s.keyState.GetNumUsed() >= s.rekeyThreshold && s.negotiationStatus == Confirmed {
+	if s.keyState.GetNumUsed() >= s.rekeyThreshold &&
+		s.negotiationStatus < NewSessionTriggered {
 		s.mux.RUnlock()
 		s.mux.Lock()
-		if s.keyState.GetNumUsed() >= s.rekeyThreshold && s.negotiationStatus == Confirmed {
+		if s.keyState.GetNumUsed() >= s.rekeyThreshold &&
+			s.negotiationStatus < NewSessionTriggered {
 			//partnerSource a rekey to create a new session
 			s.negotiationStatus = NewSessionTriggered
 			// no save is make after the update because we do not want this state
diff --git a/storage/e2e/session_test.go b/storage/e2e/session_test.go
index 495dc39095218506a1bbe427a746b971d0998164..800cac5410e8b5236d9c89aa5ed90c36a49bc654 100644
--- a/storage/e2e/session_test.go
+++ b/storage/e2e/session_test.go
@@ -16,6 +16,7 @@ import (
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"reflect"
 	"testing"
 	"time"
@@ -460,7 +461,7 @@ func TestSession_SetNegotiationStatus(t *testing.T) {
 	//	Normal paths: SetNegotiationStatus should not fail
 	// Use timestamps to determine whether a save has occurred
 	s.negotiationStatus = Sending
-	now := time.Now()
+	now := netTime.Now()
 	time.Sleep(time.Millisecond)
 	s.SetNegotiationStatus(Sent)
 	if s.negotiationStatus != Sent {
@@ -474,7 +475,7 @@ func TestSession_SetNegotiationStatus(t *testing.T) {
 		t.Errorf("save didn't occur after switching Sending to Sent")
 	}
 
-	now = time.Now()
+	now = netTime.Now()
 	time.Sleep(time.Millisecond)
 	s.SetNegotiationStatus(Confirmed)
 	if s.negotiationStatus != Confirmed {
@@ -488,7 +489,7 @@ func TestSession_SetNegotiationStatus(t *testing.T) {
 		t.Errorf("save didn't occur after switching Sent to Confirmed")
 	}
 
-	now = time.Now()
+	now = netTime.Now()
 	time.Sleep(time.Millisecond)
 	s.negotiationStatus = NewSessionTriggered
 	s.SetNegotiationStatus(NewSessionCreated)
@@ -505,7 +506,7 @@ func TestSession_SetNegotiationStatus(t *testing.T) {
 
 	// Reverting paths: SetNegotiationStatus should not fail, and a save should not take place
 	time.Sleep(time.Millisecond)
-	now = time.Now()
+	now = netTime.Now()
 	time.Sleep(time.Millisecond)
 	s.negotiationStatus = Sending
 	s.SetNegotiationStatus(Unconfirmed)
@@ -629,6 +630,7 @@ func makeTestSession() (*Session, *context) {
 			manager: &Manager{
 				ctx: ctx,
 				kv:  kv,
+				partner: &id.ID{},
 			},
 			kv: kv,
 		},
@@ -636,6 +638,7 @@ func makeTestSession() (*Session, *context) {
 		t:                 Receive,
 		negotiationStatus: Confirmed,
 		rekeyThreshold:    5,
+		partner: &id.ID{},
 	}
 	var err error
 	s.keyState, err = newStateVector(s.kv,
diff --git a/storage/e2e/stateVector.go b/storage/e2e/stateVector.go
index 4a2e6271c0f42f65060f4416bfd7603f2a3d4d5d..10306ae562bde79a5d6382d167f83b823ccbc8df 100644
--- a/storage/e2e/stateVector.go
+++ b/storage/e2e/stateVector.go
@@ -13,8 +13,8 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 const currentStateVectorVersion = 0
@@ -79,7 +79,7 @@ func loadStateVector(kv *versioned.KV, key string) (*stateVector, error) {
 }
 
 func (sv *stateVector) save() error {
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := sv.marshal()
 	if err != nil {
diff --git a/storage/e2e/store.go b/storage/e2e/store.go
index ae06cb56b5112fa39c2812de23d69b00966e8f18..a0a427e0abbff557514b6d4197335cc75c427a69 100644
--- a/storage/e2e/store.go
+++ b/storage/e2e/store.go
@@ -19,8 +19,8 @@ import (
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 const (
@@ -144,7 +144,7 @@ func LoadStore(kv *versioned.KV, myID *id.ID, rng *fastRNG.StreamGenerator) (*St
 }
 
 func (s *Store) save() error {
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := s.marshal()
 	if err != nil {
@@ -249,16 +249,24 @@ func (s *Store) unmarshal(b []byte) error {
 		return err
 	}
 
-	for _, partnerID := range contacts {
+	for i := range contacts {
+		//load the contact separately to ensure pointers do not get swapped
+		partnerID := (&contacts[i]).DeepCopy()
 		// Load the relationship. The relationship handles adding the fingerprints via the
 		// context object
-		manager, err := loadManager(s.context, s.kv, &partnerID)
+		manager, err := loadManager(s.context, s.kv, partnerID)
 		if err != nil {
 			jww.FATAL.Panicf("Failed to load relationship for partner %s: %s",
-				&partnerID, err.Error())
+				partnerID, err.Error())
 		}
 
-		s.managers[partnerID] = manager
+		if !manager.GetPartnerID().Cmp(partnerID){
+			jww.FATAL.Panicf("Loaded a manager with the wrong partner " +
+				"ID: \n\t loaded: %s \n\t present: %s",
+				partnerID, manager.GetPartnerID())
+		}
+
+		s.managers[*partnerID] = manager
 	}
 
 	s.dhPrivateKey, err = utility.LoadCyclicKey(s.kv, privKeyKey)
diff --git a/storage/partition/multiPartMessage.go b/storage/partition/multiPartMessage.go
index 7dc6cbb886136577caee703337485cab0367369f..754c524702498c2c6586d54a42adedf3351a7cc5 100644
--- a/storage/partition/multiPartMessage.go
+++ b/storage/partition/multiPartMessage.go
@@ -17,6 +17,7 @@ import (
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
 	"time"
 )
@@ -85,7 +86,7 @@ func (mpm *multiPartMessage) save() error {
 
 	obj := versioned.Object{
 		Version:   currentMultiPartMessageVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      data,
 	}
 
diff --git a/storage/partition/multiPartMessage_test.go b/storage/partition/multiPartMessage_test.go
index ec871783b1e935a0653283102a29b7b8e7b9b939..dff3c0fabb41cffd20f714497b487ea8bcbd4644 100644
--- a/storage/partition/multiPartMessage_test.go
+++ b/storage/partition/multiPartMessage_test.go
@@ -15,6 +15,7 @@ import (
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"testing"
@@ -24,7 +25,7 @@ import (
 // Tests the creation part of loadOrCreateMultiPartMessage().
 func Test_loadOrCreateMultiPartMessage_Create(t *testing.T) {
 	// Set up expected test value
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	expectedMpm := &multiPartMessage{
 		Sender:       id.NewIdFromUInt(prng.Uint64(), id.User, t),
 		MessageID:    prng.Uint64(),
@@ -60,7 +61,7 @@ func Test_loadOrCreateMultiPartMessage_Create(t *testing.T) {
 // Tests the loading part of loadOrCreateMultiPartMessage().
 func Test_loadOrCreateMultiPartMessage_Load(t *testing.T) {
 	// Set up expected test value
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	expectedMpm := &multiPartMessage{
 		Sender:       id.NewIdFromUInt(prng.Uint64(), id.User, t),
 		MessageID:    prng.Uint64(),
@@ -115,7 +116,7 @@ func CheckMultiPartMessages(expectedMpm *multiPartMessage, mpm *multiPartMessage
 // Tests happy path of multiPartMessage.Add().
 func TestMultiPartMessage_Add(t *testing.T) {
 	// Generate test values
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	mpm := loadOrCreateMultiPartMessage(id.NewIdFromUInt(prng.Uint64(), id.User, t),
 		prng.Uint64(), versioned.NewKV(make(ekv.Memstore)))
 	partNums, parts := generateParts(prng, 0)
@@ -156,13 +157,13 @@ func TestMultiPartMessage_Add(t *testing.T) {
 // Tests happy path of multiPartMessage.AddFirst().
 func TestMultiPartMessage_AddFirst(t *testing.T) {
 	// Generate test values
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	expectedMpm := &multiPartMessage{
 		Sender:       id.NewIdFromUInt(prng.Uint64(), id.User, t),
 		MessageID:    prng.Uint64(),
 		NumParts:     uint8(prng.Uint32()),
 		PresentParts: 1,
-		Timestamp:    time.Now(),
+		Timestamp:    netTime.Now(),
 		MessageType:  message.NoType,
 		parts:        make([][]byte, 3),
 		kv:           versioned.NewKV(make(ekv.Memstore)),
@@ -190,7 +191,7 @@ func TestMultiPartMessage_AddFirst(t *testing.T) {
 // Tests happy path of multiPartMessage.IsComplete().
 func TestMultiPartMessage_IsComplete(t *testing.T) {
 	// Create multiPartMessage and fill with random parts
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	mid := prng.Uint64()
 	mpm := loadOrCreateMultiPartMessage(id.NewIdFromUInt(prng.Uint64(), id.User, t),
 		mid, versioned.NewKV(make(ekv.Memstore)))
@@ -202,7 +203,7 @@ func TestMultiPartMessage_IsComplete(t *testing.T) {
 		t.Error("IsComplete() returned true when NumParts == 0.")
 	}
 
-	mpm.AddFirst(message.Text, partNums[0], 75, time.Now(), parts[0])
+	mpm.AddFirst(message.Text, partNums[0], 75, netTime.Now(), parts[0])
 	for i := range partNums {
 		if i > 0 {
 			mpm.Add(partNums[i], parts[i])
@@ -237,7 +238,7 @@ func TestMultiPartMessage_IsComplete(t *testing.T) {
 
 // Tests happy path of multiPartMessage.delete().
 func TestMultiPartMessage_delete(t *testing.T) {
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	kv := versioned.NewKV(make(ekv.Memstore))
 	mpm := loadOrCreateMultiPartMessage(id.NewIdFromUInt(prng.Uint64(), id.User, t),
 		prng.Uint64(), kv)
diff --git a/storage/partition/part.go b/storage/partition/part.go
index 66206fd4345d19ba233cfbd185f4251fb4bd74a6..9c24861ff83e732606341e1130bf041cc344c75a 100644
--- a/storage/partition/part.go
+++ b/storage/partition/part.go
@@ -10,7 +10,7 @@ package partition
 import (
 	"fmt"
 	"gitlab.com/elixxir/client/storage/versioned"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentMultiPartMessagePartVersion = 0
@@ -31,7 +31,7 @@ func savePart(kv *versioned.KV, partNum uint8, part []byte) error {
 
 	obj := versioned.Object{
 		Version:   currentMultiPartMessagePartVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      part,
 	}
 
diff --git a/storage/partition/part_test.go b/storage/partition/part_test.go
index 22dfa11156024976b1d96c50988c464f1ec00612..b1db602f7932a505a877e8c34a54ed61173cf1ab 100644
--- a/storage/partition/part_test.go
+++ b/storage/partition/part_test.go
@@ -11,15 +11,15 @@ import (
 	"bytes"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"testing"
-	"time"
 )
 
 // Tests happy path of savePart().
 func Test_savePart(t *testing.T) {
 	// Set up test values
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	kv := versioned.NewKV(make(ekv.Memstore))
 	partNum := uint8(prng.Uint32())
 	part := make([]byte, prng.Int31n(500))
@@ -48,7 +48,7 @@ func Test_savePart(t *testing.T) {
 // Tests happy path of loadPart().
 func Test_loadPart(t *testing.T) {
 	// Set up test values
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	rootKv := versioned.NewKV(make(ekv.Memstore))
 	partNum := uint8(prng.Uint32())
 	part := make([]byte, prng.Int31n(500))
@@ -56,7 +56,7 @@ func Test_loadPart(t *testing.T) {
 	key := makeMultiPartMessagePartKey(partNum)
 
 	// Save part to key value store
-	err := rootKv.Set(key, 0, &versioned.Object{Timestamp: time.Now(), Data: part})
+	err := rootKv.Set(key, 0, &versioned.Object{Timestamp: netTime.Now(), Data: part})
 	if err != nil {
 		t.Fatalf("Failed to set object: %v", err)
 	}
@@ -78,7 +78,7 @@ func Test_loadPart(t *testing.T) {
 // key.
 func Test_loadPart_NotFoundError(t *testing.T) {
 	// Set up test values
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	kv := versioned.NewKV(make(ekv.Memstore))
 	partNum := uint8(prng.Uint32())
 	part := make([]byte, prng.Int31n(500))
@@ -100,7 +100,7 @@ func Test_loadPart_NotFoundError(t *testing.T) {
 // Test happy path of deletePart().
 func TestDeletePart(t *testing.T) {
 	// Set up test values
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	kv := versioned.NewKV(make(ekv.Memstore))
 	partNum := uint8(prng.Uint32())
 	part := make([]byte, prng.Int31n(500))
diff --git a/storage/partition/store_test.go b/storage/partition/store_test.go
index c150d026d55389793dd32952b2fe209a29192e8b..9de6327d989d032e6ed987db0aff891d6be0fa3b 100644
--- a/storage/partition/store_test.go
+++ b/storage/partition/store_test.go
@@ -13,9 +13,9 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"reflect"
 	"testing"
-	"time"
 )
 
 // Tests happy path of New().
@@ -40,7 +40,7 @@ func TestStore_AddFirst(t *testing.T) {
 	s := New(versioned.NewKV(ekv.Memstore{}))
 
 	msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t),
-		message.Text, 5, 0, 1, time.Now(), part,
+		message.Text, 5, 0, 1, netTime.Now(), part,
 		[]byte{0})
 
 	if !complete {
@@ -60,7 +60,7 @@ func TestStore_Add(t *testing.T) {
 	s := New(versioned.NewKV(ekv.Memstore{}))
 
 	msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t),
-		message.Text, 5, 0, 2, time.Now(), part1,
+		message.Text, 5, 0, 2, netTime.Now(), part1,
 		[]byte{0})
 
 	if complete {
diff --git a/storage/reception/IdentityUse.go b/storage/reception/IdentityUse.go
index 37432d9d1e8ea40b6da4e92a723ae99b96353f73..93fc6b8d6c374cbf166d1a55e3c302a46192704f 100644
--- a/storage/reception/IdentityUse.go
+++ b/storage/reception/IdentityUse.go
@@ -2,6 +2,7 @@ package reception
 
 import (
 	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/storage/rounds"
 	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/crypto/randomness"
 	"io"
@@ -19,8 +20,8 @@ type IdentityUse struct {
 	// Denotes if the identity is fake, in which case we do not process messages
 	Fake bool
 
-	// rounds data
-	UR *UnknownRound
+	UR *rounds.UnknownRounds
+	ER *rounds.EarliestRound
 }
 
 // setSamplingPeriod add the Request mask as a random buffer around the sampling
diff --git a/storage/reception/fake_test.go b/storage/reception/fake_test.go
index 1327f84a03f6f779a63f652584fdb4e17c2cb72b..35ff0e1727a76645ef350b8d1e4a7cd5a76691e9 100644
--- a/storage/reception/fake_test.go
+++ b/storage/reception/fake_test.go
@@ -24,7 +24,7 @@ func Test_generateFakeIdentity(t *testing.T) {
 		"\"EndValid\":" + string(endValid) + "," +
 		"\"RequestMask\":86400000000000,\"Ephemeral\":true," +
 		"\"StartRequest\":\"0001-01-01T00:00:00Z\"," +
-		"\"EndRequest\":\"0001-01-01T00:00:00Z\",\"Fake\":true,\"UR\":null}"
+		"\"EndRequest\":\"0001-01-01T00:00:00Z\",\"Fake\":true,\"UR\":null,\"ER\":null}"
 
 	timestamp := time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
 
diff --git a/storage/reception/identity.go b/storage/reception/identity.go
index e4fa2556c6564226c7226689b30478e9a693493c..4c65d9696ba4a6d0fd567395a4d86e8bd9145b45 100644
--- a/storage/reception/identity.go
+++ b/storage/reception/identity.go
@@ -6,6 +6,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"strconv"
 	"time"
 )
@@ -44,6 +45,7 @@ func loadIdentity(kv *versioned.KV) (Identity, error) {
 	if err != nil {
 		return Identity{}, errors.WithMessage(err, "Failed to unmarshal Identity")
 	}
+
 	return r, nil
 }
 
@@ -57,7 +59,7 @@ func (i Identity) store(kv *versioned.KV) error {
 	// Create versioned object with data
 	obj := &versioned.Object{
 		Version:   identityStorageVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      regStr,
 	}
 
diff --git a/storage/reception/identity_test.go b/storage/reception/identity_test.go
index 8499050e9e988b1a48b9e59ad8501ddd211a74c6..d80b9501486c94045209da5c99dc0b77a07306f8 100644
--- a/storage/reception/identity_test.go
+++ b/storage/reception/identity_test.go
@@ -5,6 +5,7 @@ import (
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"testing"
 	"time"
@@ -15,10 +16,10 @@ func TestIdentity_EncodeDecode(t *testing.T) {
 	r := Identity{
 		EphId:       ephemeral.Id{},
 		Source:      &id.Permissioning,
-		End:         time.Now().Round(0),
+		End:         netTime.Now().Round(0),
 		ExtraChecks: 12,
-		StartValid:  time.Now().Round(0),
-		EndValid:    time.Now().Round(0),
+		StartValid:  netTime.Now().Round(0),
+		EndValid:    netTime.Now().Round(0),
 		RequestMask: 2 * time.Hour,
 		Ephemeral:   false,
 	}
@@ -44,10 +45,10 @@ func TestIdentity_Delete(t *testing.T) {
 	r := Identity{
 		EphId:       ephemeral.Id{},
 		Source:      &id.Permissioning,
-		End:         time.Now().Round(0),
+		End:         netTime.Now().Round(0),
 		ExtraChecks: 12,
-		StartValid:  time.Now().Round(0),
-		EndValid:    time.Now().Round(0),
+		StartValid:  netTime.Now().Round(0),
+		EndValid:    netTime.Now().Round(0),
 		RequestMask: 2 * time.Hour,
 		Ephemeral:   false,
 	}
@@ -85,7 +86,7 @@ func TestIdentity_Equal(t *testing.T) {
 	timestamp := time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
 	a, _ := generateFakeIdentity(rand.New(rand.NewSource(42)), 15, timestamp)
 	b, _ := generateFakeIdentity(rand.New(rand.NewSource(42)), 15, timestamp)
-	c, _ := generateFakeIdentity(rand.New(rand.NewSource(42)), 15, time.Now())
+	c, _ := generateFakeIdentity(rand.New(rand.NewSource(42)), 15, netTime.Now())
 
 	if !a.Identity.Equal(b.Identity) {
 		t.Errorf("Equal() found two equal identities as unequal."+
diff --git a/storage/reception/registration.go b/storage/reception/registration.go
index 2365cdea68701671620ffe9b86eddef8e901c7a7..70647129c7c621b9a757b9d42ec82ef66f3c1bd3 100644
--- a/storage/reception/registration.go
+++ b/storage/reception/registration.go
@@ -2,9 +2,11 @@ package reception
 
 import (
 	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/storage/rounds"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"strconv"
 	"time"
 )
@@ -13,7 +15,8 @@ const knownRoundsStorageKey = "krStorage"
 
 type registration struct {
 	Identity
-	ur *UnknownRound
+	UR *rounds.UnknownRounds
+	ER *rounds.EarliestRound
 	kv *versioned.KV
 }
 
@@ -23,7 +26,7 @@ func newRegistration(reg Identity, kv *versioned.KV) (*registration, error) {
 	reg.EndValid = reg.EndValid.Round(0)
 	reg.End = reg.End.Round(0)
 
-	now := time.Now()
+	now := netTime.Now()
 
 	// Do edge checks to determine if the identity is valid
 	if now.After(reg.End) && reg.ExtraChecks < 1 {
@@ -36,10 +39,14 @@ func newRegistration(reg Identity, kv *versioned.KV) (*registration, error) {
 
 	r := &registration{
 		Identity: reg,
-		ur:       NewUnknownRound(!reg.Ephemeral, kv),
 		kv:       kv,
 	}
 
+	urParams := rounds.DefaultUnknownRoundsParams()
+	urParams.Stored = !reg.Ephemeral
+	r.UR = rounds.NewUnknownRounds(kv, urParams)
+	r.ER = rounds.NewEarliestRound(!reg.Ephemeral, kv)
+
 	// If this is not ephemeral, then store everything
 	if !reg.Ephemeral {
 		// Store known rounds
@@ -64,12 +71,11 @@ func loadRegistration(EphId ephemeral.Id, Source *id.ID, startValid time.Time,
 			"for %s", regPrefix(EphId, Source, startValid))
 	}
 
-	ur := LoadUnknownRound(kv)
-
 	r := &registration{
 		Identity: reg,
-		ur:       ur,
 		kv:       kv,
+		UR:       rounds.LoadUnknownRounds(kv, rounds.DefaultUnknownRoundsParams()),
+		ER:       rounds.LoadEarliestRound(kv),
 	}
 
 	return r, nil
@@ -77,7 +83,7 @@ func loadRegistration(EphId ephemeral.Id, Source *id.ID, startValid time.Time,
 
 func (r *registration) Delete() error {
 	if !r.Ephemeral {
-		r.ur.delete()
+		r.UR.Delete()
 		if err := r.delete(r.kv); err != nil {
 			return errors.WithMessagef(err, "Failed to delete registration "+
 				"public data %s", r)
diff --git a/storage/reception/registration_test.go b/storage/reception/registration_test.go
index 77475258af4ef6030b222b5b58523bc82e2e530b..8e9024c46d9fdb60726498b9fb103cb2b1beddbb 100644
--- a/storage/reception/registration_test.go
+++ b/storage/reception/registration_test.go
@@ -3,6 +3,7 @@ package reception
 import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"strings"
 	"testing"
@@ -34,7 +35,7 @@ func TestNewRegistration_Ephemeral(t *testing.T) {
 	id := idu.Identity
 	kv := versioned.NewKV(make(ekv.Memstore))
 
-	id.End = time.Now().Add(1 * time.Hour)
+	id.End = netTime.Now().Add(1 * time.Hour)
 	id.ExtraChecks = 2
 	id.Ephemeral = true
 
@@ -44,10 +45,6 @@ func TestNewRegistration_Ephemeral(t *testing.T) {
 			"succeeded: %+v", err)
 	}
 
-	if reg.ur == nil {
-		t.Error("Ephemeral identity does not have a known rounds.")
-	}
-
 	if _, err = reg.kv.Get(identityStorageKey, 0); err == nil {
 		t.Error("Ephemeral identity stored the identity when it should not have.")
 	}
@@ -61,7 +58,7 @@ func TestNewRegistration_Persistent(t *testing.T) {
 	id := idu.Identity
 	kv := versioned.NewKV(make(ekv.Memstore))
 
-	id.End = time.Now().Add(1 * time.Hour)
+	id.End = netTime.Now().Add(1 * time.Hour)
 	id.ExtraChecks = 2
 	id.Ephemeral = false
 
@@ -71,14 +68,6 @@ func TestNewRegistration_Persistent(t *testing.T) {
 			"succeeded: %+v", err)
 	}
 
-	if reg.ur == nil {
-		t.Error("Persistent identity does not have a known rounds.")
-	}
-
-	// Check if the known rounds is stored, it should not be. this will panic
-	// if it isnt
-	LoadUnknownRound(reg.kv)
-
 	if _, err = reg.kv.Get(identityStorageKey, 0); err != nil {
 		t.Errorf("Persistent identity did not store the identity when "+
 			"it should: %+v.", err)
@@ -93,7 +82,7 @@ func TestLoadRegistration(t *testing.T) {
 	id := idu.Identity
 	kv := versioned.NewKV(make(ekv.Memstore))
 
-	id.End = time.Now().Add(1 * time.Hour)
+	id.End = netTime.Now().Add(1 * time.Hour)
 	id.ExtraChecks = 2
 	id.Ephemeral = false
 
@@ -103,15 +92,11 @@ func TestLoadRegistration(t *testing.T) {
 			"succeeded: %+v", err)
 	}
 
-	reg, err := loadRegistration(idu.EphId, idu.Source, idu.StartValid, kv)
+	_, err = loadRegistration(idu.EphId, idu.Source, idu.StartValid, kv)
 	if err != nil {
 		t.Fatalf("Registration loading failed: %+v", err)
 	}
 
-	if reg.ur == nil {
-		t.Error("Loading should have a UR.")
-	}
-
 }
 
 // TODO: finish
@@ -123,7 +108,7 @@ func Test_registration_Delete(t *testing.T) {
 	id := idu.Identity
 	kv := versioned.NewKV(make(ekv.Memstore))
 
-	id.End = time.Now().Add(1 * time.Hour)
+	id.End = netTime.Now().Add(1 * time.Hour)
 	id.ExtraChecks = 2
 	id.Ephemeral = false
 
diff --git a/storage/reception/store.go b/storage/reception/store.go
index dcf7dcb796bd1a4232d877cad825cd4b197c6939..f87ee416abaecd01e3955549080e462b3ae1e3ad 100644
--- a/storage/reception/store.go
+++ b/storage/reception/store.go
@@ -10,6 +10,7 @@ import (
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
 	"io"
 	"strconv"
 	"sync"
@@ -133,7 +134,7 @@ func (s *Store) save() error {
 	// Create versioned object with data
 	obj := &versioned.Object{
 		Version:   receptionStoreStorageVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      data,
 	}
 
@@ -169,7 +170,7 @@ func (s *Store) GetIdentity(rng io.Reader) (IdentityUse, error) {
 	s.mux.Lock()
 	defer s.mux.Unlock()
 
-	now := time.Now()
+	now := netTime.Now()
 
 	// Remove any now expired identities
 	s.prune(now)
@@ -307,7 +308,7 @@ func (s *Store) UpdateIdSize(idSize uint) {
 	// Store the ID size
 	obj := &versioned.Object{
 		Version:   receptionIDSizeStorageVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte(strconv.Itoa(s.idSize)),
 	}
 
@@ -379,6 +380,7 @@ func (s *Store) selectIdentity(rng io.Reader, now time.Time) (IdentityUse, error
 	return IdentityUse{
 		Identity: selected.Identity,
 		Fake:     false,
-		UR:       selected.ur,
+		UR:       selected.UR,
+		ER:       selected.ER,
 	}, nil
 }
diff --git a/storage/reception/store_test.go b/storage/reception/store_test.go
index 7f5dcd089127db9939a205e2d8e6ea4733c65bf0..8779e8f54cedacd24ae9e4c892fb3b19c279b814 100644
--- a/storage/reception/store_test.go
+++ b/storage/reception/store_test.go
@@ -5,6 +5,7 @@ import (
 	"encoding/json"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"testing"
@@ -49,7 +50,7 @@ func TestLoadStore(t *testing.T) {
 
 	// Fill active registration with fake identities
 	for i := 0; i < 10; i++ {
-		testID, err := generateFakeIdentity(prng, 15, time.Now())
+		testID, err := generateFakeIdentity(prng, 15, netTime.Now())
 		if err != nil {
 			t.Fatalf("Failed to generate fake ID: %+v", err)
 		}
@@ -66,7 +67,6 @@ func TestLoadStore(t *testing.T) {
 
 	testStore := LoadStore(kv)
 	for i, active := range testStore.active {
-		s.active[i].ur = nil
 		if !s.active[i].Equal(active.Identity) {
 			t.Errorf("Failed to generate expected Store."+
 				"\nexpected: %#v\nreceived: %#v", s.active[i], active)
@@ -81,7 +81,7 @@ func TestStore_save(t *testing.T) {
 
 	// Fill active registration with fake identities
 	for i := 0; i < 10; i++ {
-		testID, err := generateFakeIdentity(prng, 15, time.Now())
+		testID, err := generateFakeIdentity(prng, 15, netTime.Now())
 		if err != nil {
 			t.Fatalf("Failed to generate fake ID: %+v", err)
 		}
@@ -120,7 +120,7 @@ func TestStore_makeStoredReferences(t *testing.T) {
 
 	// Fill active registration with fake identities
 	for i := 0; i < 10; i++ {
-		testID, err := generateFakeIdentity(prng, 15, time.Now())
+		testID, err := generateFakeIdentity(prng, 15, netTime.Now())
 		if err != nil {
 			t.Fatalf("Failed to generate fake ID: %+v", err)
 		}
@@ -146,7 +146,7 @@ func TestStore_GetIdentity(t *testing.T) {
 	kv := versioned.NewKV(make(ekv.Memstore))
 	s := NewStore(kv)
 	prng := rand.New(rand.NewSource(42))
-	testID, err := generateFakeIdentity(prng, 15, time.Now())
+	testID, err := generateFakeIdentity(prng, 15, netTime.Now())
 	if err != nil {
 		t.Fatalf("Failed to generate fake ID: %+v", err)
 	}
@@ -169,7 +169,7 @@ func TestStore_AddIdentity(t *testing.T) {
 	kv := versioned.NewKV(make(ekv.Memstore))
 	s := NewStore(kv)
 	prng := rand.New(rand.NewSource(42))
-	testID, err := generateFakeIdentity(prng, 15, time.Now())
+	testID, err := generateFakeIdentity(prng, 15, netTime.Now())
 	if err != nil {
 		t.Fatalf("Failed to generate fake ID: %+v", err)
 	}
@@ -189,7 +189,7 @@ func TestStore_RemoveIdentity(t *testing.T) {
 	kv := versioned.NewKV(make(ekv.Memstore))
 	s := NewStore(kv)
 	prng := rand.New(rand.NewSource(42))
-	testID, err := generateFakeIdentity(prng, 15, time.Now())
+	testID, err := generateFakeIdentity(prng, 15, netTime.Now())
 	if err != nil {
 		t.Fatalf("Failed to generate fake ID: %+v", err)
 	}
@@ -225,7 +225,7 @@ func TestStore_prune(t *testing.T) {
 	expected := make([]*registration, runs/2)
 
 	for i := 0; i < runs; i++ {
-		timestamp := time.Now()
+		timestamp := netTime.Now()
 		if i%2 == 0 {
 			timestamp = timestamp.Add(24 * time.Hour)
 		}
@@ -242,7 +242,7 @@ func TestStore_prune(t *testing.T) {
 		}
 	}
 
-	s.prune(time.Now().Add(24 * time.Hour))
+	s.prune(netTime.Now().Add(24 * time.Hour))
 
 	for i, reg := range s.active {
 		if !reg.Equal(expected[i].Identity) {
@@ -260,7 +260,7 @@ func TestStore_selectIdentity(t *testing.T) {
 	expectedReg := make([]*registration, runs)
 
 	for i := 0; i < runs; i++ {
-		testID, err := generateFakeIdentity(prng, 15, time.Now())
+		testID, err := generateFakeIdentity(prng, 15, netTime.Now())
 		if err != nil {
 			t.Fatalf("Failed to generate fake ID: %+v", err)
 		}
@@ -272,7 +272,7 @@ func TestStore_selectIdentity(t *testing.T) {
 	}
 
 	for i := 0; i < runs; i++ {
-		idu, err := s.selectIdentity(prng, time.Now())
+		idu, err := s.selectIdentity(prng, netTime.Now())
 		if err != nil {
 			t.Errorf("selectIdentity() produced an error: %+v", err)
 		}
diff --git a/storage/reception/unknownRound.go b/storage/reception/unknownRound.go
deleted file mode 100644
index 94feb079bf41ad2b770fa9688cf56267612a4e9a..0000000000000000000000000000000000000000
--- a/storage/reception/unknownRound.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package reception
-
-import (
-	"encoding/json"
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/storage/versioned"
-	"gitlab.com/xx_network/primitives/id"
-	"sync"
-	"time"
-)
-
-const unknownRoundStorageKey = "unknownRoundStorage"
-const unknownRoundStorageVersion = 0
-
-type UnknownRound struct {
-	stored bool
-	kv     *versioned.KV
-	rid    id.Round
-	mux    sync.Mutex
-}
-
-func NewUnknownRound(stored bool, kv *versioned.KV) *UnknownRound {
-	ur := &UnknownRound{
-		stored: stored,
-		kv:     kv,
-		rid:    0,
-	}
-	ur.save()
-	return ur
-}
-
-func LoadUnknownRound(kv *versioned.KV) *UnknownRound {
-	ur := &UnknownRound{
-		stored: true,
-		kv:     kv,
-		rid:    0,
-	}
-
-	obj, err := kv.Get(unknownRoundStorageKey, unknownRoundStorageVersion)
-	if err != nil {
-		jww.FATAL.Panicf("Failed to get the unknown round: %+v", err)
-	}
-
-	err = json.Unmarshal(obj.Data, &ur.rid)
-	if err != nil {
-		jww.FATAL.Panicf("Failed to unmarshal the unknown round: %+v", err)
-	}
-	return ur
-}
-
-func (ur *UnknownRound) save() {
-	if ur.stored {
-		urStr, err := json.Marshal(&ur.rid)
-		if err != nil {
-			jww.FATAL.Panicf("Failed to marshal the unknown round: %+v", err)
-		}
-
-		// Create versioned object with data
-		obj := &versioned.Object{
-			Version:   unknownRoundStorageVersion,
-			Timestamp: time.Now(),
-			Data:      urStr,
-		}
-
-		err = ur.kv.Set(unknownRoundStorageKey,
-			unknownRoundStorageVersion, obj)
-		if err != nil {
-			jww.FATAL.Panicf("Failed to store the unknown round: %+v", err)
-		}
-
-	}
-}
-
-func (ur *UnknownRound) Set(rid id.Round) id.Round {
-	ur.mux.Lock()
-	defer ur.mux.Unlock()
-	if rid > ur.rid {
-		ur.rid = rid
-		ur.save()
-	}
-	return ur.rid
-}
-
-func (ur *UnknownRound) Get() id.Round {
-	ur.mux.Lock()
-	defer ur.mux.Unlock()
-	return ur.rid
-}
-
-func (ur *UnknownRound) delete() {
-	ur.mux.Lock()
-	defer ur.mux.Unlock()
-	err := ur.kv.Delete(unknownRoundStorageKey, unknownRoundStorageVersion)
-	if err != nil {
-		jww.FATAL.Panicf("Failed to delete unknownRound storage: %+v", err)
-	}
-}
diff --git a/storage/regCode.go b/storage/regCode.go
index 8e9533395ede948ca495b6660e8d9c4a17cdb212..da0a306d78537f1baee90e193230146f4053753d 100644
--- a/storage/regCode.go
+++ b/storage/regCode.go
@@ -11,7 +11,7 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const regCodeKey = "regCode"
@@ -23,7 +23,7 @@ func (s *Session) SetRegCode(regCode string) {
 		&versioned.Object{
 			Version:   regCodeVersion,
 			Data:      []byte(regCode),
-			Timestamp: time.Now(),
+			Timestamp: netTime.Now(),
 		}); err != nil {
 		jww.FATAL.Panicf("Failed to set the registration code: %s", err)
 	}
diff --git a/storage/regStatus.go b/storage/regStatus.go
index ec18a0cfcb92aaa9c154f23528a40a96f202273f..dfb2619c810920269be39c91b2aa642bcba002ab 100644
--- a/storage/regStatus.go
+++ b/storage/regStatus.go
@@ -12,7 +12,7 @@ import (
 	"fmt"
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/storage/versioned"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentRegistrationStatusVersion = 0
@@ -59,7 +59,7 @@ func (rs RegistrationStatus) marshalBinary() []byte {
 func (s *Session) newRegStatus() error {
 	s.regStatus = NotStarted
 
-	now := time.Now()
+	now := netTime.Now()
 
 	obj := versioned.Object{
 		Version:   currentRegistrationStatusVersion,
@@ -98,7 +98,7 @@ func (s *Session) ForwardRegistrationStatus(regStatus RegistrationStatus) error
 			s.regStatus, regStatus)
 	}
 
-	now := time.Now()
+	now := netTime.Now()
 
 	obj := versioned.Object{
 		Version:   currentRegistrationStatusVersion,
diff --git a/storage/rounds/earliestRound.go b/storage/rounds/earliestRound.go
new file mode 100644
index 0000000000000000000000000000000000000000..456e11c146e1998e45c3e9b814d5f718ddf99807
--- /dev/null
+++ b/storage/rounds/earliestRound.go
@@ -0,0 +1,99 @@
+package rounds
+
+import (
+	"encoding/json"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+	"sync"
+)
+
+const earliestRoundStorageKey = "unknownRoundStorage"
+const earliestRoundStorageVersion = 0
+
+type EarliestRound struct {
+	stored bool
+	kv     *versioned.KV
+	rid    id.Round
+	mux    sync.Mutex
+}
+
+func NewEarliestRound(stored bool, kv *versioned.KV) *EarliestRound {
+	ur := &EarliestRound{
+		stored: stored,
+		kv:     kv,
+		rid:    0,
+	}
+	ur.save()
+	return ur
+}
+
+func LoadEarliestRound(kv *versioned.KV) *EarliestRound {
+	ur := &EarliestRound{
+		stored: true,
+		kv:     kv,
+		rid:    0,
+	}
+
+	obj, err := kv.Get(earliestRoundStorageKey, earliestRoundStorageVersion)
+	if err != nil {
+		jww.FATAL.Panicf("Failed to get the earlest round: %+v", err)
+	}
+
+	err = json.Unmarshal(obj.Data, &ur.rid)
+	if err != nil {
+		jww.FATAL.Panicf("Failed to unmarshal the earliest round: %+v", err)
+	}
+	return ur
+}
+
+func (ur *EarliestRound) save() {
+	if ur.stored {
+		urStr, err := json.Marshal(&ur.rid)
+		if err != nil {
+			jww.FATAL.Panicf("Failed to marshal the earliest round: %+v", err)
+		}
+
+		// Create versioned object with data
+		obj := &versioned.Object{
+			Version:   earliestRoundStorageVersion,
+			Timestamp: netTime.Now(),
+			Data:      urStr,
+		}
+
+		err = ur.kv.Set(earliestRoundStorageKey,
+			earliestRoundStorageVersion, obj)
+		if err != nil {
+			jww.FATAL.Panicf("Failed to store the earliest round: %+v", err)
+		}
+
+	}
+}
+
+func (ur *EarliestRound) Set(rid id.Round) (id.Round, bool) {
+	ur.mux.Lock()
+	defer ur.mux.Unlock()
+	changed := false
+	if rid > ur.rid {
+		changed = true
+		ur.rid = rid
+		ur.save()
+	}
+	return ur.rid, changed
+}
+
+func (ur *EarliestRound) Get() id.Round {
+	ur.mux.Lock()
+	defer ur.mux.Unlock()
+	return ur.rid
+}
+
+func (ur *EarliestRound) delete() {
+	ur.mux.Lock()
+	defer ur.mux.Unlock()
+	err := ur.kv.Delete(earliestRoundStorageKey, earliestRoundStorageVersion)
+	if err != nil {
+		jww.FATAL.Panicf("Failed to delete earliest storage: %+v", err)
+	}
+}
diff --git a/storage/rounds/unknownRounds.go b/storage/rounds/unknownRounds.go
new file mode 100644
index 0000000000000000000000000000000000000000..3711b8787f530633a360bb91ab7911d9f8cc6830
--- /dev/null
+++ b/storage/rounds/unknownRounds.go
@@ -0,0 +1,199 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package rounds
+
+import (
+	"encoding/json"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+	"sync"
+	"sync/atomic"
+)
+
+const (
+	unknownRoundsStorageKey     = "UnknownRoundsKey"
+	unknownRoundsStorageVersion = 0
+	unknownRoundPrefix          = "UnknownRoundPrefix"
+	defaultMaxCheck             = 3
+)
+
+// UnknownRounds tracks data for unknown rounds
+// Should adhere to UnknownRounds interface
+type UnknownRounds struct {
+	// Maps an unknown round to how many times the round
+	// has been checked
+	rounds map[id.Round]*uint64
+	// Configurations of UnknownRoundStore
+	params UnknownRoundsParams
+
+	// Key Value store to save data to disk
+	kv *versioned.KV
+
+	mux sync.Mutex
+}
+
+// Allows configuration of UnknownRounds parameters
+type UnknownRoundsParams struct {
+	// Maximum amount of checks of a round
+	// before that round gets discarded
+	MaxChecks uint64
+	//Determines if the unknown rounds is stored to disk
+	Stored bool
+}
+
+// Returns a default set of UnknownRoundsParams
+func DefaultUnknownRoundsParams() UnknownRoundsParams {
+	return UnknownRoundsParams{
+		MaxChecks: defaultMaxCheck,
+		Stored:    true,
+	}
+}
+
+// Build and return new UnknownRounds object
+func NewUnknownRounds(kv *versioned.KV,
+	params UnknownRoundsParams) *UnknownRounds {
+
+	urs := newUnknownRounds(kv, params)
+
+	if err := urs.save(); err != nil {
+		jww.FATAL.Printf("Failed to store New Unknown Rounds: %+v", err)
+	}
+
+	return urs
+}
+
+func newUnknownRounds(kv *versioned.KV,
+	params UnknownRoundsParams) *UnknownRounds {
+	// Build the UnmixedMessagesMap
+	// Modify the prefix of the KV
+	kv = kv.Prefix(unknownRoundPrefix)
+
+	urs := &UnknownRounds{
+		rounds: make(map[id.Round]*uint64),
+		params: params,
+		kv:     kv,
+	}
+
+	return urs
+}
+
+// LoadUnknownRounds loads the data for a UnknownRoundStore from disk into an object
+func LoadUnknownRounds(kv *versioned.KV,
+	params UnknownRoundsParams) *UnknownRounds {
+	kv = kv.Prefix(unknownRoundPrefix)
+
+	urs := newUnknownRounds(kv, params)
+
+	// Get the versioned data from the kv
+	obj, err := kv.Get(unknownRoundsStorageKey, unknownRoundsStorageVersion)
+	if err != nil {
+		jww.FATAL.Panicf("Failed to load UnknownRounds: %+v", err)
+	}
+
+	// Process the data into the object
+	err = urs.unmarshal(obj.Data)
+	if err != nil {
+		jww.FATAL.Panicf("Failed to unmarshal UnknownRounds: %+v", err)
+	}
+
+	return urs
+}
+
+// Iterate iterates over all rounds. First it runs the
+// checker function on the stored rounds:
+// If true, it removes from the map and adds to the return slice
+// If false, it increments the counter and if it has passed the maxChecks
+// in params, it removes from the map
+// Afterwards it adds the roundToAdd to the map if an entry isn't present
+// Finally it saves the modified map to disk.
+func (urs *UnknownRounds) Iterate(checker func(rid id.Round) bool,
+	roundsToAdd []id.Round) []id.Round {
+	returnSlice := make([]id.Round, 0)
+	urs.mux.Lock()
+	defer urs.mux.Unlock()
+	// Check the rounds stored
+	for rnd := range urs.rounds {
+		ok := checker(rnd)
+		if ok {
+			// If true, Append to the return list and remove from the map
+			returnSlice = append(returnSlice, rnd)
+			delete(urs.rounds, rnd)
+		} else {
+			// If false, we increment the check counter for that round
+			totalChecks := atomic.AddUint64(urs.rounds[rnd], 1)
+
+			// If the round has been checked the maximum amount,
+			// the rond is removed from the map
+			if totalChecks > urs.params.MaxChecks {
+				delete(urs.rounds, rnd)
+			}
+		}
+
+	}
+
+	// Iterate over all rounds passed in
+	for _, rnd := range roundsToAdd {
+		// Process non-tracked rounds into map
+		if _, ok := urs.rounds[rnd]; !ok {
+			newCheck := uint64(0)
+			urs.rounds[rnd] = &newCheck
+		}
+	}
+
+	if err := urs.save(); err != nil {
+		jww.FATAL.Panicf("Failed to save unknown reounds after "+
+			"edit: %+v", err)
+	}
+
+	return returnSlice
+}
+
+// save stores the unknown rounds store.
+func (urs *UnknownRounds) save() error {
+	if !urs.params.Stored {
+		return nil
+	}
+	now := netTime.Now()
+
+	// Serialize the map
+	data, err := json.Marshal(urs.rounds)
+	if err != nil {
+		return err
+	}
+
+	// Construct versioning object
+	obj := versioned.Object{
+		Version:   unknownRoundsStorageVersion,
+		Timestamp: now,
+		Data:      data,
+	}
+
+	// Save to disk
+	return urs.kv.Set(unknownRoundsStorageKey, unknownRoundsStorageVersion, &obj)
+}
+
+// save stores the unknown rounds store.
+func (urs *UnknownRounds) Delete() {
+	urs.mux.Lock()
+	defer urs.mux.Unlock()
+	if urs.params.Stored {
+		if err := urs.kv.Delete(unknownRoundPrefix, unknownRoundsStorageVersion); err != nil {
+			jww.FATAL.Panicf("Failed to delete unknown rounds: %+v", err)
+		}
+	}
+
+	urs.kv = nil
+	urs.rounds = nil
+}
+
+// unmarshal loads the serialized round data into the UnknownRounds map
+func (urs *UnknownRounds) unmarshal(b []byte) error {
+	return json.Unmarshal(b, &urs.rounds)
+}
diff --git a/storage/rounds/unknownRounds_test.go b/storage/rounds/unknownRounds_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ffc9bdd46a74060948a7a06d724cf2590d203da4
--- /dev/null
+++ b/storage/rounds/unknownRounds_test.go
@@ -0,0 +1,203 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package rounds
+
+import (
+	"bytes"
+	"encoding/json"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/id"
+	"reflect"
+	"sync/atomic"
+	"testing"
+)
+
+// Happy path
+func TestNewUnknownRoundsStore(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	expectedStore := &UnknownRounds{
+		rounds: make(map[id.Round]*uint64),
+		kv:     kv.Prefix(unknownRoundPrefix),
+		params: DefaultUnknownRoundsParams(),
+	}
+
+	store := NewUnknownRounds(kv,  DefaultUnknownRoundsParams())
+
+	// Compare manually created object with NewUnknownRoundsStore
+	if !reflect.DeepEqual(expectedStore, store) {
+		t.Errorf("NewUnknownRoundsStore() returned incorrect Store."+
+			"\n\texpected: %+v\n\treceived: %+v", expectedStore, store)
+	}
+
+	if err := store.save(); err != nil {
+		t.Fatalf("save() could not write to disk: %v", err)
+	}
+
+	expectedData, err := json.Marshal(store.rounds)
+	if err != nil {
+		t.Fatalf("json.Marshal() produced an error: %v", err)
+	}
+
+	key, err := store.kv.Get(unknownRoundsStorageKey, unknownRoundsStorageVersion)
+	if err != nil {
+		t.Fatalf("Get() encoutnered an error when getting Store from KV: %v", err)
+	}
+
+	// Check that the stored data is the data outputted by marshal
+	if !bytes.Equal(expectedData, key.Data) {
+		t.Errorf("NewUnknownRoundsStore() returned incorrect Store."+
+			"\n\texpected: %+v\n\treceived: %+v", expectedData, key.Data)
+	}
+
+}
+
+// Full test
+func TestUnknownRoundsStore_Iterate(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	store := NewUnknownRounds(kv,  DefaultUnknownRoundsParams())
+
+	// Return true only for rounds that are even
+	mockChecker := func(rid id.Round) bool {
+		return uint64(rid)%2 == 0
+	}
+
+	// Construct 3 lists of round IDs
+	roundListLen := 25
+	unknownRounds := make([]id.Round, roundListLen)
+	roundListEven := make([]id.Round, roundListLen)
+	for i := 0; i < roundListLen; i++ {
+		// Will contain a list of round Ids in range [0,25)
+		unknownRounds[i] = id.Round(i)
+		// Will contain even round Id's in range [50,100)
+		roundListEven[i] = id.Round((i + roundListLen) * 2)
+
+	}
+
+	// Add unknown rounds to map
+	for _, rnd := range unknownRounds {
+		roundVal := uint64(0)
+		store.rounds[rnd] = &roundVal
+	}
+
+	// Iterate over initial map
+	received := store.Iterate(mockChecker, nil)
+
+	// Check the received list for 2 conditions:
+	// a) that returned rounds are no longer in the map
+	// b) that returned round Ids are even (as per our checker)
+	for _, rnd := range received {
+		// Our returned list should contain only even rounds.
+		if uint64(rnd)%2 != 0 {
+			t.Errorf("Unexpected result from iterate(). "+
+				"Round %d should not be in received list", rnd)
+		}
+		// Elements in the returned list should be deleted from the map.
+		if _, ok := store.rounds[rnd]; ok {
+			t.Errorf("Returned rounds from iterate should be removed from map"+
+				"\n\tFound round %d in map", rnd)
+		}
+
+	}
+
+	// Add even round list to map
+	received = store.Iterate(mockChecker, roundListEven)
+
+	if len(received) != 0 {
+		t.Errorf("Second iteration should return an empty list (no even rounds are left)."+
+			"\n\tReturned: %v", received)
+	}
+
+	// Iterate over map until all rounds have checks incremented over
+	// maxCheck
+	for i := 0; i < defaultMaxCheck+1; i++ {
+		_ = store.Iterate(mockChecker,[]id.Round{})
+
+	}
+
+	// Check map has been cleared out
+	if len(store.rounds) != 0 {
+		t.Errorf("Map should be empty after %d iterations", defaultMaxCheck)
+	}
+}
+
+// Unit test
+func TestLoadUnknownRoundsStore(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	store := NewUnknownRounds(kv, DefaultUnknownRoundsParams())
+
+	// Construct 3 lists of round IDs
+	roundListLen := 25
+	expectedRounds := make([]id.Round, roundListLen)
+	for i := 0; i < roundListLen; i++ {
+		// Will contain a list of round Ids in range [0,25)
+		expectedRounds[i] = id.Round(i)
+
+	}
+
+	// Add unknown rounds to map
+	expectedCheckVal := 0
+	for _, rnd := range expectedRounds {
+		roundVal := uint64(expectedCheckVal)
+		store.rounds[rnd] = &roundVal
+	}
+
+	if err := store.save(); err != nil {
+		t.Fatalf("save produced an error: %v", err)
+	}
+
+	// Load the store from kv
+	receivedStore := LoadUnknownRounds(kv, DefaultUnknownRoundsParams())
+
+	// Check the state of the map of the loaded store
+	for _, rnd := range expectedRounds {
+		check, ok := receivedStore.rounds[rnd]
+		if !ok {
+			t.Fatalf("Expected round %d in loaded store", rnd)
+		}
+
+		if atomic.LoadUint64(check) != 0 {
+			t.Fatalf("Loaded value in map is unexpected."+
+				"\n\tExpected: %v"+
+				"\n\tReceived: %v", expectedCheckVal, atomic.LoadUint64(check))
+		}
+	}
+
+	/* Check save used in iterate call */
+
+	// Check that LoadStore works after iterate call (which implicitly saves)
+	mockChecker := func(round id.Round) bool { return false }
+	received := store.Iterate(mockChecker, nil)
+
+	// Iterate is being called as a dummy, should not return anything
+	if len(received) != 0 {
+		t.Fatalf("Returned list from iterate should not return any rounds."+
+			"\n\tReceived: %v", received)
+	}
+
+	// Increment check value (iterate will increment all rounds' checked value)
+	expectedCheckVal++
+
+	// Load the store from kv
+	receivedStore = LoadUnknownRounds(kv, DefaultUnknownRoundsParams())
+
+	// Check the state of the map of the loaded store
+	for _, rnd := range expectedRounds {
+		check, ok := receivedStore.rounds[rnd]
+		if !ok {
+			t.Fatalf("Expected round %d in loaded store", rnd)
+		}
+
+		if atomic.LoadUint64(check) != uint64(expectedCheckVal) {
+			t.Fatalf("Loaded value in map is unexpected."+
+				"\n\tExpected: %v"+
+				"\n\tReceived: %v", expectedCheckVal, atomic.LoadUint64(check))
+		}
+	}
+
+}
diff --git a/storage/session.go b/storage/session.go
index be1837de7fb32adf9d13549c8f42bfe00683c05f..608068472b49517922d6a84a8a57d90f9dc0054f 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -363,5 +363,6 @@ func InitTestingSession(i interface{}) *Session {
 	s.partition = partition.New(s.kv)
 
 	s.reception = reception.NewStore(s.kv)
+
 	return s
 }
diff --git a/storage/session_test.go b/storage/session_test.go
index 7b0d5ebc78c3f888d800d0506169f65a64c289f4..73fe66a252cabc444a9c6c325f9c582dff7d1705 100644
--- a/storage/session_test.go
+++ b/storage/session_test.go
@@ -27,7 +27,7 @@ func TestSession_Smoke(t *testing.T) {
 
 	err := s.Set("testkey", &versioned.Object{
 		Version:   0,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte("test"),
 	})
 	if err != nil {
diff --git a/storage/user/cryptographic.go b/storage/user/cryptographic.go
index c01b6ffa1bc1e835f2cae169f678de566b572778..592fc9c2322d3f8552d3e0ebc5f721cd292ed384 100644
--- a/storage/user/cryptographic.go
+++ b/storage/user/cryptographic.go
@@ -15,7 +15,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentCryptographicIdentityVersion = 0
@@ -112,7 +112,7 @@ func (ci *CryptographicIdentity) save(kv *versioned.KV) error {
 
 	obj := &versioned.Object{
 		Version:   currentCryptographicIdentityVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      userDataBuffer.Bytes(),
 	}
 
diff --git a/storage/user/regValidationSig.go b/storage/user/regValidationSig.go
index 4b5e09957e1597c899628fcecc58b0913afb575a..7440500fc680e2aee821ac761f47c8d9b201f40a 100644
--- a/storage/user/regValidationSig.go
+++ b/storage/user/regValidationSig.go
@@ -10,7 +10,7 @@ package user
 import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentRegValidationSigVersion = 0
@@ -68,7 +68,7 @@ func (u *User) SetTransmissionRegistrationValidationSignature(b []byte) {
 
 	obj := &versioned.Object{
 		Version:   currentRegValidationSigVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      b,
 	}
 
@@ -95,7 +95,7 @@ func (u *User) SetReceptionRegistrationValidationSignature(b []byte) {
 
 	obj := &versioned.Object{
 		Version:   currentRegValidationSigVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      b,
 	}
 
diff --git a/storage/user/regValidationSig_test.go b/storage/user/regValidationSig_test.go
index c824ad8891075f71a7d9bbd5e90ab1ac91bb1263..68a69f60c8a8dca24161a4ec8bc9721d096aa6a9 100644
--- a/storage/user/regValidationSig_test.go
+++ b/storage/user/regValidationSig_test.go
@@ -13,8 +13,8 @@ import (
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"testing"
-	"time"
 )
 
 // Test User GetRegistrationValidationSignature function
@@ -109,7 +109,7 @@ func TestUser_loadRegistrationValidationSignature(t *testing.T) {
 	err = kv.Set(transmissionRegValidationSigKey,
 		currentRegValidationSigVersion, &versioned.Object{
 			Version:   currentRegValidationSigVersion,
-			Timestamp: time.Now(),
+			Timestamp: netTime.Now(),
 			Data:      sig,
 		})
 	if err != nil {
@@ -125,7 +125,7 @@ func TestUser_loadRegistrationValidationSignature(t *testing.T) {
 	err = kv.Set(receptionRegValidationSigKey,
 		currentRegValidationSigVersion, &versioned.Object{
 			Version:   currentRegValidationSigVersion,
-			Timestamp: time.Now(),
+			Timestamp: netTime.Now(),
 			Data:      sig,
 		})
 	if err != nil {
diff --git a/storage/user/username.go b/storage/user/username.go
index 268025e2ea728645a3124165c0cd30f368a93942..c36e0eba99883f5d735d4aeb2e557848f8ff4180 100644
--- a/storage/user/username.go
+++ b/storage/user/username.go
@@ -11,7 +11,7 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentUsernameVersion = 0
@@ -35,7 +35,7 @@ func (u *User) SetUsername(username string) error {
 
 	obj := &versioned.Object{
 		Version:   currentUsernameVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte(username),
 	}
 
diff --git a/storage/user/username_test.go b/storage/user/username_test.go
index 1da1ce0eb9dc96a8d85b965bbdb867bdc36846fe..7571d3804136b560f5730b76d69b5672cd6d5c48 100644
--- a/storage/user/username_test.go
+++ b/storage/user/username_test.go
@@ -12,8 +12,8 @@ import (
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"testing"
-	"time"
 )
 
 // Test normal function and errors for User's SetUsername function
@@ -94,7 +94,7 @@ func TestUser_loadUsername(t *testing.T) {
 
 	err = u.kv.Set(usernameKey, currentUsernameVersion, &versioned.Object{
 		Version:   currentUsernameVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte(u1),
 	})
 	u.loadUsername()
diff --git a/storage/utility/NDF.go b/storage/utility/NDF.go
index 728ec90c9fcf12db993e25b5566203c98783dbf4..e4e6281b26ed92c6466a8afaa9cbec7375ed5107 100644
--- a/storage/utility/NDF.go
+++ b/storage/utility/NDF.go
@@ -10,7 +10,7 @@ package utility
 import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/ndf"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentNDFVersion = 0
@@ -35,7 +35,7 @@ func SaveNDF(kv *versioned.KV, key string, ndf *ndf.NetworkDefinition) error {
 		return err
 	}
 
-	now := time.Now()
+	now := netTime.Now()
 
 	obj := versioned.Object{
 		Version:   currentNDFVersion,
diff --git a/storage/utility/cmixMessageBuffer.go b/storage/utility/cmixMessageBuffer.go
index 367d4fd534bad871472590ecf5ecf4fd7c017f95..6091c65bc59ee0836384d4a475a15f8c8f7a940e 100644
--- a/storage/utility/cmixMessageBuffer.go
+++ b/storage/utility/cmixMessageBuffer.go
@@ -15,7 +15,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentCmixMessageVersion = 0
@@ -45,7 +45,7 @@ func (cmh *cmixMessageHandler) SaveMessage(kv *versioned.KV, m interface{}, key
 	// Create versioned object
 	obj := versioned.Object{
 		Version:   currentCmixMessageVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      sm.Marshal(),
 	}
 
diff --git a/storage/utility/cmixMessageBuffer_test.go b/storage/utility/cmixMessageBuffer_test.go
index f884d73d78629dbc51e88ce5443dfee8f3bde66e..b015cb2c66f028be8472b3281603f0b9e026b335 100644
--- a/storage/utility/cmixMessageBuffer_test.go
+++ b/storage/utility/cmixMessageBuffer_test.go
@@ -13,10 +13,10 @@ import (
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"testing"
-	"time"
 )
 
 // Test happy path of cmixMessageHandler.SaveMessage().
@@ -159,7 +159,7 @@ func TestCmixMessageBuffer_Smoke(t *testing.T) {
 // expected map after they are added to the buffer.
 func makeTestCmixMessages(n int) ([]format.Message, []*id.ID, map[MessageHash]struct{}) {
 	cmh := &cmixMessageHandler{}
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	mh := map[MessageHash]struct{}{}
 	msgs := make([]format.Message, n)
 	ids := make([]*id.ID, n)
diff --git a/storage/utility/contact.go b/storage/utility/contact.go
index cef79e2ffc8748798908cfcedd87a3e96c0c0e7e..cccfef3483c47fc83579563e29b18e0578a17610 100644
--- a/storage/utility/contact.go
+++ b/storage/utility/contact.go
@@ -9,16 +9,16 @@ package utility
 
 import (
 	"fmt"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentContactVersion = 0
 
 func StoreContact(kv *versioned.KV, c contact.Contact) error {
-	now := time.Now()
+	now := netTime.Now()
 
 	obj := versioned.Object{
 		Version:   currentContactVersion,
diff --git a/storage/utility/dh.go b/storage/utility/dh.go
index ea2f6296d1289378189c4e4d85e6c344b9715aa1..9b0280ed1ef4bd96e71d15fcc788b5633c51fe03 100644
--- a/storage/utility/dh.go
+++ b/storage/utility/dh.go
@@ -10,13 +10,13 @@ package utility
 import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentCyclicVersion = 0
 
 func StoreCyclicKey(kv *versioned.KV, cy *cyclic.Int, key string) error {
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := cy.GobEncode()
 	if err != nil {
diff --git a/storage/utility/e2eMessageBuffer.go b/storage/utility/e2eMessageBuffer.go
index 9f0d3f417e6fd9c84e66c71dc324d13df31cf0ac..b8de8f65d3219f662df87680d174aec47743b97f 100644
--- a/storage/utility/e2eMessageBuffer.go
+++ b/storage/utility/e2eMessageBuffer.go
@@ -16,8 +16,7 @@ import (
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
-
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentE2EMessageVersion = 0
@@ -44,7 +43,7 @@ func (emh *e2eMessageHandler) SaveMessage(kv *versioned.KV, m interface{}, key s
 	// Create versioned object
 	obj := versioned.Object{
 		Version:   currentE2EMessageVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      b,
 	}
 
diff --git a/storage/utility/e2eMessageBuffer_test.go b/storage/utility/e2eMessageBuffer_test.go
index aa7366ced5e5964fc666b67b3015f34a46433d4c..0aca79126fe53903957780f298e26ae1434597db 100644
--- a/storage/utility/e2eMessageBuffer_test.go
+++ b/storage/utility/e2eMessageBuffer_test.go
@@ -14,10 +14,10 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"reflect"
 	"testing"
-	"time"
 )
 
 // Test happy path of e2eMessageHandler.SaveMessage().
@@ -155,7 +155,7 @@ func TestE2EMessageHandler_Smoke(t *testing.T) {
 // makeTestE2EMessages creates a list of messages with random data and the
 // expected map after they are added to the buffer.
 func makeTestE2EMessages(n int, t *testing.T) ([]e2eMessage, []message.Send) {
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	msgs := make([]e2eMessage, n)
 	send := make([]message.Send, n)
 	for i := range msgs {
diff --git a/storage/utility/group.go b/storage/utility/group.go
index 20a05e8378fde158a0ec6b1b6009a6f9f68ebc55..2b2e40678cbdd7f7f004ce86a15965c346d7e042 100644
--- a/storage/utility/group.go
+++ b/storage/utility/group.go
@@ -10,13 +10,13 @@ package utility
 import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"time"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
 const currentGroupVersion = 0
 
 func StoreGroup(kv *versioned.KV, grp *cyclic.Group, key string) error {
-	now := time.Now()
+	now := netTime.Now()
 
 	data, err := grp.GobEncode()
 	if err != nil {
diff --git a/storage/utility/knownRounds.go b/storage/utility/knownRounds.go
index 5b57c29484b91570abd93d7149ed0e91ccd9e651..85203145b7fead0131b3c861539c2c89cabd475b 100644
--- a/storage/utility/knownRounds.go
+++ b/storage/utility/knownRounds.go
@@ -61,7 +61,7 @@ func LoadKnownRounds(kv *versioned.KV, key string, size int) (*KnownRounds, erro
 
 // save saves the round buffer as a versioned object to the key value store.
 func (kr *KnownRounds) save() error {
-	now := time.Now()
+	now := netTime.Now()
 
 	// Marshal list of rounds
 	data, err := kr.rounds.Marshal()
diff --git a/storage/utility/messageBuffer.go b/storage/utility/messageBuffer.go
index 59743c855072ec9343ecd6460c4e1044af2d45f5..31af9f7f2a9b472873d476a686321a33145b2b42 100644
--- a/storage/utility/messageBuffer.go
+++ b/storage/utility/messageBuffer.go
@@ -8,12 +8,13 @@
 package utility
 
 import (
+	"encoding/base64"
 	"encoding/json"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
-	"time"
 )
 
 // MessageHash stores the hash of a message, which is used as the key for each
@@ -105,7 +106,7 @@ func LoadMessageBuffer(kv *versioned.KV, handler MessageHandler,
 // are in the "not processed" or "processing" state are stored together and
 // considered "not processed".
 func (mb *MessageBuffer) save() error {
-	now := time.Now()
+	now := netTime.Now()
 
 	// Build a combined list of message hashes in messages + processingMessages
 	allMessages := mb.getMessageList()
@@ -207,6 +208,8 @@ func (mb *MessageBuffer) Add(m interface{}) {
 // Add adds a message to the buffer in "processing" state.
 func (mb *MessageBuffer) AddProcessing(m interface{}) {
 	h := mb.handler.HashMessage(m)
+	jww.TRACE.Printf("Critical Messages AddProcessing(%s)",
+		base64.StdEncoding.EncodeToString(h[:]))
 
 	mb.mux.Lock()
 	defer mb.mux.Unlock()
@@ -247,6 +250,9 @@ func (mb *MessageBuffer) Next() (interface{}, bool) {
 
 	// Pop the next MessageHash from the "not processing" list
 	h := next(mb.messages)
+	jww.TRACE.Printf("Critical Messages Next returned %s",
+		base64.StdEncoding.EncodeToString(h[:]))
+
 	delete(mb.messages, h)
 
 	// Add message to list of processing messages
@@ -272,6 +278,8 @@ func next(msgMap map[MessageHash]struct{}) MessageHash {
 // Remove sets a messaged as processed and removed it from the buffer.
 func (mb *MessageBuffer) Succeeded(m interface{}) {
 	h := mb.handler.HashMessage(m)
+	jww.TRACE.Printf("Critical Messages Succeeded(%s)",
+		base64.StdEncoding.EncodeToString((h[:])))
 
 	mb.mux.Lock()
 	defer mb.mux.Unlock()
@@ -297,6 +305,8 @@ func (mb *MessageBuffer) Succeeded(m interface{}) {
 // the "not processed" state.
 func (mb *MessageBuffer) Failed(m interface{}) {
 	h := mb.handler.HashMessage(m)
+	jww.TRACE.Printf("Critical Messages Failed(%s)",
+		base64.StdEncoding.EncodeToString(h[:]))
 
 	mb.mux.Lock()
 	defer mb.mux.Unlock()
diff --git a/storage/utility/messageBuffer_test.go b/storage/utility/messageBuffer_test.go
index f331078fd5429a81c317620caf28802932617ba6..fc4de8be8dd5573520d02c9a35fae07593bb6a90 100644
--- a/storage/utility/messageBuffer_test.go
+++ b/storage/utility/messageBuffer_test.go
@@ -13,11 +13,11 @@ import (
 	"encoding/json"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"os"
 	"reflect"
 	"testing"
-	"time"
 )
 
 type testHandler struct {
@@ -294,7 +294,7 @@ func TestMessageBuffer_Failed(t *testing.T) {
 
 // addTestMessages adds random messages to the buffer.
 func addTestMessages(mb *MessageBuffer, n int) []MessageHash {
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	msgs := make([]MessageHash, n)
 	for i := 0; i < n; i++ {
 		keyData := make([]byte, 16)
@@ -337,7 +337,7 @@ func cmpMessageHash(arrA, arrB []MessageHash) bool {
 // makeTestMessages creates a list of messages with random data and the expected
 // map after they are added to the buffer.
 func makeTestMessages(n int) ([][]byte, map[MessageHash]struct{}) {
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	mh := map[MessageHash]struct{}{}
 	msgs := make([][]byte, n)
 	for i := range msgs {
diff --git a/storage/utility/meteredCmixMessageBuffer.go b/storage/utility/meteredCmixMessageBuffer.go
index e4b7ab4fbce6e5e97cf00c8fcadb0d130f13167e..719faa3883ebf6d47e5abf86931c3e9e1b8e0143 100644
--- a/storage/utility/meteredCmixMessageBuffer.go
+++ b/storage/utility/meteredCmixMessageBuffer.go
@@ -14,6 +14,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/primitives/netTime"
 	"time"
 )
 
@@ -40,7 +41,7 @@ func (*meteredCmixMessageHandler) SaveMessage(kv *versioned.KV, m interface{}, k
 	// Create versioned object
 	obj := versioned.Object{
 		Version:   currentMeteredCmixMessageVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      marshaled,
 	}
 
@@ -111,7 +112,7 @@ func (mcmb *MeteredCmixMessageBuffer) Add(m format.Message) {
 	msg := meteredCmixMessage{
 		M:         m.Marshal(),
 		Count:     0,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 	}
 	mcmb.mb.Add(msg)
 }
@@ -120,7 +121,7 @@ func (mcmb *MeteredCmixMessageBuffer) AddProcessing(m format.Message) {
 	msg := meteredCmixMessage{
 		M:         m.Marshal(),
 		Count:     0,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 	}
 	mcmb.mb.AddProcessing(msg)
 }
diff --git a/storage/utility/meteredCmixMessageBuffer_test.go b/storage/utility/meteredCmixMessageBuffer_test.go
index bd2edcd259cb1bff0b04068d6c5fa8600fb16d82..a8116a7235dd7f64c701d04d3e655bef2237bc5a 100644
--- a/storage/utility/meteredCmixMessageBuffer_test.go
+++ b/storage/utility/meteredCmixMessageBuffer_test.go
@@ -13,6 +13,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
 	"testing"
 	"time"
@@ -188,7 +189,7 @@ func Test_meteredCmixMessageHandler_Smoke(t *testing.T) {
 // expected map after they are added to the buffer.
 func makeTestMeteredCmixMessage(n int) ([]meteredCmixMessage, map[MessageHash]struct{}) {
 	mcmh := &meteredCmixMessageHandler{}
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	mh := map[MessageHash]struct{}{}
 	msgs := make([]meteredCmixMessage, n)
 	for i := range msgs {
@@ -207,7 +208,7 @@ func makeTestMeteredCmixMessage(n int) ([]meteredCmixMessage, map[MessageHash]st
 
 // makeTestFormatMessages creates a list of messages with random data.
 func makeTestFormatMessages(n int) []format.Message {
-	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
+	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
 	msgs := make([]format.Message, n)
 	for i := range msgs {
 		msgs[i] = format.NewMessage(128)
diff --git a/storage/versioned/kv_test.go b/storage/versioned/kv_test.go
index 58ec70ad4f77972a326d089df74263e7aeae80fb..393078152ab91f82045108c0eee3fa5f4706ed66 100644
--- a/storage/versioned/kv_test.go
+++ b/storage/versioned/kv_test.go
@@ -10,10 +10,9 @@ package versioned
 import (
 	"bytes"
 	"errors"
-	"testing"
-	"time"
-
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/netTime"
+	"testing"
 )
 
 // KV Get should call the Upgrade function when it's available
@@ -40,7 +39,7 @@ func TestVersionedKV_GetUpgrade(t *testing.T) {
 	key := vkv.GetFullKey("test", 0)
 	original := Object{
 		Version:   0,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte("not upgraded"),
 	}
 	originalSerialized := original.Marshal()
@@ -49,7 +48,7 @@ func TestVersionedKV_GetUpgrade(t *testing.T) {
 	upgrade := []Upgrade{func(oldObject *Object) (*Object, error) {
 		return &Object{
 			Version:   1,
-			Timestamp: time.Now(),
+			Timestamp: netTime.Now(),
 			Data:      []byte("this object was upgraded from v0 to v1"),
 		}, nil
 	}}
@@ -77,7 +76,7 @@ func TestVersionedKV_GetUpgrade_KeyNotFound(t *testing.T) {
 	upgrade := []Upgrade{func(oldObject *Object) (*Object, error) {
 		return &Object{
 			Version:   1,
-			Timestamp: time.Now(),
+			Timestamp: netTime.Now(),
 			Data:      []byte("this object was upgraded from v0 to v1"),
 		}, nil
 	}}
@@ -97,7 +96,7 @@ func TestVersionedKV_GetUpgrade_UpgradeReturnsError(t *testing.T) {
 	key := vkv.GetFullKey("test", 0)
 	original := Object{
 		Version:   0,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte("not upgraded"),
 	}
 	originalSerialized := original.Marshal()
@@ -125,7 +124,7 @@ func TestVersionedKV_Delete(t *testing.T) {
 	key := vkv.GetFullKey("test", 0)
 	original := Object{
 		Version:   0,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte("not upgraded"),
 	}
 	originalSerialized := original.Marshal()
@@ -151,7 +150,7 @@ func TestVersionedKV_Get(t *testing.T) {
 	key := vkv.GetFullKey("test", originalVersion)
 	original := Object{
 		Version:   originalVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte("not upgraded"),
 	}
 	originalSerialized := original.Marshal()
@@ -176,7 +175,7 @@ func TestVersionedKV_Set(t *testing.T) {
 	key := vkv.GetFullKey("test", originalVersion)
 	original := Object{
 		Version:   originalVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      []byte("not upgraded"),
 	}
 	err := vkv.Set("test", originalVersion, &original)
diff --git a/ud/lookup.go b/ud/lookup.go
index d7ce0fa69f2addc3bb09419f98ec60b3a6cc2985..e7bdb0da0c0ed10bc8ccaa15c79bc6b9c30b8a9e 100644
--- a/ud/lookup.go
+++ b/ud/lookup.go
@@ -5,7 +5,7 @@ import (
 	"github.com/golang/protobuf/proto"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/id"
 	"time"
 )
diff --git a/ud/lookup_test.go b/ud/lookup_test.go
index 413b85f9d0443411977557937dfd74cee8833d63..8bdb21a1ae0d347b8561da54a52d4c9dcf7bb33e 100644
--- a/ud/lookup_test.go
+++ b/ud/lookup_test.go
@@ -3,9 +3,9 @@ package ud
 import (
 	"github.com/golang/protobuf/proto"
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/stoppable"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
diff --git a/ud/manager.go b/ud/manager.go
index d38c5aa5b7f2490e75fc502dd89c131c2faad94a..842d8d353a6d05ab523db2f887c2036d169f976c 100644
--- a/ud/manager.go
+++ b/ud/manager.go
@@ -5,11 +5,11 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/api"
 	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/comms/client"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/comms/connect"
diff --git a/ud/registered.go b/ud/registered.go
index 8191f2667246b8936a098eac688c49d2c2ae2be5..d81e615894e6928f5e7a529cf10c2ca288f21e04 100644
--- a/ud/registered.go
+++ b/ud/registered.go
@@ -5,8 +5,8 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/netTime"
 	"sync/atomic"
-	"time"
 )
 
 const isRegisteredKey = "isRegisteredKey"
@@ -44,7 +44,7 @@ func (m *Manager) setRegistered() error {
 
 	obj := &versioned.Object{
 		Version:   isRegisteredVersion,
-		Timestamp: time.Now(),
+		Timestamp: netTime.Now(),
 		Data:      data,
 	}
 
diff --git a/ud/search.go b/ud/search.go
index 5367fe10c5d65b22814a799f6071584ffeca8e24..8624c778d1be0d6f8443b6fe0ca13153ac82c429 100644
--- a/ud/search.go
+++ b/ud/search.go
@@ -4,7 +4,7 @@ import (
 	"github.com/golang/protobuf/proto"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/factID"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
diff --git a/ud/search_test.go b/ud/search_test.go
index bbbb65c0d517f8abaa09df06628a5acecd663e27..ac14e1a63243fc4d0296768c23420cf1adc03f16 100644
--- a/ud/search_test.go
+++ b/ud/search_test.go
@@ -4,9 +4,9 @@ import (
 	"fmt"
 	"github.com/golang/protobuf/proto"
 	errors "github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/stoppable"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/factID"
 	"gitlab.com/elixxir/primitives/fact"