diff --git a/e2e/fpGenerator.go b/e2e/fpGenerator.go
index 2e42f9af79bd186885392d2333f7c69cd461368d..19d7958925aa60cb198e21f5d65d945e3f2a593f 100644
--- a/e2e/fpGenerator.go
+++ b/e2e/fpGenerator.go
@@ -13,7 +13,7 @@ type fpGenerator struct {
 }
 
 func (fp *fpGenerator) AddKey(k *session.Cypher) {
-	err := fp.net.AddFingerprint(fp.myID, k.Fingerprint(), &processor{
+	err := fp.net.AddFingerprint(fp.myDefaultID, k.Fingerprint(), &processor{
 		cy: k,
 		m:  fp.manager,
 	})
@@ -24,5 +24,5 @@ func (fp *fpGenerator) AddKey(k *session.Cypher) {
 }
 
 func (fp *fpGenerator) DeleteKey(k *session.Cypher) {
-	fp.net.DeleteFingerprint(fp.myID, k.Fingerprint())
+	fp.net.DeleteFingerprint(fp.myDefaultID, k.Fingerprint())
 }
diff --git a/e2e/interface.go b/e2e/interface.go
index d9990b4d472201c11bdad2a07deac38f303ca5fd..84e10dcfd510227cf67adbf9a56de4930012596d 100644
--- a/e2e/interface.go
+++ b/e2e/interface.go
@@ -94,19 +94,28 @@ type Handler interface {
 
 	// AddPartner adds a partner. Automatically creates both send and receive
 	// sessions using the passed cryptographic data and per the parameters sent
-	AddPartner(partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.Int,
-		partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey,
-		sendParams, receiveParams session.Params, myID *id.ID, myPrivateKey *cyclic.Int, temporary bool) (*partner.Manager, error)
+	// If an alternate ID public key are to be used for this relationship,
+	// then pass them in, otherwise, leave myID and myPrivateKey nil
+	// If temporary is true, an alternate ram kv will be used for storage and
+	// the relationship will not survive a reset
+	AddPartner(myID *id.ID, myPrivateKey *cyclic.Int, partnerID *id.ID,
+		partnerPubKey, myPrivKey *cyclic.Int, partnerSIDHPubKey *sidh.PublicKey,
+		mySIDHPrivKey *sidh.PrivateKey, sendParams,
+		receiveParams session.Params, temporary bool) (*partner.Manager, error)
 
 	// GetPartner returns the partner per its ID, if it exists
-	GetPartner(partnerID *id.ID) (*partner.Manager, error)
+	// myID is your ID in the relationship, if left blank, it will
+	// assume to be your defaultID
+	GetPartner(partnerID *id.ID, myID *id.ID) (*partner.Manager, error)
 
 	// DeletePartner removes the associated contact from the E2E store
-	DeletePartner(partnerId *id.ID) error
+	// myID is your ID in the relationship, if left blank, it will
+	// assume to be your defaultID
+	DeletePartner(partnerId *id.ID, myID *id.ID) error
 
 	// GetAllPartnerIDs returns a list of all partner IDs that the user has
 	// an E2E relationship with.
-	GetAllPartnerIDs() []*id.ID
+	GetAllPartnerIDs(myID *id.ID) []*id.ID
 
 	/* === Services ========================================================= */
 
diff --git a/e2e/manager.go b/e2e/manager.go
index c47a18644f0fb135177fdfbcfed9278744c4941c..1a35f15746b91088579b90936eec88c65cbc6d14 100644
--- a/e2e/manager.go
+++ b/e2e/manager.go
@@ -23,20 +23,24 @@ type manager struct {
 	*receive.Switchboard
 	partitioner parse.Partitioner
 	net         network.Manager
-	myID        *id.ID
+	myDefaultID *id.ID
 	rng         *fastRNG.StreamGenerator
 	events      event.Manager
 	grp         *cyclic.Group
 	crit        *critical
 }
 
-//Init Creates stores. After calling, use load
-func Init(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int, grp *cyclic.Group) error {
-	return ratchet.New(kv, myID, privKey, grp)
+// Init Creates stores. After calling, use load
+// Passes a default ID and public key which is used for relationship with
+// partners when no default ID is selected
+func Init(kv *versioned.KV, myDefaultID *id.ID, privKey *cyclic.Int, grp *cyclic.Group) error {
+	return ratchet.New(kv, myDefaultID, privKey, grp)
 }
 
 // Load returns an e2e manager from storage
-func Load(kv *versioned.KV, net network.Manager, myID *id.ID,
+// Passes a default ID which is used for relationship with
+// partners when no default ID is selected
+func Load(kv *versioned.KV, net network.Manager, myDefaultID *id.ID,
 	grp *cyclic.Group, rng *fastRNG.StreamGenerator, events event.Manager) (Handler, error) {
 
 	//build the manager
@@ -44,14 +48,14 @@ func Load(kv *versioned.KV, net network.Manager, myID *id.ID,
 		Switchboard: receive.New(),
 		partitioner: parse.NewPartitioner(kv, net.GetMaxMessageLength()),
 		net:         net,
-		myID:        myID,
+		myDefaultID: myDefaultID,
 		events:      events,
 		grp:         grp,
 	}
 	var err error
 
 	//load the ratchets
-	m.Ratchet, err = ratchet.Load(kv, myID, grp,
+	m.Ratchet, err = ratchet.Load(kv, myDefaultID, grp,
 		&fpGenerator{m}, net, rng)
 	if err != nil {
 		return nil, err
@@ -92,15 +96,15 @@ func (m *manager) StartProcesses() (stoppable.Stoppable, error) {
 // EnableUnsafeReception enables the reception of unsafe message by registering
 // bespoke services for reception. For debugging only!
 func (m *manager) EnableUnsafeReception() {
-	m.net.AddService(m.myID, message.Service{
-		Identifier: m.myID[:],
+	m.net.AddService(m.myDefaultID, message.Service{
+		Identifier: m.myDefaultID[:],
 		Tag:        ratchet.Silent,
 	}, &UnsafeProcessor{
 		m:   m,
 		tag: ratchet.Silent,
 	})
-	m.net.AddService(m.myID, message.Service{
-		Identifier: m.myID[:],
+	m.net.AddService(m.myDefaultID, message.Service{
+		Identifier: m.myDefaultID[:],
 		Tag:        ratchet.E2e,
 	}, &UnsafeProcessor{
 		m:   m,
diff --git a/e2e/ratchet/partner/manager.go b/e2e/ratchet/partner/manager.go
index 3ff4befee5f95b491bf07b3aa149308a6fa19cef..7b04009ee06c005af6b77184c8d326c8d88fc675 100644
--- a/e2e/ratchet/partner/manager.go
+++ b/e2e/ratchet/partner/manager.go
@@ -216,6 +216,11 @@ func (m *Manager) GetPartnerID() *id.ID {
 	return m.partner.DeepCopy()
 }
 
+// GetMyID returns a copy of the ID used as self.
+func (m *Manager) GetMyID() *id.ID {
+	return m.myID.DeepCopy()
+}
+
 // GetSendSession gets the Send session of the passed ID. Returns nil if no
 // session is found.
 func (m *Manager) GetSendSession(sid session.SessionID) *session.Session {
@@ -245,6 +250,11 @@ func (m *Manager) TriggerNegotiations() []*session.Session {
 	return m.send.TriggerNegotiation()
 }
 
+// IsTemporary returns if this manager stores to disk or only in ram
+func (m *Manager) IsTemporary() bool {
+	return m.kv.IsMemStore()
+}
+
 func (m *Manager) GetMyOriginPrivateKey() *cyclic.Int {
 	return m.originMyPrivKey.DeepCopy()
 }
diff --git a/e2e/ratchet/store.go b/e2e/ratchet/ratchet.go
similarity index 50%
rename from e2e/ratchet/store.go
rename to e2e/ratchet/ratchet.go
index f25e699794ed6d68af847133160c30275cc0d420..a84b1e5d5f993db01f987560acb51c0d2c386de1 100644
--- a/e2e/ratchet/store.go
+++ b/e2e/ratchet/ratchet.go
@@ -8,7 +8,6 @@
 package ratchet
 
 import (
-	"encoding/json"
 	"github.com/cloudflare/circl/dh/sidh"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
@@ -21,27 +20,24 @@ import (
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
 )
 
 const (
-	currentStoreVersion = 0
-	packagePrefix       = "e2eSession"
-	storeKey            = "Ratchet"
-	pubKeyKey           = "DhPubKey"
-	privKeyKey          = "DhPrivKey"
+	packagePrefix = "e2eSession"
+	pubKeyKey     = "DhPubKey"
+	privKeyKey    = "DhPrivKey"
 )
 
 var NoPartnerErrorStr = "No relationship with partner found"
 
 type Ratchet struct {
-	managers map[id.ID]*partner.Manager
+	managers map[relationshipIdentity]*partner.Manager
 	mux      sync.RWMutex
 
-	myID         *id.ID
-	dhPrivateKey *cyclic.Int
-	dhPublicKey  *cyclic.Int
+	defaultID           *id.ID
+	defaultDHPrivateKey *cyclic.Int
+	defaultDHPublicKey  *cyclic.Int
 
 	grp       *cyclic.Group
 	cyHandler session.CypherHandler
@@ -52,7 +48,8 @@ type Ratchet struct {
 	sInteface   Services
 	servicesmux sync.RWMutex
 
-	kv *versioned.KV
+	kv    *versioned.KV
+	memKv *versioned.KV
 }
 
 // New creates a new store for the passed user id and private key.
@@ -69,12 +66,12 @@ func New(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int,
 	kv = kv.Prefix(packagePrefix)
 
 	r := &Ratchet{
-		managers: make(map[id.ID]*partner.Manager),
+		managers: make(map[relationshipIdentity]*partner.Manager),
 		services: make(map[string]message.Processor),
 
-		myID:         myID,
-		dhPrivateKey: privKey,
-		dhPublicKey:  pubKey,
+		defaultID:           myID,
+		defaultDHPrivateKey: privKey,
+		defaultDHPublicKey:  pubKey,
 
 		kv: kv,
 
@@ -96,90 +93,46 @@ func New(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int,
 	return r.save()
 }
 
-// Load loads an extant ratchet from disk
-func Load(kv *versioned.KV, myID *id.ID, grp *cyclic.Group,
-	cyHandler session.CypherHandler, services Services, rng *fastRNG.StreamGenerator) (
-	*Ratchet, error) {
-	kv = kv.Prefix(packagePrefix)
-
-	r := &Ratchet{
-		managers: make(map[id.ID]*partner.Manager),
-		services: make(map[string]message.Processor),
-
-		myID: myID,
-
-		kv: kv,
-
-		cyHandler: cyHandler,
-		grp:       grp,
-		rng:       rng,
-		sInteface: services,
-	}
-
-	obj, err := kv.Get(storeKey, currentStoreVersion)
-	if err != nil {
-		return nil, err
-	}
-
-	err = r.unmarshal(obj.Data)
-	if err != nil {
-		return nil, err
-	}
-
-	// add standard services
-	if err = r.AddService(Silent, nil); err != nil {
-		jww.FATAL.Panicf("Could not add standard %r "+
-			"service: %+v", Silent, err)
-	}
-	if err = r.AddService(E2e, nil); err != nil {
-		jww.FATAL.Panicf("Could not add standard %r "+
-			"service: %+v", E2e, err)
-	}
-
-	return r, nil
-}
-
-func (r *Ratchet) save() error {
-	now := netTime.Now()
-
-	data, err := r.marshal()
-	if err != nil {
-		return err
-	}
-
-	obj := versioned.Object{
-		Version:   currentStoreVersion,
-		Timestamp: now,
-		Data:      data,
-	}
-
-	return r.kv.Set(storeKey, currentStoreVersion, &obj)
-}
-
 // AddPartner adds a partner. Automatically creates both send and receive
 // sessions using the passed cryptographic data and per the parameters sent
-func (r *Ratchet) AddPartner(partnerID *id.ID, partnerPubKey,
-	myPrivKey *cyclic.Int, partnerSIDHPubKey *sidh.PublicKey,
+func (r *Ratchet) AddPartner(myID *id.ID, myPrivateKey *cyclic.Int, partnerID *id.ID,
+	partnerPubKey, myPrivKey *cyclic.Int, partnerSIDHPubKey *sidh.PublicKey,
 	mySIDHPrivKey *sidh.PrivateKey, sendParams,
-	receiveParams session.Params) (*partner.Manager, error) {
+	receiveParams session.Params, temporary bool) (*partner.Manager, error) {
 	r.mux.Lock()
 	defer r.mux.Unlock()
 
+	if myID == nil {
+		myID = r.defaultID
+	}
+
+	if myPrivateKey == nil {
+		myPrivateKey = r.defaultDHPrivateKey
+	}
+
 	jww.INFO.Printf("Adding Partner %r:\n\tMy Private Key: %r"+
-		"\n\tPartner Public Key: %r",
+		"\n\tPartner Public Key: %r to %s",
 		partnerID,
 		myPrivKey.TextVerbose(16, 0),
-		partnerPubKey.TextVerbose(16, 0))
+		partnerPubKey.TextVerbose(16, 0), myID)
 
-	if _, ok := r.managers[*partnerID]; ok {
+	rship := makeRelationshipIdentity(partnerID, myID)
+
+	if _, ok := r.managers[rship]; ok {
 		return nil, errors.New("Cannot overwrite existing partner")
 	}
 
-	m := partner.NewManager(r.kv, r.myID, partnerID, myPrivKey, partnerPubKey,
+	//pass a memory kv if it is supposed to be temporary
+	kv := r.kv
+	if temporary {
+		kv = r.memKv
+	}
+
+	m := partner.NewManager(kv, r.defaultID, partnerID, myPrivKey, partnerPubKey,
 		mySIDHPrivKey, partnerSIDHPubKey,
 		sendParams, receiveParams, r.cyHandler, r.grp, r.rng)
 
-	r.managers[*partnerID] = m
+	r.managers[rship] = m
 	if err := r.save(); err != nil {
 		jww.FATAL.Printf("Failed to add Partner %r: Save of store failed: %r",
 			partnerID, err)
@@ -192,11 +145,15 @@ func (r *Ratchet) AddPartner(partnerID *id.ID, partnerPubKey,
 }
 
 // GetPartner returns the partner per its ID, if it exists
-func (r *Ratchet) GetPartner(partnerID *id.ID) (*partner.Manager, error) {
+func (r *Ratchet) GetPartner(partnerID *id.ID, myID *id.ID) (*partner.Manager, error) {
 	r.mux.RLock()
 	defer r.mux.RUnlock()
 
-	m, ok := r.managers[*partnerID]
+	if myID == nil {
+		myID = r.defaultID
+	}
+
+	m, ok := r.managers[makeRelationshipIdentity(partnerID, myID)]
 
 	if !ok {
 		return nil, errors.New(NoPartnerErrorStr)
@@ -206,8 +163,13 @@ func (r *Ratchet) GetPartner(partnerID *id.ID) (*partner.Manager, error) {
 }
 
 // DeletePartner removes the associated contact from the E2E store
-func (r *Ratchet) DeletePartner(partnerId *id.ID) error {
-	m, ok := r.managers[*partnerId]
+func (r *Ratchet) DeletePartner(partnerId *id.ID, myID *id.ID) error {
+	if myID == nil {
+		myID = r.defaultID
+	}
+
+	rShip := makeRelationshipIdentity(partnerId, myID)
+	m, ok := r.managers[rShip]
 	if !ok {
 		return errors.New(NoPartnerErrorStr)
 	}
@@ -219,21 +181,24 @@ func (r *Ratchet) DeletePartner(partnerId *id.ID) error {
 	//delete services
 	r.delete(m)
 
-	delete(r.managers, *partnerId)
+	delete(r.managers, rShip)
 	return r.save()
 
 }
 
 // GetAllPartnerIDs returns a list of all partner IDs that the user has
 // an E2E relationship with.
-func (r *Ratchet) GetAllPartnerIDs() []*id.ID {
+func (r *Ratchet) GetAllPartnerIDs(myID *id.ID) []*id.ID {
 	r.mux.RLock()
 	defer r.mux.RUnlock()
 
 	partnerIds := make([]*id.ID, 0, len(r.managers))
 
-	for partnerId := range r.managers {
-		partnerIds = append(partnerIds, &partnerId)
+	for _, m := range r.managers {
+		if m.GetMyID().Cmp(myID) {
+			partnerIds = append(partnerIds, m.GetPartnerID())
+		}
+
 	}
 
 	return partnerIds
@@ -241,72 +206,10 @@ func (r *Ratchet) GetAllPartnerIDs() []*id.ID {
 
 // GetDHPrivateKey returns the diffie hellman private key.
 func (r *Ratchet) GetDHPrivateKey() *cyclic.Int {
-	return r.dhPrivateKey
+	return r.defaultDHPrivateKey
 }
 
 // GetDHPublicKey returns the diffie hellman public key.
 func (r *Ratchet) GetDHPublicKey() *cyclic.Int {
-	return r.dhPublicKey
-}
-
-// ekv functions
-func (r *Ratchet) marshal() ([]byte, error) {
-	contacts := make([]id.ID, len(r.managers))
-
-	index := 0
-	for partnerID := range r.managers {
-		contacts[index] = partnerID
-		index++
-	}
-
-	return json.Marshal(&contacts)
-}
-
-func (r *Ratchet) unmarshal(b []byte) error {
-
-	var contacts []id.ID
-
-	err := json.Unmarshal(b, &contacts)
-
-	if err != nil {
-		return err
-	}
-
-	for i := range contacts {
-		//load the contact separately to ensure pointers do not get swapped
-		partnerID := (&contacts[i]).DeepCopy()
-		// Load the relationship. The relationship handles adding the fingerprints via the
-		// context object
-		manager, err := partner.LoadManager(r.kv, r.myID, partnerID,
-			r.cyHandler, r.grp, r.rng)
-		if err != nil {
-			jww.FATAL.Panicf("Failed to load relationship for partner %r: %r",
-				partnerID, err.Error())
-		}
-
-		if !manager.GetPartnerID().Cmp(partnerID) {
-			jww.FATAL.Panicf("Loaded a manager with the wrong partner "+
-				"ID: \n\t loaded: %r \n\t present: %r",
-				partnerID, manager.GetPartnerID())
-		}
-
-		//add services for the manager
-		r.add(manager)
-
-		r.managers[*partnerID] = manager
-	}
-
-	r.dhPrivateKey, err = util.LoadCyclicKey(r.kv, privKeyKey)
-	if err != nil {
-		return errors.WithMessage(err,
-			"Failed to load e2e DH private key")
-	}
-
-	r.dhPublicKey, err = util.LoadCyclicKey(r.kv, pubKeyKey)
-	if err != nil {
-		return errors.WithMessage(err,
-			"Failed to load e2e DH public key")
-	}
-
-	return nil
+	return r.defaultDHPublicKey
 }
diff --git a/e2e/ratchet/store_test.go b/e2e/ratchet/ratchet_test.go
similarity index 90%
rename from e2e/ratchet/store_test.go
rename to e2e/ratchet/ratchet_test.go
index 53cd33181ff12e240d09d0c84ba6e2cc7354b6ee..409f5ef85abcdcb927733aeac383f5c15f335bab 100644
--- a/e2e/ratchet/store_test.go
+++ b/e2e/ratchet/ratchet_test.go
@@ -40,12 +40,12 @@ func TestNewStore(t *testing.T) {
 	rng := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
 	e2eP := params.GetDefaultE2ESessionParams()
 	expectedStore := &Ratchet{
-		managers:     make(map[id.ID]*partner.Manager),
-		dhPrivateKey: privKey,
-		dhPublicKey:  diffieHellman.GeneratePublicKey(privKey, grp),
-		grp:          grp,
-		kv:           kv.Prefix(packagePrefix),
-		fingerprints: &fingerprints,
+		managers:            make(map[id.ID]*partner.Manager),
+		defaultDHPrivateKey: privKey,
+		defaultDHPublicKey:  diffieHellman.GeneratePublicKey(privKey, grp),
+		grp:                 grp,
+		kv:                  kv.Prefix(packagePrefix),
+		fingerprints:        &fingerprints,
 		context: &context{
 			fa:   &fingerprints,
 			grp:  grp,
@@ -103,7 +103,7 @@ func TestStore_AddPartner(t *testing.T) {
 	rng := csprng.NewSystemRNG()
 	s, _, _ := makeTestStore()
 	partnerID := id.NewIdFromUInt(rand.Uint64(), id.User, t)
-	pubKey := diffieHellman.GeneratePublicKey(s.dhPrivateKey, s.grp)
+	pubKey := diffieHellman.GeneratePublicKey(s.defaultDHPrivateKey, s.grp)
 	p := params.GetDefaultE2ESessionParams()
 	// NOTE: e2e store doesn't contain a private SIDH key, that's
 	// because they're completely address as part of the
@@ -111,11 +111,11 @@ func TestStore_AddPartner(t *testing.T) {
 	_, pubSIDHKey := genSidhKeys(rng, sidh.KeyVariantSidhA)
 	privSIDHKey, _ := genSidhKeys(rng, sidh.KeyVariantSidhB)
 	expectedManager := partner.newManager(s.context, s.kv, partnerID,
-		s.dhPrivateKey, pubKey,
+		s.defaultDHPrivateKey, pubKey,
 		privSIDHKey, pubSIDHKey,
 		p, p)
 
-	err := s.AddPartner(partnerID, pubKey, s.dhPrivateKey, pubSIDHKey,
+	err := s.AddPartner(partnerID, pubKey, s.defaultDHPrivateKey, pubSIDHKey,
 		privSIDHKey, p, p)
 	if err != nil {
 		t.Fatalf("AddPartner returned an error: %v", err)
@@ -138,7 +138,7 @@ func TestStore_DeletePartner(t *testing.T) {
 	rng := csprng.NewSystemRNG()
 	s, _, _ := makeTestStore()
 	partnerID := id.NewIdFromUInt(rand.Uint64(), id.User, t)
-	pubKey := diffieHellman.GeneratePublicKey(s.dhPrivateKey, s.grp)
+	pubKey := diffieHellman.GeneratePublicKey(s.defaultDHPrivateKey, s.grp)
 	p := params.GetDefaultE2ESessionParams()
 	// NOTE: e2e store doesn't contain a private SIDH key, that's
 	// because they're completely address as part of the
@@ -146,7 +146,7 @@ func TestStore_DeletePartner(t *testing.T) {
 	_, pubSIDHKey := genSidhKeys(rng, sidh.KeyVariantSidhA)
 	privSIDHKey, _ := genSidhKeys(rng, sidh.KeyVariantSidhB)
 
-	err := s.AddPartner(partnerID, pubKey, s.dhPrivateKey, pubSIDHKey,
+	err := s.AddPartner(partnerID, pubKey, s.defaultDHPrivateKey, pubSIDHKey,
 		privSIDHKey, p, p)
 	if err != nil {
 		t.Fatalf("Could not add partner in set up: %v", err)
@@ -169,13 +169,13 @@ func TestStore_GetPartner(t *testing.T) {
 	rng := csprng.NewSystemRNG()
 	s, _, _ := makeTestStore()
 	partnerID := id.NewIdFromUInt(rand.Uint64(), id.User, t)
-	pubKey := diffieHellman.GeneratePublicKey(s.dhPrivateKey, s.grp)
+	pubKey := diffieHellman.GeneratePublicKey(s.defaultDHPrivateKey, s.grp)
 	p := params.GetDefaultE2ESessionParams()
 	_, pubSIDHKey := genSidhKeys(rng, sidh.KeyVariantSidhA)
 	privSIDHKey, _ := genSidhKeys(rng, sidh.KeyVariantSidhB)
 	expectedManager := partner.newManager(s.context, s.kv, partnerID,
-		s.dhPrivateKey, pubKey, privSIDHKey, pubSIDHKey, p, p)
-	_ = s.AddPartner(partnerID, pubKey, s.dhPrivateKey, pubSIDHKey,
+		s.defaultDHPrivateKey, pubKey, privSIDHKey, pubSIDHKey, p, p)
+	_ = s.AddPartner(partnerID, pubKey, s.defaultDHPrivateKey, pubSIDHKey,
 		privSIDHKey, p, p)
 
 	m, err := s.GetPartner(partnerID)
@@ -209,7 +209,7 @@ func TestStore_GetPartner_Error(t *testing.T) {
 func TestStore_GetPartnerContact(t *testing.T) {
 	s, _, _ := makeTestStore()
 	partnerID := id.NewIdFromUInt(rand.Uint64(), id.User, t)
-	pubKey := diffieHellman.GeneratePublicKey(s.dhPrivateKey, s.grp)
+	pubKey := diffieHellman.GeneratePublicKey(s.defaultDHPrivateKey, s.grp)
 	p := params.GetDefaultE2ESessionParams()
 	expected := contact.Contact{
 		ID:       partnerID,
@@ -219,7 +219,7 @@ func TestStore_GetPartnerContact(t *testing.T) {
 	_, pubSIDHKey := genSidhKeys(rng, sidh.KeyVariantSidhA)
 	privSIDHKey, _ := genSidhKeys(rng, sidh.KeyVariantSidhB)
 
-	_ = s.AddPartner(partnerID, pubKey, s.dhPrivateKey, pubSIDHKey,
+	_ = s.AddPartner(partnerID, pubKey, s.defaultDHPrivateKey, pubSIDHKey,
 		privSIDHKey, p, p)
 
 	c, err := s.GetPartnerContact(partnerID)
@@ -307,10 +307,10 @@ func TestStore_CheckKey(t *testing.T) {
 func TestStore_GetDHPrivateKey(t *testing.T) {
 	s, _, _ := makeTestStore()
 
-	if s.dhPrivateKey != s.GetDHPrivateKey() {
+	if s.defaultDHPrivateKey != s.GetDHPrivateKey() {
 		t.Errorf("GetDHPrivateKey() returned incorrect key."+
 			"\n\texpected: %v\n\treceived: %v",
-			s.dhPrivateKey, s.GetDHPrivateKey())
+			s.defaultDHPrivateKey, s.GetDHPrivateKey())
 	}
 }
 
@@ -318,10 +318,10 @@ func TestStore_GetDHPrivateKey(t *testing.T) {
 func TestStore_GetDHPublicKey(t *testing.T) {
 	s, _, _ := makeTestStore()
 
-	if s.dhPublicKey != s.GetDHPublicKey() {
+	if s.defaultDHPublicKey != s.GetDHPublicKey() {
 		t.Errorf("GetDHPublicKey() returned incorrect key."+
 			"\n\texpected: %v\n\treceived: %v",
-			s.dhPublicKey, s.GetDHPublicKey())
+			s.defaultDHPublicKey, s.GetDHPublicKey())
 	}
 }
 
diff --git a/e2e/ratchet/relationshipID.go b/e2e/ratchet/relationshipID.go
new file mode 100644
index 0000000000000000000000000000000000000000..58cdfcbcedcf3acb5163ca592207b5e27c859f99
--- /dev/null
+++ b/e2e/ratchet/relationshipID.go
@@ -0,0 +1,26 @@
+package ratchet
+
+import (
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type relationshipIdentity [2 * id.ArrIDLen]byte
+
+func makeRelationshipIdentity(partner, me *id.ID) relationshipIdentity {
+	ph := relationshipIdentity{}
+	copy(ph[:id.ArrIDLen], me[:])
+	copy(ph[id.ArrIDLen:], partner[:])
+	return ph
+}
+
+func (ri relationshipIdentity) GetMe() *id.ID {
+	me := &id.ID{}
+	copy(me[:], ri[:id.ArrIDLen])
+	return me
+}
+
+func (ri relationshipIdentity) GetPartner() *id.ID {
+	partner := &id.ID{}
+	copy(partner[:], ri[id.ArrIDLen:])
+	return partner
+}
diff --git a/e2e/ratchet/serviceList.go b/e2e/ratchet/serviceList.go
index 1f6fb32e824e9ada47a5ea2ebf9ff33abd10a6bf..6184c8f1e0df1fe279732d9fc3bc7c343b9edd23 100644
--- a/e2e/ratchet/serviceList.go
+++ b/e2e/ratchet/serviceList.go
@@ -19,7 +19,7 @@ func (r *Ratchet) add(m *partner.Manager) {
 	r.servicesmux.RLock()
 	defer r.servicesmux.RUnlock()
 	for tag, process := range r.services {
-		r.sInteface.AddService(r.myID, m.MakeService(tag), process)
+		r.sInteface.AddService(r.defaultID, m.MakeService(tag), process)
 	}
 }
 
@@ -27,7 +27,7 @@ func (r *Ratchet) delete(m *partner.Manager) {
 	r.servicesmux.RLock()
 	defer r.servicesmux.RUnlock()
 	for tag, process := range r.services {
-		r.sInteface.DeleteService(r.myID, m.MakeService(tag), process)
+		r.sInteface.DeleteService(r.defaultID, m.MakeService(tag), process)
 	}
 }
 
@@ -42,7 +42,7 @@ func (r *Ratchet) AddService(tag string, processor message.Processor) error {
 
 	//add a service for every manager
 	for _, m := range r.managers {
-		r.sInteface.AddService(r.myID, m.MakeService(tag), processor)
+		r.sInteface.AddService(r.defaultID, m.MakeService(tag), processor)
 	}
 
 	return nil
@@ -61,7 +61,7 @@ func (r *Ratchet) RemoveService(tag string) error {
 	delete(r.services, tag)
 
 	for _, m := range r.managers {
-		r.sInteface.DeleteService(r.myID, m.MakeService(tag), oldServiceProcess)
+		r.sInteface.DeleteService(r.defaultID, m.MakeService(tag), oldServiceProcess)
 	}
 
 	return nil
diff --git a/e2e/ratchet/storage.go b/e2e/ratchet/storage.go
new file mode 100644
index 0000000000000000000000000000000000000000..f170df1786f4e01544e035a091f5f51c06fef73e
--- /dev/null
+++ b/e2e/ratchet/storage.go
@@ -0,0 +1,209 @@
+package ratchet
+
+import (
+	"encoding/json"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/e2e/ratchet/partner"
+	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
+	"gitlab.com/elixxir/client/network/message"
+	util "gitlab.com/elixxir/client/storage/utility"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+)
+
+const (
+	currentStoreVersion = 0
+	storeKey            = "Store"
+)
+
+// Load loads an extant ratchet from disk
+func Load(kv *versioned.KV, myID *id.ID, grp *cyclic.Group,
+	cyHandler session.CypherHandler, services Services, rng *fastRNG.StreamGenerator) (
+	*Ratchet, error) {
+	kv = kv.Prefix(packagePrefix)
+
+	r := &Ratchet{
+		managers: make(map[relationshipIdentity]*partner.Manager),
+		services: make(map[string]message.Processor),
+
+		defaultID: myID,
+
+		kv:    kv,
+		memKv: versioned.NewKV(make(ekv.Memstore)),
+
+		cyHandler: cyHandler,
+		grp:       grp,
+		rng:       rng,
+		sInteface: services,
+	}
+
+	obj, err := kv.Get(storeKey, currentStoreVersion)
+	if err != nil {
+		//try to load an old one
+		obj, err = kv.Get(storeKey, 0)
+		if err != nil {
+			return nil, err
+		} else {
+			err = r.unmarshalOld(obj.Data)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+	} else {
+		err = r.unmarshal(obj.Data)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// add standard services
+	if err = r.AddService(Silent, nil); err != nil {
+		jww.FATAL.Panicf("Could not add standard %r "+
+			"service: %+v", Silent, err)
+	}
+	if err = r.AddService(E2e, nil); err != nil {
+		jww.FATAL.Panicf("Could not add standard %r "+
+			"service: %+v", E2e, err)
+	}
+
+	return r, nil
+}
+
+func (r *Ratchet) save() error {
+	now := netTime.Now()
+
+	data, err := r.marshal()
+	if err != nil {
+		return err
+	}
+
+	obj := versioned.Object{
+		Version:   currentStoreVersion,
+		Timestamp: now,
+		Data:      data,
+	}
+
+	return r.kv.Set(storeKey, currentStoreVersion, &obj)
+}
+
+// ekv functions
+func (r *Ratchet) marshal() ([]byte, error) {
+	contacts := make([]relationshipIdentity, len(r.managers))
+
+	index := 0
+	for rid, m := range r.managers {
+		if !m.IsTemporary() {
+			contacts[index] = rid
+			index++
+		}
+	}
+
+	return json.Marshal(&contacts)
+}
+
+// In the event an old structure was loaded, unmarshal it and upgrade it
+func (r *Ratchet) unmarshalOld(b []byte) error {
+
+	var contacts []id.ID
+
+	err := json.Unmarshal(b, &contacts)
+
+	if err != nil {
+		return err
+	}
+
+	for i := range contacts {
+		//load the contact separately to ensure pointers do not get swapped
+		partnerID := (&contacts[i]).DeepCopy()
+		// Load the relationship. The relationship handles adding the fingerprints via the
+		// context object
+		manager, err := partner.LoadManager(r.kv, r.defaultID, partnerID,
+			r.cyHandler, r.grp, r.rng)
+		if err != nil {
+			jww.FATAL.Panicf("Failed to load relationship for partner %r: %r",
+				partnerID, err.Error())
+		}
+
+		if !manager.GetPartnerID().Cmp(partnerID) {
+			jww.FATAL.Panicf("Loaded a manager with the wrong partner "+
+				"ID: \n\t loaded: %r \n\t present: %r",
+				partnerID, manager.GetPartnerID())
+		}
+
+		//add services for the manager
+		r.add(manager)
+
+		//assume
+		r.managers[makeRelationshipIdentity(partnerID, r.defaultID)] = manager
+	}
+
+	r.defaultDHPrivateKey, err = util.LoadCyclicKey(r.kv, privKeyKey)
+	if err != nil {
+		return errors.WithMessage(err,
+			"Failed to load e2e DH private key")
+	}
+
+	r.defaultDHPublicKey, err = util.LoadCyclicKey(r.kv, pubKeyKey)
+	if err != nil {
+		return errors.WithMessage(err,
+			"Failed to load e2e DH public key")
+	}
+
+	return nil
+}
+
+func (r *Ratchet) unmarshal(b []byte) error {
+
+	var contacts []relationshipIdentity
+
+	err := json.Unmarshal(b, &contacts)
+
+	if err != nil {
+		return err
+	}
+
+	for i := range contacts {
+		//load the contact separately to ensure pointers do not get swapped
+		partnerID := contacts[i].GetPartner()
+		myID := contacts[i].GetMe()
+		// Load the relationship. The relationship handles adding the fingerprints via the
+		// context object
+		manager, err := partner.LoadManager(r.kv, myID, partnerID,
+			r.cyHandler, r.grp, r.rng)
+		if err != nil {
+			jww.FATAL.Panicf("Failed to load relationship for partner %r: %r",
+				partnerID, err.Error())
+		}
+
+		if !manager.GetPartnerID().Cmp(partnerID) {
+			jww.FATAL.Panicf("Loaded a manager with the wrong partner "+
+				"ID: \n\t loaded: %r \n\t present: %r",
+				partnerID, manager.GetPartnerID())
+		}
+
+		//add services for the manager
+		r.add(manager)
+
+		r.managers[contacts[i]] = manager
+	}
+
+	r.defaultDHPrivateKey, err = util.LoadCyclicKey(r.kv, privKeyKey)
+	if err != nil {
+		return errors.WithMessage(err,
+			"Failed to load e2e DH private key")
+	}
+
+	r.defaultDHPublicKey, err = util.LoadCyclicKey(r.kv, pubKeyKey)
+	if err != nil {
+		return errors.WithMessage(err,
+			"Failed to load e2e DH public key")
+	}
+
+	return nil
+}
diff --git a/e2e/rekey/confirm.go b/e2e/rekey/confirm.go
index a8d79136355be9077a8869c61ef7e05ab425e440..69c398e8ffce2c50ff360a502eba48a10f0350e2 100644
--- a/e2e/rekey/confirm.go
+++ b/e2e/rekey/confirm.go
@@ -36,12 +36,13 @@ func handleConfirm(ratchet *ratchet.Ratchet, confirmation receive.Message) {
 	if !confirmation.Encrypted {
 		jww.ERROR.Printf(
 			"[REKEY] Received non-e2e encrypted Key Exchange "+
-				"confirm from partner %s", confirmation.Sender)
+				"confirm from partner %s to %s", confirmation.Sender,
+			confirmation.RecipientID)
 		return
 	}
 
 	//get the partner
-	partner, err := ratchet.GetPartner(confirmation.Sender)
+	partner, err := ratchet.GetPartner(confirmation.Sender, confirmation.RecipientID)
 	if err != nil {
 		jww.ERROR.Printf(
 			"[REKEY] Received Key Exchange Confirmation with unknown "+
diff --git a/e2e/rekey/trigger.go b/e2e/rekey/trigger.go
index b2ea371ac7f2982a61745cab776bb397856e7bc7..34ff601a8cc1e90d6b948934d369c384ee2945f2 100644
--- a/e2e/rekey/trigger.go
+++ b/e2e/rekey/trigger.go
@@ -61,7 +61,7 @@ func handleTrigger(ratchet *ratchet.Ratchet, sender E2eSender,
 	}
 
 	//get the partner
-	partner, err := ratchet.GetPartner(request.Sender)
+	partner, err := ratchet.GetPartner(request.Sender, request.RecipientID)
 	if err != nil {
 		errMsg := fmt.Sprintf(errUnknown, request.Sender)
 		jww.ERROR.Printf(errMsg)
diff --git a/e2e/sendUnsafe.go b/e2e/sendUnsafe.go
index e602a14f96a508245c4d9b27e8908961832dfb6c..ac7582992500daa2bf1e9798d6ab7b9d010097ed 100644
--- a/e2e/sendUnsafe.go
+++ b/e2e/sendUnsafe.go
@@ -64,7 +64,7 @@ func (m *manager) sendUnsafe(mt catalog.MessageType, recipient *id.ID,
 		wg.Add(1)
 		go func(i int, payload []byte) {
 
-			unencryptedMAC, fp := e2e.SetUnencrypted(payload, m.myID)
+			unencryptedMAC, fp := e2e.SetUnencrypted(payload, m.myDefaultID)
 
 			var err error
 			roundIds[i], _, err = m.net.SendCMIX(recipient, fp,
diff --git a/storage/utility/id.go b/storage/utility/id.go
new file mode 100644
index 0000000000000000000000000000000000000000..08472b53e36da3d4912886ca3b19931d0120f78d
--- /dev/null
+++ b/storage/utility/id.go
@@ -0,0 +1,42 @@
+package utility
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+)
+
+const currentIDVersion = 0
+
+func StoreID(kv *versioned.KV, sid *id.ID, key string) error {
+	now := netTime.Now()
+
+	data, err := sid.MarshalJSON()
+	if err != nil {
+		return err
+	}
+
+	obj := versioned.Object{
+		Version:   currentIDVersion,
+		Timestamp: now,
+		Data:      data,
+	}
+
+	return kv.Set(key, currentIDVersion, &obj)
+}
+
+func LoadID(kv *versioned.KV, key string) (*id.ID, error) {
+	vo, err := kv.Get(key, currentIDVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	sid := &id.ID{}
+
+	return sid, sid.UnmarshalJSON(vo.Data)
+}
+
+// DeleteCID deletes a given cyclic key from storage
+func DeleteCID(kv *versioned.KV, key string) error {
+	return kv.Delete(key, currentIDVersion)
+}
diff --git a/storage/versioned/kv.go b/storage/versioned/kv.go
index 3e05b1b052d8a2713b9c9227e209f990c9c3f41d..fe7e8cd6a9669f75878aa87fa97846f84eb83627 100644
--- a/storage/versioned/kv.go
+++ b/storage/versioned/kv.go
@@ -151,6 +151,11 @@ func (v *KV) Prefix(prefix string) *KV {
 	return &kvPrefix
 }
 
+func (v *KV) IsMemStore() bool {
+	_, success := v.r.data.(ekv.Memstore)
+	return success
+}
+
 //Returns the key with all prefixes appended
 func (v *KV) GetFullKey(key string, version uint64) string {
 	return v.makeKey(key, version)