Skip to main content

Random-Access Authenticated Encryption
draft-sullivan-cfrg-raae-03

Document Type Active Internet-Draft (individual)
Author Nick Sullivan
Last updated 2026-07-23
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-sullivan-cfrg-raae-03
Crypto Forum                                                 N. Sullivan
Internet-Draft                               Cryptography Consulting LLC
Intended status: Informational                              23 July 2026
Expires: 24 January 2027

                 Random-Access Authenticated Encryption
                      draft-sullivan-cfrg-raae-03

Abstract

   This document defines random-access authenticated encryption (raAE),
   a primitive that partitions a message into an indexed sequence of
   segments that can be encrypted and decrypted independently and in any
   order.  It also specifies SEAL (Segmented Encryption and
   Authentication Layer), a parameterized construction that defines a
   family of concrete raAE instantiations, one for each valid choice of
   an Authenticated Encryption with Associated Data (AEAD) algorithm, a
   key derivation function (KDF), and associated parameters.

   SEAL supports immutable (write-once), append-only, and mutable (in-
   place ciphertext rewrite) operations, each with per-segment
   authentication.  A separately configured snapshot authenticator can
   additionally authenticate the complete, indexed segment set.

   The document also defines the security notions of raAE, specifies the
   requirements for conforming constructions, and analyzes SEAL against
   those requirements.  Concrete cipher suites, serialization layouts,
   and test vectors for SEAL are specified in a companion document.

Discussion Venues

   This note is to be removed before publishing as an RFC.

   Discussion of this document takes place on the Crypto Forum Research
   Group mailing list (cfrg@ietf.org), which is archived at
   https://mailarchive.ietf.org/arch/browse/cfrg.

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/.

Sullivan                 Expires 24 January 2027                [Page 1]
Internet-Draft                    raAE                         July 2026

   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 24 January 2027.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   4
     1.1.  Related Work  . . . . . . . . . . . . . . . . . . . . . .   6
   2.  Conventions and Terminology . . . . . . . . . . . . . . . . .   7
     2.1.  Taxonomy  . . . . . . . . . . . . . . . . . . . . . . . .   9
     2.2.  Notation  . . . . . . . . . . . . . . . . . . . . . . . .  10
   3.  The raAE Primitive  . . . . . . . . . . . . . . . . . . . . .  11
     3.1.  Overview  . . . . . . . . . . . . . . . . . . . . . . . .  11
     3.2.  Interface . . . . . . . . . . . . . . . . . . . . . . . .  11
     3.3.  Extended Interface  . . . . . . . . . . . . . . . . . . .  12
   4.  The SEAL Construction . . . . . . . . . . . . . . . . . . . .  14
     4.1.  Construction Overview . . . . . . . . . . . . . . . . . .  16
     4.2.  Component Suite and Parameters  . . . . . . . . . . . . .  16
       4.2.1.  Suite Choices . . . . . . . . . . . . . . . . . . . .  18
       4.2.2.  Profile-Level Constants . . . . . . . . . . . . . . .  19
       4.2.3.  Algorithm-Determined Sizes  . . . . . . . . . . . . .  19
       4.2.4.  Per-Message Inputs  . . . . . . . . . . . . . . . . .  19
     4.3.  The KDF Combiner  . . . . . . . . . . . . . . . . . . . .  20
       4.3.1.  Two-Step KDF  . . . . . . . . . . . . . . . . . . . .  21
       4.3.2.  One-Step KDF  . . . . . . . . . . . . . . . . . . . .  22
     4.4.  SEAL Encodings and Labels . . . . . . . . . . . . . . . .  22
       4.4.1.  Payload Info Construction . . . . . . . . . . . . . .  22
       4.4.2.  Segment AAD . . . . . . . . . . . . . . . . . . . . .  23
       4.4.3.  Labels  . . . . . . . . . . . . . . . . . . . . . . .  25
     4.5.  Key Schedule and Nonce Generation . . . . . . . . . . . .  26
       4.5.1.  Payload Schedule  . . . . . . . . . . . . . . . . . .  26
       4.5.2.  Epoch Key Derivation  . . . . . . . . . . . . . . . .  26
       4.5.3.  Nonce Generation  . . . . . . . . . . . . . . . . . .  27
     4.6.  Commitment  . . . . . . . . . . . . . . . . . . . . . . .  30

Sullivan                 Expires 24 January 2027                [Page 2]
Internet-Draft                    raAE                         July 2026

     4.7.  Snapshot Authenticator  . . . . . . . . . . . . . . . . .  30
       4.7.1.  Interface and Requirements  . . . . . . . . . . . . .  30
       4.7.2.  None  . . . . . . . . . . . . . . . . . . . . . . . .  33
     4.8.  Segment Algorithms  . . . . . . . . . . . . . . . . . . .  33
       4.8.1.  EncryptSegment  . . . . . . . . . . . . . . . . . . .  34
       4.8.2.  DecryptSegment  . . . . . . . . . . . . . . . . . . .  35
       4.8.3.  RewriteSegment  . . . . . . . . . . . . . . . . . . .  35
     4.9.  Top-level Algorithms  . . . . . . . . . . . . . . . . . .  36
       4.9.1.  Read-Only Operations  . . . . . . . . . . . . . . . .  36
       4.9.2.  Rewritable Operations . . . . . . . . . . . . . . . .  39
       4.9.3.  Changing Message Length . . . . . . . . . . . . . . .  40
   5.  Security Analysis . . . . . . . . . . . . . . . . . . . . . .  43
     5.1.  Security Notions  . . . . . . . . . . . . . . . . . . . .  43
       5.1.1.  ra-ROR  . . . . . . . . . . . . . . . . . . . . . . .  44
       5.1.2.  ra-CMT  . . . . . . . . . . . . . . . . . . . . . . .  44
       5.1.3.  ra-CMT-p  . . . . . . . . . . . . . . . . . . . . . .  45
       5.1.4.  Snapshot Authentication . . . . . . . . . . . . . . .  45
     5.2.  Relations to Other Notions  . . . . . . . . . . . . . . .  45
     5.3.  Adversary Model and Assumptions . . . . . . . . . . . . .  46
     5.4.  raAE Construction Requirements  . . . . . . . . . . . . .  48
     5.5.  Segment Confidentiality and Integrity . . . . . . . . . .  50
     5.6.  Commitment Security . . . . . . . . . . . . . . . . . . .  51
     5.7.  Snapshot Authenticator Security . . . . . . . . . . . . .  53
     5.8.  Capacity and Usage Limits . . . . . . . . . . . . . . . .  55
       5.8.1.  Accounting Model  . . . . . . . . . . . . . . . . . .  55
       5.8.2.  Limit Classes . . . . . . . . . . . . . . . . . . . .  56
       5.8.3.  Maximum Object Size . . . . . . . . . . . . . . . . .  56
       5.8.4.  Rewrite Capacity  . . . . . . . . . . . . . . . . . .  58
       5.8.5.  Choosing epoch_length . . . . . . . . . . . . . . . .  59
       5.8.6.  Derivations . . . . . . . . . . . . . . . . . . . . .  60
   6.  Security Considerations . . . . . . . . . . . . . . . . . . .  62
     6.1.  Detection Summary . . . . . . . . . . . . . . . . . . . .  62
     6.2.  Nonce Misuse  . . . . . . . . . . . . . . . . . . . . . .  64
     6.3.  Parameter Set Mismatch  . . . . . . . . . . . . . . . . .  65
     6.4.  Framing and Label Errors  . . . . . . . . . . . . . . . .  65
     6.5.  Parameter Misuse  . . . . . . . . . . . . . . . . . . . .  65
     6.6.  Snapshot Integrity Limitations  . . . . . . . . . . . . .  66
     6.7.  Salt Reuse  . . . . . . . . . . . . . . . . . . . . . . .  67
     6.8.  Rewrite Hazards . . . . . . . . . . . . . . . . . . . . .  68
     6.9.  Constant-Time Implementation  . . . . . . . . . . . . . .  68
     6.10. Properties Not Provided . . . . . . . . . . . . . . . . .  69
     6.11. Cross-Application Domain Separation . . . . . . . . . . .  70
   7.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  70
   8.  References  . . . . . . . . . . . . . . . . . . . . . . . . .  70
     8.1.  Normative References  . . . . . . . . . . . . . . . . . .  70
     8.2.  Informative References  . . . . . . . . . . . . . . . . .  71
   Appendix A.  Optional Plaintext-Bound Nonce Construction  . . . .  73
   Appendix B.  Optional Hedged Randomness . . . . . . . . . . . . .  74

Sullivan                 Expires 24 January 2027                [Page 3]
Internet-Draft                    raAE                         July 2026

   Appendix C.  Proof Status and Security Claim Provenance . . . . .  75
     C.1.  Provenance of the Security Claims . . . . . . . . . . . .  75
     C.2.  Advantage Notation and Adversary Parameters . . . . . . .  77
     C.3.  ra-ROR Reduction  . . . . . . . . . . . . . . . . . . . .  78
     C.4.  Commitment  . . . . . . . . . . . . . . . . . . . . . . .  79
     C.5.  Nonce Modes . . . . . . . . . . . . . . . . . . . . . . .  79
   Appendix D.  Design Rationale . . . . . . . . . . . . . . . . . .  80
     D.1.  Key Schedule Design Rationale . . . . . . . . . . . . . .  80
     D.2.  Nonce Mode Design Rationale . . . . . . . . . . . . . . .  81
   Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . .  81
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  81

1.  Introduction

   Large encrypted content is often stored as a sequence of fixed-size
   segments, so that an application can read or modify any part of it
   without processing the whole.  Encrypted backups, encrypted file
   formats, object stores with partial updates, and full-disk encryption
   over fixed-size blocks all work this way.  Such a system needs to
   encrypt, decrypt, or re-encrypt any individual segment on its own and
   in arbitrary order, and to verify that the stored object as a whole
   is authentic and complete, without re-encrypting the segments that
   did not change.

   This document specifies the raAE primitive (Section 3), whose base
   interface and security notions come from Fábrega et al.  ([FLRR25]),
   and defines SEAL (Segmented Encryption and Authentication Layer), a
   parameterized construction of raAE.  The base algorithms encrypt and
   decrypt segments in arbitrary order, so a caller can read or replace
   any segment on its own.  On top of that base, the extended raAE
   interface adds in-place rewrite and a snapshot, a stored value that
   authenticates the segment set as the writer last recorded it.  A
   rewrite re-encrypts only the changed segment and updates the
   snapshot, leaving every other segment untouched.  Appending to the
   end, or truncating from the end, composes the same per-segment
   operations, so the snapshot stays consistent without a separate
   algorithm.

   SEAL builds the primitive from a chosen AEAD algorithm, a key
   derivation function (KDF), and configuration parameters.  Under a
   snapshot authenticator, it binds every segment and the count into a
   public snapshot value that an adversary cannot forge without the
   content-derived key.

Sullivan                 Expires 24 January 2027                [Page 4]
Internet-Draft                    raAE                         July 2026

                      .------------------------------.
                      |        raAE primitive        |
                      |      abstract interface      |
                      '------------------------------'
                                     |
                                     v
      .--------------------------------------------------------------.
      |                      SEAL construction                       |
      |   parameterized by a cipher suite (AEAD + KDF), a maximum    |
      |   segment size, and an epoch length                          |
      |                                                              |
      |   .----------------------.    .----------------------.       |
      |   |  mutability:         |    |  snapshot:           |       |
      |   |  immutable           |    |  none | present      |       |
      |   |  append-only         |    |                      |       |
      |   |  mutable             |    |                      |       |
      |   '----------------------'    '----------------------'       |
      '--------------------------------------------------------------'
                                     |  provides
                    +----------------+----------------+
                    |                                 |
                    v                                 v
      .----------------------------.      .------------------------.
      |  per-segment authenticity  |      |   snapshot integrity   |
      |      (always present)      |      |     (when present)     |
      '----------------------------'      '------------------------'

           Figure 1: The raAE primitive and the SEAL construction

   raAE separates the two authentication scopes that applications often
   conflate:

   Per-segment authenticity:  One AEAD tag verifies under the segment
      index, a finality bit marking the last segment, and any caller-
      supplied associated data.  It does not establish that the segment
      belongs to the current snapshot.

   Snapshot integrity:  When a snapshot authenticator is configured,
      snapshot verification checks that the present segment set and the
      count are exactly what the writer last recorded, under a content-
      derived key.  Verification targets the whole segment set, and,
      where the authenticator supports it, can instead confirm that a
      designated subset of segments is included at their recorded
      positions, without reading the others (Section 4.7.1).  It does
      not establish freshness against whole-object rollback, which a
      consuming protocol must supply.

Sullivan                 Expires 24 January 2027                [Page 5]
Internet-Draft                    raAE                         July 2026

   raAE and SEAL are deliberately distinct layers.  A consuming protocol
   supplies serialization, storage transactions, key management, and
   rollback protection, which are out of scope here.  The full boundary
   of what raAE does not provide is Section 6.10.

   The remainder of this document presents raAE first and SEAL second.
   Section 1.1 situates raAE against prior segmented authenticated-
   encryption (AE) constructions.  Section 2 fixes terminology and
   notation.  Section 3 specifies the extended raAE primitive and its
   snapshot operations.  Section 4 defines SEAL.  Section 5 states the
   target security properties an raAE construction must meet, the
   assumptions SEAL's components must satisfy, and the operational
   limits on its use, and defines the security notions.  Cipher suites,
   serialization layouts, named instantiations, and test vectors are
   specified in the companion document [I-D.sullivan-seal-concrete].

1.1.  Related Work

   CHAIN ([HRRV15]) is a segmented authenticated-encryption construction
   that chains state from one segment to the next.  It is sequential by
   construction and supports neither independent random-access reads nor
   in-place segment rewrites.

   STREAM ([HRRV15]) turns a nonce-based AEAD into a segmented
   construction using induced nonces that encode a message nonce, the
   segment index, and a final-segment bit.  STREAM supports random-
   access decryption and encryption of individual segments, but defines
   neither authenticated snapshots nor authenticated rewrites.  SEAL's
   derived nonce mode (Section 4.5.3.2) follows STREAM's counter-plus-
   final-bit structure and adds those operations.

   Tink Streaming AEAD ([Tink]) and OpenPGP v2 Symmetrically Encrypted
   and Integrity Protected Data (SEIPD) packets ([RFC9580]) are deployed
   STREAM-family formats.  Both derive a message key and nonce prefix
   from a key and a salt, encrypt each chunk under an AEAD nonce
   carrying the chunk index, and detect truncation with a final tag over
   the empty string.  Tink derives an AES-GCM key with the HMAC-based
   Key Derivation Function (HKDF) ([RFC5869]), while v2 SEIPD selects
   its cipher and AEAD from packet identifiers.  Each chunk is
   independently authenticated and can be verified locally at its
   boundary.  Neither format defines an in-place rewrite operation or a
   snapshot authenticator over an updatable set of segment tags.

   SEAL's snapshot authenticator addresses exactly that gap.  Its per-
   segment input is the segment's metadata leaf, which binds the
   segment's content when the segment commitment is set.  It verifies
   the whole segment set against the snapshot, and optionally a single
   segment (Section 4.7.1).  A consuming protocol that authenticates the

Sullivan                 Expires 24 January 2027                [Page 6]
Internet-Draft                    raAE                         July 2026

   one snapshot value obtains integrity over the whole segment set and
   its count, and, where the segment commitment is set over a strict
   ordering, per-segment origin authentication that holds against
   holders of the content-encryption key (CEK).

   Fábrega et al.  ([FLRR25]) formalized random-access AEAD security
   over a raAE primitive syntax in which segment encryption and
   decryption may be invoked in arbitrary order, and gave a
   construction, FLOE (Fast Lightweight Online Encryption), proved to
   meet it.  FLOE realizes the base interface: segments are written
   once, and there is no snapshot.  SEAL realizes that primitive with
   the extension of this document, and Section 5.1 defines the security
   notions used in its analysis.

   Each precedent covers part of the random-access AE design space.
   raAE is the abstract interface that generalizes the family with three
   capabilities none of the precedents combines: arbitrary-order
   encryption, in-place authenticated rewrite, and a snapshot over the
   whole segment set.  SEAL realizes all three in one construction.

2.  Conventions and 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.

   A message segment is a unit of plaintext that is individually
   encrypted and authenticated.  Segments need not be uniform in length.
   A construction MAY set a maximum segment size, and any segment may be
   shorter than that maximum.

   A message is the content that one CEK and salt pair protects, the
   unit the primitive encrypts.  An object is that message in stored
   form: the ciphertext segments, their metadata, and any snapshot that
   a storage layer holds.  Each object carries one message, whose
   content may change through rewrite and length-changing operations.

   A ciphertext core is the AEAD encryption output corresponding to one
   message segment, excluding file-level headers and external segment
   metadata.  An AEAD-specific split divides this output into ct_i, the
   encrypted segment body, and tag_i, the authentication tag.

   A ciphertext segment is the stored representation of one encrypted
   message segment.  Depending on nonce_mode, it contains the ciphertext
   core and may also contain a stored nonce or other per-segment
   metadata.

Sullivan                 Expires 24 January 2027                [Page 7]
Internet-Draft                    raAE                         July 2026

   Segment metadata is per-segment information needed to decrypt or
   verify a ciphertext segment, such as a stored nonce, tag, finality
   status, or profile-defined values.

   This document writes AEAD.Encrypt and AEAD.Decrypt for the
   authenticated encryption and decryption operations defined in
   [RFC5116].

   Symbol form follows the layer a name belongs to.  The abstract
   interface and the analysis use mathematical notation: a capital
   letter is an operand of that interface, either an octet string (K, N,
   G, T_g, A_i, M_i, C_i) or the per-message state (S).  A lowercase
   letter is an integer index or bound (i, e, p, r).

   N with a lowercase letter is a size that a chosen component fixes
   rather than one a deployment picks: the AEAD (Nk, Nn, Nt, Nb), the
   KDF (Nh), the snapshot authenticator (Na), or the nonce mode (Np).
   Everything the construction names concretely uses lowercase
   snake_case, whatever its type: octet strings (salt, commitment,
   segment_key, ct_i), counts (n_seg, n_ep), lengths a deployment
   configures (segment_max, commitment_length), and identifiers, which
   take an _id suffix (aead_id, kdf_id, snap_id, protocol_id).

   Names that take arguments follow the same split.  Initialisms are
   capitalized (LH, KDF, AEAD, XOF).  The raAE tuple is CamelCase
   (KeyGen, StartEnc, EncSeg, StartDec, DecSeg, RewriteSeg, SnapVerify),
   while the methods of a component it parameterizes over are lowercase
   (snapshot, verify, add, remove, set_length), so a name shows which
   interface it belongs to.  Derivations this document defines are
   lowercase (encode, frame, leaf, nonce).

   A subscript selects one instance of a value: X_i is X for the segment
   at index i, as in A_i, P_i, ct_i, and tag_i, and d_e is the epoch
   head for epoch e.  A value written f(i), as in segment_key(i) or
   nonce(i), is the value that the named derivation defines for index i.

   Two suffixes and one prefix recur.  A _label suffix is an ASCII
   constant that separates one derivation from another (aad_label,
   epoch_key_label).  A _calc suffix marks a value recomputed for
   comparison against a stored one (d_calc(e), leaf_calc(i)).  An Adv_
   prefix names an adversary's advantage in the analysis (Adv_snap,
   Adv_muPRF).

   The remaining terms (ikm, label, info, L, salt, CEK, protocol_id,
   nonce_mode, epoch, epoch_key, payload_key, segment_key, snap_key, and
   the commitment) are defined in Section 4 where they first appear.

Sullivan                 Expires 24 January 2027                [Page 8]
Internet-Draft                    raAE                         July 2026

2.1.  Taxonomy

   This document uses the following terms to keep the raAE primitive,
   the SEAL construction, profiles, and consuming protocols distinct.

   raAE primitive:  The abstract random-access AE interface and security
      target.

   Extended raAE interface:  The base interface plus snapshot
      maintenance and verification.

   SEAL construction:  The construction specified in Section 4.

   Cipher suite:  The AEAD and KDF algorithms and their sizes.

   Profile:  A named set of fixed parameter choices, identified by a
      protocol_id, needed for interoperability.

   Parameter set:  The per-object values that affect derivation and
      verification.

   Consuming protocol:  The protocol or format that stores objects and
      manages keys.

   Serialization:  The consuming protocol's wire or storage encoding.

   Segment:  A zero-based independently encrypted plaintext unit.

   Epoch:  A group of 2^epoch_length segment indices sharing one epoch
      key.

   Snapshot value:  The public value that, when a snapshot authenticator
      is configured, authenticates one segment set.

   Snapshot authenticator:  A pluggable SEAL component that produces and
      verifies the snapshot value.  Its abstract interface is
      Section 4.7.1, and its concrete instantiations are in
      [I-D.sullivan-seal-concrete].

   Per-segment authenticity:  AEAD verification for one segment only.

   Snapshot integrity:  Verification of the complete segment set and
      snapshot.

   Segment commitment:  A hash of one segment's ciphertext, stored in
      that segment's metadata.  It binds the segment's content, not its
      position (Section 4.7.1).

Sullivan                 Expires 24 January 2027                [Page 9]
Internet-Draft                    raAE                         July 2026

   External freshness:  Rollback protection supplied outside raAE.

