de_mls/mls_crypto/credentials.rs
1//! MLS-specific credential bundle: signing keypair + credential.
2//!
3//! Built once per user from an [`crate::identity::Identity`] at User init
4//! and shared across every per-conversation `MlsService` via
5//! `Arc<MlsCredentials>`. The signing key is the long-lived MLS identity;
6//! the credential's serialized content is the user's identity bytes —
7//! the link back to whatever real-world identifier the
8//! [`crate::identity::Identity`] represents.
9
10use openmls::credentials::{BasicCredential, CredentialWithKey};
11use openmls_basic_credential::SignatureKeyPair;
12
13use crate::{
14 identity::Identity,
15 mls_crypto::{MlsError, service::CIPHERSUITE},
16};
17
18/// MLS credential + signing keypair for one user, shared across all
19/// conversations they belong to.
20#[derive(Debug)]
21pub struct MlsCredentials {
22 credential: CredentialWithKey,
23 signer: SignatureKeyPair,
24}
25
26impl MlsCredentials {
27 /// Build credentials from an [`Identity`]. Generates a fresh
28 /// signing keypair (held only in this struct, not stored in MLS
29 /// keystore until consumed by a service / KP build) and bundles it
30 /// with a basic credential whose serialized content is
31 /// `identity.identity_bytes()`.
32 pub fn from_identity<I: Identity + ?Sized>(identity: &I) -> Result<Self, MlsError> {
33 let credential = BasicCredential::new(identity.identity_bytes().to_vec());
34 let signer = SignatureKeyPair::new(CIPHERSUITE.signature_algorithm())?;
35 Ok(Self {
36 credential: CredentialWithKey {
37 credential: credential.into(),
38 signature_key: signer.to_public_vec().into(),
39 },
40 signer,
41 })
42 }
43
44 /// MLS credential bundle — public part of the identity, embedded in
45 /// every signed MLS message we produce.
46 pub fn credential(&self) -> &CredentialWithKey {
47 &self.credential
48 }
49
50 /// MLS signing keypair — owns the private key used to sign MLS
51 /// messages and proposals.
52 pub fn signer(&self) -> &SignatureKeyPair {
53 &self.signer
54 }
55}