Internet-Draft PQST Cohort November 2026
Henry Expires 6 May 2027 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-henry-pqst-cohort-00
Published:
Intended Status:
Experimental
Expires:
Author:
C. Henry

The Cohort Layer of Post-Quantum Secure Transport (PQST)

Abstract

This document specifies the cohort layer of Post-Quantum Secure Transport (PQST). With it, PQST provides independently migrating and recoverable post-quantum sessions within a persistent cohort authorization context. A cohort member's sessions move, sleep, recover and re-key on their own, and none of those events by itself requires a change of the cohort's membership. One sequencer commits the membership, the policy, and a membership epoch together with that epoch's key, and only on security events; members receive them inside their pairwise sessions, keep them through partitions, and return after dormancy or a restart without readmission, unless they were away longer than the group's expiry. This version specifies the group's control plane: membership, policy, reachability and member discovery. It describes, as the direction of the next version, a group data plane under keys derived from the epoch key, which would give the members one secure session among themselves.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 6 May 2027.

▲

Table of Contents

1. Introduction

1.1. The Cohort

A PQST session [PQST] survives the loss of every path, dormancy and the restart of either endpoint, and resumes with a fresh post-quantum exchange as the same session. The cohort applies the same idea one level up: the cohort is to its members' sessions what a session is to its paths. A member may change paths, go dormant, re-anchor, restart, or return through another gateway of the group, and the cohort exists unchanged. Its state advances only on security events: admission, removal, revocation and scheduled rotation.

Two consequences are emphasized here due to their divergence from MLS and IPsec. A removal from the cohort closes that member's sessions with the sequencer; it does not close that member's pairwise sessions with other members. A re-anchor, a restart or a path change of a member's session does not advance the membership epoch.

The purpose of the layer is a group whose members hold a unified session relative to each other: one membership, one policy, one epoch and, in the data plane this version leaves for the next, one group secret under which members communicate. Such a group can outlive its infrastructure. Members cut off from the sequencer keep their last epoch and go on, and when the partition heals they return to the current epoch by the ordered acceptance of Section 5.1, with no histories to merge; the sequencer's commits are the only history. This is the setting PQST is designed for: disconnected, intermittent and limited networks, radio nets among them, where a group service that dies with its server is of no use.

1.2. Relationship to PQST

The cohort layer is an upper layer of [PQST] and changes nothing in it.

  • It runs on the reserved stream STREAM_COHORT inside each member's pairwise session with the sequencer.

  • What must arrive travels as protocol objects, with the delivery, versioning and acknowledgement of Section 19.3 of [PQST].

  • The sequencer is a gateway group's identity (Section 16.9 of [PQST]), so a member's session to it is portable across the group's gateways.

  • Every member session requires identity proof on re-anchor (Section 16.3.3 of [PQST]).

The codepoints this document uses are reserved for it in Section 26 of [PQST]: object kinds 0x10 to 0x1F, the stream 0xE0, capability bit 0, packet type 3, and the derivation labels beginning "group ". The group data plane, when it is specified, will be an extension in the sense of Section 21 of [PQST]: a packet type enabled by a capability bit, which a pairwise endpoint that does not implement it drops without a trace.

The reader is assumed to know [PQST]. Section numbers without a document name refer to this document; a reference into PQST is written "Section N of [PQST]".

1.3. Status of This Version

This version specifies the control plane (Sections 3 to 12): what the reference implementation does and what the cohort simulator has exercised (Section 17). It carries no group data. Every datagram between members travels in a pairwise session between them, and the epoch key protects only the group's own control (Section 6). Section 13 describes the group data plane the next version is intended to add, and lists the questions that remain open; it is informative.

Scope of this version. This document specifies a sequencer-managed membership, policy-distribution, reachability and discovery control plane for identities that communicate over independently authenticated PQST sessions. It establishes no native multiparty encrypted channel: member-to-member application traffic travels in ordinary pairwise PQST sessions, or in a transport specified elsewhere. The membership epoch key serves the control plane's proof of possession and does not, by itself, authenticate any sender's application data. The group data plane of Section 13 is an informative design whose cryptographic constructions are preliminary; its packet format, replay semantics, sender authentication and confidentiality properties are not conformance requirements of this version.

1.4. Relationship to Existing Work

  • MLS ([RFC9420]) lets a group agree its keys among its members, without a trusted party for confidentiality. The cohort layer does not: a sequencer the members trust delivers the key, and post-compromise security comes from rotation, at once on removal. A deployment without a trusted sequencer would use MLS for the group key, with the sequencer as its delivery service; everything else in this document would stand.

  • G-IKEv2 ([RFC9838], which obsoletes GDOI) distributes group keys from a key server over IKEv2. The cohort layer has the same shape, a key server over authenticated pairwise channels, with two differences. The pairwise channels are PQST sessions, so a member's dormancy, restart or movement is not an event for the group. And the group itself has continuity rules (Section 3, Section 8 and Section 10) for members cut off from the server.

  • TESLA ([RFC4082]) gives source authentication from hash chains with delayed key disclosure. Section 13 considers it for broadcast flows of the data plane.

1.5. Applicability

Three statements bound what this document claims.

  • A deployment gets one history, CG2, only if it supplies the authority of Section 4: a store with the properties that section lists, by a consensus or transactional system of the deployment's choosing. This document specifies those properties and includes no such system; the reference models one.

  • The cohort's continuity is the continuity of its members' pairwise sessions to the sequencer, with the limits [PQST] states for them: a session that comes back as a new session after a lost race on a slow link is a new session here too, bound to the cohort by its first REPORT.

  • This version is a control plane. It gives a group no native channel, no roster and no sender authentication among members; member-to-member traffic is pairwise PQST, and the group data plane of Section 13 is a direction, not a specification.

1.6. Conformance

An implementation conforms to the cohort control plane of this version if it implements, as this document specifies: the three objects COHORT, GROUP_KEY and POLICY with their encodings (Section 5), acknowledging and ignoring ROSTER and MEMBER_EVENT; the four frames REPORT, LOCATE, LOCATE_RESP and EPOCH_PROOF with their fixed sizes (Section 6, Appendix A); the acceptance procedure of Section 5.1, with the persisted high-water marks and the two conflicts; standing confirmed only by an answer to the member's own report on the same session and measured from the report's sending, and its lapse (Section 8 and Section 10); the member states, the membership lookup on return and the one close reason per cause (Section 7); the duplicate-session rule and the identifier order (Section 9); the reporting of Section 11; and the rule that the epoch key is kept in memory only, never persisted, and protects no application data (Section 4 and Section 7).

A sequencer implementation conforms if, in addition, it commits as Section 8 says against an authority with the properties of Section 4 and issues nothing it has not committed.

Conformance does not include the group data plane of Section 13, a roster service, discovery policy beyond the closed default, or any consensus system; Section 17 reports what the reference implements against this list.

1.7. Structure of This Document

  • Section 1.5 is the applicability of this document and Section 1.6 its conformance clause.

  • Section 2 is the terminology.

  • Section 3 is the scope and the layer's four invariants.

  • Sections 4 to 12 are the control plane: roles and state, objects, frames, member states, epochs and delivery, duplicate sessions, partitions, services and parameters.

  • Section 13 is the intended data plane (informative).

  • Sections 14 to 17 are the security, privacy, IANA and implementation status sections.

  • Appendix A collects the wire formats; it is generated from Section 5, Section 6 and Section 16.

2. Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

The terms of [PQST] are used as defined there: session, path, generation, re-anchor, FRESH, DORMANT, RECOVERING, ESTABLISHED, protocol object, gateway group, transport-class and security-class events. In addition:

The membership epoch is distinct from everything that changes keys inside a member's sessions, which this document calls the session's own key changes: the epochs of a PQST session (Section 14 of [PQST]) and its generations (Section 16 of [PQST]).

Table 1
Session epochs and generations Membership epoch
Governs one session's traffic keys and replay state the authorized members and the cohort-wide policy
Advances on a key update (epoch) or a re-anchor after recovery, migration or a scheduled ratchet (generation) a commit: a removal, a forced or scheduled rotation
Scope one session between two endpoints one logical context shared by all members
Effect of a change none on any other session or member delivered to every ACTIVE member

3. Scope and Invariants

The cohort is to its members' sessions what a session is to its paths (Section 3 of [PQST]). The pairwise layer absorbs transport-class events inside the session, and the cohort layer absorbs session-class events inside the group. A cohort member may change paths, go dormant, re-anchor, restart or return through another gateway of the group while the cohort exists unchanged. Cohort state advances only on security-class events: admission, removal, revocation and scheduled rotation.

This version of the cohort layer is membership, policy, reachability and member discovery, run by one sequencer over the members' pairwise sessions to it, with one epoch key delivered to members for the authentication of group control. It carries no data: every datagram of a cohort travels in a pairwise session, and the epoch key encrypts nothing. The group data plane is the subject of Section 13.

The layer runs as an upper layer on the stream STREAM_COHORT = 0xE0 that [PQST] reserves for it (Section 16) inside each member's pairwise session with the sequencer. A member's session with the sequencer serves one cohort: the member names the cohort in its first REPORT on the session (Section 6), the first COHORT object delivered on it, which must agree with that name, fixes the session's cohort (Section 5.1), every later object and frame on the session belongs to that cohort, an object naming another cohort_id is refused, and a member of several cohorts of one sequencer holds a session per cohort. REPORT carries the cohort identifier, because a session is bound to no cohort until its first report; GROUP_KEY, POLICY and LOCATE carry none, because they travel only after that binding, on a session that serves one cohort; EPOCH_PROOF, which travels between members who may share more than one cohort, carries one (Section 6).

Whatever arrives travels as a protocol object of Section 19.4 of [PQST], in the kinds of Section 5, with the delivery, versioning and acknowledgement that the object mechanism provides; whatever may be lost travels as plain stream data, in the frames of Section 6. Members do not run the cohort protocol with each other in this version except the EPOCH_PROOF frame; member-to-member sessions are ordinary pairwise sessions whose addresses the discovery service supplies (Section 11). No capability bit is negotiated: a member and its sequencer are provisioned with each other's identities as any two peers are (Section 9.1 of [PQST]), and the stream is reserved.

The four invariants.

4. Roles and State

4.1. What the Sequencer Stores

The sequencer is the gateway group's identity (Section 16.9 of [PQST]): one replicated identity key, reachable through any gateway of the group, so that a member's session to the sequencer is portable across gateways like any session (Section 16.9 of [PQST]). Two kinds of state meet in it, and the authority of Section 4.2 holds only the first.

  • Authoritative, replicated: the cohort_id (16 octets, chosen at creation); the member list, for each member its identity fingerprint, its member_index and whether it is REMOVED and awaiting its drop; the epoch (32-bit, starting at 1) and the current epoch key (32 octets); the policy and its version; and the revision, the commit identifier and the term of Section 4.2. A commit is durable in that state before anything of the new epoch leaves the sequencer (Section 8).

  • Observed, held by the gateway that serves the member: the session the member last used and the sessions it holds; its latest REPORT, the addresses it named and the order of its reports; the time its session went DORMANT and the SUSPENDED and EXPIRED states that timers over that session produce (Section 7); what has been issued to it on each session; and the discovery answers made from its report (Section 11). None of this is a commit or passes through the authority; a deployment that replicates it among its gateways does so by means of its own, outside the authority; and an observation changes the authoritative state only through a commit a gateway makes on its own account, the drop at a rotation of a member it holds EXPIRED (Section 8).

The sequencer is the only source of the objects of Section 5; a member never forwards one.

4.2. The Authority

The replicated state is an authority (Section 2) that admits one commit at a time. The deployment MUST provide it with the following properties, by a consensus or transactional system of its choosing (Section 14).

  1. A commit is a conditional, atomic transaction that names the revision it succeeds and the term under which the gateway writes. The authority applies it whole or not at all, only while that revision is the latest and that term is current. A write under a superseded term is refused however late it arrives, so that a gateway that has lost its authority cannot commit, whatever it believes.

  2. An acknowledgement means the commit is durable under the deployment's fault model and cannot be superseded by an earlier or a conflicting commit.

  3. A read made for a decision that grants or restores standing returns the latest commit (Section 10), and a gateway MUST have established the currency of the state it issues from. The mechanisms differ in what they establish:

    • A fenced lease from the authority establishes currency for its validity, when the authority commits nothing conflicting while the lease holds.

    • A linearizable read establishes currency at its linearization point only, and any interval a deployment allows between such a read and an issuance is a staleness allowance, not currency, which the deployment MUST add to the revocation exposure it states (Section 12 and Section 14).

    • Past either, a lease's validity or a read's allowance, the gateway does not know, however current its last read was.

  4. The authority keeps the commit identifier of every revision for the recovery horizon of the deployment, so that a gateway can resolve an operation whose acknowledgement it lost by its identifier at any revision, after later commits too. The lookup has three outcomes:

    • the identifier found: the operation committed;

    • not found, with the whole history back to the revision the operation would have taken examined: the operation not committed;

    • unknown: when the retained history does not reach that revision, or the authority does not answer.

  5. A committed operation is never retried, even by a gateway that has meanwhile lost its term. An unknown outcome is never taken for a failure, and in particular never licenses the operation again under a new identifier, which for a rotation would mint a second key for one epoch. A retry is the same transaction: the same commit identifier, the same predecessor revision and the same successor, under the gateway's current term. The authority MUST refuse a commit identifier presented with another predecessor or another successor, or resolve it to the one record it holds for that identifier, so that a retry, whatever term it is made under, can never become a second logical operation.

  6. A lease held in a gateway's memory is a belief, not authority; only the authority's acceptance of the transaction is.

  7. A gateway begins a term, at its grant or at its own restore after a crash, by reading the authority's latest revision and continuing from that record. It commits nothing under the term before that read, so that its first write names a current predecessor and a refusal can mean only one thing. A term is never resumed: a restored gateway is granted a new one, so that its own writes from before the crash, under the old term, are refused however late they arrive.

  8. A gateway without current authority serves members' sessions and defers commits (Section 10).

4.3. What a Member Stores

A member holds what the sequencer last told it: its COHORT object, the epoch key, the policy; and the sessions it has to the sequencer. It keeps the epoch key in memory only and MUST NOT persist it; it MAY persist the policy body, under the protection its deployment gives it, and need not. What it holds of either after a restart it says in its REPORT, the epoch of the key and the version of the policy body, each 0 when it holds none (Section 6.1), and the sequencer issues what the report lacks (Section 8); the object layer's delivery of a key or a policy before the restart implies nothing about what the member holds after it (Section 19.3.4 of [PQST]). It MUST persist its freshness state, the cohort identity with the highest epoch and the highest policy_version it has accepted (Section 5.1), before it acts on a newer one, so that a restart cannot take it back past them. After a restart it holds no key, and no policy unless it persisted the body, and says so (Section 8); it applies no object naming an epoch or a policy version older than its persisted state, and takes the current key or policy issued to it again, under a new object version, for what it is: the value for an epoch or a version it has already accepted, neither a rollback nor a conflict (Section 5.1). Without that state, on a first start or after a record lost or not matching the cohort identity, it accepts what the sequencer delivers and is protected only by the sequencer's own freshness (Section 10). A member's cohort state changes only when an object arrives or its session to the sequencer is closed by a security-class reason (Section 7); the metric of CG1 counts exactly these changes.