2.2.  Notation

   I2OSP(n, w):  The w-octet big-endian encoding of the non-negative
      integer n, as defined in [RFC8017].

   uint8(n), uint16(n), uint32(n), uint64(n):  Shorthand for I2OSP(n,
      1), I2OSP(n, 2), I2OSP(n, 4), and I2OSP(n, 8) respectively.

   ||:  Octet string concatenation.

   XOR:  Bitwise exclusive-or of two octet strings of equal length.

   X[a:b]:  Octets a through b-1 inclusive of X (zero-based, half-open
      interval).

   [x, y, ...]:  An ordered list of octet strings.  A single-element
      list is written [x].  The brackets denote a list, not an optional
      parameter.

   frame, encode:  The length-prefixed injective encoding used by SEAL,
      defined in Section 4.3.  frame is total over all field lengths.
      The construction requires an injective framing (Section 5.4) but
      does not mandate this encoding.  Another profile MAY use any
      injective encoding that meets Section 5.4.

   Nk:  Key size in octets for the chosen AEAD algorithm.

   Nn:  Nonce size in octets for the chosen AEAD algorithm.

   Np:  Presented nonce size in octets: the per-segment nonce stored in
      metadata.  Np = Nn in random nonce mode and Np = 0 in derived
      nonce mode, where the nonce is recomputed from the key schedule.

   Nh:  Hash or pseudorandom function (PRF) output size in octets for
      the chosen KDF.

   Nt:  Authentication tag size in octets for the chosen AEAD algorithm.

   Nb:  Cipher block size in octets for the chosen AEAD algorithm,
      defined only for an AEAD built on a block cipher.  The block-size
      birthday limit of Section 5.8 is expressed in Nb and does not
      apply to an AEAD with no block-cipher structure.

   Na:  The snapshot value length in octets, the output size of the
      configured snapshot authenticator.  It MAY depend on the segment
      count n_seg, and is 0 when none (Section 4.7).

Sullivan                 Expires 24 January 2027               [Page 10]
Internet-Draft                    raAE                         July 2026

   n_seg:  The number of ciphertext segments in a stored message.
      Written n_seg (lowercase) to distinguish it from the per-message
      nonce N in the raAE interface (Section 3.2).

3.  The raAE Primitive

3.1.  Overview

   Random-access authenticated encryption (raAE) partitions a message
   into segments, each encrypted and decrypted on its own and in any
   order.  A reader can open one segment without the rest of the
   message, and a writer can encrypt one without holding the others.  In
   the base interface [FLRR25], each segment is written once and
   thereafter only read.

   The extended raAE interface keeps that base and adds one capability:
   a segment already written may be replaced in place, without
   disturbing the rest.  Rewriting changes the threat model.  Per-
   segment authentication binds each segment in isolation, so it cannot
   tie the segments a reader assembles to a single recorded version of
   the object: a storage layer holding the ciphertext can roll a segment
   back to an older valid copy, substitute one valid same-index segment
   for another, or drop one, and each segment it presents still
   authenticates.  An optional snapshot authenticates the segment set as
   the writer last recorded it, so a reader can detect these changes.
   The extension (Section 3.3) defines the snapshot and the operations
   that maintain it.

   The security notions follow the interface.  raAE and its rewrites
   target ra-ROR (random-access real-or-random) and ra-CMT (random-
   access context commitment) (Section 5.1).  Rewriting leaves both
   untouched, since replacing a segment is an encryption the read-only
   adversary could already ask for.  Snapshot authentication adds the
   one notion of its own, snapshot integrity (Section 5.1.4).

3.2.  Interface

   The base raAE interface, from [FLRR25], is a tuple of five
   algorithms: KeyGen, StartEnc, EncSeg, StartDec, and DecSeg.

   KeyGen:  Randomized key generation.  Takes no input.  Outputs a
      secret key K.

   StartEnc(K, N, G):  Deterministic.  Takes a secret key K, nonce N,
      and global associated data G.  Outputs a ciphertext header T_g and
      an initial per-message encryption state S.

   EncSeg(S, p, A_i, M_i):  Randomized.  Takes the encryption state S, a

Sullivan                 Expires 24 January 2027               [Page 11]
Internet-Draft                    raAE                         July 2026

      position identifier p, per-segment associated data A_i, and
      message segment M_i.  Outputs a ciphertext segment C_i.  S is not
      modified.  EncSeg may be called with the same S at any position,
      in any order, or concurrently.

   StartDec(K, N, G, T_g):  Deterministic.  Takes key K, nonce N, global
      associated data G, and ciphertext header T_g.  Outputs a per-
      message decryption state S or an error.

   DecSeg(S, p, A_i, C_i):  Deterministic.  Takes the decryption state
      S, position identifier p, per-segment associated data A_i, and
      ciphertext segment C_i.  Outputs message segment M_i or an error.

   The position identifier p = (i, b) consists of a segment number i and
   a terminal bit b in {0, 1}.  They impose a total ordering on segments
   and carry a truncation defense: a ciphertext lacking a segment with b
   = 1 is incomplete.  The encryption state S is immutable.  That
   immutability is what makes arbitrary-order and fully parallel
   operation possible.  The ciphertext header T_g commits to K, the
   nonce N, and global associated data G.  A headerless scheme emits T_g
   = empty.

