diff --git a/bindings/channels.go b/bindings/channels.go
index e3be5d13351ea0eedbf654366f36f020646a392d..ead4eceb123b829fe8c45f4eb384ad0bc2441fd4 100644
--- a/bindings/channels.go
+++ b/bindings/channels.go
@@ -331,6 +331,15 @@ func LoadChannelsManager(cmixID int, storageTag string,
 	return channelManagerTrackerSingleton.make(m), nil
 }
 
+// ChannelGeneration contains information about a newly generated channel. It
+// contains the public channel info formatted in pretty print and the private
+// key for the channel in PEM format.
+//
+// Example JSON:
+//  {
+//    "Channel": "\u003cSpeakeasy-v1:My_Channel,description:Here is information about my channel.,level:Public,secrets:8AS3SczFvAYZftWuj4ZkOM9muFPIwq/0HuVCUJgTK8w=,GpPl1510/G07J4RfdYX9J5plTX3WNLVm+uuGmCwgFeU=,5,1,mRfdUGM6WxWjjCuLzO+2+zc3BQh2zMT2CHD8ZnBwpVI=\u003e",
+//    "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMDECAQACBgDMIU9LpQIDAQABAgYAvCd9ewECAw0tzQIDD305AgMFu4UCAwd+kQID\nAQxc\n-----END RSA PRIVATE KEY-----"
+//  }
 type ChannelGeneration struct {
 	Channel    string
 	PrivateKey string
@@ -341,24 +350,35 @@ type ChannelGeneration struct {
 //
 // It returns a pretty print of the channel and the private key.
 //
-// The name cannot be longer that __ characters. The description cannot be
-// longer than __ and can only use ______ characters.
-//
 // Parameters:
 //  - cmixID - The tracked cmix object ID. This can be retrieved using
 //    [Cmix.GetID].
-//  - name - The name of the new channel. The name cannot be longer than __
-//    characters and must contain only _____ characters. It cannot be changed
+//  - name - The name of the new channel. The name must be between 3 and 24
+//    characters inclusive. It can only include upper and lowercase unicode
+//    letters, digits 0 through 9, and underscores (_). It cannot be changed
 //    once a channel is created.
-//  - description - The description of a channel. The description cannot be
-//    longer than __ characters and must contain only _____ characters. It
-//    cannot be changed once a channel is created.
+//  - description - The description of a channel. The description is optional
+//    but cannot be longer than 144 characters and can include all unicode
+//    characters. It cannot be changed once a channel is created.
+//  - privacyLevel - The broadcast.PrivacyLevel of the channel. 0 = public,
+//    1 = private, and 2 = secret. Refer to the comment below for more
+//    information.
 //
 // Returns:
-//  - []byte - ChannelGeneration describes a generated channel. It contains both
-//    the public channel info and the private key for the channel in PEM format.
-//    fixme: document json
-func GenerateChannel(cmixID int, name, description string) ([]byte, error) {
+//  - []byte - [ChannelGeneration] describes a generated channel. It contains
+//    both the public channel info and the private key for the channel in PEM
+//    format.
+//
+// The [broadcast.PrivacyLevel] of a channel indicates the level of channel
+// information revealed when sharing it via URL. For any channel besides public
+// channels, the secret information is encrypted and a password is required to
+// share and join a channel.
+//  - A privacy level of [broadcast.Public] reveals all the information
+//    including the name, description, privacy level, public key and salt.
+//  - A privacy level of [broadcast.Private] reveals only the name and
+//    description.
+//  - A privacy level of [broadcast.Secret] reveals nothing.
+func GenerateChannel(cmixID int, name, description string, privacyLevel int) ([]byte, error) {
 	// Get cmix from singleton so its rng can be used
 	cmix, err := cmixTrackerSingleton.get(cmixID)
 	if err != nil {
@@ -367,8 +387,9 @@ func GenerateChannel(cmixID int, name, description string) ([]byte, error) {
 
 	stream := cmix.api.GetRng().GetStream()
 	defer stream.Close()
-	c, pk, err := cryptoBroadcast.NewChannel(
-		name, description, cmix.api.GetCmix().GetMaxMessageLength(), stream)
+	level := cryptoBroadcast.PrivacyLevel(privacyLevel)
+	c, pk, err := cryptoBroadcast.NewChannel(name, description, level,
+		cmix.api.GetCmix().GetMaxMessageLength(), stream)
 	if err != nil {
 		return nil, err
 	}
@@ -415,6 +436,14 @@ func makeChannelPrivateKeyStoreKey(channelID *id.ID) string {
 	return channelPrivateKeyStoreKey + "/" + channelID.String()
 }
 
+// ChannelInfo contains information about a channel.
+//
+// Example of ChannelInfo JSON:
+//  {
+//    "Name": "Test Channel",
+//    "Description": "This is a test channel",
+//    "ChannelID": "RRnpRhmvXtW9ugS1nILJ3WfttdctDvC2jeuH43E0g/0D",
+//  }
 type ChannelInfo struct {
 	Name        string
 	Description string
@@ -427,11 +456,10 @@ type ChannelInfo struct {
 //  - prettyPrint - The pretty print of the channel.
 //
 // The pretty print will be of the format:
-//  <XXChannel-v1:Test Channel,description:This is a test channel,secrets:pn0kIs6P1pHvAe7u8kUyf33GYVKmkoCX9LhCtvKJZQI=,3A5eB5pzSHyxN09w1kOVrTIEr5UyBbzmmd9Ga5Dx0XA=,0,0,/zChIlLr2p3Vsm2X4+3TiFapoapaTi8EJIisJSqwfGc=>
+//  <Speakeasy-v1:Test Channel,description:This is a test channel,secrets:YxHhRAKy2D4XU2oW5xnW/3yaqOeh8nO+ZSd3nUmiQ3c=,6pXN2H9FXcOj7pjJIZoq6nMi4tGX2s53fWH5ze2dU1g=,493,1,MVjkHlm0JuPxQNAn6WHsPdOw9M/BUF39p7XB/QEkQyc=>
 //
 // Returns:
-//  - []byte - ChannelInfo describes all relevant channel info.
-//    fixme: document json
+//  - []byte - JSON of [ChannelInfo], which describes all relevant channel info.
 func GetChannelInfo(prettyPrint string) ([]byte, error) {
 	_, bytes, err := getChannelInfo(prettyPrint)
 	return bytes, err
@@ -462,11 +490,10 @@ func getChannelInfo(prettyPrint string) (*cryptoBroadcast.Channel, []byte, error
 //    another user or generated via GenerateChannel.
 //
 // The pretty print will be of the format:
-//  <XXChannel-v1:Test Channel,description:This is a test channel,secrets:pn0kIs6P1pHvAe7u8kUyf33GYVKmkoCX9LhCtvKJZQI=,3A5eB5pzSHyxN09w1kOVrTIEr5UyBbzmmd9Ga5Dx0XA=,0,0,/zChIlLr2p3Vsm2X4+3TiFapoapaTi8EJIisJSqwfGc=>"
+//  <Speakeasy-v1:Test Channel,description:This is a test channel,secrets:YxHhRAKy2D4XU2oW5xnW/3yaqOeh8nO+ZSd3nUmiQ3c=,6pXN2H9FXcOj7pjJIZoq6nMi4tGX2s53fWH5ze2dU1g=,493,1,MVjkHlm0JuPxQNAn6WHsPdOw9M/BUF39p7XB/QEkQyc=>
 //
 // Returns:
-//  - []byte - ChannelInfo describes all relevant channel info.
-//    fixme: document json
+//  - []byte - JSON of [ChannelInfo], which describes all relevant channel info.
 func (cm *ChannelsManager) JoinChannel(channelPretty string) ([]byte, error) {
 	c, info, err := getChannelInfo(channelPretty)
 	if err != nil {
@@ -479,6 +506,40 @@ func (cm *ChannelsManager) JoinChannel(channelPretty string) ([]byte, error) {
 	return info, err
 }
 
+// JoinChannelFromURL joins the given channel from a URL. It will fail if the
+// channel has already been joined. A password is required unless it is of the
+// privacy level [broadcast.Public], in which case it can be left empty. To get
+// the privacy level of a channel URL, use [GetShareUrlType].
+//
+// Parameters:
+//  - url - The channel's share URL. Should be received from another user or
+//    generated via [GetShareURL].
+//  - password - The password needed to decrypt the secret data in the URL. Only
+//    required for private or secret channels.
+//
+// Returns:
+//  - []byte - [ChannelInfo] describes all relevant channel info.
+func (cm *ChannelsManager) JoinChannelFromURL(url, password string) ([]byte, error) {
+	c, err := cryptoBroadcast.DecodeShareURL(url, password)
+	if err != nil {
+		return nil, err
+	}
+
+	info, err := json.Marshal(&ChannelInfo{
+		Name:        c.Name,
+		Description: c.Description,
+		ChannelID:   c.ReceptionID.String(),
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	// Join the channel using the API
+	err = cm.api.JoinChannel(c)
+
+	return info, err
+}
+
 // GetChannels returns the IDs of all channels that have been joined.
 //
 // Returns:
@@ -527,6 +588,116 @@ func (cm *ChannelsManager) ReplayChannel(marshalledChanId []byte) error {
 	return cm.api.ReplayChannel(chanId)
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// Channel Share URL                                                          //
+////////////////////////////////////////////////////////////////////////////////
+
+// ShareURL is returned from ChannelsManager.GetShareURL. It includes the
+// channel's share URL and password, if it needs one.
+//
+// JSON example for a public channel:
+//  {
+//    "url": "https://internet.speakeasy.tech/?0Name=My_Channel&Description=Here+is+information+about+my+channel.&2Level=Public&e=3CCvzK8diF%2B6vUZetyZkcyemoiI8uFLGSh%2B%2F9%2Bh5YQE%3D&k=zBakjn1Snay7AMr2CZ%2BCoWCHbe9TrtQqAVftIDi9Fjs%3D&l=5&m=0&p=1&s=Seyvx%2F5%2FOVTj5LClUG42AuLamDnqrbtMOoLymyIpFqY%3D&v=0",
+//    "password": ""
+//  }
+//
+// JSON example for a private channel:
+//  {
+//    "url": "https://internet.speakeasy.tech/?0Name=My_Channel&1Description=Here+is+information+about+my+channel.&d=i%2FwBAK6i89YT3LjPYb5%2BMmog5Gjk2unYzYt25y%2BmZH3%2Bo08oUIHHEoC7JYjk50Q2%2BMcSj6fQh%2BW3LBvWv02f1g60PLXZ1H8OS2rqoxBhwHvTpNgXRdUIErbk6q3ljIdjtSqJtWIzAx5no%2F96jaIBsob0U9jDE1jgsU8XNGxDz3TeKcdTOFiUpnh4R%2BALcys%3D&m=1&v=0",
+//    "password": "easter boaster musket catalyze unproven vendetta plated grinning"
+//  }
+//
+// JSON example for a secret channel:
+//  {
+//    "url": "https://internet.speakeasy.tech/?d=xRORDN8lt%2BI2SAn%2F21ZpOzj50J3HOV1GkMsPkhtgoYyQUqpPBZhhKpewzuDI%2B3wTQlpANLDMtFVL4J7y2lBpvIz9LQ5%2F6CoRdVkoXbG7uRqv6wscYdwWPYZBARC2cJSyeVad6RbxnoZ65Z0dtEVEff328ri3ZpaMBlP%2BpUH928pcVHibALW7Bw04Rkmh%2FWx6wJGw%2FU0gTHo02UlYFHh4G9CC%2BIU1x13BmEuW6Hyk6Ty9BlHt29QbsQ7uU30RwzQOyg8%3D&m=2&v=0",
+//    "password": "florist angled valid snarl discharge endearing harbor hazy"
+//  }
+type ShareURL struct {
+	URL      string `json:"url"`
+	Password string `json:"password"`
+}
+
+// GetShareURL generates a URL that can be used to share this channel with
+// others on the given host.
+//
+// A URL comes in one of three forms based on the privacy level set when
+// generating the channel. Each privacy level hides more information than the
+// last with the lowest level revealing everything and the highest level
+// revealing nothing. For any level above the lowest, a password is returned,
+// which will be required when decoding the URL.
+//
+// The maxUses is the maximum number of times this URL can be used to join a
+// channel. If it is set to 0, then it can be shared unlimited times. The max
+// uses is set as a URL parameter using the key [broadcast.MaxUsesKey]. Note
+// that this number is also encoded in the secret data for private and secret
+// URLs, so if the number is changed in the URL, is will be verified when
+// calling [ChannelsManager.JoinChannelFromURL]. There is no enforcement for
+// public URLs.
+//
+// Parameters:
+//  - cmixID - The tracked Cmix object ID.
+//  - host - The URL to append the channel info to.
+//  - maxUses - The maximum number of uses the link can be used (0 for
+//    unlimited).
+//  - marshalledChanId - A marshalled channel ID ([id.ID]).
+//
+// Returns:
+//  - JSON of ShareURL.
+func (cm *ChannelsManager) GetShareURL(cmixID int, host string, maxUses int,
+	marshalledChanId []byte) ([]byte, error) {
+
+	// Unmarshal channel ID
+	chanId, err := id.Unmarshal(marshalledChanId)
+	if err != nil {
+		return nil, err
+	}
+
+	// Get the channel from the ID
+	ch, err := cm.api.GetChannel(chanId)
+	if err != nil {
+		return nil, err
+	}
+
+	// Get user from singleton
+	user, err := cmixTrackerSingleton.get(cmixID)
+	if err != nil {
+		return nil, err
+	}
+
+	// Generate share URL and password
+	rng := user.api.GetRng().GetStream()
+	url, password, err := ch.ShareURL(host, maxUses, rng)
+	rng.Close()
+	if err != nil {
+		return nil, err
+	}
+
+	su := ShareURL{
+		URL:      url,
+		Password: password,
+	}
+
+	return json.Marshal(su)
+}
+
+// GetShareUrlType determines the [broadcast.PrivacyLevel] of the channel URL.
+// If the URL is an invalid channel URL, an error is returned.
+//
+// Parameters:
+//  - url - The channel share URL.
+//
+// Returns:
+//  - An int that corresponds to the [broadcast.PrivacyLevel] as outlined below.
+//
+// Possible returns:
+//  0 = public channel
+//  1 = private channel
+//  2 = secret channel
+func GetShareUrlType(url string) (int, error) {
+	level, err := cryptoBroadcast.GetShareUrlType(url)
+	return int(level), err
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Channel Sending Methods & Reports                                          //
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/broadcast/rsaToPublic_test.go b/broadcast/rsaToPublic_test.go
index 159f9d1016ead09866c8db1bd3f15faedfc94404..9be17453b96db68ca8a735fdcd9234ccd7ad2e3e 100644
--- a/broadcast/rsaToPublic_test.go
+++ b/broadcast/rsaToPublic_test.go
@@ -59,7 +59,7 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 	packetPayloadLength := newMockCmix(cMixHandler).GetMaxMessageLength()
 
 	channel, pk, _ := crypto.NewChannel(
-		cName, cDesc, packetPayloadLength, rngGen.GetStream())
+		cName, cDesc, crypto.Public, packetPayloadLength, rngGen.GetStream())
 	cid := channel.ReceptionID
 
 	// Must mutate cMixHandler such that it's processorMap contains a
diff --git a/channels/joinedChannel_test.go b/channels/joinedChannel_test.go
index e5a0899c6d6d204ede3b7999842ee64549bacc77..ca0ba9ba8319bb246c05f33e816bfbbb9f8b8b39 100644
--- a/channels/joinedChannel_test.go
+++ b/channels/joinedChannel_test.go
@@ -52,8 +52,9 @@ func Test_manager_store(t *testing.T) {
 	m := mFace.(*manager)
 
 	for i := 0; i < 10; i++ {
-		ch, _, err := newTestChannel("name_"+strconv.Itoa(i),
-			"description_"+strconv.Itoa(i), m.rng.GetStream())
+		ch, _, err := newTestChannel(
+			"name_"+strconv.Itoa(i), "description_"+strconv.Itoa(i),
+			m.rng.GetStream(), cryptoBroadcast.Public)
 		if err != nil {
 			t.Errorf("Failed to create new channel %d: %+v", i, err)
 		}
@@ -100,8 +101,8 @@ func Test_manager_loadChannels(t *testing.T) {
 	expected := make([]*joinedChannel, 10)
 
 	for i := range expected {
-		ch, _, err := newTestChannel("name_"+strconv.Itoa(i),
-			"description_"+strconv.Itoa(i), m.rng.GetStream())
+		ch, _, err := newTestChannel(
+			"name_"+strconv.Itoa(i), "description_"+strconv.Itoa(i), m.rng.GetStream(), cryptoBroadcast.Public)
 		if err != nil {
 			t.Errorf("Failed to create new channel %d: %+v", i, err)
 		}
@@ -169,7 +170,8 @@ func Test_manager_addChannel(t *testing.T) {
 
 	m := mFace.(*manager)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -214,7 +216,8 @@ func Test_manager_addChannel_ChannelAlreadyExistsErr(t *testing.T) {
 
 	m := mFace.(*manager)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -250,7 +253,8 @@ func Test_manager_removeChannel(t *testing.T) {
 
 	m := mFace.(*manager)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -295,7 +299,8 @@ func Test_manager_removeChannel_ChannelDoesNotExistsErr(t *testing.T) {
 
 	m := mFace.(*manager)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -327,7 +332,8 @@ func Test_manager_getChannel(t *testing.T) {
 
 	m := mFace.(*manager)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -368,7 +374,8 @@ func Test_manager_getChannel_ChannelDoesNotExistsErr(t *testing.T) {
 
 	m := mFace.(*manager)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -404,8 +411,8 @@ func Test_manager_getChannels(t *testing.T) {
 	expected := make([]*id.ID, 10)
 
 	for i := range expected {
-		ch, _, err := newTestChannel("name_"+strconv.Itoa(i),
-			"description_"+strconv.Itoa(i), m.rng.GetStream())
+		ch, _, err := newTestChannel(
+			"name_"+strconv.Itoa(i), "description_"+strconv.Itoa(i), m.rng.GetStream(), cryptoBroadcast.Public)
 		if err != nil {
 			t.Errorf("Failed to create new channel %d: %+v", i, err)
 		}
@@ -437,7 +444,8 @@ func Test_manager_getChannels(t *testing.T) {
 func Test_joinedChannel_Store(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	rng := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG)
-	ch, _, err := newTestChannel("name", "description", rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -480,7 +488,8 @@ func Test_loadJoinedChannel(t *testing.T) {
 
 	m := mFace.(*manager)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -509,7 +518,8 @@ func Test_loadJoinedChannel(t *testing.T) {
 func Test_joinedChannel_delete(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	rng := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG)
-	ch, _, err := newTestChannel("name", "description", rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", rng.GetStream(), cryptoBroadcast.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -566,9 +576,11 @@ func Test_makeJoinedChannelKey_Consistency(t *testing.T) {
 // newTestChannel creates a new cryptoBroadcast.Channel in the same way that
 // cryptoBroadcast.NewChannel does but with a smaller RSA key and salt to make
 // tests run quicker.
-func newTestChannel(name, description string, rng csprng.Source) (
+func newTestChannel(name, description string, rng csprng.Source,
+	level cryptoBroadcast.PrivacyLevel) (
 	*cryptoBroadcast.Channel, rsa.PrivateKey, error) {
-	c, pk, err := cryptoBroadcast.NewChannelVariableKeyUnsafe(name, description, 1000, 512, rng)
+	c, pk, err := cryptoBroadcast.NewChannelVariableKeyUnsafe(
+		name, description, level, 1000, 512, rng)
 	return c, pk, err
 }
 
diff --git a/channels/manager_test.go b/channels/manager_test.go
index 6f07e2013d222e10d8c93bce7beeabbfd59ef8b1..e4213bd7c369143fec41c60895150bf79e0ea3a6 100644
--- a/channels/manager_test.go
+++ b/channels/manager_test.go
@@ -11,6 +11,7 @@ import (
 	"fmt"
 	"gitlab.com/elixxir/client/broadcast"
 	"gitlab.com/elixxir/client/storage/versioned"
+	broadcast2 "gitlab.com/elixxir/crypto/broadcast"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/ekv"
@@ -51,7 +52,8 @@ func TestManager_JoinChannel(t *testing.T) {
 	m := mFace.(*manager)
 	mem := m.events.model.(*mockEventModel)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), broadcast2.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -94,7 +96,8 @@ func TestManager_LeaveChannel(t *testing.T) {
 	m := mFace.(*manager)
 	mem := m.events.model.(*mockEventModel)
 
-	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	ch, _, err := newTestChannel(
+		"name", "description", m.rng.GetStream(), broadcast2.Public)
 	if err != nil {
 		t.Errorf("Failed to create new channel: %+v", err)
 	}
@@ -135,9 +138,9 @@ func TestManager_GetChannels(t *testing.T) {
 	chList := make(map[id.ID]interface{})
 
 	for i := 0; i < 10; i++ {
-		name := fmt.Sprintf("testChannel %d", numtests)
+		name := fmt.Sprintf("testChannel_%d", numtests)
 		s := rng.GetStream()
-		tc, _, err := newTestChannel(name, "blarg", s)
+		tc, _, err := newTestChannel(name, "blarg", s, broadcast2.Public)
 		s.Close()
 		if err != nil {
 			t.Fatalf("failed to generate channel %s", name)
@@ -172,9 +175,9 @@ func TestManager_GetChannel(t *testing.T) {
 	chList := make([]*id.ID, 0, numtests)
 
 	for i := 0; i < 10; i++ {
-		name := fmt.Sprintf("testChannel %d", numtests)
+		name := fmt.Sprintf("testChannel_%d", numtests)
 		s := rng.GetStream()
-		tc, _, err := newTestChannel(name, "blarg", s)
+		tc, _, err := newTestChannel(name, "blarg", s, broadcast2.Public)
 		s.Close()
 		if err != nil {
 			t.Fatalf("failed to generate channel %s", name)
diff --git a/channels/send_test.go b/channels/send_test.go
index c3c8114c85d69193216c04bf903991f69129917e..6886519a42dbd95431dcb927ada369c46bb7c94a 100644
--- a/channels/send_test.go
+++ b/channels/send_test.go
@@ -272,8 +272,8 @@ func TestAdminGeneric(t *testing.T) {
 	validUntil := time.Hour
 
 	rng := &csprng.SystemRNG{}
-	ch, priv, err := cryptoBroadcast.NewChannel("test", "test",
-		1000, rng)
+	ch, priv, err := cryptoBroadcast.NewChannel(
+		"test", "test", cryptoBroadcast.Public, 1000, rng)
 	if err != nil {
 		t.Fatalf("Failed to generate channel: %+v", err)
 	}
diff --git a/cmd/broadcast.go b/cmd/broadcast.go
index 7b0e7c9183ae1311bf7f2478640309723ca824e4..df52c82f13ae29ae780670a9a502d68be86e2142 100644
--- a/cmd/broadcast.go
+++ b/cmd/broadcast.go
@@ -81,7 +81,8 @@ var broadcastCmd = &cobra.Command{
 
 			if viper.GetBool(broadcastNewFlag) {
 				// Create a new broadcast channel
-				channel, pk, err = crypto.NewChannel(name, desc, user.GetCmix().GetMaxMessageLength(), user.GetRng().GetStream())
+				channel, pk, err = crypto.NewChannel(name, desc, crypto.Public,
+					user.GetCmix().GetMaxMessageLength(), user.GetRng().GetStream())
 				if err != nil {
 					jww.FATAL.Panicf("Failed to create new channel: %+v", err)
 				}
diff --git a/cmd/version.go b/cmd/version.go
index 328c9cb0e5bd41b410b01bf498bf0f59997e041c..fcfa3b927bbe2f5669ee881fce0dfd30beb3d20a 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -18,7 +18,7 @@ import (
 )
 
 // Change this value to set the version for this build
-const currentVersion = "4.2.0"
+const currentVersion = "4.3.0"
 
 func Version() string {
 	out := fmt.Sprintf("Elixxir Client v%s -- %s\n\n", xxdk.SEMVER,
diff --git a/go.mod b/go.mod
index cf73253e0921d1501752e9ce93529b4d314d1710..8a645be7f7d412bdcc4def2953582206d040ada5 100644
--- a/go.mod
+++ b/go.mod
@@ -14,13 +14,13 @@ require (
 	github.com/spf13/viper v1.12.0
 	github.com/stretchr/testify v1.8.0
 	gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f
-	gitlab.com/elixxir/comms v0.0.4-0.20221011183106-8c4450ba3cfb
-	gitlab.com/elixxir/crypto v0.0.7-0.20221015023742-e1108df47b6b
+	gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa
+	gitlab.com/elixxir/crypto v0.0.7-0.20221017173452-565da4101a3b
 	gitlab.com/elixxir/ekv v0.2.1
-	gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6
-	gitlab.com/xx_network/comms v0.0.4-0.20221005205845-b34d538ffd85
-	gitlab.com/xx_network/crypto v0.0.5-0.20220913213008-98764f5b3287
-	gitlab.com/xx_network/primitives v0.0.4-0.20221010192422-3479f09b7769
+	gitlab.com/elixxir/primitives v0.0.3-0.20221017172918-6176818d1aba
+	gitlab.com/xx_network/comms v0.0.4-0.20221017172508-09e33697dc15
+	gitlab.com/xx_network/crypto v0.0.5-0.20221017172404-b384a8d8b171
+	gitlab.com/xx_network/primitives v0.0.4-0.20221017171439-42169a3e5c0d
 	go.uber.org/ratelimit v0.2.0
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
 	golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c
@@ -50,6 +50,7 @@ require (
 	github.com/pelletier/go-toml/v2 v2.0.2 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/rs/cors v1.8.2 // indirect
+	github.com/sethvargo/go-diceware v0.3.0 // indirect
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
 	github.com/soheilhy/cmux v0.1.5 // indirect
 	github.com/spf13/afero v1.9.2 // indirect
diff --git a/go.sum b/go.sum
index a7a1300530c0d37858b4f22a65cc05b9ac20ef22..228e659a3bfdcb6c35fb46fb872f8bc87b73460c 100644
--- a/go.sum
+++ b/go.sum
@@ -547,6 +547,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
 github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sethvargo/go-diceware v0.3.0 h1:UVVEfmN/uF50JfWAN7nbY6CiAlp5xeSx+5U0lWKkMCQ=
+github.com/sethvargo/go-diceware v0.3.0/go.mod h1:lH5Q/oSPMivseNdhMERAC7Ti5oOPqsaVddU1BcN1CY0=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -629,39 +631,32 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
 github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f h1:yXGvNBqzZwAhDYlSnxPRbgor6JWoOt1Z7s3z1O9JR40=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k=
-gitlab.com/elixxir/comms v0.0.4-0.20221011183106-8c4450ba3cfb h1:aw7Ao1oqho+97gO35HkzBmv2e25qluRXEiNXw/oD8MM=
-gitlab.com/elixxir/comms v0.0.4-0.20221011183106-8c4450ba3cfb/go.mod h1:oRteMH+R5t1j/FZ+KJJnZUcqJO2sLXnWksN5HPkZUIo=
+gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa h1:/FEpu0N0rAyq74FkvO3uY8BcQoWLSbVPhj/s5QfscZw=
+gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa/go.mod h1:rW7xdbHntP2MoF3q+2+f+IR8OHol94MRyviotfR5rXg=
 gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c=
 gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA=
-gitlab.com/elixxir/crypto v0.0.7-0.20220913220142-ab0771bad0af/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
-gitlab.com/elixxir/crypto v0.0.7-0.20221014161526-ce04e14b9f80 h1:M9imzr2ZrD0GXsR+nfrzLnJ8Y9axj2Pvq8CTDE+IQb4=
-gitlab.com/elixxir/crypto v0.0.7-0.20221014161526-ce04e14b9f80/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
-gitlab.com/elixxir/crypto v0.0.7-0.20221015023742-e1108df47b6b h1:gWB95fteva1kMYR/qzdkxMMAs771wIvYd97D9nPy/xI=
-gitlab.com/elixxir/crypto v0.0.7-0.20221015023742-e1108df47b6b/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
+gitlab.com/elixxir/crypto v0.0.7-0.20221017173452-565da4101a3b h1:5VBuenFNKOq0omDYmUet3Deu3pAkzNIkveQBtNO/o0k=
+gitlab.com/elixxir/crypto v0.0.7-0.20221017173452-565da4101a3b/go.mod h1:1rftbwSVdy49LkBIkPr+w+P2mDOerYeBKoZuB3r0yqI=
 gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is=
 gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU=
 gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg=
 gitlab.com/elixxir/primitives v0.0.0-20200804170709-a1896d262cd9/go.mod h1:p0VelQda72OzoUckr1O+vPW0AiFe0nyKQ6gYcmFSuF8=
 gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc=
 gitlab.com/elixxir/primitives v0.0.1/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
-gitlab.com/elixxir/primitives v0.0.3-0.20220606195757-40f7a589347f/go.mod h1:9Bb2+u+CDSwsEU5Droo6saDAXuBDvLRjexpBhPAYxhA=
-gitlab.com/elixxir/primitives v0.0.3-0.20220810173935-592f34a88326/go.mod h1:9Bb2+u+CDSwsEU5Droo6saDAXuBDvLRjexpBhPAYxhA=
-gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6 h1:/cxxZBP5jTPDpC3zgOx9vV1ojmJyG8pYtkl3IbcewNQ=
-gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6/go.mod h1:9Bb2+u+CDSwsEU5Droo6saDAXuBDvLRjexpBhPAYxhA=
+gitlab.com/elixxir/primitives v0.0.3-0.20221017172918-6176818d1aba h1:skhrlmHdEQfuT/4Ip2IVcI4ToNzPlmAxTYlTk034Il0=
+gitlab.com/elixxir/primitives v0.0.3-0.20221017172918-6176818d1aba/go.mod h1:Rqbl8ToZxPn86RyqrpjIE9FJbFHoJgQfg68iSOTPcz8=
 gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
-gitlab.com/xx_network/comms v0.0.4-0.20221005205845-b34d538ffd85 h1:bX2IYFnEbWTNGhZHfzHME19pkfD4Q7oTxFGI70PM2PM=
-gitlab.com/xx_network/comms v0.0.4-0.20221005205845-b34d538ffd85/go.mod h1:E2QKOKyPKLRjLUwMxgZpTKueEsHDEqshfqOHJ54ttxU=
+gitlab.com/xx_network/comms v0.0.4-0.20221017172508-09e33697dc15 h1:H2OptkCpcGAgplz5PYMqUiA4aH/LUcjc9nLbGM+vUus=
+gitlab.com/xx_network/comms v0.0.4-0.20221017172508-09e33697dc15/go.mod h1:yBDaXAWiPGGv2zXQgP35Ks/ek800Uaah4roVFyvMkWU=
 gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE=
 gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk=
-gitlab.com/xx_network/crypto v0.0.5-0.20220913213008-98764f5b3287 h1:Jd71F8f/8rieWybMqkxpKKZVVyGkeCNZWZcviGGnQ9A=
-gitlab.com/xx_network/crypto v0.0.5-0.20220913213008-98764f5b3287/go.mod h1:/SJf+R75E+QepdTLh0H1/udsovxx2Q5ru34q1v0umKk=
+gitlab.com/xx_network/crypto v0.0.5-0.20221017172404-b384a8d8b171 h1:zGrUU8U6pMl5J4yzKzJ3QOAoo6g0Nna7Z+vVxxijpLg=
+gitlab.com/xx_network/crypto v0.0.5-0.20221017172404-b384a8d8b171/go.mod h1:sZ5bMKbb6v+Qx3zwXsWsbhVikOte/1ibflLpbCVuboQ=
 gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA=
 gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug=
 gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc=
-gitlab.com/xx_network/primitives v0.0.4-0.20220222211843-901fa4a2d72b/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE=
-gitlab.com/xx_network/primitives v0.0.4-0.20220809193445-9fc0a5209548/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
-gitlab.com/xx_network/primitives v0.0.4-0.20221010192422-3479f09b7769 h1:BBYSog3VSKudey4rhWnCw54PcGcD4YRjTrnwzOhJ/GE=
-gitlab.com/xx_network/primitives v0.0.4-0.20221010192422-3479f09b7769/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
+gitlab.com/xx_network/primitives v0.0.4-0.20221017171439-42169a3e5c0d h1:rOcGGx5SrhBkbD1P8JqbtqBBeuGhOSZxETytNGJcf/U=
+gitlab.com/xx_network/primitives v0.0.4-0.20221017171439-42169a3e5c0d/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
 gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93 h1:eJZrXqHsMmmejEPWw8gNAt0I8CGAMNO/7C339Zco3TM=
 gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
diff --git a/xxdk/version_vars.go b/xxdk/version_vars.go
index 61bd87da81f93ce196ac84a628a11107357ecb24..76a41f587dcf4dfd5fa2e3ba8b7ebea7510c4d58 100644
--- a/xxdk/version_vars.go
+++ b/xxdk/version_vars.go
@@ -1,11 +1,11 @@
 // Code generated by go generate; DO NOT EDIT.
 // This file was generated by robots at
-// 2022-09-15 10:52:12.1953796 -0700 PDT m=+0.451573601
+// 2022-10-17 12:52:49.822998 -0500 CDT m=+0.037589931
 
 package xxdk
 
-const GITVERSION = `55b66f6b Update proto files`
-const SEMVER = "4.2.0"
+const GITVERSION = `a401d138 update deps`
+const SEMVER = "4.3.0"
 const DEPENDENCIES = `module gitlab.com/elixxir/client
 
 go 1.17
@@ -20,35 +20,47 @@ require (
 	github.com/spf13/cobra v1.5.0
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/viper v1.12.0
+	github.com/stretchr/testify v1.8.0
 	gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f
-	gitlab.com/elixxir/comms v0.0.4-0.20220914220142-601071b77d78
-	gitlab.com/elixxir/crypto v0.0.7-0.20220901215826-1ceaeb59081f
+	gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa
+	gitlab.com/elixxir/crypto v0.0.7-0.20221017173452-565da4101a3b
 	gitlab.com/elixxir/ekv v0.2.1
-	gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6
-	gitlab.com/xx_network/comms v0.0.4-0.20220914220351-2e461edbfe48
-	gitlab.com/xx_network/crypto v0.0.5-0.20220902182733-69aad094b487
-	gitlab.com/xx_network/primitives v0.0.4-0.20220902183448-319596e2fec8
+	gitlab.com/elixxir/primitives v0.0.3-0.20221017172918-6176818d1aba
+	gitlab.com/xx_network/comms v0.0.4-0.20221017172508-09e33697dc15
+	gitlab.com/xx_network/crypto v0.0.5-0.20221017172404-b384a8d8b171
+	gitlab.com/xx_network/primitives v0.0.4-0.20221017171439-42169a3e5c0d
 	go.uber.org/ratelimit v0.2.0
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
-	golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b
-	google.golang.org/grpc v1.48.0
+	golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c
+	google.golang.org/grpc v1.49.0
 	google.golang.org/protobuf v1.28.1
 )
 
 require (
+	git.xx.network/elixxir/grpc-web-go-client v0.0.0-20220908170150-ef04339ffe65 // indirect
 	github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
 	github.com/badoux/checkmail v1.2.1 // indirect
+	github.com/cenkalti/backoff/v4 v4.1.3 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
 	github.com/elliotchance/orderedmap v1.4.0 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
+	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/improbable-eng/grpc-web v0.15.0 // indirect
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
+	github.com/klauspost/compress v1.11.7 // indirect
 	github.com/klauspost/cpuid/v2 v2.1.0 // indirect
 	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	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/pmezard/go-difflib v1.0.0 // indirect
+	github.com/rs/cors v1.8.2 // indirect
+	github.com/sethvargo/go-diceware v0.3.0 // indirect
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
+	github.com/soheilhy/cmux v0.1.5 // indirect
 	github.com/spf13/afero v1.9.2 // indirect
 	github.com/spf13/cast v1.5.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
@@ -58,11 +70,13 @@ require (
 	github.com/tyler-smith/go-bip39 v1.1.0 // indirect
 	github.com/zeebo/blake3 v0.2.3 // indirect
 	gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93 // indirect
+	go.uber.org/atomic v1.10.0 // indirect
 	golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect
 	golang.org/x/text v0.3.7 // indirect
-	google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 // indirect
+	google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	nhooyr.io/websocket v1.8.7 // indirect
 )
 `