diff --git a/channels/channelMessages.pb.go b/channels/channelMessages.pb.go
index f9fe30584be5787e7b73924071839cb87ef233a9..911c35da9cfb33b1e319f64233c174f81f1c25d6 100644
--- a/channels/channelMessages.pb.go
+++ b/channels/channelMessages.pb.go
@@ -47,6 +47,10 @@ type ChannelMessage struct {
 	// nickname is the name which the user is using for this message
 	// it will not be longer than 24 characters
 	Nickname string `protobuf:"bytes,5,opt,name=Nickname,proto3" json:"Nickname,omitempty"`
+	// Nonce is 32 bits of randomness to ensure that two messages in the same
+	// round with that have the same nickname, payload, and lease will not have
+	// the same message ID.
+	Nonce []byte `protobuf:"bytes,6,opt,name=Nonce,proto3" json:"Nonce,omitempty"`
 }
 
 func (x *ChannelMessage) Reset() {
@@ -116,6 +120,13 @@ func (x *ChannelMessage) GetNickname() string {
 	return ""
 }
 
+func (x *ChannelMessage) GetNonce() []byte {
+	if x != nil {
+		return x.Nonce
+	}
+	return nil
+}
+
 // UserMessage is a message sent by a user who is a member within the channel.
 type UserMessage struct {
 	state         protoimpl.MessageState
@@ -194,7 +205,7 @@ var File_channelMessages_proto protoreflect.FileDescriptor
 var file_channelMessages_proto_rawDesc = []byte{
 	0x0a, 0x15, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
 	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
-	0x73, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73,
+	0x73, 0x22, 0xae, 0x01, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73,
 	0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20,
 	0x01, 0x28, 0x03, 0x52, 0x05, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f,
 	0x75, 0x6e, 0x64, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x52, 0x6f, 0x75,
@@ -203,17 +214,18 @@ var file_channelMessages_proto_rawDesc = []byte{
 	0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
 	0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
 	0x12, 0x1a, 0x0a, 0x08, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x08, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x69, 0x0a, 0x0b,
-	0x55, 0x73, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x4d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x4d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
-	0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
-	0x75, 0x72, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x45, 0x43, 0x43, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
-	0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x45, 0x43, 0x43, 0x50, 0x75,
-	0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x24, 0x5a, 0x22, 0x67, 0x69, 0x74, 0x6c, 0x61,
-	0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78, 0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c,
-	0x69, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x62, 0x06, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x28, 0x09, 0x52, 0x08, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05,
+	0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x4e, 0x6f, 0x6e,
+	0x63, 0x65, 0x22, 0x69, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53,
+	0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09,
+	0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x45, 0x43, 0x43,
+	0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x0c, 0x45, 0x43, 0x43, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x24, 0x5a,
+	0x22, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78,
+	0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x6e,
+	0x65, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/channels/channelMessages.proto b/channels/channelMessages.proto
index b0ceb6fd8c156c4c24f80743eb8e1b54973cf084..548cfc67c9e8f02a750f12fff45bb27b8b613b4b 100644
--- a/channels/channelMessages.proto
+++ b/channels/channelMessages.proto
@@ -32,10 +32,10 @@ message ChannelMessage{
     // it will not be longer than 24 characters
     string Nickname = 5;
 
-    // Nonce is 32 bits of randomness to ensure that in the event that in the
-    // same round two messages are send with the same nickname, payload,
-    // and lease, they will not have the same message ID.
-    bytes  Nonce = 6;
+    // Nonce is 32 bits of randomness to ensure that two messages in the same
+    // round with that have the same nickname, payload, and lease will not have
+    // the same message ID.
+    bytes Nonce = 6;
 }
 
 // UserMessage is a message sent by a user who is a member within the channel.
@@ -54,4 +54,4 @@ message UserMessage {
     // ECCPublicKey is the user's EC Public key. This is provided by the
     // network.
     bytes  ECCPublicKey = 5;
-}
+}
\ No newline at end of file
diff --git a/channels/send.go b/channels/send.go
index af1c33e09a926a0cbb4c3dff2fff8c353919574a..9b5b4fdb5fed58078168286e553ad7dc5dc78137 100644
--- a/channels/send.go
+++ b/channels/send.go
@@ -9,6 +9,7 @@ package channels
 
 import (
 	"crypto/ed25519"
+	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
@@ -24,6 +25,9 @@ const (
 	cmixChannelReactionVersion = 0
 )
 
+// The size of the nonce used in the message ID.
+const messageNonceSize = 4
+
 // SendGeneric is used to send a raw message over a channel. In general, it
 // should be wrapped in a function which defines the wire protocol
 // If the final message, before being sent over the wire, is too long, this will
@@ -49,6 +53,21 @@ func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
 		PayloadType: uint32(messageType),
 		Payload:     msg,
 		Nickname:    nickname,
+		Nonce:       make([]byte, messageNonceSize),
+	}
+
+	// Generate random nonce to be used for message ID generation. This makes it
+	// so two identical messages sent on the same round have different message IDs
+	rng := m.rng.GetStream()
+	n, err := rng.Read(chMsg.Nonce)
+	rng.Close()
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf("Failed to generate nonce: %+v", err)
+	} else if n != messageNonceSize {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf(
+				"Generated %d bytes for %-byte nonce", n, messageNonceSize)
 	}
 
 	usrMsg := &UserMessage{
@@ -124,9 +143,25 @@ func (m *manager) SendAdminGeneric(privKey rsa.PrivateKey, channelID *id.ID,
 		PayloadType: uint32(messageType),
 		Payload:     msg,
 		Nickname:    AdminUsername,
+		Nonce:       make([]byte, messageNonceSize),
 	}
-	//Note: we are not checking check if message is too long before trying to
-	//find a round
+
+	// Generate random nonce to be used for message ID generation. This makes it
+	// so two identical messages sent on the same round have different message IDs
+	rng := m.rng.GetStream()
+	n, err := rng.Read(chMsg.Nonce)
+	rng.Close()
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf("Failed to generate nonce: %+v", err)
+	} else if n != messageNonceSize {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf(
+				"Generated %d bytes for %-byte nonce", n, messageNonceSize)
+	}
+
+	// Note: we are not checking if message is too long before trying to
+	// find a round
 
 	//Build the function pointer that will build the message
 	assemble := func(rid id.Round) ([]byte, error) {
diff --git a/channels/send_test.go b/channels/send_test.go
index d8c96c028fa249a74de615e749c60767697b8b1e..5da3010922520fe229f918784d72ad32146e59f0 100644
--- a/channels/send_test.go
+++ b/channels/send_test.go
@@ -15,11 +15,13 @@ import (
 	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/storage/versioned"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/netTime"
 	"math/rand"
+	"sync"
 	"testing"
 	"time"
 
@@ -153,6 +155,8 @@ func TestSendGeneric(t *testing.T) {
 	m := &manager{
 		me:       pi,
 		channels: make(map[id.ID]*joinedChannel),
+		mux:      sync.RWMutex{},
+		rng:      fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 		nicknameManager: &nicknameManager{
 			byChannel: make(map[id.ID]string),
 			kv:        nil,
@@ -196,9 +200,9 @@ func TestSendGeneric(t *testing.T) {
 	}
 	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
 
-	//verify the message was handled correctly
+	// verify the message was handled correctly
 
-	//decode the user message
+	// decode the user message
 	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
 	if err != nil {
 		t.Fatalf("Failed to decode the user message: %s", err)
@@ -242,7 +246,8 @@ func TestAdminGeneric(t *testing.T) {
 			byChannel: make(map[id.ID]string),
 			kv:        nil,
 		},
-		me: pi,
+		me:  pi,
+		rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 		st: loadSendTracker(&mockBroadcastClient{},
 			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
 				umi *userMessageInternal, ts time.Time,
@@ -282,7 +287,7 @@ func TestAdminGeneric(t *testing.T) {
 	}
 	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
 
-	//verify the message was handled correctly
+	// verify the message was handled correctly
 
 	msgID := cryptoChannel.MakeMessageID(mbc.payload, ch.ReceptionID)
 
@@ -291,7 +296,7 @@ func TestAdminGeneric(t *testing.T) {
 			msgID, messageId)
 	}
 
-	//decode the channel message
+	// decode the channel message
 	chMgs := &ChannelMessage{}
 	err = proto.Unmarshal(mbc.payload, chMgs)
 	if err != nil {
@@ -332,6 +337,7 @@ func TestSendMessage(t *testing.T) {
 			byChannel: make(map[id.ID]string),
 			kv:        nil,
 		},
+		rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 		st: loadSendTracker(&mockBroadcastClient{},
 			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
 				umi *userMessageInternal, ts time.Time,
@@ -370,9 +376,9 @@ func TestSendMessage(t *testing.T) {
 	}
 	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
 
-	//verify the message was handled correctly
+	// verify the message was handled correctly
 
-	//decode the user message
+	// decode the user message
 	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
 	if err != nil {
 		t.Fatalf("Failed to decode the user message: %s", err)
@@ -394,7 +400,7 @@ func TestSendMessage(t *testing.T) {
 			umi.GetChannelMessage().RoundID, returnedRound)
 	}
 
-	//decode the text message
+	// decode the text message
 	txt := &CMIXChannelText{}
 	err = proto.Unmarshal(umi.GetChannelMessage().Payload, txt)
 	if err != nil {
@@ -426,6 +432,7 @@ func TestSendReply(t *testing.T) {
 			byChannel: make(map[id.ID]string),
 			kv:        nil,
 		},
+		rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 		st: loadSendTracker(&mockBroadcastClient{},
 			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
 				umi *userMessageInternal, ts time.Time,
@@ -464,9 +471,9 @@ func TestSendReply(t *testing.T) {
 	}
 	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
 
-	//verify the message was handled correctly
+	// verify the message was handled correctly
 
-	//decode the user message
+	// decode the user message
 	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
 	if err != nil {
 		t.Fatalf("Failed to decode the user message: %s", err)
@@ -488,7 +495,7 @@ func TestSendReply(t *testing.T) {
 			umi.GetChannelMessage().RoundID, returnedRound)
 	}
 
-	//decode the text message
+	// decode the text message
 	txt := &CMIXChannelText{}
 	err = proto.Unmarshal(umi.GetChannelMessage().Payload, txt)
 	if err != nil {
@@ -519,6 +526,7 @@ func TestSendReaction(t *testing.T) {
 			byChannel: make(map[id.ID]string),
 			kv:        nil,
 		},
+		rng:      fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 		channels: make(map[id.ID]*joinedChannel),
 		st: loadSendTracker(&mockBroadcastClient{},
 			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
@@ -557,9 +565,9 @@ func TestSendReaction(t *testing.T) {
 	}
 	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
 
-	//verify the message was handled correctly
+	// verify the message was handled correctly
 
-	//decode the user message
+	// decode the user message
 	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
 	if err != nil {
 		t.Fatalf("Failed to decode the user message: %s", err)
@@ -581,7 +589,7 @@ func TestSendReaction(t *testing.T) {
 			umi.GetChannelMessage().RoundID, returnedRound)
 	}
 
-	//decode the text message
+	// decode the text message
 	txt := &CMIXChannelReaction{}
 	err = proto.Unmarshal(umi.GetChannelMessage().Payload, txt)
 	if err != nil {