3.3.  Extended Interface

   Replacing a segment already written, without re-encrypting the
   others, requires no new operation: re-encrypting a position is an
   ordinary EncSeg call over the immutable state, and it leaves ra-ROR
   and ra-CMT untouched.

   A scheme that supports rewriting MAY carry a snapshot, a value over
   the current set of segments that a reader checks to detect tampering
   that per-segment authentication does not catch.  A write-once scheme
   MAY carry one too: a single value that a consuming protocol
   authenticates once for the whole segment set (Section 4.7.1).

   Two operations, added by this document, maintain and check the
   snapshot.  RewriteSeg replaces a segment and updates the snapshot in
   the same step.  SnapVerify decides whether a given set of segments is
   the one the writer last recorded.

   RewriteSeg(S, p, A_i, M'_i, C_i, snapshot):  Randomized.  Takes the
      encryption state S and position identifier p, per-segment
      associated data A_i, the new message segment M'_i, the existing
      ciphertext C_i at position p, and the current snapshot.  Outputs
      replacement ciphertext C'_i and an updated snapshot value,
      snapshot'.

   SnapVerify(S, segments, snapshot):  Deterministic.  Takes the

Sullivan                 Expires 24 January 2027               [Page 12]
Internet-Draft                    raAE                         July 2026

      encryption state S, the segments to verify as (position,
      ciphertext segment) pairs, and the snapshot.  These are either the
      whole current object state or, where the authenticator supports
      it, a designated subset of it.  Outputs accept or reject.

   The extension also changes two base signatures.  In the extended
   interface:

   StartEnc(K, N, G):  Deterministic.  As in Section 3.2, and
      additionally outputs the initial snapshot value, the snapshot over
      the empty segment set.

   EncSeg(S, p, A_i, M_i):  Randomized.  As in Section 3.2, and
      additionally outputs the snapshot value over the segment set that
      results from adding C_i at position p.

   The snapshot is an authenticator over the set of segments belonging
   to the current object state.  The base primitive has no snapshot
   value.

   These additions define the extended raAE interface of this document:
   the tuple (KeyGen, StartEnc, EncSeg, StartDec, DecSeg, RewriteSeg,
   SnapVerify) over the snapshot value.  The first five algorithms are
   those of Section 3.2.  The snapshot value, RewriteSeg, and SnapVerify
   are the extension.  A scheme can realize the base interface alone, as
   FLOE ([FLRR25]) does.  SEAL (Section 4) realizes the full extended
   interface.

   Changing a message's length is a composition of these operations, not
   a separate algorithm in either direction.  Position-addressed
   encryption over immutable state already permits re-encrypting a
   position or encrypting at a higher index (see Section 5.1.1).

   A holder appends by encrypting the new segments and re-marking the
   old final segment with RewriteSeg to clear its terminal bit.  It
   truncates by re-marking the new final segment with RewriteSeg,
   dropping the trailing segments, and updating the snapshot over the
   surviving set.  Appending to an empty object skips the re-mark, since
   there is no old final segment, and truncating away every segment
   yields the empty object, with no new final segment to re-mark.

   A length change appends segments or drops a suffix.  Each step
   updates the snapshot, and Section 4.9.3 gives the construction for
   both directions.

Sullivan                 Expires 24 January 2027               [Page 13]
Internet-Draft                    raAE                         July 2026

4.  The SEAL Construction

   SEAL is a construction for the raAE primitive of Section 3, realizing
   its extended interface from a KDF, an AEAD, the labels, a nonce-
   generation method, and an optional snapshot authenticator.  Its KDF
   combiner (Section 4.3) frames every derived key and input over any
   KDF with a two-step or one-step form.  SEAL provides commitment
   around the AEAD, which need not itself commit.

   A SEAL construction MAY select any AEAD, KDF, nonce mode, commitment
   configuration, or snapshot authenticator that satisfies the
   requirements of this section.  Section 5 derives SEAL's bounds from
   the abstract properties of these components.  Concrete parameter
   choices and interoperable suites are in [I-D.sullivan-seal-concrete].

   In the key hierarchy below, a CEK and per-content salt feed the
   payload schedule, which derives four per-message values
   (Section 4.5).

Sullivan                 Expires 24 January 2027               [Page 14]
Internet-Draft                    raAE                         July 2026

                     CEK + salt
                         |
                         v
                  .-----------.
                  |  Payload  |
                  |  Schedule |
                  '-----------'
               /     |      |     \
              v      v      v      v
          commit  payload  nonce   snap
                   key     base    key
            |       |       |       |
            v       v       v       |
          .---.  .------. .-----.   |
          |cmt|  |seg   | |nonce|   |
          |   |  |key(i)| | (i) |   |
          '---'  '------' '-----'   |
                     \       /      |
                      \     /       |
                       v   v        |
                    .----------.    |
                    |   AEAD   |    |
                    |  Seal(i) |    |
                    '----------'    |
                      /      \      |
                     v        v     |
                   ct_i     tag_i   |
                               \    |
                                v   v
                        .-----------------.
                        |    Snapshot     |
                        |  Authenticator  |
                        '-----------------'
                                 |
                                 v
                             snapshot

                        Figure 2: SEAL Key Hierarchy

   The figure shows each segment's tag feeding the authenticator.  Its
   actual per-segment input is the segment's metadata leaf
   (Section 4.7.1).

Sullivan                 Expires 24 January 2027               [Page 15]
Internet-Draft                    raAE                         July 2026

4.1.  Construction Overview

   The commitment lets a reader reject a wrong key or parameter set
   before decrypting.  The snapshot, when present, authenticates the
   current segment set.  SEAL realizes the raAE operations of
   Section 3.2 as follows:

         +============+==========================================+
         | raAE       | SEAL realization                         |
         | operation  |                                          |
         +============+==========================================+
         | StartEnc   | Derive the payload schedule from the CEK |
         |            | and salt, committing G (Section 4.5)     |
         +------------+------------------------------------------+
         | StartDec   | Re-derive the schedule and verify the    |
         |            | stored commitment (Section 4.6)          |
         +------------+------------------------------------------+
         | EncSeg,    | EncryptSegment and DecryptSegment        |
         | DecSeg     | (Section 4.8)                            |
         +------------+------------------------------------------+
         | RewriteSeg | RewriteSegment, then update the snapshot |
         |            | authenticator for the changed segment    |
         |            | (Section 4.9.2.1)                        |
         +------------+------------------------------------------+
         | SnapVerify | Check the present indices and finality,  |
         |            | then verify the snapshot via the         |
         |            | authenticator (Section 4.7)              |
         +------------+------------------------------------------+

            Table 1: raAE operations and their SEAL realizations

   SEAL's salt, payload_info, and G carry the raAE per-message inputs,
   and the commitment stands in for the header (Section 4.2).

4.2.  Component Suite and Parameters

   Table 2 lists the parameters, inputs, and derived values, with what
   sets each and where it is defined.

    +===================+===================+=============+==========+
    | Parameter         | Type or range     | Set by      | Defined  |
    |                   |                   |             | in       |
    +===================+===================+=============+==========+
    | AEAD              | RFC 5116          | suite       | Section  |
    |                   | algorithm         |             | 4.2.1    |
    +-------------------+-------------------+-------------+----------+
    | KDF               | KDF algorithm     | suite       | Section  |
    |                   |                   |             | 4.3      |

Sullivan                 Expires 24 January 2027               [Page 16]
Internet-Draft                    raAE                         July 2026

    +-------------------+-------------------+-------------+----------+
    | segment_max       | power of two, at  | suite       | Section  |
    |                   | least 4096        |             | 4.2.1    |
    +-------------------+-------------------+-------------+----------+
    | epoch_length      | integer r in 0 to | suite       | Section  |
    |                   | 63                |             | 4.5.2    |
    +-------------------+-------------------+-------------+----------+
    | protocol_id       | octet string      | application | Section  |
    |                   |                   |             | 6.11     |
    +-------------------+-------------------+-------------+----------+
    | nonce_mode        | "random" or       | message,    | Section  |
    |                   | "derived"         | within the  | 4.5.3    |
    |                   |                   | profile     |          |
    +-------------------+-------------------+-------------+----------+
    | aad_label         | ASCII string      | profile     | Section  |
    |                   |                   |             | 4.4.2    |
    +-------------------+-------------------+-------------+----------+
    | commitment_length | integer, at least | profile     | Appendix |
    |                   | 16, default Nh    |             | C.4      |
    +-------------------+-------------------+-------------+----------+
    | Nk, Nn, Nt, Nb    | sizes in octets   | AEAD        | Section  |
    |                   |                   |             | 2.2      |
    +-------------------+-------------------+-------------+----------+
    | Nh                | size in octets    | KDF         | Section  |
    |                   |                   |             | 2.2      |
    +-------------------+-------------------+-------------+----------+
    | CEK               | 32 uniform random | message     | Section  |
    |                   | octets            | input       | 4.5      |
    +-------------------+-------------------+-------------+----------+
    | salt              | 32 uniform random | message     | Section  |
    |                   | octets            | input       | 4.5      |
    +-------------------+-------------------+-------------+----------+
    | payload_info      | ordered element   | message     | Section  |
    |                   | list              | input       | 4.4      |
    +-------------------+-------------------+-------------+----------+
    | G                 | octet string,     | message     | Section  |
    |                   | empty by default  | input       | 4.6      |
    +-------------------+-------------------+-------------+----------+
    | commitment        | commitment_length | derived per | Section  |
    |                   | octets            | message     | 4.5      |
    +-------------------+-------------------+-------------+----------+
    | payload_key       | Nk octets         | derived per | Section  |
    |                   |                   | message     | 4.5      |
    +-------------------+-------------------+-------------+----------+
    | snap_key          | Nh octets         | derived per | Section  |
    |                   |                   | message     | 4.5      |
    +-------------------+-------------------+-------------+----------+
    | nonce_base        | Nn octets,        | derived per | Section  |

Sullivan                 Expires 24 January 2027               [Page 17]
Internet-Draft                    raAE                         July 2026

    |                   | derived mode only | message     | 4.5      |
    +-------------------+-------------------+-------------+----------+
    | epoch_key(i)      | Nk octets         | derived per | Section  |
    |                   |                   | segment     | 4.5.2    |
    +-------------------+-------------------+-------------+----------+
    | segment_key(i)    | Nk octets         | derived per | Section  |
    |                   |                   | segment     | 4.5.2    |
    +-------------------+-------------------+-------------+----------+
    | nonce(i)          | Nn octets         | derived per | Section  |
    |                   |                   | segment     | 4.5.3    |
    +-------------------+-------------------+-------------+----------+
    | segment_aad(i,    | octet string      | derived per | Section  |
    | is_final, A_i)    |                   | segment     | 4.4.2    |
    +-------------------+-------------------+-------------+----------+
    | tag_i             | Nt octets         | derived per | Section  |
    |                   |                   | segment     | 4.8      |
    +-------------------+-------------------+-------------+----------+

             Table 2: Parameters, inputs, and derived values

   SEAL fixes the segment additional authenticated data (AAD) encoding
   (Section 4.4.2), the commitment derivation (Section 4.6), and the
   snapshot value (Section 4.7) identically across all suites.  Their
   octet lengths still vary by suite, because Nh and Nt are suite-
   dependent.

4.2.1.  Suite Choices

   A suite is assembled from the following choices.

   AEAD:  An authenticated encryption with associated data algorithm
      satisfying the interface of [RFC5116], with Nk-octet keys, Nn-
      octet nonces, and Nt-octet authentication tags.

   KDF:  A key derivation function supporting the abstract interface
      defined in Section 4.3.

   segment_max:  A positive integer, a power of two and at least 4096
      octets.  Each segment carries at most this many plaintext octets.
      The length-dependent limits of Section 5.8 are computed at this
      size.

   epoch_length:  A non-negative integer r in 0 to 63.  Each epoch
      covers 2^r consecutive segments aligned to a multiple of 2^r, so r
      sets the key-rotation granularity: r = 0 gives a fresh epoch key
      per segment and r = 63 one key for all segments (Section 4.5.2).
      Profiles MAY restrict r further per AEAD.

Sullivan                 Expires 24 January 2027               [Page 18]
Internet-Draft                    raAE                         July 2026

   protocol_id:  An application-chosen octet string that binds all
      derived values to a specific protocol version.  Selection guidance
      is in Section 6.11.

   nonce_mode:  A payload_info element selecting one of two nonce
      constructions, "random" or "derived".  The constructions are
      defined in Section 4.5.3, and the valid (nonce_mode, snap_id)
      tuples depend on the profile.

4.2.2.  Profile-Level Constants

   One constant is fixed by the profile rather than carried per message.

   aad_label:  A profile-level ASCII string bound as the first element
      of the segment AAD encoding (Section 4.4.2).  Consuming protocols
      MAY define their own profiles with a distinct aad_label.

4.2.3.  Algorithm-Determined Sizes

   The sizes Nk, Nn, Nt, and Nh are fixed by the chosen AEAD and KDF
   rather than by the parameter set directly, as is Nb where it is
   defined.  They are defined in Section 2.2.  One configurable length
   defaults from Nh.

   commitment_length:  A positive integer of at least 16, defaulting to
      Nh, the length in octets of the key commitment prefix.  The
      collision bounds for each length are given in Appendix C.4.

4.2.4.  Per-Message Inputs

   An encrypted message is built from four input values.

   CEK:  A 32-octet uniform random Content Encryption Key generated
      fresh for each message.  The CEK is input keying material for the
      key schedule, not an AEAD key.

   salt:  A per-content value of 32 uniformly random octets.  The salt
      separates payload schedule outputs across messages even when the
      CEK is reused.  Section 4.9.1.1 and Section 4.9.3 give the rules
      for generating and reusing it, and Section 6.7 analyzes the
      consequences of reuse.

   payload_info:  The committed record of the object's configuration: an
      ordered list of parameter set context elements covering key
      derivation, AEAD operations, AAD construction, and nonce
      construction, which the commitment (Section 4.6) binds.  The
      profile fixes the concrete element set and their encodings.
      SEAL's payload_info is specified in Section 4.4.

Sullivan                 Expires 24 January 2027               [Page 19]
Internet-Draft                    raAE                         July 2026

   G:  An octet string of global associated data, the G input of
      StartEnc in the raAE primitive (Section 3.2), binding whole-
      message application context such as a name, version, or policy.  G
      defaults to the empty octet string and is never stored: a
      decryptor supplies it from application context, and the commitment
      binds it (Section 4.6).

   The remaining symbols in Table 2 are derived values.  The payload
   schedule computes the per-message values once from the CEK and
   payload_info, fixing them for the message's lifetime (Section 4.5).
   The commitment additionally binds G (Section 4.6).  Per-segment
   values are defined where they are computed, in the sections Table 2
   cites.

4.3.  The KDF Combiner

   The KDF combiner uses a length-prefixed encoding for all of its
   inputs.

   frame(x):
       if len(x) <= 0xFFFE:  return uint16(len(x)) || x     ;; literal
       else:                 return uint16(0xFFFF) || LH(x) ;; digest

   encode(x1, ..., xn) = frame(x1) || ... || frame(xn)

   frame is total over every field length.  A field too large to emit
   literally is instead prefixed by the reserved length 0xFFFF and an
   Nh-octet digest LH(x).

   LH(x), the over-large-field digest, runs the cipher suite's native
   KDF primitive directly on x, invoking neither encode nor frame, and
   returns Nh octets.  The two-step and one-step classes are HPKE's: a
   two-step KDF ([RFC9180]) uses its extract step, and a one-step KDF
   ([I-D.ietf-hpke-pq]) its XOF, with x carried under the label "raAE-
   LP-v1":

   two-step:  LH(x) = Extract("raAE-LP-v1", x)
   one-step:  LH(x) = XOF("raAE-LP-v1" || x, Nh)

   Running LH through the full KDF would re-enter frame on the over-
   large x and recurse.  The direct native call avoids that.

Sullivan                 Expires 24 January 2027               [Page 20]
Internet-Draft                    raAE                         July 2026

   Section 5.4 requires the construction to justify the collision
   resistance of the over-large-field digest.  LH's is that of the
   cipher suite's KDF primitive at the suite's Nh.  In the two-step
   class LH(x) is HMAC under the fixed public key "raAE-LP-v1", so a
   collision in LH yields a collision in the underlying hash, by the
   reduction Section 5.3 gives for the commit derivation.  In the one-
   step class LH(x) is the XOF itself over a domain-separated input, so
   a collision in LH is a collision in the XOF at that output length.

   The injectivity of encode, and LH's domain separation from the
   literal encoding, are established in Section 5.4.

   Key material is derived through a KDF with the interface

   KDF(protocol_id, label, ikm, info, L)

   *  protocol_id: binds the output to a specific protocol version and
      application context.

   *  label: a unique ASCII string identifying the derivation role.

   *  ikm: input keying material, provided as a single octet string or
      an ordered list of octet strings.

   *  info: context information, provided as a single octet string or an
      ordered list of octet strings.

   *  L: the requested output length in octets.

   This KDF binds protocol_id, a label, and inputs of any size into a
   derived value.  frame reduces any over-large input to a fixed-size
   digest before the KDF sees it.  Any protocol instantiates the
   combiner by supplying its own protocol_id, which domain-separates its
   derivations from those of every other protocol.

   The KDF is built from the cipher suite's hash in one of two forms.
   The cipher suite's kdf_id selects which one.

4.3.1.  Two-Step KDF

   KDF(protocol_id, label, ikm, info, L):
     extract_input = encode(protocol_id, label,
                            ...ikm)
     prk = Extract(salt=protocol_id,
                   ikm=extract_input)
     expand_info = encode(protocol_id, label,
                          ...info, uint16(L))
     return Expand(prk, expand_info, L)

Sullivan                 Expires 24 January 2027               [Page 21]
Internet-Draft                    raAE                         July 2026

   The notation ...x means each element of the sequence x, whether ikm
   or info, is a separate argument to encode.  A single octet string is
   the one-element sequence containing it.  An absent value is the empty
   sequence and contributes no arguments.  The empty sequence and the
   one-element sequence whose element is the empty octet string are
   distinct: the first adds nothing to the encode, the second adds one
   zero-length field.  A derivation with no info MUST use the empty
   sequence, not the empty octet string, so that every implementation
   encodes a given (protocol_id, label, ikm, info, L) tuple to the same
   octets.  The protocol_id appears in both the Extract salt and the
   extract_input as a defensive measure, and binding in either position
   suffices for domain separation.

   The label appears in both Extract and Expand so that label binding is
   preserved even if one phase is weak in isolation.  Implementations
   MAY amortize the Extract computation internally when deriving
   multiple outputs from the same protocol_id, label, and ikm.

4.3.2.  One-Step KDF

   KDF(protocol_id, label, ikm, info, L):
     M = encode(protocol_id, label,
                encode(...ikm), encode(...info),
                uint16(L))
     return XOF(M, L)

   The XOF-based form frames ikm and info each as a single element of
   one length-prefixed encode and squeezes L octets of output.
   protocol_id binding is via the message-side encode prefix only.  In
   both forms the encoded input ends with uint16(L): the two-step form
   places it last in expand_info and the one-step form places it last in
   M.  Within a fixed kdf_id, distinct (protocol_id, label, ikm, info,
   L) tuples yield distinct outputs, by the injectivity of encode
   (established in Section 5.4).  The two forms are not mutually
   injective: a cipher suite's kdf_id selects one form for that suite,
   and payload_info commits to the kdf_id (Section 4.4), so no
   derivation ever compares outputs across forms.  The two-step form
   binds ikm in Extract and info in Expand.  A multi-value ikm or info
   is the encode of its elements, so any number of elements is admitted.

4.4.  SEAL Encodings and Labels

4.4.1.  Payload Info Construction

  payload_info = [aead_id, segment_max_be, kdf_id, snap_id,
                  segment_commitment, nonce_mode, epoch_length_u8, salt]

   Element encodings for SEAL:

Sullivan                 Expires 24 January 2027               [Page 22]
Internet-Draft                    raAE                         July 2026

   *  aead_id: 2 octets, uint16(id), the unsigned 16-bit AEAD
      identifier.

   *  segment_max_be: 4 octets, uint32(segment_max).

   *  kdf_id: 2 octets, uint16(id), the unsigned 16-bit KDF identifier.

   *  snap_id: 2 octets, uint16(id), the snapshot authenticator
      identifier.

   *  segment_commitment: 1 octet, 0x00 when the leaf does not bind the
      segment's content and 0x01 when it does (Section 4.7.1).  It is a
      choice independent of snap_id, but not every (snap_id,
      segment_commitment) pair is sound, so a profile selects a valid
      one.

   *  nonce_mode: 1 octet, the nonce construction: 0x00 for random, 0x01
      for derived.  A profile MAY select any valid (nonce_mode, snap_id,
      segment_commitment) tuple.

   *  epoch_length_u8: 1 octet, uint8(epoch_length).  Implementations
      MUST reject epoch_length >= 64 on both encode and decode.

   *  salt: 32 raw octets, the per-message salt.

   The aad_label is a profile-level constant for SEAL (see
   Section 4.4.2) and is not carried in payload_info.  The KDF
   (Section 4.3) applies frame to each element of the list.

4.4.2.  Segment AAD

   The segment AAD binds each segment to its context.  What it must
   carry depends on the nonce mode: a random nonce binds neither the
   segment index nor the finality bit, so the AAD must, whereas a
   derived nonce binds both (Section 4.5.3.2).

   segment_aad(i, is_final, A_i):
     if nonce_mode is "random":
       if A_i is empty:
         return encode(aad_label, uint64(i), uint8(is_final))
       return encode(aad_label, uint64(i), uint8(is_final), A_i)
     ;; derived nonce mode
     if A_i is empty:
       return ""
     return encode(aad_label, A_i)

Sullivan                 Expires 24 January 2027               [Page 23]
Internet-Draft                    raAE                         July 2026

    +=============+======================+============================+
    |             | Random nonce mode    | Derived nonce mode         |
    +=============+======================+============================+
    | Index i and | bound in the AAD     | bound in the nonce         |
    | is_final    |                      |                            |
    +-------------+----------------------+----------------------------+
    | A_i, when   | appended as a fourth | the sole variable element  |
    | present     | encode element       |                            |
    +-------------+----------------------+----------------------------+
    | A_i, when   | omitted, not a zero- | segment_aad is empty, with |
    | empty       | length element       | no associated-data pass    |
    +-------------+----------------------+----------------------------+

                     Table 3: Segment AAD by nonce mode

   aad_label is the profile-chosen label from the parameter set, the
   index i is a big-endian 8-octet integer, and is_final is 1 for the
   last segment and 0 for all others.  Because encode length-prefixes
   every element, omitting an empty A_i stays injective, so the index
   and finality bit remain authenticated.  Any profile that defines a
   random-mode segment_aad MUST preserve injectivity and MUST
   authenticate the segment index and finality bit.  aad_label is bound
   transitively through protocol_id (Section 6.3), so segment_aad need
   not repeat it for cross-profile separation.

   More generally, the binding of the triple (i, is_final, A_i) MUST be
   unambiguous under one segment key, so that no two distinct triples
   present the same inputs to the AEAD.  In random nonce mode
   segment_aad alone MUST injectively bind the triple, because the nonce
   is an independent random draw.  In derived nonce mode i and is_final
   are bound in the nonce and A_i, when present, in segment_aad, and the
   (nonce, segment_aad) pair MUST jointly determine the triple
   (Section 4.5.3.2).

   A_i is the caller-supplied per-segment associated data of EncSeg and
   DecSeg (Section 3.2), passed to the segment algorithms (Section 4.8).
   It MAY be empty and MAY differ per segment.  Unlike a global
   associated data value G, which the commitment fixes at creation
   (Section 4.6), A_i rides the per-segment AEAD associated data and is
   rewritable: a rewrite can change a segment's A_i.

   The salt is not included in the AAD because it is already bound into
   segment_key via the payload schedule.  Different messages produce
   different segment keys even at the same index.  Transposing two
   segments within a message fails because the AAD at each position
   encodes the expected index.

Sullivan                 Expires 24 January 2027               [Page 24]
Internet-Draft                    raAE                         July 2026

   Because each segment binds its index and finality bit (through the
   AAD or the nonce, per Table 3), these truncation and extension
   attacks are caught by per-segment authentication alone, not by the
   snapshot, and a reader checks them locally before decrypting any one
   segment.  Unauthorized truncation is detectable and Section 4.9.1.2
   requires a decryptor to reject it: a highest-indexed present segment
   carrying is_final = 0 signals missing data.  Authorized truncation by
   the CEK holder instead re-marks the new final segment and updates the
   snapshot (Section 4.9.3).  Appending after a segment marked is_final
   = 1 either invalidates that segment on re-read or produces a
   ciphertext that cannot verify.

   The per-segment AEAD binds a segment's index and finality, not its
   length, by the same means.  A segment's ciphertext length is
   authenticated implicitly by the AEAD tag over the ciphertext:
   altering, truncating, or splicing a segment ciphertext is an AEAD
   forgery, not a parsing ambiguity.  Because segments may be shorter
   than segment_max, the consuming format MUST convey each segment's
   ciphertext length to the decoder.  A wrong length yields an AEAD
   rejection, never a silent accept.

4.4.3.  Labels

    +============================+===================+===============+
    | Derivation role            | Label variable    | Value         |
    +============================+===================+===============+
    | Commitment                 | commit_label      | "commit"      |
    +----------------------------+-------------------+---------------+
    | Payload key                | payload_key_label | "payload_key" |
    +----------------------------+-------------------+---------------+
    | Snapshot authenticator key | snap_key_label    | "snap_key"    |
    +----------------------------+-------------------+---------------+
    | Nonce base                 | nonce_base_label  | "nonce_base"  |
    +----------------------------+-------------------+---------------+
    | Epoch key                  | epoch_key_label   | "epoch_key"   |
    +----------------------------+-------------------+---------------+

                  Table 4: SEAL core KDF labels by role

   SEAL fixes each label to the value above.  The construction formulas
   reference labels by variable name, so the labels are SEAL parameters
   rather than constants of the raAE construction.  Each value is an
   ASCII string and is distinct from all others.  These are the always-
   present key-schedule labels.  The configured snapshot authenticator
   (Section 4.7.1), the plaintext-bound nonce construction (Appendix A),
   and hedged randomness (Appendix B) each define their own labels.

Sullivan                 Expires 24 January 2027               [Page 25]
Internet-Draft                    raAE                         July 2026

4.5.  Key Schedule and Nonce Generation

   A message's entire key hierarchy grows from two random values.  All
   other keys are derived deterministically through the KDF of
   Section 4.3.

4.5.1.  Payload Schedule

   Four values are derived from the CEK and per-content salt.

   payload_info = [aead_id,
                   uint32(segment_max),
                   kdf_id,
                   snap_id,
                   segment_commitment,
                   nonce_mode,
                   uint8(epoch_length),
                   salt]

   commitment  = KDF(protocol_id, commit_label,
                     [CEK], [...payload_info, G], commitment_length)
   payload_key = KDF(protocol_id, payload_key_label,
                     [CEK], payload_info, Nk)
   snap_key     = KDF(protocol_id, snap_key_label,
                     [CEK], payload_info, Nh)

   ;; For derived nonce mode only:
   nonce_base  = KDF(protocol_id, nonce_base_label,
                     [CEK], payload_info, Nn)

   G is the global associated data of Section 4.2.4, always the last
   element of the commitment info.  It defaults to the empty octet
   string, one zero-length element, so every commitment derivation
   includes it.  The other three derivations never take G.

4.5.2.  Epoch Key Derivation

   An AEAD with a 96-bit nonce (Nn = 12) has, at a 2^(-32) collision-
   probability target, a random-nonce budget of about 2^32 encryptions
   per key.  For rewritable content, this limit can be reached through
   repeated modifications to the same segments.  Epoch keys partition
   the nonce space: each epoch key covers at most 2^r segment positions
   (initial writes plus rewrites), so the per-key invocation count is
   bounded regardless of the content's total size.

   When epoch_length = r is specified, the segment key for segment i is
   an epoch key derived from the payload key:

Sullivan                 Expires 24 January 2027               [Page 26]
Internet-Draft                    raAE                         July 2026

   segment_key(i):
     epoch_index = i >> epoch_length
     return KDF(protocol_id, epoch_key_label,
                [payload_key],
                [uint64(epoch_index)], Nk)

   At epoch_length = 0 the shift is the identity, so each segment has
   its own epoch key.  At a large epoch_length every segment shares one
   epoch key.  Implementations MUST apply this derivation at every
   epoch_length, including 0, and MUST NOT use payload_key directly as a
   segment key.  Epoch keys implement the parallel external rekeying
   pattern of [RFC8645], adapted for random-access patterns.

4.5.3.  Nonce Generation

   Two nonce modes, random and derived, trade off AEAD flexibility,
   storage cost, and trust in a cryptographically secure pseudorandom
   number generator (CSPRNG).  Derived mode needs misuse-resistant
   authenticated encryption (MRAE) unless the profile's writer
   discipline keeps every derived nonce unique.  The chosen mode is part
   of the parameter set and MUST be consistent across all segments of a
   message.

   Random:            Derived:
                      nonce_base
   Random(Nn)           |
       |              XOR ((i<<1)|is_final)
       v                |
    nonce(i)           nonce(i)

                       Figure 3: The Two Nonce Modes

   The two modes differ as follows:

Sullivan                 Expires 24 January 2027               [Page 27]
Internet-Draft                    raAE                         July 2026

    +===============+===================+=============================+
    | Property      | Random nonce mode | Derived nonce mode          |
    +===============+===================+=============================+
    | Per-segment   | yes, in segment   | no                          |
    | nonce stored  | metadata          |                             |
    +---------------+-------------------+-----------------------------+
    | CSPRNG        | yes               | no                          |
    | required      |                   |                             |
    +---------------+-------------------+-----------------------------+
    | AEAD          | any AEAD          | MRAE, or any under a nonce- |
    | requirement   |                   | uniqueness discipline       |
    +---------------+-------------------+-----------------------------+
    | Rewrite       | fresh nonce each  | nonce fixed by index,       |
    |               | write             | reused on rewrite           |
    +---------------+-------------------+-----------------------------+
    | Per-segment   | binds index and   | empty when no A_i (index/   |
    | AAD           | finality          | finality in nonce)          |
    +---------------+-------------------+-----------------------------+
    | Minimum nonce | no added          | at least 8 octets           |
    | size Nn       | constraint        |                             |
    +---------------+-------------------+-----------------------------+

                  Table 5: Random and derived nonce modes

4.5.3.1.  Random Nonce Mode

   In random nonce mode (nonce_mode = "random"), each segment gets an
   independent random nonce:

   nonce(i) = Random(Nn)

   Each segment's nonce is stored in per-segment metadata and MUST be
   accessible to any reader that decrypts individual segments.  This
   mode requires a functioning CSPRNG.  The nonce collision probability
   across independently generated per-segment nonces follows the
   standard birthday bound.  See Section 5.8.

   Two optional encryptor-side hedges harden this mode against different
   threats.  Hedged randomness (Appendix B) mixes in a long-term key and
   defends against a weak or predictable CSPRNG.  It does not defend
   against CSPRNG state duplication, since identical CSPRNG output still
   yields identical hedged output.  Only the plaintext-bound
   construction (Appendix A), which mixes in plaintext content, defends
   against state duplication.  Both are implementation-local, leave the
   wire format unchanged, and are not separate nonce modes.

Sullivan                 Expires 24 January 2027               [Page 28]
Internet-Draft                    raAE                         July 2026

4.5.3.2.  Derived Nonce Mode

   Derived nonce mode is intended for profiles that do not store a per-
   segment nonce.  Nonces are derived deterministically from the payload
   schedule.  Derived nonce mode is defined only for AEADs whose nonce
   size Nn is at least 8 octets.  The segment index occupies the high
   bits of an 8-octet counter and the finality bit occupies the low bit,
   so the per-segment AAD need not carry either one.  The XOR is applied
   to the last 8 octets of nonce_base, with the remaining octets
   unchanged:

   nonce(i) = nonce_base[0:Nn-8]
              || (nonce_base[Nn-8:Nn]
                  XOR uint64((i << 1) | is_final))

   The encoded value (i << 1) | is_final MUST fit in the low 8 octets of
   nonce_base, so the segment index i MUST be less than 2^63.  This caps
   an object at 2^63 segments, far beyond any reachable object.  See
   Section 5.8.3 for the resulting size limit.

   A derived nonce is fixed by the segment's index and finality bit, so
   re-encrypting a segment at the same index and finality repeats its
   nonce.  The repetition is harmless when the plaintext and the
   associated data are unchanged, because AEAD.Encrypt is a function of
   its inputs: the second invocation reproduces the first one's
   ciphertext and tells an adversary nothing it did not already hold.
   With changed inputs it is not harmless.  An MRAE AEAD tolerates it,
   degrading to equality leakage rather than plaintext recovery, within
   the per-segment rewrite limit given in Section 5.8.  A non-MRAE AEAD
   does not: it leaks plaintext.  So with a non-MRAE AEAD, derived nonce
   mode MUST be confined to a profile whose discipline never re-encrypts
   a segment with a different plaintext or associated data.

   Two such disciplines matter here.  A write-once profile rewrites
   nothing and performs no length change, so no segment is re-encrypted
   at all.  An append-only profile re-encrypts one segment per append,
   the re-mark that supersedes the old terminal segment, and that re-
   mark carries the segment's existing plaintext and changes only the
   finality bit, which changes the nonce (Section 4.9.3.1).

   Under either discipline the encryptor MUST draw a fresh salt for
   every object, so the nonce base differs, and MUST NOT reuse any (i,
   is_final) pair under that salt, including after a crash
   (Section 6.2).

Sullivan                 Expires 24 January 2027               [Page 29]
Internet-Draft                    raAE                         July 2026

   Because the nonce binds index and finality, an immutable, write-once
   profile in derived nonce mode coincides with STREAM (Section 1.1) at
   the nonce-and-AEAD layer: a key-derived counter-plus-final-bit nonce
   over a per-segment AEAD with no associated data.

4.6.  Commitment

   The commitment is a commitment_length-octet value the payload
   schedule derives from the CEK, payload_info, and the global
   associated data G (Section 4.5).

   A reader MUST verify the commitment before decrypting any segment,
   deriving the expected value from the CEK, payload_info, and G and
   comparing it octet-for-octet with the stored value, and MUST treat a
   mismatch as an authentication failure for the object.  A mismatch
   indicates a wrong key, parameter set, or G, or a corrupted header.
   This is the ra-CMT context commitment (Section 5.1.2).  The reduction
   outline and bound are in Section 5.6.

   Because the commitment is fixed at creation, G is immutable: changing
   it invalidates the stored commitment, while segment contents stay
   rewritable through the snapshot authenticator (Section 4.7).

   G defaults to the empty octet string, so an application that supplies
   no context commits over an empty final element.  A wrong G fails the
   commitment check (Section 4.9.1.2) the same way a wrong CEK does
   (Section 6.3).

4.7.  Snapshot Authenticator

   The snapshot authenticator binds the current segment set into the
   public snapshot value.  A SEAL profile selects one with snap_id.

4.7.1.  Interface and Requirements

   A snapshot authenticator defines a per-segment input, one value per
   segment.  It produces and checks a snapshot value over the (index,
   input) set and the count with two operations:

   snapshot():  Produce the snapshot value over the current (index,
      input) set and the count n_seg.

   verify(snapshot):  Recompute the snapshot value over the current
      (index, input) set and the count, and accept only if it equals the
      stored snapshot under a constant-time comparison.

Sullivan                 Expires 24 January 2027               [Page 30]
Internet-Draft                    raAE                         July 2026

   The per-segment input is the segment's metadata leaf, binding the
   segment's index and presented nonce.  A CEK holder can reproduce that
   binding for altered content.  Setting the segment commitment binds
   the segment's ciphertext into the leaf, so changing the ciphertext
   changes the snapshot value.  The commitment is therefore needed where
   the object is shared among CEK holders, and MAY be omitted where the
   CEK has a single holder.

   The segment commitment is necessary for that binding but not
   sufficient.  An ordering is linear when a holder of the snapshot key
   can solve for a different segment set giving the same snapshot value,
   and strict when finding one is a collision problem.  Under a linear
   ordering a snap_key holder can find such a set even when every leaf
   commits to its content, so content binding against a CEK holder
   requires the segment commitment, a strict ordering, and a snapshot
   authenticated outside the construction (Section 5.3).

   Every authenticator supports the whole-object target: verify the full
   (index, input) set and the count.  An authenticator MAY additionally
   support a subset target: verify that a designated subset of (index,
   input) pairs is included at their positions in the recorded set,
   without the rest.  The snapshot value stays a single target-
   independent value of length Na, with no per-segment proof stored.

   To change a stored object, an authenticator updates its snapshot
   value.  It MAY provide add(i, input), remove(i, input), and
   set_length(n) to update the value in place from the changed segment
   alone, or it MAY recompute the value over the changed (index, input)
   set.

   A snapshot update is not atomic against a second concurrent update,
   so a consuming protocol MUST serialize concurrent updates to one
   object.  This document requires that a serialization exist and does
   not say how to obtain it, which remains a storage-transaction concern
   of the consuming protocol.  Serialization is needed whether the
   authenticator recomputes the value or updates it in place, and only
   the failure differs.  An authenticator that recomputes over the full
   set binds whatever set it read, which is neither the state before the
   interleaved update nor the state after.  One that updates in place
   loses an update, when two read-modify-write cycles on the stored
   value interleave and the later write never observed the earlier
   delta.  This is the concurrent case, distinct from the crash case of
   Section 6.8, where one update is interrupted rather than two
   interleaved.

   The scheme's RewriteSeg and SnapVerify (Section 3.3) are realized
   from these operations.  SnapVerify(S, segments, snapshot) checks a
   stored snapshot:

Sullivan                 Expires 24 January 2027               [Page 31]
Internet-Draft                    raAE                         July 2026

   1.  Let n_seg be the number of present segments.

   2.  Verify that the present segments occupy exactly the indices
       0..n_seg-1, each once.

   3.  Call verify(snapshot) over the present (index, input) set and the
       count n_seg.

   Finality is not checked in SnapVerify: is_final is authenticated by
   the segment AEAD at decryption, and Section 4.9.1.2 rejects a present
   set whose highest-indexed segment does not carry is_final = 1.

   A duplicate or missing index is caught only by step 2, because an
   authenticator's verify MAY accept a malformed index multiset.  An
   implementation MUST NOT skip the index-set check.

   A conforming authenticator's snapshot() MUST bind both the (index,
   input) set and the count n_seg, so a verifier detects any added,
   dropped, reordered, re-marked, or otherwise altered segment, and the
   snapshot value MUST be unforgeable by a party without the
   authenticator's key, under that authenticator's security assumption.

   The snapshot value is a fixed-length value of Na octets, with Na = 0
   meaning no value.

   A segment's finality is a function of its index and the count:

   is_final(i) = 1 if i = n_seg - 1, else 0

   It is carried by that segment's input.  Because finality follows the
   count, changing n_seg re-marks the boundary segment on its own, so
   rewrite, extend, and truncate are one update over the segments whose
   input changes:

   1.  Under the current count, remove each changed segment's current
       input (remove(i, input)).  The current n_seg fixes which segment
       is terminal, so each removal carries that segment's current
       finality.

   2.  Set the length to the new count (set_length(n)).

   3.  Under the new count, re-encrypt each surviving changed segment
       under its new finality and add its new input (add(i, input)).
       New segments are added here.  Discarded segments are not added
       back.

   4.  Call snapshot(), which recomputes the snapshot value over the new
       count and segment set.

