diff --git a/backup/backupRestore.go b/backup/backupRestore.go
index 91950ce8ad8912a50cadbf0d3aa60051e17a4c1a..94e1180ae0d5a993d4d13ca63854e6b690885e1c 100644
--- a/backup/backupRestore.go
+++ b/backup/backupRestore.go
@@ -8,6 +8,7 @@ package backup
 
 import (
 	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/client/e2e/rekey"
 	"gitlab.com/elixxir/client/storage"
@@ -35,6 +36,9 @@ func NewClientFromBackup(ndfJSON, storageDir string, sessionPassword,
 			"Failed to unmarshal decrypted client contents.")
 	}
 
+	jww.INFO.Printf("Decrypted backup ID to Restore: %v",
+		backUp.ReceptionIdentity.ComputedID)
+
 	userInfo := user.NewUserFromBackup(backUp)
 
 	def, err := xxdk.ParseNDF(ndfJSON)
diff --git a/cmd/backup.go b/cmd/backup.go
index 6a54958e88bd4441b268b979d82f3e10c4dd477a..faabf16661b45b783a6c11a6ff8f9438b02b1ac5 100644
--- a/cmd/backup.go
+++ b/cmd/backup.go
@@ -8,6 +8,10 @@ package cmd
 
 import (
 	"encoding/json"
+	"io/fs"
+	"io/ioutil"
+	"os"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
@@ -15,9 +19,6 @@ import (
 	"gitlab.com/elixxir/client/xxdk"
 	backupCrypto "gitlab.com/elixxir/crypto/backup"
 	"gitlab.com/xx_network/primitives/utils"
-	"io/fs"
-	"io/ioutil"
-	"os"
 )
 
 // loadOrInitBackup will build a new xxdk.E2e from existing storage
diff --git a/cmd/init.go b/cmd/init.go
index 20dc35ede7d85dbce8310798d2233e2df8e877d3..a126e95e983a99de5693a525dc11b8a25405d8cb 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -9,14 +9,17 @@
 package cmd
 
 import (
+	"fmt"
+
+	"io/fs"
+	"io/ioutil"
+	"os"
+
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
 	"gitlab.com/elixxir/client/xxdk"
-	"io/fs"
-	"io/ioutil"
-	"os"
 )
 
 // initCmd creates a new user object with the given NDF
@@ -54,6 +57,9 @@ var initCmd = &cobra.Command{
 
 		jww.INFO.Printf("User: %s", identity.ID)
 		writeContact(identity.GetContact())
+
+		// NOTE: DO NOT REMOVE THIS LINE. YOU WILL BREAK INTEGRATION
+		fmt.Printf("%s\n", identity.ID)
 	},
 }
 
@@ -65,9 +71,9 @@ func init() {
 	rootCmd.AddCommand(initCmd)
 }
 
-// loadOrInitClient will build a new xxdk.E2e from existing storage
+// loadOrInitMessenger will build a new xxdk.E2e from existing storage
 // or from a new storage that it will create if none already exists
-func loadOrInitClient(password []byte, storeDir, regCode string,
+func loadOrInitMessenger(forceLegacy bool, password []byte, storeDir, regCode string,
 	cmixParams xxdk.CMIXParams, e2eParams xxdk.E2EParams) *xxdk.E2e {
 	jww.INFO.Printf("Using normal sender")
 
@@ -87,7 +93,12 @@ func loadOrInitClient(password []byte, storeDir, regCode string,
 			jww.FATAL.Panicf("%+v", err)
 		}
 
-		identity, err = xxdk.MakeReceptionIdentity(net)
+		if forceLegacy {
+			jww.INFO.Printf("Forcing legacy sender")
+			identity, err = xxdk.MakeLegacyReceptionIdentity(net)
+		} else {
+			identity, err = xxdk.MakeReceptionIdentity(net)
+		}
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
 		}
@@ -108,11 +119,11 @@ func loadOrInitClient(password []byte, storeDir, regCode string,
 		}
 	}
 
-	client, err := xxdk.Login(net, authCbs, identity, e2eParams)
+	messenger, err := xxdk.Login(net, authCbs, identity, e2eParams)
 	if err != nil {
 		jww.FATAL.Panicf("%+v", err)
 	}
-	return client
+	return messenger
 }
 
 // loadOrInitVanity will build a new xxdk.E2e from existing storage
