diff --git a/api/client.go b/api/client.go
index 257373d4c243e35ad4d7229a151cfbee8131d35d..3f4623c5af5179a02fc8ce368306c2f54974d0b4 100644
--- a/api/client.go
+++ b/api/client.go
@@ -25,7 +25,6 @@ import (
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/storage/user"
 	"gitlab.com/elixxir/comms/client"
-	cryptoBackup "gitlab.com/elixxir/crypto/backup"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/primitives/version"
@@ -74,18 +73,18 @@ func NewClient(ndfJSON, storageDir string, password []byte,
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 1024,
 		csprng.NewSystemRNG)
 
-	def, err := parseNDF(ndfJSON)
+	def, err := ParseNDF(ndfJSON)
 	if err != nil {
 		return err
 	}
 
-	cmixGrp, e2eGrp := decodeGroups(def)
+	cmixGrp, e2eGrp := DecodeGroups(def)
 	start := netTime.Now()
 	protoUser := createNewUser(rngStreamGen)
 	jww.DEBUG.Printf("PortableUserInfo generation took: %s",
 		netTime.Now().Sub(start))
 
-	_, err = checkVersionAndSetupStorage(def, storageDir, password,
+	_, err = CheckVersionAndSetupStorage(def, storageDir, password,
 		protoUser, cmixGrp, e2eGrp, registrationCode)
 	if err != nil {
 		return err
@@ -107,16 +106,16 @@ func NewVanityClient(ndfJSON, storageDir string, password []byte,
 		csprng.NewSystemRNG)
 	rngStream := rngStreamGen.GetStream()
 
-	def, err := parseNDF(ndfJSON)
+	def, err := ParseNDF(ndfJSON)
 	if err != nil {
 		return err
 	}
-	cmixGrp, e2eGrp := decodeGroups(def)
+	cmixGrp, e2eGrp := DecodeGroups(def)
 
 	protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp,
 		userIdPrefix)
 
-	_, err = checkVersionAndSetupStorage(def, storageDir, password,
+	_, err = CheckVersionAndSetupStorage(def, storageDir, password,
 		protoUser, cmixGrp, e2eGrp, registrationCode)
 	if err != nil {
 		return err
@@ -125,53 +124,6 @@ func NewVanityClient(ndfJSON, storageDir string, password []byte,
 	return nil
 }
 
-// NewClientFromBackup constructs a new Client from an encrypted
-// backup. The backup is decrypted using the backupPassphrase. On
-// success a successful client creation, the function will return a
-// JSON encoded list of the E2E partners contained in the backup and a
-// json-encoded string containing parameters stored in the backup
-func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword,
-	backupPassphrase []byte, backupFileContents []byte) ([]*id.ID,
-	string, error) {
-
-	backUp := &cryptoBackup.Backup{}
-	err := backUp.Decrypt(string(backupPassphrase), backupFileContents)
-	if err != nil {
-		return nil, "", errors.WithMessage(err,
-			"Failed to unmarshal decrypted client contents.")
-	}
-
-	usr := user.NewUserFromBackup(backUp)
-
-	def, err := parseNDF(ndfJSON)
-	if err != nil {
-		return nil, "", err
-	}
-
-	cmixGrp, e2eGrp := decodeGroups(def)
-
-	// Note we do not need registration here
-	storageSess, err := checkVersionAndSetupStorage(def, storageDir,
-		[]byte(sessionPassword), usr, cmixGrp, e2eGrp,
-		backUp.RegistrationCode)
-
-	storageSess.SetReceptionRegistrationValidationSignature(
-		backUp.ReceptionIdentity.RegistrarSignature)
-	storageSess.SetTransmissionRegistrationValidationSignature(
-		backUp.TransmissionIdentity.RegistrarSignature)
-	storageSess.SetRegistrationTimestamp(backUp.RegistrationTimestamp)
-
-	//move the registration state to indicate registered with
-	// registration on proto client
-	err = storageSess.ForwardRegistrationStatus(
-		storage.PermissioningComplete)
-	if err != nil {
-		return nil, "", err
-	}
-
-	return backUp.Contacts.Identities, backUp.JSONParams, nil
-}
-
 // OpenClient session, but don't connect to the network or log in
 func OpenClient(storageDir string, password []byte,
 	parameters Params) (*Client, error) {
@@ -224,12 +176,12 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password,
 	protoClientJSON []byte) error {
 	jww.INFO.Printf("NewProtoClient_Unsafe")
 
-	def, err := parseNDF(ndfJSON)
+	def, err := ParseNDF(ndfJSON)
 	if err != nil {
 		return err
 	}
 
-	cmixGrp, e2eGrp := decodeGroups(def)
+	cmixGrp, e2eGrp := DecodeGroups(def)
 
 	protoUser := &user.Proto{}
 	err = json.Unmarshal(protoClientJSON, protoUser)
@@ -239,7 +191,7 @@ func NewProtoClient_Unsafe(ndfJSON, storageDir string, password,
 
 	usr := user.NewUserFromProto(protoUser)
 
-	storageSess, err := checkVersionAndSetupStorage(def, storageDir,
+	storageSess, err := CheckVersionAndSetupStorage(def, storageDir,
 		password, usr, cmixGrp, e2eGrp, protoUser.RegCode)
 	if err != nil {
 		return err
@@ -325,7 +277,7 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
 	params Params) (*Client, error) {
 	jww.INFO.Printf("LoginWithNewBaseNDF_UNSAFE()")
 
-	def, err := parseNDF(newBaseNdf)
+	def, err := ParseNDF(newBaseNdf)
 	if err != nil {
 		return nil, err
 	}
@@ -370,7 +322,7 @@ func LoginWithProtoClient(storageDir string, password []byte,
 	params Params) (*Client, error) {
 	jww.INFO.Printf("LoginWithProtoClient()")
 
-	def, err := parseNDF(newBaseNdf)
+	def, err := ParseNDF(newBaseNdf)
 	if err != nil {
 		return nil, err
 	}
@@ -689,9 +641,9 @@ func (c *Client) GetPreferredBins(countryCode string) ([]string, error) {
 }
 
 // ----- Utility Functions -----
-// parseNDF parses the initial ndf string for the client. do not check the
+// ParseNDF parses the initial ndf string for the client. do not check the
 // signature, it is deprecated.
-func parseNDF(ndfString string) (*ndf.NetworkDefinition, error) {
+func ParseNDF(ndfString string) (*ndf.NetworkDefinition, error) {
 	if ndfString == "" {
 		return nil, errors.New("ndf file empty")
 	}
@@ -704,8 +656,8 @@ func parseNDF(ndfString string) (*ndf.NetworkDefinition, error) {
 	return netDef, nil
 }
 
-// decodeGroups returns the e2e and cmix groups from the ndf
-func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) {
+// DecodeGroups returns the e2e and cmix groups from the ndf
+func DecodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) {
 	largeIntBits := 16
 
 	//Generate the cmix group
@@ -720,10 +672,10 @@ func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) {
 	return cmixGrp, e2eGrp
 }
 
-// checkVersionAndSetupStorage is common code shared by NewClient,
+// 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,
+func CheckVersionAndSetupStorage(def *ndf.NetworkDefinition,
 	storageDir string, password []byte, protoUser user.Info,
 	cmixGrp, e2eGrp *cyclic.Group, registrationCode string) (
 	storage.Session, error) {
diff --git a/api/messenger/messenger.go b/api/messenger/messenger.go
index 901d458c602a25722257497865f4b6ecc0d29f1f..2677e6fbaf23270e7eb6fc6009266da1638eaade 100644
--- a/api/messenger/messenger.go
+++ b/api/messenger/messenger.go
@@ -69,11 +69,20 @@ func LoadOrInitE2e(client *api.Client) (e2e.Handler, error) {
 			//generate the key
 			var privkey *cyclic.Int
 			if client.GetStorage().IsPrecanned() {
-				precannedID := binary.BigEndian.Uint64(client.GetStorage().GetReceptionID()[:])
-				privkey = generatePrecanDHKeypair(uint(precannedID), client.GetStorage().GetE2EGroup())
+				jww.WARN.Printf("Using Precanned DH key")
+				precannedID := binary.BigEndian.Uint64(
+					client.GetStorage().GetReceptionID()[:])
+				privkey = generatePrecanDHKeypair(
+					uint(precannedID),
+					client.GetStorage().GetE2EGroup())
+			} else if usr.E2eDhPrivateKey != nil {
+				jww.INFO.Printf("Using pre-existing DH key")
+				privkey = usr.E2eDhPrivateKey
 			} else {
+				jww.INFO.Printf("Generating new DH key")
 				rngStream := client.GetRng().GetStream()
-				privkey = diffieHellman.GeneratePrivateKey(len(e2eGrp.GetPBytes()),
+				privkey = diffieHellman.GeneratePrivateKey(
+					len(e2eGrp.GetPBytes()),
 					e2eGrp, rngStream)
 				rngStream.Close()
 			}
diff --git a/api/precan.go b/api/precan.go
index eaa471e9ee963a41d493c2a0452c762bb072fa1e..150d90fa9a806db81277fe9677a9a6ecc13e64dc 100644
--- a/api/precan.go
+++ b/api/precan.go
@@ -9,6 +9,7 @@ package api
 
 import (
 	"encoding/binary"
+
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/storage/user"
@@ -59,15 +60,15 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string,
 		csprng.NewSystemRNG)
 	rngStream := rngStreamGen.GetStream()
 
-	def, err := parseNDF(defJSON)
+	def, err := ParseNDF(defJSON)
 	if err != nil {
 		return err
 	}
-	cmixGrp, e2eGrp := decodeGroups(def)
+	cmixGrp, e2eGrp := DecodeGroups(def)
 
 	protoUser := CreatePrecannedUser(precannedID, rngStream)
 
-	store, err := checkVersionAndSetupStorage(def, storageDir, password,
+	store, err := CheckVersionAndSetupStorage(def, storageDir, password,
 		protoUser, cmixGrp, e2eGrp, "")
 	if err != nil {
 		return err
@@ -81,4 +82,4 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string,
 	}
 
 	return nil
-}
\ No newline at end of file
+}
diff --git a/cmd/root.go b/cmd/root.go
index 1237e52678dcac1e7051a0b88bbe51f08478a8f2..7d8733e1dca001782df6579acd22d2a4dc355093 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -560,8 +560,11 @@ func createClient() *api.Client {
 			}
 
 			// Construct client from backup data
-			backupIdList, _, err := api.NewClientFromBackup(string(ndfJSON), storeDir,
+			backupIdList, _, err := messenger.NewClientFromBackup(string(ndfJSON), storeDir,
 				pass, backupPass, backupFile)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
 
 			backupIdListPath := viper.GetString("backupIdList")
 			if backupIdListPath != "" {
diff --git a/ud/manager.go b/ud/manager.go
index 9d60515e5995059eb4926e6ef33384a69e6a0347..3cd1b679a3586248c14f8608eb31cddb2e1f43e7 100644
--- a/ud/manager.go
+++ b/ud/manager.go
@@ -2,6 +2,9 @@ package ud
 
 import (
 	"fmt"
+	"sync"
+	"time"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/api"
@@ -13,8 +16,6 @@ import (
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/id"
-	"sync"
-	"time"
 )
 
 const (
@@ -116,7 +117,7 @@ func NewManager(services CMix, e2e E2E,
 	}
 
 	// Set storage to registered
-	if err = m.setRegistered(); err != nil && m.events != nil {
+	if err = setRegistered(kv); err != nil && m.events != nil {
 		m.events.Report(1, "UserDiscovery", "Registration",
 			fmt.Sprintf("User Registered with UD: %+v",
 				username))
@@ -163,6 +164,13 @@ func NewManagerFromBackup(services CMix,
 			"from backup")
 	}
 
+	// Set as registered. Since it's from a backup,
+	// the client is already registered
+	if err = setRegistered(kv); err != nil {
+		return nil, errors.WithMessage(err, "failed to set client as "+
+			"registered with user discovery.")
+	}
+
 	// Create the user discovery host object
 	_, err = m.getOrAddUdHost()
 	if err != nil {
@@ -170,14 +178,33 @@ func NewManagerFromBackup(services CMix,
 			"not be constructed.")
 	}
 
+	return m, nil
+}
+
+// InitStoreFromBackup initializes the UD storage from the backup subsystem
+func InitStoreFromBackup(kv *versioned.KV,
+	username, email, phone fact.Fact) error {
+	// Initialize our store
+	udStore, err := store.NewOrLoadStore(kv)
+	if err != nil {
+		return err
+	}
+
+	// Put any passed in missing facts into store
+	err = udStore.BackUpMissingFacts(email, phone)
+	if err != nil {
+		return errors.WithMessage(err, "Failed to restore UD store "+
+			"from backup")
+	}
+
 	// Set as registered. Since it's from a backup,
 	// the client is already registered
-	if err = m.setRegistered(); err != nil {
-		return nil, errors.WithMessage(err, "failed to set client as "+
+	if err = setRegistered(kv); err != nil {
+		return errors.WithMessage(err, "failed to set client as "+
 			"registered with user discovery.")
 	}
 
-	return m, nil
+	return nil
 }
 
 // LoadManager loads the state of the Manager
diff --git a/ud/registered.go b/ud/registered.go
index 47104cc2f56315fcbe11dbf925f7d415f2dbf132..71eab2a4e71ede3019c866c261dd818e325ebdaa 100644
--- a/ud/registered.go
+++ b/ud/registered.go
@@ -2,6 +2,7 @@ package ud
 
 import (
 	"encoding/binary"
+
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/netTime"
@@ -21,8 +22,8 @@ func (m *Manager) isRegistered() bool {
 	return true
 }
 
-// isRegistered returns if the client is registered with user discovery
-func (m *Manager) setRegistered() error {
+// setRegistered sets the user to registered
+func setRegistered(kv *versioned.KV) error {
 	data := make([]byte, 4)
 	binary.BigEndian.PutUint32(data, 1)
 	obj := &versioned.Object{
@@ -31,7 +32,7 @@ func (m *Manager) setRegistered() error {
 		Data:      data,
 	}
 
-	if err := m.kv.Set(isRegisteredKey, isRegisteredVersion, obj); err != nil {
+	if err := kv.Set(isRegisteredKey, isRegisteredVersion, obj); err != nil {
 		jww.FATAL.Panicf("Failed to store that the client is "+
 			"registered: %+v", err)
 	}