From a93eb1be02c900391c3a59c3243771325a346625 Mon Sep 17 00:00:00 2001
From: josh <josh@elixxir.io>
Date: Fri, 29 Apr 2022 15:00:21 -0700
Subject: [PATCH] Fix compile issues in ud subcommand

---
 api/client.go                 |   5 +
 api/precan.go                 |   9 +-
 api/user.go                   |  27 ++-
 bindings/ud.go                |  24 +-
 cmd/ud.go                     | 404 ++++++++++++++++++----------------
 go.sum                        |   2 +
 single/request.go             |   2 -
 storage/user/cryptographic.go |   4 +-
 ud/interfaces.go              |   4 +
 ud/manager.go                 |   5 +
 ud/register.go                |   2 +-
 xxmutils/restoreContacts.go   |  23 +-
 12 files changed, 277 insertions(+), 234 deletions(-)

diff --git a/api/client.go b/api/client.go
index 97241cf29..7c23d024a 100644
--- a/api/client.go
+++ b/api/client.go
@@ -716,6 +716,11 @@ func (c *Client) GetE2EHandler() e2e.Handler {
 	return c.e2e
 }
 
+// GetEventReporter returns the event reporter
+func (c *Client) GetEventReporter() event.Reporter {
+	return c.events
+}
+
 // GetBackup returns a pointer to the backup container so that the backup can be
 // set and triggered.
 func (c *Client) GetBackup() *backup.Backup {
diff --git a/api/precan.go b/api/precan.go
index f85210df1..a563faa23 100644
--- a/api/precan.go
+++ b/api/precan.go
@@ -9,6 +9,7 @@ package api
 
 import (
 	"encoding/binary"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"math/rand"
 
 	"github.com/cloudflare/circl/dh/sidh"
@@ -33,10 +34,7 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix,
 	prng := rand.New(rand.NewSource(int64(precannedID)))
 	prime := e2e.GetPBytes()
 	keyLen := len(prime)
-	e2eKeyBytes, err := csprng.GenerateInGroup(prime, keyLen, prng)
-	if err != nil {
-		jww.FATAL.Panicf(err.Error())
-	}
+	e2eKey := diffieHellman.GeneratePrivateKey(keyLen, e2e, prng)
 
 	// Salt, UID, etc gen
 	salt := make([]byte, SaltSize)
@@ -57,7 +55,8 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix,
 		ReceptionID:      &userID,
 		ReceptionSalt:    salt,
 		Precanned:        true,
-		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
+		E2eDhPrivateKey:  e2eKey,
+		E2eDhPublicKey:   diffieHellman.GeneratePublicKey(e2eKey, e2e),
 		TransmissionRSA:  rsaKey,
 		ReceptionRSA:     rsaKey,
 	}
diff --git a/api/user.go b/api/user.go
index 5913185b4..f0538a1a9 100644
--- a/api/user.go
+++ b/api/user.go
@@ -8,6 +8,7 @@
 package api
 
 import (
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"regexp"
 	"runtime"
 	"strings"
@@ -33,10 +34,10 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix,
 	e2e *cyclic.Group) user.Info {
 	// CMIX Keygen
 	var transmissionRsaKey, receptionRsaKey *rsa.PrivateKey
+	var e2eKey *cyclic.Int
+	var transmissionSalt, receptionSalt []byte
 
-	var e2eKeyBytes, transmissionSalt, receptionSalt []byte
-
-	e2eKeyBytes, transmissionSalt, receptionSalt,
+	transmissionSalt, receptionSalt, e2eKey,
 		transmissionRsaKey, receptionRsaKey = createKeys(rng, e2e)
 
 	// Salt, UID, etc gen
@@ -85,13 +86,14 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix,
 		ReceptionSalt:    receptionSalt,
 		ReceptionRSA:     receptionRsaKey,
 		Precanned:        false,
-		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
+		E2eDhPrivateKey:  e2eKey,
+		E2eDhPublicKey:   diffieHellman.GeneratePublicKey(e2eKey, e2e),
 	}
 }
 
 func createKeys(rng *fastRNG.StreamGenerator,
-	e2e *cyclic.Group) (e2eKeyBytes,
-	transmissionSalt, receptionSalt []byte,
+	e2e *cyclic.Group) (
+	transmissionSalt, receptionSalt []byte, e2eKey *cyclic.Int,
 	transmissionRsaKey, receptionRsaKey *rsa.PrivateKey) {
 	wg := sync.WaitGroup{}
 
@@ -101,9 +103,7 @@ func createKeys(rng *fastRNG.StreamGenerator,
 		defer wg.Done()
 		var err error
 		rngStream := rng.GetStream()
-		prime := e2e.GetPBytes()
-		keyLen := len(prime)
-		e2eKeyBytes, err = csprng.GenerateInGroup(prime, keyLen,
+		e2eKey = diffieHellman.GeneratePrivateKey(len(e2e.GetPBytes()), e2e,
 			rngStream)
 		rngStream.Close()
 		if err != nil {
@@ -148,10 +148,8 @@ func createNewVanityUser(rng csprng.Source, cmix,
 	// DH Keygen
 	prime := e2e.GetPBytes()
 	keyLen := len(prime)
-	e2eKeyBytes, err := csprng.GenerateInGroup(prime, keyLen, rng)
-	if err != nil {
-		jww.FATAL.Panicf(err.Error())
-	}
+
+	e2eKey := diffieHellman.GeneratePrivateKey(keyLen, e2e, rng)
 
 	// RSA Keygen (4096 bit defaults)
 	transmissionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
@@ -261,6 +259,7 @@ func createNewVanityUser(rng csprng.Source, cmix,
 		ReceptionSalt:    receptionSalt,
 		ReceptionRSA:     receptionRsaKey,
 		Precanned:        false,
-		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
+		E2eDhPrivateKey:  e2eKey,
+		E2eDhPublicKey:   diffieHellman.GeneratePublicKey(e2eKey, e2e),
 	}
 }
diff --git a/bindings/ud.go b/bindings/ud.go
index 23195fd75..ea8f5390a 100644
--- a/bindings/ud.go
+++ b/bindings/ud.go
@@ -41,8 +41,8 @@ func NewUserDiscovery(client *Client, username string) (*UserDiscovery, error) {
 	stream := client.api.GetRng().GetStream()
 	defer stream.Close()
 	m, err := udPackage.NewManager(client.api.GetNetworkInterface(),
-		client.api.GetE2e(), client.api.NetworkFollowerStatus,
-		client.api.GetEventManager(),
+		client.api.GetE2EHandler(), client.api.NetworkFollowerStatus,
+		client.api.GetEventReporter(),
 		client.api.GetComms(), client.api.GetStorage(),
 		stream,
 		username, client.api.GetStorage().GetKV())
@@ -60,7 +60,7 @@ func NewUserDiscovery(client *Client, username string) (*UserDiscovery, error) {
 // instantiation of the manager by NewUserDiscovery.
 func LoadUserDiscovery(client *Client) (*UserDiscovery, error) {
 	m, err := udPackage.LoadManager(client.api.GetNetworkInterface(),
-		client.api.GetE2e(), client.api.GetEventManager(),
+		client.api.GetE2EHandler(), client.api.GetEventReporter(),
 		client.api.GetComms(), client.api.GetStorage(),
 		client.api.GetStorage().GetKV())
 
@@ -119,7 +119,11 @@ func NewUserDiscoveryFromBackup(client *Client,
 			"registered phone number")
 	}
 
-	m, err := udPackage.NewManagerFromBackup(client.api.GetNetworkInterface(), client.api.GetE2e(), client.api.NetworkFollowerStatus, client.api.GetEventManager(), client.api.GetComms(), client.api.GetStorage(), emailFact, phoneFact, client.api.GetStorage().GetKV())
+	m, err := udPackage.NewManagerFromBackup(client.api.GetNetworkInterface(),
+		client.api.GetE2EHandler(), client.api.NetworkFollowerStatus,
+		client.api.GetEventReporter(), client.api.GetComms(),
+		client.api.GetStorage(), emailFact, phoneFact,
+		client.api.GetStorage().GetKV())
 	if err != nil {
 		return nil, errors.WithMessage(err,
 			"Failed to create User Discovery Manager")
@@ -228,8 +232,8 @@ func (ud UserDiscovery) Search(client *Client,
 	}
 
 	rids, _, err := udPackage.Search(
-		client.api.GetNetworkInterface(), client.api.GetEventManager(),
-		stream, client.api.GetE2e().GetGroup(), udContact,
+		client.api.GetNetworkInterface(), client.api.GetEventReporter(),
+		stream, client.api.GetE2EHandler().GetGroup(), udContact,
 		cb, factList, p)
 
 	if err != nil {
@@ -285,8 +289,8 @@ func (ud UserDiscovery) SearchSingle(client *Client, f string, callback SingleSe
 	}
 
 	rids, _, err := udPackage.Search(client.api.GetNetworkInterface(),
-		client.api.GetEventManager(),
-		stream, client.api.GetE2e().GetGroup(), udContact,
+		client.api.GetEventReporter(),
+		stream, client.api.GetE2EHandler().GetGroup(), udContact,
 		cb, []fact.Fact{fObj}, p)
 
 	if err != nil {
@@ -361,7 +365,7 @@ func (ud UserDiscovery) Lookup(client *Client,
 	}
 
 	rid, _, err := udPackage.Lookup(client.api.GetNetworkInterface(),
-		stream, client.api.GetE2e().GetGroup(),
+		stream, client.api.GetE2EHandler().GetGroup(),
 		udContact,
 		cb, uid, p)
 
@@ -447,7 +451,7 @@ func (ud UserDiscovery) MultiLookup(client *Client,
 			stream := client.api.GetRng().GetStream()
 			defer stream.Close()
 			_, _, err := udPackage.Lookup(client.api.GetNetworkInterface(),
-				stream, client.api.GetE2e().GetGroup(),
+				stream, client.api.GetE2EHandler().GetGroup(),
 				udContact, cb, localID, p)
 			if err != nil {
 				results <- lookupResponse{
diff --git a/cmd/ud.go b/cmd/ud.go
index 9a7466373..67fa9d933 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -10,6 +10,12 @@ package cmd
 
 import (
 	"fmt"
+	"gitlab.com/elixxir/client/single"
+	"gitlab.com/elixxir/client/ud"
+	"gitlab.com/elixxir/client/xxmutils"
+	"gitlab.com/elixxir/primitives/fact"
+	"gitlab.com/xx_network/primitives/utils"
+	"time"
 
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
@@ -26,12 +32,12 @@ var udCmd = &cobra.Command{
 	Short: "Register for and search users using the xx network user discovery service.",
 	Args:  cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
-		// client := initClient()
+		client := initClient()
 
-		// // get user and save contact to file
-		// user := client.GetUser()
-		// jww.INFO.Printf("User: %s", user.ReceptionID)
-		// writeContact(user.GetContact())
+		// get user and save contact to file
+		user := client.GetUser()
+		jww.INFO.Printf("User: %s", user.ReceptionID)
+		writeContact(user.GetContact())
 
 		// // Set up reception handler
 		// swBoard := client.GetSwitchboard()
@@ -57,194 +63,206 @@ var udCmd = &cobra.Command{
 		// 	})
 		// }
 
-		// err := client.StartNetworkFollower(50 * time.Millisecond)
-		// if err != nil {
-		// 	jww.FATAL.Panicf("%+v", err)
-		// }
-
-		// // Wait until connected or crash on timeout
-		// connected := make(chan bool, 10)
-		// client.GetHealth().AddChannel(connected)
-		// waitUntilConnected(connected)
-
-		// // Make single-use manager and start receiving process
-		// singleMng := old.NewManager(client)
-		// err = client.AddService(singleMng.StartProcesses)
-		// if err != nil {
-		// 	jww.FATAL.Panicf("Failed to add single use process: %+v", err)
-		// }
-
-		// // Make user discovery manager
-		// userDiscoveryMgr, err := ud.NewManager(client, singleMng)
-		// if err != nil {
-		// 	jww.FATAL.Panicf("Failed to create new UD manager: %+v", err)
-		// }
-
-		// userToRegister := viper.GetString("register")
-		// if userToRegister != "" {
-		// 	err = userDiscoveryMgr.Register(userToRegister)
-		// 	if err != nil {
-		// 		fmt.Printf("Failed to register user %s: %s\n",
-		// 			userToRegister, err.Error())
-		// 		jww.FATAL.Panicf("Failed to register user %s: %+v", userToRegister, err)
-		// 	}
-		// }
-
-		// var newFacts fact.FactList
-		// phone := viper.GetString("addphone")
-		// if phone != "" {
-		// 	f, err := fact.NewFact(fact.Phone, phone)
-		// 	if err != nil {
-		// 		jww.FATAL.Panicf("Failed to create new fact: %+v", err)
-		// 	}
-		// 	newFacts = append(newFacts, f)
-		// }
-
-		// email := viper.GetString("addemail")
-		// if email != "" {
-		// 	f, err := fact.NewFact(fact.Email, email)
-		// 	if err != nil {
-		// 		jww.FATAL.Panicf("Failed to create new fact: %+v", err)
-		// 	}
-		// 	newFacts = append(newFacts, f)
-		// }
-
-		// for i := 0; i < len(newFacts); i++ {
-		// 	r, err := userDiscoveryMgr.SendRegisterFact(newFacts[i])
-		// 	if err != nil {
-		// 		fmt.Printf("Failed to register fact: %s\n",
-		// 			newFacts[i])
-		// 		jww.FATAL.Panicf("Failed to send register fact: %+v", err)
-		// 	}
-		// 	// TODO Store the code?
-		// 	jww.INFO.Printf("Fact Add Response: %+v", r)
-		// }
-
-		// confirmID := viper.GetString("confirm")
-		// if confirmID != "" {
-		// 	err = userDiscoveryMgr.SendConfirmFact(confirmID, confirmID)
-		// 	if err != nil {
-		// 		fmt.Printf("Couldn't confirm fact: %s\n",
-		// 			err.Error())
-		// 		jww.FATAL.Panicf("%+v", err)
-		// 	}
-		// }
-
-		// // Handle lookup (verification) process
-		// // Note: Cryptographic verification occurs above the bindings layer
-		// lookupIDStr := viper.GetString("lookup")
-		// if lookupIDStr != "" {
-		// 	lookupID, _ := parseRecipient(lookupIDStr)
-		// 	//if !ok {
-		// 	//	jww.FATAL.Panicf("Could not parse recipient: %s", lookupIDStr)
-		// 	//}
-		// 	err = userDiscoveryMgr.Lookup(lookupID,
-		// 		func(newContact contact.Contact, err error) {
-		// 			if err != nil {
-		// 				jww.FATAL.Panicf("UserDiscovery Lookup error: %+v", err)
-		// 			}
-		// 			printContact(newContact)
-		// 		}, 30*time.Second)
-
-		// 	if err != nil {
-		// 		jww.WARN.Printf("Failed UD lookup: %+v", err)
-		// 	}
-
-		// 	time.Sleep(31 * time.Second)
-		// }
-
-		// if viper.GetString("batchadd") != "" {
-		// 	idListFile, err := utils.ReadFile(viper.GetString("batchadd"))
-		// 	if err != nil {
-		// 		fmt.Printf("BATCHADD: Couldn't read file: %s\n",
-		// 			err.Error())
-		// 		jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err)
-		// 	}
-		// 	restored, _, _, err := xxmutils.RestoreContactsFromBackup(
-		// 		idListFile, client, userDiscoveryMgr, nil)
-		// 	if err != nil {
-		// 		jww.FATAL.Panicf("%+v", err)
-		// 	}
-		// 	for i := 0; i < len(restored); i++ {
-		// 		uid := restored[i]
-		// 		for !client.HasAuthenticatedChannel(uid) {
-		// 			time.Sleep(time.Second)
-		// 		}
-		// 		jww.INFO.Printf("Authenticated channel established for %s", uid)
-		// 	}
-		// }
-		// usernameSearchStr := viper.GetString("searchusername")
-		// emailSearchStr := viper.GetString("searchemail")
-		// phoneSearchStr := viper.GetString("searchphone")
-
-		// var facts fact.FactList
-		// if usernameSearchStr != "" {
-		// 	f, err := fact.NewFact(fact.Username, usernameSearchStr)
-		// 	if err != nil {
-		// 		jww.FATAL.Panicf("Failed to create new fact: %+v", err)
-		// 	}
-		// 	facts = append(facts, f)
-		// }
-		// if emailSearchStr != "" {
-		// 	f, err := fact.NewFact(fact.Email, emailSearchStr)
-		// 	if err != nil {
-		// 		jww.FATAL.Panicf("Failed to create new fact: %+v", err)
-		// 	}
-		// 	facts = append(facts, f)
-		// }
-		// if phoneSearchStr != "" {
-		// 	f, err := fact.NewFact(fact.Phone, phoneSearchStr)
-		// 	if err != nil {
-		// 		jww.FATAL.Panicf("Failed to create new fact: %+v", err)
-		// 	}
-		// 	facts = append(facts, f)
-		// }
-
-		// userToRemove := viper.GetString("remove")
-		// if userToRemove != "" {
-		// 	f, err := fact.NewFact(fact.Username, userToRemove)
-		// 	if err != nil {
-		// 		jww.FATAL.Panicf(
-		// 			"Failed to create new fact: %+v", err)
-		// 	}
-		// 	err = userDiscoveryMgr.RemoveUser(f)
-		// 	if err != nil {
-		// 		fmt.Printf("Couldn't remove user %s\n",
-		// 			userToRemove)
-		// 		jww.FATAL.Panicf(
-		// 			"Failed to remove user %s: %+v",
-		// 			userToRemove, err)
-		// 	}
-		// 	fmt.Printf("Removed user from discovery: %s\n",
-		// 		userToRemove)
-		// }
-
-		// if len(facts) == 0 {
-		// 	err = client.StopNetworkFollower()
-		// 	if err != nil {
-		// 		jww.WARN.Print(err)
-		// 	}
-		// 	return
-		// }
-
-		// err = userDiscoveryMgr.Search(facts,
-		// 	func(contacts []contact.Contact, err error) {
-		// 		if err != nil {
-		// 			jww.FATAL.Panicf("%+v", err)
-		// 		}
-		// 		for _, c := range contacts {
-		// 			printContact(c)
-		// 		}
-		// 	}, 90*time.Second)
-		// if err != nil {
-		// 	jww.FATAL.Panicf("%+v", err)
-		// }
-
-		// time.Sleep(91 * time.Second)
-		// err = client.StopNetworkFollower()
-		// if err != nil {
-		// 	jww.WARN.Print(err)
-		// }
+		err := client.StartNetworkFollower(50 * time.Millisecond)
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
+		}
+
+		// Wait until connected or crash on timeout
+		connected := make(chan bool, 10)
+		client.GetNetworkInterface().AddHealthCallback(
+			func(isconnected bool) {
+				connected <- isconnected
+			})
+		waitUntilConnected(connected)
+
+		// Make user discovery manager
+		stream := client.GetRng().GetStream()
+		defer stream.Close()
+		userToRegister := viper.GetString("register")
+		userDiscoveryMgr, err := ud.NewManager(client.GetNetworkInterface(),
+			client.GetE2EHandler(), client.NetworkFollowerStatus,
+			client.GetEventReporter(),
+			client.GetComms(), client.GetStorage(),
+			stream,
+			userToRegister, client.GetStorage().GetKV())
+		if err != nil {
+			userDiscoveryMgr, err = ud.LoadManager(client.GetNetworkInterface(),
+				client.GetE2EHandler(), client.GetEventReporter(),
+				client.GetComms(),
+				client.GetStorage(), client.GetStorage().GetKV())
+			if err != nil {
+				jww.FATAL.Panicf("Failed to create new UD manager: %+v", err)
+			}
+		}
+
+		var newFacts fact.FactList
+		phone := viper.GetString("addphone")
+		if phone != "" {
+			f, err := fact.NewFact(fact.Phone, phone)
+			if err != nil {
+				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
+			}
+			newFacts = append(newFacts, f)
+		}
+
+		email := viper.GetString("addemail")
+		if email != "" {
+			f, err := fact.NewFact(fact.Email, email)
+			if err != nil {
+				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
+			}
+			newFacts = append(newFacts, f)
+		}
+
+		for i := 0; i < len(newFacts); i++ {
+			r, err := userDiscoveryMgr.SendRegisterFact(newFacts[i])
+			if err != nil {
+				fmt.Printf("Failed to register fact: %s\n",
+					newFacts[i])
+				jww.FATAL.Panicf("Failed to send register fact: %+v", err)
+			}
+			// TODO Store the code?
+			jww.INFO.Printf("Fact Add Response: %+v", r)
+		}
+
+		confirmID := viper.GetString("confirm")
+		if confirmID != "" {
+			err = userDiscoveryMgr.ConfirmFact(confirmID, confirmID)
+			if err != nil {
+				fmt.Printf("Couldn't confirm fact: %s\n",
+					err.Error())
+				jww.FATAL.Panicf("%+v", err)
+			}
+		}
+
+		udContact, err := userDiscoveryMgr.GetContact()
+		if err != nil {
+			fmt.Printf("Failed to get user discovery contact object: %+v", err)
+			jww.FATAL.Printf("Failed to get user discovery contact object: %+v", err)
+		}
+
+		// Handle lookup (verification) process
+		// Note: Cryptographic verification occurs above the bindings layer
+		lookupIDStr := viper.GetString("lookup")
+		if lookupIDStr != "" {
+			lookupID, _ := parseRecipient(lookupIDStr)
+			//if !ok {
+			//	jww.FATAL.Panicf("Could not parse recipient: %s", lookupIDStr)
+			//}
+
+			cb := func(newContact contact.Contact, err error) {
+				if err != nil {
+					jww.FATAL.Panicf("UserDiscovery Lookup error: %+v", err)
+				}
+				printContact(newContact)
+			}
+			_, _, err = ud.Lookup(client.GetNetworkInterface(),
+				stream, client.GetE2EHandler().GetGroup(),
+				udContact, cb, lookupID, single.GetDefaultRequestParams())
+			if err != nil {
+				jww.WARN.Printf("Failed UD lookup: %+v", err)
+			}
+
+			time.Sleep(31 * time.Second)
+		}
+
+		if viper.GetString("batchadd") != "" {
+			idListFile, err := utils.ReadFile(viper.GetString("batchadd"))
+			if err != nil {
+				fmt.Printf("BATCHADD: Couldn't read file: %s\n",
+					err.Error())
+				jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err)
+			}
+			restored, _, _, err := xxmutils.RestoreContactsFromBackup(
+				idListFile, client, userDiscoveryMgr, nil)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			for i := 0; i < len(restored); i++ {
+				uid := restored[i]
+				for !client.HasAuthenticatedChannel(uid) {
+					time.Sleep(time.Second)
+				}
+				jww.INFO.Printf("Authenticated channel established for %s", uid)
+			}
+		}
+		usernameSearchStr := viper.GetString("searchusername")
+		emailSearchStr := viper.GetString("searchemail")
+		phoneSearchStr := viper.GetString("searchphone")
+
+		var facts fact.FactList
+		if usernameSearchStr != "" {
+			f, err := fact.NewFact(fact.Username, usernameSearchStr)
+			if err != nil {
+				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
+			}
+			facts = append(facts, f)
+		}
+		if emailSearchStr != "" {
+			f, err := fact.NewFact(fact.Email, emailSearchStr)
+			if err != nil {
+				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
+			}
+			facts = append(facts, f)
+		}
+		if phoneSearchStr != "" {
+			f, err := fact.NewFact(fact.Phone, phoneSearchStr)
+			if err != nil {
+				jww.FATAL.Panicf("Failed to create new fact: %+v", err)
+			}
+			facts = append(facts, f)
+		}
+
+		userToRemove := viper.GetString("remove")
+		if userToRemove != "" {
+			f, err := fact.NewFact(fact.Username, userToRemove)
+			if err != nil {
+				jww.FATAL.Panicf(
+					"Failed to create new fact: %+v", err)
+			}
+			err = userDiscoveryMgr.PermanentDeleteAccount(f)
+			if err != nil {
+				fmt.Printf("Couldn't remove user %s\n",
+					userToRemove)
+				jww.FATAL.Panicf(
+					"Failed to remove user %s: %+v",
+					userToRemove, err)
+			}
+			fmt.Printf("Removed user from discovery: %s\n",
+				userToRemove)
+		}
+
+		if len(facts) == 0 {
+			err = client.StopNetworkFollower()
+			if err != nil {
+				jww.WARN.Print(err)
+			}
+			return
+		}
+
+		cb := func(contacts []contact.Contact, err error) {
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			for _, c := range contacts {
+				printContact(c)
+			}
+		}
+
+		_, _, err = ud.Search(client.GetNetworkInterface(),
+			client.GetEventReporter(),
+			stream, client.GetE2EHandler().GetGroup(),
+			udContact, cb, facts, single.GetDefaultRequestParams())
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
+		}
+
+		time.Sleep(91 * time.Second)
+		err = client.StopNetworkFollower()
+		if err != nil {
+			jww.WARN.Print(err)
+		}
 	},
 }
 
diff --git a/go.sum b/go.sum
index 4aa07bafa..b2b24d4d7 100644
--- a/go.sum
+++ b/go.sum
@@ -285,6 +285,8 @@ gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp0
 gitlab.com/elixxir/crypto v0.0.7-0.20220222221347-95c7ae58da6b/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
 gitlab.com/elixxir/crypto v0.0.7-0.20220309234716-1ba339865787 h1:+qmsWov412+Yn7AKUhTbOcDgAydNXlNLPmFpO2W5LwY=
 gitlab.com/elixxir/crypto v0.0.7-0.20220309234716-1ba339865787/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
+gitlab.com/elixxir/crypto v0.0.7-0.20220317172048-3de167bd9406 h1:PRA8OJMXuy9JZmUuZ442AIE/tWY7HisqezyLNhpZZ9w=
+gitlab.com/elixxir/crypto v0.0.7-0.20220317172048-3de167bd9406/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
 gitlab.com/elixxir/crypto v0.0.7-0.20220325215559-7489d68d7714 h1:epnov8zyFWod14MUNtGHSbZCVSkZjN4NvoiBs1TgEV8=
 gitlab.com/elixxir/crypto v0.0.7-0.20220325215559-7489d68d7714/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
 gitlab.com/elixxir/crypto v0.0.7-0.20220325224306-705ce59288bb h1:WdlmG+KPaM2Pjo1EFiFFPYEVSMV64Di1CitQnXGWBOQ=
diff --git a/single/request.go b/single/request.go
index 6f2d71ae8..6cb079652 100644
--- a/single/request.go
+++ b/single/request.go
@@ -212,8 +212,6 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 			errors.Errorf(errSendRequest, tag, recipient, err)
 	}
 
-	// todo: this is jono's work but there's a send above it,
-	//  probably just WIP code, talk to jono and resolve once tests work
 	roundIDs := make([]id.Round, len(parts)+1)
 	roundIDs[0] = rid
 	for i, part := range parts {
diff --git a/storage/user/cryptographic.go b/storage/user/cryptographic.go
index 592fc9c23..fd4b73047 100644
--- a/storage/user/cryptographic.go
+++ b/storage/user/cryptographic.go
@@ -41,7 +41,9 @@ type ciDisk struct {
 	IsPrecanned        bool
 }
 
-func newCryptographicIdentity(transmissionID, receptionID *id.ID, transmissionSalt, receptionSalt []byte, transmissionRsa, receptionRsa *rsa.PrivateKey,
+func newCryptographicIdentity(transmissionID, receptionID *id.ID,
+	transmissionSalt, receptionSalt []byte,
+	transmissionRsa, receptionRsa *rsa.PrivateKey,
 	isPrecanned bool, kv *versioned.KV) *CryptographicIdentity {
 
 	ci := &CryptographicIdentity{
diff --git a/ud/interfaces.go b/ud/interfaces.go
index 6042ae755..ba5bff8b7 100644
--- a/ud/interfaces.go
+++ b/ud/interfaces.go
@@ -24,6 +24,10 @@ type E2E interface {
 
 	// GetReceptionID returns the default IDs
 	GetReceptionID() *id.ID
+
+	// GetHistoricalDHPubkey returns the user's Historical DH
+	// Public Key
+	GetHistoricalDHPubkey() *cyclic.Int
 }
 
 // UserInfo is a sub-interface for the user.User object in storage.
diff --git a/ud/manager.go b/ud/manager.go
index 53e6a37f6..32e2cb25d 100644
--- a/ud/manager.go
+++ b/ud/manager.go
@@ -85,6 +85,11 @@ func NewManager(services CMix, e2e E2E,
 		kv:      kv,
 	}
 
+	if m.isRegistered() {
+		return nil, errors.Errorf("NewManager is already registered. " +
+			"NewManager is meant for the first instantiation. Use LoadManager for all other calls")
+	}
+
 	// Initialize store
 	var err error
 	m.store, err = store.NewOrLoadStore(kv)
diff --git a/ud/register.go b/ud/register.go
index caae813dc..3df8edd64 100644
--- a/ud/register.go
+++ b/ud/register.go
@@ -25,7 +25,7 @@ func (m *Manager) register(username string, rng csprng.Source,
 		RSAPublicPem:           string(rsa.CreatePublicKeyPem(cryptoUser.ReceptionRSA.GetPublic())),
 		IdentityRegistration: &pb.Identity{
 			Username: username,
-			DhPubKey: cryptoUser.E2eDhPublicKey.Bytes(),
+			DhPubKey: m.e2e.GetHistoricalDHPubkey().Bytes(),
 			Salt:     cryptoUser.ReceptionSalt,
 		},
 		UID:       cryptoUser.ReceptionID.Marshal(),
diff --git a/xxmutils/restoreContacts.go b/xxmutils/restoreContacts.go
index 6b8afad70..69a09d2e6 100644
--- a/xxmutils/restoreContacts.go
+++ b/xxmutils/restoreContacts.go
@@ -11,6 +11,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"gitlab.com/elixxir/client/single"
 	"gitlab.com/xx_network/primitives/netTime"
 	"math"
 	"strings"
@@ -41,6 +42,11 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
 	updatesCb interfaces.RestoreContactsUpdater) ([]*id.ID, []*id.ID,
 	[]error, error) {
 
+	udContact, err := udManager.GetContact()
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
 	var restored, failed []*id.ID
 	var errs []error
 
@@ -93,7 +99,7 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
 	rsWg := &sync.WaitGroup{}
 	rsWg.Add(numRoutines)
 	for i := 0; i < numRoutines; i++ {
-		go LookupContacts(lookupCh, foundCh, failCh, udManager, lcWg)
+		go LookupContacts(lookupCh, foundCh, failCh, client, udContact, lcWg)
 		go ResetSessions(resetContactCh, restoredCh, failCh, *client,
 			rsWg)
 	}
@@ -125,7 +131,6 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
 
 	// Event Processing
 	done := false
-	var err error = nil
 	for !done {
 		// NOTE: Timer is reset every loop
 		timeoutTimer := time.NewTimer(restoreTimeout)
@@ -173,13 +178,13 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
 func LookupContacts(in chan *id.ID, out chan *contact.Contact,
-	failCh chan failure, udManager *ud.Manager,
+	failCh chan failure, client *api.Client, udContact contact.Contact,
 	wg *sync.WaitGroup) {
 	defer wg.Done()
 	// Start looking up contacts with user discovery and feed this
 	// contacts channel.
 	for lookupID := range in {
-		c, err := LookupContact(lookupID, udManager)
+		c, err := LookupContact(lookupID, client, udContact)
 		if err == nil {
 			out <- c
 			continue
@@ -221,7 +226,7 @@ func ResetSessions(in, out chan *contact.Contact, failCh chan failure,
 // xxDK users should not use this function. This function is used by
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
-func LookupContact(userID *id.ID, udManager *ud.Manager) (
+func LookupContact(userID *id.ID, client *api.Client, udContact contact.Contact) (
 	*contact.Contact, error) {
 	// This is a little wonky, but wait until we get called then
 	// set the result to the contact objects details if there is
@@ -240,8 +245,10 @@ func LookupContact(userID *id.ID, udManager *ud.Manager) (
 	waiter.Lock()
 
 	// in MS, so 90 seconds
-	timeout := time.Duration(90 * time.Second)
-	udManager.Lookup(userID, lookupCB, timeout)
+	stream := client.GetRng().GetStream()
+	defer stream.Close()
+	_, _, err = ud.Lookup(client.GetNetworkInterface(), stream, client.GetE2EHandler().GetGroup(),
+		udContact, lookupCB, userID, single.GetDefaultRequestParams())
 
 	// Now force a wait for callback to exit
 	waiter.Lock()
@@ -272,7 +279,7 @@ type failure struct {
 const stateStoreFmt = "restoreContactsFromBackup/v1/%s"
 
 type stateStore struct {
-	apiStore *storage.Session
+	apiStore storage.Session
 	// TODO: We could put a syncmap or something here instead of
 	// 1-key-per-id
 }
-- 
GitLab