pub struct EncryptedGroupInfoBlobV1 {
pub nonce: Vec<u8>,
pub ciphertext: Vec<u8>,
pub epoch: u64,
pub group_state_hash: Vec<u8>,
pub expires_at_ns: u64,
}Expand description
v1 shape of the encrypted-GroupInfo envelope.
epoch and group_state_hash are plaintext metadata serving two
distinct purposes:
-
epochprovides a total ordering on uploads. The service accepts an upload iffupload.epoch > current.epoch(strictly newer); lower-epoch uploads are stale and rejected outright. -
group_state_hashis a consistency check at a single epoch. MLS is deterministic — every member that applies the same commit derives identical group state — so two correct uploads at the same epoch MUST carry the same hash. Whenupload.epoch == current.epoch: equal hashes mean an idempotent re-upload (no-op or duplicate-reject); different hashes mean the uploaders are on forked views of the group and the service must refuse to pick a winner.
The joiner additionally verifies on download that the blob’s epoch
and group_state_hash match the decrypted GroupInfo before
attempting to join — closes the “malicious service swapped
ciphertext” gap.
Fields§
§nonce: Vec<u8>12 bytes; ChaCha20Poly1305 nonce specific to this ciphertext.
ciphertext: Vec<u8>wrap_payload_symmetric output: AEAD ciphertext over the serialized MlsMessageOut(GroupInfo).
epoch: u64MLS group epoch of the wrapped GroupInfo. Plaintext; the service totally orders uploads by this value — strictly-newer wins, stale is rejected. Joiner verifies against the decrypted GroupInfo before joining.
group_state_hash: Vec<u8>Tree-hash (or equivalent group-state digest) of the wrapped GroupInfo. Plaintext; the service uses this only at equal epochs to detect forks (same epoch + differing hash = forked uploaders). Not used for ordering. Joiner verifies against the decrypted GroupInfo before joining.
expires_at_ns: u64Wall-clock expiry of this blob, in nanoseconds since UNIX epoch.
0 means no expiry. The service uses this as a TTL hint and MAY
garbage-collect blobs past their expires_at_ns autonomously.
The joining client also enforces this — refuses to join from an
expired blob even if the service is still serving it. Admin
bounds the campaign by setting this at upload time; extending an
invite is a re-upload with a later value.
Trait Implementations§
Source§impl Clone for EncryptedGroupInfoBlobV1
impl Clone for EncryptedGroupInfoBlobV1
Source§fn clone(&self) -> EncryptedGroupInfoBlobV1
fn clone(&self) -> EncryptedGroupInfoBlobV1
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for EncryptedGroupInfoBlobV1
impl Debug for EncryptedGroupInfoBlobV1
Source§impl Default for EncryptedGroupInfoBlobV1
impl Default for EncryptedGroupInfoBlobV1
§impl<'de> Deserialize<'de> for EncryptedGroupInfoBlobV1
impl<'de> Deserialize<'de> for EncryptedGroupInfoBlobV1
§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Source§impl Hash for EncryptedGroupInfoBlobV1
impl Hash for EncryptedGroupInfoBlobV1
Source§impl Message for EncryptedGroupInfoBlobV1
impl Message for EncryptedGroupInfoBlobV1
Source§fn encoded_len(&self) -> usize
fn encoded_len(&self) -> usize
Source§fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError>where
Self: Sized,
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError>where
Self: Sized,
Source§fn encode_to_vec(&self) -> Vec<u8> ⓘwhere
Self: Sized,
fn encode_to_vec(&self) -> Vec<u8> ⓘwhere
Self: Sized,
Source§fn encode_length_delimited(
&self,
buf: &mut impl BufMut,
) -> Result<(), EncodeError>where
Self: Sized,
fn encode_length_delimited(
&self,
buf: &mut impl BufMut,
) -> Result<(), EncodeError>where
Self: Sized,
Source§fn encode_length_delimited_to_vec(&self) -> Vec<u8> ⓘwhere
Self: Sized,
fn encode_length_delimited_to_vec(&self) -> Vec<u8> ⓘwhere
Self: Sized,
Source§fn decode(buf: impl Buf) -> Result<Self, DecodeError>where
Self: Default,
fn decode(buf: impl Buf) -> Result<Self, DecodeError>where
Self: Default,
Source§fn decode_length_delimited(buf: impl Buf) -> Result<Self, DecodeError>where
Self: Default,
fn decode_length_delimited(buf: impl Buf) -> Result<Self, DecodeError>where
Self: Default,
Source§fn merge(&mut self, buf: impl Buf) -> Result<(), DecodeError>where
Self: Sized,
fn merge(&mut self, buf: impl Buf) -> Result<(), DecodeError>where
Self: Sized,
self. Read moreSource§fn merge_length_delimited(&mut self, buf: impl Buf) -> Result<(), DecodeError>where
Self: Sized,
fn merge_length_delimited(&mut self, buf: impl Buf) -> Result<(), DecodeError>where
Self: Sized,
self.Source§impl Name for EncryptedGroupInfoBlobV1
impl Name for EncryptedGroupInfoBlobV1
Source§const NAME: &'static str = "EncryptedGroupInfoBlobV1"
const NAME: &'static str = "EncryptedGroupInfoBlobV1"
Message.
This name is the same as it appears in the source .proto file, e.g. FooBar.Source§const PACKAGE: &'static str = "xmtp.mls.message_contents"
const PACKAGE: &'static str = "xmtp.mls.message_contents"
., e.g. google.protobuf.Source§fn full_name() -> String
fn full_name() -> String
Message.
It’s prefixed with the package name and names of any parent messages,
e.g. google.rpc.BadRequest.FieldViolation.
By default, this is the package name followed by the message name.
Fully-qualified names must be unique within a domain of Type URLs.Source§impl PartialEq for EncryptedGroupInfoBlobV1
impl PartialEq for EncryptedGroupInfoBlobV1
Source§fn eq(&self, other: &EncryptedGroupInfoBlobV1) -> bool
fn eq(&self, other: &EncryptedGroupInfoBlobV1) -> bool
self and other values to be equal, and is used by ==.§impl Serialize for EncryptedGroupInfoBlobV1
impl Serialize for EncryptedGroupInfoBlobV1
impl Eq for EncryptedGroupInfoBlobV1
impl StructuralPartialEq for EncryptedGroupInfoBlobV1
Auto Trait Implementations§
impl Freeze for EncryptedGroupInfoBlobV1
impl RefUnwindSafe for EncryptedGroupInfoBlobV1
impl Send for EncryptedGroupInfoBlobV1
impl Sync for EncryptedGroupInfoBlobV1
impl Unpin for EncryptedGroupInfoBlobV1
impl UnsafeUnpin for EncryptedGroupInfoBlobV1
impl UnwindSafe for EncryptedGroupInfoBlobV1
Blanket Implementations§
§impl<T> AggregateExpressionMethods for T
impl<T> AggregateExpressionMethods for T
§fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
DISTINCT modifier for aggregate functions Read more§fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
ALL modifier for aggregate functions Read more§fn aggregate_filter<P>(self, f: P) -> Self::Outputwhere
P: AsExpression<Bool>,
Self: FilterDsl<<P as AsExpression<Bool>>::Expression>,
fn aggregate_filter<P>(self, f: P) -> Self::Outputwhere
P: AsExpression<Bool>,
Self: FilterDsl<<P as AsExpression<Bool>>::Expression>,
§fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Classify for T
impl<T> Classify for T
type Classified = T
fn classify(self) -> T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Declassify for T
impl<T> Declassify for T
type Declassified = T
fn declassify(self) -> T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSend for T
impl<T> DowncastSend for T
§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<T> IntoSql for T
impl<T> IntoSql for T
§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].