ANP 1.1 is the default latest version. ANP 1.0 remains available as an archive.
ANP Profile 6: Group End-to-End Encryption (MLS Usage Profile Revised Draft)
- Document ID: ANP-P6
- Title: Group End-to-End Encryption
- Status: Draft
- Version: 0.3.2 (MLS Usage Profile Revised Draft)
- Language: English
- Applicability: This Profile is suitable for the Group End-to-End Encryption control layer based on Group DID and works closely with
anp.group.base.v1.
1. Purpose
This Profile defines the Group End-to-End Encryption control layer of ANP, stipulating:
- How to bind
group_did,group_state_version, andgroup_event_seqto the group cryptography state machine; - How to use MLS as the basic protocol for group key establishment, member changes, and application message protection;
- How to bind the
did:wbaidentity with MLS member credentials, KeyPackage, and leaf signature keys; - How to define a set of independent
group.e2ee.*JSON-RPC methods to specifically carry MLS cryptographic actions; - How to work closely with
anp.group.base.v1through state coupling instead of "embedding the MLS handshake object in the P4 method"; - How to deal with
epoch,Welcome,PrivateMessage,PublicMessage,epoch_authenticator, fork detection and recovery.
This Profile does not define:
- Pull historical messages;
- Read and online status;
- Device or internal copy concept;
- How to share group key status among multiple execution units within the Agent;
- Specific implementation of directory synchronization outside the group;
- end-to-end encryption for non-group scenarios;
- External Commit main line;
group_join_infoandgroup.e2ee.get_join_info;accept_welcomeprotocol method;- The second set of business member status models.
2. Terminology and Normative Conventions
2.1 Normative Keywords
In this article, MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, OPTIONAL are interpreted as normative requirements according to their capitalized form.
2.2 Terminology
- Group DID: The application layer global identifier of the group, which is
group_did. - Crypto Group ID: Group cryptography internal identifier, corresponding to MLS
group_id, which can be different fromgroup_did. - Group Host Service: The service responsible for the group basic status ordering, policy application and group message entry; not the MLS controller.
- MLS Group State: Group cryptographic state maintained based on MLS.
- Epoch: A generational advance in MLS group state.
- KeyPackage: MLS adding material object, used to add a new member to the group.
- Welcome: MLS welcome object, used to help new members initialize the group state.
- PrivateMessage: Encrypted MLS message with member authentication.
- PublicMessage: MLS message that is only signed and not encrypted.
- did:wba Binding: Binds an MLS leaf signature key, member credential, or KeyPackage to a verifiable proof object of
agent_did. - MLS Controller: The subject responsible for executing MLS member change control actions. Fixed to group
ownerin v1. - State Coupling: P4 and P6 do not do method-by-method mapping, but a coupling method that triggers cryptographic state advancement through business state changes.
- E2EE Notice: P6's self-defined independent encryption notification object, used to deliver cryptographic results such as
commitandwelcome. - Fork: An irreconcilable sequence of
epoch/epoch_authenticator/ status advancement was observed by different members for the samegroup_did.
3. Design Principles
3.1 Group identity and cryptographic status stratification
This Profile clearly distinguishes between:
group_did: application layer group global identifier;crypto_group_id: cryptography group internal identifier;group_state_version: Application layer group state version assigned by Group Host;epoch: Cryptozoological group generation assigned by the MLS state machine.
The four MUST NOT be mechanically equivalent; but there MUST be a verifiable binding between them.
3.2 An Agent = an external group member
Within the external interworking boundary of this Profile, a group member is always represented by an agent_did. The protocol layer does not introduce the concept of devices, terminals, or internal replica members.
If there are multiple execution copies within an Agent, how they share or synchronize the MLS group state belongs to the internal implementation of the Agent and does not belong to the interoperability semantics of this Profile.
3.3 P4 is the main business protocol, and P6 is the cryptography control layer
The relationship between this Profile and anp.group.base.v1 is as follows:
- P4 defines the business actions, business state, ordering semantics and receipt semantics of the group;
- P6 defines MLS cryptographic actions, cryptographic objects, binding rules and verification requirements;
- P4 is still the business layer authority;
- P6 does not redefine business member status such as
active / left / removed; - P6 does not require MLS native objects to be carried directly in the P4 method body.
3.4 State coupling instead of method-by-method mapping
The coupling between P4 and P6 is achieved through state, rather than through "a certain P4 method directly mapping a certain P6 method".
Specifically:
- P4 determines whether something is valid in business terms;
- P6 observes business-state changes and advances the MLS state accordingly.
For example:
- A group is successfully created in P4, and the creator has become
owner→ owner automatically executesgroup.e2ee.create - A member becomes
activein P4 and has not yet entered the MLS membership set → owner automatically executesgroup.e2ee.add - A member becomes
leftorremovedin P4 and is still in the MLS membership set → owner automatically executesgroup.e2ee.remove
3.5 owner is the only MLS controller
In v1, only the owner assumes the MLS controller role.
owner is responsible for:
-Create MLS group;
- Execute
add; - Execute
remove; - Generate
commitcorresponding to member changes; - Generate
welcomefor new members; - Advance
epochafter member change.
The core idea of P6 is not to put MLS objects into P4 method bodies, but to let cryptographic state advance together with business state. The following diagram summarizes this state coupling so that readers can understand the causal relationships among methods before reading the detailed constraints below.
flowchart TB
P4[P4 business-state changes<br/>group.create / member active / member left or removed]
OBS[owner observes business state]
CREATE[group.e2ee.create]
ADD[group.e2ee.add]
REMOVE[group.e2ee.remove]
HOST[Group Host]
NOTICE[group.e2ee.notice]
P4 --> OBS
OBS -->|group created and has no crypto_group_id yet| CREATE
OBS -->|member active and not yet in MLS| ADD
OBS -->|member left or removed and still in MLS| REMOVE
CREATE --> HOST
ADD --> HOST
REMOVE --> HOST
HOST --> NOTICE2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Figure P6-1: Overview of P4 / P6 state coupling (non-normative).
This diagram emphasizes trigger relationships rather than a new business state machine: P4 remains the authority for the business layer, and P6 only observes those business results and materializes them as MLS create / add / remove operations.
3.6 Group Host is responsible for ordering and is not responsible for MLS control
The responsibilities of Group Host Service are:
- Receive and ordering P4 business operations;
- Assign
group_event_seqto accepted events; - Advance
group_state_version; - generate
group_receipt; - Distribute group messages and E2EE Notice;
- Witness the implementation of MLS control results at the business layer.
By default, Group Host Service:
- SHOULD NOT act as an MLS controller;
- SHOULD NOT serve as an MLS group member;
- SHOULD NOT hold group application plaintext decryption capabilities.
3.7 The owner manages group state; active members manage group messages
The owner controls only:
- Member changes;
- Advancement of the group cryptographic state;
- Updates to
epoch.
All active members can:
- Use the current group state to generate their own group-message ciphertext;
- Call
group.e2ee.sendto send their own group message; - Decrypt other members' group messages.
This Profile does not require that all group messages be encrypted by the owner.
3.8 v1 does not support External Commit
In v1:
- External Commit is not supported;
group_join_infois not defined;group.e2ee.get_join_infois not defined;- The
accept_welcomeprotocol method is not defined.
All group entry paths are eventually unified into MLS add initiated by the owner at the cryptographic layer.
3.9 Only the message side enters PrivateMessage
In v1:
- Only the application message content of
group.e2ee.sendenters MLSPrivateMessageand is encrypted; group.e2ee.create,group.e2ee.add, andgroup.e2ee.removeall continue to use plaintext JSON-RPC request bodies;- Objects such as
commitandwelcomeappear as method inputs or Notice payloads instead of being embedded in the P4 business method body.
4. Dependency, Profile identification and target modeling
4.1 Profile name
The standard name of this Profile is:
anp.group.e2ee.v1
4.2 Dependencies
This Profile MUST depend on the following Profiles:
anp.core.binding.v1anp.identity.discovery.v1anp.group.base.v1
4.3 Security Profile
When using this Profile:
meta.profileMUST be equal toanp.group.e2ee.v1.
Among them:
group.e2ee.publish_key_package,group.e2ee.get_key_package,group.e2ee.noticeMUST usetransport-protectedgroup.e2ee.create,group.e2ee.add,group.e2ee.remove,group.e2ee.sendMUST usegroup-e2ee
For group.e2ee.send, group-e2ee means that the message semantics it carries belong to the group E2EE side; it does not mean that its outer JSON-RPC request body is encrypted by the group again.
4.4 Method Target Modeling
4.4.1 service-scoped
The following methods MUST be service-scoped:
group.e2ee.publish_key_packagegroup.e2ee.get_key_packagegroup.e2ee.create
Rules:
meta.target.kind = "service"meta.target.didMUST equal target publicANPMessageService.serviceDid
The reason why group.e2ee.create uses service-scoped is:
Before the success of group.create in the business layer, the business state of the group has just been established. Although group_did has been generated, the creation action itself still completes cryptographic initialization for the group Host service entrance, so v1 uniformly uses service-scoped.
4.4.2 group-addressed
The following methods MUST be group-addressed:
group.e2ee.addgroup.e2ee.removegroup.e2ee.send
Rules:
meta.target.kind = "group"meta.target.didMUST equal targetgroup_did
4.4.3 agent-addressed notification
The following notification MUST be agent-addressed:
group.e2ee.notice
Rules:
meta.target.kind = "agent"meta.target.didMUST be equal to the notification recipient Agent DID
5. Cryptographic Mainline and MTI Suite
5.1 Mainline Protocol
This Profile's group key mainline MUST be implemented based on MLS 1.0 semantics, but v1 only fixes a restricted usage subset of it.
v1 mainline includes at least:
- KeyPackage
- Add
- Remove
- Commit
- Welcome
- PrivateMessage
- Epoch advancement
Among them:
commit_b64uMUST be represented as raw bytes of the complete MLSMLSMessage(mls-public-message) serialized by TLS;welcome_b64uMUST be represented as raw bytes of the MLSWelcomeobject serialized by TLS;PrivateMessageMUST serve as the only ciphertext bearer object for group application messages.
The MLS library MAY additionally supports standard capabilities such as Update, proposal batching, PSK, and ReInit; however, these capabilities do not belong to the minimum protocol mainline of this Profile v1, and do not constitute interoperability requirements for v1.
5.2 Mandatory-to-Implement Suite
To ensure minimal interoperability, implementations conforming to this Profile MUST support the following MTI packages:
MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
5.3 Additional Suites
Implementation MAY support more MLS suites, but:
- All members within the same group MUST agree on the kit used;
- If group policy restrictions allow package collection, MLS Controller MUST reject packages that do not satisfy the policy.
5.4 Relationship with did:wba
The relationship between the main line of this Profile and did:wba is as follows:
authentication/assertionMethodin the DID document is used for identity binding proof;keyAgreementSHOULD in the DID document contains at least one X25519 entry, indicating that the Agent has E2EE capabilities;- The MLS group member's leaf signing key SHOUNT be directly equivalent to the DID long-term identity signing key;
- The leaf signature key SHOULD be generated separately and bound to
agent_didviadid:wba Binding.
6. did:wba and MLS binding model
6.1 Binding target
This Profile requires the following MLS elements to be bound to agent_did:
- KeyPackage owner;
- Current leaf signature key;
- The identity string in the group member's credentials.
6.2 Credential Identity Rules
For this Profile, credential.identity MUST in the MLS member credential is equal to the UTF-8 byte string of agent_did.
Implementation MUST NOT replace credential.identity with a local account ID, device ID, numeric user ID, or other non-DID string.
6.3 did_wba_binding object
This Profile defines the did_wba_binding object used to bind the MLS leaf signature key to agent_did.
The recommended structure is as follows:
{
"agent_did": "did:wba:example.com:agents:alice:e1_<fingerprint>",
"verification_method": "did:wba:example.com:agents:alice:e1_<fingerprint>#key-1",
"leaf_signature_key_b64u": "BASE64URL_ED25519_LEAF_PK",
"issued_at": "2026-03-29T12:00:00Z",
"expires_at": "2026-04-29T12:00:00Z",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"created": "2026-03-29T12:00:00Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:wba:example.com:agents:alice:e1_<fingerprint>#key-1",
"proofValue": "z..."
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
did_wba_binding.proof MUST reuse the shared Object Proof Profile defined in P1 Appendix B.
For did_wba_binding:
- issuer DID MUST be
agent_did - The protected document MUST be the entire
did_wba_bindingobject after removingproof proof.verificationMethodMUST point to the authentication method authorized byassertionMethodin theagent_didDID document
6.4 did_wba_binding verification rules
The recipient MUST complete the following verifications before accepting KeyPackage, LeafNode updates, or new members:
agent_didcan be parsed;verification_methodexists in the DID document;verification_methodMUST be authorized byassertionMethodof the DID document;proofMUST exist, and MUST meet the shared Object Proof Profile of P1 Appendix B;- The issuer DID MUST of
proofis equal toagent_did; proofverification passed;- The document content bound to
proofMUST cover at leastagent_did,verification_method,leaf_signature_key_b64u,issued_at, andexpires_at; - The actual leaf signature public key in KeyPackage / LeafNode is consistent with
leaf_signature_key_b64u; credential.identityin the MLS certificate is consistent withagent_did;- If
issued_at/expires_atexists, implement MUST to verify its time window according to the local time validity policy.
P6 defines did_wba_binding because the MLS leaf signature key should not be directly equated with the DID long-term identity signing key. The following diagram connects agent_did, the DID document, the binding object, and KeyPackage / credential.identity so that readers can understand the verification order.
flowchart LR
DID[agent_did]
DOC[DID Document]
VM[assertionMethod verificationMethod]
BIND[did_wba_binding.proof]
LEAF[leaf_signature_key_b64u]
KP[MLS KeyPackage]
CID[credential.identity = agent_did]
DID --> DOC --> VM --> BIND --> LEAF --> KP
DID --> CID
CID --> KP2
3
4
5
6
7
8
9
10
11
12
Figure P6-2: did:wba and MLS binding chain (non-normative).
During verification, the recipient should not only check that the internal MLS signature is valid. It should also follow this chain to confirm that credential.identity, the leaf signature key, and agent_did are fully bound.
6.5 e1_ is compatible with k1_
- For the default
e1_DID,did_wba_binding.proofMUST reuse the shared Object Proof Profile of P1 Appendix B; - For compatible
k1_DID,did_wba_binding.proofMAY use the alternative Object Proof Profile defined by explicit extension negotiation; but when there is no explicit extension negotiation, v1 MTI does not bindk1_proof as the default interworking path; - MTI leaf signature keys for MLS groups still MAY use Ed25519 regardless of the DID's identity curve, as long as the proof of binding holds.
7. Core objects
7.1 crypto_group_id
crypto_group_id represents the MLS's internal group_id.
The rules are as follows:
crypto_group_idMUST treated as opaque bytes;- In JSON, MUST be represented by
base64url, and the field name is recommended to becrypto_group_id_b64u; crypto_group_idMUST establish a verifiable binding togroup_did.
7.2 group_state_ref
This Profile reuses the group_state_ref concept of P4 and requires that the E2EE group contains at least:
group_didgroup_state_versionpolicy_hash(if the group policy has been hashed)
In group E2EE, readers can easily connect the wrong mental model among four identifiers / versions at different layers: Group DID, business-state version, cryptographic internal group ID, and MLS epoch. The following diagram puts their sources and advancement relationships in one view.
flowchart TD
GD[group_did<br/>application-layer group identifier]
SV[group_state_version<br/>P4 business-state version]
CG[crypto_group_id<br/>MLS group_id]
EP[epoch<br/>MLS generation]
CREATE[group.e2ee.create]
ADDRM[group.e2ee.add / remove]
MSG[group.e2ee.send]
GD --> CREATE
SV --> CREATE
CREATE --> CG
CREATE --> EP
SV --> ADDRM
CG --> ADDRM
ADDRM --> EP
GD --> MSG
SV --> MSG
CG --> MSG
EP --> MSG2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Figure P6-3: Relationship among group_did, crypto_group_id, group_state_version, and epoch (non-normative).
When reading the subsequent object structures and verification rules, treat these four values as coordinates from different layers: they need to be bound, but they cannot replace each other and should not be mechanically treated as the same value.
7.3 group_key_package
This Profile definition group adds material packaging objects:
{
"key_package_id": "kp-001",
"owner_did": "did:wba:example.com:agents:bob:e1_<fingerprint>",
"suite": "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519",
"mls_key_package_b64u": "BASE64URL_KEYPACKAGE",
"did_wba_binding": { ... },
"expires_at": "2026-04-30T00:00:00Z"
}2
3
4
5
6
7
8
Among them:
key_package_idMUST exist;owner_didMUST exist;suiteMUST exist;mls_key_package_b64uMUST exist;did_wba_bindingMUST exist;expires_atSHOULD exist;mls_key_package_b64uMUST be no-padding base64url for the raw bytes of the MLSKeyPackageobject after serialization by MLS 1.0 TLS.
group_key_package is mainly used by owner to subsequently execute group.e2ee.add.
7.4 group_cipher_object
group_cipher_object is the wire protocol message body object of group.e2ee.send.
The recommended structure is as follows:
{
"crypto_group_id_b64u": "BASE64URL_GROUPID",
"epoch": "7",
"private_message_b64u": "BASE64URL_PRIVATEMESSAGE",
"group_state_ref": {
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_version": "42",
"policy_hash": "sha-256:..."
},
"epoch_authenticator": "BASE64URL_AUTH"
}2
3
4
5
6
7
8
9
10
11
Rules:
crypto_group_id_b64uMUST exist;epochMUST exist;private_message_b64uMUST exist;private_message_b64uMUST be no-padding base64url for the raw bytes of the MLSPrivateMessageobject serialized by MLS 1.0 TLS;group_state_ref.group_didMUST be equal to the outer targetgroup_did.
7.5 Group Application Plaintext
Before group application messages enter MLS PrivateMessage encryption, MUST be normalized into the following inner plaintext objects:
{
"application_content_type": "text/plain | application/json | application/anp-attachment-manifest+json | ...",
"thread_id": "thr-001",
"reply_to_message_id": "msg-0009",
"annotations": {},
"text": "...",
"payload": {},
"payload_b64u": "..."
}2
3
4
5
6
7
8
9
Rules:
application_content_typeMUST exist;- Exactly one of
text,payload, orpayload_b64uMUST be present; - The message semantic fields
thread_id,reply_to_message_id, andannotationsin P4 MUST be located in the inner object under group E2EE; - The sender MUST serialize the entire
Group Application Plaintextobject into a byte string using UTF-8 + RFC 8785 JCS before encryption; the receiver MUST interpret the object according to the same rules after decryption.
7.6 e2ee_notice_object
P6 defines an independent cryptographic notification object used to deliver cryptographic results.
The recommended structure is as follows:
{
"notice_id": "en-001",
"notice_type": "commit-delivery | welcome-delivery",
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_ref": {
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_version": "43",
"policy_hash": "sha-256:..."
},
"crypto_group_id_b64u": "BASE64URL_GROUPID",
"epoch": "8",
"subject_did": "did:wba:b.example:agents:bob:e1_<fingerprint>",
"commit_b64u": "BASE64URL_MLSMESSAGE",
"welcome_b64u": "BASE64URL_WELCOME",
"ratchet_tree_b64u": "BASE64URL_RATCHET_TREE",
"epoch_authenticator": "BASE64URL_AUTH",
"group_receipt": { ... }
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Rules:
notice_typeMUST exist;group_didMUST exist;group_state_refMUST exist;crypto_group_id_b64uMUST exist;epochMUST exist;commit_b64uMUST exist whennotice_type = "commit-delivery"is present;- When
notice_type = "welcome-delivery",welcome_b64uandratchet_tree_b64uMUST exist at the same time; ratchet_tree_b64uMUST be no-padding base64url of raw bytes for TLS serialization of the ratchet tree;group_receiptMAY exist to associate cryptographic results with the location of business ordering.
8. KeyPackage publishing and discovery methods
8.1 group.e2ee.publish_key_package
8.1.1 Semantics
Published by an Agent to its own exposed ANPMessageService, a KeyPackage that can be used for group joining.
8.1.2 Request Requirements
method = "group.e2ee.publish_key_package"meta.profile = "anp.group.e2ee.v1"meta.security_profile = "transport-protected"meta.target.kind = "service"meta.target.didMUST be equal to the publisher’s own publicANPMessageService.serviceDidmeta.sender_didMUST existbody.group_key_packageMUST existbody.group_key_package.owner_didMUST equalmeta.sender_did
Authentication constraints:
- This method belongs to service-scoped Control-Plane Methods;
- The caller MUST be running in an authenticated local session or an equivalent hop- and service-level authentication context;
- v1 does not require an additional business-layer
origin_prooffor this method.
8.1.3 Successful Response
A successful response MUST contain at least:
published = trueowner_didkey_package_idpublished_at
8.2 group.e2ee.get_key_package
8.2.1 Semantics
Get an available KeyPackage through the target Agent's ANPMessageService.
8.2.2 Request Requirements
meta.profile = "anp.group.e2ee.v1"meta.security_profile = "transport-protected"meta.target.kind = "service"meta.target.didMUST be equal to theANPMessageService.serviceDidexposed by the target Agent
body MUST contain:
target_did
body MAY contain:
preferred_suiterequire_fresh
Authentication constraints:
- This method belongs to service-scoped Control-Plane Methods;
- v1 Minimum Interoperability Requirements is at least hop/service level certification;
- Anonymous retrieval of KeyPackage is not part of v1 MTI.
8.2.3 Successful Response
A successful response MUST contain at least:
target_didgroup_key_package
8.2.4 Server-side distribution rules
ANPMessageService When returning group_key_package:
- SHOULD return KeyPackage that has not expired, not been revoked and not consumed;
- The server MAY mark it as
reserved, or assign an equivalent status after return, to avoid concurrent re-issuance; - When the corresponding
group.e2ee.addis successfully accepted by the Group Host and the cryptographic membership change is completed, MUST mark it asconsumedor delete it from the publishing set; - If the corresponding process fails, is canceled or times out, whether to release the reserved KeyPackage is determined by the deployment strategy, but SHOULD NOT will cause the same KeyPackage to be concurrently reused by both
group.e2ee.adds that will succeed; - Caller identity, rate limiting and anti-abuse policies MUST be implemented based on hop/service level authentication.
9. MLS Control-Plane Methods
9.1 General
The methods in this chapter are independent JSON-RPC methods. They are not "additional fields" to the P4 business method, but are P6's own cryptographic control actions.
Among them:
group.e2ee.create,group.e2ee.add,group.e2ee.removeare member change control methodsgroup.e2ee.sendis the message sending methodgroup.e2ee.create/add/removeis bound to the existing business state of P4, but will not create a new P4 business member stategroup.e2ee.sendis directly used as the online delivery method, without secondary packaging bygroup.send
9.2 group.e2ee.create
9.2.1 Semantics
Create a new MLS group state and add the owner as the initial member.
9.2.2 Caller
owner only.
9.2.3 Request Requirements
method = "group.e2ee.create"meta.profile = "anp.group.e2ee.v1"meta.security_profile = "group-e2ee"meta.target.kind = "service"meta.target.didMUST be equal to theANPMessageService.serviceDidexposed by the target group Hostmeta.sender_didMUST be equal to the current groupownerauth.origin_proofMUST exist
body MUST contain at least:
group_didgroup_state_refsuitecreator_key_packagecrypto_group_id_b64uepoch
Rules:
creator_key_package.owner_didMUST equalmeta.sender_didgroup_state_ref.group_didMUST equalbody.group_didepochFor the initial group state SHOULD be"0"or an initial value explicitly agreed upon by the implementation
9.2.4 Successful Response
A successful response MUST contain at least:
created = truegroup_didgroup_state_refcrypto_group_id_b64uepochaccepted_at
Notes:
group.e2ee.createitself MUST NOT create a new P4 business group;- It is only executed after
group.createhas been accepted by the business layer; - It no longer generates new
group_state_versionorgroup_event_seqindependently.
9.3 group.e2ee.add
9.3.1 Semantics
The owner executes MLS add to add a member who has become active in the business layer but has not yet entered the MLS membership set to the cryptography group.
9.3.2 Caller
owner only.
9.3.3 Request Requirements
method = "group.e2ee.add"meta.profile = "anp.group.e2ee.v1"meta.security_profile = "group-e2ee"meta.target.kind = "group"meta.target.didMUST equal targetgroup_didmeta.sender_didMUST be equal to the current groupownerauth.origin_proofMUST exist
body MUST contain at least:
member_didgroup_state_refgroup_key_packagecrypto_group_id_b64uepochcommit_b64uwelcome_b64uratchet_tree_b64u
Rules:
group_state_ref.group_didMUST equal outer targetgroup_didgroup_key_package.owner_didMUST equalmember_didcommit_b64uMUST be no-padding base64url for the complete MLSMLSMessageobject serialized by TLSwelcome_b64uMUST be no-padding base64url for the MLSWelcomeobject after serialization by TLSratchet_tree_b64uMUST be no-padding base64url of raw bytes for TLS serialization of the ratchet treeepochMUST indicate the newepochafter thisadd
9.3.4 Successful Response
A successful response MUST contain at least:
accepted = truegroup_didmember_didgroup_state_refcrypto_group_id_b64uepochaccepted_at
Notes:
group.e2ee.additself MUST NOT change the P4 business state of the target member toactive;- The business state MUST already have been determined by P4;
- This method is only responsible for implementing the business results to MLS.
9.4 group.e2ee.remove
9.4.1 Semantics
The owner executes MLS remove to remove a member who has become removed or left at the business layer from the cryptography group.
9.4.2 Caller
owner only.
9.4.3 Request Requirements
method = "group.e2ee.remove"meta.profile = "anp.group.e2ee.v1"meta.security_profile = "group-e2ee"meta.target.kind = "group"meta.target.didMUST equal targetgroup_didmeta.sender_didMUST be equal to the current groupownerauth.origin_proofMUST exist
body MUST contain at least:
member_didgroup_state_refcrypto_group_id_b64uepochcommit_b64u
Rules:
commit_b64uMUST be no-padding base64url for the complete MLSMLSMessageobject serialized by TLSepochMUST indicate the newepochafter thisremove
9.4.4 Successful Response
A successful response MUST contain at least:
accepted = truegroup_didmember_didgroup_state_refcrypto_group_id_b64uepochaccepted_at
9.5 group.e2ee.send
9.5.1 Semantics
Send an MLS encrypted group message directly to a group.
9.5.2 Caller
Any current active member.
9.5.3 Request Requirements
A compliant group.e2ee.send request MUST satisfy:
method = "group.e2ee.send"meta.profile = "anp.group.e2ee.v1"meta.security_profile = "group-e2ee"meta.target.kind = "group"meta.target.didMUST be the targetgroup_didmeta.sender_didMUST be the current sender Agent DIDmeta.message_idMUST existmeta.operation_idMUST existmeta.content_typeMUST be fixed toapplication/anp-group-cipher+jsonauth.origin_proofMUST existbodyMUST directly carrygroup_cipher_object
Notes:
group.e2ee.sendis the online sending method itself;- It no longer wraps another layer via P4
group.send.
9.5.4 Successful Response
A successful response MUST contain at least:
accepted = truegroup_didmessage_idoperation_idgroup_event_seqgroup_state_versionaccepted_atepochgroup_receipt
The Success Semantics says:
- Group Host has accepted and ordering an MLS ciphertext object;
- It does not automatically mean that all members have successfully decrypted the message.
10. State coupling rules
10.1 General
The coupling between P4 and P6 is completed through business-state changes.
This Profile no longer requires the maintenance of a method-by-method mapping table for group.create -> create and group.add -> add.
owner MUST be known via trusted state observation:
- A certain group has been created at the business layer;
- A member has become
activeat the business level; - A member has become
leftorremovedat the business level.
The status observation method MAY be:
- Internal orchestration of local and Group Host;
- Subscription to
group.state_changed; - Or other equivalent and reliable state observation mechanism.
10.2 Group creation coupling rules
When the owner observes that the following business states are simultaneously true:
- A certain
group_didhas been created; - The creator is yourself;
- There are no
crypto_group_ids attached to this group yet
owner MUST trigger group.e2ee.create once.
10.3 Member joining coupling rules
When the owner observes that the following business states are simultaneously true:
- A certain
member_didis already a member ofactiveof the group in P4; - The member is not currently in the MLS membership;
- The member has
group_key_packageavailable
owner MUST trigger group.e2ee.add once.
This rule also applies to:
group.joingroup.add- Deployment extension invites to join
- Deployment extension approved
In other words, P4’s various service entry points eventually converge to group.e2ee.add at the cryptographic layer.
10.4 Member Removal / Leaving Coupling Rules
When the owner observes that the following business states are simultaneously true:
- An
member_didhas becomeremovedorleftin P4; - The member is currently still in the MLS membership set
owner SHOULD trigger group.e2ee.remove once.
10.5 Message sending rules
group.e2ee.send is not a method that triggers state coupling.
It is an online sending method explicitly initiated by members.
But its business consistency requirements are still tightly tied to P4:
- The sender MUST be a current member of
active; - Sender MUST meet P4
group_policy.permissions.send - The semantics of
group_event_seq,group_state_version, andgroup_receiptin Successful Response follow the definition of group messages in P4.
11. MLS Usage Profile (normative)
11.1 General and external specification references
This chapter defines the restricted use subset and fixed configuration of this Profile for MLS.
The goal of this chapter is not to rewrite the MLS standards, but to provide:
- Which objects and state machine actions of MLS are allowed to be used in v1;
- How these objects are encoded in the online protocol;
- What local status and processing obligations do owner, active member, and Group Host need to bear respectively?
- What are the MLS semantics behind
group.e2ee.create,group.e2ee.add,group.e2ee.remove, andgroup.e2ee.send.
Implement MUST NOT to modify the core algorithm semantics of MLS; but when the default degrees of freedom of the MLS standard library conflict with the v1 restricted rules of this Profile, MUST shall prevail.
Subset of MLS allowed in 11.2 v1
The MLS mainline of this Profile v1 only allows the following objects and actions to enter the interoperability boundary:
KeyPackageAddRemoveCommitWelcomePrivateMessageepochAdvance
In this Profile v1:
commit_b64uMUST correspond to the complete MLSMLSMessage, and its wire format MUST bemls-public-messagewelcome_b64uMUST correspond to MLSWelcomeprivate_message_b64uMUST correspond to MLSPrivateMessage
This Profile v1 does not include the following capabilities into the main interoperability line:
- External Commit
GroupInfo/group_join_infogroup.e2ee.get_join_info- Standalone
accept_welcomeprotocol method - Concurrent submission by multiple controllers
- Member changes initiated by non-owner
Updateas protocol-level mainline action- proposal batching as an interoperability requirement
- ReInit, PSK, Subgroup or custom MLS extensions required as v1 MTI
The MLS library used by the implementation MAY support the above capabilities; but when not explicitly extended for negotiation, MUST NOT bring them into v1 wire protocol interworking.
11.3 MTI suite and fixed algorithm
This Profile v1 MUST implement the following MTI suites:
MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
The corresponding fixed algorithm configuration is as follows:
- KEM / HPKE DH:
DHKEMX25519 - AEAD:
AES-128-GCM - Hash/KDF base:
SHA-256 - Leaf signature:
Ed25519
Additionally, all JSON objects in this Profile that go into proof, AAD, or inner plaintext bindings MUST be encoded using UTF-8 + RFC 8785 JCS. This requirement applies at least to:
- Protected object of
did_wba_binding Group Application Plaintextgroup.e2ee.sendofauthenticated_data- Authenticated binding object submitted by member change
11.4 MLS semantics of group.e2ee.create
group.e2ee.create is only executed after group.create has been accepted by the business layer.
When executing group.e2ee.create, owner's local MLS runtime MUST:
- Verify
creator_key_package - Verify
did_wba_bindingin it - Create a new MLS group state
- Generate new
crypto_group_id - Add owner as the first MLS member
- Form initial
epoch - Establish local persistent state of owner
group.e2ee.create MUST NOT create a new P4 business group separately; it only creates the corresponding initial MLS state for the existing business group.
11.5 MLS Semantics of group.e2ee.add
group.e2ee.add is the only standard entry cryptography mainline in v1.
When executing group.e2ee.add, owner's local MLS runtime MUST:
- Obtain and verify the
group_key_packageof the target member - Verify
KeyPackageanddid_wba_binding - Verify that the target member has become
activeat the business layer - Execute MLS
Addbased on current group state - Generate new
Commit - Generate
Welcomefor new members - Export or construct ratchet tree materials sufficient for bootstrap of new members
- Promote new
epoch - Update owner local group state
Therefore, the main line of standard group cryptography in v1 is:
KeyPackage
→ Add
→ Commit
→ Welcome
→ ratchet_tree
→ new epoch2
3
4
5
6
To reduce implementation ambiguity, v1 stipulates:
commit_b64uMUST be the TLS-serialized raw bytes of the complete MLSMLSMessage;welcome_b64uMUST be the TLS-serialized raw bytes of the MLSWelcomeobject;ratchet_tree_b64uMUST be provided explicitly, and only to new members;welcome-deliveryMUST NOT rely on the library-level optional behavior "Welcome may come with ratchet tree internally".
11.6 MLS Semantics of group.e2ee.remove
When executing group.e2ee.remove, owner's local MLS runtime MUST:
- Verify that the target member has entered
removedorleftat the business layer - Verify that the member is still in the MLS membership set
- Execute MLS
Removebased on the current group state - Generate new
Commit - Promote new
epoch - Update the owner's local group state
- Make the removed members lose the ability to decrypt subsequent messages
The line protocol output for group.e2ee.remove MUST contain at least:
commit_b64ucrypto_group_id_b64uepochgroup_state_ref
11.7 Encryption semantics of group.e2ee.send
When the sender calls group.e2ee.send, its local MLS runtime MUST:
- Verify that you are currently a member of
active - Verify that it meets P4
permissions.send - Construct
Group Application Plaintext - Construct
authenticated_datadefined in Chapter 13 - Use the current MLS group state to encrypt the inner plaintext to MLS
PrivateMessage - Construct
group_cipher_object - Submit the object to the Group Host as
bodyofgroup.e2ee.send
Success with group.e2ee.send simply means:
- Group Host has accepted and ordering an MLS ciphertext object;
- It does not automatically mean that all members have successfully decrypted the message.
11.8 Group message decryption obligations
After the receiving member receives the ciphertext object corresponding to group.e2ee.send, MUST:
- Find the local corresponding MLS group state based on
group_did - Verify that
crypto_group_id_b64uis consistent with local binding - Verify whether
epochis within the acceptable window - Decrypt
private_message_b64uusing local MLS state - Verify
authenticated_data - Parse inner layer
Group Application Plaintext - Only after all checks pass, the message is delivered to the upper layer
If any step fails, the receiver MUST NOT deliver the message to the application layer as a valid group message.
11.9 Local processing obligations for group.e2ee.notice
11.9.1 commit-delivery
When receiving notice_type = "commit-delivery", the receiver's local MLS runtime MUST:
- Decode
commit_b64u - Verify
group_did,group_state_ref,crypto_group_id_b64u,epoch - Apply the commit to the local MLS group state
- Update local current
epoch - Document the necessary
epoch_authenticatoror consistency status if present
11.9.2 welcome-delivery
New member local MLS runtime MUST when receiving notice_type = "welcome-delivery":
- Decode
welcome_b64u - Decode
ratchet_tree_b64u - Verify
group_did,group_state_ref,crypto_group_id_b64u,epoch - Initialize the local MLS group state with
welcome_b64u+ratchet_tree_b64u - Bind this status to local
group_did - Prepare to receive subsequent
commit-deliveryand group messages
Welcome handling is a local behavior specification, not a new JSON-RPC protocol method.
11.10 Local persistent state requirements
In order to ensure achievability across restarts and across notification timings, each participant SHOULD must at least persist the following states.
11.10.1 owner
owner SHOULD be at least persistent:
group_didcrypto_group_id- Current
epoch - Current MLS group state
- The synchronized member set view of the current business layer
add/removeresult reference from the most recent successful application
11.10.2 active member
Ordinary active members SHOULD be at least persistent:
group_didcrypto_group_id- Currently available MLS group state
- Current
epoch - The most recent successfully applied
commit/welcomereference
11.10.3 Group Host
The Group Host SHOULD persist at least:
group_state_versiongroup_event_seqgroup_receipt- Outer binding reference to
crypto_group_id,epoch
By default, the Group Host is not required to persist MLS private state capable of decrypting group messages.
MLS capabilities not supported in 11.11 v1
In addition to the exclusions listed in Section 11.2, this Profile v1 does not support:
- Expose
Updateas a separate protocol-level action - Deliver unbound cryptographic results of
group_state_refvia notice - Rely on MLS library to implicitly and automatically restore missing tree material
- Let non-owner members submit
Committhat changes the membership set - Let the Group Host complete the final MLS validity judgment on behalf of the members
12. Independent notification model
12.1 General
P6 defines independent notifications by yourself:
group.e2ee.notice
It does not reuse P4's group.state_changed to pass Welcome or Commit.group.state_changed of P4 continues to be only responsible for business-state changes;
P6's group.e2ee.notice is specifically responsible for cryptographic result delivery.
12.2 group.e2ee.notice
12.2.1 Semantics
Directly deliver group cryptography-related result objects to a target Agent.
12.2.2 Notification envelope constraints
method = "group.e2ee.notice"meta.profile = "anp.group.e2ee.v1"meta.security_profile = "transport-protected"meta.target.kind = "agent"meta.target.didMUST equal the current notification recipient DIDmeta.sender_didSHOULD be equal togroup_didbodyMUST directly carrye2ee_notice_object
12.3 notice_type = "commit-delivery"
For delivery to current MLS members:
commit_b64u- NEW
epoch - New
epoch_authenticator(if available)
After receiving it, the receiver should process the commit according to the local MLS runtime rules.
12.4 notice_type = "welcome-delivery"
For targeted delivery to new members:
welcome_b64uratchet_tree_b64u- NEW
epoch group_state_ref
The rules are as follows:
welcome_b64uMUST be the TLS-serialized raw bytes of the MLSWelcomeobject;ratchet_tree_b64uMUST be the TLS-serialized raw bytes of the ratchet tree;- This notice MUST NOT be sent to a recipient other than the intended new member;
- The new member MUST use
welcome_b64u + ratchet_tree_b64uto complete local bootstrap.
12.5 Relationship to P4 Notifications
- P4
group.state_changed: only carries business events - P4
group.incoming: Continue to carry group message delivery - P6
group.e2ee.notice: only carries cryptographic notice
In this way, the boundaries between the three are clear and they do not pretend to be each other.
13. Binding, AAD and Authentication Requirements
13.1 Minimum binding set
The following fields MUST enter the authenticated binding scope:
group_didcrypto_group_idgroup_state_version(orgroup_state_ref)policy_hash(if present)meta.sender_didmeta.message_id/meta.operation_idmeta.security_profile = group-e2ee
13.1.1 authenticated_data of authenticated_data
group.e2ee.send When using MLS PrivateMessage, its authenticated_data MUST be the UTF-8 + RFC 8785 JCS encoded byte string of the following JSON object:
{
"content_type": "application/anp-group-cipher+json",
"group_did": "<outer meta.target.did>",
"crypto_group_id_b64u": "<body.crypto_group_id_b64u>",
"group_state_ref": { "...": "..." },
"security_profile": "group-e2ee",
"sender_did": "<outer meta.sender_did>",
"message_id": "<outer meta.message_id>",
"operation_id": "<outer meta.operation_id>"
}2
3
4
5
6
7
8
9
10
13.1.2 Submission binding of group.e2ee.add/remove
When owner generates commit_b64u locally, SHOULD put at least the following semantics into its authenticated binding scope (such as MLS authenticated_data or equivalent context):
{
"group_did": "<outer meta.target.did>",
"crypto_group_id_b64u": "<body.crypto_group_id_b64u>",
"group_state_ref": { "...": "..." },
"subject_method": "group.e2ee.add | group.e2ee.remove",
"member_did": "<body.member_did>",
"epoch": "<body.epoch>",
"security_profile": "group-e2ee",
"sender_did": "<outer meta.sender_did>",
"operation_id": "<outer meta.operation_id>"
}2
3
4
5
6
7
8
9
10
11
All default optional fields MUST be omitted directly, MUST NOT use null, empty string or other placeholder values to replace the omitted fields.
13.2 KeyPackage verification
Before the receiver accepts a KeyPackage for joining the group, MUST:
- Decoding MLS
KeyPackage - Verify that its protocol version and suite meet the requirements of this group
- Verify that it has not expired, been revoked and has not been marked as consumed
- Verify that
leaf_nodeis valid forKeyPackage - Verify the
KeyPackagesignature using the public key inleaf_node.credential - Verify
credential.identity == owner_did - Verify
did_wba_binding - Verify that the leaf signature public key is consistent with
did_wba_binding.leaf_signature_key_b64u
If a KeyPackage has been successfully used once for group.e2ee.add and accepted by the Group Host, implementations MUST NOT will then treat it as valid join material for reuse, unless the deployment explicitly declares a last-resort exception.
13.3 group.e2ee.send Request Verification
Before accepting an group.e2ee.send, the Group Host MUST verify at least:
auth.origin_proofis legalgroup_didexists and can be managed by the current Hostgroup_state_ref.group_didis consistent with the outer targetmeta.sender_didis currently a member ofactivegroup_policy.permissions.sendallows this sender- The
group_cipher_objectfield is complete and in the correct format.
13.4 group.e2ee.add/remove Request Verification
Before the Group Host accepts an group.e2ee.add or group.e2ee.remove, MUST verify at least:
auth.origin_proofis legalmeta.sender_didis currently the groupownergroup_state_ref.group_didis consistent with the outer targetcrypto_group_idis consistent with the current cryptographic binding of the groupmember_didis semantically consistent with the request target- The
commit_b64u(andwelcome_b64u, if present) field format is legal
13.5 group.e2ee.create Request Verification
Before accepting an group.e2ee.create, the Group Host MUST verify at least:
auth.origin_proofis legalmeta.sender_didis the current business layer ownercreator_key_package.owner_didis consistent withmeta.sender_didcrypto_group_id_b64u,epoch, andgroup_state_reffields are complete- There is currently no accepted MLS initial status for this group.
14. ordering, Epoch, receipt and forks
14.1 ordering Responsibilities
- P4 business operation and
group.e2ee.sendenter the group event ordering link from the Group Host; group.e2ee.create/add/removeis a cryptographic control action bound to the existing business state, MUST NOT create a new P4group_state_versionindependently;- Relevant cryptographic results are delivered via
group.e2ee.notice.
14.2 epoch processing
epochMUST expressed as a decimal string in the outer object;- The receiver MUST reject application messages that are obviously old and outside the tolerance window;
- The implementation MAY reserve a finite old epoch decryption window for delayed messages, but MUST set an upper limit.
14.3 epoch_authenticator
If the package can export epoch_authenticator or equivalent consistency token, implement SHOULD in:
group_cipher_objectgroup.e2ee.noticegroup_receipt(if applicable)
Expose this value so that members can do consistency checks.
14.4 Group receipt
group_receiptcontinues to be generated by Group Host;- For
group.e2ee.send,group_receiptis still the standard return field; - For
group.e2ee.add/remove/create,group_receiptMAY appear as additional information ofgroup.e2ee.notice, which is used to anchor the cryptographic results to the corresponding business state; - If
group_receiptcarriesproof, its proof syntax, protected document and verification steps MUST reuse the shared Object Proof Profile of P4 Section 7.9 and P1 Appendix B.
14.5 Fork detection
If a member observes:
- The same
group_didcorresponds to multiple irreconcilablecrypto_group_id - Inconsistent
epoch_authenticatorin the same or adjacent state - There are different valid
Commits in the same context
Then implement SHOULD to mark the group as fork-suspected and suspend the sending of new group messages until the status is reconfirmed.
15. Flow Diagrams
15.1 Group establishment process
sequenceDiagram
participant C as Creator (owner)
participant H as Group Host
C->>H: group.create
H-->>C: business creation succeeded (group_did, group_state_version)
C->>H: group.e2ee.create
H-->>C: MLS initialization succeeded (crypto_group_id, epoch)2
3
4
5
6
7
8
15.2 Self-service joining process (open-join)
sequenceDiagram
participant B as New Member
participant H as Group Host
participant O as owner
B->>H: group.join
H-->>B: business join succeeded (active)
H-->>O: group.state_changed(member-activated)
O->>H: group.e2ee.add
H-->>B: group.e2ee.notice(welcome-delivery)
H-->>ActiveMembers: group.e2ee.notice(commit-delivery)2
3
4
5
6
7
8
9
10
11
15.3 Direct addition process (admin-add)
sequenceDiagram
participant A as admin
participant H as Group Host
participant O as owner
participant B as New Member
A->>H: group.add
H-->>A: member addition succeeded (target active)
H-->>O: group.state_changed(member-activated)
O->>H: group.e2ee.add
H-->>B: group.e2ee.notice(welcome-delivery)
H-->>ActiveMembers: group.e2ee.notice(commit-delivery)2
3
4
5
6
7
8
9
10
11
12
15.4 Removal / Leaving Process
sequenceDiagram
participant X as operator/member
participant H as Group Host
participant O as owner
X->>H: group.remove / group.leave
H-->>X: business state changed (removed/left)
H-->>O: group.state_changed(member-removed/member-left)
O->>H: group.e2ee.remove
H-->>RemainingMembers: group.e2ee.notice(commit-delivery)2
3
4
5
6
7
8
9
10
15.5 Group message sending process
sequenceDiagram
participant S as Sending Member
participant H as Group Host
participant M as Other Members
Note over S: Locally construct Group Application Plaintext
Note over S: Locally generate PrivateMessage and group_cipher_object
S->>H: group.e2ee.send
H-->>S: accepted + group_event_seq + group_receipt
H-->>M: group.incoming2
3
4
5
6
7
8
9
10
16. Security and Policy Requirements
16.1 Host does not replace member encryption permissions
The Group Host MUST NOT be presumed to have access to group plaintext merely because it is responsible for ordering.
16.2 Relationship between origin_proof and MLS member signatures
auth.origin_proofproves "who requested this action at the application layer";- MLS member signature/commit object proves "which cryptographic group member produced this ciphertext or commit".
Both MUST NOT replace each other.
16.3 Group policy takes precedence over pure cryptography capabilities
Even if a member "can generate some kind of Proposal/Commit/PrivateMessage" from a pure MLS perspective, whether the application layer allows its execution is still MUST determined by P4's group_policy.
16.4 Sending permission of group.e2ee.send
Only if sender:
- Currently a member of
active; - Meet
group_policy.permissions.send;
Group Host can only accept group.e2ee.send.
16.5 owner as sole controller
As long as v1 is not extended to the multi-controller model, then:
- Only owner can call
group.e2ee.create/add/remove - admin cannot call these methods directly
- The business layer actions of admin only affect the P4 status, and are eventually implemented to MLS by owner
17. Profile specific errors (recommended)
On the premise of following the ANP Core public error model, this Profile recommends the following anp_code:
code | anp_code | Meaning |
|---|---|---|
| 5000 | group.e2ee.key_package_not_found | No available KeyPackage found |
| 5001 | group.e2ee.invalid_key_package | KeyPackage is invalid |
| 5002 | group.e2ee.did_binding_invalid | did:wba binding verification failed |
| 5003 | group.e2ee.controller_required | The current caller is not an MLS controller |
| 5004 | group.e2ee.state_not_ready | The corresponding business state is not ready yet |
| 5005 | group.e2ee.epoch_conflict | epoch conflict |
| 5006 | group.e2ee.crypto_group_mismatch | The binding of group_did and crypto_group_id is inconsistent |
| 5007 | group.e2ee.private_message_invalid | The group message ciphertext object is invalid |
| 5008 | group.e2ee.commit_invalid | The Commit object is invalid |
| 5009 | group.e2ee.welcome_invalid | The Welcome object is invalid |
| 5010 | group.e2ee.fork_suspected | Potential fork detected |
| 5011 | group.e2ee.notice_type_unsupported | Unsupported E2EE Notice type |
| 5012 | group.e2ee.key_package_consumed | KeyPackage has been consumed and cannot be reused |
18. Minimum Interoperability Requirements
An implementation conforming to this Profile MUST support at least:
MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519- MLS Usage Profile Restricted Use Subset as defined in Chapter 11
group.e2ee.publish_key_packagegroup.e2ee.get_key_packagegroup.e2ee.creategroup.e2ee.addgroup.e2ee.removegroup.e2ee.send- did:wba binding verification
- Service-scoped target model of
group.e2ee.create group.e2ee.add/remove/send’s group-addressed target model- Agent-addressed notification model of
group.e2ee.notice - owner as sole MLS controller
- Drive
create/add/removethrough P4 business state group.e2ee.senddirectly sends MLS ciphertext without being packaged bygroup.sendgroup.e2ee.noticeis used forwelcome-deliveryandcommit-delivery- Explicit delivery of
ratchet_tree_b64uinwelcome-delivery group.incomingcontinues to receive notifications as group messages- Only the message side enters
PrivateMessage - The business semantics of
group_receipt,group_state_version, andgroup_event_seqare consistent with P4
This Profile v1 does not require:
- External Commit
group_join_infogroup.e2ee.get_join_infoaccept_welcome- Standalone
get_statemethod Updateas protocol-level mainline action- Concurrent submission by multiple controllers
19. Example
19.1 group.e2ee.publish_key_package Example
{
"jsonrpc": "2.0",
"id": "req-gk-001",
"method": "group.e2ee.publish_key_package",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.group.e2ee.v1",
"security_profile": "transport-protected",
"sender_did": "did:wba:a.example:agents:alice:e1_<fingerprint>",
"target": {
"kind": "service",
"did": "did:wba:a.example"
},
"operation_id": "op-gk-001",
"created_at": "2026-03-29T16:00:00Z"
},
"body": {
"group_key_package": {
"key_package_id": "kp-001",
"owner_did": "did:wba:a.example:agents:alice:e1_<fingerprint>",
"suite": "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519",
"mls_key_package_b64u": "BASE64URL_KEYPACKAGE",
"did_wba_binding": {
"agent_did": "did:wba:a.example:agents:alice:e1_<fingerprint>",
"verification_method": "did:wba:a.example:agents:alice:e1_<fingerprint>#key-1",
"leaf_signature_key_b64u": "BASE64URL_ED25519_LEAF_PK",
"issued_at": "2026-03-29T16:00:00Z",
"expires_at": "2026-04-29T16:00:00Z",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"created": "2026-03-29T16:00:00Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:wba:a.example:agents:alice:e1_<fingerprint>#key-1",
"proofValue": "z..."
}
},
"expires_at": "2026-04-30T00:00:00Z"
}
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
19.2 group.e2ee.create Example
{
"jsonrpc": "2.0",
"id": "req-gec-001",
"method": "group.e2ee.create",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.group.e2ee.v1",
"security_profile": "group-e2ee",
"sender_did": "did:wba:a.example:agents:alice:e1_<fingerprint>",
"target": {
"kind": "service",
"did": "did:wba:groups.example"
},
"operation_id": "op-gec-001",
"created_at": "2026-03-29T16:10:00Z"
},
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_DIGEST:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1774797000;expires=1774797060;nonce=\"n-create\";keyid=\"did:wba:a.example:agents:alice:e1_<fingerprint>#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
},
"body": {
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_ref": {
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_version": "1",
"policy_hash": "sha-256:abcd"
},
"suite": "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519",
"creator_key_package": {
"key_package_id": "kp-owner-001",
"owner_did": "did:wba:a.example:agents:alice:e1_<fingerprint>",
"suite": "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519",
"mls_key_package_b64u": "BASE64URL_KEYPACKAGE",
"did_wba_binding": { "agent_did": "did:wba:a.example:agents:alice:e1_<fingerprint>" }
},
"crypto_group_id_b64u": "BASE64URL_GROUPID",
"epoch": "0"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
19.3 group.e2ee.add Example
{
"jsonrpc": "2.0",
"id": "req-gea-001",
"method": "group.e2ee.add",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.group.e2ee.v1",
"security_profile": "group-e2ee",
"sender_did": "did:wba:a.example:agents:alice:e1_<fingerprint>",
"target": {
"kind": "group",
"did": "did:wba:groups.example:team:dev:e1_<fingerprint>"
},
"operation_id": "op-gea-001",
"created_at": "2026-03-29T16:20:00Z"
},
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_DIGEST:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1774797600;expires=1774797660;nonce=\"n-add\";keyid=\"did:wba:a.example:agents:alice:e1_<fingerprint>#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
},
"body": {
"member_did": "did:wba:b.example:agents:bob:e1_<fingerprint>",
"group_state_ref": {
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_version": "2",
"policy_hash": "sha-256:efgh"
},
"group_key_package": {
"key_package_id": "kp-bob-001",
"owner_did": "did:wba:b.example:agents:bob:e1_<fingerprint>",
"suite": "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519",
"mls_key_package_b64u": "BASE64URL_KEYPACKAGE",
"did_wba_binding": { "agent_did": "did:wba:b.example:agents:bob:e1_<fingerprint>" }
},
"crypto_group_id_b64u": "BASE64URL_GROUPID",
"epoch": "1",
"commit_b64u": "BASE64URL_MLSMESSAGE_COMMIT",
"welcome_b64u": "BASE64URL_WELCOME",
"ratchet_tree_b64u": "BASE64URL_RATCHET_TREE"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
19.4 group.e2ee.send Example
{
"jsonrpc": "2.0",
"id": "req-ges-001",
"method": "group.e2ee.send",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.group.e2ee.v1",
"security_profile": "group-e2ee",
"sender_did": "did:wba:a.example:agents:alice:e1_<fingerprint>",
"target": {
"kind": "group",
"did": "did:wba:groups.example:team:dev:e1_<fingerprint>"
},
"operation_id": "msg-ges-001",
"message_id": "msg-ges-001",
"content_type": "application/anp-group-cipher+json",
"created_at": "2026-03-29T16:30:00Z"
},
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_DIGEST:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1774798200;expires=1774798260;nonce=\"n-send\";keyid=\"did:wba:a.example:agents:alice:e1_<fingerprint>#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
},
"body": {
"crypto_group_id_b64u": "BASE64URL_GROUPID",
"epoch": "1",
"private_message_b64u": "BASE64URL_PRIVATEMESSAGE",
"group_state_ref": {
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_version": "2",
"policy_hash": "sha-256:efgh"
},
"epoch_authenticator": "BASE64URL_AUTH"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
19.5 group.e2ee.notice example (welcome-delivery)
{
"jsonrpc": "2.0",
"method": "group.e2ee.notice",
"params": {
"meta": {
"profile": "anp.group.e2ee.v1",
"security_profile": "transport-protected",
"sender_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"target": {
"kind": "agent",
"did": "did:wba:b.example:agents:bob:e1_<fingerprint>"
},
"operation_id": "op-notice-001",
"created_at": "2026-03-29T16:21:00Z"
},
"body": {
"notice_id": "en-001",
"notice_type": "welcome-delivery",
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_ref": {
"group_did": "did:wba:groups.example:team:dev:e1_<fingerprint>",
"group_state_version": "2",
"policy_hash": "sha-256:efgh"
},
"crypto_group_id_b64u": "BASE64URL_GROUPID",
"epoch": "1",
"subject_did": "did:wba:b.example:agents:bob:e1_<fingerprint>",
"welcome_b64u": "BASE64URL_WELCOME",
"ratchet_tree_b64u": "BASE64URL_RATCHET_TREE"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
20. Registry Placeholder
Subsequent versions of this standard SHOULD establish the following registry:
- Group E2EE suite registration form;
- did:wba Binding certification type registry;
group.e2ee.notice.notice_typeregistry;- Group E2EE error code registry.
21. Reference Implementation Notes (Non-Normative)
When implementing this Profile, the implementer should regard it as:
- MLS control layer that works closely with
anp.group.base.v1; - A group E2EE model in which the owner is responsible for member change control and members are responsible for sending ordinary messages;
- Convergent scheme that drives
create/add/removethrough state changes; - The solution to complete the delivery of
commitandwelcomethrough independentgroup.e2ee.notice.
For future versions, further consideration may be given to:
- admin as alternate MLS controller;
- Multi-controller collaboration;
- External Commit is reintroduced as an optional extension;
- More detailed fork recovery mechanism;
- Post-Quantum Swarm Kit.