diff --git a/cmix/identity/receptionID/store.go b/cmix/identity/receptionID/store.go
index e13eddfac252e4fd9daf2032f920f0e110a75dfe..312ebaaf7d65de7a409993801e121f0bc2ba534c 100644
--- a/cmix/identity/receptionID/store.go
+++ b/cmix/identity/receptionID/store.go
@@ -5,6 +5,7 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/shuffle"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
@@ -21,6 +22,8 @@ const (
 	receptionStoreStorageVersion = 0
 )
 
+var InvalidRequestedNumIdentities = errors.New("Cannot get less than 1 identities")
+
 type Store struct {
 	// Identities which are being actively checked
 	active  []*registration
@@ -150,6 +153,8 @@ func (s *Store) makeStoredReferences() []storedReference {
 	return identities[:i]
 }
 
+// GetIdentity will return a single identity. If none are available, it will
+// return a fake one
 func (s *Store) GetIdentity(rng io.Reader, addressSize uint8) (IdentityUse, error) {
 	s.mux.Lock()
 	defer s.mux.Unlock()
@@ -181,6 +186,47 @@ func (s *Store) GetIdentity(rng io.Reader, addressSize uint8) (IdentityUse, erro
 	return identity, nil
 }
 
+// GetIdentities will return up to 'num' identities randomly in a random order.
+// if no identities exist, it will return a single fake identity
+func (s *Store) GetIdentities(num int, rng io.Reader,
+	addressSize uint8) ([]IdentityUse, error) {
+
+	if num < 1 {
+		return nil, errors.New("Cannot get less than 1 identities")
+	}
+
+	s.mux.Lock()
+	defer s.mux.Unlock()
+
+	now := netTime.Now()
+
+	// Remove any now expired identities
+	s.prune(now)
+
+	var identities []IdentityUse
+	var err error
+
+	// If the list is empty, then return a randomly generated identity to poll
+	// with so that we can continue tracking the network and to further
+	// obfuscate network identities.
+	if len(s.active) == 0 {
+		fakeIdentity, err := generateFakeIdentity(rng, addressSize, now)
+		if err != nil {
+			jww.FATAL.Panicf(
+				"Failed to generate a new ID when none available: %+v", err)
+		}
+		identities = append(identities, fakeIdentity)
+
+	} else {
+		identities, err = s.selectIdentities(num, rng, now)
+		if err != nil {
+			jww.FATAL.Panicf("Failed to select a list of IDs: %+v", err)
+		}
+	}
+
+	return identities, nil
+}
+
 func (s *Store) AddIdentity(identity Identity) error {
 	idH := makeIdHash(identity.EphId, identity.Source)
 	s.mux.Lock()
@@ -353,3 +399,52 @@ func (s *Store) selectIdentity(rng io.Reader, now time.Time) (IdentityUse, error
 		CR:       selected.CR,
 	}, nil
 }
+
+func (s *Store) selectIdentities(num int, rng io.Reader, now time.Time) ([]IdentityUse, error) {
+	// Choose a member from the list
+	selected := make([]IdentityUse, 0, num)
+
+	if len(s.active) == 1 {
+		selected = append(selected, makeIdentityUse(s.active[0], now))
+	} else {
+
+		// make the seed
+		seed := make([]byte, 32)
+		if _, err := rng.Read(seed); err != nil {
+			return nil, errors.WithMessage(err, "Failed to choose "+
+				"ID due to RNG failure")
+		}
+
+		// make the list to shuffle
+		registered := make([]*registration, 0, len(s.active))
+		for i := 0; i < len(s.active); i++ {
+			registered = append(registered, s.active[i])
+		}
+
+		//shuffle the list via fisher-yates
+		shuffle.ShuffleSwap(seed, len(s.active), func(i int, j int) {
+			registered[i], registered[j] = registered[j], registered[i]
+		})
+
+		//convert the list to identity use
+		for i := 0; i < len(registered) && (i < num); i++ {
+			selected = append(selected, makeIdentityUse(registered[i], now))
+		}
+
+	}
+
+	return selected, nil
+}
+
+func makeIdentityUse(selected *registration, now time.Time) IdentityUse {
+	if now.After(selected.End) {
+		selected.ExtraChecks--
+	}
+	return IdentityUse{
+		Identity: selected.Identity,
+		Fake:     false,
+		UR:       selected.UR,
+		ER:       selected.ER,
+		CR:       selected.CR,
+	}
+}
diff --git a/cmix/identity/receptionID/store_test.go b/cmix/identity/receptionID/store_test.go
index 19a53f97b11a9e7abaef0ecf3c2c0c1698602105..3fa162c605b7696772199a53be689b60e8b055e2 100644
--- a/cmix/identity/receptionID/store_test.go
+++ b/cmix/identity/receptionID/store_test.go
@@ -2,10 +2,13 @@ package receptionID
 
 import (
 	"bytes"
+	"encoding/binary"
 	"encoding/json"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/netTime"
+	"math"
 	"math/rand"
 	"reflect"
 	"testing"
@@ -164,6 +167,222 @@ func TestStore_GetIdentity(t *testing.T) {
 	}
 }
 
+func TestStore_GetIdentity_NoIdentities(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	s := NewOrLoadStore(kv)
+	prng := rand.New(rand.NewSource(42))
+
+	idu, err := s.GetIdentity(prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if !idu.Fake {
+		t.Errorf("GetIdentity() did not return a fake identity")
+	}
+}
+
+func TestStore_GetIdentities(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	s := NewOrLoadStore(kv)
+	prng := rand.New(rand.NewSource(42))
+
+	numToTest := 100
+
+	idsGenerated := make(map[uint64]interface{})
+
+	for i := 0; i < numToTest; i++ {
+		testID, err := generateFakeIdentity(prng, 15, netTime.Now())
+		if err != nil {
+			t.Fatalf("Failed to generate fake ID: %+v", err)
+		}
+		testID.Fake = false
+		if s.AddIdentity(testID.Identity) != nil {
+			t.Errorf("AddIdentity() produced an error: %+v", err)
+		}
+
+		idsGenerated[getIDFp(testID.EphemeralIdentity)] = nil
+
+	}
+
+	//get one
+	idu, err := s.GetIdentities(1, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if _, exists := idsGenerated[getIDFp(idu[0].EphemeralIdentity)]; !exists ||
+		idu[0].Fake {
+		t.Errorf("An unknown or fake identity was returned")
+	}
+
+	//get three
+	idu, err = s.GetIdentities(3, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 3 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get ten
+	idu, err = s.GetIdentities(10, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 10 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get fifty
+	idu, err = s.GetIdentities(50, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 50 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get 100
+	idu, err = s.GetIdentities(100, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 100 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get 1000, should only return 100
+	idu, err = s.GetIdentities(1000, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 100 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	// get 100 a second time and make sure the order is not the same as a
+	// smoke test that the shuffle is working
+	idu2, err := s.GetIdentities(1000, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	diferent := false
+	for i := 0; i < len(idu); i++ {
+		if !idu[i].Source.Cmp(idu2[i].Source) {
+			diferent = true
+			break
+		}
+	}
+
+	if !diferent {
+		t.Errorf("The 2 100 shuffels retruned the same result, shuffling" +
+			" is likley not occuring")
+	}
+
+}
+
+func TestStore_GetIdentities_NoIdentities(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	s := NewOrLoadStore(kv)
+	prng := rand.New(rand.NewSource(42))
+
+	idu, err := s.GetIdentities(5, prng, 15)
+	if err != nil {
+		t.Errorf("GetIdentities() produced an error: %+v", err)
+	}
+
+	if len(idu) != 1 {
+		t.Errorf("GetIdenties() did not return only one identity " +
+			"when looking for a fake")
+	}
+
+	if !idu[0].Fake {
+		t.Errorf("GetIdenties() did not return a fake identity " +
+			"when only one is avalible")
+	}
+}
+
+func TestStore_GetIdentities_BadNum(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	s := NewOrLoadStore(kv)
+	prng := rand.New(rand.NewSource(42))
+
+	_, err := s.GetIdentities(0, prng, 15)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+
+	_, err = s.GetIdentities(-1, prng, 15)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+
+	_, err = s.GetIdentities(-100, prng, 15)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+
+	_, err = s.GetIdentities(-1000000, prng, 15)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+
+	_, err = s.GetIdentities(math.MinInt64, prng, 15)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+}
+
+func getIDFp(identity EphemeralIdentity) uint64 {
+	h, _ := hash.NewCMixHash()
+	h.Write(identity.EphId[:])
+	h.Write(identity.Source.Bytes())
+	r := h.Sum(nil)
+	return binary.BigEndian.Uint64(r)
+}
+
 func TestStore_AddIdentity(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	s := NewOrLoadStore(kv)
diff --git a/cmix/identity/tracker.go b/cmix/identity/tracker.go
index 8d9f8a6d2a168d27147f9fe280f2d777e0b9935c..2a2cfbd18dcb9f7a1f8d1e08ba81a51145fe9a72 100644
--- a/cmix/identity/tracker.go
+++ b/cmix/identity/tracker.go
@@ -144,11 +144,21 @@ func (t *manager) RemoveIdentity(id *id.ID) {
 }
 
 // GetEphemeralIdentity returns an ephemeral Identity to poll the network with.
+// It will return a fake identity if none are available.
 func (t *manager) GetEphemeralIdentity(rng io.Reader, addressSize uint8) (
 	receptionID.IdentityUse, error) {
 	return t.ephemeral.GetIdentity(rng, addressSize)
 }
 
+// GetEphemeralIdentities returns a fisher-yates shuffled list of up to 'num'
+// ephemeral identities. It will return a fake identity if none are available
+// and less than 'num' if less than 'num' are available.
+// 'num' must be positive non-zero
+func (t *manager) GetEphemeralIdentities(num int, rng io.Reader, addressSize uint8) (
+	[]receptionID.IdentityUse, error) {
+	return t.ephemeral.GetIdentities(num, rng, addressSize)
+}
+
 // GetIdentity returns a currently tracked identity
 func (t *manager) GetIdentity(get *id.ID) (TrackedID, error) {
 	t.mux.Lock()
diff --git a/go.mod b/go.mod
index 7b732085c5ae630d5ef1cca6c40e3af43f7b5d70..bba8ff464ab07d868e0f0f3f7af973e74677605c 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
 	github.com/golang/protobuf v1.5.2
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
 	github.com/pkg/errors v0.9.1
+	github.com/pkg/profile v1.6.0
 	github.com/spf13/cobra v1.5.0
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/viper v1.12.0
@@ -39,7 +40,6 @@ require (
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.2 // indirect
-	github.com/pkg/profile v1.6.0 // indirect
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
 	github.com/spf13/afero v1.9.2 // indirect
 	github.com/spf13/cast v1.5.0 // indirect