4.4. Session Cohort Context

Session cohort context. In this version a member-sequencer session carries the control state of exactly one cohort, fixed by the first authenticated COHORT object delivered on it and bound to the session for its life (Section 3). A GROUP_KEY, POLICY or other cohort object delivered on the session MUST be interpreted within that cohort only, and an endpoint MUST NOT apply an object of one cohort to another, whatever the sequencer identity and the epoch number. Membership in several cohorts of one sequencer needs a session per cohort, the member naming the cohort in its first REPORT on each (Section 6) and the sequencer treating a session as belonging to no cohort until then (Section 9); a later version that multiplexes cohorts on one session must add the identifier to its objects and change the scope of object versioning with it.

5. Objects

Kinds 0x10 to 0x14, in the range 0x10 to 0x1F that [PQST] reserves for this document (Section 19.4 of [PQST]), registered in Section 16. An endpoint hands the kinds of that range to the layer above the session (Section 19.3.4 of [PQST]), held with its version, and acknowledges it as the object mechanism requires; the cohort layer never sees a partial or unauthenticated object, because the session sealed it.

flags bit 0, REMOVAL, marks a key whose commit dropped a REMOVED member (Section 8); a holder erases its previous epoch's key on receiving it and accepts no proof for that epoch (Section 10). Senders MUST set every bit other than bit 0 to zero; receivers MUST ignore every bit other than bit 0, and MUST still honour bit 0, so that a later version can extend the octet. Kinds 0x13 ROSTER and 0x14 MEMBER_EVENT are registered (Section 16) for a roster service and have no body in this version; a member MUST accept and ignore them. member_state is 1 ACTIVE, 2 SUSPENDED, 3 EXPIRED, 4 REMOVED (Section 7); ACTIVE and REMOVED are the authority's, SUSPENDED and EXPIRED the issuing gateway's observations (Section 4.1). in_reply_to is the report_id of the REPORT the object answers (Section 6), or 0 when the object is unsolicited: only an object answering, on the same session, a report the member sent within report_interval confirms the member's standing, from the report's sending, and carries its own member_state (Section 5.1, Section 8 and Section 10). member_index is 16 bits and unique within an epoch (Section 7). A POLICY object is bounded by MAX_OBJECT (16,384 octets, Section 19.3.2 of [PQST]), carried in segments when it exceeds a packet, and a sequencer MUST refuse a larger policy. The body of POLICY is opaque to this layer: an application-defined document the member applies, versioned by the sequencer alone. Every object is issued by the sequencer, versioned per session as Section 19.4 of [PQST] requires, and, when it names an epoch and a policy version no lower than the holder's (Section 5.1), replaces the holder's previous version of its kind.

5.1. Cohort State Freshness

The object version of Section 19.3 of [PQST] orders the objects of one kind within one session and says nothing across sessions: a new session's versions start again, and an older sequencer state delivered on it is as well-formed and as authentic as a newer one. Freshness is the cohort layer's own judgement, made after the session has delivered an object and apart from it.

A member keeps, per cohort identity (Section 2), the highest epoch and the highest policy_version it has accepted, and persists both (Section 4). It judges every object delivered on a session to the sequencer by the following steps, in this order; the table of Section 8 renders the same steps.

  1. A COHORT object naming a cohort_id other than the one the member named in the session's first REPORT (Section 6), or a sequencer_fp other than the identity the session authenticates, is refused: nothing is applied, the objects staged for the session included. The first COHORT fixes the session's cohort only by agreeing with the member's nomination, and one session serves one cohort (Section 3).

  2. Before the first accepted COHORT the session belongs to no cohort, and a GROUP_KEY or POLICY carries no cohort identifier: the member stages it, at most one object per kind, the latest, and applies the staged objects under the steps below when the first COHORT is accepted, so that a key can never be taken for another cohort's.

  3. A COHORT or GROUP_KEY naming an epoch below the member's highest, or a COHORT or POLICY naming a policy_version below its highest, is applied to nothing: the object is acknowledged at the object layer, so that its sender stops sending it, and the member sends a REPORT naming the epoch it holds (Section 8), so that a sequencer behind it learns so. An acknowledgement of an object is therefore delivery, never acceptance; a sequencer that needs to know what a member holds reads the member's report.

  4. A GROUP_KEY for the highest epoch the member has accepted, when it holds no key for that epoch, after a restart or a loss of the key, installs that key once the session's cohort is fixed (step 2): it neither lowers nor advances the persisted high-water mark and confirms no standing, which step 7 alone does. One for the epoch the member holds a key for, carrying the same key, is idempotent and applies nothing; one carrying a different key is a conflict: two keys for one epoch cannot both come from a sequencer that committed as Section 8 says. The member keeps the key it holds, applies nothing, reports, and raises a security-class event to the layer above; it MUST NOT replace the key.

  5. A COHORT naming policy version N and the POLICY carrying N arrive in either order: the POLICY whose version equals the member's highest installs when the member holds no body for it yet, and a second body under a version already installed is a conflict like a second key, kept out and reported.

  6. A COHORT or GROUP_KEY for a higher epoch, and a POLICY for a higher version, are applied as they arrive, whichever of COHORT and GROUP_KEY comes first, the member persisting the new high-water mark before it acts on the object: a GROUP_KEY is issued only to a member the sequencer holds ACTIVE in that epoch (Section 8), so a key arriving before the COHORT object for its epoch says what that object will say of the member's state in the list, and confirms no standing, which step 7 alone does; and a policy change is independent of the epoch by design. A COHORT for the epoch the member holds is taken as well, since the member's own member_state changes within an epoch (Section 7); what it may change is decided by step 7 alone.

  7. The member's own member_state, and the standing it confirms, come only from a COHORT whose in_reply_to names a REPORT the member sent on the same session within group_suspend, the standing a report's sending gives, and only when that report was sent, by the member's own clock, after the report whose answer set the state the member holds, whatever the sessions involved: such an object answers that report and is as fresh as it. Standing then runs from the report's sending, not from the answer's arrival, so that an answer delayed confirms what the report asked and grants no lifetime for arriving late (Section 10), and the states the sequencer assigns are ordered by the member's own reports across sessions, so that no delayed object, on any session, can take the member back to an earlier one. A COHORT naming the member SUSPENDED, EXPIRED or REMOVED confirms no standing, whatever it answers.

  8. Any other object fresh under steps 3 to 6, unsolicited, late, or answering a report sent on another session, synchronises the cohort identity, the epoch, the index and the policy version and nothing else: it renews no standing and changes no member_state.

The rules are the same on every session with the sequencer, on a new session (Section 9), after a re-anchor and after a restart: the session says who delivered an object; the cohort layer says whether it is still current.

6. Frames on the Stream

Stream data on STREAM_COHORT, one frame per DATA payload, typed by its first octet. Frames are plain data: a lost frame is not retransmitted by this layer, and the sequencer treats a frame as data from the member, never as an instruction; in particular a REPORT naming an epoch above a gateway's own is a signal to read the authority, never an instruction to stop issuing (Section 10).

REPORT        = 0x01 cohort_id(16) report_id(4) epoch(4)
                policy_version(4) path_count(1) addr_count(1)
                *( len(1) addr(len) )
LOCATE        = 0x02 request_id(4) fingerprint(48)
LOCATE_RESP   = 0x03 request_id(4) fingerprint(48)
                [ age(4) *( len(1) addr(len) ) ]
EPOCH_PROOF   = 0x04 cohort_id(16) epoch(4) proof(16)
addr          = family(1) address(4|16) port(2)

