diff --git a/e2e/critical.go b/e2e/critical.go
index 9a803886ff81faeded4e546a8462af9e78c73dc9..30dc3c05ffb13373888c1f7866137a13b3abf19f 100644
--- a/e2e/critical.go
+++ b/e2e/critical.go
@@ -29,7 +29,7 @@ type roundEventRegistrar interface {
 // anonymous function to include the structures from manager that critical is
 // not aware of.
 type criticalSender func(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error)
+	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, e2e.KeyResidue, error)
 
 // critical is a structure that allows the auto resending of messages that must
 // be received.
@@ -138,7 +138,7 @@ func (c *critical) evaluate(stop *stoppable.Single) {
 				format.DigestContents(payload))
 
 			// Send the message
-			round, _, _, err := c.send(mt, recipient, payload,
+			round, _, _, _, err := c.send(mt, recipient, payload,
 				params)
 
 			// Pass to the handler
diff --git a/e2e/fpGenerator_test.go b/e2e/fpGenerator_test.go
index ebd2d7cc381a3d3ccc908b9118b697226bb0af59..1360d14e6c527aa7f063e49c6d19760b9a8a8b0a 100644
--- a/e2e/fpGenerator_test.go
+++ b/e2e/fpGenerator_test.go
@@ -16,6 +16,7 @@ import (
 	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/comms/network"
+	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/id"
@@ -90,11 +91,15 @@ type mockSessionCypher struct {
 	fp format.Fingerprint
 }
 
-func (m mockSessionCypher) GetSession() *session.Session             { return nil }
-func (m mockSessionCypher) Fingerprint() format.Fingerprint          { return m.fp }
-func (m mockSessionCypher) Encrypt([]byte) (ecrContents, mac []byte) { return nil, nil }
-func (m mockSessionCypher) Decrypt(format.Message) ([]byte, error)   { return nil, nil }
-func (m mockSessionCypher) Use()                                     {}
+func (m mockSessionCypher) GetSession() *session.Session    { return nil }
+func (m mockSessionCypher) Fingerprint() format.Fingerprint { return m.fp }
+func (m mockSessionCypher) Encrypt([]byte) (ecrContents, mac []byte, residue e2e.KeyResidue) {
+	return nil, nil, e2e.KeyResidue{}
+}
+func (m mockSessionCypher) Decrypt(format.Message) ([]byte, e2e.KeyResidue, error) {
+	return nil, e2e.KeyResidue{}, nil
+}
+func (m mockSessionCypher) Use() {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Mock cMix                                                           //
diff --git a/e2e/interface.go b/e2e/interface.go
index 0578bbc719731f5d1c83a7e16330506aac8bac66..e78997fbb67909eb6a986d52d1223ccc4d161013 100644
--- a/e2e/interface.go
+++ b/e2e/interface.go
@@ -35,7 +35,7 @@ type Handler interface {
 	// Will return an error if the network is not healthy or in
 	// the event of a failed send
 	SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte,
-		params Params) ([]id.Round, e2e.MessageID, time.Time, error)
+		params Params) ([]id.Round, e2e.MessageID, time.Time, e2e.KeyResidue, error)
 
 	/* === Reception ==================================================== */
 
diff --git a/e2e/manager.go b/e2e/manager.go
index bd7c313811a792ddc5535f8e4ab0f00cd97406b0..eda1ea43ba0c1b36d63bf9dae63b99d03945ebf6 100644
--- a/e2e/manager.go
+++ b/e2e/manager.go
@@ -215,7 +215,7 @@ func (m *manager) StartProcesses() (stoppable.Stoppable, error) {
 	rekeySendFunc := func(mt catalog.MessageType,
 		recipient *id.ID, payload []byte,
 		cmixParams cmix.CMIXParams) (
-		[]id.Round, e2e.MessageID, time.Time, error) {
+		[]id.Round, e2e.MessageID, time.Time, e2e.KeyResidue, error) {
 		// FIXME: we should have access to the e2e params here...
 		par := GetDefaultParams()
 		par.CMIXParams = cmixParams
@@ -284,7 +284,7 @@ func (m *manager) DeletePartnerNotify(partnerId *id.ID, params Params) error {
 	m.DeletePartnerCallbacks(partnerId)
 
 	// Send closing E2E message
-	rounds, msgID, timestamp, err := sendFunc()
+	rounds, msgID, timestamp, _, err := sendFunc()
 	if err != nil {
 		jww.ERROR.Printf("Failed to send %s E2E message to %s: %+v",
 			catalog.E2eClose, partnerId, err)
diff --git a/e2e/processor.go b/e2e/processor.go
index 5377eb5ace4e53dc1585167e392995369b5fb6c1..cf720db0ec25f8651bdfa7287a0e4941bb5b4835 100644
--- a/e2e/processor.go
+++ b/e2e/processor.go
@@ -30,8 +30,9 @@ func (p *processor) Process(ecrMsg format.Message,
 		return
 	}
 
+	// todo: handle residue here
 	sess := p.cy.GetSession()
-	message, done := p.m.partitioner.HandlePartition(sess.GetPartner(),
+	message, _, done := p.m.partitioner.HandlePartition(sess.GetPartner(),
 		contents, sess.GetRelationshipFingerprint(), residue)
 	if done {
 		message.RecipientID = receptionID.Source
diff --git a/e2e/rekey/exchange.go b/e2e/rekey/exchange.go
index 30345ca1a28cf7b30ea8db9fd6587289e4092aec..db3ae9d8e79b7451b3a3ffa3b691f6173aa8bce8 100644
--- a/e2e/rekey/exchange.go
+++ b/e2e/rekey/exchange.go
@@ -21,7 +21,7 @@ import (
 
 type E2eSender func(mt catalog.MessageType, recipient *id.ID, payload []byte,
 	cmixParams cmix.CMIXParams) (
-	[]id.Round, e2e.MessageID, time.Time, error)
+	[]id.Round, e2e.MessageID, time.Time, e2e.KeyResidue, error)
 
 func Start(switchboard *receive.Switchboard, ratchet *ratchet.Ratchet,
 	sender E2eSender, net cmix.Client, grp *cyclic.Group, params Params) (stoppable.Stoppable, error) {
diff --git a/e2e/rekey/rekey.go b/e2e/rekey/rekey.go
index 960df918f20e3aee3e87a77ac4959668fc5db87c..8bb3aa94b8b15c64496e21b71cf7b87258b4530f 100644
--- a/e2e/rekey/rekey.go
+++ b/e2e/rekey/rekey.go
@@ -125,7 +125,8 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe
 	params := cmix.GetDefaultCMIXParams()
 	params.DebugTag = "kx.Request"
 
-	rounds, msgID, _, err := sendE2E(param.Trigger, sess.GetPartner(),
+	// fixme: should this use the key residue?
+	rounds, msgID, _, _, err := sendE2E(param.Trigger, sess.GetPartner(),
 		payload, params)
 	// If the send fails, returns the error so it can be handled. The caller
 	// should ensure the calling session is in a state where the Rekey will
diff --git a/e2e/rekey/trigger.go b/e2e/rekey/trigger.go
index 80d2cd2b62a8a1840e8605aa79bc7d4e501cbb2d..d389d34885cd34e4238e79b6a1d6ccade0c1a97a 100644
--- a/e2e/rekey/trigger.go
+++ b/e2e/rekey/trigger.go
@@ -127,7 +127,8 @@ func handleTrigger(ratchet *ratchet.Ratchet, sender E2eSender,
 	params := cmix.GetDefaultCMIXParams()
 	params.Critical = true
 	//ignore results, the passed sender interface makes it a critical message
-	_, _, _, _ = sender(param.Confirm, request.Sender, payload,
+	// fixme: sould this use the key residue
+	_, _, _, _, _ = sender(param.Confirm, request.Sender, payload,
 		params)
 
 	return nil
diff --git a/e2e/rekey/utils_test.go b/e2e/rekey/utils_test.go
index 3e1f77f1dcdc80a760498da5ea6b1905b90cec84..f3de03391bd845700b5347d34bd8c7cf65a55f61 100644
--- a/e2e/rekey/utils_test.go
+++ b/e2e/rekey/utils_test.go
@@ -73,7 +73,8 @@ func genSidhKeys() (*sidh.PrivateKey, *sidh.PublicKey, *sidh.PrivateKey, *sidh.P
 }
 
 func testSendE2E(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, cmixParams cmix.CMIXParams) ([]id.Round, e2e.MessageID, time.Time, error) {
+	payload []byte, cmixParams cmix.CMIXParams) (
+	[]id.Round, e2e.MessageID, time.Time, e2e.KeyResidue, error) {
 	rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)}
 	alicePartner, err := r.GetPartner(aliceID)
 	if err != nil {
@@ -109,7 +110,7 @@ func testSendE2E(mt catalog.MessageType, recipient *id.ID,
 
 	bobSwitchboard.Speak(confirmMessage)
 
-	return rounds, e2e.MessageID{}, time.Time{}, nil
+	return rounds, e2e.MessageID{}, time.Time{}, e2e.KeyResidue{}, nil
 }
 
 var pub = "-----BEGIN CERTIFICATE-----\nMIIGHTCCBAWgAwIBAgIUOcAn9cpH+hyRH8/UfqtbFDoSxYswDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJQ2xhcmVt\nb250MRAwDgYDVQQKDAdFbGl4eGlyMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEZMBcG\nA1UEAwwQZ2F0ZXdheS5jbWl4LnJpcDEfMB0GCSqGSIb3DQEJARYQYWRtaW5AZWxp\neHhpci5pbzAeFw0xOTA4MTYwMDQ4MTNaFw0yMDA4MTUwMDQ4MTNaMIGSMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCUNsYXJlbW9udDEQMA4GA1UE\nCgwHRWxpeHhpcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGTAXBgNVBAMMEGdhdGV3\nYXkuY21peC5yaXAxHzAdBgkqhkiG9w0BCQEWEGFkbWluQGVsaXh4aXIuaW8wggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7Dkb6VXFn4cdpU0xh6ji0nTDQ\nUyT9DSNW9I3jVwBrWfqMc4ymJuonMZbuqK+cY2l+suS2eugevWZrtzujFPBRFp9O\n14Jl3fFLfvtjZvkrKbUMHDHFehascwzrp3tXNryiRMmCNQV55TfITVCv8CLE0t1i\nbiyOGM9ZWYB2OjXt59j76lPARYww5qwC46vS6+3Cn2Yt9zkcrGeskWEFa2VttHqF\n910TP+DZk2R5C7koAh6wZYK6NQ4S83YQurdHAT51LKGrbGehFKXq6/OAXCU1JLi3\nkW2PovTb6MZuvxEiRmVAONsOcXKu7zWCmFjuZZwfRt2RhnpcSgzfrarmsGM0LZh6\nJY3MGJ9YdPcVGSz+Vs2E4zWbNW+ZQoqlcGeMKgsIiQ670g0xSjYICqldpt79gaET\n9PZsoXKEmKUaj6pq1d4qXDk7s63HRQazwVLGBdJQK8qX41eCdR8VMKbrCaOkzD5z\ngnEu0jBBAwdMtcigkMIk1GRv91j7HmqwryOBHryLi6NWBY3tjb4So9AppDQB41SH\n3SwNenAbNO1CXeUqN0hHX6I1bE7OlbjqI7tXdrTllHAJTyVVjenPel2ApMXp+LVR\ndDbKtwBiuM6+n+z0I7YYerxN1gfvpYgcXm4uye8dfwotZj6H2J/uSALsU2v9UHBz\nprdrLSZk2YpozJb+CQIDAQABo2kwZzAdBgNVHQ4EFgQUDaTvG7SwgRQ3wcYx4l+W\nMcZjX7owHwYDVR0jBBgwFoAUDaTvG7SwgRQ3wcYx4l+WMcZjX7owDwYDVR0TAQH/\nBAUwAwEB/zAUBgNVHREEDTALgglmb28uY28udWswDQYJKoZIhvcNAQELBQADggIB\nADKz0ST0uS57oC4rT9zWhFqVZkEGh1x1XJ28bYtNUhozS8GmnttV9SnJpq0EBCm/\nr6Ub6+Wmf60b85vCN5WDYdoZqGJEBjGGsFzl4jkYEE1eeMfF17xlNUSdt1qLCE8h\nU0glr32uX4a6nsEkvw1vo1Liuyt+y0cOU/w4lgWwCqyweu3VuwjZqDoD+3DShVzX\n8f1p7nfnXKitrVJt9/uE+AtAk2kDnjBFbRxCfO49EX4Cc5rADUVXMXm0itquGBYp\nMbzSgFmsMp40jREfLYRRzijSZj8tw14c2U9z0svvK9vrLCrx9+CZQt7cONGHpr/C\n/GIrP/qvlg0DoLAtjea73WxjSCbdL3Nc0uNX/ymXVHdQ5husMCZbczc9LYdoT2VP\nD+GhkAuZV9g09COtRX4VP09zRdXiiBvweiq3K78ML7fISsY7kmc8KgVH22vcXvMX\nCgGwbrxi6QbQ80rWjGOzW5OxNFvjhvJ3vlbOT6r9cKZGIPY8IdN/zIyQxHiim0Jz\noavr9CPDdQefu9onizsmjsXFridjG/ctsJxcUEqK7R12zvaTxu/CVYZbYEUFjsCe\nq6ZAACiEJGvGeKbb/mSPvGs2P1kS70/cGp+P5kBCKqrm586FB7BcafHmGFrWhT3E\nLOUYkOV/gADT2hVDCrkPosg7Wb6ND9/mhCVVhf4hLGRh\n-----END CERTIFICATE-----\n"
diff --git a/e2e/sendE2E.go b/e2e/sendE2E.go
index 33460a6d149f26d231e63222dfd300d7669a3fb6..890337e4f2b56402edadcfcc0ec4e1c1869bb30b 100644
--- a/e2e/sendE2E.go
+++ b/e2e/sendE2E.go
@@ -20,10 +20,10 @@ import (
 )
 
 func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) {
+	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, e2e.KeyResidue, error) {
 
 	if !m.net.IsHealthy() {
-		return nil, e2e.MessageID{}, time.Time{},
+		return nil, e2e.MessageID{}, time.Time{}, e2e.KeyResidue{},
 			errors.New("cannot sendE2E when network is not healthy")
 	}
 
@@ -40,7 +40,7 @@ func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID,
 	if handleCritical {
 		m.crit.handle(mt, recipient, payload, rounds, err)
 	}
-	return rounds, msgID, t, err
+	return rounds, msgID, t, residue, err
 
 }
 
@@ -92,7 +92,7 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID,
 			// Check if any rekeys need to happen and trigger them
 			rekeySendFunc := func(mt catalog.MessageType, recipient *id.ID,
 				payload []byte, cmixParams cmix.CMIXParams) (
-				[]id.Round, e2e.MessageID, time.Time, error) {
+				[]id.Round, e2e.MessageID, time.Time, e2e.KeyResidue, error) {
 				par := params
 				par.CMIXParams = cmixParams
 				return m.SendE2E(mt, recipient, payload, par)
diff --git a/e2e/sendE2E_test.go b/e2e/sendE2E_test.go
index d316b90c79a388ac32c405542e49d882089138d1..26a25d1933181c31e6f0f40acdd888bab3e9bffe 100644
--- a/e2e/sendE2E_test.go
+++ b/e2e/sendE2E_test.go
@@ -22,6 +22,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
 	dh "gitlab.com/elixxir/crypto/diffieHellman"
+	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
@@ -106,7 +107,7 @@ func Test_manager_SendE2E_Smoke(t *testing.T) {
 
 	payload := []byte("My Payload")
 	p := GetDefaultParams()
-	_, _, _, err = m1.SendE2E(catalog.NoType, partnerID, payload, p)
+	_, _, _, _, err = m1.SendE2E(catalog.NoType, partnerID, payload, p)
 	if err != nil {
 		t.Errorf("SendE2E failed: %+v", err)
 	}
@@ -221,11 +222,15 @@ type mockWaitForKeyCypher struct {
 	cypherNum int
 }
 
-func (m *mockWaitForKeyCypher) GetSession() *session.Session           { return nil }
-func (m *mockWaitForKeyCypher) Fingerprint() format.Fingerprint        { return format.Fingerprint{} }
-func (m *mockWaitForKeyCypher) Encrypt([]byte) ([]byte, []byte)        { return nil, nil }
-func (m *mockWaitForKeyCypher) Decrypt(format.Message) ([]byte, error) { return nil, nil }
-func (m *mockWaitForKeyCypher) Use()                                   {}
+func (m *mockWaitForKeyCypher) GetSession() *session.Session    { return nil }
+func (m *mockWaitForKeyCypher) Fingerprint() format.Fingerprint { return format.Fingerprint{} }
+func (m *mockWaitForKeyCypher) Encrypt([]byte) ([]byte, []byte, e2e.KeyResidue) {
+	return nil, nil, e2e.KeyResidue{}
+}
+func (m *mockWaitForKeyCypher) Decrypt(format.Message) ([]byte, e2e.KeyResidue, error) {
+	return nil, e2e.KeyResidue{}, nil
+}
+func (m *mockWaitForKeyCypher) Use() {}
 
 // Tests that getSendErrors returns all the errors on the channel.
 func Test_getSendErrors(t *testing.T) {
diff --git a/e2e/unsafeProcessor.go b/e2e/unsafeProcessor.go
index 3cd173d525244ea2bdb15cd1c28fe4af1847ce58..741ae088b71f185c32a6cd6d53d2ed769199f627 100644
--- a/e2e/unsafeProcessor.go
+++ b/e2e/unsafeProcessor.go
@@ -33,8 +33,9 @@ func (up *UnsafeProcessor) Process(ecrMsg format.Message,
 	}
 
 	//Parse
-	message, done := up.m.partitioner.HandlePartition(sender,
-		ecrMsg.GetContents(), nil)
+	// todo: handle residue here
+	message, _, done := up.m.partitioner.HandlePartition(sender,
+		ecrMsg.GetContents(), nil, e2e.KeyResidue{})
 
 	if done {
 		message.RecipientID = receptionID.Source