Meshline
English translationDownload Markdown

The Simplified Chinese text is authoritative.

Group Model and Keys

Group hosting protocol · Group core objects

Fixed Hosting

Each group selects a hosting relay at creation, with no later migration or automatic takeover. The relay is authoritative for current state, member projections, event order, and key-epoch order; clients retain long-term message history and their own secrets. Group state uses neither account home relays nor DHT.

Role Permissions

Member roles are owner, administrator, or member. Each group always has exactly one owner.

Roles express in-group business permissions:

Operation owner administrator member
Send, synchronize, and subscribe Yes Yes Yes
Change in-group nickname Self only Self only Self only
Create invitations Yes Yes Determined by invite_policy
View invitations All All Own invitations
Revoke invitations All Own invitations Own invitations
Approve join applications Yes Yes No
Change properties/roles, transfer ownership, or close Yes No No
Remove members Any non-owner Ordinary members only No
Ban accounts Any non-owner Ordinary members or nonmembers No
Unban Yes Yes No
Approve member key resets Any member, including self Other ordinary members only No
Rotate client group secret Yes No No
Leave voluntarily Transfer ownership first Yes Yes

Relays MUST use roles current at execution. Events or list results prove only prior acceptance, not continued future administrative authority.

Client and Relay Secrets

Groups use two random 32-byte secrets, both from cryptographically secure sources:

  • client_group_secret is shared by current members and MUST NOT be obtained by the hosting relay.
  • relay_epoch_secret is independently generated by the host for each epoch.

Key Epoch Advancement

epoch starts at 0 and strictly increases within the group, without requiring continuity. Creation, application approval, leaving, removal, member-key-reset approval, client-secret rotation, and relay-initiated rotation create new epochs. A ban batch containing current members removes them and creates one epoch; a batch containing only nonmembers does not advance keys. Property/role changes, ownership transfers, unbanning, and ordinary messages do not advance epochs.

Client Secret Commitment

Calculate the commitment using Network-bound JSON inputs:

client_secret_commitment =
  network_bound_json_hash({
    $type: "meshline.group.client_secret.commitment",
    group_id,
    secret: base64url(client_group_secret)
  })

Store the initial commitment at creation; only successful client-secret rotation replaces it. Application approval, membership changes, and relay-secret rotation may advance epoch while retaining the current commitment.

The relay does not know the client secret, so cannot recompute its commitment or confirm what a client secret box contains. Members receiving boxes perform those cryptographic checks. For join-approval and member-key-reset-approval requests, the relay checks the supplied commitment against the current one and rejects mismatches.

Group Secret Boxes and Wrapping Rules

GroupSecretBox

Field Type Required Semantics and constraints
alg string Yes Fixed as X25519-HKDF-SHA256-AES256GCM; unsupported or mismatched algorithms MUST cause box rejection
enc string Yes Sender-generated ephemeral 32-byte X25519 public key for this box, unpadded base64url
sealed_secret string Yes Concatenated 12-byte AES-GCM nonce, 32-byte ciphertext, and 16-byte tag, unpadded base64url; decryption MUST yield exactly 32 secret bytes

Both client and relay secret boxes use GroupSecretBox, wrapping their respective 32-byte secrets as follows:

  1. Generate an ephemeral X25519 pair per box and compute a shared secret from ephemeral private key and target public key. The recipient uses its target private key and box enc to compute the same secret. Both MUST reject all-zero results under X25519 validation before wrapping or unwrapping proceeds.
  2. Use that shared secret as HKDF-SHA-256 IKM, SHA-256 of UTF-8 Meshline/keybox-salt/v1 as salt, and the box type's network-bound JSON input below as info to derive a 32-byte wrapping key.
  3. Encrypt the secret with AES-256-GCM using that key, an independently generated random 12-byte nonce, and AAD identical to info; package as sealed_secret.

