diff --git a/e2e/fpGenerator.go b/e2e/fpGenerator.go
new file mode 100644
index 0000000000000000000000000000000000000000..81479a451acddbd7fe147657c9e64f968d3d6343
--- /dev/null
+++ b/e2e/fpGenerator.go
@@ -0,0 +1,25 @@
+package e2e
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
+)
+
+type fpGenerator struct {
+	*Manager
+}
+
+func (fp *fpGenerator) AddKey(k *session.Cypher) {
+	err := fp.net.AddFingerprint(fp.myID, k.Fingerprint(), &processor{
+		cy: k,
+		m:  fp.Manager,
+	})
+	if err != nil {
+		jww.ERROR.Printf("Could not add fingerprint %s: %+v",
+			k.Fingerprint(), err)
+	}
+}
+
+func (fp *fpGenerator) DeleteKey(k *session.Cypher) {
+	fp.net.DeleteFingerprint(fp.myID, k.Fingerprint())
+}
diff --git a/e2e/interface.go b/e2e/interface.go
index 2ccf9f6076e0e81d5c5c2563c57bb34dbbba5065..8546eef3bd5f237f6e180321ea7f50c51aa81941 100644
--- a/e2e/interface.go
+++ b/e2e/interface.go
@@ -24,5 +24,3 @@ type Handler interface {
 	AddService(tag string, source []byte, processor message2.Processor)
 	RemoveService(tag string, source []byte)
 }
