From 96034c6b581198eacd6380619541a240e85186e2 Mon Sep 17 00:00:00 2001
From: Jake Taylor <jake@elixxir.io>
Date: Wed, 29 Jun 2022 16:58:56 -0500
Subject: [PATCH] change structure of identities in api and bindings

---
 bindings/contact.go                |  16 +--
 bindings/e2e.go                    |  41 +-------
 cmd/broadcast.go                   |  17 ++--
 cmd/init.go                        |  22 ++--
 groupChat/groupStore/store_test.go |   2 +-
 groupChat/manager_test.go          |  28 ++---
 storage/user/info.go               |  10 --
 xxdk/cmix.go                       |  10 +-
 xxdk/e2e.go                        |  68 ++++++-------
 xxdk/identity.go                   | 158 +++++++++++++++++++++++++++--
 xxdk/permissioning.go              |  17 ++--
 11 files changed, 235 insertions(+), 154 deletions(-)

diff --git a/bindings/contact.go b/bindings/contact.go
index 251c810f4..82631bf6e 100644
--- a/bindings/contact.go
+++ b/bindings/contact.go
@@ -5,7 +5,6 @@ import (
 	"gitlab.com/elixxir/client/xxdk"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
-	"gitlab.com/xx_network/crypto/signature/rsa"
 )
 
 // ReceptionIdentity struct