Ephemeral private keys and nonces MUST come from cryptographically secure random sources. The two box types MUST use their own contexts and MUST NOT be interchanged.

Client Secret Boxes

KDF info and AES-GCM AAD use this network-bound object:

{
  "$type": "meshline.group.client_secret_box.aad",
  "group_id": "grp_...",
  "account": "neo:860833102:...",
  "member_encryption_public_key": "base64url...",
  "client_secret_commitment": "sha256:..."
}

Clients MUST determine target account and member_encryption_public_key under the method. For new-member approval or public-key reset, the approver first verifies the complete signed member request and certificate; account comes from the verified certificate, and public key from the complete signed request. Failed chain, approver-permission, request-signature, or account-binding checks MUST prevent secret wrapping or upload.

For requests containing client boxes, the relay checks target accounts and coverage as required by the method, and each box's algorithm and encoding lengths. Without member private keys, it cannot unwrap boxes or verify plaintext, AAD targets, or client-secret commitments.

On decryption, recipients MUST derive the public key from the private key corresponding to the wrapping target and reconstruct AAD from expected context. Historical boxes use their original target public keys. Failed AEAD or post-decryption commitment checks MUST reject the box.

For rotation preparation, see group.secret.rotation.prepare. Member public-key changes do not rewrap historical client boxes; those still require the corresponding old private keys.

Client boxes do not bind epoch; an unchanged client secret and target member key allow box reuse across epochs. Boxes are outer delivery material of write methods, excluded from signed events. The submitting owner or administrator MUST ensure the secret and target context are correct.

Relay Secret Boxes

KDF info and AES-GCM AAD use this network-bound object:

{
  "$type": "meshline.group.relay_secret_box.aad",
  "group_id": "grp_...",
  "account": "neo:860833102:...",
  "device_id": "dev_...",
  "epoch": 7
}

The relay determines calling account, device ID, and device encryption public key from the group.key.sync device session and wraps the relay secret accordingly. Recipients reconstruct AAD using their own device context.

Group Application Secret Derivation

After obtaining both secrets and validating the commitment, clients derive a 32-byte group application secret:

epoch_application_secret = HKDF-SHA-256(
  IKM  = client_group_secret || relay_epoch_secret,
  salt = SHA-256(UTF8("Meshline/group-epoch-salt/v1")),
  info = network_bound_json_bytes({
    $type: "meshline.group.epoch_secret",
    group_id,
    epoch,
    client_secret_commitment
  }),
  L = 32
)

Concatenating fixed-length shared secrets before HKDF is consistent with the fixed-length combination described in RFC 9954 Section 3.3.

Security Boundaries

The relay alone holds only relay_epoch_secret; members hold the client secret and relay secrets sent to their devices. A relay may deny service, prune bounded history, or hide material from different devices, but cannot decrypt using only its own data. Collusion with any party still holding the client secret allows combination with retained relay secrets for corresponding epochs to derive application secrets and decrypt those messages.

After membership or device access ends, relay-secret rotation can prevent obtaining new message keys, but cannot repair disclosure of the client secret itself.

If client-secret disclosure is known or suspected, the owner is advised to rotate it, providing new boxes only to currently trusted members. If a current member is no longer trusted, the owner MUST remove it first, generate a fresh client secret, and complete rotation. After activation, parties without it cannot derive later application secrets. Rotation cannot restore confidentiality to disclosed or decrypted history or stop currently authorized members from colluding with the relay.

To exclude collusion by a departed or removed member, the owner MUST generate a fresh secret and commitment after membership ends and prepare rotation anew; continuing an earlier preparation does not achieve that exclusion.

Banning removes current membership and prevents rejoining; secret rotation follows the same rules as removal.

A new device's historical starting point is also only a relay-access boundary. If it obtains old ciphertext and relay secret for the same epoch elsewhere, the protocol cannot prevent decryption.

This protocol claims neither forward secrecy nor post-compromise security.