Sullivan                 Expires 24 January 2027               [Page 32]
Internet-Draft                    raAE                         July 2026

   Each operation is an instance of that shape over different segments:

   +===========+===========+=============+==============+==============+
   | Operation | Count     | Inputs      | Inputs       | Terminal re- |
   |           |           | removed     | added        | mark         |
   +===========+===========+=============+==============+==============+
   | Rewrite   | unchanged | the changed | the changed  | none         |
   |           |           | segment     | segment      |              |
   +-----------+-----------+-------------+--------------+--------------+
   | Extend by | n_seg to  | old         | old          | old final, 1 |
   | k         | n_seg+k   | terminal    | terminal     | to 0 (none   |
   |           |           |             | and k new    | if empty)    |
   +-----------+-----------+-------------+--------------+--------------+
   | Truncate  | n_seg to  | the tail    | new          | new final, 0 |
   | to m      | m         | and old     | terminal     | to 1 (none   |
   |           |           | terminal    |              | if m=0)      |
   +-----------+-----------+-------------+--------------+--------------+

                   Table 6: Rewrite, extend, and truncate

   This sequence uses remove, the mutable-authenticator path.  One that
   omits remove instead resets and re-adds the surviving segments to
   rebuild the value.

4.7.2.  None

   This selection configures no snapshot authenticator: no snapshot
   value is produced (Na = 0), snapshot() and verify() are no-ops, and a
   mutable object rests on per-segment authentication alone.  Such a
   profile MUST NOT produce the empty object (n_seg = 0).  With no
   snapshot value to bind the zero count, a truncation that removed
   every segment would be indistinguishable from a legitimate empty
   object, so a valid object always has at least one segment
   (Section 6.6).

4.8.  Segment Algorithms

   The construction defines the per-segment subroutines EncryptSegment,
   DecryptSegment, and RewriteSegment.  In this random-access
   construction, is_final is an explicit input to each subroutine.
   Full-message encryption derives it from the total segment count
   n_seg, while random-access decryption and rewrite callers supply it
   directly.  The full-message procedures (Section 4.9.1.1,
   Section 4.9.1.2, Section 4.9.3) and the rewrite procedure
   (Section 4.9.2.1) compose them.

Sullivan                 Expires 24 January 2027               [Page 33]
Internet-Draft                    raAE                         July 2026

   Each subroutine is the cryptographic core of one operation of the
   base or extended raAE interface (Section 3.2, Section 3.3), refining
   Table 1 to the signature level.  The primitive's position becomes the
   explicit arguments i and is_final, and its state is the payload
   schedule, which the segment_key(i), nonce(i), and segment_aad calls
   below read from context rather than take as an argument.  A segment's
   plaintext is P_i, and its stored record is stored_i =
   (nonce_metadata_i, ct_i, tag_i).  leaf(i) is the segment's leaf
   (Section 4.7.1), and new_leaf(i) the leaf of a rewritten segment.

      +================+================+==========================+
      | Subroutine     | Realizes       | Composed by              |
      +================+================+==========================+
      | EncryptSegment | the encryption | Section 4.9.1.1 and      |
      |                | core of EncSeg | Section 4.9.3, which add |
      |                |                | the snapshot bookkeeping |
      +----------------+----------------+--------------------------+
      | DecryptSegment | DecSeg         | Section 4.9.1.2          |
      +----------------+----------------+--------------------------+
      | RewriteSegment | the encryption | Section 4.9.2.1 and      |
      |                | core of        | Section 4.9.3, which add |
      |                | RewriteSeg     | the snapshot bookkeeping |
      +----------------+----------------+--------------------------+

        Table 7: Segment subroutines and the primitive operations
                               they realize

   These subroutines emit ct_i and tag_i as separate fields, with ct_i
   of length len(P_i), at most segment_max.  DecryptSegment splits
   stored_i using the ciphertext length the consuming format conveys
   (Section 4.4.2).

   In every subroutine, i is the segment index (a non-negative integer),
   is_final is 1 for the last segment and 0 for all others, A_i is the
   caller-supplied associated data for segment i, and P_i is the segment
   plaintext.  The subroutines call segment_key(i) and nonce(i) as
   defined in Section 4.5, with nonce(i) following the chosen
   nonce_mode, and segment_aad(i, is_final, A_i) as defined in
   Section 4.4.2.

   nonce_metadata_i denotes the stored nonce metadata for segment i:
   nonce(i) when nonce_mode is "random", and empty when it is "derived".
   In random mode DecryptSegment reads its nonce from nonce_metadata_i,
   and in derived mode it recomputes nonce(i).

4.8.1.  EncryptSegment

Sullivan                 Expires 24 January 2027               [Page 34]
Internet-Draft                    raAE                         July 2026

   EncryptSegment(i, is_final, A_i, P_i):
     key   = segment_key(i)
     nonce = nonce(i)
     aad   = segment_aad(i, is_final, A_i)
     C_i   = AEAD.Encrypt(key, nonce, aad, P_i)
     split C_i into ct_i and tag_i
     return (nonce_metadata_i, ct_i, tag_i)

   AEAD.Encrypt and AEAD.Decrypt are the interfaces of [RFC5116]
   Sections 2.1 and 2.2.  For an AEAD whose ciphertext places the tag in
   its final Nt octets, ct_i is the first len(P_i) octets and C_i =
   ct_i || tag_i.

   The caller supplies the segment's leaf to the snapshot authenticator
   (Section 4.7.1).  EncryptSegment itself does no snapshot work.

4.8.2.  DecryptSegment

   DecryptSegment returns the segment plaintext, or a decryption error:

   DecryptSegment(i, is_final, A_i, stored_i):
     nonce_metadata_i, ct_i, tag_i = stored_i
     key   = segment_key(i)
     nonce = nonce_metadata_i or nonce(i)
     aad   = segment_aad(i, is_final, A_i)
     C_i   = ct_i || tag_i
     P_i   = AEAD.Decrypt(key, nonce, aad, C_i)
             (on verification failure, return a decryption error)
     return P_i

4.8.3.  RewriteSegment

   RewriteSegment assumes the caller has already verified the commitment
   or otherwise confirmed it holds the correct CEK.  A rewrite under the
   wrong key produces unreadable ciphertext and corrupts the snapshot
   authenticator's state.  The error is detectable only on a subsequent
   read.

   RewriteSegment(i, is_final, A_i, new_P_i) is defined as
   EncryptSegment(i, is_final, A_i, new_P_i): a rewrite is a fresh
   encryption of the new plaintext new_P_i.  The output record
   new_stored_i replaces the stored record for segment i.

   RewriteSegment produces the replacement record new_stored_i only.
   The caller updates the snapshot authenticator with the old and new
   leaves, calling remove(i, leaf(i)) then add(i, new_leaf(i))
   (Section 4.9.2.1).

Sullivan                 Expires 24 January 2027               [Page 35]
Internet-Draft                    raAE                         July 2026

4.9.  Top-level Algorithms

   The top-level algorithms compose the segment subroutines
   (Section 4.8) over complete messages.  They call the snapshot-
   authenticator operations of Section 4.7 (snapshot() and verify() in
   every profile, and add(i, input), remove(i, input), and set_length(n)
   in a mutable or append-only profile) without referring to how any is
   computed.  The profile's selected authenticator realizes those
   operations (Section 4.7.1).

   These procedures do not expose per-segment associated data, so they
   pass an empty A_i to each subroutine.  An application that needs per-
   segment A_i calls the subroutines directly.

4.9.1.  Read-Only Operations

   Encryption and decryption are available in every SEAL profile.  They
   write a message once and read individual segments.  Neither rewrites
   a stored segment.  When the profile configures no snapshot
   authenticator, the snapshot steps below are omitted, and a reader
   relies on per-segment authentication alone.

4.9.1.1.  Encryption

   Encryption runs in two phases.  The first derives the per-message
   schedule and writes the commitment.  The second encrypts each segment
   independently, feeds its input to the snapshot authenticator, and
   then calls snapshot() to bind the whole (index, input) set and the
   count.  Because the segments are independent, the second phase may
   encrypt them in any order or in parallel.  The snapshot calls mutate
   one value under a single writer, so encryption is never the
   concurrent case that Section 4.7.1 requires a protocol to order.

      CEK, salt
          |
          v
     payload schedule
          |
     +----+----------+----------+
     v               v          v
   commitment   payload_key   snap_key
                     |
                     v
      EncryptSegment(i, P_i)   using payload_key   (one per segment)
                     |
                     v
                ct_i, tag_i

Sullivan                 Expires 24 January 2027               [Page 36]
Internet-Draft                    raAE                         July 2026

               Figure 4: Key Schedule and Segment Encryption

   An application that writes a new message MUST generate a fresh,
   uniformly random salt.  Given a CEK, that salt, a parameter set, G,
   and a plaintext P split into segments P_0 through P_{n_seg-1}:

   derive  commitment, payload_key, snap_key from the payload schedule
           (and nonce_base, in derived mode)
   store   commitment

   for i in 0 .. n_seg-1:
       is_final = 1 if i = n_seg-1, else 0
       stored_i = EncryptSegment(i, is_final, empty, P_i)
       store stored_i

   if snapshot authentication is enabled:
       snapshot = snapshot()
       store snapshot

   A zero-length plaintext produces a single segment of length 0 with
   is_final = 1.

4.9.1.2.  Decryption of Segment i

   Opening a segment is a local operation: check the commitment to
   reject a wrong key early, then AEAD-decrypt the one segment.  This
   yields per-segment authenticity over the ciphertext core, the segment
   index, and the finality bit.  Under a snapshot authenticator, whole-
   set authenticity is a separate and stronger check that requires the
   full present segment set.  It detects any altered segment set,
   including same-index rollback to an older sibling (Section 4.7.1).  A
   reader holding only one segment gets per-segment authenticity but
   MUST NOT claim snapshot integrity until it runs SnapVerify
   (Section 4.7).  A profile with no snapshot authenticator defines no
   snapshot, so per-segment authenticity is the whole integrity
   guarantee.

   Given the CEK, salt, parameter set, G, segment index i, finality
   status, and the stored ciphertext segment for index i:

  derive  commitment from CEK, salt, and G
  derive  payload_key, snap_key from CEK and salt
  if stored commitment != derived commitment:  return error
  P_i = DecryptSegment(i, is_final, empty, stored_i)
         (return its error on failure)
  if snapshot authentication is enabled and the full set is available:
      if SnapVerify(snapshot) fails:  return error  (do not deliver P_i)
  return P_i

Sullivan                 Expires 24 January 2027               [Page 37]
Internet-Draft                    raAE                         July 2026

   Here SnapVerify is the three-argument SnapVerify(S, segments,
   snapshot) of Section 3.3, with S the derived schedule and segments
   the present set, each carrying the authenticator's per-segment input
   (Section 4.7.1).

   Whole-object SnapVerify needs the leaf of every segment
   (Section 4.7.1), so a reader that streams segments in order cannot
   gate their release on whole-object snapshot integrity without first
   buffering those leaves or using a layout that carries them in a
   header.  Where the authenticator supports a subset target, a reader
   can instead verify a subset it holds against the snapshot without the
   leaves of the other segments.  Delivering on per-segment authenticity
   alone forgoes snapshot freshness for that segment (Section 6.6).  A
   streaming reader likewise cannot rule out truncation before the end
   of the stream: plaintext delivered before the highest-indexed segment
   verifies under is_final = 1, and before SnapVerify passes where a
   snapshot authenticator is configured, MUST be treated as unverified
   with respect to completeness.

   A decryptor MUST reject a truncated object: one whose highest-indexed
   present segment carries is_final = 0 is incomplete, and the decryptor
   MUST fail rather than return the partial plaintext.

   The check works because the application supplies the segment count
   n_seg, from which the decryptor derives the finality each segment
   must carry (Section 4.8).  It then verifies the final segment under
   is_final = 1.  A truncated object, whose last surviving segment was
   written as non-final, fails that verification.  The finality bit is
   bound per segment and unforgeable without the CEK, through the nonce
   or the segment AAD per the nonce mode (Section 4.4.2).

   Under a write-once profile no segment ever carried an earlier
   terminal form, so an adversary cannot present a valid is_final = 1
   segment at a truncated boundary: it cannot re-mark a non-final
   segment, and this check detects every dropped trailing segment.  A
   profile that changes length re-marks a terminal segment
   (Section 4.9.3), so one segment may have carried is_final = 1 under
   an earlier nonce.  An adversary can replay that retained terminal
   ciphertext at the shorter count, which this check alone accepts.
   SnapVerify over the complete segment set then rejects the replay.
   The mutable profile requires a snapshot authenticator, so SnapVerify
   always runs there (Section 6.6).

   Authorized truncation by the CEK holder re-encrypts the new final
   segment under is_final = 1 with a fresh nonce (Section 4.9.3), so a
   legitimately truncated object still ends with is_final = 1 and
   verifies.  This check needs no snapshot authenticator.

Sullivan                 Expires 24 January 2027               [Page 38]
Internet-Draft                    raAE                         July 2026

   Truncation to an empty object is covered too.  Without a snapshot
   authenticator a valid object has at least one segment, so a decryptor
   MUST reject one with none.  With a snapshot authenticator the
   snapshot binds the count, making the empty object (n_seg = 0) a
   distinct authenticated state (Section 6.6).

   On a commitment mismatch the implementation MUST NOT proceed with
   decryption, SHOULD zeroize derived key material, and MUST return an
   error.  The SnapVerify gate in the procedure above runs whenever a
   snapshot authenticator is configured and the full present set is
   available, for example a full read or an integrity audit.

   Decryption can fail in up to three distinguishable ways:

       +===========================+===============================+
       | Failure                   | Cause                         |
       +===========================+===============================+
       | Commitment mismatch       | wrong key or parameters       |
       +---------------------------+-------------------------------+
       | AEAD verification failure | corrupted or tampered segment |
       +---------------------------+-------------------------------+
       | Snapshot mismatch         | segment set or count modified |
       |                           | (snapshot authenticator only) |
       +---------------------------+-------------------------------+

                   Table 8: Decryption failure conditions

   Implementations SHOULD report these as distinct error conditions for
   local diagnosis, but SHOULD return a single opaque error to untrusted
   callers to avoid leaking an oracle (for example, distinguishing
   "wrong key" from "tampered segment" over a network).

4.9.2.  Rewritable Operations

   Rewriting is available only in a mutable profile, which requires a
   snapshot authenticator.  Length change is a separate operation
   (Section 4.9.3), available in both directions in a mutable profile
   and in the append direction alone in an append-only profile
   (Section 4.9.3.1).  The procedure below is written against the in-
   place update path (add, remove, set_length; Section 4.7.1).  Under an
   authenticator that recomputes instead, the remove, add, and
   set_length calls in this procedure collapse into a single snapshot()
   over the updated (index, input) set, and the operations are otherwise
   identical.  A caller that cannot recover a re-encrypted segment's
   plaintext cannot perform it.

Sullivan                 Expires 24 January 2027               [Page 39]
Internet-Draft                    raAE                         July 2026

4.9.2.1.  Rewriting Segment i

   A rewrite touches exactly one segment's ciphertext, and no other
   segment is read or decrypted (Section 4.7).  In-place update trusts,
   rather than re-verifies, the stored snapshot state, whereas an
   authenticator that recomputes rebuilds the value from the stored per-
   segment leaves and trusts none.

   The procedure is:

   read leaf(i)
   new_stored_i = RewriteSegment(i, is_final, empty, new_P_i)
   remove(i, leaf(i))
   add(i, new_leaf(i))
   snapshot = snapshot()
   store new_stored_i, snapshot

   In derived nonce mode the nonce for segment i is deterministic, so a
   rewrite reuses the same nonce under a key whose derivation context is
   identical.  This is safe because a mutable profile that selects
   derived nonce mode requires an MRAE AEAD, which tolerates the reuse
   (Section 4.5.3.2) within the per-segment rewrite limit
   (Section 5.8.4).

   The stored snapshot cannot be validated during an in-place rewrite:
   SnapVerify recomputes the authenticator from every segment's tag and
   so requires reading all tags (Section 4.7).  Because the rewrite
   trusts the stored snapshot state, the writer MUST take it from
   locally trusted storage or run SnapVerify first.  Otherwise a storage
   adversary can roll the stored snapshot back and have the writer
   rebuild on it, laundering the rollback into a snapshot that verifies
   going forward (Section 6.6).  Full validation is a separate operation
   performed with access to all tags, for example on a full read or an
   integrity audit.

4.9.3.  Changing Message Length

   An application that holds the CEK MAY change a stored message's
   length in either direction: appending new segments, or truncating to
   a prefix.  The two directions share one shape.  Exactly one retained
   segment, the old or the new terminal one, is re-encrypted to move the
   finality bit, with none re-encrypted when appending from the empty
   object or truncating to it.  Every other changed segment is removed
   or added by tag without re-encryption, and the snapshot is updated
   over the new count (Table 6).  Both reuse the existing salt: an
   application extending an existing message MUST reuse the salt from
   the object it extends.  A fresh salt would change every payload
   schedule output and force re-encryption of the retained segments.

Sullivan                 Expires 24 January 2027               [Page 40]
Internet-Draft                    raAE                         July 2026

   def Append(P_new):
     k = len(P_new)
     t = n_seg - 1

     if n_seg > 0:
       P_t = DecryptSegment(t, 1, empty, stored_t)
       new_stored_t = RewriteSegment(t, 0, empty, P_t)
       remove(t, leaf(t))

     set_length(n_seg + k)

     if n_seg > 0:
       store new_stored_t
       add(t, new_leaf(t))

     for j in n_seg .. n_seg+k-1:
       is_final = 1 if j == n_seg+k-1 else 0
       stored_j = EncryptSegment(j, is_final, empty, P_new[j-n_seg])
       store stored_j
       add(j, leaf(j))

     store snapshot()

                              Figure 5: Append

   def Truncate(m):
     t = m - 1

     if m > 0:
       P_t = DecryptSegment(t, 0, empty, stored_t)
       new_stored_t = RewriteSegment(t, 1, empty, P_t)
       remove(t, leaf(t))

     for j in m .. n_seg-1:
       remove(j, leaf(j))

     set_length(m)

     if m > 0:
       store new_stored_t
       add(t, new_leaf(t))

     discard segments m .. n_seg-1
     store snapshot()

                             Figure 6: Truncate

Sullivan                 Expires 24 January 2027               [Page 41]
Internet-Draft                    raAE                         July 2026

   With in-place update each add and remove takes the segment's stored
   tag, which already encodes that segment's is_final bit, so an
   implementation never tracks finality separately.

   A botched in-place update corrupts the snapshot authenticator's state
   silently, surfacing only at a later SnapVerify.  An implementation
   MAY run SnapVerify over the new segment set immediately after a
   length change to catch this.  A botched update yields a value that
   the from-scratch recomputation will not match, turning a silent
   corruption into a caught error.  An authenticator that recomputes
   rebuilds the snapshot from the stored per-segment leaves on every
   update, so it has no analogous silent-corruption failure mode.

   Both operations count against the same per-CEK AEAD usage budget as
   initial encryption (Section 5.8).  Each re-encrypts one terminal
   segment, except a truncate to the empty object (m = 0), which re-
   encrypts none.  In derived nonce mode the nonce for the re-marked
   segment is fixed by its index and finality bit.  Re-marking flips the
   finality bit, so this nonce differs from the segment's previous one,
   but repeated length changes in both directions can make the same
   (index, finality bit) pair recur, and only an MRAE AEAD tolerates the
   resulting nonce reuse (Section 4.5).  An append-only profile admits
   no truncation, so no pair recurs and any AEAD is safe
   (Section 4.9.3.1).

   Applications that do not need length changes MAY forbid them.  The
   salt-reuse requirement applies only when a length change is
   performed.  An application that re-encrypts the entire content can
   generate a fresh salt and is not bound by the constraints in this
   section.

4.9.3.1.  Appending Under an Append-Only Profile

   An append-only profile admits the append direction of this section
   (Figure 5) and forbids truncation.

   An encryptor under an append-only profile MUST NOT rewrite a segment
   with a different plaintext or associated data, and MUST NOT reduce
   n_seg.

   The first rule is what lets the profile pair a derived nonce with any
   AEAD, including a non-MRAE one.  At a fixed index and finality the
   key and the nonce are already fixed by the payload schedule, so the
   plaintext and the associated data are the only inputs that can
   differ, and the rule forbids exactly those.  No nonce ever carries
   two different plaintexts, which is the condition Section 4.5.3.2 sets
   for a non-MRAE AEAD.

