diff --git a/bindings/client.go b/bindings/client.go
index f07598c9386ddcb7d038224be15a9a525960cc20..a160886728f0d7f0975be56956cca85171825883 100644
--- a/bindings/client.go
+++ b/bindings/client.go
@@ -14,6 +14,7 @@ import (
 	"errors"
 	"fmt"
 	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/single/old"
 	"runtime/pprof"
 	"strings"
 	"sync"
@@ -23,7 +24,6 @@ import (
 	"gitlab.com/elixxir/client/api"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/interfaces/params"
-	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/states"
@@ -47,7 +47,7 @@ func init() {
 // to support the gomobile Client interface
 type Client struct {
 	api       api.Client
-	single    *single.Manager
+	single    *old.Manager
 	singleMux sync.Mutex
 }
 
@@ -582,12 +582,12 @@ func (b *BindingsClient) Search(data, separator string,
 // getSingle is a function which returns the single mananger if it
 // exists or creates a new one, checking appropriate constraints
 // (that the network follower is running) if it needs to make one
-func (c *Client) getSingle() (*single.Manager, error) {
+func (c *Client) getSingle() (*old.Manager, error) {
 	c.singleMux.Lock()
 	defer c.singleMux.Unlock()
 	if c.single == nil {
 		apiClient := &c.api
-		c.single = single.NewManager(apiClient)
+		c.single = old.NewManager(apiClient)
 		err := apiClient.AddService(c.single.StartProcesses)
 		if err != nil {
 			return nil, err
diff --git a/cmd/single.go b/cmd/single.go
index bacc818dbeab9591c4d6b0e6a582352de94b7b3b..42eb4d844c3a847e14caadc84840f1e8b7222237 100644
--- a/cmd/single.go
+++ b/cmd/single.go
@@ -15,7 +15,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
 	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/single"
+	"gitlab.com/elixxir/client/single/old"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/utils"
@@ -73,14 +73,14 @@ var singleCmd = &cobra.Command{
 		waitUntilConnected(connected)
 
 		// Make single-use manager and start receiving process
-		singleMng := single.NewManager(client)
+		singleMng := old.NewManager(client)
 
 		// get the tag
 		tag := viper.GetString("tag")
 
 		// Register the callback
 		callbackChan := make(chan responseCallbackChan)
-		callback := func(payload []byte, c single.Contact) {
+		callback := func(payload []byte, c old.Contact) {
 			callbackChan <- responseCallbackChan{payload, c}
 		}
 		singleMng.RegisterCallback(tag, callback)
@@ -149,7 +149,7 @@ func init() {
 }
 
 // sendSingleUse sends a single use message.
-func sendSingleUse(m *single.Manager, partner contact.Contact, payload []byte,
+func sendSingleUse(m *old.Manager, partner contact.Contact, payload []byte,
 	maxMessages uint8, timeout time.Duration, tag string) {
 	// Construct callback
 	callbackChan := make(chan struct {
@@ -193,7 +193,7 @@ func sendSingleUse(m *single.Manager, partner contact.Contact, payload []byte,
 
 // replySingleUse responds to any single-use message it receives by replying\
 // with the same payload.
-func replySingleUse(m *single.Manager, timeout time.Duration, callbackChan chan responseCallbackChan) {
+func replySingleUse(m *old.Manager, timeout time.Duration, callbackChan chan responseCallbackChan) {
 
 	// Wait to receive a message or stop after timeout occurs
 	fmt.Println("Waiting for single-use message.")
@@ -229,13 +229,13 @@ func replySingleUse(m *single.Manager, timeout time.Duration, callbackChan chan
 // response callback.
 type responseCallbackChan struct {
 	payload []byte
-	c       single.Contact
+	c       old.Contact
 }
 
 // makeResponsePayload generates a new payload that will span the max number of
 // message parts in the contact. Each resulting message payload will contain a
 // copy of the supplied payload with spaces taking up any remaining data.
-func makeResponsePayload(m *single.Manager, payload []byte, maxParts uint8) []byte {
+func makeResponsePayload(m *old.Manager, payload []byte, maxParts uint8) []byte {
 	payloads := make([][]byte, maxParts)
 	payloadPart := makeResponsePayloadPart(m, payload)
 	for i := range payloads {
@@ -247,7 +247,7 @@ func makeResponsePayload(m *single.Manager, payload []byte, maxParts uint8) []by
 
 // makeResponsePayloadPart creates a single response payload by coping the given
 // payload and filling the rest with spaces.
-func makeResponsePayloadPart(m *single.Manager, payload []byte) []byte {
+func makeResponsePayloadPart(m *old.Manager, payload []byte) []byte {
 	payloadPart := make([]byte, m.GetMaxResponsePayloadSize())
 	for i := range payloadPart {
 		payloadPart[i] = ' '
diff --git a/cmd/ud.go b/cmd/ud.go
index 39d5a8aa764c7c3509b76bf474ebd5de11b11562..10271f53b445935df01fa654451eb2e93723a435 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -10,13 +10,13 @@ package cmd
 
 import (
 	"fmt"
+	"gitlab.com/elixxir/client/single/old"
 	"time"
 
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
 	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/elixxir/client/ud"
 	"gitlab.com/elixxir/client/xxmutils"
@@ -76,7 +76,7 @@ var udCmd = &cobra.Command{
 		waitUntilConnected(connected)
 
 		// Make single-use manager and start receiving process
-		singleMng := single.NewManager(client)
+		singleMng := old.NewManager(client)
 		err = client.AddService(singleMng.StartProcesses)
 		if err != nil {
 			jww.FATAL.Panicf("Failed to add single use process: %+v", err)
diff --git a/cmix/message/fingerprints.go b/cmix/message/fingerprints.go
index 884475364c1049ae58344630a76bb037ef41e28b..e396530db3abd5179502824bb39ad1f11841f99b 100644
--- a/cmix/message/fingerprints.go
+++ b/cmix/message/fingerprints.go
@@ -8,6 +8,8 @@
 package message
 
 import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/xx_network/crypto/csprng"
 	"sync"
 
 	"github.com/pkg/errors"
@@ -115,3 +117,13 @@ func (f *FingerprintsManager) DeleteClientFingerprints(clientID *id.ID) {
 	defer f.Unlock()
 	delete(f.fpMap, *clientID)
 }
+
+func RandomFingerprint(rng csprng.Source) format.Fingerprint {
+	fp := format.Fingerprint{}
+	fpBuf := make([]byte, len(fp[:]))
+	if _, err := rng.Read(fpBuf); err != nil {
+		jww.FATAL.Panicf("Failed to generate fingerprint: %+v", err)
+	}
+	copy(fp[:], fpBuf)
+	return fp
+}
diff --git a/cmix/params.go b/cmix/params.go
index 23ce735e8df136fe064ea05fae43114bbdbf9a73..bfd0cd1a5011fabd45c06d971da6ddd7112f7527 100644
--- a/cmix/params.go
+++ b/cmix/params.go
@@ -103,6 +103,8 @@ func GetParameters(params string) (Params, error) {
 
 type NodeMap map[id.ID]bool
 
+const DefaultDebugTag = "External"
+
 type CMIXParams struct {
 	// RoundTries is the maximum number of rounds to try to send on
 	RoundTries     uint
@@ -140,7 +142,7 @@ func GetDefaultCMIXParams() CMIXParams {
 		Timeout:     25 * time.Second,
 		RetryDelay:  1 * time.Second,
 		SendTimeout: 3 * time.Second,
-		DebugTag:    "External",
+		DebugTag:    DefaultDebugTag,
 		// Unused stoppable so components that require one have a channel to
 		// wait on
 		Stop: stoppable.NewSingle("cmixParamsDefault"),
diff --git a/single/callbackMap.go b/single/callbackMap.go
deleted file mode 100644
index 39bd3cc166d96e8c3a712a39726b0c5d1cdf820a..0000000000000000000000000000000000000000
--- a/single/callbackMap.go
+++ /dev/null
@@ -1,60 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"sync"
-)
-
-type ReceiveComm func(payload []byte, c Contact)
-
-// callbackMap stores a list of possible callbacks that can be called when a
-// message is received. To receive a transmission, each transmitted message must
-// use the same tag as the registered callback. The tag fingerprint is a hash of
-// a tag string that is used to identify the module that the transmission
-// message belongs to. The tag can be anything, but should be long enough so
-// that it is unique.
-type callbackMap struct {
-	callbacks map[singleUse.TagFP]ReceiveComm
-	sync.RWMutex
-}
-
-// newCallbackMap initialises a new map.
-func newCallbackMap() *callbackMap {
-	return &callbackMap{
-		callbacks: map[singleUse.TagFP]ReceiveComm{},
-	}
-}
-
-// registerCallback adds a callback function to the map that associates it with
-// its tag. The tag should be a unique string identifying the module using the
-// callback.
-func (cbm *callbackMap) registerCallback(tag string, callback ReceiveComm) {
-	cbm.Lock()
-	defer cbm.Unlock()
-
-	tagFP := singleUse.NewTagFP(tag)
-	cbm.callbacks[tagFP] = callback
-}
-
-// getCallback returns the callback registered with the given tag fingerprint.
-// An error is returned if no associated callback exists.
-func (cbm *callbackMap) getCallback(tagFP singleUse.TagFP) (ReceiveComm, error) {
-	cbm.RLock()
-	defer cbm.RUnlock()
-
-	cb, exists := cbm.callbacks[tagFP]
-	if !exists {
-		return nil, errors.Errorf("no callback registered for the tag "+
-			"fingerprint %s.", tagFP)
-	}
-
-	return cb, nil
-}
diff --git a/single/callbackMap_test.go b/single/callbackMap_test.go
deleted file mode 100644
index 5af02c8cac5b5b64f372a391ecb031b515f52298..0000000000000000000000000000000000000000
--- a/single/callbackMap_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"testing"
-)
-
-// Happy path.
-func Test_callbackMap_registerCallback(t *testing.T) {
-	m := newTestManager(0, false, t)
-	callbackChan := make(chan int)
-	testCallbacks := []struct {
-		tag string
-		cb  ReceiveComm
-	}{
-		{"tag1", func([]byte, Contact) { callbackChan <- 0 }},
-		{"tag2", func([]byte, Contact) { callbackChan <- 1 }},
-		{"tag3", func([]byte, Contact) { callbackChan <- 2 }},
-	}
-
-	for _, val := range testCallbacks {
-		m.callbackMap.registerCallback(val.tag, val.cb)
-	}
-
-	for i, val := range testCallbacks {
-		go m.callbackMap.callbacks[singleUse.NewTagFP(val.tag)](nil, Contact{})
-		result := <-callbackChan
-		if result != i {
-			t.Errorf("getCallback() did not return the expected callback."+
-				"\nexpected: %d\nreceived: %d", i, result)
-		}
-	}
-}
-
-// Happy path.
-func Test_callbackMap_getCallback(t *testing.T) {
-	m := newTestManager(0, false, t)
-	callbackChan := make(chan int)
-	testCallbacks := []struct {
-		tagFP singleUse.TagFP
-		cb    ReceiveComm
-	}{
-		{singleUse.UnmarshalTagFP([]byte("tag1")), func([]byte, Contact) { callbackChan <- 0 }},
-		{singleUse.UnmarshalTagFP([]byte("tag2")), func([]byte, Contact) { callbackChan <- 1 }},
-		{singleUse.UnmarshalTagFP([]byte("tsg3")), func([]byte, Contact) { callbackChan <- 2 }},
-	}
-
-	for _, val := range testCallbacks {
-		m.callbackMap.callbacks[val.tagFP] = val.cb
-	}
-
-	cb, err := m.callbackMap.getCallback(testCallbacks[1].tagFP)
-	if err != nil {
-		t.Errorf("getCallback() returned an error: %+v", err)
-	}
-
-	go cb(nil, Contact{})
-
-	result := <-callbackChan
-	if result != 1 {
-		t.Errorf("getCallback() did not return the expected callback."+
-			"\nexpected: %d\nreceived: %d", 1, result)
-	}
-}
-
-// Error path: no callback exists for the given tag fingerprint.
-func Test_callbackMap_getCallback_NoCallbackError(t *testing.T) {
-	m := newTestManager(0, false, t)
-
-	_, err := m.callbackMap.getCallback(singleUse.UnmarshalTagFP([]byte("tag1")))
-	if err == nil {
-		t.Error("getCallback() failed to return an error for a callback that " +
-			"does not exist.")
-	}
-}
diff --git a/single/contact.go b/single/contact.go
deleted file mode 100644
index bf0599899609261f38475e0ee5eed245898709ae..0000000000000000000000000000000000000000
--- a/single/contact.go
+++ /dev/null
@@ -1,67 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"fmt"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/xx_network/primitives/id"
-)
-
-// Contact contains the information to respond to a single-use contact.
-type Contact struct {
-	partner       *id.ID          // ID of the person to respond to
-	partnerPubKey *cyclic.Int     // Public key of the partner
-	dhKey         *cyclic.Int     // DH key
-	tagFP         singleUse.TagFP // Identifies which callback to use
-	maxParts      uint8           // Max number of messages allowed in reply
-	used          *int32          // Atomic variable
-}
-
-// NewContact initialises a new Contact with the specified fields.
-func NewContact(partner *id.ID, partnerPubKey, dhKey *cyclic.Int,
-	tagFP singleUse.TagFP, maxParts uint8) Contact {
-	used := int32(0)
-	return Contact{
-		partner:       partner,
-		partnerPubKey: partnerPubKey,
-		dhKey:         dhKey,
-		tagFP:         tagFP,
-		maxParts:      maxParts,
-		used:          &used,
-	}
-}
-
-// GetMaxParts returns the maximum number of message parts that can be sent in a
-// reply.
-func (c Contact) GetMaxParts() uint8 {
-	return c.maxParts
-}
-
-// GetPartner returns a copy of the partner ID.
-func (c Contact) GetPartner() *id.ID {
-	return c.partner.DeepCopy()
-}
-
-// String returns a string of the Contact structure.
-func (c Contact) String() string {
-	format := "Contact{partner:%s  partnerPubKey:%s  dhKey:%s  tagFP:%s  maxParts:%d  used:%d}"
-	return fmt.Sprintf(format, c.partner, c.partnerPubKey.Text(10),
-		c.dhKey.Text(10), c.tagFP, c.maxParts, *c.used)
-}
-
-// Equal determines if c and b have equal field values.
-func (c Contact) Equal(b Contact) bool {
-	return c.partner.Cmp(b.partner) &&
-		c.partnerPubKey.Cmp(b.partnerPubKey) == 0 &&
-		c.dhKey.Cmp(b.dhKey) == 0 &&
-		c.tagFP == b.tagFP &&
-		c.maxParts == b.maxParts &&
-		*c.used == *b.used
-}
diff --git a/single/contact_test.go b/single/contact_test.go
deleted file mode 100644
index 533e5600f935f1feaf36aad48735e47917466357..0000000000000000000000000000000000000000
--- a/single/contact_test.go
+++ /dev/null
@@ -1,102 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/xx_network/primitives/id"
-	"math/rand"
-	"testing"
-)
-
-// Happy path.
-func TestNewContact(t *testing.T) {
-	grp := getGroup()
-	used := int32(0)
-	expected := Contact{
-		partner:       id.NewIdFromString("sender ID", id.User, t),
-		partnerPubKey: grp.NewInt(99),
-		dhKey:         grp.NewInt(42),
-		tagFP:         singleUse.UnmarshalTagFP([]byte("test tagFP")),
-		maxParts:      uint8(rand.Uint64()),
-		used:          &used,
-	}
-
-	testC := NewContact(expected.partner, expected.partnerPubKey,
-		expected.dhKey, expected.tagFP, expected.maxParts)
-
-	if !expected.Equal(testC) {
-		t.Errorf("NewContact() did not return the expected Contact."+
-			"\nexpected: %s\nrecieved: %s", expected, testC)
-	}
-}
-
-// Happy path.
-func TestContact_GetMaxParts(t *testing.T) {
-	grp := getGroup()
-	maxParts := uint8(rand.Uint64())
-	c := NewContact(id.NewIdFromString("sender ID", id.User, t), grp.NewInt(99),
-		grp.NewInt(42), singleUse.TagFP{}, maxParts)
-
-	if maxParts != c.GetMaxParts() {
-		t.Errorf("GetMaxParts() failed to return the expected maxParts."+
-			"\nexpected %d\nreceived: %d", maxParts, c.GetMaxParts())
-	}
-}
-
-// Happy path.
-func TestContact_GetPartner(t *testing.T) {
-	grp := getGroup()
-	senderID := id.NewIdFromString("sender ID", id.User, t)
-	c := NewContact(senderID, grp.NewInt(99), grp.NewInt(42), singleUse.TagFP{},
-		uint8(rand.Uint64()))
-
-	if !senderID.Cmp(c.GetPartner()) {
-		t.Errorf("GetPartner() failed to return the expected sender ID."+
-			"\nexpected %s\nreceived: %s", senderID, c.GetPartner())
-	}
-
-}
-
-// Happy path.
-func TestContact_String(t *testing.T) {
-	grp := getGroup()
-	a := NewContact(id.NewIdFromString("sender ID 1", id.User, t), grp.NewInt(99),
-		grp.NewInt(42), singleUse.UnmarshalTagFP([]byte("test tagFP 1")), uint8(rand.Uint64()))
-	b := NewContact(id.NewIdFromString("sender ID 2", id.User, t),
-		grp.NewInt(98), grp.NewInt(43), singleUse.UnmarshalTagFP([]byte("test tagFP 2")), uint8(rand.Uint64()))
-	c := NewContact(a.GetPartner(), a.partnerPubKey.DeepCopy(), a.dhKey.DeepCopy(), a.tagFP, a.maxParts)
-
-	if a.String() == b.String() {
-		t.Errorf("String() did not return the expected string."+
-			"\na: %s\nb: %s", a, b)
-	}
-	if a.String() != c.String() {
-		t.Errorf("String() did not return the expected string."+
-			"\na: %s\nc: %s", a, c)
-	}
-}
-
-// Happy path.
-func TestContact_Equal(t *testing.T) {
-	grp := getGroup()
-	a := NewContact(id.NewIdFromString("sender ID 1", id.User, t),
-		grp.NewInt(99), grp.NewInt(42), singleUse.UnmarshalTagFP([]byte("test tagFP 1")), uint8(rand.Uint64()))
-	b := NewContact(id.NewIdFromString("sender ID 2", id.User, t),
-		grp.NewInt(98), grp.NewInt(43), singleUse.UnmarshalTagFP([]byte("test tagFP 2")), uint8(rand.Uint64()))
-	c := NewContact(a.GetPartner(), a.partnerPubKey.DeepCopy(), a.dhKey.DeepCopy(), a.tagFP, a.maxParts)
-
-	if a.Equal(b) {
-		t.Errorf("Equal() found two different Contacts as equal."+
-			"\na: %s\nb: %s", a, b)
-	}
-	if !a.Equal(c) {
-		t.Errorf("Equal() found two equal Contacts as not equal."+
-			"\na: %s\nc: %s", a, c)
-	}
-}
diff --git a/single/cypher.go b/single/cypher.go
new file mode 100644
index 0000000000000000000000000000000000000000..f4365ddc92d28d5035db88691707671f6a352a00
--- /dev/null
+++ b/single/cypher.go
@@ -0,0 +1,70 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package single
+
+import (
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/single/message"
+	"gitlab.com/elixxir/crypto/cyclic"
+	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
+	"gitlab.com/elixxir/crypto/e2e/singleUse"
+	"gitlab.com/elixxir/primitives/format"
+)
+
+// makeCyphers generates all fingerprints for a given number of messages.
+func makeCyphers(dhKey *cyclic.Int, messageCount uint8) []cypher {
+
+	cylist := make([]cypher, messageCount)
+
+	for i := uint8(0); i < messageCount; i++ {
+		cylist[i] = cypher{
+			dhkey: dhKey,
+			num:   i,
+		}
+	}
+
+	return cylist
+}
+
+type cypher struct {
+	dhkey *cyclic.Int
+	num   uint8
+}
+
+func (rk *cypher) getKey() []byte {
+	return singleUse.NewResponseKey(rk.dhkey, uint64(rk.num))
+}
+
+func (rk *cypher) GetFingerprint() format.Fingerprint {
+	return singleUse.NewResponseFingerprint(rk.dhkey, uint64(rk.num))
+}
+
+func (rk *cypher) Encrypt(rp message.ResponsePart) (
+	fp format.Fingerprint, encryptedPayload, mac []byte) {
+	fp = rk.GetFingerprint()
+	key := rk.getKey()
+	//fixme: encryption is identical to what is used by e2e.Crypt, lets make
+	//them the same codepath
+	encryptedPayload = cAuth.Crypt(key, fp[:24], rp.Marshal())
+	mac = singleUse.MakeMAC(key, encryptedPayload)
+	return fp, encryptedPayload, mac
+}
+
+func (rk *cypher) Decrypt(contents, mac []byte) ([]byte, error) {
+
+	fp := rk.GetFingerprint()
+	key := rk.getKey()
+
+	// Verify the CMIX message MAC
+	if !singleUse.VerifyMAC(key, contents, mac) {
+		return nil, errors.New("failed to verify the single use mac")
+	}
+
+	//decrypt the payload
+	return cAuth.Crypt(key, fp[:24], contents), nil
+}
diff --git a/single/fingerprintMap.go b/single/fingerprintMap.go
deleted file mode 100644
index 27f7b54f1bb9b990097cc6cd4b36cb2ecd16f658..0000000000000000000000000000000000000000
--- a/single/fingerprintMap.go
+++ /dev/null
@@ -1,55 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"sync"
-)
-
-// fingerprintMap stores a map of fingerprint to key numbers.
-type fingerprintMap struct {
-	fps map[format.Fingerprint]uint64
-	sync.Mutex
-}
-
-// newFingerprintMap returns a map of fingerprints generated from the provided
-// key that is messageCount long.
-func newFingerprintMap(dhKey *cyclic.Int, messageCount uint64) *fingerprintMap {
-	fpm := &fingerprintMap{
-		fps: make(map[format.Fingerprint]uint64, messageCount),
-	}
-
-	for i := uint64(0); i < messageCount; i++ {
-		fp := singleUse.NewResponseFingerprint(dhKey, i)
-		fpm.fps[fp] = i
-	}
-
-	return fpm
-}
-
-// getKey returns true and the corresponding key of the fingerprint exists in
-// the map and returns false otherwise. If the fingerprint exists, then it is
-// deleted prior to returning the key.
-func (fpm *fingerprintMap) getKey(dhKey *cyclic.Int, fp format.Fingerprint) ([]byte, bool) {
-	fpm.Lock()
-	defer fpm.Unlock()
-
-	num, exists := fpm.fps[fp]
-	if !exists {
-		return nil, false
-	}
-
-	// delete found fingerprint
-	delete(fpm.fps, fp)
-
-	// Generate and return the key
-	return singleUse.NewResponseKey(dhKey, num), true
-}
diff --git a/single/fingerprintMap_test.go b/single/fingerprintMap_test.go
deleted file mode 100644
index 2be4e3f8d447beaa6385770bedfca87864a5ca97..0000000000000000000000000000000000000000
--- a/single/fingerprintMap_test.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package single
-
-import (
-	"bytes"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"reflect"
-	"testing"
-)
-
-// Happy path.
-func Test_newFingerprintMap(t *testing.T) {
-	baseKey := getGroup().NewInt(42)
-	messageCount := 3
-	expected := &fingerprintMap{
-		fps: map[format.Fingerprint]uint64{
-			singleUse.NewResponseFingerprint(baseKey, 0): 0,
-			singleUse.NewResponseFingerprint(baseKey, 1): 1,
-			singleUse.NewResponseFingerprint(baseKey, 2): 2,
-		},
-	}
-
-	fpm := newFingerprintMap(baseKey, uint64(messageCount))
-
-	if !reflect.DeepEqual(expected, fpm) {
-		t.Errorf("newFingerprintMap() did not generate the expected map."+
-			"\nexpected: %+v\nreceived: %+v", expected, fpm)
-	}
-}
-
-// Happy path.
-func TestFingerprintMap_getKey(t *testing.T) {
-	baseKey := getGroup().NewInt(42)
-	fpm := newFingerprintMap(baseKey, 5)
-	fp := singleUse.NewResponseFingerprint(baseKey, 3)
-	expectedKey := singleUse.NewResponseKey(baseKey, 3)
-
-	testKey, exists := fpm.getKey(baseKey, fp)
-	if !exists {
-		t.Errorf("getKey() failed to find key that exists in map."+
-			"\nfingerprint: %+v", fp)
-	}
-
-	if !bytes.Equal(expectedKey, testKey) {
-		t.Errorf("getKey() returned the wrong key.\nexpected: %+v\nreceived: %+v",
-			expectedKey, testKey)
-	}
-
-	testFP, exists := fpm.fps[fp]
-	if exists {
-		t.Errorf("getKey() failed to delete the found fingerprint."+
-			"\nfingerprint: %+v", testFP)
-	}
-}
-
-// Error path: fingerprint does not exist in map.
-func TestFingerprintMap_getKey_FingerprintNotInMap(t *testing.T) {
-	baseKey := getGroup().NewInt(42)
-	fpm := newFingerprintMap(baseKey, 5)
-	fp := singleUse.NewResponseFingerprint(baseKey, 30)
-
-	key, exists := fpm.getKey(baseKey, fp)
-	if exists {
-		t.Errorf("getKey() found a fingerprint in the map that should not exist."+
-			"\nfingerprint: %+v\nkey:         %+v", fp, key)
-	}
-
-	// Ensure no fingerprints were deleted
-	if len(fpm.fps) != 5 {
-		t.Errorf("getKey() deleted fingerprint."+
-			"\nexpected size: %d\nreceived size: %d", 5, len(fpm.fps))
-	}
-}
diff --git a/single/listener.go b/single/listener.go
new file mode 100644
index 0000000000000000000000000000000000000000..cf49e7868711c205a40fbdcc92be0b2507e30165
--- /dev/null
+++ b/single/listener.go
@@ -0,0 +1,118 @@
+package single
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	cmixMsg "gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/single/message"
+	"gitlab.com/elixxir/crypto/cyclic"
+	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
+	"gitlab.com/elixxir/crypto/e2e/singleUse"
+	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type Receiver interface {
+	Callback(*Request, receptionID.EphemeralIdentity, rounds.Round)
+}
+
+type Listener interface {
+	// Stop unregisters the listener
+	Stop()
+}
+
+type listener struct {
+	myId      *id.ID
+	myPrivkey *cyclic.Int
+	tag       string
+	grp       *cyclic.Group
+	cb        Receiver
+	net       cmix.Client
+}
+
+func Listen(tag string, myId *id.ID, privkey *cyclic.Int, net cmix.Client,
+	e2eGrp *cyclic.Group, cb Receiver) Listener {
+
+	l := &listener{
+		myId:      myId,
+		myPrivkey: privkey,
+		tag:       tag,
+		grp:       e2eGrp,
+		cb:        cb,
+		net:       net,
+	}
+
+	svc := cmixMsg.Service{
+		Identifier: myId[:],
+		Tag:        tag,
+		Metadata:   myId[:],
+	}
+
+	net.AddService(myId, svc, l)
+
+	return l
+}
+
+func (l *listener) Process(ecrMsg format.Message,
+	receptionID receptionID.EphemeralIdentity,
+	round rounds.Round) {
+
+	// Unmarshal the CMIX message contents to a transmission message
+	transmitMsg, err := message.UnmarshalRequest(ecrMsg.GetContents(),
+		l.grp.GetP().ByteLen())
+	if err != nil {
+		jww.WARN.Printf("failed to unmarshal contents on single use "+
+			"request to %s on tag %s: %+v", l.myId, l.tag, err)
+		return
+	}
+
+	// Generate DH key and symmetric key
+	senderPubkey := transmitMsg.GetPubKey(l.grp)
+	dhKey := l.grp.Exp(senderPubkey, l.myPrivkey,
+		l.grp.NewInt(1))
+	key := singleUse.NewTransmitKey(dhKey)
+
+	// Verify the MAC
+	if !singleUse.VerifyMAC(key, transmitMsg.GetPayload(), ecrMsg.GetMac()) {
+		jww.WARN.Printf("mac check failed on single use request to %s "+
+			"on tag %s", l.myId, l.tag)
+		return
+	}
+
+	// Decrypt the transmission message payload
+	fp := ecrMsg.GetKeyFP()
+	decryptedPayload := cAuth.Crypt(key, fp[:24], transmitMsg.GetPayload())
+
+	// Unmarshal payload
+	payload, err := message.UnmarshalRequestPayload(decryptedPayload)
+	if err != nil {
+		jww.WARN.Printf("failed to unmarshal decrypted payload on "+
+			"single use request to %s on tag %s: %+v", l.myId, l.tag, err)
+		return
+	}
+
+	used := uint32(0)
+
+	r := Request{
+		sender:         payload.GetRID(transmitMsg.GetPubKey(l.grp)),
+		senderPubKey:   senderPubkey,
+		dhKey:          dhKey,
+		tag:            l.tag,
+		maxParts:       0,
+		used:           &used,
+		requestPayload: payload.GetContents(),
+		net:            l.net,
+	}
+
+	go l.cb.Callback(&r, receptionID, round)
+}
+
+func (l *listener) Stop() {
+	svc := cmixMsg.Service{
+		Identifier: l.myId[:],
+		Tag:        l.tag,
+	}
+	l.net.DeleteService(l.myId, svc, l)
+}
diff --git a/single/manager.go b/single/manager.go
deleted file mode 100644
index c86bb3ed82b94e7a60973f0209bb2c3efbbd25c2..0000000000000000000000000000000000000000
--- a/single/manager.go
+++ /dev/null
@@ -1,97 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/cmix/identity/receptionID"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/client/storage"
-	"gitlab.com/elixxir/crypto/fastRNG"
-	"gitlab.com/xx_network/primitives/id"
-)
-
-const (
-	rawMessageBuffSize           = 100
-	singleUseTransmission        = "SingleUseTransmission"
-	singleUseReceiveTransmission = "SingleUseReceiveTransmission"
-	singleUseResponse            = "SingleUseResponse"
-	singleUseReceiveResponse     = "SingleUseReceiveResponse"
-	singleUseStop                = "SingleUse"
-)
-
-// Manager handles the transmission and reception of single-use communication.
-type Manager struct {
-	// Client and its field
-	client    *api.Client
-	store     *storage.Session
-	reception *receptionID.Store
-	swb       interfaces.Switchboard
-	net       interfaces.NetworkManager
-	rng       *fastRNG.StreamGenerator
-
-	// Holds the information needed to manage each pending communication. A
-	// state is created when a transmission is started and is removed on
-	// response or timeout.
-	p *pending
-
-	// List of callbacks that can be called when a transmission is received. For
-	// an entity to receive a message, it must register a callback in this map
-	// with the same tag used to send the message.
-	callbackMap *callbackMap
-}
-
-// NewManager creates a new single-use communication manager.
-func NewManager(client *api.Client) *Manager {
-	return newManager(client, client.GetStorage().Reception())
-}
-
-func newManager(client *api.Client, reception *receptionID.Store) *Manager {
-	return &Manager{
-		client:      client,
-		store:       client.GetStorage(),
-		reception:   reception,
-		swb:         client.GetSwitchboard(),
-		net:         client.GetNetworkInterface(),
-		rng:         client.GetRng(),
-		p:           newPending(),
-		callbackMap: newCallbackMap(),
-	}
-}
-
-// StartProcesses starts the process of receiving single-use transmissions and
-// replies.
-func (m *Manager) StartProcesses() (stoppable.Stoppable, error) {
-	// Start waiting for single-use transmission
-	transmissionStop := stoppable.NewSingle(singleUseTransmission)
-	transmissionChan := make(chan message.Receive, rawMessageBuffSize)
-	m.swb.RegisterChannel(singleUseReceiveTransmission, &id.ID{}, message.Raw, transmissionChan)
-	go m.receiveTransmissionHandler(transmissionChan, transmissionStop)
-
-	// Start waiting for single-use response
-	responseStop := stoppable.NewSingle(singleUseResponse)
-	responseChan := make(chan message.Receive, rawMessageBuffSize)
-	m.swb.RegisterChannel(singleUseReceiveResponse, &id.ID{}, message.Raw, responseChan)
-	go m.receiveResponseHandler(responseChan, responseStop)
-
-	// Create a multi stoppable
-	singleUseMulti := stoppable.NewMulti(singleUseStop)
-	singleUseMulti.Add(transmissionStop)
-	singleUseMulti.Add(responseStop)
-
-	return singleUseMulti, nil
-}
-
-// RegisterCallback registers a callback for received messages.
-func (m *Manager) RegisterCallback(tag string, callback ReceiveComm) {
-	jww.DEBUG.Printf("Registering single-use callback with tag %s.", tag)
-	m.callbackMap.registerCallback(tag, callback)
-}
diff --git a/single/manager_test.go b/single/manager_test.go
deleted file mode 100644
index a7de399c871667d1b765e965e044f50e7b1043cb..0000000000000000000000000000000000000000
--- a/single/manager_test.go
+++ /dev/null
@@ -1,411 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"bytes"
-	"errors"
-	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/cmix/gateway"
-	ephemeral2 "gitlab.com/elixxir/client/cmix/identity/receptionID"
-	"gitlab.com/elixxir/client/event"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/interfaces/params"
-	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/client/storage"
-	"gitlab.com/elixxir/client/storage/versioned"
-	"gitlab.com/elixxir/client/switchboard"
-	"gitlab.com/elixxir/comms/network"
-	contact2 "gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/crypto/fastRNG"
-	"gitlab.com/elixxir/ekv"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/comms/connect"
-	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"gitlab.com/xx_network/primitives/ndf"
-	"gitlab.com/xx_network/primitives/netTime"
-	"math/rand"
-	"reflect"
-	"sync"
-	"testing"
-	"time"
-)
-
-// Happy path.
-func Test_newManager(t *testing.T) {
-	client := &api.Client{}
-	e := &Manager{
-		client: client,
-		p:      newPending(),
-	}
-	m := newManager(client, &ephemeral2.Store{})
-
-	if e.client != m.client || e.store != m.store || e.net != m.net ||
-		e.rng != m.rng || !reflect.DeepEqual(e.p, m.p) {
-		t.Errorf("NewHandler() did not return the expected new Manager."+
-			"\nexpected: %+v\nreceived: %+v", e, m)
-	}
-}
-
-// Happy path.
-func TestManager_StartProcesses(t *testing.T) {
-	m := newTestManager(0, false, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetDHPublicKey(),
-	}
-	tag := "Test tag"
-	payload := make([]byte, 130)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReceiveComm()
-
-	transmitMsg, _, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, 8, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
-	}
-
-	_, sender, err := m.processTransmission(transmitMsg, singleUse.NewTransmitFingerprint(m.store.E2e().GetDHPublicKey()))
-
-	replyMsgs, err := m.makeReplyCmixMessages(sender, payload)
-	if err != nil {
-		t.Fatalf("Failed to generate reply CMIX messages: %+v", err)
-	}
-
-	receiveMsg := message.Receive{
-		Payload:     transmitMsg.Marshal(),
-		MessageType: message.Raw,
-		Sender:      rid,
-		RecipientID: partner.ID,
-	}
-
-	m.callbackMap.registerCallback(tag, callback)
-
-	_, _ = m.StartProcesses()
-	m.swb.(*switchboard.Switchboard).Speak(receiveMsg)
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		if !bytes.Equal(results.payload, payload) {
-			t.Errorf("Callback received wrong payload."+
-				"\nexpected: %+v\nreceived: %+v", payload, results.payload)
-		}
-	case <-timer.C:
-		t.Errorf("Callback failed to be called.")
-	}
-
-	callbackFunc, callbackFuncChan := createReplyComm()
-	m.p.Lock()
-	m.p.singleUse[*rid] = newState(sender.dhKey, sender.maxParts, callbackFunc)
-	m.p.Unlock()
-	eid, _, _, _ := ephemeral.GetId(partner.ID, id.ArrIDLen, netTime.Now().UnixNano())
-	replyMsg := message.Receive{
-		Payload:     replyMsgs[0].Marshal(),
-		MessageType: message.Raw,
-		Sender:      partner.ID,
-		RecipientID: rid,
-		EphemeralID: eid,
-	}
-
-	go func() {
-		timer := time.NewTimer(50 * time.Millisecond)
-		select {
-		case <-timer.C:
-			t.Errorf("quitChan never set.")
-		case <-m.p.singleUse[*rid].quitChan:
-		}
-	}()
-
-	m.swb.(*switchboard.Switchboard).Speak(replyMsg)
-
-	timer = time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackFuncChan:
-		if !bytes.Equal(results.payload, payload) {
-			t.Errorf("Callback received wrong payload."+
-				"\nexpected: %+v\nreceived: %+v", payload, results.payload)
-		}
-	case <-timer.C:
-		t.Errorf("Callback failed to be called.")
-	}
-}
-
-// Happy path: tests that the stoppable stops both routines.
-func TestManager_StartProcesses_Stop(t *testing.T) {
-	m := newTestManager(0, false, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetDHPublicKey(),
-	}
-	tag := "Test tag"
-	payload := make([]byte, 130)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReceiveComm()
-
-	transmitMsg, _, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, 8, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
-	}
-
-	_, sender, err := m.processTransmission(transmitMsg, singleUse.NewTransmitFingerprint(m.store.E2e().GetDHPublicKey()))
-
-	replyMsgs, err := m.makeReplyCmixMessages(sender, payload)
-	if err != nil {
-		t.Fatalf("Failed to generate reply CMIX messages: %+v", err)
-	}
-
-	receiveMsg := message.Receive{
-		Payload:     transmitMsg.Marshal(),
-		MessageType: message.Raw,
-		Sender:      rid,
-		RecipientID: partner.ID,
-	}
-
-	m.callbackMap.registerCallback(tag, callback)
-
-	stop, _ := m.StartProcesses()
-	if !stop.IsRunning() {
-		t.Error("Stoppable is not running.")
-	}
-
-	err = stop.Close()
-	if err != nil {
-		t.Errorf("Failed to close: %+v", err)
-	}
-
-	// Wait for the stoppable to close
-	for !stop.IsStopped() {
-		time.Sleep(10 * time.Millisecond)
-	}
-
-	m.swb.(*switchboard.Switchboard).Speak(receiveMsg)
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback called when the thread should have stopped."+
-			"\npayload: %+v\ncontact: %+v", results.payload, results.c)
-	case <-timer.C:
-	}
-
-	callbackFunc, callbackFuncChan := createReplyComm()
-	m.p.Lock()
-	m.p.singleUse[*rid] = newState(sender.dhKey, sender.maxParts, callbackFunc)
-	m.p.Unlock()
-	eid, _, _, _ := ephemeral.GetId(partner.ID, id.ArrIDLen, netTime.Now().UnixNano())
-	replyMsg := message.Receive{
-		Payload:     replyMsgs[0].Marshal(),
-		MessageType: message.Raw,
-		Sender:      partner.ID,
-		RecipientID: rid,
-		EphemeralID: eid,
-	}
-
-	m.swb.(*switchboard.Switchboard).Speak(replyMsg)
-
-	timer = time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackFuncChan:
-		t.Errorf("Callback called when the thread should have stopped."+
-			"\npayload: %+v\nerror: %+v", results.payload, results.err)
-	case <-timer.C:
-	}
-}
-
-type receiveCommData struct {
-	payload []byte
-	c       Contact
-}
-
-func createReceiveComm() (ReceiveComm, chan receiveCommData) {
-	callbackChan := make(chan receiveCommData)
-
-	callback := func(payload []byte, c Contact) {
-		callbackChan <- receiveCommData{payload: payload, c: c}
-	}
-	return callback, callbackChan
-}
-
-func newTestManager(timeout time.Duration, cmixErr bool, t *testing.T) *Manager {
-	return &Manager{
-		client:      nil,
-		store:       storage.InitTestingSession(t),
-		reception:   ephemeral2.NewStore(versioned.NewKV(make(ekv.Memstore))),
-		swb:         switchboard.New(),
-		net:         newTestNetworkManager(timeout, cmixErr, t),
-		rng:         fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
-		p:           newPending(),
-		callbackMap: newCallbackMap(),
-	}
-}
-
-func newTestNetworkManager(timeout time.Duration, cmixErr bool, t *testing.T) interfaces.NetworkManager {
-	instanceComms := &connect.ProtoComms{
-		Manager: connect.NewManagerTesting(t),
-	}
-
-	thisInstance, err := network.NewInstanceTesting(instanceComms, getNDF(),
-		getNDF(), nil, nil, t)
-	if err != nil {
-		t.Fatalf("Failed to create new test instance: %v", err)
-	}
-
-	return &testNetworkManager{
-		instance:    thisInstance,
-		msgs:        []format.Message{},
-		cmixTimeout: timeout,
-		cmixErr:     cmixErr,
-	}
-}
-
-// testNetworkManager is a test implementation of NetworkManager interface.
-type testNetworkManager struct {
-	instance    *network.Instance
-	msgs        []format.Message
-	cmixTimeout time.Duration
-	cmixErr     bool
-	sync.RWMutex
-}
-
-func (tnm *testNetworkManager) GetMsg(i int) format.Message {
-	tnm.RLock()
-	defer tnm.RUnlock()
-	return tnm.msgs[i]
-}
-
-func (tnm *testNetworkManager) SendE2E(message.Send, params.E2E, *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error) {
-	return nil, e2e.MessageID{}, time.Time{}, nil
-}
-
-func (tnm *testNetworkManager) GetVerboseRounds() string {
-	return ""
-}
-
-func (tnm *testNetworkManager) SendUnsafe(_ message.Send, _ params.Unsafe) ([]id.Round, error) {
-	return []id.Round{}, nil
-}
-
-func (tnm *testNetworkManager) SendCMIX(msg format.Message, _ *id.ID, _ params.CMIX) (id.Round, ephemeral.Id, error) {
-	if tnm.cmixTimeout != 0 {
-		time.Sleep(tnm.cmixTimeout)
-	} else if tnm.cmixErr {
-		return 0, ephemeral.Id{}, errors.New("sendCMIX error")
-	}
-
-	tnm.Lock()
-	defer tnm.Unlock()
-
-	tnm.msgs = append(tnm.msgs, msg)
-
-	return id.Round(rand.Uint64()), ephemeral.Id{}, nil
-}
-
-func (tnm *testNetworkManager) SendManyCMIX(messages []message.TargetedCmixMessage, p params.CMIX) (id.Round, []ephemeral.Id, error) {
-	if tnm.cmixTimeout != 0 {
-		time.Sleep(tnm.cmixTimeout)
-	} else if tnm.cmixErr {
-		return 0, []ephemeral.Id{}, errors.New("sendCMIX error")
-	}
-
-	tnm.Lock()
-	defer tnm.Unlock()
-
-	for _, msg := range messages {
-		tnm.msgs = append(tnm.msgs, msg.Message)
-	}
-
-	return id.Round(rand.Uint64()), []ephemeral.Id{}, nil
-}
-
-func (tnm *testNetworkManager) GetInstance() *network.Instance {
-	return tnm.instance
-}
-
-type dummyEventMgr struct{}
-
-func (d *dummyEventMgr) Report(p int, a, b, c string) {}
-func (t *testNetworkManager) GetEventManager() event.Manager {
-	return &dummyEventMgr{}
-}
-
-func (tnm *testNetworkManager) GetHealthTracker() interfaces.HealthTracker {
-	return nil
-}
-
-func (tnm *testNetworkManager) Follow(report interfaces.ClientErrorReport) (stoppable.Stoppable, error) {
-	return nil, nil
-}
-
-func (tnm *testNetworkManager) CheckGarbledMessages() {}
-
-func (tnm *testNetworkManager) InProgressRegistrations() int {
-	return 0
-}
-
-func (tnm *testNetworkManager) GetSender() *gateway.Sender {
-	return nil
-}
-
-func (tnm *testNetworkManager) GetAddressSize() uint8 { return 16 }
-
-func (tnm *testNetworkManager) RegisterAddressSizeNotification(string) (chan uint8, error) {
-	return nil, nil
-}
-
-func (tnm *testNetworkManager) UnregisterAddressSizeNotification(string) {}
-func (tnm *testNetworkManager) SetPoolFilter(gateway.Filter)             {}
-
-func getNDF() *ndf.NetworkDefinition {
-	return &ndf.NetworkDefinition{
-		E2E: ndf.Group{
-			Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B" +
-				"7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE" +
-				"DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F" +
-				"8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041" +
-				"023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45" +
-				"3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209" +
-				"6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29" +
-				"A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E" +
-				"37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2" +
-				"78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696" +
-				"015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E" +
-				"6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873" +
-				"847AEF49F66E43873",
-			Generator: "2",
-		},
-		CMIX: ndf.Group{
-			Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" +
-				"C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" +
-				"FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" +
-				"B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" +
-				"35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" +
-				"F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" +
-				"92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" +
-				"3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B",
-			Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" +
-				"D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" +
-				"6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" +
-				"085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" +
-				"AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" +
-				"3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" +
-				"BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" +
-				"DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7",
-		},
-	}
-}
diff --git a/single/collator.go b/single/message/collator.go
similarity index 72%
rename from single/collator.go
rename to single/message/collator.go
index 2ffe34cd656b0684857e3af21da80ad9682d1afb..842d404ed8e223f4f25ec72a5b187b0cec1ee3cc 100644
--- a/single/collator.go
+++ b/single/message/collator.go
@@ -1,4 +1,4 @@
-package single
+package message
 
 import (
 	"bytes"
@@ -6,30 +6,30 @@ import (
 	"sync"
 )
 
-// Initial value of the collator maxNum that indicates it has yet to be set
+// Initial value of the Collator maxNum that indicates it has yet to be set
 const unsetCollatorMax = -1
 
-// collator stores the list of payloads in the correct order.
-type collator struct {
+// Collator stores the list of payloads in the correct order.
+type Collator struct {
 	payloads [][]byte // List of payloads, in order
 	maxNum   int      // Max number of messages that can be received
 	count    int      // Current number of messages received
 	sync.Mutex
 }
 
-// newCollator generates an empty list of payloads to fit the max number of
+// NewCollator generates an empty list of payloads to fit the max number of
 // possible messages. maxNum is set to indicate that it is not yet set.
-func newCollator(messageCount uint64) *collator {
-	return &collator{
+func NewCollator(messageCount uint8) *Collator {
+	return &Collator{
 		payloads: make([][]byte, messageCount),
 		maxNum:   unsetCollatorMax,
 	}
 }
 
-// collate collects message payload parts. Once all parts are received, the full
+// Collate collects message payload parts. Once all parts are received, the full
 // collated payload is returned along with true. Otherwise returns false.
-func (c *collator) collate(payloadBytes []byte) ([]byte, bool, error) {
-	payload, err := unmarshalResponseMessage(payloadBytes)
+func (c *Collator) Collate(payloadBytes []byte) ([]byte, bool, error) {
+	payload, err := UnmarshalResponse(payloadBytes)
 	if err != nil {
 		return nil, false, errors.Errorf("Failed to unmarshal response "+
 			"payload: %+v", err)
@@ -41,12 +41,12 @@ func (c *collator) collate(payloadBytes []byte) ([]byte, bool, error) {
 	// If this is the first message received, then set the max number of
 	// messages expected to be received off its max number of parts.
 	if c.maxNum == unsetCollatorMax {
-		if int(payload.GetMaxParts()) > len(c.payloads) {
+		if int(payload.GetNumParts()) > len(c.payloads) {
 			return nil, false, errors.Errorf("Max number of parts reported by "+
-				"payload %d is larger than collator expected (%d).",
-				payload.GetMaxParts(), len(c.payloads))
+				"payload %d is larger than Collator expected (%d).",
+				payload.GetNumParts(), len(c.payloads))
 		}
-		c.maxNum = int(payload.GetMaxParts())
+		c.maxNum = int(payload.GetNumParts())
 	}
 
 	// Make sure that the part number is within the expected number of parts
diff --git a/single/collator_test.go b/single/message/collator_test.go
similarity index 65%
rename from single/collator_test.go
rename to single/message/collator_test.go
index b940f0c7498b7d7d3ff67b92e367a6621ecc2266..a51721188e403d863825191cfc4638df2812bda8 100644
--- a/single/collator_test.go
+++ b/single/message/collator_test.go
@@ -1,4 +1,4 @@
-package single
+package message
 
 import (
 	"bytes"
@@ -10,15 +10,15 @@ import (
 // Happy path
 func Test_newCollator(t *testing.T) {
 	messageCount := uint64(10)
-	expected := &collator{
+	expected := &Collator{
 		payloads: make([][]byte, messageCount),
 		maxNum:   unsetCollatorMax,
 		count:    0,
 	}
-	c := newCollator(messageCount)
+	c := NewCollator(messageCount)
 
 	if !reflect.DeepEqual(expected, c) {
-		t.Errorf("newCollator() failed to generated the expected collator."+
+		t.Errorf("NewCollator() failed to generated the expected Collator."+
 			"\nexepcted: %+v\nreceived: %+v", expected, c)
 	}
 }
@@ -27,19 +27,19 @@ func Test_newCollator(t *testing.T) {
 func TestCollator_collate(t *testing.T) {
 	messageCount := 16
 	msgPayloadSize := 2
-	msgParts := map[int]responseMessagePart{}
+	msgParts := map[int]ResponsePart{}
 	expectedData := make([]byte, messageCount*msgPayloadSize)
 	copy(expectedData, "This is the expected final data.")
 
 	buff := bytes.NewBuffer(expectedData)
 	for i := 0; i < messageCount; i++ {
-		msgParts[i] = newResponseMessagePart(msgPayloadSize + 5)
-		msgParts[i].SetMaxParts(uint8(messageCount))
+		msgParts[i] = NewResponsePart(msgPayloadSize + 5)
+		msgParts[i].SetNumParts(uint8(messageCount))
 		msgParts[i].SetPartNum(uint8(i))
 		msgParts[i].SetContents(buff.Next(msgPayloadSize))
 	}
 
-	c := newCollator(uint64(messageCount))
+	c := NewCollator(uint64(messageCount))
 
 	i := 0
 	var fullPayload []byte
@@ -49,22 +49,22 @@ func TestCollator_collate(t *testing.T) {
 		var err error
 		var collated bool
 
-		fullPayload, collated, err = c.collate(part.Marshal())
+		fullPayload, collated, err = c.Collate(part.Marshal())
 		if err != nil {
-			t.Errorf("collate() returned an error for part #%d: %+v", j, err)
+			t.Errorf("Collate() returned an error for part #%d: %+v", j, err)
 		}
 
 		if i == messageCount && (!collated || fullPayload == nil) {
-			t.Errorf("collate() failed to collate a completed payload."+
+			t.Errorf("Collate() failed to Collate a completed payload."+
 				"\ncollated:    %v\nfullPayload: %+v", collated, fullPayload)
 		} else if i < messageCount && (collated || fullPayload != nil) {
-			t.Errorf("collate() signaled it collated an unfinished payload."+
+			t.Errorf("Collate() signaled it collated an unfinished payload."+
 				"\ncollated:    %v\nfullPayload: %+v", collated, fullPayload)
 		}
 	}
 
 	if !bytes.Equal(expectedData, fullPayload) {
-		t.Errorf("collate() failed to return the correct collated data."+
+		t.Errorf("Collate() failed to return the correct collated data."+
 			"\nexpected: %s\nreceived: %s", expectedData, fullPayload)
 	}
 }
@@ -72,33 +72,33 @@ func TestCollator_collate(t *testing.T) {
 // Error path: the byte slice cannot be unmarshaled.
 func TestCollator_collate_UnmarshalError(t *testing.T) {
 	payloadBytes := []byte{1}
-	c := newCollator(1)
-	payload, collated, err := c.collate(payloadBytes)
+	c := NewCollator(1)
+	payload, collated, err := c.Collate(payloadBytes)
 
 	if err == nil || !strings.Contains(err.Error(), "unmarshal") {
-		t.Errorf("collate() failed to return an error for failing to "+
+		t.Errorf("Collate() failed to return an error for failing to "+
 			"unmarshal the payload.\nerror: %+v", err)
 	}
 
 	if payload != nil || collated {
-		t.Errorf("collate() signaled the payload was collated on error."+
+		t.Errorf("Collate() signaled the payload was collated on error."+
 			"\npayload:  %+v\ncollated: %+v", payload, collated)
 	}
 }
 
-// Error path: max reported parts by payload larger then set in collator
+// Error path: max reported parts by payload larger then set in Collator
 func TestCollator_collate_MaxPartsError(t *testing.T) {
 	payloadBytes := []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
-	c := newCollator(1)
-	payload, collated, err := c.collate(payloadBytes)
+	c := NewCollator(1)
+	payload, collated, err := c.Collate(payloadBytes)
 
 	if err == nil || !strings.Contains(err.Error(), "Max number of parts") {
-		t.Errorf("collate() failed to return an error when the max number of "+
+		t.Errorf("Collate() failed to return an error when the max number of "+
 			"parts is larger than the payload size.\nerror: %+v", err)
 	}
 
 	if payload != nil || collated {
-		t.Errorf("collate() signaled the payload was collated on error."+
+		t.Errorf("Collate() signaled the payload was collated on error."+
 			"\npayload:  %+v\ncollated: %+v", payload, collated)
 	}
 }
@@ -106,16 +106,16 @@ func TestCollator_collate_MaxPartsError(t *testing.T) {
 // Error path: the message part number is greater than the max number of parts.
 func TestCollator_collate_PartNumTooLargeError(t *testing.T) {
 	payloadBytes := []byte{25, 5, 5, 5, 5}
-	c := newCollator(5)
-	payload, collated, err := c.collate(payloadBytes)
+	c := NewCollator(5)
+	payload, collated, err := c.Collate(payloadBytes)
 
 	if err == nil || !strings.Contains(err.Error(), "greater than max number of expected parts") {
-		t.Errorf("collate() failed to return an error when the part number is "+
+		t.Errorf("Collate() failed to return an error when the part number is "+
 			"greater than the max number of parts.\nerror: %+v", err)
 	}
 
 	if payload != nil || collated {
-		t.Errorf("collate() signaled the payload was collated on error."+
+		t.Errorf("Collate() signaled the payload was collated on error."+
 			"\npayload:  %+v\ncollated: %+v", payload, collated)
 	}
 }
@@ -123,20 +123,20 @@ func TestCollator_collate_PartNumTooLargeError(t *testing.T) {
 // Error path: a message with the part number already exists.
 func TestCollator_collate_PartExistsError(t *testing.T) {
 	payloadBytes := []byte{0, 1, 5, 0, 1, 20}
-	c := newCollator(5)
-	payload, collated, err := c.collate(payloadBytes)
+	c := NewCollator(5)
+	payload, collated, err := c.Collate(payloadBytes)
 	if err != nil {
-		t.Fatalf("collate() returned an error: %+v", err)
+		t.Fatalf("Collate() returned an error: %+v", err)
 	}
 
-	payload, collated, err = c.collate(payloadBytes)
+	payload, collated, err = c.Collate(payloadBytes)
 	if err == nil || !strings.Contains(err.Error(), "A payload for the part number") {
-		t.Errorf("collate() failed to return an error when the part number "+
+		t.Errorf("Collate() failed to return an error when the part number "+
 			"already exists.\nerror: %+v", err)
 	}
 
 	if payload != nil || collated {
-		t.Errorf("collate() signaled the payload was collated on error."+
+		t.Errorf("Collate() signaled the payload was collated on error."+
 			"\npayload:  %+v\ncollated: %+v", payload, collated)
 	}
 }
diff --git a/single/transmitMessage.go b/single/message/request.go
similarity index 54%
rename from single/transmitMessage.go
rename to single/message/request.go
index 17ce73acd2a6a5183c5c173f31eb23bd950f41c7..f4397053ad9ed771c9908611ad422ccd9c4a66a3 100644
--- a/single/transmitMessage.go
+++ b/single/message/request.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package single
+package message
 
 import (
 	"encoding/binary"
@@ -22,10 +22,10 @@ import (
 +------------------------------------------------------------------------------+
 |                              CMIX Message Contents                           |
 +------------+--------------------------------------------             --------+
-|   Version  |   pubKey   |          payload (transmitMessagePayload)          |
+|   Version  |   pubKey   |          payload (RequestPayload)          |
 |    1 byte  | pubKeySize |          externalPayloadSize - pubKeySize          |
 +------------+------------+----------+---------+----------+---------+----------+
-                          |  Tag FP  |  nonce  | maxParts |  size   | contents |
+                          |  Tag FP  |  nonce  | maxResponseParts |  size   | contents |
                           | 16 bytes | 8 bytes |  1 byte  | 2 bytes | variable |
                           +----------+---------+----------+---------+----------+
 */
@@ -33,32 +33,32 @@ import (
 const transmitMessageVersion = 0
 const transmitMessageVersionSize = 1
 
-type transmitMessage struct {
+type Request struct {
 	data    []byte // Serial of all contents
 	version []byte
 	pubKey  []byte
 	payload []byte // The encrypted payload containing reception ID and contents
 }
 
-// newTransmitMessage generates a new empty message for transmission that is the
+// NewRequest generates a new empty message for transmission that is the
 // size of the specified external payload.
-func newTransmitMessage(externalPayloadSize, pubKeySize int) transmitMessage {
+func NewRequest(externalPayloadSize, pubKeySize int) Request {
 	if externalPayloadSize < pubKeySize {
 		jww.FATAL.Panicf("Payload size of single-use transmission message "+
 			"(%d) too small to contain the public key (%d).",
 			externalPayloadSize, pubKeySize)
 	}
 
-	tm := mapTransmitMessage(make([]byte, externalPayloadSize), pubKeySize)
+	tm := mapRequest(make([]byte, externalPayloadSize), pubKeySize)
 	tm.version[0] = transmitMessageVersion
 
 	return tm
 }
 
-// mapTransmitMessage builds a message mapped to the passed in data. It is
+// mapRequest builds a message mapped to the passed in data. It is
 // mapped by reference; a copy is not made.
-func mapTransmitMessage(data []byte, pubKeySize int) transmitMessage {
-	return transmitMessage{
+func mapRequest(data []byte, pubKeySize int) Request {
+	return Request{
 		data:    data,
 		version: data[:transmitMessageVersionSize],
 		pubKey:  data[transmitMessageVersionSize : transmitMessageVersionSize+pubKeySize],
@@ -66,55 +66,55 @@ func mapTransmitMessage(data []byte, pubKeySize int) transmitMessage {
 	}
 }
 
-// unmarshalTransmitMessage unmarshalls a byte slice into a transmitMessage. An
+// UnmarshalRequest unmarshalls a byte slice into a Request. An
 // error is returned if the slice is not large enough for the public key size.
-func unmarshalTransmitMessage(b []byte, pubKeySize int) (transmitMessage, error) {
+func UnmarshalRequest(b []byte, pubKeySize int) (Request, error) {
 	if len(b) < pubKeySize {
-		return transmitMessage{}, errors.Errorf("Length of marshaled bytes "+
+		return Request{}, errors.Errorf("Length of marshaled bytes "+
 			"(%d) too small to contain public key (%d).", len(b), pubKeySize)
 	}
 
-	return mapTransmitMessage(b, pubKeySize), nil
+	return mapRequest(b, pubKeySize), nil
 }
 
-// Marshal returns the serialised data of a transmitMessage.
-func (m transmitMessage) Marshal() []byte {
+// Marshal returns the serialised data of a Request.
+func (m Request) Marshal() []byte {
 	return m.data
 }
 
 // GetPubKey returns the public key that is part of the given group.
-func (m transmitMessage) GetPubKey(grp *cyclic.Group) *cyclic.Int {
+func (m Request) GetPubKey(grp *cyclic.Group) *cyclic.Int {
 	return grp.NewIntFromBytes(m.pubKey)
 }
 
 // Version returns the version of the message.
-func (m transmitMessage) Version() uint8 {
+func (m Request) Version() uint8 {
 	return m.version[0]
 }
 
 // GetPubKeySize returns the length of the public key.
-func (m transmitMessage) GetPubKeySize() int {
+func (m Request) GetPubKeySize() int {
 	return len(m.pubKey)
 }
 
 // SetPubKey saves the public key to the message as bytes.
-func (m transmitMessage) SetPubKey(pubKey *cyclic.Int) {
+func (m Request) SetPubKey(pubKey *cyclic.Int) {
 	copy(m.pubKey, pubKey.LeftpadBytes(uint64(len(m.pubKey))))
 }
 
 // GetPayload returns the encrypted payload of the message.
-func (m transmitMessage) GetPayload() []byte {
+func (m Request) GetPayload() []byte {
 	return m.payload
 }
 
 // GetPayloadSize returns the length of the encrypted payload.
-func (m transmitMessage) GetPayloadSize() int {
+func (m Request) GetPayloadSize() int {
 	return len(m.payload)
 }
 
 // SetPayload saves the supplied bytes as the payload of the message, if the
 // size is correct.
-func (m transmitMessage) SetPayload(b []byte) {
+func (m Request) SetPayload(b []byte) {
 	if len(b) != len(m.payload) {
 		jww.FATAL.Panicf("Size of payload of single-use transmission message "+
 			"(%d) is not the same as the size of the supplied payload (%d).",
@@ -125,27 +125,26 @@ func (m transmitMessage) SetPayload(b []byte) {
 }
 
 const (
-	tagFPSize         = singleUse.TagFpSize
 	nonceSize         = 8
 	maxPartsSize      = 1
 	sizeSize          = 2
-	transmitPlMinSize = tagFPSize + nonceSize + maxPartsSize + sizeSize
+	transmitPlMinSize = nonceSize + maxPartsSize + sizeSize
 )
 
-// transmitMessagePayload is the structure of transmitMessage's payload.
-type transmitMessagePayload struct {
-	data     []byte // Serial of all contents
-	tagFP    []byte // Tag fingerprint identifies the type of message
-	nonce    []byte
-	maxParts []byte // Max number of messages expected in response
-	size     []byte // Size of the contents
-	contents []byte
+// RequestPayload is the structure of Request's payload.
+type RequestPayload struct {
+	data             []byte // Serial of all contents e
+	nonce            []byte
+	nunRequestParts  []byte
+	maxResponseParts []byte // Max number of messages expected in response
+	size             []byte // Size of the contents
+	contents         []byte
 }
 
-// newTransmitMessage generates a new empty message for transmission that is the
+// NewRequestPayload generates a new empty message for transmission that is the
 // size of the specified payload, which should match the size of the payload in
-// the corresponding transmitMessage.
-func newTransmitMessagePayload(payloadSize int) transmitMessagePayload {
+// the corresponding Request.
+func NewRequestPayload(payloadSize int, payload []byte, maxMsgs uint8) RequestPayload {
 	if payloadSize < transmitPlMinSize {
 		jww.FATAL.Panicf("Size of single-use transmission message payload "+
 			"(%d) too small to contain the necessary data (%d).",
@@ -153,67 +152,58 @@ func newTransmitMessagePayload(payloadSize int) transmitMessagePayload {
 	}
 
 	// Map fields to data
-	mp := mapTransmitMessagePayload(make([]byte, payloadSize))
+	mp := mapRequestPayload(make([]byte, payloadSize))
 
+	mp.SetMaxResponseParts(maxMsgs)
+	mp.SetContents(payload)
 	return mp
 }
 
-// mapTransmitMessagePayload builds a message payload mapped to the passed in
+// mapRequestPayload builds a message payload mapped to the passed in
 // data. It is mapped by reference; a copy is not made.
-func mapTransmitMessagePayload(data []byte) transmitMessagePayload {
-	mp := transmitMessagePayload{
-		data:     data,
-		tagFP:    data[:tagFPSize],
-		nonce:    data[tagFPSize : tagFPSize+nonceSize],
-		maxParts: data[tagFPSize+nonceSize : tagFPSize+nonceSize+maxPartsSize],
-		size:     data[tagFPSize+nonceSize+maxPartsSize : transmitPlMinSize],
-		contents: data[transmitPlMinSize:],
+func mapRequestPayload(data []byte) RequestPayload {
+	mp := RequestPayload{
+		data:             data,
+		nonce:            data[:nonceSize],
+		maxResponseParts: data[nonceSize : nonceSize+maxPartsSize],
+		size:             data[nonceSize+maxPartsSize : transmitPlMinSize],
+		contents:         data[transmitPlMinSize:],
 	}
 
 	return mp
 }
 
-// unmarshalTransmitMessagePayload unmarshalls a byte slice into a
-// transmitMessagePayload. An error is returned if the slice is not large enough
+// UnmarshalRequestPayload unmarshalls a byte slice into a
+// RequestPayload. An error is returned if the slice is not large enough
 // for the reception ID and message count.
-func unmarshalTransmitMessagePayload(b []byte) (transmitMessagePayload, error) {
+func UnmarshalRequestPayload(b []byte) (RequestPayload, error) {
 	if len(b) < transmitPlMinSize {
-		return transmitMessagePayload{}, errors.Errorf("Length of marshaled "+
+		return RequestPayload{}, errors.Errorf("Length of marshaled "+
 			"bytes(%d) too small to contain the necessary data (%d).",
 			len(b), transmitPlMinSize)
 	}
 
-	return mapTransmitMessagePayload(b), nil
+	return mapRequestPayload(b), nil
 }
 
-// Marshal returns the serialised data of a transmitMessagePayload.
-func (mp transmitMessagePayload) Marshal() []byte {
+// Marshal returns the serialised data of a RequestPayload.
+func (mp RequestPayload) Marshal() []byte {
 	return mp.data
 }
 
 // GetRID generates the reception ID from the bytes of the payload.
-func (mp transmitMessagePayload) GetRID(pubKey *cyclic.Int) *id.ID {
+func (mp RequestPayload) GetRID(pubKey *cyclic.Int) *id.ID {
 	return singleUse.NewRecipientID(pubKey, mp.Marshal())
 }
 
-// GetTagFP returns the tag fingerprint.
-func (mp transmitMessagePayload) GetTagFP() singleUse.TagFP {
-	return singleUse.UnmarshalTagFP(mp.tagFP)
-}
-
-// SetTagFP sets the tag fingerprint.
-func (mp transmitMessagePayload) SetTagFP(tagFP singleUse.TagFP) {
-	copy(mp.tagFP, tagFP.Bytes())
-}
-
 // GetNonce returns the nonce as a uint64.
-func (mp transmitMessagePayload) GetNonce() uint64 {
+func (mp RequestPayload) GetNonce() uint64 {
 	return binary.BigEndian.Uint64(mp.nonce)
 }
 
 // SetNonce generates a random nonce from the RNG. An error is returned if the
 // reader fails.
-func (mp transmitMessagePayload) SetNonce(rng io.Reader) error {
+func (mp RequestPayload) SetNonce(rng io.Reader) error {
 	if _, err := rng.Read(mp.nonce); err != nil {
 		return errors.Errorf("failed to generate nonce: %+v", err)
 	}
@@ -221,34 +211,34 @@ func (mp transmitMessagePayload) SetNonce(rng io.Reader) error {
 	return nil
 }
 
-// GetMaxParts returns the number of messages expected in response.
-func (mp transmitMessagePayload) GetMaxParts() uint8 {
-	return mp.maxParts[0]
+// GetMaxResponseParts returns the number of messages expected in response.
+func (mp RequestPayload) GetMaxResponseParts() uint8 {
+	return mp.maxResponseParts[0]
 }
 
-// SetMaxParts sets the number of expected messages.
-func (mp transmitMessagePayload) SetMaxParts(num uint8) {
-	copy(mp.maxParts, []byte{num})
+// SetMaxResponseParts sets the number of expected messages.
+func (mp RequestPayload) SetMaxResponseParts(num uint8) {
+	copy(mp.maxResponseParts, []byte{num})
 }
 
 // GetContents returns the payload's contents.
-func (mp transmitMessagePayload) GetContents() []byte {
+func (mp RequestPayload) GetContents() []byte {
 	return mp.contents[:binary.BigEndian.Uint16(mp.size)]
 }
 
 // GetContentsSize returns the length of payload's contents.
-func (mp transmitMessagePayload) GetContentsSize() int {
+func (mp RequestPayload) GetContentsSize() int {
 	return int(binary.BigEndian.Uint16(mp.size))
 }
 
 // GetMaxContentsSize returns the max capacity of the contents.
-func (mp transmitMessagePayload) GetMaxContentsSize() int {
+func (mp RequestPayload) GetMaxContentsSize() int {
 	return len(mp.contents)
 }
 
 // SetContents saves the contents to the payload, if the size is correct. Does
 // not zero out previous content.
-func (mp transmitMessagePayload) SetContents(contents []byte) {
+func (mp RequestPayload) SetContents(contents []byte) {
 	if len(contents) > len(mp.contents) {
 		jww.FATAL.Panicf("Failed to set contents of single-use transmission "+
 			"message: max size of message content (%d) is smaller than the "+
@@ -262,9 +252,9 @@ func (mp transmitMessagePayload) SetContents(contents []byte) {
 }
 
 // String returns the contents for printing adhering to the stringer interface.
-func (mp transmitMessagePayload) String() string {
-	return fmt.Sprintf("Data: %x [tagFP: %x, nonce: %x, "+
-		"maxParts: %x, size: %x, content: %x]", mp.data, mp.tagFP,
-		mp.nonce, mp.maxParts, mp.size, mp.contents)
+func (mp RequestPayload) String() string {
+	return fmt.Sprintf("Data: %x [nonce: %x, "+
+		"maxResponseParts: %x, size: %x, content: %x]", mp.data,
+		mp.nonce, mp.maxResponseParts, mp.size, mp.contents)
 
 }
diff --git a/single/transmitMessage_test.go b/single/message/request_test.go
similarity index 77%
rename from single/transmitMessage_test.go
rename to single/message/request_test.go
index b6c62d25b71f507d54d1f69a70c0a35e932af628..8b5d2f6e6e6c1175bf75905fcf79631c8a7cbec3 100644
--- a/single/transmitMessage_test.go
+++ b/single/message/request_test.go
@@ -5,11 +5,12 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package single
+package message
 
 import (
 	"bytes"
 	"encoding/binary"
+	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e/singleUse"
 	"gitlab.com/elixxir/primitives/format"
@@ -25,17 +26,17 @@ func Test_newTransmitMessage(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	externalPayloadSize := prng.Intn(2000)
 	pubKeySize := prng.Intn(externalPayloadSize)
-	expected := transmitMessage{
+	expected := Request{
 		data:    make([]byte, externalPayloadSize),
 		version: make([]byte, transmitMessageVersionSize),
 		pubKey:  make([]byte, pubKeySize),
 		payload: make([]byte, externalPayloadSize-pubKeySize-transmitMessageVersionSize),
 	}
 
-	m := newTransmitMessage(externalPayloadSize, pubKeySize)
+	m := NewRequest(externalPayloadSize, pubKeySize)
 
 	if !reflect.DeepEqual(expected, m) {
-		t.Errorf("newTransmitMessage() did not produce the expected transmitMessage."+
+		t.Errorf("NewRequest() did not produce the expected Request."+
 			"\nexpected: %#v\nreceived: %#v", expected, m)
 	}
 }
@@ -44,12 +45,12 @@ func Test_newTransmitMessage(t *testing.T) {
 func Test_newTransmitMessage_PubKeySizeError(t *testing.T) {
 	defer func() {
 		if r := recover(); r == nil || !strings.Contains(r.(string), "Payload size") {
-			t.Error("newTransmitMessage() did not panic when the size of " +
+			t.Error("NewRequest() did not panic when the size of " +
 				"the payload is smaller than the size of the public key.")
 		}
 	}()
 
-	_ = newTransmitMessage(5, 10)
+	_ = NewRequest(5, 10)
 }
 
 // Happy path.
@@ -66,20 +67,20 @@ func Test_mapTransmitMessage(t *testing.T) {
 	data = append(data, version...)
 	data = append(data, pubKey...)
 	data = append(data, payload...)
-	m := mapTransmitMessage(data, pubKeySize)
+	m := mapRequest(data, pubKeySize)
 
 	if !bytes.Equal(data, m.data) {
-		t.Errorf("mapTransmitMessage() failed to map the correct bytes for data."+
+		t.Errorf("mapRequest() failed to map the correct bytes for data."+
 			"\nexpected: %+v\nreceived: %+v", data, m.data)
 	}
 
 	if !bytes.Equal(pubKey, m.pubKey) {
-		t.Errorf("mapTransmitMessage() failed to map the correct bytes for pubKey."+
+		t.Errorf("mapRequest() failed to map the correct bytes for pubKey."+
 			"\nexpected: %+v\nreceived: %+v", pubKey, m.pubKey)
 	}
 
 	if !bytes.Equal(payload, m.payload) {
-		t.Errorf("mapTransmitMessage() failed to map the correct bytes for payload."+
+		t.Errorf("mapRequest() failed to map the correct bytes for payload."+
 			"\nexpected: %+v\nreceived: %+v", payload, m.payload)
 	}
 }
@@ -91,13 +92,13 @@ func TestTransmitMessage_Marshal_Unmarshal(t *testing.T) {
 	pubKeySize := prng.Intn(externalPayloadSize)
 	data := make([]byte, externalPayloadSize)
 	prng.Read(data)
-	m := mapTransmitMessage(data, pubKeySize)
+	m := mapRequest(data, pubKeySize)
 
 	msgBytes := m.Marshal()
 
-	newMsg, err := unmarshalTransmitMessage(msgBytes, pubKeySize)
+	newMsg, err := unmarshalRequest(msgBytes, pubKeySize)
 	if err != nil {
-		t.Errorf("unmarshalTransmitMessage produced an error: %+v", err)
+		t.Errorf("unmarshalRequest produced an error: %+v", err)
 	}
 
 	if !reflect.DeepEqual(m, newMsg) {
@@ -108,9 +109,9 @@ func TestTransmitMessage_Marshal_Unmarshal(t *testing.T) {
 
 // Error path: public key size is larger than byte slice.
 func Test_unmarshalTransmitMessage_PubKeySizeError(t *testing.T) {
-	_, err := unmarshalTransmitMessage([]byte{1, 2, 3}, 5)
+	_, err := unmarshalRequest([]byte{1, 2, 3}, 5)
 	if err == nil {
-		t.Error("unmarshalTransmitMessage() did not produce an error when the " +
+		t.Error("unmarshalRequest() did not produce an error when the " +
 			"byte slice is smaller than the public key size.")
 	}
 }
@@ -120,7 +121,7 @@ func TestTransmitMessage_SetPubKey_GetPubKey_GetPubKeySize(t *testing.T) {
 	grp := getGroup()
 	pubKey := grp.NewInt(5)
 	pubKeySize := 10
-	m := newTransmitMessage(255, pubKeySize)
+	m := NewRequest(255, pubKeySize)
 
 	m.SetPubKey(pubKey)
 	testPubKey := m.GetPubKey(grp)
@@ -143,7 +144,7 @@ func TestTransmitMessage_SetPayload_GetPayload_GetPayloadSize(t *testing.T) {
 	payloadSize := externalPayloadSize - pubKeySize - transmitMessageVersionSize
 	payload := make([]byte, payloadSize)
 	prng.Read(payload)
-	m := newTransmitMessage(externalPayloadSize, pubKeySize)
+	m := NewRequest(externalPayloadSize, pubKeySize)
 
 	m.SetPayload(payload)
 	testPayload := m.GetPayload()
@@ -168,7 +169,7 @@ func TestTransmitMessage_SetPayload_PayloadSizeError(t *testing.T) {
 		}
 	}()
 
-	m := newTransmitMessage(255, 10)
+	m := NewRequest(255, 10)
 	m.SetPayload([]byte{5})
 }
 
@@ -176,34 +177,34 @@ func TestTransmitMessage_SetPayload_PayloadSizeError(t *testing.T) {
 func Test_newTransmitMessagePayload(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	payloadSize := prng.Intn(2000)
-	expected := transmitMessagePayload{
-		data:     make([]byte, payloadSize),
-		tagFP:    make([]byte, tagFPSize),
-		nonce:    make([]byte, nonceSize),
-		maxParts: make([]byte, maxPartsSize),
-		size:     make([]byte, sizeSize),
-		contents: make([]byte, payloadSize-transmitPlMinSize),
+	expected := RequestPayload{
+		data:             make([]byte, payloadSize),
+		tagFP:            make([]byte, tagFPSize),
+		nonce:            make([]byte, nonceSize),
+		maxResponseParts: make([]byte, maxPartsSize),
+		size:             make([]byte, sizeSize),
+		contents:         make([]byte, payloadSize-transmitPlMinSize),
 	}
 
-	mp := newTransmitMessagePayload(payloadSize)
+	mp := NewRequestPayload(payloadSize)
 
 	if !reflect.DeepEqual(expected, mp) {
-		t.Errorf("newTransmitMessagePayload() did not produce the expected "+
-			"transmitMessagePayload.\nexpected: %+v\nreceived: %+v", expected, mp)
+		t.Errorf("NewRequestPayload() did not produce the expected "+
+			"RequestPayload.\nexpected: %+v\nreceived: %+v", expected, mp)
 	}
 }
 
-// Error path: payload size is smaller than than rid size + maxParts size.
+// Error path: payload size is smaller than than rid size + maxResponseParts size.
 func Test_newTransmitMessagePayload_PayloadSizeError(t *testing.T) {
 	defer func() {
 		if r := recover(); r == nil || !strings.Contains(r.(string), "Size of single-use transmission message payload") {
-			t.Error("newTransmitMessagePayload() did not panic when the size " +
+			t.Error("NewRequestPayload() did not panic when the size " +
 				"of the payload is smaller than the size of the reception ID " +
 				"+ the message count.")
 		}
 	}()
 
-	_ = newTransmitMessagePayload(10)
+	_ = NewRequestPayload(10)
 }
 
 // Happy path.
@@ -221,35 +222,35 @@ func Test_mapTransmitMessagePayload(t *testing.T) {
 	data = append(data, num)
 	data = append(data, size...)
 	data = append(data, contents...)
-	mp := mapTransmitMessagePayload(data)
+	mp := mapRequestPayload(data)
 
 	if !bytes.Equal(data, mp.data) {
-		t.Errorf("mapTransmitMessagePayload() failed to map the correct bytes "+
+		t.Errorf("mapRequestPayload() failed to map the correct bytes "+
 			"for data.\nexpected: %+v\nreceived: %+v", data, mp.data)
 	}
 
 	if !bytes.Equal(tagFP.Bytes(), mp.tagFP) {
-		t.Errorf("mapTransmitMessagePayload() failed to map the correct bytes "+
+		t.Errorf("mapRequestPayload() failed to map the correct bytes "+
 			"for tagFP.\nexpected: %+v\nreceived: %+v", tagFP.Bytes(), mp.tagFP)
 	}
 
 	if !bytes.Equal(nonceBytes, mp.nonce) {
-		t.Errorf("mapTransmitMessagePayload() failed to map the correct bytes "+
+		t.Errorf("mapRequestPayload() failed to map the correct bytes "+
 			"for the nonce.\nexpected: %s\nreceived: %s", nonceBytes, mp.nonce)
 	}
 
-	if num != mp.maxParts[0] {
-		t.Errorf("mapTransmitMessagePayload() failed to map the correct bytes "+
-			"for maxParts.\nexpected: %d\nreceived: %d", num, mp.maxParts[0])
+	if num != mp.maxResponseParts[0] {
+		t.Errorf("mapRequestPayload() failed to map the correct bytes "+
+			"for maxResponseParts.\nexpected: %d\nreceived: %d", num, mp.maxResponseParts[0])
 	}
 
 	if !bytes.Equal(size, mp.size) {
-		t.Errorf("mapTransmitMessagePayload() failed to map the correct bytes "+
+		t.Errorf("mapRequestPayload() failed to map the correct bytes "+
 			"for size.\nexpected: %+v\nreceived: %+v", size, mp.size)
 	}
 
 	if !bytes.Equal(contents, mp.contents) {
-		t.Errorf("mapTransmitMessagePayload() failed to map the correct bytes "+
+		t.Errorf("mapRequestPayload() failed to map the correct bytes "+
 			"for contents.\nexpected: %+v\nreceived: %+v", contents, mp.contents)
 	}
 }
@@ -259,13 +260,13 @@ func TestTransmitMessagePayload_Marshal_Unmarshal(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	data := make([]byte, prng.Intn(1000))
 	prng.Read(data)
-	mp := mapTransmitMessagePayload(data)
+	mp := mapRequestPayload(data)
 
 	payloadBytes := mp.Marshal()
 
-	testPayload, err := unmarshalTransmitMessagePayload(payloadBytes)
+	testPayload, err := UnmarshalRequestPayload(payloadBytes)
 	if err != nil {
-		t.Errorf("unmarshalTransmitMessagePayload() produced an error: %+v", err)
+		t.Errorf("UnmarshalRequestPayload() produced an error: %+v", err)
 	}
 
 	if !reflect.DeepEqual(mp, testPayload) {
@@ -276,9 +277,9 @@ func TestTransmitMessagePayload_Marshal_Unmarshal(t *testing.T) {
 
 // Error path: supplied byte slice is too small for the ID and message count.
 func Test_unmarshalTransmitMessagePayload(t *testing.T) {
-	_, err := unmarshalTransmitMessagePayload([]byte{6})
+	_, err := UnmarshalRequestPayload([]byte{6})
 	if err == nil {
-		t.Error("unmarshalTransmitMessagePayload() did not return an error " +
+		t.Error("UnmarshalRequestPayload() did not return an error " +
 			"when the supplied byte slice was too small.")
 	}
 }
@@ -286,7 +287,7 @@ func Test_unmarshalTransmitMessagePayload(t *testing.T) {
 // Happy path.
 func TestTransmitMessagePayload_GetRID(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
-	mp := newTransmitMessagePayload(prng.Intn(2000))
+	mp := NewRequestPayload(prng.Intn(2000))
 	expectedRID := singleUse.NewRecipientID(getGroup().NewInt(42), mp.Marshal())
 
 	testRID := mp.GetRID(getGroup().NewInt(42))
@@ -300,7 +301,7 @@ func TestTransmitMessagePayload_GetRID(t *testing.T) {
 // Happy path.
 func Test_transmitMessagePayload_SetNonce_GetNonce(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
-	mp := newTransmitMessagePayload(prng.Intn(2000))
+	mp := NewRequestPayload(prng.Intn(2000))
 
 	expectedNonce := prng.Uint64()
 	expectedNonceBytes := make([]byte, 8)
@@ -319,9 +320,9 @@ func Test_transmitMessagePayload_SetNonce_GetNonce(t *testing.T) {
 // Error path: RNG return an error.
 func Test_transmitMessagePayload_SetNonce_RngError(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
-	mp := newTransmitMessagePayload(prng.Intn(2000))
+	mp := NewRequestPayload(prng.Intn(2000))
 	err := mp.SetNonce(strings.NewReader(""))
-	if !check(err, "failed to generate nonce") {
+	if !single.check(err, "failed to generate nonce") {
 		t.Errorf("SetNonce() did not return an error when nonce generation "+
 			"fails: %+v", err)
 	}
@@ -330,14 +331,14 @@ func Test_transmitMessagePayload_SetNonce_RngError(t *testing.T) {
 // Happy path.
 func TestTransmitMessagePayload_SetMaxParts_GetMaxParts(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
-	mp := newTransmitMessagePayload(prng.Intn(2000))
+	mp := NewRequestPayload(prng.Intn(2000))
 	count := uint8(prng.Uint64())
 
-	mp.SetMaxParts(count)
-	testCount := mp.GetMaxParts()
+	mp.SetMaxResponseParts(count)
+	testCount := mp.GetMaxResponseParts()
 
 	if count != testCount {
-		t.Errorf("GetMaxParts() did not return the expected count."+
+		t.Errorf("GetNumParts() did not return the expected count."+
 			"\nexpected: %d\nreceived: %d", count, testCount)
 	}
 }
@@ -345,7 +346,7 @@ func TestTransmitMessagePayload_SetMaxParts_GetMaxParts(t *testing.T) {
 // Happy path.
 func TestTransmitMessagePayload_SetContents_GetContents_GetContentsSize_GetMaxContentsSize(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
-	mp := newTransmitMessagePayload(format.MinimumPrimeSize)
+	mp := NewRequestPayload(format.MinimumPrimeSize)
 	contentsSize := (format.MinimumPrimeSize - transmitPlMinSize) / 2
 	contents := make([]byte, contentsSize)
 	prng.Read(contents)
@@ -377,7 +378,7 @@ func TestTransmitMessagePayload_SetContents(t *testing.T) {
 		}
 	}()
 
-	mp := newTransmitMessagePayload(format.MinimumPrimeSize)
+	mp := NewRequestPayload(format.MinimumPrimeSize)
 	mp.SetContents(make([]byte, format.MinimumPrimeSize+1))
 }
 
diff --git a/single/responseMessage.go b/single/message/response.go
similarity index 71%
rename from single/responseMessage.go
rename to single/message/response.go
index 191038dcb7665b17578268c85623af858b1601fb..2fde98e94019e538b4fbf638d143079a363ecaae 100644
--- a/single/responseMessage.go
+++ b/single/message/response.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package single
+package message
 
 import (
 	"encoding/binary"
@@ -25,12 +25,12 @@ const (
 +---------------------------------------------------+
 |                CMIX Message Contents              |
 +---------+----------+---------+---------+----------+
-| version | maxParts |  size   | partNum | contents |
+| version | maxResponseParts |  size   | partNum | contents |
 | 1 bytes |  1 byte  | 2 bytes | 1 bytes | variable |
 +------------+----------+---------+------+----------+
 */
 
-type responseMessagePart struct {
+type ResponsePart struct {
 	data     []byte // Serial of all contents
 	version  []byte // Version of the message
 	partNum  []byte // Index of message in a series of messages
@@ -39,9 +39,9 @@ type responseMessagePart struct {
 	contents []byte // The encrypted contents
 }
 
-// newResponseMessagePart generates a new response message part of the specified
+// NewResponsePart generates a new response message part of the specified
 // size.
-func newResponseMessagePart(externalPayloadSize int) responseMessagePart {
+func NewResponsePart(externalPayloadSize int) ResponsePart {
 	if externalPayloadSize < responseMinSize {
 		jww.FATAL.Panicf("Failed to create new single-use response message "+
 			"part: size of external payload (%d) is too small to contain the "+
@@ -49,15 +49,15 @@ func newResponseMessagePart(externalPayloadSize int) responseMessagePart {
 			externalPayloadSize, responseMinSize)
 	}
 
-	rmp := mapResponseMessagePart(make([]byte, externalPayloadSize))
+	rmp := mapResponsePart(make([]byte, externalPayloadSize))
 	rmp.version[0] = receptionMessageVersion
 	return rmp
 }
 
-// mapResponseMessagePart builds a message part mapped to the passed in data.
+// mapResponsePart builds a message part mapped to the passed in data.
 // It is mapped by reference; a copy is not made.
-func mapResponseMessagePart(data []byte) responseMessagePart {
-	return responseMessagePart{
+func mapResponsePart(data []byte) ResponsePart {
+	return ResponsePart{
 		data:     data,
 		version:  data[:receptionMessageVersionLen],
 		partNum:  data[receptionMessageVersionLen : receptionMessageVersionLen+partNumLen],
@@ -67,59 +67,59 @@ func mapResponseMessagePart(data []byte) responseMessagePart {
 	}
 }
 
-// unmarshalResponseMessage converts a byte buffer into a response message part.
-func unmarshalResponseMessage(b []byte) (responseMessagePart, error) {
+// UnmarshalResponse converts a byte buffer into a response message part.
+func UnmarshalResponse(b []byte) (ResponsePart, error) {
 	if len(b) < responseMinSize {
-		return responseMessagePart{}, errors.Errorf("Size of passed in bytes "+
+		return ResponsePart{}, errors.Errorf("Size of passed in bytes "+
 			"(%d) is too small to contain the message part number and max "+
 			"parts (%d).", len(b), responseMinSize)
 	}
-	return mapResponseMessagePart(b), nil
+	return mapResponsePart(b), nil
 }
 
 // Marshal returns the bytes of the message part.
-func (m responseMessagePart) Marshal() []byte {
+func (m ResponsePart) Marshal() []byte {
 	return m.data
 }
 
 // GetPartNum returns the index of this part in the message.
-func (m responseMessagePart) GetPartNum() uint8 {
+func (m ResponsePart) GetPartNum() uint8 {
 	return m.partNum[0]
 }
 
 // SetPartNum sets the part number of the message.
-func (m responseMessagePart) SetPartNum(num uint8) {
+func (m ResponsePart) SetPartNum(num uint8) {
 	copy(m.partNum, []byte{num})
 }
 
-// GetMaxParts returns the number of parts in the message.
-func (m responseMessagePart) GetMaxParts() uint8 {
+// GetNumParts returns the number of parts in the message.
+func (m ResponsePart) GetNumParts() uint8 {
 	return m.maxParts[0]
 }
 
-// SetMaxParts sets the number of parts in the message.
-func (m responseMessagePart) SetMaxParts(max uint8) {
+// SetNumParts sets the number of parts in the message.
+func (m ResponsePart) SetNumParts(max uint8) {
 	copy(m.maxParts, []byte{max})
 }
 
 // GetContents returns the contents of the message part.
-func (m responseMessagePart) GetContents() []byte {
+func (m ResponsePart) GetContents() []byte {
 	return m.contents[:binary.BigEndian.Uint16(m.size)]
 }
 
 // GetContentsSize returns the length of the contents.
-func (m responseMessagePart) GetContentsSize() int {
+func (m ResponsePart) GetContentsSize() int {
 	return int(binary.BigEndian.Uint16(m.size))
 }
 
 // GetMaxContentsSize returns the max capacity of the contents.
-func (m responseMessagePart) GetMaxContentsSize() int {
+func (m ResponsePart) GetMaxContentsSize() int {
 	return len(m.contents)
 }
 
 // SetContents sets the contents of the message part. Does not zero out previous
 // contents.
-func (m responseMessagePart) SetContents(contents []byte) {
+func (m ResponsePart) SetContents(contents []byte) {
 	if len(contents) > len(m.contents) {
 		jww.FATAL.Panicf("Failed to set contents of single-use response "+
 			"message part: max size of message contents (%d) is smaller than "+
diff --git a/single/responseMessage_test.go b/single/message/response_test.go
similarity index 77%
rename from single/responseMessage_test.go
rename to single/message/response_test.go
index f9a78f068fb90021f1a7a9f9571ca02d244b91d1..4d4e85fcb2c6bae21f48c85c6059615f6a65c969 100644
--- a/single/responseMessage_test.go
+++ b/single/message/response_test.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package single
+package message
 
 import (
 	"bytes"
@@ -19,7 +19,7 @@ import (
 func Test_newResponseMessagePart(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	payloadSize := prng.Intn(2000)
-	expected := responseMessagePart{
+	expected := ResponsePart{
 		data:     make([]byte, payloadSize),
 		version:  make([]byte, receptionMessageVersionLen),
 		partNum:  make([]byte, partNumLen),
@@ -28,11 +28,11 @@ func Test_newResponseMessagePart(t *testing.T) {
 		contents: make([]byte, payloadSize-partNumLen-maxPartsLen-sizeSize-receptionMessageVersionLen),
 	}
 
-	rmp := newResponseMessagePart(payloadSize)
+	rmp := NewResponsePart(payloadSize)
 
 	if !reflect.DeepEqual(expected, rmp) {
-		t.Errorf("newResponseMessagePart() did not return the expected "+
-			"responseMessagePart.\nexpected: %+v\nreceived: %+v", expected, rmp)
+		t.Errorf("NewResponsePart() did not return the expected "+
+			"ResponsePart.\nexpected: %+v\nreceived: %+v", expected, rmp)
 	}
 }
 
@@ -40,12 +40,12 @@ func Test_newResponseMessagePart(t *testing.T) {
 func Test_newResponseMessagePart_PayloadSizeError(t *testing.T) {
 	defer func() {
 		if r := recover(); r == nil || !strings.Contains(r.(string), "size of external payload") {
-			t.Error("newResponseMessagePart() did not panic when the size of " +
+			t.Error("NewResponsePart() did not panic when the size of " +
 				"the payload is smaller than the required size.")
 		}
 	}()
 
-	_ = newResponseMessagePart(1)
+	_ = NewResponsePart(1)
 }
 
 // Happy path.
@@ -62,25 +62,25 @@ func Test_mapResponseMessagePart(t *testing.T) {
 	data = append(data, size...)
 	data = append(data, expectedContents...)
 
-	rmp := mapResponseMessagePart(data)
+	rmp := mapResponsePart(data)
 
 	if expectedPartNum != rmp.partNum[0] {
-		t.Errorf("mapResponseMessagePart() did not correctly map partNum."+
+		t.Errorf("mapResponsePart() did not correctly map partNum."+
 			"\nexpected: %d\nreceived: %d", expectedPartNum, rmp.partNum[0])
 	}
 
 	if expectedMaxParts != rmp.maxParts[0] {
-		t.Errorf("mapResponseMessagePart() did not correctly map maxParts."+
+		t.Errorf("mapResponsePart() did not correctly map maxResponseParts."+
 			"\nexpected: %d\nreceived: %d", expectedMaxParts, rmp.maxParts[0])
 	}
 
 	if !bytes.Equal(expectedContents, rmp.contents) {
-		t.Errorf("mapResponseMessagePart() did not correctly map contents."+
+		t.Errorf("mapResponsePart() did not correctly map contents."+
 			"\nexpected: %+v\nreceived: %+v", expectedContents, rmp.contents)
 	}
 
 	if !bytes.Equal(data, rmp.data) {
-		t.Errorf("mapResponseMessagePart() did not save the data correctly."+
+		t.Errorf("mapResponsePart() did not save the data correctly."+
 			"\nexpected: %+v\nreceived: %+v", data, rmp.data)
 	}
 }
@@ -90,26 +90,26 @@ func TestResponseMessagePart_Marshal_Unmarshal(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	payload := make([]byte, prng.Intn(2000))
 	prng.Read(payload)
-	rmp := newResponseMessagePart(prng.Intn(2000))
+	rmp := NewResponsePart(prng.Intn(2000))
 
 	data := rmp.Marshal()
 
-	newRmp, err := unmarshalResponseMessage(data)
+	newRmp, err := UnmarshalResponse(data)
 	if err != nil {
-		t.Errorf("unmarshalResponseMessage() produced an error: %+v", err)
+		t.Errorf("UnmarshalResponse() produced an error: %+v", err)
 	}
 
 	if !reflect.DeepEqual(rmp, newRmp) {
-		t.Errorf("Failed to Marshal() and unmarshal() the responseMessagePart."+
+		t.Errorf("Failed to Marshal() and unmarshal() the ResponsePart."+
 			"\nexpected: %+v\nrecieved: %+v", rmp, newRmp)
 	}
 }
 
 // Error path: provided bytes are too small.
 func Test_unmarshalResponseMessage(t *testing.T) {
-	_, err := unmarshalResponseMessage([]byte{1})
+	_, err := UnmarshalResponse([]byte{1})
 	if err == nil {
-		t.Error("unmarshalResponseMessage() did not produce an error when the " +
+		t.Error("UnmarshalResponse() did not produce an error when the " +
 			"byte slice is smaller required.")
 	}
 }
@@ -118,7 +118,7 @@ func Test_unmarshalResponseMessage(t *testing.T) {
 func TestResponseMessagePart_SetPartNum_GetPartNum(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	expectedPartNum := uint8(prng.Uint32())
-	rmp := newResponseMessagePart(prng.Intn(2000))
+	rmp := NewResponsePart(prng.Intn(2000))
 
 	rmp.SetPartNum(expectedPartNum)
 
@@ -132,13 +132,13 @@ func TestResponseMessagePart_SetPartNum_GetPartNum(t *testing.T) {
 func TestResponseMessagePart_SetMaxParts_GetMaxParts(t *testing.T) {
 	prng := rand.New(rand.NewSource(42))
 	expectedMaxParts := uint8(prng.Uint32())
-	rmp := newResponseMessagePart(prng.Intn(2000))
+	rmp := NewResponsePart(prng.Intn(2000))
 
-	rmp.SetMaxParts(expectedMaxParts)
+	rmp.SetNumParts(expectedMaxParts)
 
-	if expectedMaxParts != rmp.GetMaxParts() {
-		t.Errorf("GetMaxParts() failed to return the expected max parts."+
-			"\nexpected: %d\nrecieved: %d", expectedMaxParts, rmp.GetMaxParts())
+	if expectedMaxParts != rmp.GetNumParts() {
+		t.Errorf("GetNumParts() failed to return the expected max parts."+
+			"\nexpected: %d\nrecieved: %d", expectedMaxParts, rmp.GetNumParts())
 	}
 }
 
@@ -149,7 +149,7 @@ func TestResponseMessagePart_SetContents_GetContents_GetContentsSize_GetMaxConte
 	contentSize := externalPayloadSize - responseMinSize - 10
 	expectedContents := make([]byte, contentSize)
 	prng.Read(expectedContents)
-	rmp := newResponseMessagePart(externalPayloadSize)
+	rmp := NewResponsePart(externalPayloadSize)
 	rmp.SetContents(expectedContents)
 
 	if !bytes.Equal(expectedContents, rmp.GetContents()) {
@@ -178,6 +178,6 @@ func TestResponseMessagePart_SetContents_ContentsSizeError(t *testing.T) {
 		}
 	}()
 
-	rmp := newResponseMessagePart(255)
+	rmp := NewResponsePart(255)
 	rmp.SetContents(make([]byte, 500))
 }
diff --git a/single/receiveResponse.go b/single/receiveResponse.go
deleted file mode 100644
index 19d17da6ccb2e03efa1005060fc7252fa7497c7d..0000000000000000000000000000000000000000
--- a/single/receiveResponse.go
+++ /dev/null
@@ -1,128 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"fmt"
-	"github.com/pkg/errors"
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"strings"
-)
-
-// receiveResponseHandler handles the reception of single-use response messages.
-func (m *Manager) receiveResponseHandler(rawMessages chan message.Receive,
-	stop *stoppable.Single) {
-	jww.DEBUG.Print("Waiting to receive single-use response messages.")
-	for {
-		select {
-		case <-stop.Quit():
-			jww.DEBUG.Printf("Stopping waiting to receive single-use " +
-				"response message.")
-			stop.ToStopped()
-			return
-		case msg := <-rawMessages:
-			jww.TRACE.Printf("Received CMIX message; checking if it is a " +
-				"single-use response.")
-
-			// Process CMIX message
-			err := m.processesResponse(msg.RecipientID, msg.EphemeralID, msg.Payload)
-			if err != nil {
-				em := fmt.Sprintf("Failed to read single-use "+
-					"CMIX message response: %+v", err)
-				if strings.Contains(err.Error(), "no state exists for the reception ID") {
-					jww.TRACE.Print(em)
-				} else {
-					if m.client != nil {
-						m.client.ReportEvent(9, "SingleUse",
-							"Error", em)
-					}
-				}
-			}
-		}
-	}
-}
-
-// processesResponse processes the CMIX message and collates its payload. If the
-// message is invalid, an error is returned.
-func (m *Manager) processesResponse(rid *id.ID, ephID ephemeral.Id,
-	msgBytes []byte) error {
-
-	// get the state from the map
-	m.p.RLock()
-	state, exists := m.p.singleUse[*rid]
-	m.p.RUnlock()
-
-	// Check that the state exists
-	if !exists {
-		return errors.Errorf("no state exists for the reception ID %s.", rid)
-	}
-
-	// Unmarshal CMIX message
-	cmixMsg, err := format.Unmarshal(msgBytes)
-	if err != nil {
-		return err
-	}
-
-	// Ensure the fingerprints match
-	fp := cmixMsg.GetKeyFP()
-	key, exists := state.fpMap.getKey(state.dhKey, fp)
-	if !exists {
-		return errors.New("message fingerprint does not correspond to the " +
-			"expected fingerprint.")
-	}
-
-	// Verify the CMIX message MAC
-	if !singleUse.VerifyMAC(key, cmixMsg.GetContents(), cmixMsg.GetMac()) {
-		return errors.New("failed to verify the CMIX message MAC.")
-	}
-
-	// Denote that the message is not garbled
-	jww.DEBUG.Print("Received single-use response message.")
-	m.store.GetGarbledMessages().Remove(cmixMsg)
-
-	// Decrypt and collate the payload
-	decryptedPayload := auth.Crypt(key, fp[:24], cmixMsg.GetContents())
-	collatedPayload, collated, err := state.c.collate(decryptedPayload)
-	if err != nil {
-		return errors.Errorf("failed to collate payload: %+v", err)
-	}
-	jww.DEBUG.Print("Successfully processed single-use response message part.")
-
-	// Once all message parts have been received delete and close everything
-	if collated {
-		if m.client != nil {
-			m.client.ReportEvent(1, "SingleUse", "MessageReceived",
-				fmt.Sprintf("Single use response received "+
-					"from %s", rid))
-		}
-		jww.DEBUG.Print("Received all parts of single-use response message.")
-		// Exit the timeout handler
-		state.quitChan <- struct{}{}
-
-		// Remove identity
-		m.reception.RemoveIdentity(ephID)
-
-		// Remove state from map
-		m.p.Lock()
-		delete(m.p.singleUse, *rid)
-		m.p.Unlock()
-
-		// Call in separate routine to prevent blocking
-		jww.DEBUG.Print("Calling single-use response message callback.")
-		go state.callback(collatedPayload, nil)
-	}
-
-	return nil
-}
diff --git a/single/receiveResponse_test.go b/single/receiveResponse_test.go
deleted file mode 100644
index bed0f9053b72fad10233e28d16f2b0d044bbcd59..0000000000000000000000000000000000000000
--- a/single/receiveResponse_test.go
+++ /dev/null
@@ -1,330 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"bytes"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"gitlab.com/xx_network/primitives/netTime"
-	"math/rand"
-	"strings"
-	"testing"
-	"time"
-)
-
-// Happy path.
-func TestManager_ReceiveResponseHandler(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rawMessages := make(chan message.Receive, rawMessageBuffSize)
-	stop := stoppable.NewSingle("singleStoppable")
-	partner := NewContact(id.NewIdFromString("recipientID", id.User, t),
-		m.store.E2e().GetGroup().NewInt(43), m.store.E2e().GetGroup().NewInt(42),
-		singleUse.TagFP{}, 8)
-	ephID, _, _, err := ephemeral.GetId(partner.partner, id.ArrIDLen, netTime.Now().UnixNano())
-	payload := make([]byte, 2000)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReplyComm()
-	rid := id.NewIdFromString("rid", id.User, t)
-
-	m.p.singleUse[*rid] = newState(partner.dhKey, partner.maxParts, callback)
-
-	msgs, err := m.makeReplyCmixMessages(partner, payload)
-	if err != nil {
-		t.Fatalf("Failed to generate CMIX messages: %+v", err)
-	}
-
-	go func() {
-		timer := time.NewTimer(50 * time.Millisecond)
-		select {
-		case <-timer.C:
-			t.Errorf("quitChan never set.")
-		case <-m.p.singleUse[*rid].quitChan:
-		}
-	}()
-
-	go m.receiveResponseHandler(rawMessages, stop)
-
-	for _, msg := range msgs {
-		rawMessages <- message.Receive{
-			Payload:     msg.Marshal(),
-			Sender:      partner.partner,
-			RecipientID: rid,
-			EphemeralID: ephID,
-		}
-	}
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		if !bytes.Equal(results.payload, payload) {
-			t.Errorf("Callback received wrong payload."+
-				"\nexpected: %+v\nreceived: %+v", payload, results.payload)
-		}
-		if results.err != nil {
-			t.Errorf("Callback received an error: %+v", results.err)
-		}
-	case <-timer.C:
-		t.Errorf("Callback failed to be called.")
-	}
-
-	if err := stop.Close(); err != nil {
-		t.Errorf("Failed to signal close to process: %+v", err)
-	}
-}
-
-// Error path: invalid CMIX message.
-func TestManager_ReceiveResponseHandler_CmixMessageError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rawMessages := make(chan message.Receive, rawMessageBuffSize)
-	stop := stoppable.NewSingle("singleStoppable")
-	partner := NewContact(id.NewIdFromString("recipientID", id.User, t),
-		m.store.E2e().GetGroup().NewInt(43), m.store.E2e().GetGroup().NewInt(42),
-		singleUse.TagFP{}, 8)
-	ephID, _, _, _ := ephemeral.GetId(partner.partner, id.ArrIDLen, netTime.Now().UnixNano())
-	payload := make([]byte, 2000)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReplyComm()
-	rid := id.NewIdFromString("rid", id.User, t)
-
-	m.p.singleUse[*rid] = newState(partner.dhKey, partner.maxParts, callback)
-
-	go func() {
-		timer := time.NewTimer(50 * time.Millisecond)
-		select {
-		case <-timer.C:
-		case <-m.p.singleUse[*rid].quitChan:
-			t.Error("quitChan called on error.")
-		}
-	}()
-
-	go m.receiveResponseHandler(rawMessages, stop)
-
-	rawMessages <- message.Receive{
-		Payload:     make([]byte, format.MinimumPrimeSize*2),
-		Sender:      partner.partner,
-		RecipientID: rid,
-		EphemeralID: ephID,
-	}
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback called when it should not have been."+
-			"payload: %+v\nerror: %+v", results.payload, results.err)
-	case <-timer.C:
-	}
-
-	if err := stop.Close(); err != nil {
-		t.Errorf("Failed to signal close to process: %+v", err)
-	}
-}
-
-// Happy path.
-func TestManager_processesResponse(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rid := id.NewIdFromString("test RID", id.User, t)
-	ephID, _, _, err := ephemeral.GetId(rid, id.ArrIDLen, netTime.Now().UnixNano())
-	if err != nil {
-		t.Fatalf("Failed to create address ID: %+v", err)
-	}
-	dhKey := getGroup().NewInt(5)
-	maxMsgs := uint8(6)
-	timeout := 5 * time.Millisecond
-	callback, callbackChan := createReplyComm()
-
-	m.p.singleUse[*rid] = newState(dhKey, maxMsgs, callback)
-
-	expectedData := []string{"This i", "s the ", "expect", "ed fin", "al dat", "a."}
-	var msgs []format.Message
-	for fp, i := range m.p.singleUse[*rid].fpMap.fps {
-		newMsg := format.NewMessage(format.MinimumPrimeSize)
-		part := newResponseMessagePart(newMsg.ContentsSize())
-		part.SetContents([]byte(expectedData[i]))
-		part.SetPartNum(uint8(i))
-		part.SetMaxParts(maxMsgs)
-
-		key := singleUse.NewResponseKey(dhKey, i)
-		encryptedPayload := auth.Crypt(key, fp[:24], part.Marshal())
-
-		newMsg.SetKeyFP(fp)
-		newMsg.SetMac(singleUse.MakeMAC(key, encryptedPayload))
-		newMsg.SetContents(encryptedPayload)
-		msgs = append(msgs, newMsg)
-	}
-
-	go func() {
-		timer := time.NewTimer(timeout)
-		select {
-		case <-timer.C:
-			t.Errorf("quitChan never set.")
-		case <-m.p.singleUse[*rid].quitChan:
-		}
-	}()
-
-	for i, msg := range msgs {
-		err := m.processesResponse(rid, ephID, msg.Marshal())
-		if err != nil {
-			t.Errorf("processesResponse() returned an error (%d): %+v", i, err)
-		}
-	}
-
-	timer := time.NewTimer(timeout)
-	select {
-	case <-timer.C:
-		t.Errorf("Callback never called.")
-	case results := <-callbackChan:
-		if results.err != nil {
-			t.Errorf("Callback returned an error: %+v", err)
-		}
-		if !bytes.Equal([]byte(strings.Join(expectedData, "")), results.payload) {
-			t.Errorf("Callback returned incorrect data."+
-				"\nexpected: %s\nreceived: %s", expectedData, results.payload)
-		}
-	}
-
-	if _, exists := m.p.singleUse[*rid]; exists {
-		t.Error("Failed to delete the state after collation is complete.")
-	}
-}
-
-// Error path: no state in map.
-func TestManager_processesResponse_NoStateError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rid := id.NewIdFromString("test RID", id.User, t)
-
-	err := m.processesResponse(rid, ephemeral.Id{}, []byte{})
-	if !check(err, "no state exists for the reception ID") {
-		t.Errorf("processesResponse() did not return an error when the state "+
-			"is not in the map: %+v", err)
-	}
-}
-
-// Error path: failed to verify MAC.
-func TestManager_processesResponse_MacVerificationError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rid := id.NewIdFromString("test RID", id.User, t)
-	dhKey := getGroup().NewInt(5)
-	timeout := 5 * time.Millisecond
-	callback := func(payload []byte, err error) {}
-
-	quitChan, _, err := m.p.addState(rid, dhKey, 1, callback, timeout)
-	if err != nil {
-		t.Fatalf("Failed to add state: %+v", err)
-	}
-	quitChan <- struct{}{}
-
-	newMsg := format.NewMessage(format.MinimumPrimeSize)
-	part := newResponseMessagePart(newMsg.ContentsSize())
-	part.SetContents([]byte("payload data"))
-	part.SetPartNum(0)
-	part.SetMaxParts(1)
-	newMsg.SetMac(singleUse.MakeMAC(dhKey.Bytes(), []byte("some data")))
-	newMsg.SetContents([]byte("payload data"))
-
-	var fp format.Fingerprint
-	for fpt, i := range m.p.singleUse[*rid].fpMap.fps {
-		if i == 0 {
-			fp = fpt
-		}
-	}
-	newMsg.SetKeyFP(fp)
-
-	err = m.processesResponse(rid, ephemeral.Id{}, newMsg.Marshal())
-	if !check(err, "MAC") {
-		t.Errorf("processesResponse() did not return an error when MAC "+
-			"verification should have failed: %+v", err)
-	}
-}
-
-// Error path: CMIX message fingerprint does not match fingerprints in map.
-func TestManager_processesResponse_FingerprintError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rid := id.NewIdFromString("test RID", id.User, t)
-	dhKey := getGroup().NewInt(5)
-	timeout := 5 * time.Millisecond
-	callback := func(payload []byte, err error) {}
-
-	quitChan, _, err := m.p.addState(rid, dhKey, 1, callback, timeout)
-	if err != nil {
-		t.Fatalf("Failed to add state: %+v", err)
-	}
-	quitChan <- struct{}{}
-
-	var fp format.Fingerprint
-	for fpt, i := range m.p.singleUse[*rid].fpMap.fps {
-		if i == 0 {
-			fp = fpt
-		}
-	}
-	newMsg := format.NewMessage(format.MinimumPrimeSize)
-	part := newResponseMessagePart(newMsg.ContentsSize())
-	part.SetContents([]byte("payload data"))
-	part.SetPartNum(0)
-	part.SetMaxParts(1)
-
-	key := singleUse.NewResponseKey(dhKey, 0)
-	encryptedPayload := auth.Crypt(key, fp[:24], part.Marshal())
-
-	newMsg.SetKeyFP(format.NewFingerprint([]byte("Invalid Fingerprint")))
-	newMsg.SetMac(singleUse.MakeMAC(key, encryptedPayload))
-	newMsg.SetContents(encryptedPayload)
-
-	err = m.processesResponse(rid, ephemeral.Id{}, newMsg.Marshal())
-	if !check(err, "fingerprint") {
-		t.Errorf("processesResponse() did not return an error when "+
-			"fingerprint was wrong: %+v", err)
-	}
-}
-
-// Error path: collator fails because part number is wrong.
-func TestManager_processesResponse_CollatorError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rid := id.NewIdFromString("test RID", id.User, t)
-	dhKey := getGroup().NewInt(5)
-	timeout := 5 * time.Millisecond
-	callback := func(payload []byte, err error) {}
-
-	quitChan, _, err := m.p.addState(rid, dhKey, 1, callback, timeout)
-	if err != nil {
-		t.Fatalf("Failed to add state: %+v", err)
-	}
-	quitChan <- struct{}{}
-
-	var fp format.Fingerprint
-	for fpt, i := range m.p.singleUse[*rid].fpMap.fps {
-		if i == 0 {
-			fp = fpt
-		}
-	}
-	newMsg := format.NewMessage(format.MinimumPrimeSize)
-	part := newResponseMessagePart(newMsg.ContentsSize())
-	part.SetContents([]byte("payload data"))
-	part.SetPartNum(5)
-	part.SetMaxParts(1)
-
-	key := singleUse.NewResponseKey(dhKey, 0)
-	encryptedPayload := auth.Crypt(key, fp[:24], part.Marshal())
-
-	newMsg.SetKeyFP(fp)
-	newMsg.SetMac(singleUse.MakeMAC(key, encryptedPayload))
-	newMsg.SetContents(encryptedPayload)
-
-	err = m.processesResponse(rid, ephemeral.Id{}, newMsg.Marshal())
-	if !check(err, "collate") {
-		t.Errorf("processesResponse() did not return an error when "+
-			"collation should have failed: %+v", err)
-	}
-}
diff --git a/single/receivedRequest.go b/single/receivedRequest.go
new file mode 100644
index 0000000000000000000000000000000000000000..b98d117504d895d9489fe41cc865161c1c5a3870
--- /dev/null
+++ b/single/receivedRequest.go
@@ -0,0 +1,186 @@
+package single
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix"
+	cmixMsg "gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/single/message"
+	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+// Request contains the information to respond to a single-use contact.
+type Request struct {
+	sender         *id.ID      // ID of the person to respond to
+	senderPubKey   *cyclic.Int // Public key of the sender
+	dhKey          *cyclic.Int // DH key
+	tag            string      // Identifies which callback to use
+	maxParts       uint8       // Max number of messages allowed in reply
+	used           *uint32     // Atomic variable
+	requestPayload []byte
+	net            cmix.Client
+}
+
+// GetMaxParts returns the maximum number of message parts that can be sent in a
+// reply.
+func (r Request) GetMaxParts() uint8 {
+	return r.maxParts
+}
+
+func (r Request) GetMaxResponseLength() int {
+	responseMsg := message.NewResponsePart(r.net.GetMaxMessageLength())
+
+	// Maximum payload size is the maximum amount of room in each message
+	// multiplied by the number of messages
+	return responseMsg.GetMaxContentsSize() * int(r.GetMaxParts())
+}
+
+// GetPartner returns a copy of the sender ID.
+func (r Request) GetPartner() *id.ID {
+	return r.sender.DeepCopy()
+}
+
+// GetTag returns the tag for the request.
+func (r Request) GetTag() string {
+	return r.tag
+}
+
+// GetPayload returns the payload that came in the request
+func (r Request) GetPayload() []byte {
+	return r.requestPayload
+}
+
+// String returns a string of the Contact structure.
+func (r Request) String() string {
+	format := "Request{sender:%s  senderPubKey:%s  dhKey:%s  tagFP:%s  " +
+		"maxParts:%d}"
+	return fmt.Sprintf(format, r.sender, r.senderPubKey.Text(10),
+		r.dhKey.Text(10), r.tag, r.maxParts)
+}
+
+func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams,
+	timeout time.Duration) ([]id.Round, error) {
+	// make sure this has only been run once
+	newRun := atomic.CompareAndSwapUint32(r.used, 0, 1)
+	if !newRun {
+		return nil, errors.Errorf("cannot respond to " +
+			"single-use response that has already been responded to.")
+	}
+
+	//check that the payload isn't too long
+	if len(payload) > r.GetMaxResponseLength() {
+		return nil, errors.Errorf("length of provided "+
+			"payload too long for message payload capacity, max: %d, "+
+			"received: %d", r.GetMaxResponseLength(),
+			len(payload))
+	}
+
+	//partition the payload
+	parts := partitionResponse(payload, r.net.GetMaxMessageLength(), r.maxParts)
+
+	//encrypt and send the partitions
+	cyphers := makeCyphers(r.dhKey, uint8(len(parts)))
+	rounds := make([]id.Round, len(parts))
+	sendResults := make(chan ds.EventReturn, len(parts))
+
+	wg := sync.WaitGroup{}
+	wg.Add(len(parts))
+
+	if cmixParams.DebugTag != cmix.DefaultDebugTag {
+		cmixParams.DebugTag = "single.Response"
+	}
+
+	svc := cmixMsg.Service{
+		Identifier: r.dhKey.Bytes(),
+		Tag:        "single.response-dummyservice",
+		Metadata:   nil,
+	}
+
+	for i := 0; i < len(parts); i++ {
+		// fixme: handle the case where a send fails, also on failures,
+		// unset use
+		go func(j int) {
+			defer wg.Done()
+			partFP, ecrPart, mac := cyphers[j].Encrypt(parts[j])
+			// Send Message
+			round, ephID, err := r.net.Send(r.sender, partFP, svc, ecrPart, mac,
+				cmixParams)
+			if err != nil {
+				jww.ERROR.Printf("Failed to send single-use response CMIX "+
+					"message part %d: %+v", j, err)
+			}
+			jww.DEBUG.Printf("Sending single-use response CMIX message part "+
+				"%d on round %d to address ID %d.", j, round, ephID.Int64())
+			rounds[j] = round
+
+			r.net.GetInstance().GetRoundEvents().AddRoundEventChan(round, sendResults,
+				timeout, states.COMPLETED, states.FAILED)
+		}(i)
+	}
+
+	// Wait for all go routines to finish
+	wg.Wait()
+	jww.DEBUG.Printf("Sent %d single-use response CMIX messages to %s.",
+		len(parts), r.sender)
+
+	// Count the number of rounds
+	roundMap := map[id.Round]struct{}{}
+	for _, roundID := range rounds {
+		roundMap[roundID] = struct{}{}
+	}
+
+	// Wait until the result tracking responds
+	success, numRoundFail, numTimeOut := cmix.TrackResults(sendResults, len(roundMap))
+	if !success {
+
+		return nil, errors.Errorf("tracking results of %d rounds: %d round "+
+			"failures, %d round event time outs; the send cannot be retried.",
+			len(rounds), numRoundFail, numTimeOut)
+	}
+
+	jww.DEBUG.Printf("Tracked %d single-use response message round(s).", len(roundMap))
+
+	return rounds, nil
+}
+
+// partitionResponse breaks a payload into its sub payloads for sending
+func partitionResponse(payload []byte, cmixMessageLength int, maxParts uint8) []message.ResponsePart {
+	responseMsg := message.NewResponsePart(cmixMessageLength)
+
+	// Split payloads
+	payloadParts := splitPayload(payload, responseMsg.GetMaxContentsSize(),
+		int(maxParts))
+
+	// Create messages
+	parts := make([]message.ResponsePart, len(payloadParts))
+	for i := range payloadParts {
+		nrp := message.NewResponsePart(cmixMessageLength)
+		nrp.SetPartNum(uint8(i))
+		nrp.SetContents(payloadParts[i])
+		nrp.SetNumParts(uint8(len(payloadParts)))
+		parts[i] = nrp
+	}
+
+	return parts
+}
+
+// splitPayload splits the given payload into separate payload parts and returns
+// them in a slice. Each part's size is less than or equal to maxSize. Any extra
+// data in the payload is not used if it is longer than the maximum capacity.
+func splitPayload(payload []byte, maxSize, maxParts int) [][]byte {
+	var parts [][]byte
+	buff := bytes.NewBuffer(payload)
+
+	for i := 0; i < maxParts && buff.Len() > 0; i++ {
+		parts = append(parts, buff.Next(maxSize))
+	}
+	return parts
+}
diff --git a/single/reception.go b/single/reception.go
deleted file mode 100644
index 01faada1fa07ada31f779ec25f2eecc973f95f9b..0000000000000000000000000000000000000000
--- a/single/reception.go
+++ /dev/null
@@ -1,121 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"github.com/pkg/errors"
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/stoppable"
-	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-)
-
-// receiveTransmissionHandler waits to receive single-use transmissions. When
-// a message is received, its is returned via its registered callback.
-func (m *Manager) receiveTransmissionHandler(rawMessages chan message.Receive,
-	stop *stoppable.Single) {
-	fp := singleUse.NewTransmitFingerprint(m.store.E2e().GetDHPublicKey())
-	jww.DEBUG.Print("Waiting to receive single-use transmission messages.")
-	for {
-		select {
-		case <-stop.Quit():
-			jww.DEBUG.Printf("Stopping waiting to receive single-use " +
-				"transmission message.")
-			stop.ToStopped()
-			return
-		case msg := <-rawMessages:
-			jww.TRACE.Printf("Received CMIX message; checking if it is a " +
-				"single-use transmission.")
-			go func(m *Manager, msg message.Receive) {
-				// Check if message is a single-use transmit message
-				cmixMsg, err := format.Unmarshal(msg.Payload)
-				if err != nil {
-					jww.ERROR.Printf("Could not unmarshal msg: %s",
-						err.Error())
-					return
-				}
-				if fp != cmixMsg.GetKeyFP() {
-					// If the verification fails, then ignore the message as it is
-					// likely garbled or for a different protocol
-					jww.TRACE.Print("Failed to read single-use CMIX message: " +
-						"fingerprint verification failed.")
-					return
-				}
-
-				// Denote that the message is not garbled
-				jww.DEBUG.Printf("Received single-use transmission message.")
-				m.store.GetGarbledMessages().Remove(cmixMsg)
-
-				// Handle message
-				payload, c, err := m.processTransmission(cmixMsg, fp)
-				if err != nil {
-					jww.WARN.Printf("Failed to read single-use CMIX message: %+v",
-						err)
-					return
-				}
-				jww.DEBUG.Printf("Successfully processed single-use transmission message.")
-
-				// Lookup the registered callback for the message's tag fingerprint
-				callback, err := m.callbackMap.getCallback(c.tagFP)
-				if err != nil {
-					jww.WARN.Printf("Failed to find module to pass single-use "+
-						"payload: %+v", err)
-					return
-				}
-
-				jww.DEBUG.Printf("Calling single-use callback with tag "+
-					"fingerprint %s.", c.tagFP)
-
-				callback(payload, c)
-			}(m, msg)
-		}
-	}
-}
-
-// processTransmission unmarshalls and decrypts the message payload and
-// returns the decrypted payload and the contact information for the sender.
-func (m *Manager) processTransmission(msg format.Message,
-	fp format.Fingerprint) ([]byte, Contact, error) {
-	grp := m.store.E2e().GetGroup()
-	dhPrivKey := m.store.E2e().GetDHPrivateKey()
-
-	// Unmarshal the CMIX message contents to a transmission message
-	transmitMsg, err := unmarshalTransmitMessage(msg.GetContents(),
-		grp.GetP().ByteLen())
-	if err != nil {
-		return nil, Contact{}, errors.Errorf("failed to unmarshal contents: %+v", err)
-	}
-
-	// Generate DH key and symmetric key
-	dhKey := grp.Exp(transmitMsg.GetPubKey(grp), dhPrivKey, grp.NewInt(1))
-	key := singleUse.NewTransmitKey(dhKey)
-
-	// Verify the MAC
-	if !singleUse.VerifyMAC(key, transmitMsg.GetPayload(), msg.GetMac()) {
-		return nil, Contact{}, errors.New("failed to verify MAC.")
-	}
-
-	// Decrypt the transmission message payload
-	decryptedPayload := cAuth.Crypt(key, fp[:24], transmitMsg.GetPayload())
-
-	// Unmarshal the decrypted payload to a transmission message payload
-	payload, err := unmarshalTransmitMessagePayload(decryptedPayload)
-	if err != nil {
-		return nil, Contact{}, errors.Errorf("failed to unmarshal payload: %+v", err)
-	}
-
-	c := NewContact(payload.GetRID(transmitMsg.GetPubKey(grp)),
-		transmitMsg.GetPubKey(grp), dhKey, payload.GetTagFP(), payload.GetMaxParts())
-
-	jww.INFO.Printf("Generated by singe use receiver reception id for single use. EphId %s, PubKey: %x",
-		c.partner, transmitMsg.GetPubKey(grp).Bytes())
-
-	return payload.GetContents(), c, nil
-}
diff --git a/single/reception_test.go b/single/reception_test.go
deleted file mode 100644
index efa83406dbb27791d2a209430043520b4a30c4c3..0000000000000000000000000000000000000000
--- a/single/reception_test.go
+++ /dev/null
@@ -1,260 +0,0 @@
-package single
-
-import (
-	"bytes"
-	"gitlab.com/elixxir/client/interfaces/message"
-	"gitlab.com/elixxir/client/stoppable"
-	contact2 "gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/netTime"
-	"math/rand"
-	"testing"
-	"time"
-)
-
-// Happy path.
-func TestManager_receiveTransmissionHandler(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rawMessages := make(chan message.Receive, rawMessageBuffSize)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetDHPublicKey(),
-	}
-	tag := "Test tag"
-	payload := make([]byte, 130)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReceiveComm()
-
-	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
-	}
-
-	m.callbackMap.registerCallback(tag, callback)
-
-	go m.receiveTransmissionHandler(rawMessages, stoppable.NewSingle("singleStoppable"))
-	rawMessages <- message.Receive{
-		Payload: msg.Marshal(),
-	}
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		if !bytes.Equal(results.payload, payload) {
-			t.Errorf("Callback received wrong payload."+
-				"\nexpected: %+v\nreceived: %+v", payload, results.payload)
-		}
-	case <-timer.C:
-		t.Errorf("Callback failed to be called.")
-	}
-}
-
-// Happy path: quit channel.
-func TestManager_receiveTransmissionHandler_QuitChan(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rawMessages := make(chan message.Receive, rawMessageBuffSize)
-	stop := stoppable.NewSingle("singleStoppable")
-	tag := "Test tag"
-	payload := make([]byte, 132)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReceiveComm()
-
-	m.callbackMap.registerCallback(tag, callback)
-
-	go m.receiveTransmissionHandler(rawMessages, stop)
-
-	if err := stop.Close(); err != nil {
-		t.Errorf("Failed to signal close to process: %+v", err)
-	}
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback called when the message should not have been processed."+
-			"\npayload: %+v\ncontact: %+v", results.payload, results.c)
-	case <-timer.C:
-	}
-}
-
-// Error path: CMIX message fingerprint does not match.
-func TestManager_receiveTransmissionHandler_FingerPrintError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rawMessages := make(chan message.Receive, rawMessageBuffSize)
-	stop := stoppable.NewSingle("singleStoppable")
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(42),
-	}
-	tag := "Test tag"
-	payload := make([]byte, 130)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReceiveComm()
-
-	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
-	}
-
-	m.callbackMap.registerCallback(tag, callback)
-
-	go m.receiveTransmissionHandler(rawMessages, stop)
-	rawMessages <- message.Receive{
-		Payload: msg.Marshal(),
-	}
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback called when the fingerprints do not match."+
-			"\npayload: %+v\ncontact: %+v", results.payload, results.c)
-	case <-timer.C:
-	}
-}
-
-// Error path: cannot process transmission message.
-func TestManager_receiveTransmissionHandler_ProcessMessageError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rawMessages := make(chan message.Receive, rawMessageBuffSize)
-	stop := stoppable.NewSingle("singleStoppable")
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetDHPublicKey(),
-	}
-	tag := "Test tag"
-	payload := make([]byte, 130)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReceiveComm()
-
-	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
-	}
-
-	msg.SetMac(make([]byte, format.MacLen))
-
-	m.callbackMap.registerCallback(tag, callback)
-
-	go m.receiveTransmissionHandler(rawMessages, stop)
-	rawMessages <- message.Receive{
-		Payload: msg.Marshal(),
-	}
-
-	timer := time.NewTimer(50 * time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback called when the message should not have been processed."+
-			"\npayload: %+v\ncontact: %+v", results.payload, results.c)
-	case <-timer.C:
-	}
-}
-
-// Error path: tag fingerprint does not match.
-func TestManager_receiveTransmissionHandler_TagFpError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	rawMessages := make(chan message.Receive, rawMessageBuffSize)
-	stop := stoppable.NewSingle("singleStoppable")
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetDHPublicKey(),
-	}
-	tag := "Test tag"
-	payload := make([]byte, 130)
-	rand.New(rand.NewSource(42)).Read(payload)
-
-	msg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload, tag, 8, 32,
-		30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to create tranmission CMIX message: %+v", err)
-	}
-
-	go m.receiveTransmissionHandler(rawMessages, stop)
-	rawMessages <- message.Receive{
-		Payload: msg.Marshal(),
-	}
-}
-
-// Happy path.
-func TestManager_processTransmission(t *testing.T) {
-	m := newTestManager(0, false, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("partnerID", id.User, t),
-		DhPubKey: m.store.E2e().GetDHPublicKey(),
-	}
-	tag := "test tag"
-	payload := []byte("This is the payload.")
-	maxMsgs := uint8(6)
-	cmixMsg, dhKey, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, maxMsgs, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to generate expected CMIX message: %+v", err)
-	}
-
-	tMsg, err := unmarshalTransmitMessage(cmixMsg.GetContents(), m.store.E2e().GetGroup().GetP().ByteLen())
-	if err != nil {
-		t.Fatalf("Failed to make transmitMessage: %+v", err)
-	}
-
-	expectedC := NewContact(rid, tMsg.GetPubKey(m.store.E2e().GetGroup()),
-		dhKey, singleUse.NewTagFP(tag), maxMsgs)
-
-	fp := singleUse.NewTransmitFingerprint(m.store.E2e().GetDHPublicKey())
-	content, testC, err := m.processTransmission(cmixMsg, fp)
-	if err != nil {
-		t.Errorf("processTransmission() produced an error: %+v", err)
-	}
-
-	if !expectedC.Equal(testC) {
-		t.Errorf("processTransmission() did not return the expected values."+
-			"\nexpected: %+v\nrecieved: %+v", expectedC, testC)
-	}
-
-	if !bytes.Equal(payload, content) {
-		t.Errorf("processTransmission() returned the wrong payload."+
-			"\nexpected: %+v\nreceived: %+v", payload, content)
-	}
-}
-
-// Error path: fails to unmarshal transmitMessage.
-func TestManager_processTransmission_TransmitMessageUnmarshalError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	cmixMsg := format.NewMessage(format.MinimumPrimeSize)
-
-	fp := singleUse.NewTransmitFingerprint(m.store.E2e().GetDHPublicKey())
-	_, _, err := m.processTransmission(cmixMsg, fp)
-	if !check(err, "failed to unmarshal contents") {
-		t.Errorf("processTransmission() did not produce an error when "+
-			"the transmitMessage failed to unmarshal: %+v", err)
-	}
-}
-
-// Error path: MAC fails to verify.
-func TestManager_processTransmission_MacVerifyError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("partnerID", id.User, t),
-		DhPubKey: m.store.E2e().GetDHPublicKey(),
-	}
-	cmixMsg, _, _, _, err := m.makeTransmitCmixMessage(partner, []byte{}, "", 6,
-		32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to generate expected CMIX message: %+v", err)
-	}
-
-	cmixMsg.SetMac(make([]byte, 32))
-
-	fp := singleUse.NewTransmitFingerprint(m.store.E2e().GetDHPublicKey())
-	_, _, err = m.processTransmission(cmixMsg, fp)
-	if !check(err, "failed to verify MAC") {
-		t.Errorf("processTransmission() did not produce an error when "+
-			"the MAC failed to verify: %+v", err)
-	}
-}
diff --git a/single/request.go b/single/request.go
new file mode 100644
index 0000000000000000000000000000000000000000..c464eec421366c72a44e0c462900458d2e21bdf3
--- /dev/null
+++ b/single/request.go
@@ -0,0 +1,209 @@
+package single
+
+import (
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	cmixMsg "gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/single/message"
+	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/e2e/auth"
+	"gitlab.com/elixxir/crypto/e2e/singleUse"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
+	"io"
+	"sync"
+	"time"
+)
+
+type Response interface {
+	Callback(payload []byte, receptionID receptionID.EphemeralIdentity,
+		round rounds.Round, err error)
+}
+
+type RequestParams struct {
+	Timeout     time.Duration
+	MaxMessages uint8
+	CmixParam   cmix.CMIXParams
+}
+
+func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
+	callback Response, param RequestParams, net cmix.Client, rng csprng.Source,
+	e2eGrp *cyclic.Group) (id.Round, receptionID.EphemeralIdentity, error) {
+	// get address ID address space size; this blocks until the address space
+	// size is set for the first time
+	addressSize := net.GetAddressSpace()
+	timeStart := netTime.Now()
+
+	// Generate DH key and public key
+	dhKey, publicKey, err := generateDhKeys(e2eGrp, recipient.DhPubKey, rng)
+	if err != nil {
+		return 0, receptionID.EphemeralIdentity{}, err
+	}
+
+	//build the message payload
+	request := message.NewRequest(net.GetMaxMessageLength(),
+		e2eGrp.GetP().ByteLen())
+	requestPayload := message.NewRequestPayload(request.GetPayloadSize(),
+		payload, param.MaxMessages)
+
+	// Generate new user ID and address ID
+	var sendingID receptionID.EphemeralIdentity
+	requestPayload, sendingID, err = makeIDs(requestPayload, publicKey, addressSize, param.Timeout,
+		timeStart, rng)
+	if err != nil {
+		return 0, receptionID.EphemeralIdentity{}, errors.Errorf("failed to generate IDs: %+v", err)
+	}
+
+	// Encrypt payload
+	fp := singleUse.NewTransmitFingerprint(recipient.DhPubKey)
+	key := singleUse.NewTransmitKey(dhKey)
+	encryptedPayload := auth.Crypt(key, fp[:24], requestPayload.Marshal())
+
+	// Generate CMIX message MAC
+	mac := singleUse.MakeMAC(key, encryptedPayload)
+
+	//assemble the payload
+	request.SetPubKey(publicKey)
+	request.SetPayload(encryptedPayload)
+
+	//register the response pickup
+	collator := message.NewCollator(param.MaxMessages)
+	timeoutKillChan := make(chan bool)
+	callbackOnce := sync.Once{}
+	wrapper := func(payload []byte, receptionID receptionID.EphemeralIdentity,
+		round rounds.Round, err error) {
+		select {
+		case timeoutKillChan <- true:
+		default:
+		}
+		callbackOnce.Do(func() {
+			net.DeleteClientFingerprints(sendingID.Source)
+			go callback.Callback(payload, receptionID, round, err)
+		})
+	}
+
+	cyphers := makeCyphers(dhKey, param.MaxMessages)
+
+	for i := uint8(0); i < param.MaxMessages; i++ {
+		processor := responceProcessor{
+			sendingID: sendingID,
+			c:         collator,
+			callback:  wrapper,
+			cy:        cyphers[i],
+			tag:       tag,
+			recipient: &recipient,
+		}
+
+		if err = net.AddFingerprint(sendingID.Source, processor.cy.GetFingerprint(),
+			&processor); err != nil {
+			return 0, receptionID.EphemeralIdentity{},
+				errors.Errorf("failed to add fingerprint %d IDs: %+v", i, err)
+		}
+	}
+
+	net.AddIdentity(sendingID.Source, timeStart.Add(param.Timeout), false)
+
+	//send the payload
+	svc := cmixMsg.Service{
+		Identifier: recipient.ID[:],
+		Tag:        tag,
+		Metadata:   nil,
+	}
+	param.CmixParam.Timeout = param.Timeout
+
+	rid, _, err := net.Send(recipient.ID, cmixMsg.RandomFingerprint(rng), svc, request.Marshal(), mac,
+		param.CmixParam)
+
+	if err != nil {
+		return 0, receptionID.EphemeralIdentity{}, err
+	}
+
+	remainingTimeout := param.Timeout - netTime.Since(timeStart)
+	go waitForTimeout(timeoutKillChan, wrapper, remainingTimeout)
+
+	return rid, sendingID, nil
+}
+
+// generateDhKeys generates a new public key and DH key.
+func generateDhKeys(grp *cyclic.Group, dhPubKey *cyclic.Int,
+	rng io.Reader) (*cyclic.Int, *cyclic.Int, error) {
+	// Generate private key
+	privKeyBytes, err := csprng.GenerateInGroup(grp.GetP().Bytes(),
+		grp.GetP().ByteLen(), rng)
+	if err != nil {
+		return nil, nil, errors.Errorf("failed to generate key in group: %+v",
+			err)
+	}
+	privKey := grp.NewIntFromBytes(privKeyBytes)
+
+	// Generate public key and DH key
+	publicKey := grp.ExpG(privKey, grp.NewInt(1))
+	dhKey := grp.Exp(dhPubKey, privKey, grp.NewInt(1))
+	return dhKey, publicKey, nil
+}
+
+// makeIDs generates a new user ID and address ID with a start and end within
+// the given timout. The ID is generated from the unencrypted msg payload, which
+// contains a nonce. If the generated address ID has a window that is not
+// within +/- the given 2*Timeout from now, then the IDs are generated again
+// using a new nonce.
+func makeIDs(msg message.RequestPayload, publicKey *cyclic.Int,
+	addressSize uint8, timeout time.Duration, timeNow time.Time,
+	rng io.Reader) (message.RequestPayload, receptionID.EphemeralIdentity, error) {
+	var rid *id.ID
+	var ephID ephemeral.Id
+
+	// Generate acceptable window for the address ID to exist in
+	windowStart, windowEnd := timeNow.Add(-2*timeout), timeNow.Add(2*timeout)
+	start, end := timeNow, timeNow
+
+	// Loop until the address ID's start and end are within bounds
+	for windowStart.Before(start) || windowEnd.After(end) {
+		// Generate new nonce
+		err := msg.SetNonce(rng)
+		if err != nil {
+			return message.RequestPayload{}, receptionID.EphemeralIdentity{},
+				errors.Errorf("failed to generate nonce: %+v", err)
+		}
+
+		// Generate ID from unencrypted payload
+		rid = msg.GetRID(publicKey)
+
+		// Generate the address ID
+		ephID, start, end, err = ephemeral.GetId(rid, uint(addressSize),
+			timeNow.UnixNano())
+		if err != nil {
+			return message.RequestPayload{}, receptionID.EphemeralIdentity{},
+				errors.Errorf("failed to generate "+
+					"address ID from newly generated ID: %+v", err)
+		}
+		jww.DEBUG.Printf("address.GetId(%s, %d, %d) = %d", rid,
+			addressSize, timeNow.UnixNano(), ephID.Int64())
+	}
+
+	jww.INFO.Printf("generated by singe use sender reception id for single use: %s, "+
+		"ephId: %d, pubkey: %x, msg: %s", rid, ephID.Int64(), publicKey.Bytes(), msg)
+
+	return msg, receptionID.EphemeralIdentity{
+		EphId:  ephID,
+		Source: rid,
+	}, nil
+}
+
+func waitForTimeout(kill chan bool, callback callbackWrapper, timeout time.Duration) {
+	timer := time.NewTimer(timeout)
+	select {
+	case <-kill:
+		return
+	case <-timer.C:
+		err := errors.Errorf("waiting for response to single-use transmission "+
+			"timed out after %s.", timeout)
+		callback(nil, receptionID.EphemeralIdentity{}, rounds.Round{}, err)
+	}
+}
diff --git a/single/response.go b/single/response.go
deleted file mode 100644
index 9856a919032592dc2a6074794059140fe779387c..0000000000000000000000000000000000000000
--- a/single/response.go
+++ /dev/null
@@ -1,191 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"bytes"
-	"github.com/pkg/errors"
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/cmix"
-	"gitlab.com/elixxir/client/interfaces/params"
-	ds "gitlab.com/elixxir/comms/network/dataStructures"
-	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/elixxir/primitives/states"
-	"gitlab.com/xx_network/primitives/id"
-	"sync"
-	"sync/atomic"
-	"time"
-)
-
-// GetMaxResponsePayloadSize returns the maximum payload size for a response
-// message.
-func (m *Manager) GetMaxResponsePayloadSize() int {
-	// Generate empty messages to determine the available space for the payload
-	cmixMsg := format.NewMessage(m.store.Cmix().GetGroup().GetP().ByteLen())
-	responseMsg := newResponseMessagePart(cmixMsg.ContentsSize())
-
-	return responseMsg.GetMaxContentsSize()
-}
-
-// RespondSingleUse creates the single-use response messages with the given
-// payload and sends them to the given partner.
-func (m *Manager) RespondSingleUse(partner Contact, payload []byte,
-	timeout time.Duration) error {
-	return m.respondSingleUse(partner, payload, timeout,
-		m.net.GetInstance().GetRoundEvents())
-}
-
-// respondSingleUse allows for easier testing.
-func (m *Manager) respondSingleUse(partner Contact, payload []byte,
-	timeout time.Duration, roundEvents roundEvents) error {
-	// Ensure that only a single reply can be sent in response
-	firstUse := atomic.CompareAndSwapInt32(partner.used, 0, 1)
-	if !firstUse {
-		return errors.Errorf("cannot send to single-use contact that has " +
-			"already been sent to.")
-	}
-
-	// Generate messages from payload
-	msgs, err := m.makeReplyCmixMessages(partner, payload)
-	if err != nil {
-		return errors.Errorf("failed to create new CMIX messages: %+v", err)
-	}
-
-	jww.DEBUG.Printf("Created %d single-use response CMIX message parts.", len(msgs))
-
-	// Tracks the numbers of rounds that messages are sent on
-	rounds := make([]id.Round, len(msgs))
-
-	sendResults := make(chan ds.EventReturn, len(msgs))
-
-	// Send CMIX messages
-	wg := sync.WaitGroup{}
-	for i, cmixMsg := range msgs {
-		wg.Add(1)
-		cmixMsgFunc := cmixMsg
-		j := i
-		go func() {
-			defer wg.Done()
-			// Send Message
-			p := params.GetDefaultCMIX()
-			p.DebugTag = "single.Response"
-			round, ephID, err := m.net.SendCMIX(cmixMsgFunc, partner.partner, p)
-			if err != nil {
-				jww.ERROR.Printf("Failed to send single-use response CMIX "+
-					"message part %d: %+v", j, err)
-			}
-			jww.DEBUG.Printf("Sending single-use response CMIX message part "+
-				"%d on round %d to address ID %d.", j, round, ephID.Int64())
-			rounds[j] = round
-
-			roundEvents.AddRoundEventChan(round, sendResults, timeout,
-				states.COMPLETED, states.FAILED)
-		}()
-	}
-
-	// Wait for all go routines to finish
-	wg.Wait()
-	jww.DEBUG.Printf("Sent %d single-use response CMIX messages to %s.", len(msgs), partner.partner)
-
-	// Count the number of rounds
-	roundMap := map[id.Round]struct{}{}
-	for _, roundID := range rounds {
-		roundMap[roundID] = struct{}{}
-	}
-
-	// Wait until the result tracking responds
-	success, numRoundFail, numTimeOut := cmix.TrackResults(sendResults, len(roundMap))
-	if !success {
-		return errors.Errorf("tracking results of %d rounds: %d round "+
-			"failures, %d round event time outs; the send cannot be retried.",
-			len(rounds), numRoundFail, numTimeOut)
-	}
-	jww.DEBUG.Printf("Tracked %d single-use response message round(s).", len(roundMap))
-
-	return nil
-}
-
-// makeReplyCmixMessages
-func (m *Manager) makeReplyCmixMessages(partner Contact, payload []byte) ([]format.Message, error) {
-	// Generate internal payloads based off key size to determine if the passed
-	// in payload is too large to fit in the available contents
-	cmixMsg := format.NewMessage(m.store.Cmix().GetGroup().GetP().ByteLen())
-	responseMsg := newResponseMessagePart(cmixMsg.ContentsSize())
-
-	// Maximum payload size is the maximum amount of room in each message
-	// multiplied by the number of messages
-	maxPayloadSize := responseMsg.GetMaxContentsSize() * int(partner.GetMaxParts())
-
-	if maxPayloadSize < len(payload) {
-		return nil, errors.Errorf("length of provided payload (%d) too long "+
-			"for message payload capacity (%d = %d byte payload * %d messages).",
-			len(payload), maxPayloadSize, responseMsg.GetMaxContentsSize(),
-			partner.GetMaxParts())
-	}
-
-	// Split payloads
-	payloadParts := m.splitPayload(payload, responseMsg.GetMaxContentsSize(),
-		int(partner.GetMaxParts()))
-
-	// Create CMIX messages
-	cmixMsgs := make([]format.Message, len(payloadParts))
-	wg := sync.WaitGroup{}
-	for i, contents := range payloadParts {
-		wg.Add(1)
-		go func(partner Contact, contents []byte, i uint8) {
-			defer wg.Done()
-			cmixMsgs[i] = m.makeMessagePart(partner, contents, uint8(len(payloadParts)), i)
-		}(partner, contents, uint8(i))
-	}
-
-	// Wait for all go routines to finish
-	wg.Wait()
-
-	return cmixMsgs, nil
-}
-
-// makeMessagePart generates a CMIX message containing a responseMessagePart.
-func (m *Manager) makeMessagePart(partner Contact, contents []byte, maxPart, i uint8) format.Message {
-	cmixMsg := format.NewMessage(m.store.Cmix().GetGroup().GetP().ByteLen())
-	responseMsg := newResponseMessagePart(cmixMsg.ContentsSize())
-
-	// Compose response message
-	responseMsg.SetMaxParts(maxPart)
-	responseMsg.SetPartNum(i)
-	responseMsg.SetContents(contents)
-
-	// Encrypt payload
-	fp := singleUse.NewResponseFingerprint(partner.dhKey, uint64(i))
-	key := singleUse.NewResponseKey(partner.dhKey, uint64(i))
-	encryptedPayload := cAuth.Crypt(key, fp[:24], responseMsg.Marshal())
-
-	// Generate CMIX message MAC
-	mac := singleUse.MakeMAC(key, encryptedPayload)
-
-	// Compose CMIX message contents
-	cmixMsg.SetContents(encryptedPayload)
-	cmixMsg.SetKeyFP(fp)
-	cmixMsg.SetMac(mac)
-
-	return cmixMsg
-}
-
-// splitPayload splits the given payload into separate payload parts and returns
-// them in a slice. Each part's size is less than or equal to maxSize. Any extra
-// data in the payload is not used if it is longer than the maximum capacity.
-func (m *Manager) splitPayload(payload []byte, maxSize, maxParts int) [][]byte {
-	var parts [][]byte
-	buff := bytes.NewBuffer(payload)
-
-	for i := 0; i < maxParts && buff.Len() > 0; i++ {
-		parts = append(parts, buff.Next(maxSize))
-	}
-	return parts
-}
diff --git a/single/responseProcessor.go b/single/responseProcessor.go
new file mode 100644
index 0000000000000000000000000000000000000000..9eb56ef2bf4ddb7ce14409962129a3f4fdf64188
--- /dev/null
+++ b/single/responseProcessor.go
@@ -0,0 +1,46 @@
+package single
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/single/message"
+	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/elixxir/primitives/format"
+)
+
+type callbackWrapper func(payload []byte,
+	receptionID receptionID.EphemeralIdentity, round rounds.Round, err error)
+
+//by fingerprint
+type responceProcessor struct {
+	sendingID receptionID.EphemeralIdentity
+	c         *message.Collator
+	callback  callbackWrapper
+	cy        cypher
+	tag       string
+	recipient *contact.Contact
+}
+
+func (rsp *responceProcessor) Process(ecrMsg format.Message,
+	receptionID receptionID.EphemeralIdentity,
+	round rounds.Round) {
+
+	decrypted, err := rsp.cy.Decrypt(ecrMsg.GetContents(), ecrMsg.GetMac())
+	if err != nil {
+		jww.ERROR.Printf("Failed to decrypt payload for %s to %s, "+
+			"single use may fail: %+v", rsp.tag, rsp.recipient.ID, err)
+		return
+	}
+
+	payload, done, err := rsp.c.Collate(decrypted)
+	if err != nil {
+		jww.ERROR.Printf("Failed to collage payload for %s to %s, "+
+			"single use may fail: %+v", rsp.tag, rsp.recipient.ID, err)
+		return
+	}
+
+	if done {
+		rsp.callback(payload, receptionID, round, nil)
+	}
+}
diff --git a/single/response_test.go b/single/response_test.go
deleted file mode 100644
index fcacf19a51bb2c15bcdb961b53665e67248837da..0000000000000000000000000000000000000000
--- a/single/response_test.go
+++ /dev/null
@@ -1,260 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"bytes"
-	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"math/rand"
-	"reflect"
-	"testing"
-	"time"
-)
-
-// Happy path.
-func TestManager_GetMaxResponsePayloadSize(t *testing.T) {
-	m := newTestManager(0, false, t)
-	cmixPrimeSize := m.store.Cmix().GetGroup().GetP().ByteLen()
-	expectedSize := 2*cmixPrimeSize - format.KeyFPLen - format.MacLen - format.RecipientIDLen - responseMinSize - 1
-	testSize := m.GetMaxResponsePayloadSize()
-
-	if expectedSize != testSize {
-		t.Errorf("GetMaxResponsePayloadSize() failed to return the expected size."+
-			"\nexpected: %d\nreceived: %d", expectedSize, testSize)
-	}
-}
-
-// Happy path.
-func TestManager_respondSingleUse(t *testing.T) {
-	m := newTestManager(0, false, t)
-	used := int32(0)
-	partner := Contact{
-		partner:       id.NewIdFromString("partner ID:", id.User, t),
-		partnerPubKey: m.store.E2e().GetGroup().NewInt(42),
-		dhKey:         m.store.E2e().GetGroup().NewInt(99),
-		tagFP:         singleUse.NewTagFP("tag"),
-		maxParts:      10,
-		used:          &used,
-	}
-	payload := make([]byte, 400*int(partner.maxParts))
-	rand.New(rand.NewSource(42)).Read(payload)
-	re := newTestRoundEvents(false)
-
-	expectedMsgs, err := m.makeReplyCmixMessages(partner, payload)
-	if err != nil {
-		t.Fatalf("Failed to created expected messages: %+v", err)
-	}
-
-	err = m.respondSingleUse(partner, payload, 10*time.Millisecond, re)
-	if err != nil {
-		t.Errorf("respondSingleUse() produced an error: %+v", err)
-	}
-
-	// Check that all messages are expected and received
-	if len(m.net.(*testNetworkManager).msgs) != int(partner.GetMaxParts()) {
-		t.Errorf("Recieved incorrect number of messages."+
-			"\nexpected: %d\nreceived: %d", int(partner.GetMaxParts()),
-			len(m.net.(*testNetworkManager).msgs))
-	}
-
-	// Check that all received messages were expected
-	var exists bool
-	for _, received := range m.net.(*testNetworkManager).msgs {
-		exists = false
-		for _, msg := range expectedMsgs {
-			if reflect.DeepEqual(msg, received) {
-				exists = true
-			}
-		}
-		if !exists {
-			t.Errorf("Unexpected message: %+v", received)
-		}
-	}
-}
-
-// Error path: response has already been sent.
-func TestManager_respondSingleUse_ResponseUsedError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	used := int32(1)
-	partner := Contact{
-		partner:       id.NewIdFromString("partner ID:", id.User, t),
-		partnerPubKey: m.store.E2e().GetGroup().NewInt(42),
-		dhKey:         m.store.E2e().GetGroup().NewInt(99),
-		tagFP:         singleUse.NewTagFP("tag"),
-		maxParts:      10,
-		used:          &used,
-	}
-
-	err := m.respondSingleUse(partner, []byte{}, 10*time.Millisecond, newTestRoundEvents(false))
-	if !check(err, "cannot send to single-use contact that has already been sent to") {
-		t.Errorf("respondSingleUse() did not produce the expected error when "+
-			"the contact has been used: %+v", err)
-	}
-}
-
-// Error path: cannot create CMIX message when payload is too large.
-func TestManager_respondSingleUse_MakeCmixMessageError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	used := int32(0)
-	partner := Contact{
-		partner:       id.NewIdFromString("partner ID:", id.User, t),
-		partnerPubKey: m.store.E2e().GetGroup().NewInt(42),
-		dhKey:         m.store.E2e().GetGroup().NewInt(99),
-		tagFP:         singleUse.NewTagFP("tag"),
-		maxParts:      10,
-		used:          &used,
-	}
-	payload := make([]byte, 500*int(partner.maxParts))
-	rand.New(rand.NewSource(42)).Read(payload)
-
-	err := m.respondSingleUse(partner, payload, 10*time.Millisecond, newTestRoundEvents(false))
-	if !check(err, "failed to create new CMIX messages") {
-		t.Errorf("respondSingleUse() did not produce the expected error when "+
-			"the CMIX message creation failed: %+v", err)
-	}
-}
-
-// Error path: TrackResults returns an error.
-func TestManager_respondSingleUse_TrackResultsError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	used := int32(0)
-	partner := Contact{
-		partner:       id.NewIdFromString("partner ID:", id.User, t),
-		partnerPubKey: m.store.E2e().GetGroup().NewInt(42),
-		dhKey:         m.store.E2e().GetGroup().NewInt(99),
-		tagFP:         singleUse.NewTagFP("tag"),
-		maxParts:      10,
-		used:          &used,
-	}
-	payload := make([]byte, 400*int(partner.maxParts))
-	rand.New(rand.NewSource(42)).Read(payload)
-
-	err := m.respondSingleUse(partner, payload, 10*time.Millisecond, newTestRoundEvents(true))
-	if !check(err, "tracking results of") {
-		t.Errorf("respondSingleUse() did not produce the expected error when "+
-			"the CMIX message creation failed: %+v", err)
-	}
-}
-
-// Happy path.
-func TestManager_makeReplyCmixMessages(t *testing.T) {
-	m := newTestManager(0, false, t)
-	partner := Contact{
-		partner:       id.NewIdFromString("partner ID:", id.User, t),
-		partnerPubKey: m.store.E2e().GetGroup().NewInt(42),
-		dhKey:         m.store.E2e().GetGroup().NewInt(99),
-		tagFP:         singleUse.NewTagFP("tag"),
-		maxParts:      255,
-	}
-	payload := make([]byte, 400*int(partner.maxParts))
-	rand.New(rand.NewSource(42)).Read(payload)
-
-	msgs, err := m.makeReplyCmixMessages(partner, payload)
-	if err != nil {
-		t.Errorf("makeReplyCmixMessages() returned an error: %+v", err)
-	}
-
-	buff := bytes.NewBuffer(payload)
-	for i, msg := range msgs {
-		checkReplyCmixMessage(partner,
-			buff.Next(len(msgs[0].GetContents())-responseMinSize), msg, len(msgs), i, t)
-	}
-}
-
-// Error path: size of payload too large.
-func TestManager_makeReplyCmixMessages_PayloadSizeError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	partner := Contact{
-		partner:       id.NewIdFromString("partner ID:", id.User, t),
-		partnerPubKey: m.store.E2e().GetGroup().NewInt(42),
-		dhKey:         m.store.E2e().GetGroup().NewInt(99),
-		tagFP:         singleUse.NewTagFP("tag"),
-		maxParts:      255,
-	}
-	payload := make([]byte, 500*int(partner.maxParts))
-	rand.New(rand.NewSource(42)).Read(payload)
-
-	_, err := m.makeReplyCmixMessages(partner, payload)
-	if err == nil {
-		t.Error("makeReplyCmixMessages() did not return an error when the " +
-			"payload is too large.")
-	}
-}
-
-func checkReplyCmixMessage(c Contact, payload []byte, msg format.Message, maxParts, i int, t *testing.T) {
-	expectedFP := singleUse.NewResponseFingerprint(c.dhKey, uint64(i))
-	key := singleUse.NewResponseKey(c.dhKey, uint64(i))
-	expectedMac := singleUse.MakeMAC(key, msg.GetContents())
-
-	// Check CMIX message
-	if expectedFP != msg.GetKeyFP() {
-		t.Errorf("CMIX message #%d had incorrect fingerprint."+
-			"\nexpected: %s\nrecieved: %s", i, expectedFP, msg.GetKeyFP())
-	}
-
-	if !singleUse.VerifyMAC(key, msg.GetContents(), msg.GetMac()) {
-		t.Errorf("CMIX message #%d had incorrect MAC."+
-			"\nexpected: %+v\nrecieved: %+v", i, expectedMac, msg.GetMac())
-	}
-
-	// Decrypt payload
-	decryptedPayload := cAuth.Crypt(key, expectedFP[:24], msg.GetContents())
-	responseMsg, err := unmarshalResponseMessage(decryptedPayload)
-	if err != nil {
-		t.Errorf("Failed to unmarshal pay load of CMIX message #%d: %+v", i, err)
-	}
-
-	if !bytes.Equal(payload, responseMsg.GetContents()) {
-		t.Errorf("Response message #%d had incorrect contents."+
-			"\nexpected: %+v\nrecieved: %+v",
-			i, payload, responseMsg.GetContents())
-	}
-
-	if uint8(maxParts) != responseMsg.GetMaxParts() {
-		t.Errorf("Response message #%d had incorrect max parts."+
-			"\nexpected: %+v\nrecieved: %+v",
-			i, maxParts, responseMsg.GetMaxParts())
-	}
-
-	if i != int(responseMsg.GetPartNum()) {
-		t.Errorf("Response message #%d had incorrect part number."+
-			"\nexpected: %+v\nrecieved: %+v",
-			i, i, responseMsg.GetPartNum())
-	}
-}
-
-// Happy path.
-func TestManager_splitPayload(t *testing.T) {
-	m := newTestManager(0, false, t)
-	maxSize := 5
-	maxParts := 10
-	payload := []byte("0123456789012345678901234567890123456789012345678901234" +
-		"5678901234567890123456789012345678901234567890123456789")
-	expectedParts := [][]byte{
-		payload[:maxSize],
-		payload[maxSize : 2*maxSize],
-		payload[2*maxSize : 3*maxSize],
-		payload[3*maxSize : 4*maxSize],
-		payload[4*maxSize : 5*maxSize],
-		payload[5*maxSize : 6*maxSize],
-		payload[6*maxSize : 7*maxSize],
-		payload[7*maxSize : 8*maxSize],
-		payload[8*maxSize : 9*maxSize],
-		payload[9*maxSize : 10*maxSize],
-	}
-
-	testParts := m.splitPayload(payload, maxSize, maxParts)
-
-	if !reflect.DeepEqual(expectedParts, testParts) {
-		t.Errorf("splitPayload() failed to correctly split the payload."+
-			"\nexpected: %s\nreceived: %s", expectedParts, testParts)
-	}
-}
diff --git a/single/singleUseMap.go b/single/singleUseMap.go
deleted file mode 100644
index 01e1cca5b6b5472dc75063cf79f20b25e3cb65da..0000000000000000000000000000000000000000
--- a/single/singleUseMap.go
+++ /dev/null
@@ -1,123 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"github.com/pkg/errors"
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/xx_network/primitives/id"
-	"sync"
-	"sync/atomic"
-	"time"
-)
-
-// pending contains a map of all pending single-use states.
-type pending struct {
-	singleUse map[id.ID]*state
-	sync.RWMutex
-}
-
-type ReplyComm func(payload []byte, err error)
-
-// state contains the information and state of each single-use message that is
-// being transmitted.
-type state struct {
-	dhKey    *cyclic.Int
-	fpMap    *fingerprintMap // List of fingerprints for each response part
-	c        *collator       // Collects all response message parts
-	callback ReplyComm       // Returns the error status of the communication
-	quitChan chan struct{}   // Sending on channel kills the timeout handler
-}
-
-// newPending creates a pending object with an empty map.
-func newPending() *pending {
-	return &pending{
-		singleUse: map[id.ID]*state{},
-	}
-}
-
-// newState generates a new state object with the fingerprint map and collator
-// initialised.
-func newState(dhKey *cyclic.Int, messageCount uint8, callback ReplyComm) *state {
-	return &state{
-		dhKey:    dhKey,
-		fpMap:    newFingerprintMap(dhKey, uint64(messageCount)),
-		c:        newCollator(uint64(messageCount)),
-		callback: callback,
-		quitChan: make(chan struct{}),
-	}
-}
-
-// addState adds a new state to the map and starts a thread waiting for all the
-// message parts or for the timeout to occur.
-func (p *pending) addState(rid *id.ID, dhKey *cyclic.Int, maxMsgs uint8,
-	callback ReplyComm, timeout time.Duration) (chan struct{}, *int32, error) {
-	p.Lock()
-
-	// Check if the state already exists
-	if _, exists := p.singleUse[*rid]; exists {
-		return nil, nil, errors.Errorf("a state already exists in the map with "+
-			"the ID %s.", rid)
-	}
-
-	jww.DEBUG.Printf("Successfully added single-use state with the ID %s to "+
-		"the map.", rid)
-
-	// Add the state
-	p.singleUse[*rid] = newState(dhKey, maxMsgs, callback)
-	quitChan := p.singleUse[*rid].quitChan
-	p.Unlock()
-
-	// Create atomic which is set when the timeoutHandler thread is killed
-	quit := int32(0)
-
-	go p.timeoutHandler(rid, callback, timeout, quitChan, &quit)
-
-	return quitChan, &quit, nil
-}
-
-// timeoutHandler waits for the signal to complete or times out and deletes the
-// state.
-func (p *pending) timeoutHandler(rid *id.ID, callback ReplyComm,
-	timeout time.Duration, quitChan chan struct{}, quit *int32) {
-	jww.DEBUG.Printf("Starting handler for sending single-use transmission "+
-		"that will timeout after %s.", timeout)
-
-	timer := time.NewTimer(timeout)
-
-	// Signal on the atomic when this thread quits
-	defer func() {
-		atomic.StoreInt32(quit, 1)
-	}()
-
-	select {
-	case <-quitChan:
-		jww.DEBUG.Print("Single-use transmission timeout handler quitting.")
-		return
-	case <-timer.C:
-		jww.WARN.Printf("Single-use transmission timeout handler timed out "+
-			"after %s.", timeout)
-
-		p.Lock()
-		if _, exists := p.singleUse[*rid]; !exists {
-			p.Unlock()
-			return
-		}
-		delete(p.singleUse, *rid)
-
-		p.Unlock()
-
-		err := errors.Errorf("waiting for response to single-use transmission "+
-			"timed out after %s.", timeout.String())
-		jww.DEBUG.Printf("Deleted single-use from map. Calling callback with "+
-			"error: %+v", err)
-
-		callback(nil, err)
-	}
-}
diff --git a/single/singleUseMap_test.go b/single/singleUseMap_test.go
deleted file mode 100644
index 1f91c755f048fa2a2444109a521931b21cdc6867..0000000000000000000000000000000000000000
--- a/single/singleUseMap_test.go
+++ /dev/null
@@ -1,206 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"gitlab.com/xx_network/primitives/id"
-	"reflect"
-	"strings"
-	"sync/atomic"
-	"testing"
-	"time"
-)
-
-// Happy path: trigger the exit channel.
-func Test_pending_addState_ExitChan(t *testing.T) {
-	p := newPending()
-	rid := id.NewIdFromString("test RID", id.User, t)
-	dhKey := getGroup().NewInt(5)
-	maxMsgs := uint8(6)
-	timeout := 500 * time.Millisecond
-	callback, callbackChan := createReplyComm()
-
-	quitChan, quit, err := p.addState(rid, dhKey, maxMsgs, callback, timeout)
-	if err != nil {
-		t.Errorf("addState() returned an error: %+v", err)
-	}
-
-	hasQuit := atomic.CompareAndSwapInt32(quit, 0, 1)
-	if !hasQuit {
-		t.Error("Quit atomic called.")
-	}
-
-	expectedState := newState(dhKey, maxMsgs, callback)
-
-	quitChan <- struct{}{}
-
-	timer := time.NewTimer(timeout + 1*time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback called when the quit channel was used."+
-			"\npayload: %+v\nerror:   %+v", results.payload, results.err)
-	case <-timer.C:
-	}
-
-	state, exists := p.singleUse[*rid]
-	if !exists {
-		t.Error("State not found in map.")
-	}
-	if !equalState(*expectedState, *state, t) {
-		t.Errorf("State in map is incorrect.\nexpected: %+v\nreceived: %+v",
-			*expectedState, *state)
-	}
-
-	hasQuit = atomic.CompareAndSwapInt32(quit, 0, 1)
-	if hasQuit {
-		t.Error("Quit atomic not called.")
-	}
-}
-
-// Happy path: state is removed before deletion can occur.
-func Test_pending_addState_StateRemoved(t *testing.T) {
-	p := newPending()
-	rid := id.NewIdFromString("test RID", id.User, t)
-	dhKey := getGroup().NewInt(5)
-	maxMsgs := uint8(6)
-	timeout := 5 * time.Millisecond
-	callback, callbackChan := createReplyComm()
-
-	_, _, err := p.addState(rid, dhKey, maxMsgs, callback, timeout)
-	if err != nil {
-		t.Errorf("addState() returned an error: %+v", err)
-	}
-
-	p.Lock()
-	delete(p.singleUse, *rid)
-	p.Unlock()
-
-	timer := time.NewTimer(timeout + 1*time.Millisecond)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback should not have been called.\npayload: %+v\nerror:   %+v",
-			results.payload, results.err)
-	case <-timer.C:
-	}
-}
-
-// Error path: timeout occurs and deletes the entry from the map.
-func Test_pending_addState_TimeoutError(t *testing.T) {
-	p := newPending()
-	rid := id.NewIdFromString("test RID", id.User, t)
-	dhKey := getGroup().NewInt(5)
-	maxMsgs := uint8(6)
-	timeout := 5 * time.Millisecond
-	callback, callbackChan := createReplyComm()
-
-	_, _, err := p.addState(rid, dhKey, maxMsgs, callback, timeout)
-	if err != nil {
-		t.Errorf("addState() returned an error: %+v", err)
-	}
-
-	expectedState := newState(dhKey, maxMsgs, callback)
-	p.Lock()
-	state, exists := p.singleUse[*rid]
-	p.Unlock()
-	if !exists {
-		t.Error("State not found in map.")
-	}
-	if !equalState(*expectedState, *state, t) {
-		t.Errorf("State in map is incorrect.\nexpected: %+v\nreceived: %+v",
-			*expectedState, *state)
-	}
-
-	timerTimeout := timeout * 4
-
-	select {
-	case results := <-callbackChan:
-		state, exists = p.singleUse[*rid]
-		if exists {
-			t.Errorf("State found in map when it should have been deleted."+
-				"\nstate: %+v", state)
-		}
-		if results.payload != nil {
-			t.Errorf("Payload not nil on timeout.\npayload: %+v", results.payload)
-		}
-		if results.err == nil || !strings.Contains(results.err.Error(), "timed out") {
-			t.Errorf("Callback did not return a time out error on return: %+v", results.err)
-		}
-	case <-time.NewTimer(timerTimeout).C:
-		t.Errorf("Failed to time out after %s.", timerTimeout)
-	}
-}
-
-// Error path: state already exists.
-func Test_pending_addState_StateExistsError(t *testing.T) {
-	p := newPending()
-	rid := id.NewIdFromString("test RID", id.User, t)
-	dhKey := getGroup().NewInt(5)
-	maxMsgs := uint8(6)
-	timeout := 5 * time.Millisecond
-	callback, _ := createReplyComm()
-
-	quitChan, _, err := p.addState(rid, dhKey, maxMsgs, callback, timeout)
-	if err != nil {
-		t.Errorf("addState() returned an error: %+v", err)
-	}
-	quitChan <- struct{}{}
-
-	quitChan, _, err = p.addState(rid, dhKey, maxMsgs, callback, timeout)
-	if !check(err, "a state already exists in the map") {
-		t.Errorf("addState() did not return an error when the state already "+
-			"exists: %+v", err)
-	}
-}
-
-type replyCommData struct {
-	payload []byte
-	err     error
-}
-
-func createReplyComm() (func(payload []byte, err error), chan replyCommData) {
-	callbackChan := make(chan replyCommData)
-	callback := func(payload []byte, err error) {
-		callbackChan <- replyCommData{
-			payload: payload,
-			err:     err,
-		}
-	}
-	return callback, callbackChan
-}
-
-// equalState determines if the two states have equal values.
-func equalState(a, b state, t *testing.T) bool {
-	if a.dhKey.Cmp(b.dhKey) != 0 {
-		t.Errorf("DH Keys differ.\nexpected: %s\nreceived: %s",
-			a.dhKey.Text(10), b.dhKey.Text(10))
-		return false
-	}
-	if !reflect.DeepEqual(a.fpMap.fps, b.fpMap.fps) {
-		t.Errorf("Fingerprint maps differ.\nexpected: %+v\nreceived: %+v",
-			a.fpMap.fps, b.fpMap.fps)
-		return false
-	}
-	if !reflect.DeepEqual(b.c, b.c) {
-		t.Errorf("collators differ.\nexpected: %+v\nreceived: %+v",
-			a.c, b.c)
-		return false
-	}
-	if reflect.ValueOf(a.callback).Pointer() != reflect.ValueOf(b.callback).Pointer() {
-		t.Errorf("callbackFuncs differ.\nexpected: %p\nreceived: %p",
-			a.callback, b.callback)
-		return false
-	}
-	return true
-}
-
-// check returns true if the error is not nil and contains the substring.
-func check(err error, subStr string) bool {
-	return err != nil && strings.Contains(err.Error(), subStr)
-}
diff --git a/single/transmission.go b/single/transmission.go
deleted file mode 100644
index 715078cf4050ce0b5fd4dbd8874e1acac6be8b89..0000000000000000000000000000000000000000
--- a/single/transmission.go
+++ /dev/null
@@ -1,267 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package single
-
-import (
-	"fmt"
-	"github.com/pkg/errors"
-	jww "github.com/spf13/jwalterweatherman"
-	ephemeral2 "gitlab.com/elixxir/client/cmix/identity/receptionID"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/params"
-	ds "gitlab.com/elixxir/comms/network/dataStructures"
-	contact2 "gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/elixxir/primitives/states"
-	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"gitlab.com/xx_network/primitives/netTime"
-	"io"
-	"sync/atomic"
-	"time"
-)
-
-// GetMaxTransmissionPayloadSize returns the maximum payload size for a
-// transmission message.
-func (m *Manager) GetMaxTransmissionPayloadSize() int {
-	// Generate empty messages to determine the available space for the payload
-	cmixPrimeSize := m.store.Cmix().GetGroup().GetP().ByteLen()
-	e2ePrimeSize := m.store.E2e().GetGroup().GetP().ByteLen()
-	cmixMsg := format.NewMessage(cmixPrimeSize)
-	transmitMsg := newTransmitMessage(cmixMsg.ContentsSize(), e2ePrimeSize)
-	msgPayload := newTransmitMessagePayload(transmitMsg.GetPayloadSize())
-
-	return msgPayload.GetMaxContentsSize()
-}
-
-// TransmitSingleUse creates a CMIX message, sends it, and waits for delivery.
-func (m *Manager) TransmitSingleUse(partner contact2.Contact, payload []byte,
-	tag string, maxMsgs uint8, callback ReplyComm, timeout time.Duration) error {
-
-	rngReader := m.rng.GetStream()
-	defer rngReader.Close()
-
-	return m.transmitSingleUse(partner, payload, tag, maxMsgs, rngReader, callback, timeout)
-}
-
-// roundEvents interface allows custom round events to be passed in for testing.
-type roundEvents interface {
-	AddRoundEventChan(id.Round, chan ds.EventReturn, time.Duration,
-		...states.Round) *ds.EventCallback
-}
-
-// transmitSingleUse has the fields passed in for easier testing.
-func (m *Manager) transmitSingleUse(partner contact2.Contact, payload []byte,
-	tag string, MaxMsgs uint8, rng io.Reader, callback ReplyComm, timeout time.Duration) error {
-
-	// get address ID address space size; this blocks until the address space
-	// size is set for the first time
-	addressSize := m.net.GetAddressSize()
-	timeStart := netTime.Now()
-
-	// Create new CMIX message containing the transmission payload
-	cmixMsg, dhKey, rid, ephID, err := m.makeTransmitCmixMessage(partner,
-		payload, tag, MaxMsgs, addressSize, timeout, timeStart, rng)
-	if err != nil {
-		return errors.Errorf("failed to create new CMIX message: %+v", err)
-	}
-
-	startValid := timeStart.Add(-2 * timeout)
-	endValid := timeStart.Add(2 * timeout)
-	jww.DEBUG.Printf("Created single-use transmission CMIX message with new ID "+
-		"%s and EphID %d (Valid %s - %s)", rid, ephID.Int64(), startValid.String(), endValid.String())
-
-	// Add message state to map
-	quitChan, quit, err := m.p.addState(rid, dhKey, MaxMsgs, callback, timeout)
-	if err != nil {
-		return errors.Errorf("failed to add pending state: %+v", err)
-	}
-
-	// Add identity for newly generated ID
-	err = m.reception.AddIdentity(ephemeral2.Identity{
-		EphId:       ephID,
-		Source:      rid,
-		AddressSize: addressSize,
-		End:         endValid,
-		ExtraChecks: interfaces.DefaultExtraChecks,
-		StartValid:  startValid,
-		EndValid:    endValid,
-		Ephemeral:   true,
-	})
-	if err != nil {
-		errorString := fmt.Sprintf("failed to add new identity to "+
-			"reception storage for single-use: %+v", err)
-		jww.ERROR.Print(errorString)
-
-		// Exit the state timeout handler, delete the state from map, and
-		// return an error on the callback
-		quitChan <- struct{}{}
-		m.p.Lock()
-		delete(m.p.singleUse, *rid)
-		m.p.Unlock()
-		go callback(nil, errors.New(errorString))
-	}
-
-	go func() {
-		// Send Message
-		jww.DEBUG.Printf("Sending single-use transmission CMIX "+
-			"message to %s.", partner.ID)
-		p := params.GetDefaultCMIX()
-		p.DebugTag = "single.Transmit"
-		round, _, err := m.net.SendCMIX(cmixMsg, partner.ID, p)
-		if err != nil {
-			errorString := fmt.Sprintf("failed to send single-use transmission "+
-				"CMIX message: %+v", err)
-			jww.ERROR.Printf(errorString)
-
-			// Exit the state timeout handler, delete the state from map, and
-			// return an error on the callback
-			quitChan <- struct{}{}
-			m.p.Lock()
-			delete(m.p.singleUse, *rid)
-			m.p.Unlock()
-			go callback(nil, errors.New(errorString))
-		}
-
-		// Check if the state timeout handler has quit
-		if atomic.LoadInt32(quit) == 1 {
-			jww.ERROR.Print("Stopping to send single-use transmission CMIX " +
-				"message because the timeout handler quit.")
-			return
-		}
-		jww.DEBUG.Printf("Sent single-use transmission CMIX "+
-			"message to %s and address ID %d on round %d.",
-			partner.ID, ephID.Int64(), round)
-	}()
-
-	return nil
-}
-
-// makeTransmitCmixMessage generates a CMIX message containing the transmission message,
-// which contains the encrypted payload.
-func (m *Manager) makeTransmitCmixMessage(partner contact2.Contact,
-	payload []byte, tag string, maxMsgs uint8, addressSize uint8,
-	timeout time.Duration, timeNow time.Time, rng io.Reader) (format.Message,
-	*cyclic.Int, *id.ID, ephemeral.Id, error) {
-	e2eGrp := m.store.E2e().GetGroup()
-
-	// Generate internal payloads based off key size to determine if the passed
-	// in payload is too large to fit in the available contents
-	cmixMsg := format.NewMessage(m.store.Cmix().GetGroup().GetP().ByteLen())
-	transmitMsg := newTransmitMessage(cmixMsg.ContentsSize(), e2eGrp.GetP().ByteLen())
-	msgPayload := newTransmitMessagePayload(transmitMsg.GetPayloadSize())
-
-	if msgPayload.GetMaxContentsSize() < len(payload) {
-		return format.Message{}, nil, nil, ephemeral.Id{},
-			errors.Errorf("length of provided payload (%d) too long for message "+
-				"payload capacity (%d).", len(payload), len(msgPayload.contents))
-	}
-
-	// Generate DH key and public key
-	dhKey, publicKey, err := generateDhKeys(e2eGrp, partner.DhPubKey, rng)
-	if err != nil {
-		return format.Message{}, nil, nil, ephemeral.Id{}, err
-	}
-
-	// Compose payload
-	msgPayload.SetTagFP(singleUse.NewTagFP(tag))
-	msgPayload.SetMaxParts(maxMsgs)
-	msgPayload.SetContents(payload)
-
-	// Generate new user ID and address ID
-	rid, ephID, err := makeIDs(&msgPayload, publicKey, addressSize, timeout,
-		timeNow, rng)
-	if err != nil {
-		return format.Message{}, nil, nil, ephemeral.Id{},
-			errors.Errorf("failed to generate IDs: %+v", err)
-	}
-
-	// Encrypt payload
-	fp := singleUse.NewTransmitFingerprint(partner.DhPubKey)
-	key := singleUse.NewTransmitKey(dhKey)
-	encryptedPayload := auth.Crypt(key, fp[:24], msgPayload.Marshal())
-
-	// Generate CMIX message MAC
-	mac := singleUse.MakeMAC(key, encryptedPayload)
-
-	// Compose transmission message
-	transmitMsg.SetPubKey(publicKey)
-	transmitMsg.SetPayload(encryptedPayload)
-
-	// Compose CMIX message contents
-	cmixMsg.SetContents(transmitMsg.Marshal())
-	cmixMsg.SetKeyFP(fp)
-	cmixMsg.SetMac(mac)
-
-	return cmixMsg, dhKey, rid, ephID, nil
-}
-
-// generateDhKeys generates a new public key and DH key.
-func generateDhKeys(grp *cyclic.Group, dhPubKey *cyclic.Int,
-	rng io.Reader) (*cyclic.Int, *cyclic.Int, error) {
-	// Generate private key
-	privKeyBytes, err := csprng.GenerateInGroup(grp.GetP().Bytes(),
-		grp.GetP().ByteLen(), rng)
-	if err != nil {
-		return nil, nil, errors.Errorf("failed to generate key in group: %+v",
-			err)
-	}
-	privKey := grp.NewIntFromBytes(privKeyBytes)
-
-	// Generate public key and DH key
-	publicKey := grp.ExpG(privKey, grp.NewInt(1))
-	dhKey := grp.Exp(dhPubKey, privKey, grp.NewInt(1))
-
-	return dhKey, publicKey, nil
-}
-
-// makeIDs generates a new user ID and address ID with a start and end within
-// the given timout. The ID is generated from the unencrypted msg payload, which
-// contains a nonce. If the generated address ID has a window that is not
-// within +/- the given 2*timeout from now, then the IDs are generated again
-// using a new nonce.
-func makeIDs(msg *transmitMessagePayload, publicKey *cyclic.Int,
-	addressSize uint8, timeout time.Duration, timeNow time.Time,
-	rng io.Reader) (*id.ID, ephemeral.Id, error) {
-	var rid *id.ID
-	var ephID ephemeral.Id
-
-	// Generate acceptable window for the address ID to exist in
-	windowStart, windowEnd := timeNow.Add(-2*timeout), timeNow.Add(2*timeout)
-	start, end := timeNow, timeNow
-
-	// Loop until the address ID's start and end are within bounds
-	for windowStart.Before(start) || windowEnd.After(end) {
-		// Generate new nonce
-		err := msg.SetNonce(rng)
-		if err != nil {
-			return nil, ephemeral.Id{},
-				errors.Errorf("failed to generate nonce: %+v", err)
-		}
-
-		// Generate ID from unencrypted payload
-		rid = msg.GetRID(publicKey)
-
-		// Generate the address ID
-		ephID, start, end, err = ephemeral.GetId(rid, uint(addressSize), timeNow.UnixNano())
-		if err != nil {
-			return nil, ephemeral.Id{}, errors.Errorf("failed to generate "+
-				"address ID from newly generated ID: %+v", err)
-		}
-		jww.DEBUG.Printf("address.GetId(%s, %d, %d) = %d", rid, addressSize, timeNow.UnixNano(), ephID.Int64())
-	}
-
-	jww.INFO.Printf("generated by singe use sender reception id for single use: %s, "+
-		"ephId: %d, pubkey: %x, msg: %s", rid, ephID.Int64(), publicKey.Bytes(), msg)
-
-	return rid, ephID, nil
-}
diff --git a/single/transmission_test.go b/single/transmission_test.go
deleted file mode 100644
index 5fd81ec1bea27ace947d46468a2e913dd9c713ff..0000000000000000000000000000000000000000
--- a/single/transmission_test.go
+++ /dev/null
@@ -1,445 +0,0 @@
-package single
-
-import (
-	"bytes"
-	pb "gitlab.com/elixxir/comms/mixmessages"
-	ds "gitlab.com/elixxir/comms/network/dataStructures"
-	contact2 "gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/crypto/e2e/singleUse"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/elixxir/primitives/states"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"gitlab.com/xx_network/primitives/netTime"
-	"math/rand"
-	"reflect"
-	"strings"
-	"sync"
-	"testing"
-	"time"
-)
-
-// Happy path.
-func TestManager_GetMaxTransmissionPayloadSize(t *testing.T) {
-	m := newTestManager(0, false, t)
-	cmixPrimeSize := m.store.Cmix().GetGroup().GetP().ByteLen()
-	e2ePrimeSize := m.store.E2e().GetGroup().GetP().ByteLen()
-	expectedSize := 2*cmixPrimeSize - e2ePrimeSize - format.KeyFPLen - format.MacLen - format.RecipientIDLen - transmitPlMinSize - transmitMessageVersionSize - 1
-	testSize := m.GetMaxTransmissionPayloadSize()
-
-	if expectedSize != testSize {
-		t.Errorf("GetMaxTransmissionPayloadSize() failed to return the expected size."+
-			"\nexpected: %d\nreceived: %d", expectedSize, testSize)
-	}
-}
-
-// Happy path.
-func TestManager_transmitSingleUse(t *testing.T) {
-	m := newTestManager(0, false, t)
-	prng := rand.New(rand.NewSource(42))
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("Contact ID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(5),
-	}
-	payload := make([]byte, 95)
-	rand.New(rand.NewSource(42)).Read(payload)
-	tag := "testTag"
-	maxMsgs := uint8(8)
-	callback, callbackChan := createReplyComm()
-	timeout := 15 * time.Millisecond
-
-	err := m.transmitSingleUse(partner, payload, tag, maxMsgs, prng, callback, timeout)
-	if err != nil {
-		t.Errorf("transmitSingleUse() returned an error: %+v", err)
-	}
-
-	for _, state := range m.p.singleUse {
-		state.quitChan <- struct{}{}
-	}
-
-	expectedMsg, _, _, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, maxMsgs, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to make expected message: %+v", err)
-	}
-
-	if !reflect.DeepEqual(expectedMsg, m.net.(*testNetworkManager).GetMsg(0)) {
-		t.Errorf("transmitSingleUse() failed to send the correct CMIX message."+
-			"\nexpected: %+v\nreceived: %+v",
-			expectedMsg, m.net.(*testNetworkManager).GetMsg(0))
-	}
-
-	timer := time.NewTimer(timeout * 2)
-
-	select {
-	case results := <-callbackChan:
-		t.Errorf("Callback called when the thread should have quit."+
-			"\npayload: %+v\nerror:   %+v", results.payload, results.err)
-	case <-timer.C:
-	}
-}
-
-// Error path: function quits early if the timoutHandler quit.
-func TestManager_transmitSingleUse_QuitChanError(t *testing.T) {
-	m := newTestManager(10*time.Millisecond, false, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("Contact ID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(5),
-	}
-	callback, callbackChan := createReplyComm()
-	timeout := 15 * time.Millisecond
-
-	err := m.transmitSingleUse(partner, []byte{}, "testTag", 9,
-		rand.New(rand.NewSource(42)), callback, timeout)
-	if err != nil {
-		t.Errorf("transmitSingleUse() returned an error: %+v", err)
-	}
-
-	for _, state := range m.p.singleUse {
-		state.quitChan <- struct{}{}
-	}
-
-	timer := time.NewTimer(2 * timeout)
-
-	select {
-	case results := <-callbackChan:
-		if results.payload != nil || results.err != nil {
-			t.Errorf("Callback called when the timeout thread should have quit."+
-				"\npayload: %+v\nerror:   %+v", results.payload, results.err)
-		}
-	case <-timer.C:
-	}
-}
-
-// Error path: fails to add a new identity.
-func TestManager_transmitSingleUse_AddIdentityError(t *testing.T) {
-	timeout := 15 * time.Millisecond
-	m := newTestManager(timeout, false, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("Contact ID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(5),
-	}
-	callback, callbackChan := createReplyComm()
-
-	err := m.transmitSingleUse(partner, []byte{}, "testTag", 9,
-		rand.New(rand.NewSource(42)), callback, timeout)
-	if err != nil {
-		t.Errorf("transmitSingleUse() returned an error: %+v", err)
-	}
-
-	for _, state := range m.p.singleUse {
-		state.quitChan <- struct{}{}
-	}
-
-	timer := time.NewTimer(2 * timeout)
-
-	select {
-	case results := <-callbackChan:
-		if results.payload != nil || !check(results.err, "Failed to add new identity") {
-			t.Errorf("Callback did not return the correct error when the "+
-				"routine quit early.\npayload: %+v\nerror:   %+v",
-				results.payload, results.err)
-		}
-	case <-timer.C:
-	}
-}
-
-// Error path: Send fails to send message.
-func TestManager_transmitSingleUse_SendCMIXError(t *testing.T) {
-	m := newTestManager(0, true, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("Contact ID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(5),
-	}
-	callback, callbackChan := createReplyComm()
-	timeout := 15 * time.Millisecond
-
-	err := m.transmitSingleUse(partner, []byte{}, "testTag", 9,
-		rand.New(rand.NewSource(42)), callback, timeout)
-	if err != nil {
-		t.Errorf("transmitSingleUse() returned an error: %+v", err)
-	}
-
-	timer := time.NewTimer(timeout * 2)
-
-	select {
-	case results := <-callbackChan:
-		if results.payload != nil || !check(results.err, "failed to send single-use transmission CMIX message") {
-			t.Errorf("Callback did not return the correct error when the "+
-				"routine quit early.\npayload: %+v\nerror:   %+v",
-				results.payload, results.err)
-		}
-	case <-timer.C:
-	}
-}
-
-// Error path: failed to create CMIX message because the payload is too large.
-func TestManager_transmitSingleUse_MakeTransmitCmixMessageError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	prng := rand.New(rand.NewSource(42))
-	payload := make([]byte, m.store.Cmix().GetGroup().GetP().ByteLen())
-
-	err := m.transmitSingleUse(contact2.Contact{}, payload, "", 0, prng, nil, 0)
-	if err == nil {
-		t.Error("transmitSingleUse() did not return an error when the payload " +
-			"is too large.")
-	}
-}
-
-// Error path: failed to add pending state because is already exists.
-func TestManager_transmitSingleUse_AddStateError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("Contact ID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(5),
-	}
-	payload := make([]byte, 95)
-	rand.New(rand.NewSource(42)).Read(payload)
-	tag := "testTag"
-	maxMsgs := uint8(8)
-	callback, _ := createReplyComm()
-	timeout := 15 * time.Millisecond
-
-	// Create new CMIX and add a state
-	_, dhKey, rid, _, err := m.makeTransmitCmixMessage(partner, payload, tag,
-		maxMsgs, 32, 30*time.Second, netTime.Now(), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to create new CMIX message: %+v", err)
-	}
-	m.p.singleUse[*rid] = newState(dhKey, maxMsgs, nil)
-
-	err = m.transmitSingleUse(partner, payload, tag, maxMsgs,
-		rand.New(rand.NewSource(42)), callback, timeout)
-	if !check(err, "failed to add pending state") {
-		t.Errorf("transmitSingleUse() failed to error when on adding state "+
-			"when the state already exists: %+v", err)
-	}
-}
-
-// Error path: timeout occurs on tracking results of round.
-func TestManager_transmitSingleUse_RoundTimeoutError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	prng := rand.New(rand.NewSource(42))
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("Contact ID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(5),
-	}
-	payload := make([]byte, 95)
-	rand.New(rand.NewSource(42)).Read(payload)
-	callback, callbackChan := createReplyComm()
-	timeout := 15 * time.Millisecond
-
-	err := m.transmitSingleUse(partner, payload, "testTag", 8, prng, callback, timeout)
-	if err != nil {
-		t.Errorf("transmitSingleUse() returned an error: %+v", err)
-	}
-
-	timer := time.NewTimer(timeout * 2)
-
-	select {
-	case results := <-callbackChan:
-		if results.payload != nil || !check(results.err, "timed out") {
-			t.Errorf("Callback did not return the correct error when it "+
-				"should have timed out.\npayload: %+v\nerror:   %+v",
-				results.payload, results.err)
-		}
-	case <-timer.C:
-	}
-}
-
-// Happy path
-func TestManager_makeTransmitCmixMessage(t *testing.T) {
-	m := newTestManager(0, false, t)
-	prng := rand.New(rand.NewSource(42))
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(42),
-	}
-	tag := "Test tag"
-	payload := make([]byte, 130)
-	rand.New(rand.NewSource(42)).Read(payload)
-	maxMsgs := uint8(8)
-	timeNow := netTime.Now()
-
-	msg, dhKey, rid, _, err := m.makeTransmitCmixMessage(partner, payload,
-		tag, maxMsgs, 32, 30*time.Second, timeNow, prng)
-
-	if err != nil {
-		t.Errorf("makeTransmitCmixMessage() produced an error: %+v", err)
-	}
-
-	fp := singleUse.NewTransmitFingerprint(partner.DhPubKey)
-	key := singleUse.NewTransmitKey(dhKey)
-
-	encPayload, err := unmarshalTransmitMessage(msg.GetContents(),
-		m.store.E2e().GetGroup().GetP().ByteLen())
-	if err != nil {
-		t.Errorf("Failed to unmarshal contents: %+v", err)
-	}
-
-	decryptedPayload, err := unmarshalTransmitMessagePayload(auth.Crypt(key,
-		fp[:24], encPayload.GetPayload()))
-	if err != nil {
-		t.Errorf("Failed to unmarshal payload: %+v", err)
-	}
-
-	if !bytes.Equal(payload, decryptedPayload.GetContents()) {
-		t.Errorf("Failed to decrypt payload.\nexpected: %+v\nreceived: %+v",
-			payload, decryptedPayload.GetContents())
-	}
-
-	if !singleUse.VerifyMAC(key, encPayload.GetPayload(), msg.GetMac()) {
-		t.Error("Failed to verify the message MAC.")
-	}
-
-	if fp != msg.GetKeyFP() {
-		t.Errorf("Failed to verify the CMIX message fingperprint."+
-			"\nexpected: %s\nreceived: %s", fp, msg.GetKeyFP())
-	}
-
-	if maxMsgs != decryptedPayload.GetMaxParts() {
-		t.Errorf("Incorrect maxMsgs.\nexpected: %d\nreceived: %d",
-			maxMsgs, decryptedPayload.GetMaxParts())
-	}
-
-	expectedTagFP := singleUse.NewTagFP(tag)
-	if decryptedPayload.GetTagFP() != expectedTagFP {
-		t.Errorf("Incorrect TagFP.\nexpected: %s\nreceived: %s",
-			expectedTagFP, decryptedPayload.GetTagFP())
-	}
-
-	if !rid.Cmp(decryptedPayload.GetRID(encPayload.GetPubKey(m.store.E2e().GetGroup()))) {
-		t.Errorf("Returned incorrect recipient ID.\nexpected: %s\nreceived: %s",
-			decryptedPayload.GetRID(encPayload.GetPubKey(m.store.E2e().GetGroup())), rid)
-	}
-}
-
-// Error path: supplied payload to large for message.
-func TestManager_makeTransmitCmixMessage_PayloadTooLargeError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	prng := rand.New(rand.NewSource(42))
-	payload := make([]byte, 1000)
-	rand.New(rand.NewSource(42)).Read(payload)
-
-	_, _, _, _, err := m.makeTransmitCmixMessage(contact2.Contact{}, payload, "", 8, 32,
-		30*time.Second, netTime.Now(), prng)
-
-	if !check(err, "too long for message payload capacity") {
-		t.Errorf("makeTransmitCmixMessage() failed to error when the payload is too "+
-			"large: %+v", err)
-	}
-}
-
-// Error path: key generation fails.
-func TestManager_makeTransmitCmixMessage_KeyGenerationError(t *testing.T) {
-	m := newTestManager(0, false, t)
-	prng := strings.NewReader("a")
-	partner := contact2.Contact{
-		ID:       id.NewIdFromString("recipientID", id.User, t),
-		DhPubKey: m.store.E2e().GetGroup().NewInt(42),
-	}
-
-	_, _, _, _, err := m.makeTransmitCmixMessage(partner, nil, "", 8, 32,
-		30*time.Second, netTime.Now(), prng)
-
-	if !check(err, "failed to generate key in group") {
-		t.Errorf("makeTransmitCmixMessage() failed to error when key "+
-			"generation failed: %+v", err)
-	}
-}
-
-// Happy path: test for consistency.
-func Test_makeIDs_Consistency(t *testing.T) {
-	m := newTestManager(0, false, t)
-	cmixMsg := format.NewMessage(m.store.Cmix().GetGroup().GetP().ByteLen())
-	transmitMsg := newTransmitMessage(cmixMsg.ContentsSize(), m.store.E2e().GetGroup().GetP().ByteLen())
-	msgPayload := newTransmitMessagePayload(transmitMsg.GetPayloadSize())
-	msgPayload.SetTagFP(singleUse.NewTagFP("tag"))
-	msgPayload.SetMaxParts(8)
-	msgPayload.SetContents([]byte("payload"))
-	_, publicKey, err := generateDhKeys(m.store.E2e().GetGroup(),
-		m.store.E2e().GetGroup().NewInt(42), rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to generate public key: %+v", err)
-	}
-	addressSize := uint8(32)
-
-	expectedPayload, err := unmarshalTransmitMessagePayload(msgPayload.Marshal())
-	if err != nil {
-		t.Fatalf("Failed to copy payload: %+v", err)
-	}
-
-	err = expectedPayload.SetNonce(rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Fatalf("Failed to set nonce: %+v", err)
-	}
-
-	timeNow := netTime.Now()
-
-	rid, ephID, err := makeIDs(&msgPayload, publicKey, addressSize,
-		30*time.Second, timeNow, rand.New(rand.NewSource(42)))
-	if err != nil {
-		t.Errorf("makeIDs() returned an error: %+v", err)
-	}
-
-	if expectedPayload.GetNonce() != msgPayload.GetNonce() {
-		t.Errorf("makeIDs() failed to set the expected nonce."+
-			"\nexpected: %d\nreceived: %d", expectedPayload.GetNonce(), msgPayload.GetNonce())
-	}
-
-	if !expectedPayload.GetRID(publicKey).Cmp(rid) {
-		t.Errorf("makeIDs() did not return the expected ID."+
-			"\nexpected: %s\nreceived: %s", expectedPayload.GetRID(publicKey), rid)
-	}
-
-	expectedEphID, _, _, err := ephemeral.GetId(expectedPayload.GetRID(publicKey),
-		uint(addressSize), timeNow.UnixNano())
-	if err != nil {
-		t.Fatalf("Failed to generate expected address ID: %+v", err)
-	}
-
-	if expectedEphID != ephID {
-		t.Errorf("makeIDs() did not return the expected address ID."+
-			"\nexpected: %d\nreceived: %d", expectedEphID.Int64(), ephID.Int64())
-	}
-}
-
-// Error path: failed to generate nonce.
-func Test_makeIDs_NonceError(t *testing.T) {
-	msgPayload := newTransmitMessagePayload(transmitPlMinSize)
-
-	_, _, err := makeIDs(&msgPayload, &cyclic.Int{}, 32, 30*time.Second,
-		netTime.Now(), strings.NewReader(""))
-	if !check(err, "failed to generate nonce") {
-		t.Errorf("makeIDs() did not return an error when failing to make nonce: %+v", err)
-	}
-}
-
-type testRoundEvents struct {
-	callbacks    map[id.Round][states.NUM_STATES]map[*ds.EventCallback]*ds.EventCallback
-	timeoutError bool
-	mux          sync.RWMutex
-}
-
-func newTestRoundEvents(timeoutError bool) *testRoundEvents {
-	return &testRoundEvents{
-		callbacks:    make(map[id.Round][states.NUM_STATES]map[*ds.EventCallback]*ds.EventCallback),
-		timeoutError: timeoutError,
-	}
-}
-
-func (r *testRoundEvents) AddRoundEventChan(_ id.Round,
-	eventChan chan ds.EventReturn, _ time.Duration, _ ...states.Round) *ds.EventCallback {
-
-	eventChan <- struct {
-		RoundInfo *pb.RoundInfo
-		TimedOut  bool
-	}{
-		RoundInfo: &pb.RoundInfo{State: uint32(states.COMPLETED)},
-		TimedOut:  r.timeoutError,
-	}
-
-	return nil
-}
diff --git a/ud/lookup_test.go b/ud/lookup_test.go
index 63cb7ab60c07c3b5740ab676a3579667192025c3..a6debf89424b24b44ad70033e32d947541277cf8 100644
--- a/ud/lookup_test.go
+++ b/ud/lookup_test.go
@@ -191,7 +191,7 @@ type mockSingleLookup struct {
 }
 
 func (s *mockSingleLookup) TransmitSingleUse(_ contact.Contact, payload []byte,
-	_ string, _ uint8, callback single.ReplyComm, _ time.Duration) error {
+	_ string, _ uint8, callback single.ReplyCallback, _ time.Duration) error {
 
 	lookupMsg := &LookupSend{}
 	if err := proto.Unmarshal(payload, lookupMsg); err != nil {
diff --git a/ud/manager.go b/ud/manager.go
index e0c0d8ea3dd6349e7e7b961a694d5bd5d592fdd4..6bd6b7b1a7f5f78532509d00c8a5f89ed4437651 100644
--- a/ud/manager.go
+++ b/ud/manager.go
@@ -6,6 +6,7 @@ import (
 	"gitlab.com/elixxir/client/api"
 	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/single"
+	"gitlab.com/elixxir/client/single/old"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/comms/client"
@@ -21,7 +22,7 @@ import (
 )
 
 type SingleInterface interface {
-	TransmitSingleUse(contact.Contact, []byte, string, uint8, single.ReplyComm,
+	TransmitSingleUse(contact.Contact, []byte, string, uint8, single.ReplyCallback,
 		time.Duration) error
 	StartProcesses() (stoppable.Stoppable, error)
 }
@@ -59,7 +60,7 @@ type alternateUd struct {
 
 // NewManager builds a new user discovery manager. It requires that an updated
 // NDF is available and will error if one is not.
-func NewManager(client *api.Client, single *single.Manager) (*Manager, error) {
+func NewManager(client *api.Client, single *old.Manager) (*Manager, error) {
 	jww.INFO.Println("ud.NewManager()")
 	if client.NetworkFollowerStatus() != api.Running {
 		return nil, errors.New(
diff --git a/ud/search_test.go b/ud/search_test.go
index 9a34441b18b97b7539c55071894af6cc07c037db..9ba8651529d1b0666bf7bdb9c268941fc7638551 100644
--- a/ud/search_test.go
+++ b/ud/search_test.go
@@ -521,7 +521,7 @@ type mockSingleSearch struct {
 }
 
 func (s *mockSingleSearch) TransmitSingleUse(partner contact.Contact, payload []byte,
-	_ string, _ uint8, callback single.ReplyComm, _ time.Duration) error {
+	_ string, _ uint8, callback single.ReplyCallback, _ time.Duration) error {
 
 	searchMsg := &SearchSend{}
 	if err := proto.Unmarshal(payload, searchMsg); err != nil {