@@ -27,23 +26,12 @@ type ReceptionIdentity struct {
 
 // MakeIdentity generates a new cryptographic identity for receiving messages
 func (c *Cmix) MakeIdentity() ([]byte, error) {
-	s := c.api.GetRng().GetStream()
-	defer s.Close()
-	ident, err := xxdk.MakeReceptionIdentity(s, c.api.GetStorage().GetE2EGroup())
-
-	dhPrivJson, err := ident.DHKeyPrivate.MarshalJSON()
+	ident, err := xxdk.MakeReceptionIdentity(c.api)
 	if err != nil {
 		return nil, err
 	}
-	//create the identity object
-	I := ReceptionIdentity{
-		ID:            ident.ID.Marshal(),
-		RSAPrivatePem: rsa.CreatePrivateKeyPem(ident.RSAPrivatePem),
-		Salt:          ident.Salt,
-		DHKeyPrivate:  dhPrivJson,
-	}
 
-	return json.Marshal(&I)
+	return ident.Marshal()
 }
 
 // GetIDFromContact accepts a marshalled contact.Contact object & returns a marshalled id.ID object
diff --git a/bindings/e2e.go b/bindings/e2e.go
index dffc2560f..8820d59f9 100644
--- a/bindings/e2e.go
+++ b/bindings/e2e.go
@@ -7,15 +7,11 @@
 package bindings
 
 import (
-	"encoding/json"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/xxdk"
 	"gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
 )
 
 // e2eTrackerSingleton is used to track E2e objects so that
@@ -46,7 +42,7 @@ func LoginE2e(cmixId int, callbacks AuthCallbacks, identity []byte) (*E2e, error
 		return nil, err
 	}
 
-	newIdentity, err := unmarshalIdentity(identity, cmix.api.GetStorage().GetE2EGroup())
+	newIdentity, err := xxdk.UnmarshalReceptionIdentity(identity)
 	if err != nil {
 		return nil, err
 	}
@@ -75,7 +71,7 @@ func LoginE2eEphemeral(cmixId int, callbacks AuthCallbacks, identity []byte) (*E
 		return nil, err
 	}
 
-	newIdentity, err := unmarshalIdentity(identity, cmix.api.GetStorage().GetE2EGroup())
+	newIdentity, err := xxdk.UnmarshalReceptionIdentity(identity)
 	if err != nil {
 		return nil, err
 	}
@@ -121,38 +117,7 @@ func LoginE2eLegacy(cmixId int, callbacks AuthCallbacks) (*E2e, error) {
 
 // GetContact returns a marshalled contact.Contact object for the E2e ReceptionIdentity
 func (e *E2e) GetContact() []byte {
-	return e.api.GetReceptionIdentity().GetContact(e.api.GetStorage().GetE2EGroup()).Marshal()
-}
-
-// unmarshalIdentity is a helper function for taking in a marshalled xxdk.ReceptionIdentity and making it an object
-func unmarshalIdentity(marshaled []byte, e2eGrp *cyclic.Group) (xxdk.ReceptionIdentity, error) {
-	newIdentity := xxdk.ReceptionIdentity{}
-
-	// Unmarshal given identity into ReceptionIdentity object
-	givenIdentity := ReceptionIdentity{}
-	err := json.Unmarshal(marshaled, &givenIdentity)
-	if err != nil {
-		return xxdk.ReceptionIdentity{}, err
-	}
-
-	newIdentity.ID, err = id.Unmarshal(givenIdentity.ID)
-	if err != nil {
-		return xxdk.ReceptionIdentity{}, err
-	}
-
-	newIdentity.DHKeyPrivate = e2eGrp.NewInt(1)
-	err = newIdentity.DHKeyPrivate.UnmarshalJSON(givenIdentity.DHKeyPrivate)
-	if err != nil {
-		return xxdk.ReceptionIdentity{}, err
-	}
-
-	newIdentity.RSAPrivatePem, err = rsa.LoadPrivateKeyFromPem(givenIdentity.RSAPrivatePem)
-	if err != nil {
-		return xxdk.ReceptionIdentity{}, err
-	}
-
-	newIdentity.Salt = givenIdentity.Salt
-	return newIdentity, nil
+	return e.api.GetReceptionIdentity().GetContact().Marshal()
 }
 
 // AuthCallbacks is the bindings-specific interface for auth.Callbacks methods.
diff --git a/cmd/broadcast.go b/cmd/broadcast.go
index 8b9ae2358..c4c1209e9 100644
--- a/cmd/broadcast.go
+++ b/cmd/broadcast.go
@@ -26,9 +26,8 @@ var broadcastCmd = &cobra.Command{
 		client := initClient()
 
 		// Write user contact to file
-		user := client.GetUser()
-		jww.INFO.Printf("User: %s", user.ReceptionID)
-		jww.INFO.Printf("User Transmission: %s", user.TransmissionID)
+		user := client.GetReceptionIdentity()
+		jww.INFO.Printf("User: %s", user.ID)
 		writeContact(user.GetContact())
 
 		err := client.StartNetworkFollower(5 * time.Second)
@@ -39,8 +38,8 @@ var broadcastCmd = &cobra.Command{
 		// Wait until connected or crash on timeout
 		connected := make(chan bool, 10)
 		client.GetCmix().AddHealthCallback(
-			func(isconnected bool) {
-				connected <- isconnected
+			func(isConnected bool) {
+				connected <- isConnected
 			})
 		waitUntilConnected(connected)
 
@@ -69,10 +68,10 @@ var broadcastCmd = &cobra.Command{
 				jww.FATAL.Panicf("description cannot be empty")
 			}
 
-			var channel *crypto.Channel
+			var cryptChannel *crypto.Channel
 			if viper.GetBool("new") {
 				// Create a new broadcast channel
-				channel, pk, err = crypto.NewChannel(name, desc, client.GetRng().GetStream())
+				cryptChannel, pk, err = crypto.NewChannel(name, desc, client.GetRng().GetStream())
 				if err != nil {
 					jww.FATAL.Panicf("Failed to create new channel: %+v", err)
 				}
@@ -99,7 +98,7 @@ var broadcastCmd = &cobra.Command{
 					jww.FATAL.Panicf("Failed to generate channel ID: %+v", err)
 				}
 
-				channel = &crypto.Channel{
+				cryptChannel = &crypto.Channel{
 					ReceptionID: rid,
 					Name:        name,
 					Description: desc,
@@ -126,7 +125,7 @@ var broadcastCmd = &cobra.Command{
 			}
 
 			// Save channel to disk
-			cBytes, err := channel.Marshal()
+			cBytes, err := cryptChannel.Marshal()
 			if err != nil {
 				jww.ERROR.Printf("Failed to marshal channel to bytes: %+v", err)
 			}
diff --git a/cmd/init.go b/cmd/init.go
index 6c42b9cfc..f5c7483d0 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -9,14 +9,15 @@
 package cmd
 
 import (
-	"fmt"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/xxdk"
 
 	"github.com/spf13/cobra"
-	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
 )
 
+const identityStorageKey = "identityStorageKey"
+
 // initCmd creates a new user object with the given NDF
 var initCmd = &cobra.Command{
 	Use:   "init",
@@ -24,16 +25,19 @@ var initCmd = &cobra.Command{
 	Args:  cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
 		client := createClient()
-		e2e, err := xxdk.LoadOrInitE2e(client)
+
+		identity, err := xxdk.MakeReceptionIdentity(client)
+		if err != nil {
+			return
+		}
+
+		err = xxdk.StoreReceptionIdentity(identityStorageKey, identity, client)
 		if err != nil {
-			jww.FATAL.Panicf("%+v", err)
+			return
 		}
-		user := client.GetUser()
-		user.E2eDhPublicKey = e2e.GetHistoricalDHPubkey()
 
-		jww.INFO.Printf("User: %s", user.ReceptionID)
-		writeContact(user.GetContact())
-		fmt.Printf("%s\n", user.ReceptionID)
+		jww.INFO.Printf("User: %s", identity.ID)
+		writeContact(identity.GetContact())
 	},
 }
 
diff --git a/groupChat/groupStore/store_test.go b/groupChat/groupStore/store_test.go
index a41439b73..e5549f06b 100644
--- a/groupChat/groupStore/store_test.go
+++ b/groupChat/groupStore/store_test.go
@@ -558,7 +558,7 @@ func TestStore_GetUser(t *testing.T) {
 	}
 
 	if !user.Equal(store.GetUser()) {
-		t.Errorf("GetUser() failed to return the expected member."+
+		t.Errorf("GetTransmissionIdentity() failed to return the expected member."+
 			"\nexpected: %#v\nreceived: %#v", user, store.GetUser())
 	}
 }
diff --git a/groupChat/manager_test.go b/groupChat/manager_test.go
index 374062ea8..de32491e4 100644
--- a/groupChat/manager_test.go
+++ b/groupChat/manager_test.go
@@ -170,26 +170,26 @@ func TestNewManager_LoadError(t *testing.T) {
 // 	m2, _ := newTestManagerWithStore(prng, 10, 0, requestFunc2, receiveFunc2, t)
 // 	m3, _ := newTestManagerWithStore(prng, 10, 0, requestFunc3, receiveFunc3, t)
 //
-// 	membership, err := group.NewMembership(m1.store.GetUser().Contact(),
-// 		m2.store.GetUser().Contact(), m3.store.GetUser().Contact())
+// 	membership, err := group.NewMembership(m1.store.GetTransmissionIdentity().Contact(),
+// 		m2.store.GetTransmissionIdentity().Contact(), m3.store.GetTransmissionIdentity().Contact())
 // 	if err != nil {
 // 		t.Errorf("Failed to generate new membership: %+v", err)
 // 	}
 //
-// 	dhKeys := gs.GenerateDhKeyList(m1.gs.GetUser().ID,
-// 		m1.store.GetUser().E2eDhPrivateKey, membership, m1.store.E2e().GetGroup())
+// 	dhKeys := gs.GenerateDhKeyList(m1.gs.GetTransmissionIdentity().ID,
+// 		m1.store.GetTransmissionIdentity().E2eDhPrivateKey, membership, m1.store.E2e().GetGroup())
 //
-// 	grp1 := newTestGroup(m1.store.E2e().GetGroup(), m1.store.GetUser().E2eDhPrivateKey, prng, t)
+// 	grp1 := newTestGroup(m1.store.E2e().GetGroup(), m1.store.GetTransmissionIdentity().E2eDhPrivateKey, prng, t)
 // 	grp1.Members = membership
 // 	grp1.DhKeys = dhKeys
 // 	grp1.ID = group.NewID(grp1.IdPreimage, grp1.Members)
 // 	grp1.Key = group.NewKey(grp1.KeyPreimage, grp1.Members)
 // 	grp2 := grp1.DeepCopy()
-// 	grp2.DhKeys = gs.GenerateDhKeyList(m2.gs.GetUser().ID,
-// 		m2.store.GetUser().E2eDhPrivateKey, membership, m2.store.E2e().GetGroup())
+// 	grp2.DhKeys = gs.GenerateDhKeyList(m2.gs.GetTransmissionIdentity().ID,
+// 		m2.store.GetTransmissionIdentity().E2eDhPrivateKey, membership, m2.store.E2e().GetGroup())
 // 	grp3 := grp1.DeepCopy()
-// 	grp3.DhKeys = gs.GenerateDhKeyList(m3.gs.GetUser().ID,
-// 		m3.store.GetUser().E2eDhPrivateKey, membership, m3.store.E2e().GetGroup())
+// 	grp3.DhKeys = gs.GenerateDhKeyList(m3.gs.GetTransmissionIdentity().ID,
+// 		m3.store.GetTransmissionIdentity().E2eDhPrivateKey, membership, m3.store.E2e().GetGroup())
 //
 // 	err = m1.gs.Add(grp1)
 // 	if err != nil {
@@ -222,7 +222,7 @@ func TestNewManager_LoadError(t *testing.T) {
 // 	msg := message.Receive{
 // 		Payload:     requestMarshaled,
 // 		MessageType: message.GroupCreationRequest,
-// 		Sender:      m1.gs.GetUser().ID,
+// 		Sender:      m1.gs.GetTransmissionIdentity().ID,
 // 	}
 //
 // 	m2.swb.(*switchboard.Switchboard).Speak(msg)
@@ -252,14 +252,14 @@ func TestNewManager_LoadError(t *testing.T) {
 // 	timestamp := netTime.Now()
 //
 // 	// Create cMix message and get public message
-// 	cMixMsg, err := m1.newCmixMsg(grp1, contents, timestamp, m2.gs.GetUser(), prng)
+// 	cMixMsg, err := m1.newCmixMsg(grp1, contents, timestamp, m2.gs.GetTransmissionIdentity(), prng)
 // 	if err != nil {
 // 		t.Errorf("Failed to create new cMix message: %+v", err)
 // 	}
 //
 // 	internalMsg, _ := newInternalMsg(cMixMsg.ContentsSize() - publicMinLen)
 // 	internalMsg.SetTimestamp(timestamp)
-// 	internalMsg.SetSenderID(m1.gs.GetUser().ID)
+// 	internalMsg.SetSenderID(m1.gs.GetTransmissionIdentity().ID)
 // 	internalMsg.SetPayload(contents)
 // 	expectedMsgID := group.NewMessageID(grp1.ID, internalMsg.Marshal())
 //
@@ -267,14 +267,14 @@ func TestNewManager_LoadError(t *testing.T) {
 // 		GroupID:        grp1.ID,
 // 		ID:             expectedMsgID,
 // 		Payload:        contents,
-// 		SenderID:       m1.gs.GetUser().ID,
+// 		SenderID:       m1.gs.GetTransmissionIdentity().ID,
 // 		RoundTimestamp: timestamp.Local(),
 // 	}
 //
 // 	msg = message.Receive{
 // 		Payload:        cMixMsg.Marshal(),
 // 		MessageType:    message.Raw,
-// 		Sender:         m1.gs.GetUser().ID,
+// 		Sender:         m1.gs.GetTransmissionIdentity().ID,
 // 		RoundTimestamp: timestamp.Local(),
 // 	}
 // 	m2.swb.(*switchboard.Switchboard).Speak(msg)
diff --git a/storage/user/info.go b/storage/user/info.go
index 62603c222..3da77bb13 100644
--- a/storage/user/info.go
+++ b/storage/user/info.go
@@ -9,9 +9,7 @@ package user
 
 import (
 	"gitlab.com/elixxir/crypto/backup"
-	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 )
@@ -55,14 +53,6 @@ type Info struct {
 	E2eDhPublicKey  *cyclic.Int
 }
 
-func (u Info) GetContact() contact.Contact {
-	return contact.Contact{
-		ID:       u.ReceptionID.DeepCopy(),
-		DhPubKey: u.E2eDhPublicKey,
-		Facts:    make([]fact.Fact, 0),
-	}
-}
-
 func NewUserFromProto(proto *Proto) Info {
 	return Info{
 		TransmissionID:        proto.TransmissionID,
diff --git a/xxdk/cmix.go b/xxdk/cmix.go
index 059c9d061..54aa051cb 100644
--- a/xxdk/cmix.go
+++ b/xxdk/cmix.go
@@ -392,7 +392,6 @@ func (c *Cmix) StopNetworkFollower() error {
 
 // NetworkFollowerStatus Gets the state of the network follower. Returns:
 // Stopped 	- 0
-// Starting - 1000
 // Running	- 2000
 // Stopping	- 3000
 func (c *Cmix) NetworkFollowerStatus() Status {
@@ -421,12 +420,11 @@ func (c *Cmix) AddService(sp Service) error {
 	return c.followerServices.add(sp)
 }
 
-// GetUser returns the current user Identity for this client. This
-// can be serialized into a byte stream for out-of-band sharing.
-func (c *Cmix) GetUser() user.Info {
-	jww.INFO.Printf("GetUser()")
+// GetTransmissionIdentity returns the current TransmissionIdentity for this client
+func (c *Cmix) GetTransmissionIdentity() TransmissionIdentity {
+	jww.INFO.Printf("GetTransmissionIdentity()")
 	cMixUser := c.storage.PortableUserInfo()
-	return cMixUser
+	return buildTransmissionIdentity(cMixUser)
 }
 
 // GetComms returns the client comms object
diff --git a/xxdk/e2e.go b/xxdk/e2e.go
index e528c6335..34271b209 100644
--- a/xxdk/e2e.go
+++ b/xxdk/e2e.go
@@ -76,7 +76,9 @@ func LoginLegacy(client *Cmix, callbacks AuthCallbacks) (m *E2e, err error) {
 	if err != nil {
 		return nil, err
 	}
-	client.GetCmix().AddIdentity(client.GetUser().ReceptionID, time.Time{}, true)
+
+	userInfo := client.GetStorage().PortableUserInfo()
+	client.GetCmix().AddIdentity(userInfo.ReceptionID, time.Time{}, true)
 
 	err = client.AddService(m.e2e.StartProcesses)
 	if err != nil {
@@ -91,14 +93,7 @@ func LoginLegacy(client *Cmix, callbacks AuthCallbacks) (m *E2e, err error) {
 		return nil, err
 	}
 
-	u := m.Cmix.GetUser()
-	m.e2eIdentity = ReceptionIdentity{
-		ID:            u.TransmissionID,
-		RSAPrivatePem: u.TransmissionRSA,
-		Salt:          u.TransmissionSalt,
-		DHKeyPrivate:  u.E2eDhPrivateKey,
-	}
-
+	m.e2eIdentity, err = buildReceptionIdentity(userInfo, m.e2e.GetGroup(), m.e2e.GetHistoricalDHPrivkey())
 	return m, err
 }
 
@@ -183,12 +178,9 @@ func LoginWithProtoClient(storageDir string, password []byte,
 		return nil, err
 	}
 
-	return Login(c, callbacks, ReceptionIdentity{
-		ID:            protoUser.ReceptionID,
-		RSAPrivatePem: protoUser.ReceptionRSA,
-		Salt:          protoUser.ReceptionSalt,
-		DHKeyPrivate:  protoUser.E2eDhPrivateKey,
-	})
+	userInfo := c.GetStorage().PortableUserInfo()
+	receptionIdentity, err := buildReceptionIdentity(userInfo, c.GetStorage().GetE2EGroup(), protoUser.E2eDhPrivateKey)
+	return Login(c, callbacks, receptionIdentity)
 }
 
 // login creates a new xxdk.E2e backed by the given versioned.KV
@@ -196,7 +188,11 @@ func login(client *Cmix, callbacks AuthCallbacks,
 	identity ReceptionIdentity, kv *versioned.KV) (m *E2e, err error) {
 
 	// Verify the passed-in ReceptionIdentity matches its properties
-	generatedId, err := xx.NewID(identity.RSAPrivatePem.GetPublic(), identity.Salt, id.User)
+	privatePem, err := identity.GetRSAPrivatePem()
+	if err != nil {
+		return nil, err
+	}
+	generatedId, err := xx.NewID(privatePem.GetPublic(), identity.Salt, id.User)
 	if err != nil {
 		return nil, err
 	}
@@ -215,7 +211,11 @@ func login(client *Cmix, callbacks AuthCallbacks,
 	client.network.AddIdentity(identity.ID, time.Time{}, true)
 
 	//initialize the e2e storage
-	err = e2e.Init(kv, identity.ID, identity.DHKeyPrivate, e2eGrp,
+	dhPrivKey, err := identity.GetDHKeyPrivate()
+	if err != nil {
+		return nil, err
+	}
+	err = e2e.Init(kv, identity.ID, dhPrivKey, e2eGrp,
 		rekey.GetDefaultEphemeralParams())
 	if err != nil {
 		return nil, err
@@ -250,7 +250,7 @@ func login(client *Cmix, callbacks AuthCallbacks,
 // e2e private key. It attempts to load via a legacy construction, then tries
 // to load the modern one, creating a new modern ID if neither can be found
 func LoadOrInitE2e(client *Cmix) (e2e.Handler, error) {
-	usr := client.GetUser()
+	usr := client.GetStorage().PortableUserInfo()
 	e2eGrp := client.GetStorage().GetE2EGroup()
 	kv := client.GetStorage().GetKV()
 
@@ -314,15 +314,6 @@ func LoadOrInitE2e(client *Cmix) (e2e.Handler, error) {
 	return e2eHandler, nil
 }
 
-// GetUser replaces xxdk.Cmix's GetUser with one which includes the e2e dh
-// private keys
-func (m *E2e) GetUser() user.Info {
-	u := m.Cmix.GetUser()
-	u.E2eDhPrivateKey = m.e2e.GetHistoricalDHPrivkey()
-	u.E2eDhPublicKey = m.e2e.GetHistoricalDHPubkey()
-	return u
-}
-
 // GetReceptionIdentity returns a safe copy of the E2e ReceptionIdentity
 func (m *E2e) GetReceptionIdentity() ReceptionIdentity {
 	return m.e2eIdentity.DeepCopy()
@@ -339,15 +330,22 @@ func (m *E2e) ConstructProtoUserFile() ([]byte, error) {
 			"permissioning")
 	}
 
+	transIdentity := m.Cmix.GetTransmissionIdentity()
+	receptionIdentity := m.GetReceptionIdentity()
+	privatePem, err := receptionIdentity.GetRSAPrivatePem()
+	if err != nil {
+		return nil, err
+	}
+
 	Usr := user.Proto{
-		TransmissionID:        m.GetUser().TransmissionID,
-		TransmissionSalt:      m.GetUser().TransmissionSalt,
-		TransmissionRSA:       m.GetUser().TransmissionRSA,
-		ReceptionID:           m.GetUser().ReceptionID,
-		ReceptionSalt:         m.GetUser().ReceptionSalt,
-		ReceptionRSA:          m.GetUser().ReceptionRSA,
-		Precanned:             m.GetUser().Precanned,
-		RegistrationTimestamp: m.GetUser().RegistrationTimestamp,
+		TransmissionID:        transIdentity.ID,
+		TransmissionSalt:      transIdentity.Salt,
+		TransmissionRSA:       transIdentity.RSAPrivatePem,
+		ReceptionID:           receptionIdentity.ID,
+		ReceptionSalt:         receptionIdentity.Salt,
+		ReceptionRSA:          privatePem,
+		Precanned:             m.GetStorage().IsPrecanned(),
+		RegistrationTimestamp: transIdentity.RegistrationTimestamp,
 		RegCode:               regCode,
 		TransmissionRegValidationSig: m.GetStorage().
 			GetTransmissionRegistrationValidationSignature(),
diff --git a/xxdk/identity.go b/xxdk/identity.go
index 923bf3d5c..566ed4f19 100644
--- a/xxdk/identity.go
+++ b/xxdk/identity.go
@@ -7,26 +7,87 @@
 package xxdk
 
 import (
+	"encoding/json"
+	"gitlab.com/elixxir/client/storage/user"
+	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/crypto/xx"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
 )
 
+const idVersion = 0
+
+// ReceptionIdentity is used by the E2e object for managing
+// identities used for message pickup
 type ReceptionIdentity struct {
 	ID            *id.ID
-	RSAPrivatePem *rsa.PrivateKey
+	RSAPrivatePem []byte
 	Salt          []byte
-	DHKeyPrivate  *cyclic.Int
+	DHKeyPrivate  []byte
+	E2eGrp        []byte
+}
+
+// StoreReceptionIdentity stores the given identity in Cmix storage with the given key
+// This is the ideal way to securely store identities, as the caller of this function
+// is only required to store the given key separately rather than the keying material
+func StoreReceptionIdentity(key string, identity ReceptionIdentity, client *Cmix) error {
+	marshalledIdentity, err := identity.Marshal()
+	if err != nil {
+		return err
+	}
+
+	return client.GetStorage().Set(key, &versioned.Object{
+		Version:   idVersion,
+		Timestamp: netTime.Now(),
+		Data:      marshalledIdentity,
+	})
+}
+
+// LoadReceptionIdentity loads the given identity in Cmix storage with the given key
+func LoadReceptionIdentity(key string, client *Cmix) (ReceptionIdentity, error) {
+	storageObj, err := client.GetStorage().Get(key)
+	if err != nil {
+		return ReceptionIdentity{}, err
+	}
+
+	return UnmarshalReceptionIdentity(storageObj.Data)
+}
+
+// Marshal returns the JSON representation of a ReceptionIdentity
+func (r ReceptionIdentity) Marshal() ([]byte, error) {
+	return json.Marshal(&r)
+}
+
+// UnmarshalReceptionIdentity takes in a marshalled ReceptionIdentity
+// and converts it to an object
+func UnmarshalReceptionIdentity(marshaled []byte) (ReceptionIdentity, error) {
+	newIdentity := ReceptionIdentity{}
+	return newIdentity, json.Unmarshal(marshaled, &newIdentity)
+}
+
+// GetDHKeyPrivate returns the DHKeyPrivate in go format
+func (r ReceptionIdentity) GetDHKeyPrivate() (*cyclic.Int, error) {
+	dhKeyPriv := &cyclic.Int{}
+	err := dhKeyPriv.UnmarshalJSON(r.DHKeyPrivate)
+	return dhKeyPriv, err
+}
+
+// GetRSAPrivatePem returns the RSAPrivatePem in go format
+func (r ReceptionIdentity) GetRSAPrivatePem() (*rsa.PrivateKey, error) {
+	return rsa.LoadPrivateKeyFromPem(r.RSAPrivatePem)
 }
 
 // MakeReceptionIdentity generates a new cryptographic identity
 // for receiving messages.
-func MakeReceptionIdentity(rng csprng.Source,
-	grp *cyclic.Group) (ReceptionIdentity, error) {
+func MakeReceptionIdentity(client *Cmix) (ReceptionIdentity, error) {
+	rng := client.GetRng().GetStream()
+	defer rng.Close()
+	grp := client.GetStorage().GetE2EGroup()
+
 	//make RSA Key
 	rsaKey, err := rsa.GenerateKey(rng,
 		rsa.DefaultRSABitLen)
@@ -50,12 +111,24 @@ func MakeReceptionIdentity(rng csprng.Source,
 		return ReceptionIdentity{}, err
 	}
 
+	privKeyBytes, err := privKey.MarshalJSON()
+	if err != nil {
+		return ReceptionIdentity{}, err
+	}
+
+	grpBytes, err := grp.MarshalJSON()
+	if err != nil {
+		return ReceptionIdentity{}, err
+	}
+
 	//create the identity object
+	rsaPem := rsa.CreatePrivateKeyPem(rsaKey)
 	I := ReceptionIdentity{
 		ID:            newId,
-		RSAPrivatePem: rsaKey,
+		RSAPrivatePem: rsaPem,
 		Salt:          salt,
-		DHKeyPrivate:  privKey,
+		DHKeyPrivate:  privKeyBytes,
+		E2eGrp:        grpBytes,
 	}
 
 	return I, nil
@@ -65,18 +138,24 @@ func MakeReceptionIdentity(rng csprng.Source,
 func (r ReceptionIdentity) DeepCopy() ReceptionIdentity {
 	saltCopy := make([]byte, len(r.Salt))
 	copy(saltCopy, r.Salt)
+
+	dhKeyCopy := make([]byte, len(r.DHKeyPrivate))
+	copy(dhKeyCopy, r.DHKeyPrivate)
 	return ReceptionIdentity{
 		ID:            r.ID.DeepCopy(),
 		RSAPrivatePem: r.RSAPrivatePem,
 		Salt:          saltCopy,
-		DHKeyPrivate:  r.DHKeyPrivate.DeepCopy(),
+		DHKeyPrivate:  dhKeyCopy,
 	}
 }
 
 // GetContact accepts a xxdk.ReceptionIdentity object and returns a contact.Contact object
-func (r ReceptionIdentity) GetContact(grp *cyclic.Group) contact.Contact {
-	dhPub := grp.ExpG(r.DHKeyPrivate, grp.NewInt(1))
+func (r ReceptionIdentity) GetContact() contact.Contact {
+	grp := &cyclic.Group{}
+	_ = grp.UnmarshalJSON(r.E2eGrp)
+	dhKeyPriv, _ := r.GetDHKeyPrivate()
 
+	dhPub := grp.ExpG(dhKeyPriv, grp.NewInt(1))
 	ct := contact.Contact{
 		ID:             r.ID,
 		DhPubKey:       dhPub,
@@ -85,3 +164,62 @@ func (r ReceptionIdentity) GetContact(grp *cyclic.Group) contact.Contact {
 	}
 	return ct
 }
+
+// buildReceptionIdentity creates a new ReceptionIdentity
+// from the given user.Info
+func buildReceptionIdentity(userInfo user.Info, e2eGrp *cyclic.Group, dHPrivkey *cyclic.Int) (ReceptionIdentity, error) {
+	saltCopy := make([]byte, len(userInfo.TransmissionSalt))
+	copy(saltCopy, userInfo.TransmissionSalt)
+
+	grp, err := e2eGrp.MarshalJSON()
+	if err != nil {
+		return ReceptionIdentity{}, err
+	}
+	privKey, err := dHPrivkey.MarshalJSON()
+	if err != nil {
+		return ReceptionIdentity{}, err
+	}
+
+	return ReceptionIdentity{
+		ID:            userInfo.ReceptionID.DeepCopy(),
+		RSAPrivatePem: rsa.CreatePrivateKeyPem(userInfo.ReceptionRSA),
+		Salt:          saltCopy,
+		DHKeyPrivate:  privKey,
+		E2eGrp:        grp,
+	}, nil
+}
+
+// TransmissionIdentity represents the identity
+// used to transmit over the network via a specific Cmix object
+type TransmissionIdentity struct {
+	ID            *id.ID
+	RSAPrivatePem *rsa.PrivateKey
+	Salt          []byte
+	// Timestamp in which user has registered with the network
+	RegistrationTimestamp int64
+}
+
+// DeepCopy produces a safe copy of a TransmissionIdentity
+func (t TransmissionIdentity) DeepCopy() TransmissionIdentity {
+	saltCopy := make([]byte, len(t.Salt))
+	copy(saltCopy, t.Salt)
+	return TransmissionIdentity{
+		ID:                    t.ID.DeepCopy(),
+		RSAPrivatePem:         t.RSAPrivatePem,
+		Salt:                  saltCopy,
+		RegistrationTimestamp: t.RegistrationTimestamp,
+	}
+}
+
+// buildTransmissionIdentity creates a new TransmissionIdentity
+// from the given user.Info
+func buildTransmissionIdentity(userInfo user.Info) TransmissionIdentity {
+	saltCopy := make([]byte, len(userInfo.TransmissionSalt))
+	copy(saltCopy, userInfo.TransmissionSalt)
+	return TransmissionIdentity{
+		ID:                    userInfo.TransmissionID.DeepCopy(),
+		RSAPrivatePem:         userInfo.TransmissionRSA,
+		Salt:                  saltCopy,
+		RegistrationTimestamp: userInfo.RegistrationTimestamp,
+	}
+}
diff --git a/xxdk/permissioning.go b/xxdk/permissioning.go
index 2e1d735e1..e3327d8a8 100644
--- a/xxdk/permissioning.go
+++ b/xxdk/permissioning.go
@@ -63,15 +63,16 @@ func (c *Cmix) ConstructProtoUserFile() ([]byte, error) {
 			"permissioning")
 	}
 
+	userInfo := c.GetStorage().PortableUserInfo()
 	Usr := user.Proto{
-		TransmissionID:               c.GetUser().TransmissionID,
-		TransmissionSalt:             c.GetUser().TransmissionSalt,
-		TransmissionRSA:              c.GetUser().TransmissionRSA,
-		ReceptionID:                  c.GetUser().ReceptionID,
-		ReceptionSalt:                c.GetUser().ReceptionSalt,
-		ReceptionRSA:                 c.GetUser().ReceptionRSA,
-		Precanned:                    c.GetUser().Precanned,
-		RegistrationTimestamp:        c.GetUser().RegistrationTimestamp,
+		TransmissionID:               userInfo.TransmissionID,
+		TransmissionSalt:             userInfo.TransmissionSalt,
+		TransmissionRSA:              userInfo.TransmissionRSA,
+		ReceptionID:                  userInfo.ReceptionID,
+		ReceptionSalt:                userInfo.ReceptionSalt,
+		ReceptionRSA:                 userInfo.ReceptionRSA,
+		Precanned:                    userInfo.Precanned,
+		RegistrationTimestamp:        userInfo.RegistrationTimestamp,
 		RegCode:                      regCode,
 		TransmissionRegValidationSig: c.storage.GetTransmissionRegistrationValidationSignature(),
 		ReceptionRegValidationSig:    c.storage.GetReceptionRegistrationValidationSignature(),
-- 
GitLab