-type Manager interface {
-}
diff --git a/e2e/manager.go b/e2e/manager.go
new file mode 100644
index 0000000000000000000000000000000000000000..5871e7b069eed49e2db4584c6998d44b8239256e
--- /dev/null
+++ b/e2e/manager.go
@@ -0,0 +1,23 @@
+package e2e
+
+import (
+	"gitlab.com/elixxir/client/e2e/parse"
+	"gitlab.com/elixxir/client/e2e/ratchet"
+	"gitlab.com/elixxir/client/e2e/receive"
+	"gitlab.com/elixxir/client/network"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type Manager struct {
+	*ratchet.Ratchet
+	*receive.Switchboard
+	partitioner parse.Partitioner
+	net         network.Manager
+	myID        *id.ID
+}
+
+func InitManager(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int) {
+
+}
diff --git a/storage/conversation/message.go b/e2e/parse/conversation/message.go
similarity index 100%
rename from storage/conversation/message.go
rename to e2e/parse/conversation/message.go
diff --git a/storage/conversation/message_test.go b/e2e/parse/conversation/message_test.go
similarity index 100%
rename from storage/conversation/message_test.go
rename to e2e/parse/conversation/message_test.go
diff --git a/storage/conversation/partner.go b/e2e/parse/conversation/partner.go
similarity index 100%
rename from storage/conversation/partner.go
rename to e2e/parse/conversation/partner.go
diff --git a/storage/conversation/partner_test.go b/e2e/parse/conversation/partner_test.go
similarity index 100%
rename from storage/conversation/partner_test.go
rename to e2e/parse/conversation/partner_test.go
diff --git a/storage/conversation/ring.go b/e2e/parse/conversation/ring.go
similarity index 100%
rename from storage/conversation/ring.go
rename to e2e/parse/conversation/ring.go
diff --git a/storage/conversation/ring_test.go b/e2e/parse/conversation/ring_test.go
similarity index 100%
rename from storage/conversation/ring_test.go
rename to e2e/parse/conversation/ring_test.go
diff --git a/storage/conversation/store.go b/e2e/parse/conversation/store.go
similarity index 100%
rename from storage/conversation/store.go
rename to e2e/parse/conversation/store.go
diff --git a/storage/conversation/store_test.go b/e2e/parse/conversation/store_test.go
similarity index 100%
rename from storage/conversation/store_test.go
rename to e2e/parse/conversation/store_test.go
diff --git a/e2e/parse/partition.go b/e2e/parse/partition.go
index ad4ab21fc95ef750238f35d4162d9e0e18b43d26..06e10bcae00615e356ad305d4fef8d5ae5a38e4e 100644
--- a/e2e/parse/partition.go
+++ b/e2e/parse/partition.go
@@ -10,8 +10,10 @@ package parse
 import (
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/e2e/parse/conversation"
+	"gitlab.com/elixxir/client/e2e/parse/partition"
 	"gitlab.com/elixxir/client/e2e/receive"
-	"gitlab.com/elixxir/client/storage"
+	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 	"time"
@@ -25,16 +27,18 @@ type Partitioner struct {
 	partContentsSize  int
 	deltaFirstPart    int
 	maxSize           int
-	session           *storage.Session
+	conversation      *conversation.Store
+	partition         *partition.Store
 }
 
-func NewPartitioner(messageSize int, session *storage.Session) Partitioner {
+func NewPartitioner(messageSize int, kv *versioned.KV) Partitioner {
 	p := Partitioner{
 		baseMessageSize:   messageSize,
 		firstContentsSize: messageSize - firstHeaderLen,
 		partContentsSize:  messageSize - headerLen,
 		deltaFirstPart:    firstHeaderLen - headerLen,
-		session:           session,
+		conversation:      conversation.NewStore(kv),
+		partition:         partition.NewOrLoad(kv),
 	}
 	p.maxSize = p.firstContentsSize + (MaxMessageParts-1)*p.partContentsSize
 	return p
@@ -49,7 +53,7 @@ func (p Partitioner) Partition(recipient *id.ID, mt catalog.MessageType,
 	}
 
 	// Get the ID of the sent message
-	fullMessageID, messageID := p.session.Conversations().Get(recipient).GetNextSendID()
+	fullMessageID, messageID := p.conversation.Get(recipient).GetNextSendID()
 
 	// Get the number of parts of the message; this equates to just a linear
 	// equation
@@ -80,19 +84,19 @@ func (p Partitioner) HandlePartition(sender *id.ID,
 		fm := FirstMessagePartFromBytes(contents)
 
 		// Handle the message ID
-		messageID := p.session.Conversations().Get(sender).
+		messageID := p.conversation.Get(sender).
 			ProcessReceivedMessageID(fm.GetID())
 		storeageTimestamp := netTime.Now()
-		return p.session.Partition().AddFirst(sender, fm.GetType(),
+		return p.partition.AddFirst(sender, fm.GetType(),
 			messageID, fm.GetPart(), fm.GetNumParts(), fm.GetTimestamp(), storeageTimestamp,
 			fm.GetSizedContents(), relationshipFingerprint)
 	} else {
 		// If it is a subsequent message part, handle it as so
 		mp := messagePartFromBytes(contents)
-		messageID := p.session.Conversations().Get(sender).
+		messageID := p.conversation.Get(sender).
 			ProcessReceivedMessageID(mp.GetID())
 
-		return p.session.Partition().Add(sender, messageID, mp.GetPart(),
+		return p.partition.Add(sender, messageID, mp.GetPart(),
 			mp.GetSizedContents(), relationshipFingerprint)
 	}
 }
diff --git a/storage/partition/multiPartMessage.go b/e2e/parse/partition/multiPartMessage.go
similarity index 95%
rename from storage/partition/multiPartMessage.go
rename to e2e/parse/partition/multiPartMessage.go
index 3aa8cffb556c3bd23f8afb6f8730830919b3c07f..581689984e6b561c4abbc78ca18632d89f5fada9 100644
--- a/storage/partition/multiPartMessage.go
+++ b/e2e/parse/partition/multiPartMessage.go
@@ -12,7 +12,8 @@ import (
 	"fmt"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/message"
+	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/ekv"
@@ -34,7 +35,7 @@ type multiPartMessage struct {
 	SenderTimestamp time.Time
 	// Timestamp in which message was stored in RAM
 	StorageTimestamp time.Time
-	MessageType      message.Type
+	MessageType      catalog.MessageType
 
 	parts [][]byte
 	kv    *versioned.KV
@@ -121,7 +122,7 @@ func (mpm *multiPartMessage) Add(partNumber uint8, part []byte) {
 	}
 }
 
-func (mpm *multiPartMessage) AddFirst(mt message.Type, partNumber uint8,
+func (mpm *multiPartMessage) AddFirst(mt catalog.MessageType, partNumber uint8,
 	numParts uint8, senderTimestamp, storageTimestamp time.Time, part []byte) {
 	mpm.mux.Lock()
 	defer mpm.mux.Unlock()
@@ -151,11 +152,11 @@ func (mpm *multiPartMessage) AddFirst(mt message.Type, partNumber uint8,
 	}
 }
 
-func (mpm *multiPartMessage) IsComplete(relationshipFingerprint []byte) (message.Receive, bool) {
+func (mpm *multiPartMessage) IsComplete(relationshipFingerprint []byte) (receive.Message, bool) {
 	mpm.mux.Lock()
 	if mpm.NumParts == 0 || mpm.NumParts != mpm.PresentParts {
 		mpm.mux.Unlock()
-		return message.Receive{}, false
+		return receive.Message{}, false
 	}
 
 	// Make sure the parts buffer is large enough to load all parts from disk
@@ -181,14 +182,12 @@ func (mpm *multiPartMessage) IsComplete(relationshipFingerprint []byte) (message
 	}
 
 	// Return the message
-	m := message.Receive{
+	m := receive.Message{
 		Payload:     reconstructed,
 		MessageType: mpm.MessageType,
 		Sender:      mpm.Sender,
 		Timestamp:   mpm.SenderTimestamp,
-		// Encryption will be set externally
-		Encryption: 0,
-		ID:         mid,
+		ID:          mid,
 	}
 
 	return m, true
diff --git a/storage/partition/multiPartMessage_test.go b/e2e/parse/partition/multiPartMessage_test.go
similarity index 100%
rename from storage/partition/multiPartMessage_test.go
rename to e2e/parse/partition/multiPartMessage_test.go
diff --git a/storage/partition/part.go b/e2e/parse/partition/part.go
similarity index 100%
rename from storage/partition/part.go
rename to e2e/parse/partition/part.go
diff --git a/storage/partition/part_test.go b/e2e/parse/partition/part_test.go
similarity index 100%
rename from storage/partition/part_test.go
rename to e2e/parse/partition/part_test.go
diff --git a/storage/partition/store.go b/e2e/parse/partition/store.go
similarity index 90%
rename from storage/partition/store.go
rename to e2e/parse/partition/store.go
index f8a0e8e2c8054e6bbad61ee764c18b7664cee57f..6ad8cb4fb48014ffb1d87c5ab0f2f81cabb1759f 100644
--- a/storage/partition/store.go
+++ b/e2e/parse/partition/store.go
@@ -11,7 +11,8 @@ import (
 	"encoding/binary"
 	"encoding/json"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/message"
+	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
@@ -34,15 +35,7 @@ type Store struct {
 	mux         sync.Mutex
 }
 
-func New(kv *versioned.KV) *Store {
-	return &Store{
-		multiParts:  make(map[multiPartID]*multiPartMessage),
-		activeParts: make(map[*multiPartMessage]bool),
-		kv:          kv.Prefix(packagePrefix),
-	}
-}
-
-func Load(kv *versioned.KV) *Store {
+func NewOrLoad(kv *versioned.KV) *Store {
 	partitionStore := &Store{
 		multiParts:  make(map[multiPartID]*multiPartMessage),
 		activeParts: make(map[*multiPartMessage]bool),
@@ -56,9 +49,9 @@ func Load(kv *versioned.KV) *Store {
 	return partitionStore
 }
 
-func (s *Store) AddFirst(partner *id.ID, mt message.Type, messageID uint64,
+func (s *Store) AddFirst(partner *id.ID, mt catalog.MessageType, messageID uint64,
 	partNum, numParts uint8, senderTimestamp, storageTimestamp time.Time,
-	part []byte, relationshipFingerprint []byte) (message.Receive, bool) {
+	part []byte, relationshipFingerprint []byte) (receive.Message, bool) {
 
 	mpm := s.load(partner, messageID)
 
@@ -78,7 +71,7 @@ func (s *Store) AddFirst(partner *id.ID, mt message.Type, messageID uint64,
 }
 
 func (s *Store) Add(partner *id.ID, messageID uint64, partNum uint8,
-	part []byte, relationshipFingerprint []byte) (message.Receive, bool) {
+	part []byte, relationshipFingerprint []byte) (receive.Message, bool) {
 
 	mpm := s.load(partner, messageID)
 
diff --git a/storage/partition/store_test.go b/e2e/parse/partition/store_test.go
similarity index 97%
rename from storage/partition/store_test.go
rename to e2e/parse/partition/store_test.go
index 0b05232ca20380f5c066dfa31405dea0833a778f..1fcd8c54a74cc5976c022d38b0d597826ed13991 100644
--- a/storage/partition/store_test.go
+++ b/e2e/parse/partition/store_test.go
@@ -27,7 +27,7 @@ func TestNew(t *testing.T) {
 		kv:          rootKv.Prefix(packagePrefix),
 	}
 
-	store := New(rootKv)
+	store := NewOrLoad(rootKv)
 
 	if !reflect.DeepEqual(expectedStore, store) {
 		t.Errorf("New() did not return the expecte Store."+
@@ -38,7 +38,7 @@ func TestNew(t *testing.T) {
 // Tests happy path of Store.AddFirst().
 func TestStore_AddFirst(t *testing.T) {
 	part := []byte("Test message.")
-	s := New(versioned.NewKV(ekv.Memstore{}))
+	s := NewOrLoad(versioned.NewKV(ekv.Memstore{}))
 
 	msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t),
 		message.XxMessage, 5, 0, 1, netTime.Now(), netTime.Now(), part,
diff --git a/e2e/parse/partition_test.go b/e2e/parse/partition_test.go
index 7c063f2d222d9171416a7d0366325dd464da7475..4d1f64c82880ff38f311fb23a2a1e4513db13f86 100644
--- a/e2e/parse/partition_test.go
+++ b/e2e/parse/partition_test.go
@@ -56,9 +56,6 @@ func TestNewPartitioner(t *testing.T) {
 			4088, p.partContentsSize)
 	}
 
-	if p.session != storeSession {
-		t.Errorf("session content mismatch")
-	}
 }
 
 // Test that no error is returned running Partition
diff --git a/e2e/processor.go b/e2e/processor.go
new file mode 100644
index 0000000000000000000000000000000000000000..e86e1a20bd8e86b649637ff172274107898eaf67
--- /dev/null
+++ b/e2e/processor.go
@@ -0,0 +1,41 @@
+package e2e
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
+	"gitlab.com/elixxir/client/network/historical"
+	"gitlab.com/elixxir/client/network/identity/receptionID"
+	"gitlab.com/elixxir/primitives/format"
+)
+
+type processor struct {
+	cy *session.Cypher
+	m  *Manager
+}
+
+func (p *processor) Process(ecrMsg format.Message, receptionID receptionID.EphemeralIdentity,
+	round historical.Round) {
+	//ensure the key is used before returning
+	defer p.cy.Use()
+
+	//decrypt
+	msg, err := p.cy.Decrypt(ecrMsg)
+	if err != nil {
+		jww.ERROR.Printf("Decryption Failed of %s (fp: %s), dropping: %+v",
+			ecrMsg.Digest(), p.cy.Fingerprint(), err)
+		return
+	}
+
+	//Parse
+	sess := p.cy.GetSession()
+	message, done := p.m.partitioner.HandlePartition(sess.GetPartner(),
+		msg.GetContents(), sess.GetRelationshipFingerprint())
+
+	if done {
+		message.RecipientID = receptionID.Source
+		message.EphemeralID = receptionID.EphId
+		message.Round = round
+		message.Encrypted = true
+		p.m.Switchboard.Speak(message)
+	}
+}
diff --git a/e2e/ratchet/partner/session/cypher.go b/e2e/ratchet/partner/session/cypher.go
index 34ee21885ddd66e9e621c9dae027854837d2ea83..5a8f352b9147ca6bfefd09e6309a3ae8bf9107c6 100644
--- a/e2e/ratchet/partner/session/cypher.go
+++ b/e2e/ratchet/partner/session/cypher.go
@@ -127,8 +127,8 @@ func (k *Cypher) Decrypt(msg format.Message) (format.Message, error) {
 	return msg, nil
 }
 
-// Sets the key as used
-func (k *Cypher) denoteUse() {
+// Use sets the key as used. It cannot be used again.
+func (k *Cypher) Use() {
 	k.session.useKey(k.keyNum)
 }
 
diff --git a/e2e/ratchet/partner/session/cypher_test.go b/e2e/ratchet/partner/session/cypher_test.go
index 26d3b104aa6427ef1ab500f3225eefd3d447748f..47f9d5289ed4f2466a215954d104eb2520828dfb 100644
--- a/e2e/ratchet/partner/session/cypher_test.go
+++ b/e2e/ratchet/partner/session/cypher_test.go
@@ -172,16 +172,16 @@ func TestKey_EncryptDecrypt(t *testing.T) {
 	}
 }
 
-// Happy path of Key.denoteUse()
+// Happy path of Key.Use()
 func TestKey_denoteUse(t *testing.T) {
 	keyNum := uint32(rand.Int31n(31))
 
 	k := newKey(getSession(t), keyNum)
 
-	k.denoteUse()
+	k.Use()
 
 	if !k.session.keyState.Used(keyNum) {
-		t.Errorf("denoteUse() did not use the key")
+		t.Errorf("Use() did not use the key")
 	}
 }