pub struct MlsManager { /* private fields */ }Expand description
Main MLS manager for end-to-end encryption.
Implementations§
Source§impl MlsManager
impl MlsManager
Sourcepub fn identity_assertion(&self, signed_data: &[u8]) -> Result<Vec<u8>>
pub fn identity_assertion(&self, signed_data: &[u8]) -> Result<Vec<u8>>
Builds this identity’s assertion over signed_data.
The result is what a Bluetooth LE peripheral serves from its Identity characteristic and what a peer-stream transport sends first. The key never leaves the manager: the caller supplies the bytes to sign and receives the whole layout, so no bridge assembles it.
signed_data means nothing to a verifier and may be empty. The mobile
peripherals put their mesh advertisement there; a peripheral with
nothing to say should pass nothing.
§Errors
Whatever MlsManager::sign_data returns when there is no identity to
sign with.
Source§impl MlsManager
impl MlsManager
Sourcepub fn new(
user_id: impl Into<String>,
storage: Arc<dyn MlsStorage>,
) -> Result<Self>
pub fn new( user_id: impl Into<String>, storage: Arc<dyn MlsStorage>, ) -> Result<Self>
Creates a new MLS manager.
Sourcepub fn load_or_create_identity(
storage: &Arc<dyn MlsStorage>,
) -> Result<(SignatureKeyPair, Address)>
pub fn load_or_create_identity( storage: &Arc<dyn MlsStorage>, ) -> Result<(SignatureKeyPair, Address)>
Loads this device’s identity key from storage, minting and persisting
one on first call, and returns the address it derives to.
This is the bootstrap entry point: it exists so the address can be known
before an MlsManager is constructed. The manager needs its own id
at construction time (it goes into the credential and every session
slot), but under self-certifying addressing that id is a function of the
identity key — which used to be minted inside the constructor. Callers
break the circle by calling this first and passing the resulting address
to Self::new.
Idempotent: a second call returns the stored key and the same address. The keypair is written before the address is derived, so a caller that crashes between the two finds the same identity on the next start rather than minting a second one.
Sourcepub fn generate_key_package(&self) -> Result<KeyPackageBundle>
pub fn generate_key_package(&self) -> Result<KeyPackageBundle>
Generates a new key package for distribution over the push path.
Sourcepub fn generate_publication_key_package(&self) -> Result<KeyPackageBundle>
pub fn generate_publication_key_package(&self) -> Result<KeyPackageBundle>
Generates a key package reserved for a publication slot.
Distinct from Self::generate_key_package only in that the result is
withheld from Self::get_or_create_key_package — see
KeyPackageBundle::reserved_for_publication for why sharing one
package between a published record and a pushed exchange corrupts both.
Sourcepub fn get_or_create_key_package(&self) -> Result<KeyPackageBundle>
pub fn get_or_create_key_package(&self) -> Result<KeyPackageBundle>
Gets an existing unclaimed key package or generates a new one.
Three kinds of package are skipped, for the same underlying reason — an MLS init key is consumed by its first user, so two parties must never be pointed at one:
- packages reserved for publication slots, or synced by the application
(
Self::mark_key_package_synced), or a pushed-to peer and a stranger who fetched the published record would race for it; - packages already claimed by a peer over the push path
(
Self::take_push_key_package), or this peer-less entry point would hand out a key another peer is expected to use.
This is the peer-less escape hatch (the FFI surface and tests). Callers
that know the recipient should use Self::take_push_key_package,
which is what actually holds the one-key-per-peer property; a package
handed out here is unclaimed, so the push path may later claim it for
the first peer it is pushed to.
Sourcepub fn take_push_key_package(&self, peer_id: &str) -> Result<PushKeyPackage>
pub fn take_push_key_package(&self, peer_id: &str) -> Result<PushKeyPackage>
Hands peer_id the key package to advertise to it, minting one if it
has no live package of its own.
This is the push path’s entry point, and the whole point of it is that two peers never receive the same init key. Before this existed the push path returned the first stored package to every caller until somebody’s Welcome consumed it — the LastResort-style reuse RFC 9420 §16.8 permits only as a denial-of-service fallback, and which the Least Authority MDK audit flagged as enabling unsolicited joins and cross-group linkage. It also made a second peer’s Welcome unprocessable once the first had used the key, with nothing to re-drive the exchange.
Assignment is stored on the package rather than in a separate map, so it survives restarts for free and cannot disagree with the pool it describes. Resolution order:
- this peer’s own live package — a repeat push costs no new material;
- an unclaimed package (minted by the peer-less entry point, or by a build predating assignment), claimed here so upgrading does not strand it;
- a freshly minted package, claimed for this peer.
Past MAX_PUSH_KEY_PACKAGES live packages it stops growing the pool
and reuses the newest one, reporting that through
PushKeyPackage::pool_exhausted so the caller can surface it. That is
a deliberate degradation to the old behaviour rather than an error: the
alternative — refusing to advertise, or evicting a package a peer may
still be about to use — costs session establishment, which is worse than
the weakened forward secrecy it would buy.
Only step 3 is gated by the ceiling, because only minting grows the pool: claiming an unclaimed package relabels one that already exists, so degrading to a shared package while a claimable one sits idle would buy nothing. A corollary is that the shared package is always assigned to another peer — reaching that branch means neither an own nor an unclaimed package was found — and “newest” makes it the most recently assigned one, which has the most lifetime left but is also the peer most likely to be mid-establishment. If the over-ceiling peer’s Welcome lands first, that peer’s held advertisement becomes unprocessable until the next push to it mints a successor. Sharing the oldest instead would trade that for the shortest remaining lifetime; neither is free, and the exhaustion report is what makes the condition visible either way.
Consumption is what rotates a peer’s key: a Welcome built against the package removes its init key from provider storage, the loader then reports the package gone, and the next push to that peer mints a fresh one.
Sourcepub fn key_package_by_id(
&self,
package_id: &str,
) -> Result<Option<KeyPackageBundle>>
pub fn key_package_by_id( &self, package_id: &str, ) -> Result<Option<KeyPackageBundle>>
Loads a specific key package this device owns, or None if it is gone.
None is the consumption signal the publication slots run on: the
load prunes and reports missing any package whose private init key has
left the OpenMLS provider, which is exactly what processing a Welcome
built against it does. A slot whose package reads back None has been
used by somebody and needs replacing.
Sourcepub fn delete_key_package(&self, package_id: &str) -> Result<()>
pub fn delete_key_package(&self, package_id: &str) -> Result<()>
Deletes a key package this device owns.
Exists to reclaim a publication package that was minted but whose
record was never built or queued. Such a package is reserved, so
Self::get_or_create_key_package will never hand it out, and no slot
references it — nothing else would remove it before its lifetime runs
out, so a repeatedly failing publish would otherwise strand fresh
provider key material every refresh.
“Strand” is meant literally, which is why this destroys the private init key too: deleting the bundle record alone leaves the material OpenMLS holds in place with nothing left pointing at it.
Sourcepub fn import_key_package(
&self,
user_id: &str,
key_package_data: &[u8],
) -> Result<()>
pub fn import_key_package( &self, user_id: &str, key_package_data: &[u8], ) -> Result<()>
Imports a contact’s key package for later use.
Security (SEC-M5): the caller-supplied user_id becomes both the
storage key and — at session creation — the identity this key
package is trusted for. Reject storage-hostile ids (the id is a raw
key_id), cryptographically validate the key package, and require
the embedded credential identity to equal user_id so a key
package generated by one user can never be imported under
another’s name.
The identity claim is then proved rather than trusted: see
Self::verify_address_binding. No Authentication Service verdict
travels with the call any more, because there is nothing for the caller
to know — the key package carries its own proof.
Sourcepub fn get_pending_key_packages(&self) -> Result<Vec<KeyPackageBundle>>
pub fn get_pending_key_packages(&self) -> Result<Vec<KeyPackageBundle>>
Lists the live packages an application may publish itself.
Only packages nobody has spoken for: unclaimed, unreserved and not yet synced. A package the push path assigned to a peer, or one standing in one of the engine’s own publication slots, is the engine’s to publish. Listing them here invited an application following the documented upload loop to mark them synced, which handed one init key to two parties and, while marking deleted the record, stranded the old key every time the engine minted a successor.
Sourcepub fn mark_key_package_synced(&mut self, package_id: &str) -> Result<()>
pub fn mark_key_package_synced(&mut self, package_id: &str) -> Result<()>
Records that the application has published a package itself.
The record is kept, flagged, and withheld from both hand-out paths. It is not deleted, and the private init key is not destroyed:
- The key must outlive the mark, because a stranger who fetched the uploaded copy may still Welcome us, and only that Welcome consumes it.
- The record must outlive the mark, because the record is the only thing that carries expiry. Deleting it, which is what this used to do, left the init key resident for the life of the install whenever the uploaded copy was never claimed (issue 367). Kept, it is withdrawn at expiry and its key destroyed past the grace window like any other.
Marking an id that is unknown, expired or already consumed does nothing: there is no live package left to publish. Marking a package the push path already handed to a peer is allowed but logged, since that peer and the uploaded copy now share an init key; the peer’s held copy stays openable, and a failed establishment is recovered by the next push, which mints that peer a successor.
Takes &mut self so a caller sharing the manager behind an RwLock
must hold the write half. The push path claims a package under the
read half, and both are a load, a change and a store of the same
record: under two read guards the claim’s store can land second and
erase the mark, leaving the package uploaded and advertised to a
peer with nothing logged.
Sourcepub fn has_session(&self, other_user_id: &str) -> Result<bool>
pub fn has_session(&self, other_user_id: &str) -> Result<bool>
Checks if a session exists with another user.
Sourcepub fn create_session(&self, other_user_id: &str) -> Result<WelcomeMessage>
pub fn create_session(&self, other_user_id: &str) -> Result<WelcomeMessage>
Creates a new 1:1 session with another user.
Sourcepub fn join_session(&self, welcome: &WelcomeMessage) -> Result<GroupInfo>
pub fn join_session(&self, welcome: &WelcomeMessage) -> Result<GroupInfo>
Joins a session using a Welcome message.
Sourcepub fn session_established_at_ms(
&self,
other_user_id: &str,
) -> Result<Option<u64>>
pub fn session_established_at_ms( &self, other_user_id: &str, ) -> Result<Option<u64>>
When the current 1:1 session with other_user_id was created or
adopted on this device (local clock, ms), or None when there is no
session or it predates the stamp.
A frame sealed before this moment cannot have been sealed under this session, so its failure to decrypt says nothing about whether the two sides hold the same session now.
Sourcepub fn replace_session_with_welcome(
&self,
welcome: &WelcomeMessage,
) -> Result<GroupInfo>
pub fn replace_session_with_welcome( &self, welcome: &WelcomeMessage, ) -> Result<GroupInfo>
Replaces an existing session with an incoming Welcome message.
This implements the “welcome-wins” strategy for race condition resolution. When both peers simultaneously create a session, this method allows one peer to replace their own session with the other peer’s Welcome, ensuring both end up with the same cryptographic state.
Sourcepub fn encrypt_for_user(
&self,
other_user_id: &str,
plaintext: &[u8],
) -> Result<EncryptedMessage>
pub fn encrypt_for_user( &self, other_user_id: &str, plaintext: &[u8], ) -> Result<EncryptedMessage>
Encrypts a message for a 1:1 session.
Sourcepub fn encrypt_for_existing_session(
&self,
other_user_id: &str,
plaintext: &[u8],
) -> Result<EncryptedMessage>
pub fn encrypt_for_existing_session( &self, other_user_id: &str, plaintext: &[u8], ) -> Result<EncryptedMessage>
Encrypts a message for a 1:1 session that is known to exist.
Unlike encrypt_for_user, this skips the has_session() storage check
and goes directly to encrypt_message(). The caller must guarantee the
session exists (e.g., via an in-memory cache). If the session was deleted
externally, SessionNotFound is returned.
Sourcepub fn get_pending_welcome(
&self,
other_user_id: &str,
) -> Result<Option<WelcomeMessage>>
pub fn get_pending_welcome( &self, other_user_id: &str, ) -> Result<Option<WelcomeMessage>>
Gets a pending Welcome message.
Sourcepub fn clear_pending_welcome(&self, other_user_id: &str) -> Result<()>
pub fn clear_pending_welcome(&self, other_user_id: &str) -> Result<()>
Clears a pending Welcome message.
Sourcepub fn decrypt_from_user(
&self,
encrypted: &EncryptedMessage,
claimed_sender: &str,
) -> Result<Option<Vec<u8>>>
pub fn decrypt_from_user( &self, encrypted: &EncryptedMessage, claimed_sender: &str, ) -> Result<Option<Vec<u8>>>
Decrypts a message from a 1:1 session.
claimed_sender is the transport-level sender this message will be
attributed to; decryption fails with
MlsError::SenderIdentityMismatch if it does not match the
MLS-authenticated credential (SEC-M1).
Sourcepub fn list_sessions(&self) -> Result<Vec<String>>
pub fn list_sessions(&self) -> Result<Vec<String>>
Lists all active 1:1 sessions.
Sourcepub fn delete_session(&self, other_user_id: &str) -> Result<()>
pub fn delete_session(&self, other_user_id: &str) -> Result<()>
Deletes a 1:1 session.
The establishment stamp goes first: an Err must mean the session is
still there, because callers clean up their own state for the peer
only once this succeeds. Deleting the session first and then failing
on the stamp left a peer recorded as confirmed with no session.
Sourcepub fn create_group(&self, group_name: &str) -> Result<GroupInfo>
pub fn create_group(&self, group_name: &str) -> Result<GroupInfo>
Creates a new group.
Sourcepub fn add_group_member(
&self,
group_id: &GroupId,
invitee_user_id: &str,
member_key_package: &[u8],
) -> Result<(WelcomeMessage, EncryptedMessage)>
pub fn add_group_member( &self, group_id: &GroupId, invitee_user_id: &str, member_key_package: &[u8], ) -> Result<(WelcomeMessage, EncryptedMessage)>
Adds a member to a group.
Returns a tuple of (WelcomeMessage, EncryptedMessage) where the WelcomeMessage should be sent to the invitee and the EncryptedMessage (Commit) should be distributed to all existing group members so they can advance their MLS epoch.
invitee_user_id binds the package to the identity it is being added
under. This path previously ran neither check — not even the
credential-identity one import_key_package has always had — so a
package could be admitted to a group under a roster label that had
nothing to do with it. The 1:1 path and the group path apply the same
three checks.
The third is the validity-window cap, and it belongs here for the
reason it belongs anywhere: this is a third route by which a key
package this install did not mint is admitted, it takes its bytes
straight off the wire out of pending_key_packages, and a bound
applied on two routes of three is not a bound. What differs from the
1:1 path is only how long the damage lasts, since a package spent on a
commit is not also cached for re-use.
Sourcepub fn remove_group_member(
&self,
group_id: &GroupId,
member_id: &str,
) -> Result<EncryptedMessage>
pub fn remove_group_member( &self, group_id: &GroupId, member_id: &str, ) -> Result<EncryptedMessage>
Removes a member from a group.
Removes every leaf whose credential names member_id, in one
commit, rather than the first one found.
Two leaves cannot name one identity in a tree whose leaves all passed
the binding, and the reason is worth writing down because it is not
obvious: RFC 9420 requires signature keys to be unique across a group
(OpenMLS enforces it — “Duplicate signature key in proposals and
group”), and since verify_leaf_binding ties a credential to the hash
of its own signature key, two leaves with the same credential would have
to carry the same key. So through the wire gates the duplicate case is
refused one layer down, twice over.
That argument covers the gates, not the tree. It says nothing about the
case verify_sender_leaf and the get_group_info filter exist for — a
leaf written straight into the install-scoped provider store. A forged
leaf claiming a peer’s address carries the attacker’s signature key,
so it violates no uniqueness rule and sits alongside that peer’s real
leaf quite happily. There the loop is doing real work: first-match would
remove one of the two and leave the other in the group holding live
keys, while every roster read shows the member gone — an
access-revocation failure that would surface as nothing at all.
Removing every match costs one Vec and cannot have that failure
mode.
Sourcepub fn leave_group(&self, group_id: &GroupId) -> Result<()>
pub fn leave_group(&self, group_id: &GroupId) -> Result<()>
Leaves a group.
Sourcepub fn encrypt_for_group(
&self,
group_id: &GroupId,
plaintext: &[u8],
) -> Result<EncryptedMessage>
pub fn encrypt_for_group( &self, group_id: &GroupId, plaintext: &[u8], ) -> Result<EncryptedMessage>
Encrypts a message for a group.
Sourcepub fn decrypt_from_group(
&self,
encrypted: &EncryptedMessage,
claimed_sender: &str,
) -> Result<Option<Vec<u8>>>
pub fn decrypt_from_group( &self, encrypted: &EncryptedMessage, claimed_sender: &str, ) -> Result<Option<Vec<u8>>>
Decrypts a message from a group.
claimed_sender is the transport-level sender this message will be
attributed to; decryption fails with
MlsError::SenderIdentityMismatch if it does not match the
MLS-authenticated credential (SEC-M1). The check runs before any
commit is merged, so a spoofed commit cannot advance group state.
Sourcepub fn join_group(&self, welcome: &WelcomeMessage) -> Result<GroupInfo>
pub fn join_group(&self, welcome: &WelcomeMessage) -> Result<GroupInfo>
Joins a group using a Welcome message.
Sourcepub fn list_groups(&self) -> Result<Vec<GroupId>>
pub fn list_groups(&self) -> Result<Vec<GroupId>>
Lists all groups.
Sourcepub fn get_group_info(&self, group_id: &GroupId) -> Result<Option<GroupInfo>>
pub fn get_group_info(&self, group_id: &GroupId) -> Result<Option<GroupInfo>>
Gets information about a group.
Sourcepub fn has_group(&self, group_id: &GroupId) -> Result<bool>
pub fn has_group(&self, group_id: &GroupId) -> Result<bool>
Returns true if local MLS group state exists for group_id.
This is the authoritative test for “do we actually participate in this group via MLS” — it gates on the stored group marker, not the member send-cache (which relay reconciliation can populate without any MLS state). Callers use it to distinguish a genuine legacy relay-only (unencrypted) group, which has no MLS state, from an unauthenticated plaintext frame spoofed against a group the node secures with MLS.
Sourcepub fn set_group_name(&self, group_id: &GroupId, name: &str) -> Result<()>
pub fn set_group_name(&self, group_id: &GroupId, name: &str) -> Result<()>
Updates the group name.
Sourcepub fn get_group_metadata(
&self,
group_id: &GroupId,
) -> Result<Option<GroupMetadata>>
pub fn get_group_metadata( &self, group_id: &GroupId, ) -> Result<Option<GroupMetadata>>
Gets group metadata.
Sourcepub fn set_group_custom_metadata(
&self,
group_id: &GroupId,
key: &str,
value: &str,
) -> Result<()>
pub fn set_group_custom_metadata( &self, group_id: &GroupId, key: &str, value: &str, ) -> Result<()>
Sets custom metadata for a group.
Sourcepub fn remove_group_custom_metadata(
&self,
group_id: &GroupId,
key: &str,
) -> Result<()>
pub fn remove_group_custom_metadata( &self, group_id: &GroupId, key: &str, ) -> Result<()>
Removes a custom metadata key for a group.
Sourcepub fn set_member_role(
&self,
group_id: &GroupId,
user_id: &str,
role: GroupRole,
) -> Result<()>
pub fn set_member_role( &self, group_id: &GroupId, user_id: &str, role: GroupRole, ) -> Result<()>
Sets a member’s role in a group.
Sourcepub fn set_enforce_admin_commits(&mut self, enforce: bool)
pub fn set_enforce_admin_commits(&mut self, enforce: bool)
Enables or disables receive-side authorization of group membership
commits. See crate::group::GroupManager::set_enforce_admin_commits
for the fork consequence — this is off by default and enabling it is a
deployment decision, not a hardening toggle.
Applies to group commits only. The session manager owns a separate group manager and is left untouched, so 1:1 sessions are unaffected regardless of this setting.
Sourcepub fn set_group_creator(
&self,
group_id: &GroupId,
creator_id: &str,
) -> Result<()>
pub fn set_group_creator( &self, group_id: &GroupId, creator_id: &str, ) -> Result<()>
Records the group’s creator, only if none is on record yet.
created_by is the fallback GroupMetadata consults when no admin
role is stored (see the protocol layer’s check_is_admin), so it must
behave monotonically: a device that created the group, or already
adopted a creator from the Welcome that admitted it, keeps what it has.
Only the “no information” state is fillable. That makes the write
idempotent under duplicate Welcomes and stops a later invite — from an
inviter whose own metadata disagrees — from rewriting an established
admin fallback.
Returns Ok(()) whether or not the value was adopted; use
Self::get_group_metadata to observe the result.
Sourcepub fn remove_member_role(
&self,
group_id: &GroupId,
user_id: &str,
) -> Result<()>
pub fn remove_member_role( &self, group_id: &GroupId, user_id: &str, ) -> Result<()>
Removes a member’s role metadata from a group.
Sourcepub fn decrypt(
&self,
encrypted: &EncryptedMessage,
claimed_sender: &str,
) -> Result<Option<Vec<u8>>>
pub fn decrypt( &self, encrypted: &EncryptedMessage, claimed_sender: &str, ) -> Result<Option<Vec<u8>>>
Decrypts any incoming encrypted message.
claimed_sender is the transport-level sender this message will be
attributed to; it must match the MLS-authenticated credential
(SEC-M1).
Sourcepub fn process_welcome(&self, welcome: &WelcomeMessage) -> Result<GroupInfo>
pub fn process_welcome(&self, welcome: &WelcomeMessage) -> Result<GroupInfo>
Processes a Welcome message.
Source§impl MlsManager
impl MlsManager
Sourcepub fn update_keys(&self, group_id: &GroupId) -> Result<EncryptedMessage>
pub fn update_keys(&self, group_id: &GroupId) -> Result<EncryptedMessage>
Updates the cryptographic keys for a group (triggers MLS self-update).
This provides post-compromise security by rotating keys. The returned commit message must be sent to all other group members.
§Returns
Returns the commit message that must be distributed to all group members.
Sourcepub fn ensure_min_key_packages(&self, min: usize) -> Result<usize>
pub fn ensure_min_key_packages(&self, min: usize) -> Result<usize>
Ensures at least min valid key packages are available.
Generates new key packages if the current count is below the minimum. This is useful for offline scenarios where multiple key packages should be pre-generated for distribution.
§Arguments
min- Minimum number of key packages to maintain, capped atMAX_PUSH_KEY_PACKAGES. The packages this mints are unclaimed, soSelf::take_push_key_packagedraws them down one per peer; asking for more than the pool ceiling would only mint key material that ceiling stops it ever handing out, while holding the pool at capacity so every peer past the last claim is advertised a shared package.
Only packages the push path can hand out count toward min. A slot
package or one the application marked synced is held by somebody
else and never advertised to a peer, so counting it would leave the
pool short by exactly that many.
§Returns
Returns the number of live packages the push path can hand out after ensuring the minimum.
Sourcepub fn count_valid_key_packages(&self) -> Result<usize>
pub fn count_valid_key_packages(&self) -> Result<usize>
Returns the number of live key package records: unexpired, init key resident.
This includes slot packages and packages the application marked
synced, which are never handed to a peer. For the pool the push path
draws from, see Self::ensure_min_key_packages.
Sourcepub fn get_identity_public_key(&self) -> Result<Vec<u8>>
pub fn get_identity_public_key(&self) -> Result<Vec<u8>>
Returns the identity public key as raw bytes.
This is the Ed25519 public key used for MLS operations. It can be shared with others to establish your identity and verify signatures.
Sourcepub fn derive_address(public_key: &[u8]) -> Result<Address>
pub fn derive_address(public_key: &[u8]) -> Result<Address>
Derives the canonical self-certifying address of an Ed25519 identity
key: off1…, the bech32m encoding of
0x01 ‖ SHA-256(public_key)[..20].
This is the only address derivation in the SDK. It is implemented once,
in offline_protocol_sealed::derive_address, where a bare-metal leaf
node can reach it as well; this method, the derive_address FFI
function the bridges and apps call, and the interop harness are all
delegations to that one function, so every platform agrees byte for
byte.
§Arguments
public_key- The Ed25519 public key bytes (exactly 32)
§Errors
Returns MlsError::InvalidPublicKey if public_key is not 32 bytes.
The length is part of the format contract: hashing a differently-sized
input would yield a different address for the same identity. The bytes
are deliberately not checked against the curve. An address is defined
over key bytes, and what proves ownership is the signature verification
that accompanies it (see Self::verify_signature), so binding the
address format to a signature library’s parsing strictness would only
risk the derivation drifting between versions.
Sourcepub fn derive_user_id_from_public_key(public_key: &[u8]) -> String
👎Deprecated: use derive_address; this returns the self-certifying off1… address, no longer base58
pub fn derive_user_id_from_public_key(public_key: &[u8]) -> String
use derive_address; this returns the self-certifying off1… address, no longer base58
Derives a deterministic user ID from a public key.
§Arguments
public_key- The Ed25519 public key bytes
§Returns
Returns the derived address in its canonical off1… string form.
Unlike Self::derive_address this accepts any input length, which
It is also the one place that still spells the derivation out
instead of delegating to offline_protocol_sealed::derive_address,
because it deliberately does not do the length check that function
starts with. deprecated_derive_agrees_with_derive_address pins the
two together for the inputs where both are defined; the copy goes
away with the method at the next breaking release.
is precisely why it is deprecated: a caller passing a truncated or
padded key gets a plausible-looking address for an identity that
cannot exist.
Auto Trait Implementations§
impl !Freeze for MlsManager
impl !RefUnwindSafe for MlsManager
impl !UnwindSafe for MlsManager
impl Send for MlsManager
impl Sync for MlsManager
impl Unpin for MlsManager
impl UnsafeUnpin for MlsManager
Blanket Implementations§
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
Source§impl<T> Declassify for T
impl<T> Declassify for T
type Declassified = T
fn declassify(self) -> T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§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