Sullivan                 Expires 24 January 2027               [Page 42]
Internet-Draft                    raAE                         July 2026

   The re-mark satisfies the first rule without an exception: it changes
   only the finality bit, not the plaintext or associated data
   (Section 4.5.3.2).

   The second rule makes the profile append-only rather than non-
   rewriting.  It forbids the truncate direction, so a stored object
   only grows, and an index the object has spent is never freed for a
   later append to fill with different content.

   An append re-encrypts one retained segment, so each segment is
   encrypted at most twice, and an epoch key covers at most
   2^(epoch_length + 1) segment encryptions (Section 5.8.3).

   Because the re-mark preserves the segment's length, an append to an
   object whose terminal segment is short leaves a short interior
   segment, which a layout with uniformly sized interior segments cannot
   represent.  A consuming protocol using this profile supplies a
   serialization that conveys each segment's ciphertext length
   (Section 4.4.2).

5.  Security Analysis

   The formal proofs are not reproduced here.  The ra-ROR and ra-CMT
   notions are taken unchanged from [FLRR25], which proved them for a
   construction that instantiates the same component contracts other
   than the snapshot authenticator (Section 5.4).  SEAL's analysis of
   those notions follows the same structure.  Snapshot integrity is the
   one notion this document defines.  The configured authenticator's
   definition argues its snapshot-integrity bound (Section 5.7), and
   integrating that argument into a combined proof is deferred to the
   companion proof [SEALPROOFS] (in preparation).  The limits of
   Section 5.8 are operational deployment bounds, not proof obligations.

5.1.  Security Notions

   raAE has two security tiers.  The base tier comprises the notions
   inherited from [FLRR25]: ra-ROR, ra-CMT, and its position-choosing
   variant ra-CMT-p, summarized here.  The extension tier adds one
   notion, snapshot integrity, defined by this document.  A construction
   MAY provide the base tier only.  Advantage definitions and proofs for
   ra-ROR, ra-CMT, and ra-CMT-p are in [FLRR25].

Sullivan                 Expires 24 January 2027               [Page 43]
Internet-Draft                    raAE                         July 2026

5.1.1.  ra-ROR

   ra-ROR (random-access real-or-random) is the joint confidentiality
   and authenticity notion for raAE in a multi-user, nonce-respecting
   setting.  An adversary with adaptive encryption and decryption access
   across many key instances, sessions, and arbitrary positions cannot
   distinguish real ciphertexts and headers from random, and cannot make
   an out-of-context ciphertext segment decrypt.  The game is defined in
   [FLRR25].

   The encryption core of the extension operations is ordinary EncSeg.
   A RewriteSeg produces its replacement ciphertext as a repeated EncSeg
   at the same position, and appending is EncSeg at fresh positions plus
   one RewriteSeg of the old final segment.

   In random nonce mode these draw fresh nonces and stay within the
   nonce-respecting ra-ROR game.  In derived nonce mode the analysis
   turns on whether the profile permits a rewrite in place.

   Where it does, a rewrite repeats the position's derived nonce with
   new content.  That is a deliberate nonce-repeating query, and the
   underlying MRAE AEAD handles it under the equality-leakage relaxation
   documented for derived nonce mode (Appendix C.5), not the unmodified
   nonce-respecting game.

   Where it does not, no query repeats a position with new content.  The
   write-once profile re-encrypts nothing beyond an identical replay of
   an interrupted write.  The append-only profile re-encrypts only at
   the append's RewriteSeg, which flips the finality bit and so writes a
   position the initial write did not use, and at an identical replay.
   Both profiles bind every position to one set of inputs
   (Section 4.9.3.1), so their repeated queries carry the inputs of the
   query they repeat.  A reduction answers such a query from the first
   one's output, and both profiles stay in the nonce-respecting game and
   need no MRAE AEAD (Section 4.5.3.2).

   These operations also maintain a snapshot value.  That value is
   outside the [FLRR25] syntax.  It is governed not by ra-ROR but by the
   snapshot integrity notion of Section 5.1.4.

5.1.2.  ra-CMT

   ra-CMT (random-access context commitment) is the segment-level
   commitment notion: no single ciphertext segment decrypts successfully
   under two different decryption contexts (key, nonce, global
   associated data, and per-segment associated data).  In this position-
   respecting notion the two contexts share a position.  Because the
   scheme is random access, committing one segment's context commits the

Sullivan                 Expires 24 January 2027               [Page 44]
Internet-Draft                    raAE                         July 2026

   full ciphertext's context.  ra-CMT is defined in [FLRR25].

   ra-CMT is distinct from the per-AEAD notions CMT-1 and CMT-4 of
   [RFC9771]: a scheme can achieve ra-CMT through an external commitment
   mechanism even when its underlying AEAD commits to nothing.  The
   Invisible Salamanders attacks ([DGRW18]) show what a non-committing
   AEAD permits, and [ADG22] frames it as a key-commitment failure with
   fixes.

5.1.3.  ra-CMT-p

   ra-CMT-p is the position-choosing variant of ra-CMT: the two
   decryption contexts need not share a position, so the adversary binds
   a segment's content to a position of its choice.

   Under honest keys a construction inherits ra-CMT-p from the
   underlying AEAD's commitment.  Against a holder of the CEK it does
   not follow from per-segment AEAD alone: a snapshot authenticator
   restores it by committing each segment's content and ordering
   segments strictly, with the snapshot value authenticated outside the
   construction (Section 5.3, Appendix C.4).

5.1.4.  Snapshot Authentication

   Per-segment AEAD authenticates a segment at its position, but it does
   not authenticate the current object snapshot: which set of segments
   belongs to the current stored object state.  An adversary with write
   access to stored segments can silently substitute an old valid same-
   index segment or delete a segment, and per-segment AEAD verification
   at each presented segment still passes.  (A segment moved to a
   different index fails its AEAD check through the index binding of
   Section 4.4.2.)

   Snapshot authentication covers that set.  The resulting notion is
   snapshot integrity.  Its interface and requirements are in
   Section 4.7.1, and its general bound is in Section 5.7.  A combined
   formal treatment with the ra-ROR framework is in preparation
   ([SEALPROOFS]).

   A construction MAY omit snapshot integrity, providing only the per-
   segment guarantees and ra-CMT.  SEAL provides it under a snapshot
   authenticator and omits it otherwise.

5.2.  Relations to Other Notions

   AEAD ([RFC5116]):  raAE generalizes AEAD to multi-segment content
      with arbitrary-order encryption.  A single-segment raAE is an
      AEAD.

Sullivan                 Expires 24 January 2027               [Page 45]
Internet-Draft                    raAE                         July 2026

   nOAE2 ([Tink]):  nOAE2 is the nonce-based online authenticated
      encryption notion for schemes that encrypt in order and support
      random-access decryption.  Hoang and Shen introduced nOAE2 in
      their analysis of Tink Streaming AEAD ([Tink]), where they also
      show STREAM satisfies it.  ra-ROR is strictly stronger: every ra-
      ROR-secure scheme is nOAE2-secure when used in order, but
      nOAE2-secure schemes can fail when encryption order is arbitrary
      ([FLRR25]).

   Commitment ([RFC9771]):  CMT-1 and CMT-4 ([RFC9771]) are per-AEAD
      commitment notions. ra-CMT is the corresponding notion for
      segmented random-access schemes.  See Section 5.1.2.

   Rewrite safety and extension safety are corollaries of the notions
   above, not additional notions.  Replacing a segment in place is an
   EncSeg at an already-used position together with a snapshot update.
   In random nonce mode it adds no adversary capability beyond ra-ROR
   (Section 5.1.1) and snapshot integrity (Section 5.1.4).  In derived
   nonce mode the rewrite repeats the segment nonce, so it MUST use an
   MRAE AEAD (Section 4.5.3.2), and it adds the equality-leakage
   relaxation that derived nonce mode already documents (Appendix C.5).
   Each rewrite also counts against the per-key AEAD usage budget
   (Section 5.8).

   Appending and truncating likewise add no algorithm (Section 4.9.3)
   and no notion.  An adversary's ability to add, drop, reorder, or re-
   mark a terminal segment is exactly the snapshot integrity adversary
   of Section 5.1.4, and detection follows from the index and finality
   binding of Section 4.4.2 together with snapshot verification.
   Rollback of the whole object to an earlier honest (state, snapshot)
   after truncation is the freshness case that snapshot integrity
   excludes (Section 6.6).  The application supplies it.

5.3.  Adversary Model and Assumptions

   The adversary model is that of the ra-ROR game (Section 5.1.1,
   [FLRR25]).  In the construction's terms: the adversary can observe
   all ciphertexts and content metadata, tamper with individual segments
   or their ordering, replace the snapshot value, and attempt decryption
   with chosen keys.  The adversary does not know the CEK, any derived
   key, or the per-content salt.  The confidentiality and integrity
   bounds assume the CEK is secret and uniform, the single-owner regime:
   an application MUST supply a CEK that is either generated uniformly
   at random or derived so that it is computationally indistinguishable
   from uniform, such as the output of a KDF keyed by a secret.  When
   multiple messages share a CEK, the per-content salt separates payload
   schedule outputs across messages under the PRF assumption.  The
   multi-message advantage grows linearly in the number of messages.

Sullivan                 Expires 24 January 2027               [Page 46]
Internet-Draft                    raAE                         July 2026

   The commitment notions ra-CMT and ra-CMT-p (Section 5.6) also cover a
   shared-CEK regime, where the adversary holds the CEK.  A CEK holder
   defeats the per-segment AEAD: it holds the key, so it can decrypt and
   forge tags at will, and confidentiality and per-segment integrity do
   not bind it.

   One binding can still hold against a CEK holder, under three
   conditions that each close a distinct gap.  The snapshot value MUST
   be authenticated outside the construction, because a CEK holder
   derives snap_key and can otherwise forge any snapshot value directly.
   The segment commitment MUST be set: without it a segment's leaf binds
   its ciphertext only through the AEAD tag, which a CEK holder forges
   for altered content.  Setting it adds a collision-resistant
   commitment to the ciphertext that holding the CEK does not defeat.
   The authenticator's ordering MUST be strict: under a linear ordering
   a snap_key holder can present a different segment set with the same
   snapshot value even when every leaf commits to its content, and only
   a strict ordering makes finding one a collision problem.  A snapshot
   meeting all three binds each segment's content to its position
   against a CEK holder.

   The persistent state of an raAE object, and the party that owns each
   item, is:

   CEK:  Secret key-management state.  It is the root secret for the
      object.

   salt:  Stored object metadata.  It separates objects under one CEK.

   parameter set:  Profile or object metadata.  It fixes suite, maximum
      segment size, and epoch policy.

   commitment:  Stored object metadata.  It rejects wrong key or
      parameter context before decryption.

   segment metadata:  Storage-format state.  It holds AEAD tags, the
      per-segment nonces in random nonce mode, and, when the segment
      commitment is set, each segment's content commitment
      (Section 4.7.1).

   snapshot:  Stored object metadata.  It authenticates the segment set
      and segment count.

   external freshness state:  Consuming-protocol state.  It detects
      whole-object rollback.

Sullivan                 Expires 24 January 2027               [Page 47]
Internet-Draft                    raAE                         July 2026

   The security argument relies on three distinct assumptions about the
   KDF.  For derivations whose input keying material is secret and
   uniformly random, including payload_key, snap_key, nonce_base,
   epoch_key, and the snapshot authenticator's keyed derivations, the
   KDF is assumed to be a multi-user PRF with domain separation by
   protocol_id and label.

   For commitment, the function

   Commit(CEK, payload_info, G, L) =
       KDF(protocol_id, "commit", [CEK], [...payload_info, G], L)

   is additionally assumed to be collision resistant over adversarially
   chosen tuples (CEK, payload_info, G), with G empty by default.  PRF
   security alone is not sufficient for this property, because the
   commitment adversary may choose the CEK and context values.

   For the plaintext-bound nonce construction, the plaintext digest step
   targets collision resistance, not PRF security.

5.4.  raAE Construction Requirements

   The bounds below rely on properties of the construction's components,
   namely the KDF framing and the snapshot authenticator.  The
   requirements those components must satisfy are obligations on the
   raAE construction, not part of the raAE primitive of Section 3.

   A profile selects the concrete framing for every derivation surface:
   the KDF input assembly (Section 4.5), the payload_info construction
   (Section 4.2), the segment AAD (Section 4.4.2), and the snapshot
   authenticator's keyed inputs (Section 4.7).  The requirements below
   are the contract that any such framing MUST meet.  SEAL is one such
   framing (Section 4.3, Section 4.4).

   Pseudorandomness:  KDF outputs MUST be computationally
      indistinguishable from random to an adversary that does not know
      the ikm, assuming the underlying hash or PRF is a secure
      pseudorandom function.

   Injectivity:  A construction encodes the tuple (protocol_id, label,
      ikm, info, L) into the underlying primitive input, and that
      encoding MUST be injective: distinct tuples map to distinct
      primitive inputs.  This is a requirement on the encoding, not on
      the KDF, which need not itself be injective.  ikm and info MUST be
      unambiguously separable in the encoded input, whatever the number
      of elements each contains.  The two-step form binds ikm and info
      in its separate Extract and Expand inputs.  The one-step form
      frames ikm and info each as a single encode element.  Where the

Sullivan                 Expires 24 January 2027               [Page 48]
Internet-Draft                    raAE                         July 2026

      encoding admits inputs too large to encode literally, it MAY
      substitute a fixed-length digest of the over-large field.  The
      encoding is then injective only up to the collision resistance of
      that digest, which the construction MUST justify and domain-
      separate from the literal encoding (Section 4.3).

   Label uniqueness:  Each derivation role, including commitment,
      payload key, snapshot authenticator key, nonce base, epoch key,
      segment nonce, hedged key, and the authenticator's internal roles,
      MUST use a distinct label string within each protocol version.

   Protocol binding:  The protocol_id MUST appear as a distinct
      component of the KDF primitive input.  Different application
      protocols using the same AEAD and KDF MUST use different
      protocol_id values to ensure that derived values from one protocol
      cannot be confused with those from another.

   Output length commitment:  The requested output length L MUST be part
      of the KDF primitive input.  This prevents attacks in which an
      adversary attempts to use a truncated version of a longer derived
      output as a valid shorter one.

   Cross-role isolation:  Cross-role isolation follows from label
      uniqueness and PRF security of the underlying primitive: a KDF
      output for one derivation role, such as payload_key, is
      computationally independent of the output for any other role, such
      as snap_key, even when derived from the same CEK and payload_info.

   Snapshot authenticator:  The construction MUST bind the current
      segment set and the segment count into a public snapshot value
      that an adversary without the authenticator's secret key cannot
      forge for a modified segment set or count, even after observing
      snapshot values and their deltas across rewrites.  How the value
      is computed, and whether a single-segment change updates it in
      place or rebuilds it, is the authenticator's choice.  SEAL's
      snapshot authenticators are in Section 4.7.

Sullivan                 Expires 24 January 2027               [Page 49]
Internet-Draft                    raAE                         July 2026

   SEAL's construction (Section 4) satisfies these requirements.  Its
   KDF (Section 4.3), keyed by the CEK, is modeled as a pseudorandom
   function.  Its encode framing (Section 4.3) is injective and places
   protocol_id and the output length L in the primitive input, so
   injectivity, protocol binding, and output-length commitment hold.
   SEAL's labels (Table 4, each configured snapshot authenticator's own
   labels, the plaintext-bound construction's labels in Appendix A, and
   the hedged-randomness label in Appendix B) are distinct, giving label
   uniqueness and, with PRF security, cross-role isolation.  Each
   configured snapshot authenticator satisfies the snapshot
   authenticator requirement, with its forgery argument accounted in
   Section 5.7.

   SEAL's encode framing meets the injectivity requirement.  Its frame/
   encode construction, the LH digest for over-large fields, and LH's
   domain separation from the literal encoding are defined and justified
   in Section 4.3.  SEAL's own derived and fixed fields (the
   payload_info elements, the commitment, the leaf, and the uint-encoded
   scalars) are all at most 0xFFFE octets, so for them frame is byte-
   identical to a plain 2-octet length prefix.  The two caller-supplied
   octet strings, G (Section 4.2.4) and A_i, are unbounded, and a field
   longer than 0xFFFE octets is bound as 0xFFFF || LH of it.  Cross-
   protocol separation comes from protocol_id in the KDF inputs and from
   aad_label in the segment AAD, not from LH (Section 4.3).

   SEAL's additional components, the epoch keys and the snapshot
   maintained across rewrite and length change, are analyzed in
   Section 5.5 and Section 5.7.

5.5.  Segment Confidentiality and Integrity

   The construction targets ra-ROR security (Section 5.1.1).  The ra-ROR
   advantage bound, its adversary parameters, and the per-term analysis
   are in Appendix C, with the full proof in preparation ([SEALPROOFS]).

   Ciphertext cores are indistinguishable from random under the ra-ROR
   definition, up to the public length leakage, the equality leakage
   allowed by derived nonce mode, and public metadata exposed by the
   consuming format (file-level headers, stored nonces in random mode,
   the salt, and the commitment).  Each segment AEAD ciphertext binds
   the segment to its own index and finality bit (through segment_aad in
   random nonce mode and through the nonce in derived nonce mode) so an
   adversary cannot modify or substitute a segment under a given index,
   or flip its finality bit, without causing an AEAD verification
   failure on that segment.  Same-index rollback to an older valid
   segment within the same message is not detected by per-segment AEAD
   alone.  This requires the snapshot verification of Section 4.7.

Sullivan                 Expires 24 January 2027               [Page 50]
Internet-Draft                    raAE                         July 2026

   Three quadratic floors bound the multi-message advantage:

   salt collision       q_m^2 / 2^256          all suites
   epoch-key collision  n_ep^2 / 2^128         128-bit-key suite
   nonce collision      q^2 / 2^(8*Nn + 1)     random nonce mode
                        q^2 / 2^97  at Nn = 12

   In derived nonce mode the salt-collision floor is the only one for
   the 256-bit-key suites.  The 128-bit-key suite also has the epoch-key
   collision floor, which dominates (Appendix C.2).  In random nonce
   mode, with or without the plaintext-bound hedge, the nonce-collision
   floor applies.  Here q is the number of segment encryptions under one
   key, and Nn is the nonce length in octets.  The block-size birthday
   term is derived in Section 5.8.

   Segment size enters the analysis only through the forgery and block-
   size terms, both bounded in Section 5.8.  It does not affect the
   confidentiality or commitment terms.  A segment's length is
   authenticated implicitly by its AEAD tag, not through segment_aad or
   the nonce, so the analysis assumes the consuming format conveys each
   segment's true ciphertext length.  Segments shorter than segment_max
   consume no more than their share of the per-key budget and need no
   separate accounting.

5.6.  Commitment Security

   raAE's commitment target is ra-CMT (Section 5.1.2), not the per-AEAD
   CMT-1 ([RFC9771]): the commitment binds the CEK and payload_info,
   which together carry the full parameter context affecting key
   derivation, AEAD operation, and AAD and nonce construction.

   ra-CMT relies on the collision resistance of the commitment
   derivation map over the tuple (protocol_id, "commit", CEK,
   payload_info, G, commitment_length), with G empty by default.  PRF
   security alone does not suffice, because the commitment adversary may
   choose the CEK and the context values (Section 4.5).  SEAL sets
   commitment_length = Nh, so the commitment offers about 2^128
   collision-search work at Nh = 32 and about 2^256 at Nh = 64.  The
   reduction outline for this assumption and the collision quantities
   for a general commitment_length are in Appendix C.4.

Sullivan                 Expires 24 January 2027               [Page 51]
Internet-Draft                    raAE                         July 2026

   The commitment bounds the ra-CMT variant in which the positions match
   (Section 5.1.2).  It does not bind the segment position.  Position
   binding for the ra-CMT-p variant is inherited from the underlying
   AEAD's commitment level.  Because the SEAL AEADs are not relied upon
   to provide it, position confusion under an adversarially chosen key
   is out of scope, consistent with [FLRR25].  A malicious encryptor
   that controls the CEK can craft a single ciphertext segment that
   opens at two positions, and the per-segment AEAD tag does not prevent
   it.

   A snapshot authenticator that sets the segment commitment over a
   strict ordering, with the snapshot authenticated outside the
   construction, restores ra-CMT-p against adversarially chosen keys:
   the collision-resistant leaf commitment and the strict ordering
   together pin each segment's ciphertext to its index even against a
   CEK holder (Section 4.7.1, Section 5.3).  It applies only where a
   profile selects that authenticator and a consuming protocol
   authenticates the one snapshot value.  The base construction pins
   position no more strongly than the AEAD commits under an adversarial
   key.

   The per-segment associated data A_i is likewise outside the
   commitment: SEAL binds A_i through segment_aad and the AEAD tag for
   that segment.  Contexts that differ only in A_i are therefore not
   commitment collisions.  Their separation relies on AEAD commitment
   for the segment AAD.  A_i is also rewritable across rewrites and is
   not bound at the snapshot level.  An application that needs it bound
   there MUST bind it externally.  The exact accounting of this term in
   the ra-CMT reduction is deferred to Appendix C.

   A deployment that must defend against a malicious encryptor who
   controls the CEK can close the adversarial-key position gap by one of
   two changes.  These are non-normative.  SEAL adds none of them to the
   base construction.

   *  A context-committing AEAD, so that each segment ciphertext commits
      to its full decryption context rather than relying on the external
      commitment over (CEK, payload_info, G).

   *  A per-segment collision-resistant commitment over the segment's
      position and ciphertext, on the order of 16 to 64 octets per
      segment, bound alongside the segment so that no segment opens at
      two positions.