diff --git a/cmd/root.go b/cmd/root.go
index 9d0709e82bff6f7d282768d9829b7281f57ee524..4b360c8d188b767768548bf2d2904a46a1f0d5db 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -585,6 +585,7 @@ func initE2e(cmixParams xxdk.CMIXParams, e2eParams xxdk.E2EParams) *xxdk.E2e {
 	storePassword := parsePassword(viper.GetString("password"))
 	storeDir := viper.GetString("session")
 	regCode := viper.GetString("regcode")
+	forceLegacy := viper.GetBool("force-legacy")
 	jww.DEBUG.Printf("sessionDir: %v", storeDir)
 
 	// TODO: This probably shouldn't be initialized globally.
@@ -602,7 +603,7 @@ func initE2e(cmixParams xxdk.CMIXParams, e2eParams xxdk.E2EParams) *xxdk.E2e {
 	} else if backupPath != "" {
 		messenger = loadOrInitBackup(backupPath, backupPass, storePassword, storeDir, cmixParams, e2eParams)
 	} else {
-		messenger = loadOrInitClient(storePassword, storeDir, regCode, cmixParams, e2eParams)
+		messenger = loadOrInitMessenger(forceLegacy, storePassword, storeDir, regCode, cmixParams, e2eParams)
 	}
 
 	// Handle protoUser output
@@ -622,6 +623,9 @@ func initE2e(cmixParams xxdk.CMIXParams, e2eParams xxdk.E2EParams) *xxdk.E2e {
 
 	// Handle backup output
 	if backupOut := viper.GetString("backupOut"); backupOut != "" {
+		if !forceLegacy {
+			jww.FATAL.Panicf("Unable to make backup for non-legacy sender!")
+		}
 		updateBackupCb := func(encryptedBackup []byte) {
 			jww.INFO.Printf("Backup update received, size %d",
 				len(encryptedBackup))
@@ -1131,6 +1135,9 @@ func init() {
 		"ID to send message to (if below 40, will be precanned. Use "+
 			"'0x' or 'b64:' for hex and base64 representations)")
 	viper.BindPFlag("destid", rootCmd.Flags().Lookup("destid"))
+	rootCmd.PersistentFlags().Bool("force-legacy", false,
+		"Force client to operate using legacy identities.")
+	viper.BindPFlag("force-legacy", rootCmd.PersistentFlags().Lookup("force-legacy"))
 
 	rootCmd.Flags().StringP("destfile", "",
 		"", "Read this contact file for the destination id")
diff --git a/cmd/ud.go b/cmd/ud.go
index cf1a0df7be220da8ded2bc23bba9b0c1c6c01fa3..b016651f39e6e576d36e2cbf189aba94c696c445 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -39,38 +39,16 @@ var udCmd = &cobra.Command{
 
 		// get user and save contact to file
 		user := client.GetReceptionIdentity()
-		jww.INFO.Printf("User: %s", user.ID)
+		jww.INFO.Printf("[UD]User: %s", user.ID)
 		writeContact(user.GetContact())
 
-		// // Set up reception handler
-		// swBoard := client.GetSwitchboard()
-		// recvCh := make(chan message.Receive, 10000)
-		// listenerID := swBoard.RegisterChannel("DefaultCLIReceiver",
-		// 	switchboard.AnyUser(), message.XxMessage, recvCh)
-		// jww.INFO.Printf("Message ListenerID: %v", listenerID)
-
-		// // Set up auth request handler, which simply prints the user ID of the
-		// // requester
-		// authMgr := client.GetAuthRegistrar()
-		// authMgr.AddGeneralRequestCallback(printChanRequest)
-
-		// // If unsafe channels, add auto-acceptor
-		// if viper.GetBool("unsafe-channel-creation") {
-		// 	authMgr.AddGeneralRequestCallback(func(
-		// 		requester contact.Contact) {
-		// 		jww.INFO.Printf("Got Request: %s", requester.ID)
-		// 		_, err := client.ConfirmAuthenticatedChannel(requester)
-		// 		if err != nil {
-		// 			jww.FATAL.Panicf("%+v", err)
-		// 		}
-		// 	})
-		// }
-
 		err := client.StartNetworkFollower(50 * time.Millisecond)
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
 		}
 
+		jww.TRACE.Printf("[UD] Waiting for connection...")
+
 		// Wait until connected or crash on timeout
 		connected := make(chan bool, 10)
 		client.GetCmix().AddHealthCallback(
@@ -79,9 +57,12 @@ var udCmd = &cobra.Command{
 			})
 		waitUntilConnected(connected)
 
+		jww.TRACE.Printf("[UD] Connected!")
+
 		// Make user discovery manager
 		rng := client.GetRng()
 		userToRegister := viper.GetString("register")
+		jww.TRACE.Printf("[UD] Registering user %v...", userToRegister)
 		userDiscoveryMgr, err := ud.NewManager(client, client.GetComms(),
 			client.NetworkFollowerStatus, userToRegister, nil)
 		if err != nil {
@@ -95,6 +76,7 @@ var udCmd = &cobra.Command{
 
 			}
 		}
+		jww.INFO.Printf("[UD] Registered user %v", userToRegister)
 
 		var newFacts fact.FactList
 		phone := viper.GetString("addphone")
@@ -116,24 +98,29 @@ var udCmd = &cobra.Command{
 		}
 
 		for i := 0; i < len(newFacts); i++ {
+			jww.INFO.Printf("[UD] Registering Fact: %v",
+				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)
+				jww.FATAL.Panicf("[UD] Failed to send register fact: %+v", err)
 			}
 			// TODO Store the code?
-			jww.INFO.Printf("Fact Add Response: %+v", r)
+			jww.INFO.Printf("[UD] Fact Add Response: %+v", r)
 		}
 
 		confirmID := viper.GetString("confirm")
 		if confirmID != "" {
+			jww.INFO.Printf("[UD] Confirming fact: %v", confirmID)
 			err = userDiscoveryMgr.ConfirmFact(confirmID, confirmID)
 			if err != nil {
 				fmt.Printf("Couldn't confirm fact: %s\n",
 					err.Error())
 				jww.FATAL.Panicf("%+v", err)
 			}
+
+			jww.INFO.Printf("[UD] Confirmed %v", confirmID)
 		}
 
 		udContact, err := userDiscoveryMgr.GetContact()
@@ -147,9 +134,7 @@ var udCmd = &cobra.Command{
 		lookupIDStr := viper.GetString("lookup")
 		if lookupIDStr != "" {
 			lookupID := parseRecipient(lookupIDStr)
-			//if !ok {
-			//	jww.FATAL.Panicf("Could not parse recipient: %s", lookupIDStr)
-			//}
+			jww.INFO.Printf("[UD] Looking up %v", lookupID)
 
 			cb := func(newContact contact.Contact, err error) {
 				if err != nil {
@@ -177,6 +162,7 @@ var udCmd = &cobra.Command{
 					err.Error())
 				jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err)
 			}
+			jww.INFO.Printf("[UD] BATCHADD: Running")
 			restored, _, _, err := xxmutils.RestoreContactsFromBackup(
 				idListFile, client, userDiscoveryMgr, nil)
 			if err != nil {
@@ -187,7 +173,7 @@ var udCmd = &cobra.Command{
 				for !client.GetE2E().HasAuthenticatedChannel(uid) {
 					time.Sleep(time.Second)
 				}
-				jww.INFO.Printf("Authenticated channel established for %s", uid)
+				jww.INFO.Printf("[UD] Authenticated channel established for %s", uid)
 			}
 		}
 		usernameSearchStr := viper.GetString("searchusername")
@@ -232,7 +218,7 @@ var udCmd = &cobra.Command{
 					"Failed to remove user %s: %+v",
 					userToRemove, err)
 			}
-			fmt.Printf("Removed user from discovery: %s\n",
+			fmt.Printf("[UD] Removed user from discovery: %s\n",
 				userToRemove)
 		}
 
@@ -255,6 +241,7 @@ var udCmd = &cobra.Command{
 
 		stream := rng.GetStream()
 		defer stream.Close()
+		jww.INFO.Printf("[UD] Search: %v", facts)
 		_, _, err = ud.Search(client.GetCmix(),
 			client.GetEventReporter(),
 			stream, client.GetE2E().GetGroup(),
diff --git a/e2e/ratchet/partner/relationshipFingerprint.go b/e2e/ratchet/partner/relationshipFingerprint.go
index e00f6aa69638830752b079332e63f0f6bb68755f..9380b9a5051e9d82f76d3043e880350600425d6b 100644
--- a/e2e/ratchet/partner/relationshipFingerprint.go
+++ b/e2e/ratchet/partner/relationshipFingerprint.go
@@ -12,6 +12,7 @@ import (
 	session2 "gitlab.com/elixxir/client/e2e/ratchet/partner/session"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
@@ -20,7 +21,7 @@ import (
 func makeRelationshipFingerprint(t session2.RelationshipType, grp *cyclic.Group,
 	myPrivKey, partnerPubKey *cyclic.Int, me, partner *id.ID) []byte {
 
-	myPubKey := grp.ExpG(myPrivKey, grp.NewIntFromUInt(1))
+	myPubKey := diffieHellman.GeneratePublicKey(myPrivKey, grp)
 
 	switch t {
 	case session2.Send:
diff --git a/single/request.go b/single/request.go
index 1a49628653915c373fb6d7b59e632a7375eebfbc..08e78c6effd39046fada90042fd04efd8472855a 100644
--- a/single/request.go
+++ b/single/request.go
@@ -11,6 +11,7 @@ import (
 	"gitlab.com/elixxir/client/single/message"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/crypto/e2e/singleUse"
 	"gitlab.com/xx_network/crypto/csprng"
@@ -271,7 +272,7 @@ func generateDhKeys(grp *cyclic.Group, dhPubKey *cyclic.Int, rng io.Reader) (
 	privKey := grp.NewIntFromBytes(privKeyBytes)
 
 	// Generate public key and DH key
-	publicKey = grp.ExpG(privKey, grp.NewInt(1))
+	publicKey = diffieHellman.GeneratePublicKey(privKey, grp)
 	dhKey = grp.Exp(dhPubKey, privKey, grp.NewInt(1))
 
 	return dhKey, publicKey, nil
diff --git a/storage/session.go b/storage/session.go
index 89836d53ebf70a88a006e007e76c940927f7c9b1..1925d453bf8066b22921958c35519842340b5eb9 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -10,6 +10,8 @@
 package storage
 
 import (
+	"gitlab.com/elixxir/crypto/diffieHellman"
+	"math/rand"
 	"sync"
 	"testing"
 	"time"
@@ -30,13 +32,11 @@ import (
 	"gitlab.com/xx_network/primitives/ndf"
 )
 
-// Number of rounds to store in the CheckedRound buffer
-const CheckRoundsMaxSize = 1000000 / 64
 const currentSessionVersion = 0
 const cmixGroupKey = "cmixGroup"
 const e2eGroupKey = "e2eGroup"
 
-// Session object, backed by encrypted filestore
+// Session object, backed by encrypted versioned.KVc
 type Session interface {
 	GetClientVersion() version.Version
 	Get(key string) (*versioned.Object, error)
@@ -86,7 +86,7 @@ type session struct {
 	clientVersion *clientVersion.Store
 }
 
-// Initialize a new Session object
+// initStore initializes a new Session object
 func initStore(baseDir, password string) (*session, error) {
 	fs, err := ekv.NewFilestore(baseDir, password)
 	var s *session
@@ -102,7 +102,7 @@ func initStore(baseDir, password string) (*session, error) {
 	return s, nil
 }
 
-// Creates new UserData in the session
+// New UserData in the session
 func New(baseDir, password string, u user.Info,
 	currentVersion version.Version,
 	cmixGrp, e2eGrp *cyclic.Group) (Session, error) {
@@ -119,7 +119,7 @@ func New(baseDir, password string, u user.Info,
 	}
 
 	s.User, err = user.NewUser(s.kv, u.TransmissionID, u.ReceptionID, u.TransmissionSalt,
-		u.ReceptionSalt, u.TransmissionRSA, u.ReceptionRSA, u.Precanned)
+		u.ReceptionSalt, u.TransmissionRSA, u.ReceptionRSA, u.Precanned, u.E2eDhPrivateKey, u.E2eDhPublicKey)
 	if err != nil {
 		return nil, errors.WithMessage(err, "Failed to create user")
 	}
@@ -139,7 +139,7 @@ func New(baseDir, password string, u user.Info,
 	return s, nil
 }
 
-// Loads existing user data into the session
+// Load existing user data into the session
 func Load(baseDir, password string, currentVersion version.Version) (Session, error) {
 
 	s, err := initStore(baseDir, password)
@@ -196,7 +196,7 @@ func (s *session) Set(key string, object *versioned.Object) error {
 	return s.kv.Set(key, currentSessionVersion, object)
 }
 
-// delete a value in the session
+// Delete a value in the session
 func (s *session) Delete(key string) error {
 	return s.kv.Delete(key, currentSessionVersion)
 }
@@ -206,17 +206,17 @@ func (s *session) GetKV() *versioned.KV {
 	return s.kv
 }
 
-// GetCmixGrouo returns cMix Group
+// GetCmixGroup returns cMix Group
 func (s *session) GetCmixGroup() *cyclic.Group {
 	return s.cmixGroup
 }
 
-// GetE2EGrouo returns cMix Group
+// GetE2EGroup returns cMix Group
 func (s *session) GetE2EGroup() *cyclic.Group {
 	return s.e2eGroup
 }
 
-// Initializes a Session object wrapped around a MemStore object.
+// InitTestingSession object wrapped around a MemStore object.
 // FOR TESTING ONLY
 func InitTestingSession(i interface{}) Session {
 	switch i.(type) {
@@ -230,7 +230,14 @@ func InitTestingSession(i interface{}) Session {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	s := &session{kv: kv}
 	uid := id.NewIdFromString("zezima", id.User, i)
-	u, err := user.NewUser(kv, uid, uid, []byte("salt"), []byte("salt"), privKey, privKey, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := user.NewUser(kv, uid, uid, []byte("salt"), []byte("salt"), privKey, privKey, false, dhPrivKey, dhPubKey)
 	if err != nil {
 		jww.FATAL.Panicf("InitTestingSession failed to create dummy user: %+v", err)
 	}
diff --git a/storage/user/cryptographic.go b/storage/user/cryptographic.go
index fd4b73047008f6f0f78ad9a2f1b067372932aae6..8c245fc70ac257dc9eef14d9848be007c7831343 100644
--- a/storage/user/cryptographic.go
+++ b/storage/user/cryptographic.go
@@ -10,15 +10,19 @@ package user
 import (
 	"bytes"
 	"encoding/gob"
+	"encoding/json"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 )
 
-const currentCryptographicIdentityVersion = 0
+const originalCryptographicIdentityVersion = 0
+const currentCryptographicIdentityVersion = 1
 const cryptographicIdentityKey = "cryptographicIdentity"
 
 type CryptographicIdentity struct {
@@ -29,6 +33,8 @@ type CryptographicIdentity struct {
 	receptionSalt      []byte
 	receptionRsaKey    *rsa.PrivateKey
 	isPrecanned        bool
+	e2eDhPrivateKey    *cyclic.Int
+	e2eDhPublicKey     *cyclic.Int
 }
 
 type ciDisk struct {
@@ -41,10 +47,23 @@ type ciDisk struct {
 	IsPrecanned        bool
 }
 
+type ciDiskV1 struct {
+	TransmissionID     *id.ID
+	TransmissionSalt   []byte
+	TransmissionRsaKey *rsa.PrivateKey
+	ReceptionID        *id.ID
+	ReceptionSalt      []byte
+	ReceptionRsaKey    *rsa.PrivateKey
+	IsPrecanned        bool
+	E2eDhPrivateKey    []byte
+	E2eDhPublicKey     []byte
+}
+
 func newCryptographicIdentity(transmissionID, receptionID *id.ID,
 	transmissionSalt, receptionSalt []byte,
 	transmissionRsa, receptionRsa *rsa.PrivateKey,
-	isPrecanned bool, kv *versioned.KV) *CryptographicIdentity {
+	isPrecanned bool, e2eDhPrivateKey, e2eDhPublicKey *cyclic.Int,
+	kv *versioned.KV) *CryptographicIdentity {
 
 	ci := &CryptographicIdentity{
 		transmissionID:     transmissionID,
@@ -54,6 +73,8 @@ func newCryptographicIdentity(transmissionID, receptionID *id.ID,
 		receptionSalt:      receptionSalt,
 		receptionRsaKey:    receptionRsa,
 		isPrecanned:        isPrecanned,
+		e2eDhPrivateKey:    e2eDhPrivateKey,
+		e2eDhPublicKey:     e2eDhPublicKey,
 	}
 
 	if err := ci.save(kv); err != nil {
@@ -64,39 +85,115 @@ func newCryptographicIdentity(transmissionID, receptionID *id.ID,
 	return ci
 }
 
-func loadCryptographicIdentity(kv *versioned.KV) (*CryptographicIdentity, error) {
-	obj, err := kv.Get(cryptographicIdentityKey,
-		currentCryptographicIdentityVersion)
+// loadOriginalCryptographicIdentity attempts to load the originalCryptographicIdentityVersion CryptographicIdentity
+func loadOriginalCryptographicIdentity(kv *versioned.KV) (*CryptographicIdentity, error) {
+	result := &CryptographicIdentity{}
+	obj, err := kv.Get(cryptographicIdentityKey, originalCryptographicIdentityVersion)
 	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to get user "+
-			"cryptographic identity from EKV")
+		return nil, errors.WithMessagef(err, "Failed to get version %d user "+
+			"cryptographic identity from EKV", originalCryptographicIdentityVersion)
 	}
-
 	var resultBuffer bytes.Buffer
-	result := &CryptographicIdentity{}
 	decodable := &ciDisk{}
 
 	resultBuffer.Write(obj.Data)
 	dec := gob.NewDecoder(&resultBuffer)
 	err = dec.Decode(decodable)
+	if err != nil {
+		return nil, err
+	}
 
-	if decodable != nil {
-		result.isPrecanned = decodable.IsPrecanned
-		result.receptionRsaKey = decodable.ReceptionRsaKey
-		result.transmissionRsaKey = decodable.TransmissionRsaKey
-		result.transmissionSalt = decodable.TransmissionSalt
-		result.transmissionID = decodable.TransmissionID
-		result.receptionID = decodable.ReceptionID
-		result.receptionSalt = decodable.ReceptionSalt
+	result.isPrecanned = decodable.IsPrecanned
+	result.receptionRsaKey = decodable.ReceptionRsaKey
+	result.transmissionRsaKey = decodable.TransmissionRsaKey
+	result.transmissionSalt = decodable.TransmissionSalt
+	result.transmissionID = decodable.TransmissionID
+	result.receptionID = decodable.ReceptionID
+	result.receptionSalt = decodable.ReceptionSalt
+	return result, nil
+}
+
+func loadCryptographicIdentity(kv *versioned.KV) (*CryptographicIdentity, error) {
+	result := &CryptographicIdentity{}
+	obj, err := kv.Get(cryptographicIdentityKey,
+		currentCryptographicIdentityVersion)
+	if err != nil {
+		result, err = loadOriginalCryptographicIdentity(kv)
+		if err != nil {
+			return nil, err
+		}
+		jww.WARN.Printf("Attempting to migrate cryptographic identity to new version...")
+		// Populate E2E keys from legacy storage
+		result.e2eDhPublicKey, result.e2eDhPrivateKey = loadLegacyDHKeys(kv)
+		// Migrate to the new version in storage
+		return result, result.save(kv)
+	}
+
+	decodable := &ciDiskV1{}
+	err = json.Unmarshal(obj.Data, decodable)
+	if err != nil {
+		return nil, err
 	}
 
-	return result, err
+	result.isPrecanned = decodable.IsPrecanned
+	result.receptionRsaKey = decodable.ReceptionRsaKey
+	result.transmissionRsaKey = decodable.TransmissionRsaKey
+	result.transmissionSalt = decodable.TransmissionSalt
+	result.transmissionID = decodable.TransmissionID
+	result.receptionID = decodable.ReceptionID
+	result.receptionSalt = decodable.ReceptionSalt
+
+	result.e2eDhPrivateKey = &cyclic.Int{}
+	err = result.e2eDhPrivateKey.UnmarshalJSON(decodable.E2eDhPrivateKey)
+	if err != nil {
+		return nil, err
+	}
+	result.e2eDhPublicKey = &cyclic.Int{}
+	err = result.e2eDhPublicKey.UnmarshalJSON(decodable.E2eDhPublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
+
+// loadLegacyDHKeys attempts to load DH Keys from legacy storage. It
+// prints a warning to the log as users should be using ReceptionIdentity
+// instead of PortableUserInfo
+func loadLegacyDHKeys(kv *versioned.KV) (pub, priv *cyclic.Int) {
+	// Legacy package prefixes and keys, see e2e/ratchet/storage.go
+	packagePrefix := "e2eSession"
+	pubKeyKey := "DhPubKey"
+	privKeyKey := "DhPrivKey"
+
+	kvPrefix := kv.Prefix(packagePrefix)
+
+	privKey, err := utility.LoadCyclicKey(kvPrefix, privKeyKey)
+	if err != nil {
+		jww.ERROR.Printf("Failed to load e2e DH private key: %v", err)
+		return nil, nil
+	}
+
+	pubKey, err := utility.LoadCyclicKey(kvPrefix, pubKeyKey)
+	if err != nil {
+		jww.ERROR.Printf("Failed to load e2e DH public key: %v", err)
+		return nil, nil
+	}
+
+	return pubKey, privKey
 }
 
 func (ci *CryptographicIdentity) save(kv *versioned.KV) error {
-	var userDataBuffer bytes.Buffer
+	dhPriv, err := ci.e2eDhPrivateKey.MarshalJSON()
+	if err != nil {
+		return err
+	}
+	dhPub, err := ci.e2eDhPublicKey.MarshalJSON()
+	if err != nil {
+		return err
+	}
 
-	encodable := &ciDisk{
+	encodable := &ciDiskV1{
 		TransmissionID:     ci.transmissionID,
 		TransmissionSalt:   ci.transmissionSalt,
 		TransmissionRsaKey: ci.transmissionRsaKey,
@@ -104,10 +201,11 @@ func (ci *CryptographicIdentity) save(kv *versioned.KV) error {
 		ReceptionSalt:      ci.receptionSalt,
 		ReceptionRsaKey:    ci.receptionRsaKey,
 		IsPrecanned:        ci.isPrecanned,
+		E2eDhPrivateKey:    dhPriv,
+		E2eDhPublicKey:     dhPub,
 	}
 
-	enc := gob.NewEncoder(&userDataBuffer)
-	err := enc.Encode(encodable)
+	enc, err := json.Marshal(&encodable)
 	if err != nil {
 		return err
 	}
@@ -115,7 +213,7 @@ func (ci *CryptographicIdentity) save(kv *versioned.KV) error {
 	obj := &versioned.Object{
 		Version:   currentCryptographicIdentityVersion,
 		Timestamp: netTime.Now(),
-		Data:      userDataBuffer.Bytes(),
+		Data:      enc,
 	}
 
 	return kv.Set(cryptographicIdentityKey,
@@ -149,3 +247,11 @@ func (ci *CryptographicIdentity) GetTransmissionRSA() *rsa.PrivateKey {
 func (ci *CryptographicIdentity) IsPrecanned() bool {
 	return ci.isPrecanned
 }
+
+func (ci *CryptographicIdentity) GetE2eDhPublicKey() *cyclic.Int {
+	return ci.e2eDhPublicKey.DeepCopy()
+}
+
+func (ci *CryptographicIdentity) GetE2eDhPrivateKey() *cyclic.Int {
+	return ci.e2eDhPrivateKey.DeepCopy()
+}
diff --git a/storage/user/cryptographic_test.go b/storage/user/cryptographic_test.go
index 1096ccf683e288ae99577bc14989ab3fd71af599..0b9f92d9525600ad66c7746dbda12fa06fc6a318 100644
--- a/storage/user/cryptographic_test.go
+++ b/storage/user/cryptographic_test.go
@@ -11,7 +11,10 @@ import (
 	"bytes"
 	"crypto/rand"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"testing"
@@ -22,11 +25,19 @@ func TestNewCryptographicIdentity(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("zezima", id.User, t)
 	salt := []byte("salt")
-	_ = newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, kv)
 
-	_, err := kv.Get(cryptographicIdentityKey, 0)
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	_ = newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey, kv)
+
+	_, err := kv.Get(cryptographicIdentityKey, currentCryptographicIdentityVersion)
 	if err != nil {
-		t.Errorf("Did not store cryptographic identity")
+		t.Errorf("Did not store cryptographic identity: %+v", err)
 	}
 }
 
@@ -35,7 +46,15 @@ func TestLoadCryptographicIdentity(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("zezima", id.User, t)
 	salt := []byte("salt")
-	ci := newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey, kv)
 
 	err := ci.save(kv)
 	if err != nil {
@@ -64,7 +83,15 @@ func TestCryptographicIdentity_GetReceptionRSA(t *testing.T) {
 		t.Errorf("Failed to generate pk2")
 	}
 	salt := []byte("salt")
-	ci := newCryptographicIdentity(uid, uid, salt, salt, pk1, pk2, false, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(
+		uid, uid, salt, salt, pk1, pk2, false, dhPrivKey, dhPubKey, kv)
 	if ci.GetReceptionRSA().D != pk2.D {
 		t.Errorf("Did not receive expected RSA key.  Expected: %+v, Received: %+v", pk2, ci.GetReceptionRSA())
 	}
@@ -83,7 +110,15 @@ func TestCryptographicIdentity_GetTransmissionRSA(t *testing.T) {
 		t.Errorf("Failed to generate pk2")
 	}
 	salt := []byte("salt")
-	ci := newCryptographicIdentity(uid, uid, salt, salt, pk1, pk2, false, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(
+		uid, uid, salt, salt, pk1, pk2, false, dhPrivKey, dhPubKey, kv)
 	if ci.GetTransmissionRSA().D != pk1.D {
 		t.Errorf("Did not receive expected RSA key.  Expected: %+v, Received: %+v", pk1, ci.GetTransmissionRSA())
 	}
@@ -95,7 +130,15 @@ func TestCryptographicIdentity_GetTransmissionSalt(t *testing.T) {
 	uid := id.NewIdFromString("zezima", id.User, t)
 	ts := []byte("transmission salt")
 	rs := []byte("reception salt")
-	ci := newCryptographicIdentity(uid, uid, ts, rs, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(uid, uid, ts, rs, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey, kv)
 	if bytes.Compare(ci.GetTransmissionSalt(), ts) != 0 {
 		t.Errorf("Did not get expected salt.  Expected: %+v, Received: %+v", ts, ci.GetTransmissionSalt())
 	}
@@ -107,7 +150,15 @@ func TestCryptographicIdentity_GetReceptionSalt(t *testing.T) {
 	uid := id.NewIdFromString("zezima", id.User, t)
 	ts := []byte("transmission salt")
 	rs := []byte("reception salt")
-	ci := newCryptographicIdentity(uid, uid, ts, rs, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(uid, uid, ts, rs, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey, kv)
 	if bytes.Compare(ci.GetReceptionSalt(), rs) != 0 {
 		t.Errorf("Did not get expected salt.  Expected: %+v, Received: %+v", rs, ci.GetReceptionSalt())
 	}
@@ -119,7 +170,14 @@ func TestCryptographicIdentity_GetTransmissionID(t *testing.T) {
 	rid := id.NewIdFromString("zezima", id.User, t)
 	tid := id.NewIdFromString("jakexx360", id.User, t)
 	salt := []byte("salt")
-	ci := newCryptographicIdentity(tid, rid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(tid, rid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, dhPrivKey, dhPubKey, kv)
 	if !ci.GetTransmissionID().Cmp(tid) {
 		t.Errorf("Did not receive expected user ID.  Expected: %+v, Received: %+v", tid, ci.GetTransmissionID())
 	}
@@ -131,7 +189,14 @@ func TestCryptographicIdentity_GetReceptionID(t *testing.T) {
 	rid := id.NewIdFromString("zezima", id.User, t)
 	tid := id.NewIdFromString("jakexx360", id.User, t)
 	salt := []byte("salt")
-	ci := newCryptographicIdentity(tid, rid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(tid, rid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, dhPrivKey, dhPubKey, kv)
 	if !ci.GetReceptionID().Cmp(rid) {
 		t.Errorf("Did not receive expected user ID.  Expected: %+v, Received: %+v", rid, ci.GetReceptionID())
 	}
@@ -142,7 +207,14 @@ func TestCryptographicIdentity_IsPrecanned(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("zezima", id.User, t)
 	salt := []byte("salt")
-	ci := newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, true, kv)
+
+	prng := rand.Reader
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, true, dhPrivKey, dhPubKey, kv)
 	if !ci.IsPrecanned() {
 		t.Error("I really don't know how this could happen")
 	}
diff --git a/storage/user/info.go b/storage/user/info.go
index 3da77bb13935d863e382e26ad55aa529f1b63b6b..fc272cb0fe134b767e399b4bb9fca2a8cd3411e4 100644
--- a/storage/user/info.go
+++ b/storage/user/info.go
@@ -94,10 +94,8 @@ func (u *User) PortableUserInfo() Info {
 		ReceptionSalt:         copySlice(ci.GetReceptionSalt()),
 		ReceptionRSA:          ci.GetReceptionRSA(),
 		Precanned:             ci.IsPrecanned(),
-		//fixme: set these in the e2e layer, the command line layer
-		//needs more logical separation so this can be removed
-		E2eDhPrivateKey: nil,
-		E2eDhPublicKey:  nil,
+		E2eDhPrivateKey:       ci.GetE2eDhPrivateKey(),
+		E2eDhPublicKey:        ci.GetE2eDhPublicKey(),
 	}
 
 }
diff --git a/storage/user/registation_test.go b/storage/user/registation_test.go
index cec369ea41ca74c63ea972e3455a4b577ebcd464..346e662758223a755e13c5e19186002ae6b9ec6f 100644
--- a/storage/user/registation_test.go
+++ b/storage/user/registation_test.go
@@ -11,10 +11,14 @@ import (
 	"bytes"
 	"encoding/binary"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
+	"math/rand"
 	"testing"
 	"time"
 )
@@ -24,7 +28,15 @@ func TestUser_GetRegistrationValidationSignature(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("test", id.User, t)
 	salt := []byte("salt")
-	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
@@ -59,7 +71,15 @@ func TestUser_SetRegistrationValidationSignature(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("test", id.User, t)
 	salt := []byte("salt")
-	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
@@ -102,7 +122,15 @@ func TestUser_loadRegistrationValidationSignature(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("test", id.User, t)
 	salt := []byte("salt")
-	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
@@ -145,7 +173,15 @@ func TestUser_GetRegistrationTimestamp(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("test", id.User, t)
 	salt := []byte("salt")
-	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
@@ -194,7 +230,15 @@ func TestUser_loadRegistrationTimestamp(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("test", id.User, t)
 	salt := []byte("salt")
-	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
diff --git a/storage/user/user.go b/storage/user/user.go
index e79abf3300c039ab8f097672bc6e62ca8a47f286..5b84321a97cc169df474ab2ebd602bfb2769c0b1 100644
--- a/storage/user/user.go
+++ b/storage/user/user.go
@@ -10,6 +10,7 @@ package user
 import (
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"sync"
@@ -33,9 +34,11 @@ type User struct {
 
 // builds a new user.
 func NewUser(kv *versioned.KV, transmissionID, receptionID *id.ID, transmissionSalt,
-	receptionSalt []byte, transmissionRsa, receptionRsa *rsa.PrivateKey, isPrecanned bool) (*User, error) {
+	receptionSalt []byte, transmissionRsa, receptionRsa *rsa.PrivateKey, isPrecanned bool,
+	e2eDhPrivateKey, e2eDhPublicKey *cyclic.Int) (*User, error) {
 
-	ci := newCryptographicIdentity(transmissionID, receptionID, transmissionSalt, receptionSalt, transmissionRsa, receptionRsa, isPrecanned, kv)
+	ci := newCryptographicIdentity(transmissionID, receptionID, transmissionSalt,
+		receptionSalt, transmissionRsa, receptionRsa, isPrecanned, e2eDhPrivateKey, e2eDhPublicKey, kv)
 
 	return &User{CryptographicIdentity: ci, kv: kv}, nil
 }
diff --git a/storage/user/user_test.go b/storage/user/user_test.go
index 01a93088c1e54c7d2b6d03a6d5a6a1cb0cfb8803..9198e48f607e3c25d79d74242f7607819a83efd1 100644
--- a/storage/user/user_test.go
+++ b/storage/user/user_test.go
@@ -9,9 +9,13 @@ package user
 
 import (
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
+	"math/rand"
 	"testing"
 )
 
@@ -26,7 +30,15 @@ func TestLoadUser(t *testing.T) {
 
 	uid := id.NewIdFromString("test", id.User, t)
 	salt := []byte("salt")
-	ci := newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false, kv)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	ci := newCryptographicIdentity(uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey, kv)
 	err = ci.save(kv)
 	if err != nil {
 		t.Errorf("Failed to save ci to kv: %+v", err)
@@ -43,7 +55,15 @@ func TestNewUser(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	uid := id.NewIdFromString("test", id.User, t)
 	salt := []byte("salt")
-	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, uid, uid, salt, salt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
diff --git a/storage/user/username_test.go b/storage/user/username_test.go
index f4a851145b8296bdab49b07bb6996d51344dc2ae..a52b20ac003d692c38ba632299354bb8ce698faf 100644
--- a/storage/user/username_test.go
+++ b/storage/user/username_test.go
@@ -9,10 +9,14 @@ package user
 
 import (
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
+	"math/rand"
 	"testing"
 )
 
@@ -23,7 +27,15 @@ func TestUser_SetUsername(t *testing.T) {
 	rid := id.NewIdFromString("recv", id.User, t)
 	tsalt := []byte("tsalt")
 	rsalt := []byte("rsalt")
-	u, err := NewUser(kv, tid, rid, tsalt, rsalt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, tid, rid, tsalt, rsalt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
@@ -57,7 +69,15 @@ func TestUser_GetUsername(t *testing.T) {
 	rid := id.NewIdFromString("recv", id.User, t)
 	tsalt := []byte("tsalt")
 	rsalt := []byte("rsalt")
-	u, err := NewUser(kv, tid, rid, tsalt, rsalt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, tid, rid, tsalt, rsalt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
@@ -85,7 +105,15 @@ func TestUser_loadUsername(t *testing.T) {
 	rid := id.NewIdFromString("recv", id.User, t)
 	tsalt := []byte("tsalt")
 	rsalt := []byte("rsalt")
-	u, err := NewUser(kv, tid, rid, tsalt, rsalt, &rsa.PrivateKey{}, &rsa.PrivateKey{}, false)
+
+	prng := rand.New(rand.NewSource(42))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng)
+	dhPubKey := diffieHellman.GeneratePublicKey(dhPrivKey, grp)
+
+	u, err := NewUser(kv, tid, rid, tsalt, rsalt, &rsa.PrivateKey{},
+		&rsa.PrivateKey{}, false, dhPrivKey, dhPubKey)
 	if err != nil || u == nil {
 		t.Errorf("Failed to create new user: %+v", err)
 	}
diff --git a/ud/register.go b/ud/register.go
index 591a1cf1fd218c9afc9b84af5d53c4300505914e..07c7fcdb942b2f96726af26a5e1deeac92fc2278 100644
--- a/ud/register.go
+++ b/ud/register.go
@@ -3,6 +3,7 @@ package ud
 import (
 	"github.com/pkg/errors"
 	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/crypto/factID"
 	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/fact"
@@ -30,7 +31,7 @@ func (m *Manager) register(username string, rng csprng.Source,
 	if err != nil {
 		return err
 	}
-	dhKeyPub := grp.ExpG(dhKeyPriv, grp.NewInt(1))
+	dhKeyPub := diffieHellman.GeneratePublicKey(dhKeyPriv, grp)
 
 	// Construct the user registration message
 	msg := &pb.UDBUserRegistration{
diff --git a/xxdk/identity.go b/xxdk/identity.go
index 0d3f5d54771fa7cdf7ee8353624313c5beac92d3..8d4b392d8c79ea47fb39afa03f877542c8c2e0d0 100644
--- a/xxdk/identity.go
+++ b/xxdk/identity.go
@@ -8,6 +8,8 @@ package xxdk
 
 import (
 	"encoding/json"
+	"gitlab.com/elixxir/primitives/fact"
+
 	"gitlab.com/elixxir/client/storage/user"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/contact"
@@ -172,12 +174,11 @@ func (r ReceptionIdentity) GetContact() contact.Contact {
 	grp, _ := r.GetGroup()
 	dhKeyPriv, _ := r.GetDHKeyPrivate()
 
-	dhPub := grp.ExpG(dhKeyPriv, grp.NewInt(1))
 	ct := contact.Contact{
 		ID:             r.ID,
-		DhPubKey:       dhPub,
+		DhPubKey:       diffieHellman.GeneratePublicKey(dhKeyPriv, grp),
 		OwnershipProof: nil,
-		Facts:          nil,
+		Facts:          make([]fact.Fact, 0),
 	}
 	return ct
 }
diff --git a/xxdk/precan.go b/xxdk/precan.go
index a515a598e1d5f1e525bef2fb1fbaac0cefe56142..98edf51028937e17a0e555c7de1d91b60a3ff35b 100644
--- a/xxdk/precan.go
+++ b/xxdk/precan.go
@@ -9,11 +9,12 @@ package xxdk
 
 import (
 	"encoding/binary"
+	"math/rand"
+
 	"github.com/cloudflare/circl/dh/sidh"
 	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
 	util "gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/crypto/contact"
-	"math/rand"
 
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage"
@@ -60,9 +61,18 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string,
 func (m *E2e) MakePrecannedAuthenticatedChannel(precannedID uint) (
 	contact.Contact, error) {
 
-	precan := m.GetReceptionIdentity().GetContact()
+	rng := m.GetRng().GetStream()
+	precanUserInfo := createPrecannedUser(precannedID, rng, m.GetStorage().GetE2EGroup())
+	rng.Close()
+	precanRecipient, err := buildReceptionIdentity(precanUserInfo.ReceptionID,
+		precanUserInfo.ReceptionSalt, precanUserInfo.ReceptionRSA,
+		m.GetStorage().GetE2EGroup(), precanUserInfo.E2eDhPrivateKey)
+	if err != nil {
+		return contact.Contact{}, err
+	}
+	precanContact := precanRecipient.GetContact()
 
-	myID := binary.BigEndian.Uint64(m.GetStorage().GetReceptionID()[:])
+	myID := binary.BigEndian.Uint64(m.GetReceptionIdentity().ID[:])
 	// Pick a variant based on if their ID is bigger than mine.
 	myVariant := sidh.KeyVariantSidhA
 	theirVariant := sidh.KeyVariant(sidh.KeyVariantSidhB)
@@ -73,7 +83,7 @@ func (m *E2e) MakePrecannedAuthenticatedChannel(precannedID uint) (
 	prng1 := rand.New(rand.NewSource(int64(precannedID)))
 	theirSIDHPrivKey := util.NewSIDHPrivateKey(theirVariant)
 	theirSIDHPubKey := util.NewSIDHPublicKey(theirVariant)
-	err := theirSIDHPrivKey.Generate(prng1)
+	err = theirSIDHPrivKey.Generate(prng1)
 	if err != nil {
 		return contact.Contact{}, err
 	}
@@ -91,7 +101,7 @@ func (m *E2e) MakePrecannedAuthenticatedChannel(precannedID uint) (
 	// add the precanned user as a e2e contact
 	// FIXME: these params need to be threaded through...
 	sesParam := session.GetDefaultParams()
-	_, err = m.e2e.AddPartner(precan.ID, precan.DhPubKey,
+	_, err = m.e2e.AddPartner(precanContact.ID, precanContact.DhPubKey,
 		m.e2e.GetHistoricalDHPrivkey(), theirSIDHPubKey,
 		mySIDHPrivKey, sesParam, sesParam)
 
@@ -99,5 +109,5 @@ func (m *E2e) MakePrecannedAuthenticatedChannel(precannedID uint) (
 	// the channel
 	m.GetCmix().CheckInProgressMessages()
 
-	return precan, err
+	return precanContact, err
 }
diff --git a/xxdk/user.go b/xxdk/user.go
index 8b513fd6e39e27d758c43ffd16f1d393c751aa97..747fb3dbef16f64e0bb47cece6896b51477218da 100644
--- a/xxdk/user.go
+++ b/xxdk/user.go
@@ -39,7 +39,7 @@ func createNewUser(rng *fastRNG.StreamGenerator, e2eGroup *cyclic.Group) user.In
 	var transmissionSalt, receptionSalt []byte
 
 	e2eKeyBytes, transmissionSalt, receptionSalt,
-		transmissionRsaKey, receptionRsaKey := createDhKeys(rng, e2eGroup)
+		transmissionRsaKey, receptionRsaKey := createKeys(rng, e2eGroup)
 
 	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(),
 		transmissionSalt, id.User)
@@ -53,6 +53,7 @@ func createNewUser(rng *fastRNG.StreamGenerator, e2eGroup *cyclic.Group) user.In
 		jww.FATAL.Panicf(err.Error())
 	}
 
+	dhPrivKey := e2eGroup.NewIntFromBytes(e2eKeyBytes)
 	return user.Info{
 		TransmissionID:   transmissionID.DeepCopy(),
 		TransmissionSalt: transmissionSalt,
@@ -61,12 +62,12 @@ func createNewUser(rng *fastRNG.StreamGenerator, e2eGroup *cyclic.Group) user.In
 		ReceptionSalt:    receptionSalt,
 		ReceptionRSA:     receptionRsaKey,
 		Precanned:        false,
-		E2eDhPrivateKey:  e2eGroup.NewIntFromBytes(e2eKeyBytes),
-		E2eDhPublicKey:   nil,
+		E2eDhPrivateKey:  dhPrivKey,
+		E2eDhPublicKey:   diffieHellman.GeneratePublicKey(dhPrivKey, e2eGroup),
 	}
 }
 
-func createDhKeys(rng *fastRNG.StreamGenerator,
+func createKeys(rng *fastRNG.StreamGenerator,
 	e2e *cyclic.Group) (e2eKeyBytes,
 	transmissionSalt, receptionSalt []byte,
 	transmissionRsaKey, receptionRsaKey *rsa.PrivateKey) {
@@ -95,6 +96,11 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
 		var err error
 		stream := rng.GetStream()
 		transmissionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen)
+		if err != nil {
+			jww.FATAL.Panicf(err.Error())
+		}
+		transmissionSalt = make([]byte, SaltSize)
+		_, err = stream.Read(transmissionSalt)
 		stream.Close()
 		if err != nil {
 			jww.FATAL.Panicf(err.Error())
@@ -106,6 +112,11 @@ func createDhKeys(rng *fastRNG.StreamGenerator,
 		var err error
 		stream := rng.GetStream()
 		receptionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen)
+		if err != nil {
+			jww.FATAL.Panicf(err.Error())
+		}
+		receptionSalt = make([]byte, SaltSize)
+		_, err = stream.Read(receptionSalt)
 		stream.Close()
 		if err != nil {
 			jww.FATAL.Panicf(err.Error())
@@ -185,7 +196,7 @@ func createNewVanityUser(rng csprng.Source,
 			for {
 				select {
 				case <-done:
-					defer wg.Done()
+					wg.Done()
 					return
 				default:
 					n, err = csprng.NewSystemRNG().Read(
@@ -205,17 +216,17 @@ func createNewVanityUser(rng csprng.Source,
 					if err != nil {
 						jww.FATAL.Panicf(err.Error())
 					}
-					id := rID.String()
+					rid := rID.String()
 					if ignoreCase {
-						id = strings.ToLower(id)
+						rid = strings.ToLower(rid)
 					}
-					if strings.HasPrefix(id, pref) {
+					if strings.HasPrefix(rid, pref) {
 						mu.Lock()
 						receptionID = rID
 						receptionSalt = rSalt
 						mu.Unlock()
 						found <- true
-						defer wg.Done()
+						wg.Done()
 						return
 					}
 				}
@@ -241,17 +252,7 @@ func createNewVanityUser(rng csprng.Source,
 }
 
 // createPrecannedUser
-func createPrecannedUser(precannedID uint, rng csprng.Source, e2e *cyclic.Group) user.Info {
-	// DH Keygen
-	// FIXME: Why 256 bits? -- this is spec but not explained, it has
-	// to do with optimizing operations on one side and still preserves
-	// decent security -- cite this. Why valid for BOTH e2e and cmix?
-	prng := rand.New(rand.NewSource(int64(precannedID)))
-	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, prng)
-	if err != nil {
-		jww.FATAL.Panicf(err.Error())
-	}
-
+func createPrecannedUser(precannedID uint, rng csprng.Source, grp *cyclic.Group) user.Info {
 	// Salt, UID, etc gen
 	salt := make([]byte, SaltSize)
 
@@ -265,13 +266,18 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, e2e *cyclic.Group)
 		jww.FATAL.Panicf(err.Error())
 	}
 
+	prime := grp.GetPBytes()
+	keyLen := len(prime)
+	prng := rand.New(rand.NewSource(int64(precannedID)))
+	dhPrivKey := diffieHellman.GeneratePrivateKey(keyLen, grp, prng)
 	return user.Info{
 		TransmissionID:   &userID,
 		TransmissionSalt: salt,
 		ReceptionID:      &userID,
 		ReceptionSalt:    salt,
 		Precanned:        true,
-		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
+		E2eDhPrivateKey:  dhPrivKey,
+		E2eDhPublicKey:   diffieHellman.GeneratePublicKey(dhPrivKey, grp),
 		TransmissionRSA:  rsaKey,
 		ReceptionRSA:     rsaKey,
 	}