diff --git a/diffieHellman/dhkx.go b/diffieHellman/dhkx.go
index e363f5df515e0b48af20b33782835143881e715d..dd79319aeb8144d53906dd0716b0f8bad9bbbf8b 100644
--- a/diffieHellman/dhkx.go
+++ b/diffieHellman/dhkx.go
@@ -12,6 +12,7 @@ import (
 	"fmt"
 	"gitlab.com/elixxir/crypto/csprng"
 	"gitlab.com/elixxir/crypto/cyclic"
+	"io"
 )
 
 const DefaultPrivateKeyLengthBits = 256
@@ -22,7 +23,7 @@ const DefaultPrivateKeyLength = DefaultPrivateKeyLengthBits / 8
 // group. It is recommended to use the "DefaultPrivateKeyLength"
 // for most use cases.
 // key size must be divisible by 8
-func GeneratePrivateKey(size int, group *cyclic.Group, source csprng.Source) *cyclic.Int {
+func GeneratePrivateKey(size int, group *cyclic.Group, source io.Reader) *cyclic.Int {
 
 	k1, err := csprng.GenerateInGroup(group.GetPBytes(), size, source)
 
diff --git a/e2e/auth/ownership.go b/e2e/auth/ownership.go
new file mode 100644
index 0000000000000000000000000000000000000000..d9b5c23fc9c5759f2c875d54bb3dc7637da98b23
--- /dev/null
+++ b/e2e/auth/ownership.go
@@ -0,0 +1,39 @@
+package auth
+
+import (
+	"bytes"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
+	"gitlab.com/elixxir/crypto/hash"
+)
+
+const ownershipVector = "ownershipVector"
+
+// Ownership proofs allow users to build short proofs they own public DH keys
+func MakeOwnershipProof(myHistoricalPrivKey, partnerHistoricalPubKey *cyclic.Int,
+	grp *cyclic.Group) []byte {
+
+	historicalBaseKey := diffieHellman.GenerateSessionKey(myHistoricalPrivKey,
+		partnerHistoricalPubKey, grp)
+
+	h, err := hash.NewCMixHash()
+	if err != nil {
+		jww.FATAL.Panicf("Could not get hash: %+v", err)
+	}
+
+	h.Write(historicalBaseKey.Bytes())
+	h.Write([]byte(ownershipVector))
+
+	return h.Sum(nil)
+}
+
+// verifies that an ownership proof is valid
+func VerifyOwnershipProof(myHistoricalPrivKey, partnerHistoricalPubKey *cyclic.Int,
+	grp *cyclic.Group, proof []byte) bool {
+
+	generatedProof := MakeOwnershipProof(myHistoricalPrivKey,
+		partnerHistoricalPubKey, grp)
+
+	return bytes.Equal(generatedProof, proof)
+}
diff --git a/e2e/auth/ownership_test.go b/e2e/auth/ownership_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..c8db3d7026113bce4aa3dbfb5025705216d0b993
--- /dev/null
+++ b/e2e/auth/ownership_test.go
@@ -0,0 +1,93 @@
+package auth
+
+import (
+	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/diffieHellman"
+	"gitlab.com/elixxir/crypto/large"
+	"math/rand"
+	"testing"
+)
+
+//Tests that the generated proofs do not change
+func TestMakeOwnershipProof_Consistency(t *testing.T) {
+
+	expected := []string{
+		"wQ1qLb7GEpZ3EqJ8bvO9fLiRQWPg6zp885pc8mtTUik=",
+		"dAtL2QxNF+3UpFb3as7i+0FR4EpF77SJzhZYDgjzzKg=",
+		"N6eQTmXGD0XdJjj4mP/Gf+DJ64HurjBWXxyZ6fGxcWc=",
+		"4tPUddOr6ItHlqeZk7f56hXa+Fg5msd240Tcvs7cAYQ=",
+		"NT50KHtItDioL9xa5amz8RObnAOH2slKwcxFxsTk4AQ=",
+	}
+
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(42))
+
+	for i := 0; i < len(expected); i++ {
+		myPrivKey := diffieHellman.GeneratePrivateKey(512, grp, prng)
+		partnerPubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(512, grp, prng), grp)
+		proof := MakeOwnershipProof(myPrivKey, partnerPubKey, grp)
+		proof64 := base64.StdEncoding.EncodeToString(proof)
+		if expected[i] != proof64 {
+			t.Errorf("received and expected do not match at index %v\n"+
+				"\treceived: %s\n\texpected: %s", i, proof64, expected[i])
+		}
+	}
+}
+
+//Tests that the generated proofs are verified
+func TestMakeOwnershipProof_Verified(t *testing.T) {
+
+	const numTests = 100
+
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(69))
+
+	for i := 0; i < numTests; i++ {
+		myPrivKey := diffieHellman.GeneratePrivateKey(512, grp, prng)
+		partnerPubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(512, grp, prng), grp)
+		proof := MakeOwnershipProof(myPrivKey, partnerPubKey, grp)
+
+		if !VerifyOwnershipProof(myPrivKey, partnerPubKey, grp, proof) {
+			t.Errorf("Proof could not be verified at index %v", i)
+		}
+	}
+}
+
+//Tests that bad proofs are not verified
+func TestVerifyOwnershipProof_Bad(t *testing.T) {
+
+	const numTests = 100
+
+	grp := getGrp()
+	prng := rand.New(rand.NewSource(420))
+
+	for i := 0; i < numTests; i++ {
+		myPrivKey := diffieHellman.GeneratePrivateKey(512, grp, prng)
+		partnerPubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(512, grp, prng), grp)
+		proof := make([]byte, 32)
+		prng.Read(proof)
+
+		if VerifyOwnershipProof(myPrivKey, partnerPubKey, grp, proof) {
+			t.Errorf("Proof was verified at index %v when it is bad", i)
+		}
+
+	}
+}
+
+func getGrp() *cyclic.Group {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	return cyclic.NewGroup(p, g)
+}