Sullivan                 Expires 24 January 2027               [Page 52]
Internet-Draft                    raAE                         July 2026

   Both changes act in the base construction.  A snapshot authenticator
   with the segment commitment set over a strict ordering
   (Section 4.7.1) is a separate, conditional route: it leaves the base
   construction unchanged and closes the gap only where a profile
   selects it and a consuming protocol authenticates the one snapshot
   value.

   None of the SEAL AEADs is relied upon to provide CMT-1 or CMT-4
   ([RFC9771]).  In particular AES-256-GCM-SIV is not key-committing,
   with known attacks such as partitioning oracles.  raAE obtains ra-CMT
   context commitment from the external commitment over (CEK,
   payload_info, G) regardless of the AEAD, provided the commitment
   check is not bypassed and payload_info carries the full parameter
   context (Section 5.1.2).

   With commitment_length = Nh and Nt = 16, ra-CMT is bounded by the
   commitment collision resistance, and ra-CMT-p adds the per-segment
   AEAD commitment term.  The ra-CMT collision bound is derived in
   Appendix C.4, and the ra-CMT-p bound is stated there as a sum.  The
   two key regimes differ.  Under honestly generated keys the idealized
   per-pair tag-forgery floor is 2^(-128) because Nt = 16, and concrete
   per-AEAD authenticity bounds degrade with segment length
   (Section 5.8).  Under an adversarially chosen CEK the position term
   is the AEAD's commitment level, which the SEAL AEADs are not relied
   upon to provide.

   The global associated data G (Section 4.6) enters the committed map
   as an additional input, empty by default, and the collision-
   resistance argument above applies unchanged with G in the committed
   context.  This matches the ra-CMT treatment of global associated data
   in [FLRR25].

5.7.  Snapshot Authenticator Security

   The snapshot authenticator adds two operations (RewriteSeg,
   SnapVerify) over a snapshot value and one new security property,
   snapshot integrity (Section 5.1.4).  Integrating its reduction into a
   single combined proof with the ra-ROR framework is in preparation and
   will be published separately ([SEALPROOFS]).

   The keyed snapshot is not read as sender attribution.