addr is a transport address, family as in INNER_ADDR (Section 19.4.4 of [PQST]), so len is 7 or 19, and nothing follows a frame's last addr; the member reports the addresses it can be reached at. The fixed sizes are collected in Appendix A.4.

6.1. REPORT

cohort_id names the cohort the session serves (Section 3): a sequencer of another cohort ignores the report, and a session's first report binds it (Section 9). report_id is a counter the member keeps per session, increasing, never 0 and never reused within the session, persisted before a report leaves so that a restart that restores the session continues it: a COHORT object answering the report (in_reply_to, Section 5) can then be told from one answering an earlier report or none, and an answer to a report sent before a restart, whose ledger the restart lost, confirms nothing.

The counter is 32 bits so that a session's life exhausts it under no reporting interval in use; a member that has nonetheless used every identifier opens a new session. epoch is the epoch whose key the member holds, or 0 when it holds none; policy_version is the version of the policy body it holds, or 0 when it holds none, so that a member whose restart lost the body, which it need not persist (Section 4.3), is issued it again; policy versions start at 1 and 0 is reserved for this meaning, as epoch 0 is for the key: a sequencer that has issued no policy holds version 0 and issues no POLICY. path_count has no semantics in this version: senders MUST set it to 1, receivers MUST ignore it, and it is independent of addr_count. The member sends a REPORT when Section 11 says, and the sequencer answers it as Section 8 says.

Bound and validation. addr_count is at most 8, the pairwise max_paths (Section 15 of [PQST]), so that a report never needs more than one packet: 191 octets with eight IPv6 addresses, 95 with eight IPv4. A receiver validates a frame before acting on any of it: the frame type is known, the fixed fields are present, the address count is at most 8, each address has a length of 7 or 19 that matches its family octet, and no octet follows the last address; a frame that fails any of these is discarded whole, nothing of it applied, and counts as a protocol violation of the carrying session (Section 20.3 of [PQST]). LOCATE_RESP carries at most the eight addresses of the report it answers and is validated the same way (Section 6.2).

6.2. LOCATE and LOCATE_RESP

LOCATE carries a request_id the requester chooses as a 32-bit counter never reused within the session, never 0, a requester that has used every identifier opening a new session, and the fingerprint it asks about; a request is 53 octets. LOCATE_RESP echoes both, and the requester matches an answer to an outstanding request by both and discards any other answer, keeping per subject the highest identifier answered and discarding an answer to a lower one, so that requests complete in any order, an answer arriving after its request was given up is attributed to no later one, and no answer changes the addresses held for an identity it does not name. An answer with no octets after the fingerprint, 53 octets (1 + 4 + 48), says only that the requester is not to find that identity: unknown, not ACTIVE and not discoverable by this requester are one answer; a 51-octet buffer, the empty answer's size when the identifier was 16 bits, is not an answer. age is the seconds, at the gateway answering, since the latest report it holds from that member (Section 11); an answer carries at most the eight addresses of that report (Section 6.1). What an answer means, and under what policy one is given, is Section 11.

6.3. EPOCH_PROOF

proof is the first 16 octets of HMAC-SHA-384(key, label("group epoch proof") || cohort_id || epoch(4) || binding) under the epoch key named, with HMAC-SHA-384 as in Section 6.5 of [PQST] and label as in Section 7 of [PQST], where binding is the 32 octets Export(lineage, "PQST group epoch proof", cohort_id || epoch(4), 32) of the pairwise session the frame travels in (Section 8.6 of [PQST]): both ends of that session derive it, it changes at every re-anchor, and nobody else holds it. The proof names its cohort, since two members may share more than one, and a verifier accepts it only for a cohort it holds and the proof names. It says that the session's peer holds the epoch key, at least as recently as the session's current generation; it is bound to that session and generation, so that a proof taken from another session, or from an earlier generation of this one, fails verification, and no challenge travels on the wire. It encrypts nothing.

What a proof means. A valid EPOCH_PROOF demonstrates possession of the named epoch key by the authenticated peer of the carrying session, and nothing more: not current membership, not the absence of a removal since the key was issued, and no authorization for any operation. A member MUST NOT infer current cohort authorization from a proof alone: a cohort-dependent decision also requires that the verifier's own standing has not lapsed and that the epoch named is one the verifier accepts (Section 10). A member presents a proof when the layer above asks it to; this layer defines what a proof means and when one is accepted, not when one is sought. A member whose standing has lapsed presents none and accepts none.

A proof is a statement of possession, not a challenge and its response: it carries no freshness beyond the generation it is bound to and needs none inside an authenticated session, whose own replay protection excludes a copy injected by anyone but the peer; a proof repeated within a generation is the same statement made again. Nor does a proof say when its maker received the key, or that it has not since expired or been removed: an expired member that kept a copy of the key makes the same proof as a newly admitted one. A membership decision about another member comes from the sequencer, never from a proof: in this version LOCATE (Section 11) answers only for an ACTIVE member, under the discovery policy, as fresh as its age, and only an asker whose own standing holds can act on the answer; offline, a member has nothing but its own standing and its peers' statements of possession, and decides accordingly. A roster object is the next version's (Section 5).

7. Member States

         admit
 (none) -------> ACTIVE <----------------------+
                   |                           | returns: re-anchor
 dormant longer    |                           | or FRESH, re-proof,
 than group_suspendv                           | membership lookup
                SUSPENDED ---------------------+
                   |
 dormant longer    |
 than group_expire v
                EXPIRED --> re-admission; dropped at the next
                            rotation (scheduled, batched)

 from any state, on revocation, a failed re-proof or suspected
 compromise: REMOVED (one commit at once; the member's sessions
 closed with AUTHZ_REVOKED)

One close reason per cause. A return is answered with one reason, the same on the session the member had and on a new one, so that an application that branches on the reason, re-admission against staying out, branches the same way for one identity whichever session came back:

Table 2
Return Reason
REMOVED, before or after the rotation that drops the member, on the session it had or on a new one AUTHZ_REVOKED
an identity not on the list, dropped at a rotation or never admitted, on any session AUTHZ_REVOKED
EXPIRED, at the gateway that holds the member expired: its return before the drop, and the close of its session at the drop AUTHZ_EXPIRED

A rotation that drops a member changes no reason: once dropped, the identity is not on the list. The member treats either reason as the end of its membership (below).

Reachability is never an input to a security decision. The only transitions a timer makes are ACTIVE -> SUSPENDED -> EXPIRED, and neither is a commit. The suspension clock starts when the sequencer's session to the member goes DORMANT or is closed for any reason other than the sequencer's own decision (AUTHZ_REVOKED, AUTHZ_EXPIRED), and stops when the session is ESTABLISHED again.

Return. A member returns when a session between it and the sequencer is ESTABLISHED: the restored session re-anchored (Section 16 of [PQST]), a new FRESH exchange, a RECOVERING session back on a validated path (transition S14 of Section 18.2 of [PQST]), or a DORMANT one re-anchored (S17).

Proof at every re-anchor. Every re-anchor of a member's session proves the requester: the requirement is the sequencer identity's, not a session's. Every gateway of the group requires proof of the requester in every re-anchor it serves under that identity (Section 16.3.3 of [PQST]), from its own state or from a sealed record (Section 16.6.3 of [PQST]), and before it serves the request, so that the requirement rests on nothing a record carries, nothing the first REPORT says and no state of the gateway that established the session: a gateway that has never seen the session enforces it as that one did (Section 9). A CONTINUE therefore carries ct_req and a CONTINUE_0RTT is answered PROOF_REQUIRED and repeated as CONTINUE, after which the member offers the proof in every request of that session (Section 16.3.3 of [PQST]); a return from dormancy and a return after a restart prove the device's identity key before anything is delivered, and a FRESH exchange proves it by construction. The cost is one encapsulation per re-anchor at each side.

