diff --git a/e2e/singleUse/mac.go b/e2e/singleUse/mac.go
new file mode 100644
index 0000000000000000000000000000000000000000..649339f16d639629402e69535abf27324ad02b5d
--- /dev/null
+++ b/e2e/singleUse/mac.go
@@ -0,0 +1,40 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	"bytes"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
+)
+
+const macConstant = "macConstant"
+
+// MakeMAC generates the MAC for the given base key and encrypted payload.
+func MakeMAC(baseKey *cyclic.Int, encryptedPayload []byte) []byte {
+	h, err := hash.NewCMixHash()
+	if err != nil {
+		jww.ERROR.Panicf("Failed to create hash: %v", err)
+	}
+
+	// Hash the key, number, and constant
+	h.Write(baseKey.Bytes())
+	h.Write(encryptedPayload)
+	h.Write([]byte(macConstant))
+
+	return h.Sum(nil)
+}
+
+// VerifyMAC determines if the provided MAC is valid for the given base key and
+// encrypted payload.
+func VerifyMAC(baseKey *cyclic.Int, encryptedPayload, receivedMAC []byte) bool {
+	newMAC := MakeMAC(baseKey, encryptedPayload)
+
+	return bytes.Equal(newMAC, receivedMAC)
+}
diff --git a/e2e/singleUse/mac_test.go b/e2e/singleUse/mac_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..1817a33fd9d2403acd64d47fd9a6f6a51e765352
--- /dev/null
+++ b/e2e/singleUse/mac_test.go
@@ -0,0 +1,123 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
+	"math/rand"
+	"testing"
+)
+
+// Tests that the generated MACs do not change.
+func TestMAC_Consistency(t *testing.T) {
+	expectedMACs := []string{
+		"D7vXMT3iX/1tvFPjowoz3w5b3PbECB4EFgkR3hNzyCM=",
+		"ffW26eqwyTHERUPHbmFkUitRj7c+c/PQayfwQPLihNs=",
+		"/lyTEnFbzEEmmMjOQhq6qr0jUYE2j22ERcR4CLH9368=",
+		"vPB8eXP8BXWdxSU4a+Lp1pYVWb98COtWtR0sBngGyTs=",
+		"BuvhuSO01uM+nVQPwXlOwRzr7xchVM1dRoF9h5TC2HU=",
+		"vF5iYaFdhLtgOO5hWNpAF6jJaW4utF1MLGaz/gYb0TY=",
+		"opI2htMJEqZvvEKHAwWnTSqgvaAempY9//rRxNNFHQU=",
+		"ppGzFglPaLzytF5gJRtSFbYoidsShEBoX1cxkAJY3F4=",
+		"pdzZmlz6qdChwo7B5sChTRUpQ5zLvlH5LgndOhDHAt8=",
+		"BHP2yvbUcynr6vM61qt+18YshTsyArJqv0VCq/EI3+o=",
+	}
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+
+	for i, expected := range expectedMACs {
+		privKey := diffieHellman.GeneratePrivateKey(diffieHellman.DefaultPrivateKeyLength, grp, prng)
+		pubkey := diffieHellman.GeneratePublicKey(privKey, grp)
+		baseKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
+		encryptedPayload := make([]byte, 128)
+		prng.Read(encryptedPayload)
+		testMAC := MakeMAC(baseKey, encryptedPayload)
+		testMACBase64 := base64.StdEncoding.EncodeToString(testMAC)
+
+		if expected != testMACBase64 {
+			t.Errorf("MakeMAC() did not return the expected MAC for the given "+
+				"base key and encrypted payload at index %d."+
+				"\nbase key: %s\nexpected: %s\nreceived: %s",
+				i, baseKey.Text(10), expected, testMACBase64)
+		}
+	}
+}
+
+// Tests that all generated MACs are unique.
+func TestMAC_Unique(t *testing.T) {
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+	MACs := make(map[string]struct {
+		key              *cyclic.Int
+		encryptedPayload []byte
+	}, 100)
+
+	for i := 0; i < 100; i++ {
+		privKey := diffieHellman.GeneratePrivateKey(diffieHellman.DefaultPrivateKeyLength, grp, prng)
+		pubkey := diffieHellman.GeneratePublicKey(privKey, grp)
+		baseKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
+		encryptedPayload := make([]byte, 128)
+		prng.Read(encryptedPayload)
+		testMAC := MakeMAC(baseKey, encryptedPayload)
+		testMACBase64 := base64.StdEncoding.EncodeToString(testMAC)
+
+		if _, exists := MACs[testMACBase64]; exists {
+			t.Errorf("Generated MAC collides with previously generated MAC."+
+				"\ncurrent MAC:   baseKey: %s  encryptedPayload: %s"+
+				"\npreviouse MAC: baseKey: %s  encryptedPayload: %s"+
+				"\nMAC:           %s",
+				baseKey.Text(10),
+				base64.StdEncoding.EncodeToString(encryptedPayload),
+				MACs[testMACBase64].key.Text(10),
+				base64.StdEncoding.EncodeToString(MACs[testMACBase64].encryptedPayload),
+				base64.StdEncoding.EncodeToString(testMAC))
+		} else {
+			MACs[testMACBase64] = struct {
+				key              *cyclic.Int
+				encryptedPayload []byte
+			}{baseKey, encryptedPayload}
+		}
+	}
+}
+
+func TestVerifyMAC(t *testing.T) {
+	expectedMACs := []string{
+		"D7vXMT3iX/1tvFPjowoz3w5b3PbECB4EFgkR3hNzyCM=",
+		"ffW26eqwyTHERUPHbmFkUitRj7c+c/PQayfwQPLihNs=",
+		"/lyTEnFbzEEmmMjOQhq6qr0jUYE2j22ERcR4CLH9368=",
+		"vPB8eXP8BXWdxSU4a+Lp1pYVWb98COtWtR0sBngGyTs=",
+		"BuvhuSO01uM+nVQPwXlOwRzr7xchVM1dRoF9h5TC2HU=",
+		"vF5iYaFdhLtgOO5hWNpAF6jJaW4utF1MLGaz/gYb0TY=",
+		"opI2htMJEqZvvEKHAwWnTSqgvaAempY9//rRxNNFHQU=",
+		"ppGzFglPaLzytF5gJRtSFbYoidsShEBoX1cxkAJY3F4=",
+		"pdzZmlz6qdChwo7B5sChTRUpQ5zLvlH5LgndOhDHAt8=",
+		"BHP2yvbUcynr6vM61qt+18YshTsyArJqv0VCq/EI3+o=",
+	}
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+
+	for i, expected := range expectedMACs {
+		privKey := diffieHellman.GeneratePrivateKey(diffieHellman.DefaultPrivateKeyLength, grp, prng)
+		pubkey := diffieHellman.GeneratePublicKey(privKey, grp)
+		baseKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
+		encryptedPayload := make([]byte, 128)
+		prng.Read(encryptedPayload)
+		testMAC := MakeMAC(baseKey, encryptedPayload)
+		testMACBase64 := base64.StdEncoding.EncodeToString(testMAC)
+
+		receivedMac, _ := base64.StdEncoding.DecodeString(expected)
+
+		if !VerifyMAC(baseKey, encryptedPayload, receivedMac) {
+			t.Errorf("VerifyMAC() failed for a correct MAC (%d)."+
+				"\nbase key: %s\nexpected: %s\nreceived: %s",
+				i, baseKey.Text(10), expected, testMACBase64)
+		}
+	}
+}
diff --git a/e2e/singleUse/responseFingerprint.go b/e2e/singleUse/responseFingerprint.go
new file mode 100644
index 0000000000000000000000000000000000000000..5669053ca0a8310803ae40916541c79473efae97
--- /dev/null
+++ b/e2e/singleUse/responseFingerprint.go
@@ -0,0 +1,44 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	"encoding/binary"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
+	"gitlab.com/elixxir/primitives/format"
+)
+
+const responseFPConstant = "responseFPConstant"
+
+func ResponseFingerprint(pubKey *cyclic.Int, keyNum uint64) format.Fingerprint {
+	// Create fingerprint
+	fp := format.Fingerprint{}
+	copy(fp[:], makeHash(pubKey, keyNum, responseFPConstant))
+
+	return fp
+}
+
+func makeHash(pubKey *cyclic.Int, keyNum uint64, constant string) []byte {
+	h, err := hash.NewCMixHash()
+	if err != nil {
+		jww.ERROR.Panicf("Failed to create hash: %v", err)
+	}
+
+	// Convert the key number to bytes
+	buff := make([]byte, binary.MaxVarintLen64)
+	binary.BigEndian.PutUint64(buff, keyNum)
+
+	// Hash the key, number, and constant
+	h.Write(pubKey.Bytes())
+	h.Write(buff)
+	h.Write([]byte(constant))
+
+	return h.Sum(nil)
+}
diff --git a/e2e/singleUse/responseFingerprint_test.go b/e2e/singleUse/responseFingerprint_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..bfdb6f2b4cb6c6d02b1c669f6ba4ec5d122256f1
--- /dev/null
+++ b/e2e/singleUse/responseFingerprint_test.go
@@ -0,0 +1,89 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
+	"math/rand"
+	"testing"
+)
+
+// Tests that the generated fingerprints do not change.
+func TestResponseFingerprint(t *testing.T) {
+	expectedFP := "H+GySzAGq3y6o1JA0Mqxn68GO1uSzCEmpVVbHR2sJc8="
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+
+	pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
+	testFP := ResponseFingerprint(pubKey, 0)
+	testFPBase64 := base64.StdEncoding.EncodeToString(testFP[:])
+
+	if expectedFP != testFPBase64 {
+		t.Errorf("ResponseFingerprint() did not return the expected "+
+			"fingerprint for public key %s."+
+			"\nexpected: %s\nreceived: %s",
+			pubKey.Text(10), expectedFP, testFPBase64)
+	}
+}
+
+// Tests that the generated fingerprints do not change.
+func Test_makeHash_Consistency(t *testing.T) {
+	expectedHashes := []string{
+		"R7UL7by0fP2bXRBlzUOrUKo+7pRATF4r6bUD8/H+PBc=",
+		"CQsWbxgdjYOIJsdfTk/w3549Ltp7TJlSUquK94O8rAM=",
+		"5+pY4khsqHh0bEXZvYC2DLEJbxq4g5bL19JsllOcfso=",
+		"FW9gcwJAl90cLcsnxdnHLcIuJO6NpXqkVWFfbXqWXmA=",
+		"peyTwZZUKPwHB5J1UptEbL+TUEjvg4ZBVceE/J1Q3pQ=",
+		"f8YCUyFXznRHQ1gzuBJrSQegE7wC1JYb8MPTbtJ+qj0=",
+		"g6pHsrATAkSl7QMn9Re01nuc5VF88yvyWvPCHKm3upk=",
+		"S0WrlEhrMIDvJ68hhY6c0Mk5FabZqoAoUdxaBrDXdhg=",
+		"2mHHoyjQExs314tLMg+6pt1cGE5j4vckWZa18pPjZmQ=",
+		"2YMO0HeFF6dCd3cKhNQAXw76zaQ573fw0TM/3PLmUGI=",
+	}
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+
+	for i, expectedHash := range expectedHashes {
+		pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
+			diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
+		testHash := makeHash(pubKey, uint64(i), "constant")
+		testHashBase64 := base64.StdEncoding.EncodeToString(testHash)
+
+		if expectedHash != testHashBase64 {
+			t.Errorf("makeHash() did not return the expected hash for public "+
+				"key %s at index %d.\nexpected: %s\nreceived: %s",
+				pubKey.Text(10), i, expectedHash, testHashBase64)
+		}
+	}
+}
+
+// Tests that all generated fingerprints are unique.
+func Test_makeHash_Unique(t *testing.T) {
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+	hashes := make(map[string]*cyclic.Int, 100)
+
+	for i := 0; i < 100; i++ {
+		pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
+			diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
+		testHash := makeHash(pubKey, uint64(i), "constant")
+
+		hashBase64 := base64.StdEncoding.EncodeToString(testHash)
+
+		if hashes[hashBase64] != nil {
+			t.Errorf("Generated hash from key %s collides with "+
+				"previously generated hash from key %s.\nfingerprint: %s",
+				pubKey.Text(10), hashes[hashBase64].Text(10), hashBase64)
+		} else {
+			hashes[hashBase64] = pubKey
+		}
+	}
+}
diff --git a/e2e/singleUse/responseKey.go b/e2e/singleUse/responseKey.go
new file mode 100644
index 0000000000000000000000000000000000000000..a506757b7f45788e282a3053bba49bffd91e3479
--- /dev/null
+++ b/e2e/singleUse/responseKey.go
@@ -0,0 +1,18 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	"gitlab.com/elixxir/crypto/cyclic"
+)
+
+const responseKeyConstant = "responseKeyConstant"
+
+func ResponseKey(pubKey *cyclic.Int, keyNum uint64) []byte {
+	return makeHash(pubKey, keyNum, responseKeyConstant)
+}
diff --git a/e2e/singleUse/responseKey_test.go b/e2e/singleUse/responseKey_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..424eee618d697621a03a18ac07b099ee58e61d77
--- /dev/null
+++ b/e2e/singleUse/responseKey_test.go
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	"encoding/base64"
+	"gitlab.com/elixxir/crypto/diffieHellman"
+	"math/rand"
+	"testing"
+)
+
+// Tests that the generated key does not change.
+func TestResponseKey(t *testing.T) {
+	expectedKey := "6H61xTtJZYhmT8Q2cm3ZXj7J95yHO5lQN/s1cRu/j40="
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+
+	pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
+		diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
+	testKey := ResponseKey(pubKey, 0)
+	testKeyBase64 := base64.StdEncoding.EncodeToString(testKey)
+
+	if expectedKey != testKeyBase64 {
+		t.Errorf("ResponseKey() did not return the expected key for public "+
+			"key %s.\nexpected: %s\nreceived: %s",
+			pubKey.Text(10), expectedKey, testKeyBase64)
+	}
+}
diff --git a/e2e/singleUse/transmitFingerprint.go b/e2e/singleUse/transmitFingerprint.go
new file mode 100644
index 0000000000000000000000000000000000000000..1c4aaa8ece5db4b08811cd9b4b1f866d4230b8b5
--- /dev/null
+++ b/e2e/singleUse/transmitFingerprint.go
@@ -0,0 +1,36 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                           //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
+	"gitlab.com/elixxir/primitives/format"
+)
+
+const transmitFPConstant = "transmitFPConstant"
+
+func TransmitFingerprint(pubKey *cyclic.Int) format.Fingerprint {
+	// Create new hash
+	h, err := hash.NewCMixHash()
+	if err != nil {
+		jww.ERROR.Panicf("Failed to create hash: %v", err)
+	}
+
+	// Hash the key and constant
+	h.Write(pubKey.Bytes())
+	h.Write([]byte(transmitFPConstant))
+	keyHash := h.Sum(nil)
+
+	// Create fingerprint
+	fp := format.Fingerprint{}
+	copy(fp[:], keyHash)
+
+	return fp
+}
diff --git a/e2e/singleUse/transmitFingerprint_test.go b/e2e/singleUse/transmitFingerprint_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a0d8787bbc1de700ac865de5a64fd4aa903b8cba
--- /dev/null
+++ b/e2e/singleUse/transmitFingerprint_test.go
@@ -0,0 +1,86 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package singleUse
+
+import (
+	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
+	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/crypto/large"
+	"math/rand"
+	"testing"
+)
+
+// Tests that the generated fingerprints do not change.
+func TestTransmitFingerprint_Consistency(t *testing.T) {
+	expectedFPs := []string{
+		"8xef7y86YmR6+qVBaVghPYbEd0j7seLUxR1v1dxqiNo=",
+		"LJ1HQ8zZPY3z+6UkKZMSDN2WymMmwuWW3GCjtAGfUlc=",
+		"Fc8CN69uMxT1zBAr3Ed/AOy6Py3XDb3i7LngRsax0K8=",
+		"4mvA+dxgIy/UxRVIvzFgGtEuMoWI8RodF7JMFIO5xcI=",
+		"3YJPhLeI2+RawlSMUTEwTP1iJrFAa5zboCf5fjc/k3o=",
+		"mEOS0pDuNYS5hpNHeJ2IhzlZFf9J5oHRvFpovNwWS7c=",
+		"i3k7dv1Nch1oTT4aOxbBDifmf7+mT34ErFFaWW5LDb8=",
+		"ck/wkZ3lv0bcQuW+Z2dw37m+Re0URPw4UsWBPAWBEtw=",
+		"k/YRXaE2dplVPZSiEY+7C0e6GlDeR3jLrIPRWgeL3cI=",
+		"qkT2Hfz8A7jNxOhDYG266b/hvWcQtAx0ay67Az80bAY=",
+	}
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+
+	for i, expected := range expectedFPs {
+		pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
+			diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
+		testFP := TransmitFingerprint(pubKey)
+		testFPBase64 := base64.StdEncoding.EncodeToString(testFP[:])
+
+		if expected != testFPBase64 {
+			t.Errorf("TransmitFingerprint() did not return the expected "+
+				"fingerprint for public key %s at index %d."+
+				"\nexpected: %s\nreceived: %s",
+				pubKey.Text(10), i, expected, testFPBase64)
+		}
+	}
+}
+
+// Tests that all generated fingerprints are unique.
+func TestTransmitFingerprint_Unique(t *testing.T) {
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+	FPs := make(map[format.Fingerprint]*cyclic.Int, 100)
+
+	for i := 0; i < 100; i++ {
+		pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
+			diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
+		testFP := TransmitFingerprint(pubKey)
+
+		if FPs[testFP] != nil {
+			t.Errorf("Generated fingerprint from key %s collides with "+
+				"previously generated fingerprint from key %s."+
+				"\nfingerprint: %s", pubKey.Text(10), FPs[testFP].Text(10),
+				base64.StdEncoding.EncodeToString(testFP[:]))
+		} else {
+			FPs[testFP] = pubKey
+		}
+	}
+}
+
+func getGrp() *cyclic.Group {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" +
+		"A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1" +
+		"4374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDE" +
+		"E386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA4" +
+		"8361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077" +
+		"096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E8" +
+		"6039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE51" +
+		"5D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF"
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	return cyclic.NewGroup(p, g)
+}