Sullivan                 Expires 24 January 2027               [Page 53]
Internet-Draft                    raAE                         July 2026

   +=========================+================+=========+==============+
   | Guarantee               | Established    | Scope   | Provided by  |
   |                         | by             |         |              |
   +=========================+================+=========+==============+
   | Segment confidentiality | AEAD           | segment | this         |
   | and integrity, index    | decrypt,       |         | construction |
   | and finality bound      | per segment    |         |              |
   +-------------------------+----------------+---------+--------------+
   | Segment-set integrity:  | SnapVerify     | whole   | this         |
   | content, position,      | over the       | object  | construction |
   | count                   | snapshot       |         |              |
   |                         | value          |         |              |
   +-------------------------+----------------+---------+--------------+
   | Sender attribution,     | signature      | whole   | consuming    |
   | third-party             | over the       | object  | protocol,    |
   | verifiability           | snapshot       |         | not provided |
   |                         | context        |         |              |
   +-------------------------+----------------+---------+--------------+
   | Freshness, whole-object | external       | whole   | consuming    |
   | rollback protection     | version or     | object  | protocol,    |
   |                         | freshness      |         | not provided |
   |                         | state          |         |              |
   +-------------------------+----------------+---------+--------------+

                    Table 9: What each layer guarantees

   Snapshot integrity is keyed by snap_key and protects the writer's
   current segment set against a storage or write adversary that does
   not hold snap_key.  A verifier who holds snap_key, hence the CEK from
   which it is derived, detects any alteration of the segment set
   (Section 4.7.1).  Forgery of a fresh snapshot value gives no
   protection among parties that share the CEK, because any CEK-holder
   can recompute snap_key, and the value is not a third-party-verifiable
   commitment to a segment set.  Whether a fixed, externally
   authenticated snapshot value binds segment content against key
   holders depends on the authenticator (Section 4.7.1).  An application
   that needs sender attribution or third-party verifiability MUST add a
   signing layer over the snapshot context, and the configured
   authenticator determines whether its value can carry that layer.

   The snapshot authenticator adds authentication of the full segment
   set (over the authenticator's per-segment input) and the count n_seg
   as a single unit, which detects same-index rollback, segment-set
   modification, and count changes.  Its mandatory index-set check
   catches a duplicated or dropped index that an authenticator's verify
   might otherwise accept (Section 4.7.1).

Sullivan                 Expires 24 January 2027               [Page 54]
Internet-Draft                    raAE                         July 2026

   A profile MUST keep each of an authenticator's KDF labels inside the
   injective encode frame (Section 4.3) so distinct roles cannot collide
   on the primitive input.

   Whole-object rollback to a previously valid snapshot is out of scope
   and is treated in Section 6.6.  snap_key is not exposed through any
   public API.  It is derived internally per message from the CEK and
   salt, so snap_key exposure is not a threat surface in the
   construction itself.

5.8.  Capacity and Usage Limits

   These usage limits are organized around independent limit classes,
   not around named suites.  The accounting unit is one segment
   encryption under one segment-encryption key (an epoch key).  For
   random-nonce AEADs that budget is a single per-epoch-key pool.  For a
   derived-nonce MRAE AEAD there are two separate budgets: a per-epoch-
   key budget for distinct derived nonces, and a per-derived-nonce
   budget for repeated encryption of one segment.  Such an AEAD
   therefore does not follow a simple "divide the per-key budget by
   2^epoch_length" model.

   The budgets depend on the AEAD's nonce, key, tag, and cipher block
   sizes (Nn, Nk, Nt, Nb), on the AEAD's own published confidentiality
   and integrity analysis, on the KDF's output size Nh and its mu-PRF
   security (Appendix C.2), and on the suite's segment_max.  A suite
   that fixes those works out every figure below.  The mu-PRF security
   is what makes each epoch key's budget independent of every other's,
   which the per-epoch-key accounting assumes.

   The length-dependent limits in this section are computed at the
   suite's segment_max, the largest plaintext one segment encryption
   carries.  Independent of these per-key budgets, a segment-encryption
   procedure MUST respect each underlying AEAD's per-invocation input
   limits.

5.8.1.  Accounting Model

   One segment encryption consumes one write from a segment-encryption
   key's budget.  Initial writes and rewrites are both segment
   encryptions.  The budget belongs to the epoch key, not the CEK.

   epoch-key budget:  the segment encryptions allowed under one epoch
      key.

   write (initial write):  the first encryption of a segment.

   rewrite:  a later encryption of the same segment.

Sullivan                 Expires 24 January 2027               [Page 55]
Internet-Draft                    raAE                         July 2026

   epoch_length (r):  the base-2 log of the number of segments that
      share one epoch key.

   n_blk:  the blocks per segment, n_blk = segment_max / Nb, for a
      block-cipher AEAD.

   advantage target:  the bound a budget is solved against.  Every
      confidentiality budget in this section is computed at 2^-32.  A
      budget quoted from an AEAD's own analysis holds at the target that
      analysis states.

5.8.2.  Limit Classes

   Six phenomena bound how much may be encrypted.  Each is set by one
   property of the AEAD or the segment size, and each bounds
   confidentiality or integrity.

   +================+===============+===============+=================+
   | Limit class    | Applies to    | Depends on    | Failure mode    |
   +================+===============+===============+=================+
   | Random-nonce   | random nonce  | nonce size    | confidentiality |
   | collision      | modes         |               |                 |
   +----------------+---------------+---------------+-----------------+
   | Forgery bound  | all AEADs     | MAC strength, | integrity       |
   |                |               | segment size  |                 |
   +----------------+---------------+---------------+-----------------+
   | Block-size     | block-cipher  | total blocks  | confidentiality |
   | birthday       | AEADs         |               |                 |
   +----------------+---------------+---------------+-----------------+
   | MRAE distinct- | derived-nonce | derived-nonce | confidentiality |
   | nonce          | MRAE across   | count         | and integrity   |
   |                | segments      |               |                 |
   +----------------+---------------+---------------+-----------------+
   | Fixed-nonce    | derived-nonce | segment size, | confidentiality |
   | data volume    | hot rewrites  | rewrites      |                 |
   +----------------+---------------+---------------+-----------------+
   | Epoch-key      | 128-bit-key   | key size      | confidentiality |
   | collision      | AEADs         |               |                 |
   +----------------+---------------+---------------+-----------------+

                      Table 10: Usage-limit classes

5.8.3.  Maximum Object Size

   Two limits bound a write-once object: each epoch key's AEAD write
   budget, and the 2^63 segment index ceiling.  The same two bound an
   append-only object, at the write counts given at the end of this
   section.

Sullivan                 Expires 24 January 2027               [Page 56]
Internet-Draft                    raAE                         July 2026

   Under a flat key (one epoch key for the whole object), the AEAD
   budget sets the size.  Which class binds follows from the AEAD:

    +=====================+===========================================+
    | Binding class       | Flat-key write-once limit                 |
    +=====================+===========================================+
    | Block-size birthday | 2^((8*Nb + 1 - 32)/2) / n_blk segments    |
    +---------------------+-------------------------------------------+
    | MRAE distinct-nonce | the AEAD's distinct-derived-nonce ceiling |
    +---------------------+-------------------------------------------+
    | No block-cipher     | 2^63 segments, the index ceiling          |
    | structure           |                                           |
    +---------------------+-------------------------------------------+
    | No published block- | 2^63 segments, the index ceiling          |
    | size analysis       |                                           |
    +---------------------+-------------------------------------------+

         Table 11: Flat-key write-once size limit by binding class

   A block-cipher AEAD binds on the block-size birthday, a
   confidentiality bound of about 2^36 segments at Nb = 16 and n_blk =
   4096 (Section 5.8.6.2).  A derived-nonce MRAE AEAD binds instead on
   the distinct-derived-nonce ceiling its own analysis gives
   (Section 5.8.6.4).

   The last two classes carry the same limit for different reasons.  An
   AEAD with no block-cipher structure, such as one built on a stream
   cipher, has no block-size term at all: that is a property of the
   AEAD.  An AEAD whose analysis publishes no such term may still have
   one: that is a statement about the literature, not about the
   algorithm, and a suite that places an AEAD in this class says which
   of the two reasons applies.

   These figures assume derived nonce mode, which a non-MRAE AEAD may
   use only under a nonce-uniqueness discipline, the write-once or
   append-only profiles (Section 4.5.3.2).  In random nonce mode such an
   AEAD binds earlier, at the random-nonce-collision budget of 2^((8*Nn
   + 1 - 32)/2), about 2^32 per epoch key at Nn = 12 (Section 5.8.6.1).

Sullivan                 Expires 24 January 2027               [Page 57]
Internet-Draft                    raAE                         July 2026

   An append-only object re-encrypts one retained segment per append
   (Section 4.9.3.1), so a segment appended one at a time is written
   twice rather than once, and an identical replay after a crash adds a
   further write without reusing the pair (Section 4.5.3.2).  Every
   figure above that binds on a write count therefore halves, before any
   replays: the block-size birthday figure, which counts blocks, and the
   distinct-derived-nonce figure, which counts distinct nonces.  The
   2^63 entry is the index ceiling and is unchanged.  An epoch key
   correspondingly spans at most 2^(epoch_length + 1) pairs, and the
   budget it needs is that many writes plus any replays
   (Section 4.9.3.1).

   With epoch rotation each epoch key carries a fresh budget, so any
   suite can reach the 2^63-segment ceiling, about 2^79 octets at
   segment_max 65536.  An AEAD subject to the epoch-key collision class
   reaches it only with a sufficiently large epoch_length.  At
   epoch_length 0 that floor caps the object near 2^(4*Nk - 16)
   segments, about 2^48 at Nk = 16 (Section 5.8.5).  Reaching 2^63 then
   needs epoch_length at least 15, so the distinct epoch keys stay near
   2^48.

   A rotating profile MUST keep each epoch key's 2^epoch_length initial
   writes within its per-key budget.  For a derived-nonce MRAE AEAD that
   means 2^epoch_length below the AEAD's distinct-derived-nonce budget.
   An append-only profile adds one re-mark per superseded segment, so
   each epoch key spans up to 2^(epoch_length + 1) pairs, and an
   encryptor MUST size the per-key budget to cover those plus the
   replays an interrupted append costs (Section 4.9.3.1).  Rewrite
   capacity is a separate condition (Section 5.8.4).

5.8.4.  Rewrite Capacity

   A rewrite consumes the same budget as an initial write.  How that
   budget is shared depends on the nonce mode.

   For a random-nonce AEAD, epoch_length divides one per-epoch-key pool
   among the 2^epoch_length segments that share the key.  If rewrites
   are spread evenly, the count each segment can take falls as
   epoch_length rises:

   rewrites per segment  =  2^((8*Nn + 1 - 32)/2) / 2^epoch_length

   At Nn = 12 that is about 2^(32 - epoch_length): about 2^32 rewrites
   per segment at epoch_length 0, about 2^26 at 6, and about 2^22 at 10.

   For a derived-nonce MRAE AEAD the hot-segment rewrite cap is not
   divided by 2^epoch_length, because a rewrite reuses the segment's one
   derived nonce.  The cap is length-dependent instead.  Where the

Sullivan                 Expires 24 January 2027               [Page 58]
Internet-Draft                    raAE                         July 2026

   AEAD's per-record encryption is a block cipher in counter mode, the
   cap is the keystream block-size birthday over the rewritten blocks,
   quantified in Section 5.8.6.4, and applies at every epoch_length.  An
   MRAE AEAD built another way has whatever cap its own analysis gives.
   The distinct-derived-nonce budget is separate and per epoch key.  A
   derived-nonce MRAE AEAD thus has two separate constraints, the
   distinct derived nonces per epoch key and the repeated encryptions at
   one derived nonce.  An AEAD whose nonce size makes a flat key safe
   uses one, and a forgery budget that exceeds any reachable rewrite
   workload leaves no rewrite constraint at all.

   Applications MUST track segment encryptions per key and freeze the
   object before a budget is exceeded.  The CEK is fixed per object and
   cannot be rotated in place, so continued writing requires a new
   object under a fresh CEK.

5.8.5.  Choosing epoch_length

   epoch_length means different things by mode.  For the random-nonce
   AEADs, a smaller epoch_length puts fewer segments under each key, so
   each segment keeps a larger share of the random-nonce collision pool,
   at the cost of more epoch keys to derive and hold.  For a derived-
   nonce MRAE AEAD, a smaller epoch_length reduces the distinct derived
   nonces under an epoch key but does not raise the hot-segment rewrite
   cap, which is per derived nonce and length-dependent.  An AEAD with a
   256-bit nonce (Nn = 32) makes collision negligible and has a high
   forgery floor, so a flat key (epoch_length 63) is the natural choice.

   The cipher suite's default epoch_length, used when no epoch_length is
   chosen, is 0 for the suites with an epoch_length range and 63 for the
   suites whose nonce size makes a flat key safe.  A referencing
   protocol may choose directly, or by citing a profile or named
   instantiation that fixes a value.  Either way a value is chosen, and
   the default does not apply.

   A referencing protocol that chooses an epoch_length tuned to its
   expected segment count, rather than taking the default, trades some
   rotation for fewer epoch keys while staying within budget.  Because a
   segment may be shorter than segment_max, size epoch_length by the
   number of segments rather than the object's octet length.  At a fixed
   octet size, smaller segments mean more segments and more epoch keys.

   The epoch keys are independent under the PRF security of the KDF
   ([RFC8645]), so the epoch_length parameter controls budget
   distribution, not key strength.

Sullivan                 Expires 24 January 2027               [Page 59]
Internet-Draft                    raAE                         July 2026

   An AEAD with a 128-bit key (Nk = 16) adds one further constraint.
   The epoch-key collision term (Appendix C.2) is about n_ep^2/2^(8*Nk)
   over the n_ep distinct epoch keys, so a profile whose AEAD has Nk =
   16 SHOULD keep distinct epoch keys per payload_key below about
   2^(4*Nk - 16), which is about 2^48 at Nk = 16 and holds that term
   within the 2^-32 target.  At epoch_length 0 this caps such an object
   at about 2^48 segments, far below the 2^63 index ceiling, so it
   constrains only extreme object sizes.

5.8.6.  Derivations

5.8.6.1.  Confidentiality (Nonce Collision)

   For random nonce mode with Nn-octet nonces and q segment encryptions
   under one key, the collision probability follows the birthday bound:

   P(collision) <= q^2 / 2^(8*Nn + 1)

   When epoch_length = r is specified, q counts encryptions per epoch
   key (initial writes plus rewrites within that epoch), not across the
   whole content.  Each epoch key has an independent budget.

   For derived nonce mode, nonces are deterministic and distinct across
   segment indices, so this collision term does not apply.  The limits
   on reusing a derived nonce are in Section 5.8.6.4.

5.8.6.2.  Confidentiality (Block-Size Birthday Bound)

   Nonce collisions alone do not exhaust the confidentiality bound.
   Following the AEAD usage-limits analysis ([I-D.irtf-cfrg-aead-limits]
   Section 5), a block-cipher AEAD has a distinguishing bound that grows
   with the total number of cipher blocks processed under a key.  If s
   is the total number of AAD-plus-plaintext blocks, each Nb octets, and
   q is the number of encryption queries under a key, the
   confidentiality advantage is at most:

   CA <= ((s + q + 1)^2) / 2^(8*Nb + 1)

   A segment holds n_blk blocks and s = n_blk * q in the worst case, so
   CA scales as q^2 * n_blk^2 / 2^(8*Nb + 1).  Solved against the 2^-32
   target, the per-key budget is:

   q  <=  2^((8*Nb + 1 - 32)/2) / n_blk

   about 2^36 at Nb = 16 and n_blk = 4096.  In random nonce mode the
   nonce-collision bound q^2 / 2^(8*Nn + 1) dominates for typical
   deployments because n_blk^2 / 2^(8*(Nb - Nn)) is small: the block-
   size term overtakes it only once n_blk^2 exceeds 2^(8*(Nb - Nn)),

Sullivan                 Expires 24 January 2027               [Page 60]
Internet-Draft                    raAE                         July 2026

   which is 2^32 at Nb = 16 and Nn = 12.  In derived nonce mode the
   nonce-collision term vanishes and the block-size term is the binding
   confidentiality constraint.

   An AEAD with no block-cipher structure, such as one built on a stream
   cipher, has no comparable block-size bound, leaving nonce collision
   and forgery as the only relevant terms.  Nonce collision is
   negligible at a large Nn, and the per-query forgery bound governs
   integrity.  Section 5.8.6.4 gives the derived-nonce block-size
   limits.

   SEAL implementations MUST compute usage budgets from the AEAD-
   specific confidentiality and integrity bounds, not from nonce-
   collision probability alone.

5.8.6.3.  Integrity (Forgery)

   Each AEAD decryption query gives the adversary a chance to forge a
   valid ciphertext.  The forgery advantage per query depends on the
   AEAD's own analysis and on segment_max:

   IA <= v * F(segment_max)

   where v is the number of forgery attempts and F(segment_max) is the
   per-query forgery advantage the AEAD's analysis gives at a segment of
   segment_max octets.  F grows with segment_max, so a larger segment
   lowers the attempt budget for a fixed target.  The tag length bounds
   F from below, at about 2^(-8*Nt), so no AEAD offers more than about
   8*Nt bits of forgery resistance per query.  An AEAD's authenticator
   may achieve less than its tag length suggests, so F is not determined
   by Nt and a suite takes F from the analysis of its own AEAD.
   [I-D.irtf-cfrg-aead-limits] gives F for several AEADs.

5.8.6.4.  Derived-Nonce Bounds

   A derived-nonce MRAE AEAD has two limits the random-nonce analysis
   above does not capture.  Both come from the AEAD's own analysis
   rather than from its interface.

   Across the distinct segment nonces under one epoch key, an MRAE AEAD
   that derives a per-record key from the key and the nonce has a
   derived-key collision ceiling on the number of distinct derived
   nonces.  Its value is the AEAD's analysis to state.

   For a single hot segment, every rewrite reuses that segment's one
   derived nonce, so n_rw rewrites of an n_blk-block segment encrypt
   n_rw * n_blk blocks under one derived per-record key.  Where that
   per-record encryption is a block cipher in counter mode, the binding

Sullivan                 Expires 24 January 2027               [Page 61]
Internet-Draft                    raAE                         July 2026

   term is the keystream block-size birthday over the total blocks, in
   the form of [I-D.irtf-cfrg-aead-limits] Section 5 with s = n_rw *
   n_blk blocks and q = n_rw queries:

   ((s + q + 1)^2) / 2^(8*Nb + 1)  <=  2^-32

   The n_rw * n_blk term dominates, so this holds while n_rw * n_blk
   stays below about 2^((8*Nb + 1 - 32)/2), giving:

   n_rw  <=  2^((8*Nb + 1 - 32)/2) / n_blk

   the same expression as the flat-key block-size budget, counting
   rewrites of one segment at one nonce instead of writes under one key.
   That is about 2^36 rewrites at Nb = 16 and n_blk = 4096, and about
   2^38 at n_blk = 1024.

   An MRAE AEAD whose per-record encryption gives distinct plaintexts
   distinct keystreams degrades under the fixed nonce only by this
   block-birthday term and not by nonce reuse.  Two rewrites with
   identical plaintext and associated data produce identical ciphertext
   (deterministic-MRAE equality leakage), independent of this count.

6.  Security Considerations

   raAE's ra-ROR security target (Section 5.1.1) rests on three
   assumptions: the AEAD is multi-user real-or-random (mu-ROR) secure,
   the KDF is a secure multi-user pseudorandom function (mu-PRF), and
   nonces do not collide.

   Integrity is bounded by the AEAD tag: no AEAD offers more than
   approximately 8*Nt bits of forgery resistance per query.  A larger
   AEAD key raises confidentiality margins, not the tag-length forgery
   floor.

6.1.  Detection Summary

   The rows detected by SnapVerify assume a snapshot authenticator is
   configured.  Without one, those modes go undetected.

   The one exception is a dropped trailing segment under a write-once
   profile, which the per-segment finality requirement of
   Section 4.9.1.2 detects with no snapshot authenticator (the
   truncation row below).

Sullivan                 Expires 24 January 2027               [Page 62]
Internet-Draft                    raAE                         July 2026

   +==============+===================================================+
   | Failure mode | Detected by                                       |
   +==============+===================================================+
   | Wrong CEK,   | The commitment, before any segment decryption     |
   | salt, or     | (Section 4.6), when reader and writer share the   |
   | parameter    | payload_info construction.                        |
   | set          |                                                   |
   +--------------+---------------------------------------------------+
   | Modified     | AEAD.Decrypt for the affected segment.            |
   | ciphertext   |                                                   |
   | core or AEAD |                                                   |
   | tag          |                                                   |
   +--------------+---------------------------------------------------+
   | Segment      | AEAD.Decrypt: index and finality are bound by     |
   | moved to a   | segment_aad (random nonce mode) or the nonce      |
   | different    | (derived nonce mode).                             |
   | index        |                                                   |
   +--------------+---------------------------------------------------+
   | Segment      | AEAD.Decrypt, when the source used a different    |
   | copied from  | CEK or salt; a reused salt under the same CEK     |
   | another      | breaks this separation (Section 6.7).             |
   | object at    |                                                   |
   | the same     |                                                   |
   | index        |                                                   |
   +--------------+---------------------------------------------------+
   | Segment      | SnapVerify, not per-segment AEAD alone, unless    |
   | copied from  | the whole object including its snapshot is rolled |
   | another      | back to that earlier valid version.               |
   | version at   |                                                   |
   | the same     |                                                   |
   | index        |                                                   |
   +--------------+---------------------------------------------------+
   | Dropped      | Write-once: the finality requirement of           |
   | trailing     | Section 4.9.1.2 (top present segment carries      |
   | segment(s)   | is_final = 0).  Length-changing: SnapVerify,      |
   | (truncation) | since a re-marked terminal (Section 4.9.3) can be |
   |              | replayed; the mutable profile always configures   |
   |              | an authenticator.  Truncation to zero: the zero-  |
   |              | segment prohibition, or SnapVerify (Section 6.6). |
   +--------------+---------------------------------------------------+
   | Missing      | SnapVerify (segment count, finality, recomputed   |
   | interior,    | snapshot value).                                  |
   | duplicated,  |                                                   |
   | reordered,   |                                                   |
   | or inserted  |                                                   |
   | segment      |                                                   |
   +--------------+---------------------------------------------------+
   | Stale        | SnapVerify, unless the stale value is part of a   |

Sullivan                 Expires 24 January 2027               [Page 63]
Internet-Draft                    raAE                         July 2026

   | snapshot     | whole-object rollback.                            |
   | value        |                                                   |
   +--------------+---------------------------------------------------+
   | Whole-object | Not detected by raAE alone; the consuming         |
   | rollback     | protocol needs authenticated external freshness   |
   |              | state.                                            |
   +--------------+---------------------------------------------------+
   | Equality     | Not an authentication failure; rewriting equal    |
   | leakage in   | plaintext at the same index can reveal equality   |
   | derived      | (Section 4.5.3, Section 6.2).                     |
   | nonce mode   |                                                   |
   +--------------+---------------------------------------------------+

         Table 12: Failure modes and the checks that detect them

6.2.  Nonce Misuse

   Nonce reuse under a non-MRAE AEAD leaks plaintext: an adversary who
   observes two ciphertexts under the same key and nonce recovers the
   XOR of the plaintexts (for CTR-based AEADs) and can forge new
   ciphertexts.  For an AEAD whose authenticator is a polynomial
   universal hash, nonce reuse also recovers the authentication key,
   enabling forgery of arbitrary messages.

   Random nonce mode depends entirely on the CSPRNG.  If the CSPRNG
   returns duplicated state, segments collide.  Derived nonce mode
   removes that dependence, since nonces are deterministic, but the
   determinism is itself a hazard: re-encrypting a segment with
   different content under its repeated derived nonce is a two-time pad,
   catastrophic for a non-MRAE AEAD.

   A non-MRAE AEAD therefore uses derived nonces only under a discipline
   that keeps every (index, finality bit) pair unique, the write-once or
   append-only profiles, drawing a fresh salt per object and never
   reusing a pair under that salt, including after a crash
   (Section 4.5.3.2).  Write-once meets this by never re-encrypting with
   changed inputs, and by drawing a fresh salt rather than retrying an
   object it did not complete.  Append-only meets it by permitting at
   most one re-encryption per segment, the finality re-mark, under the
   three rules of Section 4.9.3.1.  An MRAE AEAD instead degrades only
   to equality leakage, not plaintext recovery.

   The plaintext-bound construction (Appendix A) partially defends
   against CSPRNG duplication: different plaintexts at the same index
   produce different nonces because the plaintext digest differs, but
   equal plaintexts still collide.  Implementations that need a full
   defense against random number generator (RNG) state duplication MUST
   use derived nonce mode with an MRAE AEAD.

Sullivan                 Expires 24 January 2027               [Page 64]
Internet-Draft                    raAE                         July 2026

6.3.  Parameter Set Mismatch

   The full parameter set that affects encryption, decryption, AAD
   construction, nonce construction, and key derivation is bound into
   payload_info (see Section 4.2) and therefore into the commitment.  A
   reader using a different parameter set than the writer triggers a
   commitment mismatch before any AEAD operation is attempted.  A reader
   supplying a different G than the encryptor likewise triggers a
   commitment mismatch (Section 4.6).  Consuming protocols MUST still
   reject unrecognized or unsupported parameter values before
   decryption, since the commitment check detects mismatch but does not
   by itself indicate which parameter value the recipient is unable to
   support.

   One profile-level constant is bound transitively rather than via
   payload_info: aad_label is bound through protocol_id (each profile
   fixes its own aad_label).  nonce_mode, by contrast, is carried in
   payload_info, so the commitment binds it directly.  Profiles MUST NOT
   share a protocol_id across distinct aad_label values.  Reusing a
   protocol_id with a changed aad_label produces objects whose
   commitment matches the wrong reader but whose per-segment AEAD
   verification fails with no clear error attribution.

6.4.  Framing and Label Errors

   Two classes of implementation error break cross-role isolation.  A
   non-injective framing function maps distinct KDF input tuples to the
   same primitive input, correlating outputs that should be independent.
   Implementations MUST verify injectivity per Section 5.4.  Reusing a
   label across roles (for example, "commit" for both commitment and
   payload key) has the same effect.  Labels MUST be distinct within a
   protocol version, and a new version that changes any derivation MUST
   change the protocol_id.

6.5.  Parameter Misuse

   The nonce mode and AEAD choice are coupled, and the table gives the
   rule for each pairing:

Sullivan                 Expires 24 January 2027               [Page 65]
Internet-Draft                    raAE                         July 2026

          +======================+==============+===============+
          | AEAD class / profile | random nonce | derived nonce |
          +======================+==============+===============+
          | non-MRAE, mutable    | valid        | unsafe        |
          +----------------------+--------------+---------------+
          | non-MRAE, write-once | valid        | valid         |
          | or append-only       |              |               |
          +----------------------+--------------+---------------+
          | MRAE, any profile    | wasteful     | valid         |
          +----------------------+--------------+---------------+

               Table 13: Nonce mode by AEAD class and profile

   Rewrite is where the coupling matters: a derived nonce is reused
   where a random nonce is redrawn, and the consequences of that reuse
   by AEAD class are in Section 6.2 and Section 4.5.3.2.

6.6.  Snapshot Integrity Limitations

   First, a reader that does not run snapshot verification (Section 4.7)
   does not verify that a segment belongs to the current authenticated
   snapshot.  Such a reader gets per-segment AEAD authenticity only,
   without the snapshot integrity guarantee of Section 5.1.4: the
   ciphertext core is authenticated under the segment index and finality
   bit, but the reader cannot detect that the segment was substituted
   from a previous valid version of the same message at the same index,
   nor that other segments were dropped or rolled back.  Such readers
   MUST still verify the commitment per Section 4.6.  Applications that
   support random-access single-segment reads MUST either run snapshot
   verification on every read or explicitly document that they accept
   per-segment authenticity without snapshot freshness.

   Conversely, snapshot verification authenticates the segment set, its
   positions, and the count.  Without the segment commitment it does not
   confirm that a tag is a valid AEAD tag for the ciphertext beside it.
   With the segment commitment set it binds the ciphertext bytes and the
   tag, but not that the tag opens the ciphertext under the AEAD
   (Section 4.7.1).  Decrypting the segment is what establishes that, so
   snapshot verification layers set, position, and count binding on top
   of per-segment AEAD without replacing it.

   Second, snapshot integrity does not provide freshness against whole-
   object rollback.  A storage adversary that rolls back the entire
   encrypted object, including the snapshot, to a previously valid
   version is not detected by raAE alone, because the rolled-back
   snapshot is itself a valid snapshot for that prior state.  This is
   replay of an intact prior snapshot, not a forgery: it stays out of
   scope unless the consuming protocol authenticates external freshness

Sullivan                 Expires 24 January 2027               [Page 66]
Internet-Draft                    raAE                         July 2026

   into the snapshot context.  Applications that require whole-object
   rollback resistance MUST bind an authenticated version field,
   timestamp, monotonic counter, or authenticated storage layer into
   that context.  Relatedly, Section 4.9.2.1 requires a writer to update
   only trusted snapshot state, so a rewrite cannot launder a rolled-
   back snapshot into a valid ongoing history.

   Third, same-index rollback within a snapshot is detected when
   snapshot verification runs.  If an adversary replaces one segment
   with a previously valid same-index segment but leaves the current
   snapshot value in place, the recomputed snapshot value no longer
   matches the stored one, so verification fails except with negligible
   forgery probability (see Section 5.7).

   Truncation, including removal of the final segment marked is_final =
   1, is detected by snapshot verification.  The removed segment is
   absent from the recomputed snapshot value and the count n_seg no
   longer matches the segments present, so verification fails.
   Truncation is a special case of the first limitation above, for
   readers that skip snapshot verification.

6.7.  Salt Reuse

   Reusing a salt with the same CEK across two files produces identical
   payload schedule outputs: the same payload_key, the same snap_key,
   and, in derived nonce mode, the same nonce_base.  The damage depends
   on the nonce mode.

   In every nonce mode, an adversary can silently swap same-index
   segments between the two files: both per-segment AEAD checks and the
   snapshot authenticator accept the swap.  Salt reuse is therefore an
   integrity break in every configuration.

   In derived nonce mode the nonces also repeat across the two files, so
   an MRAE AEAD degrades to deterministic encryption and leaks plaintext
   equality between same-index segments.  A non-MRAE AEAD then permits
   plaintext recovery.  Such an AEAD is safe under a derived nonce only
   within a single object, where the write-once or append-only
   discipline keeps each derived nonce unique (Section 4.5.3.2).
   Reusing the salt repeats nonce_base across two objects, hence every
   derived nonce, and breaks that scoping.

Sullivan                 Expires 24 January 2027               [Page 67]
Internet-Draft                    raAE                         July 2026

   In random nonce mode (and with the plaintext-bound hedge) fresh
   nonces keep confidentiality intact, although the per-key nonce-
   collision budget of Section 5.8.6.1 then counts encryptions across
   both files under the single CEK.  The integrity break above remains.
   Applications MUST therefore ensure salt uniqueness per CEK when
   creating a new message.  The freshness requirement in Section 4.9.1.1
   exists for this reason.

6.8.  Rewrite Hazards

   Applications MUST track total segment encryptions per key and freeze
   the object before exceeding the per-epoch-key budget of
   Section 5.8.4.  For a 96-bit-nonce AEAD (Nn = 12) that budget is
   roughly 2^32 encryptions per epoch key, and exceeding it risks nonce
   collisions and plaintext recovery (Section 5.8.5).

   A mutable profile with derived nonces and an MRAE AEAD reuses a
   segment's deterministic nonce across non-terminal rewrites, and a
   crash that replays a write reuses it again.  Confidentiality there
   rests on the per-segment rewrite limit (Section 5.8.4), not on nonce
   uniqueness: the AEAD degrades to equality leakage between identical
   rewrites rather than to plaintext recovery, as long as that budget is
   respected.

   The append-only profile has no such margin.  It admits a non-MRAE
   AEAD, so its safety rests on never re-encrypting a segment with
   different content (Section 4.9.3.1), and a writer that breaks that
   rule gets a two-time pad rather than a bounded leak.

   Per-segment associated data A_i is rewritable, so a reader cannot
   treat it as context fixed at creation (Section 4.4.2).  An
   application that needs creation-fixed context places it in G, which
   the commitment binds (Section 4.6), not in A_i.

   raAE also does not guarantee atomic rewrites.  A segment rewrite
   touches the nonce metadata, ciphertext core, AEAD tag, and the
   snapshot value.  A crash between any two of these leaves the content
   inconsistent.  Applications MUST use write-ahead logging, copy-on-
   write, or an equivalent mechanism to make rewrites recoverable.

6.9.  Constant-Time Implementation

   Several raAE operations handle secret data and MUST be implemented in
   constant time to prevent timing side-channels.

Sullivan                 Expires 24 January 2027               [Page 68]
Internet-Draft                    raAE                         July 2026

   The KDF calls in the payload schedule and epoch key derivation take
   the CEK or payload_key as input keying material.  Implementations
   MUST ensure that the KDF's keyed operations execute in constant time
   with respect to their key inputs.  For an HMAC-based KDF this is
   satisfied by implementations that do not branch on key octets.

   Both the commitment comparison (Section 4.9.1.2) and the snapshot
   comparison in SnapVerify MUST use a constant-time octet comparison.
   A variable-time comparison reveals the position of the first
   differing octet.  An adversary who can retry tampered inputs learns
   the expected value one octet at a time and can then present a
   matching stored value.  This reduces the forgery cost of either check
   to a linear number of trials (for the snapshot, the bound of
   Section 5.7).

   AEAD.Encrypt and AEAD.Decrypt operations inherit the constant-time
   requirements of the underlying AEAD.  Implementations SHOULD use AEAD
   libraries that document constant-time guarantees.

6.10.  Properties Not Provided

   raAE protects segment content and binds segments together.
   Everything a complete storage or messaging system needs beyond that
   is the consuming protocol's responsibility.  This section is the
   authoritative boundary of what raAE does not provide.

   Freshness and whole-object rollback:  Snapshot integrity binds the
      segment set of one recorded object state, not its recency.  A
      party holding the ciphertext can present an earlier honest state
      in full, and both per-segment and snapshot verification still
      pass.  Telling the current state from a stale one requires
      external freshness (Section 6.6).

   Forward secrecy:  The CEK must remain available as long as any reader
      needs access, so raAE provides none.

   Sender identity:  Ciphertexts are not bound to any sender.  A signing
      or MAC layer is needed for sender authentication.

   Unlinkability:  Key identifiers and structural features of the
      encrypted format are visible, so unlinkability requires
      application-layer measures.

   Whole-message replacement:  Snapshot verification covers segments
      within a message but cannot detect replacement of the message
      itself.  An adversary who swaps one encrypted message for another
      goes undetected unless the application binds message identity
      externally.

Sullivan                 Expires 24 January 2027               [Page 69]
Internet-Draft                    raAE                         July 2026

   Serialization, storage, and key management:  raAE emits and consumes
      component values but defines no wire container, storage
      transactions, or key lifecycle.  A consuming protocol supplies
      these.

6.11.  Cross-Application Domain Separation

   Two applications that both reuse the same SEAL profile label with the
   same input keying material, the same payload_info, and the same G
   derive identical commitments, keys, nonces, and AADs.  The
   protocol_id provides cross-application domain separation only when it
   is distinct per application.  Applications whose keying material may
   be shared across systems SHOULD use an application-specific
   protocol_id (for example, "myapp-backup-v1") rather than a SEAL
   profile label.  An application adopting a SEAL profile unchanged MAY
   use that profile's label.

7.  IANA Considerations

   This document has no IANA actions.  It defines an abstract primitive
   and a parameterized construction and requests no code points or
   registries of its own.  The cipher-suite code points and the
   registries of named instantiations and snapshot authenticators are
   specified in the companion ([I-D.sullivan-seal-concrete]).

   The normative reference to [I-D.ietf-hpke-pq], which defines the one-
   step KDF class this document's combiner admits, is a reference to a
   work in progress, so publication of this document waits on it.

8.  References

8.1.  Normative References

   [I-D.ietf-hpke-pq]
              Barnes, R. and D. Connolly, "Post-Quantum and Post-
              Quantum/Traditional Hybrid Algorithms for HPKE", Work in
              Progress, Internet-Draft, draft-ietf-hpke-pq-05, 6 July
              2026, <https://datatracker.ietf.org/doc/html/draft-ietf-
              hpke-pq-05>.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/rfc/rfc2119>.

   [RFC5116]  McGrew, D., "An Interface and Algorithms for Authenticated
              Encryption", RFC 5116, DOI 10.17487/RFC5116, January 2008,
              <https://www.rfc-editor.org/rfc/rfc5116>.

Sullivan                 Expires 24 January 2027               [Page 70]
Internet-Draft                    raAE                         July 2026

   [RFC5869]  Krawczyk, H. and P. Eronen, "HMAC-based Extract-and-Expand
              Key Derivation Function (HKDF)", RFC 5869,
              DOI 10.17487/RFC5869, May 2010,
              <https://www.rfc-editor.org/rfc/rfc5869>.

   [RFC8017]  Moriarty, K., Ed., Kaliski, B., Jonsson, J., and A. Rusch,
              "PKCS #1: RSA Cryptography Specifications Version 2.2",
              RFC 8017, DOI 10.17487/RFC8017, November 2016,
              <https://www.rfc-editor.org/rfc/rfc8017>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/rfc/rfc8174>.

   [RFC8452]  Gueron, S., Langley, A., and Y. Lindell, "AES-GCM-SIV:
              Nonce Misuse-Resistant Authenticated Encryption",
              RFC 8452, DOI 10.17487/RFC8452, April 2019,
              <https://www.rfc-editor.org/rfc/rfc8452>.

   [RFC9180]  Barnes, R., Bhargavan, K., Lipp, B., and C. Wood, "Hybrid
              Public Key Encryption", RFC 9180, DOI 10.17487/RFC9180,
              February 2022, <https://www.rfc-editor.org/rfc/rfc9180>.

   [RFC9861]  Viguier, B., Wong, D., Ed., Van Assche, G., Ed., Dang, Q.,
              Ed., and J. Daemen, Ed., "KangarooTwelve and TurboSHAKE",
              RFC 9861, DOI 10.17487/RFC9861, October 2025,
              <https://www.rfc-editor.org/rfc/rfc9861>.

8.2.  Informative References

   [ADG22]    Albertini, A., Duong, T., Gueron, S., Kölbl, S., Luykx,
              A., and S. Schmieg, "How to Abuse and Fix Authenticated
              Encryption Without Key Commitment", USENIX Security
              2022 pp. 3291-3308, 2022,
              <https://www.usenix.org/conference/usenixsecurity22/
              presentation/albertini>.

   [BHT18]    Bose, P., Hoang, V. T., and S. Tessaro, "Revisiting AES-
              GCM-SIV: Multi-user Security, Faster Key Derivation, and
              Better Bounds", IACR ePrint 2018/136, 2018,
              <https://eprint.iacr.org/2018/136>.

   [DGRW18]   Dodis, Y., Grubbs, P., Ristenpart, T., and J. Woodage,
              "Fast Message Franking: From Invisible Salamanders to
              Encryptment", CRYPTO 2018, LNCS vol. 10991, pp. 155-186,
              DOI 10.1007/978-3-319-96884-1_6, 2018,
              <https://doi.org/10.1007/978-3-319-96884-1_6>.

Sullivan                 Expires 24 January 2027               [Page 71]
Internet-Draft                    raAE                         July 2026

   [FLRR25]   Fábrega, A., Len, J., Ristenpart, T., and G. Rubin,
              "Random-Access AEAD for Fast Lightweight Online
              Encryption", EUROCRYPT 2026,
              DOI 10.1007/978-3-032-25333-0_10, 2026,
              <https://eprint.iacr.org/2025/2275>.

   [HRRV15]   Hoang, V. T., Reyhanitabar, R., Rogaway, P., and D. Vizár,
              "Online Authenticated-Encryption and its Nonce-Reuse
              Misuse-Resistance", IACR ePrint 2015/189, 2015,
              <https://eprint.iacr.org/2015/189>.

   [I-D.irtf-cfrg-aead-limits]
              Günther, F., Thomson, M., and C. A. Wood, "Usage Limits on
              AEAD Algorithms", Work in Progress, Internet-Draft, draft-
              irtf-cfrg-aead-limits-11, 4 December 2025,
              <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-
              aead-limits-11>.

   [I-D.sullivan-seal-concrete]
              Sullivan, N., "SEAL Cipher Suites and Instantiations",
              Work in Progress, Internet-Draft, draft-sullivan-seal-
              concrete-00, 2026, <https://datatracker.ietf.org/doc/html/
              draft-sullivan-seal-concrete-00>.

   [RFC8446]  Rescorla, E., "The Transport Layer Security (TLS) Protocol
              Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
              <https://www.rfc-editor.org/rfc/rfc8446>.

   [RFC8645]  Smyshlyaev, S., Ed., "Re-keying Mechanisms for Symmetric
              Keys", RFC 8645, DOI 10.17487/RFC8645, August 2019,
              <https://www.rfc-editor.org/rfc/rfc8645>.

   [RFC8937]  Cremers, C., Garratt, L., Smyshlyaev, S., Sullivan, N.,
              and C. Wood, "Randomness Improvements for Security
              Protocols", RFC 8937, DOI 10.17487/RFC8937, October 2020,
              <https://www.rfc-editor.org/rfc/rfc8937>.

   [RFC9580]  Wouters, P., Ed., Huigens, D., Winter, J., and Y. Niibe,
              "OpenPGP", RFC 9580, DOI 10.17487/RFC9580, July 2024,
              <https://www.rfc-editor.org/rfc/rfc9580>.

   [RFC9771]  Bozhko, A., Ed., "Properties of Authenticated Encryption
              with Associated Data (AEAD) Algorithms", RFC 9771,
              DOI 10.17487/RFC9771, May 2025,
              <https://www.rfc-editor.org/rfc/rfc9771>.

Sullivan                 Expires 24 January 2027               [Page 72]
Internet-Draft                    raAE                         July 2026

   [SEALPROOFS]
              Sullivan, N., "Security Analysis of the SEAL Construction:
              raAE, Snapshot Integrity, and Commitment", Work in
              Progress manuscript in preparation.

   [Tink]     Hoang, V. T. and Y. Shen, "Security of Streaming
              Encryption in Google's Tink Library", IACR ePrint
              2020/1019, 2020, <https://eprint.iacr.org/2020/1019>.

Appendix A.  Optional Plaintext-Bound Nonce Construction

   This appendix is informative.  It describes an optional encryptor-
   side construction that mixes plaintext content into the per-segment
   nonce derivation to defend against RNG state duplication.  The
   construction is encryptor-only: the decryptor reads the resulting
   nonce from the wire (in the same slot used by random mode) and never
   invokes any of the machinery below.  Implementations MAY use this
   construction in place of a fresh CSPRNG call when generating nonces
   under nonce_mode "random".  The wire format is indistinguishable from
   random mode and decryption is unaffected.

   One such construction:

   pt_digest(i) = LH(P_i)

   encryption_params = [aead_id, segment_max_be, kdf_id]
   pt_hash(i) = KDF(protocol_id, pt_hash_label,
                    [pt_digest(i)],
                    encryption_params, Nh)

   nonce_ctx = encode(protocol_id, uint64(i), pt_hash(i))
   nonce(i) = KDF(protocol_id, pt_nonce_label,
                  [Random(Nn), payload_key],
                  [...payload_info, nonce_ctx], Nn)

   This construction fixes two labels:

        +==========================+================+============+
        | Derivation role          | Label variable | Value      |
        +==========================+================+============+
        | Plaintext digest binding | pt_hash_label  | "pt-nonce" |
        +--------------------------+----------------+------------+
        | Final nonce derivation   | pt_nonce_label | "nonce"    |
        +--------------------------+----------------+------------+

              Table 14: Plaintext-bound construction labels

Sullivan                 Expires 24 January 2027               [Page 73]
Internet-Draft                    raAE                         July 2026

   Both labels are distinct from all other SEAL labels.  Neither
   derivation uses nonce_base_label (Table 4): the "nonce_base" label
   belongs to derived nonce mode and does not appear in this
   construction.  In the final derivation nonce_ctx enters the info list
   as one element after the payload_info elements: its encode output is
   framed behind a length prefix like any other element, not spliced
   flat into the list.

   LH is the over-large-field digest of Section 4.3.  Its collision
   resistance is justified in Section 4.3.

   When the encryptor's CSPRNG produces duplicated state (for example,
   from a virtual machine snapshot or a fork without reseed), two
   encryptions of distinct plaintexts at the same segment index still
   produce distinct nonces because pt_hash(i) differs.  Two encryptions
   of identical plaintexts at the same index produce identical nonces,
   resulting in deterministic encryption: the ciphertexts are identical,
   revealing only that the plaintexts are equal.

   For rewrites under this construction, the encryptor recomputes
   pt_hash(i) with the new plaintext, derives a fresh nonce(i) using the
   new pt_hash(i) and a new Random(Nn), seals the new plaintext under
   the new nonce, and updates the snapshot value as in Section 4.9.2.1.