Membership lookup. The sequencer then performs a membership lookup by the session's peer identity, and the member's state decides what happens: ACTIVE or SUSPENDED becomes ACTIVE and receives whatever it lacks (Section 8); EXPIRED is closed with AUTHZ_EXPIRED; REMOVED, or an identity not in the list, is closed with AUTHZ_REVOKED. No credential is carried by the member: identity re-proof plus the lookup is the whole admission check.

The member's side. On its side the member treats a session the sequencer closes with AUTHZ_REVOKED or AUTHZ_EXPIRED as the end of its current membership: it discards the epoch key and reports the corresponding state to the layer above, REMOVED for the first reason and EXPIRED for the second, so that an application can tell staying out from re-admission. A session the member closes itself, as the grantor of a grant that lapsed (Section 17 of [PQST]), is a closed session and nothing more: the member infers no removal from it, keeps its key and its standing under the rules of Section 10, which lapse on their own clock, and regains standing only through a new session, the membership lookup at its return and a confirmation (Section 8).

Admission is out of band in this version: the member's identity is registered with the sequencer as a peer, with its initial policy, and it is ACTIVE from the first session it opens.

No epoch advance. Admission in this version advances no epoch: a new member receives the key existing members hold, so possession of the epoch key says nothing about when its holder was admitted or whether it is still a member (Section 6), and the key in this version serves EPOCH_PROOF alone and MUST NOT protect application data; a data plane deriving traffic keys from the epoch key gets no backward access control from an admission that does not rotate, which is why the group data plane rotates on admission (Section 13).

The admission commit. The sequencer's record of an admission, the member's member_index and ACTIVE state, is a commit (Section 8), a revision that advances no epoch, made before the member is served, so that two gateways cannot allocate one index and a restart cannot forget an admission. The sequencer allocates the lowest member_index not held; an index is unique within an epoch and returns to the pool at the rotation that drops its holder; a cohort holds at most 65,535 members, and an admission beyond that is refused (the index will partition the data plane's nonce space, where reuse within an epoch would be fatal). Re-admission of an EXPIRED member is the same administrative act.

Rotation on admission. A sequencer MAY nonetheless rotate on an admission, for one admission or for the admissions of an admission_batch window as Section 13.4 describes, under its own policy: a rotation is a commit it may make at any time (Section 8), and a deployment that wants the admission boundary the group data plane will need has it in this version without a change to the member's state machine; the default is not to rotate.

8. Membership Epochs, Rotation and Delivery

The membership epoch advances only on a commit that rotates, and only the sequencer commits; an admission or a policy change is a commit too, one that advances no epoch (below). The rotations:

  1. the scheduled rotation, every rotation_interval;

  2. a security event: a removal, or a forced rotation by the operator.

A commit is one successor state, the next revision of the authority (Section 4):

The sequencer carries it out in this order, as the anchor exchange of Section 9.3 of [PQST] is ordered:

  1. Submit. The commit is one conditional transaction, naming the revision it succeeds and the sequencer's term; the sequencer proceeds only when the authority acknowledges it, and the epoch is part of the record, never advanced apart from it.

    • Refusal. A transaction the authority refuses, because the revision or the term is no longer current or the replication is unavailable, leaves the epoch, the key and every member exactly as they were; the operation is retried on the sequencer's timer, under its current term, until it succeeds or the sequencer learns that it has lost its authority.

    • Retry. A retry is the same transaction, the same commit identifier, predecessor revision and successor, which the authority holds it to (Section 4.2), so that no retry is a second operation.

    • Not deferred. A removal's close of the member's sessions is not deferred with its rotation.

  2. Read on an unknown outcome. When the outcome of a transaction is unknown, because the acknowledgement was lost or the connection failed, or when the authority refuses it, the sequencer reads the latest revision before anything else:

    • Its own identifier. A successor carrying its commit identifier is its own commit, succeeded, acknowledged late or made by an earlier attempt, and the sequencer continues from the authority's record of it.

    • Another identifier. A successor carrying another identifier means another sequencer committed under a later term, and this one has lost its authority, which says nothing of whether its own operation committed before that: it resolves that by the lookup of Section 4.2 with its commit identifier,

      • continuing from the authority's record of the operation when the lookup finds it committed,

      • making nothing when the lookup finds it not committed, and

      • leaving it unknown, never remade under a new identifier, when the lookup cannot say.

    • A refusal of its term. A refusal while the revision it named is still the latest is a refusal of its term, and it has lost its authority likewise.

    • Cannot be read. While the authority cannot be read the sequencer retries with the same identifier, and it never derives a second successor for one operation (Section 4).

  3. One operation at a time. An admission or a policy change arriving while a rotation's outcome is unknown, or a rotation while an admission's is, waits until that outcome is known, since a second transaction submitted beside an unresolved one could not tell its own refusal from another sequencer's commit.

  4. Issue only once the commit is known durable, and never twice for one commit. The dropped members' indices return to the pool, and GROUP_KEY, with REMOVAL set when the commit dropped a REMOVED member, with COHORT are issued to every member that is ACTIVE and reachable at that moment, over its session, each delivery acknowledged by the object mechanism.

    • Admission and policy change. An admission issues COHORT to the new member, and a policy change POLICY to every reachable ACTIVE member.

    • Asynchronous. Delivery is asynchronous and the session's business: a delivery that fails or waits invalidates nothing and commits nothing again.

No member ever holds a revision the authority has not seen, which is the measurable form of CG2 under gateway failure. A member that is ACTIVE but RECOVERING or briefly DORMANT receives the objects when it returns: delivery is the session's business, and the cohort layer never retries on its own. Nothing is issued to SUSPENDED or EXPIRED members.

Delivery on return (what a returning or newly connected member lacks, as the REPORT it sends on every return says, Section 11):

Confirmation. A COHORT object for the epoch a member holds, or a newer one, that answers, on the same session, a REPORT the member sent within group_suspend (in_reply_to, Section 5) and names it ACTIVE confirms the member's standing from the report's sending (Section 10).

Acceptance of what arrives, the steps of Section 5.1 rendered, the same on the session the member had and on a new one:

Table 3
What arrives Against what the member holds The member
COHORT or GROUP_KEY for a lower epoch a higher epoch accepted applies nothing, acknowledges, reports its epoch
GROUP_KEY for the highest epoch it has accepted, holding no key for it (after a restart) the epoch accepted, no key installs the key, the high-water mark unchanged, no standing confirmed
GROUP_KEY for the epoch it holds, the same key the key applies nothing (idempotent)
GROUP_KEY for the epoch it holds, another key the key a conflict: keeps its key, reports, raises a security-class event
COHORT for the epoch it holds its standing applies the index and the policy version when they are fresh; applies member_state, and confirms standing, only under step 7 of Section 5.1
COHORT or GROUP_KEY for a higher epoch a lower epoch applies it, persists the epoch first, in whichever order the two arrive
POLICY, or a COHORT, with a lower policy_version a higher version accepted applies nothing, acknowledges, reports
POLICY with a higher policy_version a lower version applies it, persists the version first

Sessions of dropped members. A session the sequencer closed, or that belonged to a member dropped at a rotation, that comes back (a path validated, a re-anchor, an establishment) is closed again with the reason of Section 7, AUTHZ_REVOKED for an identity no longer on the list; the tombstone of Section 19.6 of [PQST] serves the same purpose on the wire.

The reconnect storm is a non-event. N suspended members returning at once each come back, by a re-anchor or on a validated path, re-prove if restarted, are looked up and receive the objects they lack: zero commits, zero deliveries to other members.

9. Two Sessions with One Member

Both sides may recover a lost session by a FRESH exchange at the same moment (the member's recovery schedule and the sequencer's both interleave one, Section 16.7 of [PQST]), and concurrent sessions between two peers are permitted (Section 9.6.2 of [PQST]); the two endpoints may then see the two sessions established in opposite orders.

The lower identifier is kept. The sequencer keeps the session with the lower identifier and closes the other, lower in the unsigned big-endian order of the 16 octets of the session identifier, Export(session, "session id", "", 16) of Section 8.6 of [PQST], the comparison Section 9.6.1 of [PQST] makes of identity fingerprints, which the member uses as well when it chooses which live session to report on.

One session per member and cohort. A session a member had is closed when a new one with the member is established and kept, so that the sequencer has one session per member and cohort.

Scoped to the cohort. The rule is scoped to the cohort: a new session belongs to no cohort until the member's first REPORT on it names one (Section 6), and until then it displaces nothing and is served nothing.

A session re-anchored toward another gateway. A session re-anchored toward a gateway of the sequencer's identity that has not served it (Section 10), which that gateway sees arrive as a re-anchor rather than an establishment, is new to it in the same way:

Once bound. Once a session is bound, the member's reports, and so its reachability record (Section 11), come from that session alone, a report on a session it superseded updating nothing.

Different cohorts. Two sessions of one member for different cohorts coexist, and duplicates are resolved among the sessions of one cohort only; a sequencer looks the member up in the cohort its report names before it issues anything, and a member's new session for another cohort sends its first REPORT whatever sessions the member holds for other cohorts, since the choice among duplicate sessions is made within a cohort.

The member follows the objects. The member follows the session the sequencer's objects arrive on and treats every session to the sequencer that is ESTABLISHED as reachability; among several live sessions it reports on the one with the lowest identifier until an object names another.

Never ESTABLISHED. A session that was never ESTABLISHED (a half-open exchange left by an abandoned recovery attempt) is not reachability, whatever paths it validates, and is not followed.

10. Partitions

A member whose session to the sequencer is RECOVERING or DORMANT is in a partition from the cohort's point of view, whatever the cause. In it:

Healing is the member's session becoming ESTABLISHED again (Section 7, return). The member sends its report with the epoch it holds; the sequencer answers with what it lacks. An epoch the member missed is not merged: the member committed nothing. A sequencer gateway cut off from the authority, or without the term to commit, serves members' sessions, issues the objects of Section 5 only while it knows its replica to include the latest commit (below), and defers commits until it holds a current term and a current read of the authority (Section 4); a member it cannot confirm lapses as the standing rule above says, and a removal's sessions are closed at once even while its rotation waits.

Gateways and freshness. A session's authentication proves which gateway group answered, not that the gateway's replica of the group's state is current: a gateway behind its replicas holds authentic objects of an epoch the cohort has left.

11. Services

Reachability. The sequencer keeps the latest report per member with its time, the latest being the one with the highest report_id on the session (Section 6), which the member increases with every report, persists, and never reuses, and which the session authenticates: a report delivered after a later one is ignored, so that an address the member has left cannot replace the one it reported since.

Reporting. A member sends a REPORT on its session to the sequencer when the session is established, when it re-anchors, when a path of it is validated again after a loss (S14 of Section 18.2 of [PQST]), and every report_interval while the session is up, RECOVERING or DORMANT (Section 12).

Discovery. A member sends LOCATE with another member's fingerprint; the sequencer answers LOCATE_RESP from that member's latest report only when it is ACTIVE and policy allows the requester to find it, by role or by name; otherwise the answer is empty, indistinguishable from an unknown member.

Forwarding members. A member that forwards datagrams by routing key for others (Section 15.8 of [PQST]) is a path to both endpoints and nothing more: its dormancy changes their paths, never their sessions. Policy names which members may forward.

12. Parameters

Table 4
Parameter RECOMMENDED Where
group_suspend the session's max_dormancy, or less by policy sequencer policy
group_expire 7 days sequencer policy
rotation_interval 24 h sequencer policy
report_interval the minimum of 60 s and a quarter of group_suspend member policy; at most a quarter of group_suspend, so that a reachable member is confirmed at least twice within its standing with a report's delay and loss allowed for (Section 8)
previous-epoch proof window group_suspend member
standing, from the sending of the last confirmed report to its lapse group_suspend member
residual acceptance of a removed member's proofs at a peer that has not received the removal's commit (CG3, Section 10) until that peer's own standing lapses: at most group_suspend after the sending of its last confirmed report, up to 24 h at the pairwise default max_dormancy and less by policy, plus the staleness allowance of Section 4.2 where the deployment issues on reads rather than a lease member
an answer accepted as confirming the report it names within group_suspend of the report's sending member
confirmation of a reachable member in answer to the first REPORT after the last answered is group_suspend/2 - report_interval/2 old sequencer
epoch key erased without confirmation group_expire member

Relations. 0 < group_suspend < group_expire, so that the states of Section 7 are entered in their order whatever max_dormancy a deployment sets, and 0 < report_interval <= group_suspend/4; an implementation MUST refuse a configuration that violates either. A deployment that issues on linearizable reads with an allowance between read and issuance (Section 4.2) adds that allowance to the residual acceptance above, since a confirmation issued within it may rest on a revision a removal has left.

13. The Group Data Plane (Informative)

This version carries no group data. This section describes the data plane the next version is intended to add, so that the shape of the unified session is visible, and lists what is still open. Nothing in it is normative, and nothing in it changes [PQST].

13.1. What a Unified Session Needs

A PQST session has an identity-bound secret that only its endpoints hold, traffic keys and a data plane under it, continuity across path loss and restarts, generations that ratchet, replay protection per direction, and an exporter. The control plane of this document already gives the group its continuity (CG1, CG2) and a secret that rotates on schedule and at once on removal: the epoch key. What it lacks is a data plane under that secret, per-sender replay protection, and a group exporter. One property has no pairwise counterpart: in a session, a packet that opens came from the one other holder of the key; in a group, every member holds it.

13.2. The Intended Design (Preliminary)

The constructions of this section and the next are preliminary. The specification of that data plane will have to state the sender authentication and the replay-commit ordering its threat model needs, and will have to refrain from claiming individual sender integrity, malicious-member-resistant replay protection or confidentiality against a member wherever it has not provided them. The sender-key derivation and the packet format below are not final until the open question of Section 13.4 is decided.

  • The group secret is derived from the delivered epoch key, which itself still protects nothing directly: group_secret(e) = Expand(epoch_key(e), label("group traffic") || cohort_id || epoch(4), 48), with Expand as in Section 6.5 of [PQST] and label as in Section 7 of [PQST]. The sequencer makes and delivers the keys; members do not agree them among themselves as in MLS ([RFC9420]), and post-compromise security comes from rotation.

  • A native group packet under packet type 3 of [PQST], enabled by capability bit 0: one seal by the sender, opened by every receiver, on any carrier (unicast to each member, a relay that forwards by routing key without opening, multicast, or a radio net), in the protected-packet format unchanged:

    • the routing key is a group routing key that rotates per epoch;

    • epoch_id carries the cohort epoch;

    • seq carries the sender's member_index in its high 16 bits and the sender's counter in the low 48 (Section 12 of [PQST]).

  • Keys per sender, derived from the group secret and the sender's index, so that senders have disjoint nonce spaces and receivers one replay window per sender, with no coordination. This separates senders; it does not authenticate them.

  • Sender authentication per flow, where a flow needs it.

    • For small groups, a MAC per recipient, keyed from the sender's pairwise session with that recipient (its exporter, Section 8.6 of [PQST]).

    • For broadcast feeds, delayed key disclosure from hash chains in the manner of TESLA ([RFC4082]), whose anchors the sequencer distributes.

    • Traffic that must be attributable, such as a command, stays in pairwise sessions.

  • Partitions keep the frozen epoch of Section 10: members cut off from the sequencer go on under the last epoch they hold while their standing holds, group_suspend from the sending of the last confirmed report (Section 10, decision 2 of Section 13.4), after which they fall back to pairwise sessions, which never need the sequencer.

  • Where group packets may go. A member sends group packets only to addresses validated in a pairwise session with the recipient, or within the reflection budget of Section 15.4 of [PQST] toward any other, so that a member cannot aim the group's traffic at a victim.

  • A group exporter Export(group, ulabel, context, L) from the group secret, rotating with the epoch, under the "PQST group" exporter labels that [PQST] reserves.

The receive path would be the pairwise one, with a sender index in place of a lineage: header protection, the pre-authentication filter, one AEAD, the two-phase replay check. A group packet that fails would leave no trace in authoritative state and never create or change pairwise state, as Section 21 of [PQST] requires of any packet type an extension defines.

13.3. What It Costs

  • A member's compromise exposes the group's traffic until the next rotation; removal rotates at once, so the window is the time to detect the compromise.

  • Without a per-flow sender authentication, members can forge each other within the group.

  • The network sees the group: within an epoch every group packet carries the same routing key, so an observer links them to one group and sees its volume. Rotating the key per epoch bounds the linkage; nothing hides a group from a listener on its radio net.

  • One replay window per sender heard from, bounded by the membership.

13.4. Decisions and the Open Question for the Next Version

  1. A group packet proves possession of the epoch key, not membership (Section 6); sender authentication is per flow where a flow needs it, as Section 13.2 describes, and traffic that must be attributable stays pairwise.

  2. A partitioned group sends under its frozen epoch while its members' standing holds, group_suspend from the sending of each one's last confirmed report (Section 10), then falls back to its pairwise sessions; a member erases the key at group_expire.

  3. All three carriers are in scope from the first: unicast fan-out, a relay at the gateway group that forwards by routing key without opening, and broadcast media.

  4. An inner address space per cohort is in scope: the sequencer assigns each member an address from the cohort's prefix; an inner packet to a member travels in the pairwise session with it, one to the cohort's broadcast address as a group packet.

  5. An admission under the group data plane is a commit that advances the epoch with a new key, as a removal is: the new member receives nothing from which earlier traffic keys derive, and sends or receives group packets only under the epoch of its admission, so that the admission boundary is a cryptographic one (backward access control, Section 14).

    • Batching. Admissions arriving within admission_batch of one another are one commit; the recommended value is 0, one commit per admission, and a deployment with high churn raises it.

    • The previous key. Receivers keep the previous epoch's key for receiving only until group_suspend after the successor arrived, unless the successor came with REMOVAL, in which case the previous key is erased at once (Section 10): a member partitioned from the sequencer stays audible until its standing lapses, the connected members having one rule for packets and proofs, while the new member, which never held the previous key, reads nothing from before its admission.

    • Expiry. An expired member receives no later key and is dropped at the next rotation, as now.

  6. The group plane authenticates the group, not the sender: every member derives every sender's key, so a malicious member can forge another member's index, advance the receivers' replay window for that sender so that the honest sender's next packet is refused as a replay, and repeat that sender's key and nonce.

    • Verify before the replay state moves. A receiver that needs to know the sender therefore verifies the per-flow sender authentication of Section 13.2, the per-recipient MAC or the delayed-disclosure scheme, before the claimed sender's replay state moves, and never on the group AEAD alone.

    • Without it. A flow without it gets what the group key gives, which is that an outsider forged nothing, and traffic that must be attributable or must survive a malicious member stays pairwise.

    • Stated before the receiver is written. These limits are stated in Section 14 of the data-plane version before its receiver is written.

Open. Whether receivers must constrain each individual sender against a malicious member, or whether a member is trusted because it holds the current group key. The answer decides whether native cohort traffic suits only telemetry of low impact or also security-critical control, and it decides the sender-key derivation and the replay-commit ordering; until it is taken, nothing in Section 13.2 and Section 13.3 is final, and decision 6 states the limit of the shared-key construction.

14. Security Considerations

The security considerations of [PQST] apply to every session this layer uses; those below are the cohort layer's own. Section 13.3 states what the intended data plane would cost.

15. Privacy Considerations

Cohort control is stream data inside pairwise packets of the same shape as any other (Section 24 of [PQST]): an observer cannot tell group control from data, and the privacy properties of Section 24 of [PQST] carry over unchanged. A forwarding member does not learn the content, nor the authenticated PQST sender identity, from the protected packet's encrypted contents alone; it can observe routing identifiers, packet sizes, timing and whatever the carrier shows it, a source address or a link identity among them, so that PQST gives no sender anonymity against a forwarding member.

Discovery is closed by default and opened by policy, and a member reports only the addresses its policy allows: the sequencer, which sees a member's transport address anyway, learns nothing more unless the member's policy says so, and no member learns another's addresses unless the policy names it. Nothing in a pairwise session's wire data shows whether its endpoints are members (Section 24.6 of [PQST]); the data plane of Section 13 would change that for the group's own packets (Section 13.3).

16. IANA Considerations

The assignments in this section are requested for the publication of this document as an RFC. At the Internet-Draft stage none has been allocated, and implementations use the values here provisionally until then.

A new registry. This document establishes a "Cohort Frames" registry in the "PQST Parameters" group that [PQST] creates. The field is one octet. Its ranges and policies, in the terms of [RFC8126]: 0x00 Reserved; 0x01-0x3F IETF Review; 0x40-0x7F Reserved; 0x80-0xBF Specification Required, under the guidance to designated experts of Section 25 of [PQST]; 0xC0-0xFF Private Use. Initial contents:

Table 5
Value Name Reference
0x01 REPORT Section 6
0x02 LOCATE Section 6
0x03 LOCATE_RESP Section 6
0x04 EPOCH_PROOF Section 6

Registrations in the PQST registries. [PQST] reserves the following for this document. IANA is asked to record the assignments with this document as the reference, and to mark the reservations as reservations.

Table 6
Registry Value Name Status
Object Kinds 0x10 COHORT assigned (Section 5)
Object Kinds 0x11 GROUP_KEY assigned (Section 5)
Object Kinds 0x12 POLICY assigned (Section 5)
Object Kinds 0x13 ROSTER Reserved: no payload semantics in this version
Object Kinds 0x14 MEMBER_EVENT Reserved: no payload semantics in this version
Object Kinds 0x15-0x1F -- Reserved for later versions of this document
Stream Identifiers 0xE0 STREAM_COHORT assigned (Section 3)
Capability Bits 0 -- Reserved for a future group data-plane specification (Section 13); not set by implementations of this version
Packet Types 3 -- Reserved for a future group data-plane specification (Section 13); no processing semantics in this version

The derivation labels beginning "group " that [PQST] reserves for this document are internal to the key schedule and are not a registry: this document uses label("group epoch proof") (Section 6) and intends label("group traffic") and label("group sender") for the data plane. The exporter labels beginning "PQST group" are reserved likewise (Section 8.6 of [PQST]).

17. Implementation Status

This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in [RFC7942]. The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs. Please note that the listing of any individual implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors. This is not intended as, and must not be construed to be, a catalog of available implementations or their features. Readers are advised to note that other implementations may exist. According to [RFC7942], "this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature. It is up to the individual working group to use this information as they see fit".

Reference implementation. A Go implementation of Sections 3 to 12 by the author, over the reference implementation of [PQST], covering every item of the conformance clause of Section 1.6 for both roles, the member and the sequencer, the authority being a model (below):

Maturity: a research prototype. Revision: the one this draft was built from, recorded in the manifest of the implementation's repository (pqst/validation/EVIDENCE.md), which is available from the author on request until it is published; the test names in this section are the names of the checks the manifest and the traceability index list. Licensing Declaration to Be Provided Later. There is no independent implementation of this layer yet: the independent implementation of [PQST] is to be extended to it after this revision, and nothing here is reported as interoperated.

Simulation. A cohort harness runs N members and a model sequencer on the pairwise simulator of the PQST reference.

Censuses. Censuses, each one generated distribution on one revision, are evidence about the model sequencer described above, not about a deployment's authority. On the code of this revision (pkg/cohort and pkg/endpoint as committed through 5f02c7c), the census of 2026-11-02, in eight shards:

Earlier censuses. The censuses of earlier revisions found defects in both families: two of the dormant member on the code before the external reviews; 41 of the cohort family and 1,871 of the 10,000 gateway-group scenarios on the code after them; and one gateway-group failure after those corrections. Each was reduced to a minimal scenario kept as a directed test, and the rules they forced are in Section 7, Section 8, Section 9, Section 10 and Section 11:

Every one of those seeds passes on the code of this revision. The changes of the eighth, ninth and tenth reviews each have a directed test in this layer (TestLosingSessionReportDoesNotUpdate, TestLocateEmptyWhenBehind, TestMemberReportsCloseReason, TestParamsRefused) and are within the census above.

Four events kept apart. These figures keep apart four events that differ in cost:

No single figure is a group recovery latency.

Regression tests of the reviews. The rules the external reviews forced each have a directed test in the reference, named in the reviews' own numbering and kept as regressions, the manifest mapping each name to its file:

The manifest named above records each test's file and the revision it ran on, and the traceability index beside it (pqst/validation/TRACEABILITY.md) links CG1 to CG4 and each review's property to its directed tests, monitors, censuses, models and what nothing covers.

Not implemented. The data plane of Section 13, and the ROSTER and MEMBER_EVENT kinds.

Known limitations.

The reproduction data is in the manifest named above.

18. References

18.1. Normative References

[PQST]
Henry, C., "Post-Quantum Secure Transport (PQST)", Work in Progress, Internet-Draft, draft-henry-pqst-00, , <https://datatracker.ietf.org/doc/html/draft-henry-pqst-00>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, BCP 14, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC8126]
Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", RFC 8126, BCP 26, , <https://www.rfc-editor.org/rfc/rfc8126>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", RFC 8174, BCP 14, , <https://www.rfc-editor.org/rfc/rfc8174>.

18.2. Informative References

[RFC4082]
Perrig, A., Song, D., Canetti, R., Tygar, J. D., and B. Briscoe, "Timed Efficient Stream Loss-Tolerant Authentication (TESLA): Multicast Source Authentication Transform Introduction", RFC 4082, , <https://www.rfc-editor.org/rfc/rfc4082>.
[RFC7942]
Sheffer, Y. and A. Farrel, "Improving Awareness of Running Code: The Implementation Status Section", RFC 7942, BCP 205, , <https://www.rfc-editor.org/rfc/rfc7942>.
[RFC9420]
Barnes, R., Beurdouche, B., Robert, R., Millican, J., Omara, E., and K. Cohn-Gordon, "The Messaging Layer Security (MLS) Protocol", RFC 9420, , <https://www.rfc-editor.org/rfc/rfc9420>.
[RFC9838]
Smyslov, V. and B. Weis, "Group Key Management Using the Internet Key Exchange Protocol Version 2 (IKEv2)", RFC 9838, , <https://www.rfc-editor.org/rfc/rfc9838>.

Appendix A. Wire Formats (Informative)

This appendix collects in one place the layout of every structure the cohort layer puts on the wire, inside the pairwise session's stream and objects. It is generated from the sections that define them and adds nothing to them: Section 5 for the objects, Section 6 for the frames, Section 16 for the codepoints. Everything travels inside a PQST session, so the packet formats are those of the wire-format appendix of [PQST].

A.1. Objects

Object bodies (Section 5), carried by the object mechanism of Section 19.4 of [PQST]:

  • 0x10. Name: COHORT; Body: cohort_id(16) sequencer_fp(48) policy_version(4) epoch(4) member_index(2) member_state(1) in_reply_to(4) (79 octets); Delivered to: each member; When: on a new session, on every change of the member's own state, and whenever anything else is delivered

  • 0x11. Name: GROUP_KEY; Body: epoch(4) flags(1) key(32) (37 octets); Delivered to: each ACTIVE member; When: when the member's key is older than the epoch: on a new session, on rotation, on a report naming an older epoch

  • 0x12. Name: POLICY; Body: policy_version(4) body(*); Delivered to: each ACTIVE member; When: when the member's policy version is older than the current one

A.2. Frames

Frames on STREAM_COHORT (Section 6), one per DATA payload, typed by the first octet:

REPORT        = 0x01 cohort_id(16) report_id(4) epoch(4)
                policy_version(4) path_count(1) addr_count(1)
                *( len(1) addr(len) )
LOCATE        = 0x02 request_id(4) fingerprint(48)
LOCATE_RESP   = 0x03 request_id(4) fingerprint(48)
                [ age(4) *( len(1) addr(len) ) ]
EPOCH_PROOF   = 0x04 cohort_id(16) epoch(4) proof(16)
addr          = family(1) address(4|16) port(2)

proof is the first 16 octets of HMAC-SHA-384(key, label("group epoch proof") || cohort_id || epoch(4) || binding) under the epoch key named, with HMAC-SHA-384 as in Section 6.5 of [PQST] and label as in Section 7 of [PQST], where binding is the 32 octets Export(lineage, "PQST group epoch proof", cohort_id || epoch(4), 32) of the pairwise session the frame travels in (Section 8.6 of [PQST]): both ends of that session derive it, it changes at every re-anchor, and nobody else holds it.

A.3. Codepoints

The Cohort Frames registry (Section 16):

Table 7
Value Name Reference
0x01 REPORT Section 6
0x02 LOCATE Section 6
0x03 LOCATE_RESP Section 6
0x04 EPOCH_PROOF Section 6

Registrations in the PQST registries (Section 16):

Table 8
Registry Value Name Status
Object Kinds 0x10 COHORT assigned (Section 5)
Object Kinds 0x11 GROUP_KEY assigned (Section 5)
Object Kinds 0x12 POLICY assigned (Section 5)
Object Kinds 0x13 ROSTER Reserved: no payload semantics in this version
Object Kinds 0x14 MEMBER_EVENT Reserved: no payload semantics in this version
Object Kinds 0x15-0x1F -- Reserved for later versions of this document
Stream Identifiers 0xE0 STREAM_COHORT assigned (Section 3)
Capability Bits 0 -- Reserved for a future group data-plane specification (Section 13); not set by implementations of this version
Packet Types 3 -- Reserved for a future group data-plane specification (Section 13); no processing semantics in this version

A.4. Fixed Sizes

Table 9
Quantity Octets Where
COHORT body 79 Section 5
GROUP_KEY body 37 Section 5
proof of EPOCH_PROOF 16 Section 6
identity fingerprint 48 Section 6 and [PQST]
addr (IPv4, IPv6) 7, 19 Section 6
cohort_id 16 Section 4
epoch key 32 Section 4
member_index 2 Section 7
largest POLICY, MAX_OBJECT of [PQST] 16384 Section 5

Author's Address

Clayton Henry