Appendix B.  Optional Hedged Randomness

   When a long-term symmetric key sk of at least Nh octets is available
   to the encryptor, implementations SHOULD mix it into random
   generation using the hedging pattern of [RFC8937].  If only an
   asymmetric private key is available, it MUST first be processed
   through a KDF to produce a uniform symmetric key.

   hedge_key = KDF(protocol_id, hedge_label, sk, [], Nh)

   HedgedRandom(n, label):
     return KDF(protocol_id, label,
         [hedge_key, Random(n)], [], n)

   This construction fixes one label, hedge_label = "hedge", distinct
   from all other SEAL labels.

   HedgedRandom output depends on both the CSPRNG and sk, so a weak
   CSPRNG alone cannot predict it.  Hedging does not help when the
   CSPRNG state itself is duplicated (VM snapshots, fork without
   reseed).  Identical CSPRNG output still produces identical
   HedgedRandom output.  Appendix A describes an optional encryptor-side
   construction that defends against state duplication.  It is
   orthogonal to hedging and the two MAY be combined.

Sullivan                 Expires 24 January 2027               [Page 74]
Internet-Draft                    raAE                         July 2026

Appendix C.  Proof Status and Security Claim Provenance

   This appendix is informative.  Table 15 gives each security claim's
   source, argument, and assumptions.  Each is inherited from [FLRR25],
   argued in this document, referenced from external work, or deferred
   to the proof paper in preparation ([SEALPROOFS]).  The one claim
   proved in full here is the KDF combiner's injectivity.

   The combiner's input encoding is injective and canonical
   (Section 4.3, Section 5.4): distinct (protocol_id, label, ikm, info,
   L) tuples map to distinct primitive inputs, from the length-prefixed
   encoding rather than the KDF.  Collision resistance is assumed only
   of LH, and only for over-large fields.  A snapshot authenticator with
   the segment commitment additionally relies on LH collision resistance
   to bind each segment's ciphertext of any length (Section 4.7.1), and
   the commitment derivation carries its own separate collision-
   resistance assumption (Appendix C.4).

C.1.  Provenance of the Security Claims

   +============+==============+========+==============================+
   |Property    |Source        |Argument| Rests on                     |
   +============+==============+========+==============================+
   |ra-ROR      |[FLRR25]      |Appendix| mu-PRF KDF (two keying       |
   |            |notion and    |C.2,    | levels), mu-ROR AEAD, no     |
   |            |base proof;   |Appendix| nonce collision, fresh per-  |
   |            |SEAL's        |C.3     | message salt                 |
   |            |arbitrary-    |        |                              |
   |            |position ra-  |        |                              |
   |            |ROR syntax is |        |                              |
   |            |a SEAL-       |        |                              |
   |            |specific      |        |                              |
   |            |obligation    |        |                              |
   +------------+--------------+--------+------------------------------+
   |ra-CMT      |[FLRR25]      |Appendix| collision resistance of the  |
   |(commitment,|              |C.4     | commitment derivation map    |
   |position-   |              |        | over (protocol_id, "commit", |
   |respecting) |              |        | CEK, payload_info, G,        |
   |            |              |        | commitment_length)           |
   +------------+--------------+--------+------------------------------+
   |ra-CMT-p    |[FLRR25]      |Appendix| ra-CMT collision bound plus  |
   |(per-segment|notion and    |C.4     | the underlying AEAD's        |
   |associated- |base proof;   |        | commitment bound for the     |
   |data and    |SEAL          |        | forged position, restored    |
   |position    |position-     |        | conditionally by the segment |
   |commitment) |binding       |        | commitment over a strict     |
   |            |realization   |        | ordering where the snapshot  |
   |            |and per-      |        | is authenticated outside the |

Sullivan                 Expires 24 January 2027               [Page 75]
Internet-Draft                    raAE                         July 2026

   |            |segment       |        | construction (Section 5.6)   |
   |            |associated-   |        |                              |
   |            |data and      |        |                              |
   |            |position      |        |                              |
   |            |accounting    |        |                              |
   |            |argued here,  |        |                              |
   |            |formal write- |        |                              |
   |            |up in         |        |                              |
   |            |[SEALPROOFS]  |        |                              |
   +------------+--------------+--------+------------------------------+
   |KDF combiner|this document |Section | injectivity of the length-   |
   |injectivity |(structural,  |4.3,    | prefixed encoding (KDF need  |
   |and domain  |proof-        |Section | not be injective); collision |
   |separation  |complete)     |5.4     | resistance of LH for over-   |
   |            |              |        | large fields only            |
   +------------+--------------+--------+------------------------------+
   |Snapshot    |this document |Section | unforgeability of the        |
   |integrity   |(notion,      |5.7     | snapshot value by a party    |
   |            |Section       |        | without snap_key; per-object |
   |            |5.1.4);       |        | separation via salt-bound    |
   |            |configured    |        | snap_key                     |
   |            |authenticator |        |                              |
   |            |(bound)       |        |                              |
   +------------+--------------+--------+------------------------------+
   |AEAD usage, |external work |Section | [I-D.irtf-cfrg-aead-limits], |
   |rewrite, and|(operational, |5.8,    | [RFC8452] Section 9 with     |
   |max-object  |not proven    |Section | [BHT18], 2^63 segment-index  |
   |bounds      |here)         |5.8.3,  | ceiling                      |
   |            |              |Section |                              |
   |            |              |5.8.6.4 |                              |
   +------------+--------------+--------+------------------------------+
   |Derived-    |precedent,    |Section | write-once or append-only    |
   |nonce       |not proof     |4.5.3.2,| uniqueness discipline        |
   |unique-nonce|(TLS 1.3      |Appendix| reducing to nonce-respecting |
   |transform   |[RFC8446],    |C.5     | AEAD security                |
   |            |STREAM        |        |                              |
   |            |[HRRV15])     |        |                              |
   +------------+--------------+--------+------------------------------+
   |Derived-    |this          |Appendix| MRAE AEAD ([RFC8452]); per-  |
   |nonce       |document;     |C.5     | segment fixed-nonce data-    |
   |equality    |full proof in |        | volume cap                   |
   |leakage     |[SEALPROOFS]  |        |                              |
   |(MRAE)      |              |        |                              |
   +------------+--------------+--------+------------------------------+

                Table 15: Provenance of the security claims

Sullivan                 Expires 24 January 2027               [Page 76]
Internet-Draft                    raAE                         July 2026

C.2.  Advantage Notation and Adversary Parameters

   For a ra-ROR adversary (Section 5.3) using at most u distinct CEKs
   and q_m messages, each encrypted with an independent fresh 32-octet
   per-content salt (Section 4.9.1.1), across n_ep total epochs and
   making q_e encryption and q_d decryption segment queries with sigma =
   q_e + q_d, the advantage is bounded by:

   Adv_raROR(A) <= Adv_salt_coll
                      + Adv_muPRF(KDF, B_KDF)
                      + Adv_muROR(AEAD, B_AEAD)
                      + Adv_nonce_coll
                      + Adv_snap

   Adv_salt_coll  The probability that two messages encrypted under one
      CEK draw the same salt.  Because the salt is a 32-octet value
      drawn uniformly at random, this term is at most q_m^2 / 2^256.  A
      salt collision is not a PRF-distinguishing event: the KDF
      deterministically produces identical payload_key, snap_key, and
      nonce_base outputs whenever (CEK, payload_info) repeats, so the
      event must be charged separately.  Conditioned on no salt
      collision, distinct messages under one CEK have distinct
      payload_info values and therefore independent KDF outputs under
      the mu-PRF assumption.  This term holds only under the fresh per-
      message uniform salt requirement of Section 4.9.1.1.  A profile
      that reuses salts or draws them non-uniformly forfeits it and must
      argue payload-schedule separation by other means (Section 6.7).

   Adv_muPRF(KDF, B_KDF)  The multi-user PRF advantage of the KDF,
      covering two keying levels.  Level A is keyed by the CEK and
      produces payload_key, snap_key, and nonce_base.  It has u users,
      queried once per message.  Level B is keyed by payload_key
      (producing epoch_key per Section 4.5.2 and, in the plaintext-bound
      construction, per-segment nonces per Appendix A) and by snap_key
      (producing the snapshot authenticator's keyed derivations).  It
      has q_m users.  The snap_key subset of Level B feeds the
      configured snapshot authenticator and is counted under Adv_snap
      below.  It is not counted again here.

   Adv_muROR(AEAD, B_AEAD)  The multi-user real-or-random advantage of

Sullivan                 Expires 24 January 2027               [Page 77]
Internet-Draft                    raAE                         July 2026

      the AEAD over sigma total segment queries.  There is one mu-ROR
      user per distinct segment key, for n_ep epoch keys total (n_ep =
      q_m when each message uses a single flat epoch key).  This
      advantage absorbs a key-collision birthday term of about
      n_ep^2/2^(8*Nk) over the n_ep distinct keys.  For the 256-bit-key
      suites (Nk = 32) that term is about n_ep^2/2^256 and is
      negligible.  For the 128-bit-key suite (Nk = 16) it is about
      n_ep^2/2^128 and is the binding epoch-key collision floor.
      Section 5.8.5 bounds n_ep for that suite.

   Adv_nonce_coll  The probability of a nonce collision under any
      segment key.  In derived nonce mode it is zero, conditional on no
      salt collision (already charged via Adv_salt_coll).  In random
      nonce mode (with or without the plaintext-bound hedge) it is
      bounded per Section 5.8.6.1.  The derived-mode statement relies on
      the deterministic-MRAE analysis in Appendix C.5.

   Adv_snap  The snapshot-forgery advantage of the configured snapshot
      authenticator, present only under an authenticator that produces a
      snapshot value and zero under None (Section 4.7.2).  It covers the
      mu-PRF cost of the authenticator's snap_key derivations (the
      snap_key subset of Level B, counted here and not again in
      Adv_muPRF(KDF, B_KDF)) with the forgery and any further terms the
      authenticator's own construction requires.  A key-holder content-
      binding property, where an authenticator provides one, is a
      separate notion from this without-key advantage and is not counted
      here.

C.3.  ra-ROR Reduction

   The reduction follows the [FLRR25] hybrid over the two-level key
   schedule (Section 4.5).  Condition on no salt collision
   (Adv_salt_coll).  Replace the CEK-keyed KDF outputs and the
   payload_key-keyed outputs with uniformly random values, charged to
   Adv_muPRF; these are Level A and the payload_key subset of Level B.
   The snap_key-keyed outputs are idealized likewise, but their mu-PRF
   cost is the snap_key subset of Level B, charged to Adv_snap and not
   to Adv_muPRF (Section 5.7).  Bound the resulting segment AEAD outputs
   (Adv_muROR).  A flat epoch key is the single-epoch case of the same
   argument.  The segment AEAD calls are nonce-respecting only under no
   nonce collision, the event charged to Adv_nonce_coll (Appendix C.2).
   In derived nonce mode this term is zero conditional on the same no-
   salt-collision event (Appendix C.5).  The snapshot authenticator's
   forgery is the remaining part of Adv_snap (Section 5.7).  The
   reduction constructs adversaries B_KDF against multi-user PRF
   security of the KDF and B_AEAD against multi-user real-or-random
   security of the AEAD, each running in time approximately that of A.

Sullivan                 Expires 24 January 2027               [Page 78]
Internet-Draft                    raAE                         July 2026

C.4.  Commitment

   ra-CMT security reduces to collision resistance of the commitment
   derivation map over the tuple (protocol_id, "commit", CEK,
   payload_info, G, commitment_length), with G empty by default.  PRF
   security alone is not sufficient for this reduction, because the
   commitment adversary may choose the CEK and the context values
   (Section 4.5).

   For commitment_length = L octets, the relevant quantities are:

   fixed-pair collision probability:  2^(-8*L)
   q-query birthday probability:      q^2 / 2^(8*L + 1)
   collision-search work factor:      about 2^(4*L)

   Thus 16 octets gives about 2^64 collision-search work, 32 octets
   about 2^128, 48 octets about 2^192, and 64 octets about 2^256, each
   capped by the collision resistance of the underlying hash.  The
   fixed-pair collision probabilities at 32, 48, and 64 octets are
   2^(-256), 2^(-384), and 2^(-512), respectively.

   The ra-CMT-p advantage is bounded by the sum of two terms: the
   commitment collision bound above and the underlying AEAD's commitment
   bound for the forged position.

   Position binding is inherited from the underlying AEAD, restored by
   the segment commitment over a strict ordering where the snapshot is
   authenticated outside the construction (Section 5.6).  The notion
   derives from [FLRR25], and the per-segment associated-data and
   position accounting is deferred to [SEALPROOFS] (Appendix C.1).

C.5.  Nonce Modes

   The unique-nonce transform of Section 4.5.3.2, which XORs the segment
   index and finality bit into nonce_base, follows TLS 1.3 ([RFC8446])
   static-IV-XOR-identifier and STREAM ([HRRV15]) counter-plus-final-bit
   precedent.  The transform is injective in the pair (i, is_final).
   The leading Nn - 8 octets of nonce_base are unchanged; XOR by its
   fixed low 8-octet value is a bijection on 8-octet strings; and (i,
   is_final) maps to the integer (i << 1) | is_final, which is a
   bijection from the index range i < 2^63 onto the 64-bit values.
   Distinct pairs therefore yield distinct nonces, and a derived nonce
   repeats only when an object encrypts twice at one pair.

   Both disciplines of Section 4.5.3.2 keep every derived nonce carrying
   one plaintext, so each reduces unique-nonce record protection to
   nonce-respecting AEAD security.  That reduction is precedent, not a
   SEAL-specific proof.

Sullivan                 Expires 24 January 2027               [Page 79]
Internet-Draft                    raAE                         July 2026

   Under both disciplines no segment is ever re-encrypted with a
   different plaintext or associated data (Section 6.2,
   Section 4.9.3.1), so where a nonce is used twice both uses carry the
   same inputs, AEAD.Encrypt reproduces the same ciphertext, and a
   reduction answers the second query from the first one's output.  The
   bound is therefore the same in both cases: the underlying AEAD's
   bound under distinct nonces.

   In derived nonce mode the nonce-collision term is zero conditional on
   no salt collision, because each segment index maps to one derived
   nonce and a fresh per-message salt makes the segment keys distinct
   across messages.  A rewrite reuses a segment's derived nonce, so the
   construction relies on the underlying MRAE AEAD: re-encrypting the
   same plaintext and associated data under the same key and nonce
   reproduces the same ciphertext, which leaks only equality of those
   inputs, while distinct inputs remain real-or-random secure
   ([RFC8452]).  The formal real-or-random treatment of this equality
   leakage for derived nonce mode is in preparation ([SEALPROOFS]).
   That treatment builds on the [FLRR25] ra-ROR analysis and changes its
   nonce-respecting hypothesis: a rewrite repeats a segment's derived
   nonce, so the proof replaces the nonce-respecting AEAD assumption
   with deterministic-MRAE security, under which nonce reuse leaks only
   input equality.

Appendix D.  Design Rationale

   This appendix is informative.

D.1.  Key Schedule Design Rationale

   The per-content salt makes the payload schedule unique even when a
   CEK is reused across messages, which matters for applications that
   derive CEKs from group keys.  The encryptor chooses the salt locally
   at write time.  A per-message counter would instead require
   synchronized state.

   The CEK is 32 octets regardless of the AEAD key size Nk, so a 128-
   bit-key AEAD still derives its keys from a 256-bit CEK.

   Epoch keys bound the number of AEAD invocations under any one segment
   encryption key.

   AEAD per-key bounds:  The per-key bounds of the underlying AEAD
      (birthday for 96-bit-nonce schemes, block-size for AES, integrity
      forgery for all schemes) become the limiting factor on security
      long before the nonce space is fully exhausted.

   Write-once content:  Large content with many segments can place many

Sullivan                 Expires 24 January 2027               [Page 80]
Internet-Draft                    raAE                         July 2026

      AEAD invocations under one key, even when the content is written
      once.

   Rewrites:  Rewrites consume additional invocations and can exhaust
      the same budget faster than write-once use, but they are not the
      only reason for epoching.  Write-once large content benefits from
      the same partitioning.

   Random access:  Rekeying the entire content would defeat the random-
      access property, so epoch keys bound the per-key invocation count
      without requiring a full re-encryption.

   Labels separate derivation roles: commitment and payload_key share
   the same inputs but different labels, making them independent under
   the PRF assumption.  Once CEK and salt are chosen the hierarchy is
   fixed, with no mutable state to synchronize across writers.

D.2.  Nonce Mode Design Rationale

   Random mode is simplest but trusts the CSPRNG completely.  Derived
   mode removes that trust.  In a mutable profile it requires an MRAE
   AEAD, because an in-place rewrite reuses the segment nonce
   (Section 6.5).  In the write-once profile the write-once rule keeps
   every derived nonce unique, and in the append-only profile the
   append-only rule does, so under either, derived mode pairs with any
   AEAD.  A third rule was available and rejected: permitting a length
   change in either direction would let a truncation free indices the
   object had already spent, for a later append to encrypt new content
   at (Section 4.9.3.1).

   The nonce mode is a profile parameter: a profile selects a valid
   (nonce_mode, snap_id) tuple, subject to the MRAE requirement above.

Acknowledgments

   The author thanks Andrés Fábrega, Thomas Ristenpart, Gregory Rubin,
   Richard Barnes, Brendan McMillion, Thibault Meunier, Kenny Paterson,
   Christopher Patton, Martin Thomson, Stanislav V.  Smyshlyaev, and
   Christopher A.  Wood for their reviews, comments, and discussions.

Author's Address

   Nick Sullivan
   Cryptography Consulting LLC
   Email: nicholas.sullivan+ietf@gmail.com

Sullivan                 Expires 24 January 2027               [Page 81]