Skip to main content

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

Document Type Active Internet-Draft (individual)
Author Nick Sullivan
Last updated 2026-07-06
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-01
Crypto Forum                                                 N. Sullivan
Internet-Draft                               Cryptography Consulting LLC
Intended status: Informational                               6 July 2026
Expires: 7 January 2027

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

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 provides two profiles, immutable (write-once) and mutable (in-
   place ciphertext rewrite), 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, analyzes SEAL against
   those requirements, and provides example cipher suites and test
   vectors.

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.

   Source for this draft and an issue tracker can be found at
   https://github.com/grittygrease/draft-sullivan-cfrg-raae.

Status of This Memo

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

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

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

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

   This Internet-Draft will expire on 7 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  . . . . . . . . . . . . . . . . . . . . . . . .   5
     1.1.  Related Work  . . . . . . . . . . . . . . . . . . . . . .   7
   2.  Conventions and Terminology . . . . . . . . . . . . . . . . .   8
     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.  SEAL: A Concrete raAE Construction  . . . . . . . . . . . . .  14
     4.1.  Construction Overview . . . . . . . . . . . . . . . . . .  15
     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 . . . . . . . . . . . . . . . .  23
       4.4.1.  Payload Info Construction . . . . . . . . . . . . . .  23
       4.4.2.  Segment AAD . . . . . . . . . . . . . . . . . . . . .  24
       4.4.3.  Labels  . . . . . . . . . . . . . . . . . . . . . . .  26

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

     4.5.  Key Schedule and Nonce Generation . . . . . . . . . . . .  27
       4.5.1.  Payload Schedule  . . . . . . . . . . . . . . . . . .  27
       4.5.2.  Epoch Key Derivation  . . . . . . . . . . . . . . . .  28
       4.5.3.  Nonce Generation  . . . . . . . . . . . . . . . . . .  29
     4.6.  Commitment  . . . . . . . . . . . . . . . . . . . . . . .  32
     4.7.  Snapshot Authenticator  . . . . . . . . . . . . . . . . .  33
       4.7.1.  Interface and Requirements  . . . . . . . . . . . . .  33
       4.7.2.  Selecting an Authenticator  . . . . . . . . . . . . .  35
       4.7.3.  None  . . . . . . . . . . . . . . . . . . . . . . . .  35
       4.7.4.  Masked Multiset Hash  . . . . . . . . . . . . . . . .  36
     4.8.  Segment Algorithms  . . . . . . . . . . . . . . . . . . .  39
       4.8.1.  EncryptSegment  . . . . . . . . . . . . . . . . . . .  40
       4.8.2.  DecryptSegment  . . . . . . . . . . . . . . . . . . .  40
       4.8.3.  RewriteSegment  . . . . . . . . . . . . . . . . . . .  40
     4.9.  Top-level Algorithms  . . . . . . . . . . . . . . . . . .  41
       4.9.1.  Read-Only Operations  . . . . . . . . . . . . . . . .  41
       4.9.2.  Rewritable Operations . . . . . . . . . . . . . . . .  45
     4.10. SEAL Suites . . . . . . . . . . . . . . . . . . . . . . .  48
       4.10.1.  Algorithms . . . . . . . . . . . . . . . . . . . . .  48
       4.10.2.  Composing a SEAL Suite . . . . . . . . . . . . . . .  51
     4.11. Serialization Layouts . . . . . . . . . . . . . . . . . .  53
       4.11.1.  Linear Layout  . . . . . . . . . . . . . . . . . . .  53
       4.11.2.  Aligned Layout . . . . . . . . . . . . . . . . . . .  54
       4.11.3.  Split Layout . . . . . . . . . . . . . . . . . . . .  57
       4.11.4.  Immutable-Profile Layouts  . . . . . . . . . . . . .  58
     4.12. SEAL Named Instantiations . . . . . . . . . . . . . . . .  58
   5.  Security Analysis . . . . . . . . . . . . . . . . . . . . . .  60
     5.1.  Operational Summary . . . . . . . . . . . . . . . . . . .  60
     5.2.  Security Notions  . . . . . . . . . . . . . . . . . . . .  61
       5.2.1.  ra-ROR  . . . . . . . . . . . . . . . . . . . . . . .  61
       5.2.2.  ra-CMT  . . . . . . . . . . . . . . . . . . . . . . .  62
       5.2.3.  Snapshot Authentication . . . . . . . . . . . . . . .  62
     5.3.  Relations to Other Notions  . . . . . . . . . . . . . . .  62
     5.4.  Adversary Model and Assumptions . . . . . . . . . . . . .  63
     5.5.  raAE Construction Requirements  . . . . . . . . . . . . .  65
     5.6.  Segment Confidentiality and Integrity . . . . . . . . . .  68
     5.7.  Commitment Security . . . . . . . . . . . . . . . . . . .  69
     5.8.  Snapshot Authenticator Security . . . . . . . . . . . . .  71
       5.8.1.  Masked Multiset Hash  . . . . . . . . . . . . . . . .  72
     5.9.  Capacity and Usage Limits . . . . . . . . . . . . . . . .  72
       5.9.1.  Accounting Model  . . . . . . . . . . . . . . . . . .  72
       5.9.2.  Limit Classes . . . . . . . . . . . . . . . . . . . .  73
       5.9.3.  Binding Limits for Profiled Suites  . . . . . . . . .  74
       5.9.4.  Maximum Write-Once Object Size  . . . . . . . . . . .  75
       5.9.5.  Rewrite Capacity  . . . . . . . . . . . . . . . . . .  76
       5.9.6.  Choosing epoch_length . . . . . . . . . . . . . . . .  78
       5.9.7.  Derivations . . . . . . . . . . . . . . . . . . . . .  79
   6.  Security Considerations . . . . . . . . . . . . . . . . . . .  81

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

     6.1.  Detection Summary . . . . . . . . . . . . . . . . . . . .  81
     6.2.  Nonce Misuse  . . . . . . . . . . . . . . . . . . . . . .  83
     6.3.  Parameter Set Mismatch  . . . . . . . . . . . . . . . . .  83
     6.4.  Framing and Label Errors  . . . . . . . . . . . . . . . .  84
     6.5.  Parameter Misuse  . . . . . . . . . . . . . . . . . . . .  84
     6.6.  Snapshot Integrity Limitations  . . . . . . . . . . . . .  85
     6.7.  Salt Reuse  . . . . . . . . . . . . . . . . . . . . . . .  86
     6.8.  Rewrite Hazards . . . . . . . . . . . . . . . . . . . . .  86
     6.9.  Constant-Time Implementation  . . . . . . . . . . . . . .  88
     6.10. Properties Not Provided . . . . . . . . . . . . . . . . .  88
     6.11. Cross-Application Domain Separation . . . . . . . . . . .  89
   7.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  89
   8.  References  . . . . . . . . . . . . . . . . . . . . . . . . .  90
     8.1.  Normative References  . . . . . . . . . . . . . . . . . .  90
     8.2.  Informative References  . . . . . . . . . . . . . . . . .  91
   Appendix A.  Optional Plaintext-Bound Nonce Construction  . . . .  93
   Appendix B.  Optional Hedged Randomness . . . . . . . . . . . . .  94
   Appendix C.  Proof Status and Security Claim Provenance . . . . .  95
     C.1.  Provenance of the Security Claims . . . . . . . . . . . .  96
     C.2.  Advantage Notation and Adversary Parameters . . . . . . .  98
     C.3.  ra-ROR Reduction  . . . . . . . . . . . . . . . . . . . .  99
     C.4.  Commitment  . . . . . . . . . . . . . . . . . . . . . . . 100
     C.5.  Snapshot Authenticator  . . . . . . . . . . . . . . . . . 100
     C.6.  Nonce Modes . . . . . . . . . . . . . . . . . . . . . . . 102
   Appendix D.  Design Rationale . . . . . . . . . . . . . . . . . . 102
     D.1.  Key Schedule Design Rationale . . . . . . . . . . . . . . 102
     D.2.  Nonce Mode Design Rationale . . . . . . . . . . . . . . . 103
     D.3.  Snapshot Authenticator Design Rationale . . . . . . . . . 103
   Appendix E.  Test Vectors . . . . . . . . . . . . . . . . . . . . 104
     E.1.  Single Segment, AES-256-GCM, HKDF-SHA-256, 16384  . . . . 106
     E.2.  Commitment with Global Associated Data  . . . . . . . . . 107
     E.3.  KDF Combiner Vectors  . . . . . . . . . . . . . . . . . . 108
     E.4.  Single Segment, AES-256-GCM, HKDF-SHA-256, 65536  . . . . 110
     E.5.  Single Segment, ChaCha20-Poly1305, HKDF-SHA-256, 16384  . 111
     E.6.  Single Segment, ChaCha20-Poly1305, HKDF-SHA-256, 65536  . 112
     E.7.  Single Segment, AEGIS-256, HKDF-SHA-256, 16384  . . . . . 114
     E.8.  Single Segment, AEGIS-256, HKDF-SHA-256, 65536  . . . . . 115
     E.9.  Two Segment, AES-256-GCM, HKDF-SHA-256, 16384 . . . . . . 116
     E.10. Two Segment, AES-256-GCM, HKDF-SHA-256, 65536 . . . . . . 118
     E.11. Two Segment, ChaCha20-Poly1305, HKDF-SHA-256, 16384 . . . 119
     E.12. Two Segment, ChaCha20-Poly1305, HKDF-SHA-256, 65536 . . . 121
     E.13. Two Segment, AEGIS-256, HKDF-SHA-256, 16384 . . . . . . . 122
     E.14. Two Segment, AEGIS-256, HKDF-SHA-256, 65536 . . . . . . . 124
     E.15. TurboSHAKE-256 Cipher Suite Vectors . . . . . . . . . . . 126
       E.15.1.  Single Segment, AES-256-GCM, TurboSHAKE-256,
               65536 . . . . . . . . . . . . . . . . . . . . . . . . 126
       E.15.2.  Two Segment, AES-256-GCM, TurboSHAKE-256, 65536  . . 127
     E.16. Segment Rewrite Vector  . . . . . . . . . . . . . . . . . 130

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

       E.16.1.  Two Segment, AES-256-GCM, HKDF-SHA-256, 65536
               (Rewrite) . . . . . . . . . . . . . . . . . . . . . . 130
     E.17. Derived-Nonce Cipher Suite Vector . . . . . . . . . . . . 132
       E.17.1.  Two Segment, AES-256-GCM-SIV, HKDF-SHA-256, 65536
               (Rewrite) . . . . . . . . . . . . . . . . . . . . . . 132
     E.18. Cross-Epoch Key Vector  . . . . . . . . . . . . . . . . . 135
       E.18.1.  Two Segment, AES-256-GCM, HKDF-SHA-256, 65536,
               epoch_length 0  . . . . . . . . . . . . . . . . . . . 135
     E.19. Plaintext-Bound Nonce Component Vectors . . . . . . . . . 137
       E.19.1.  AES-256-GCM, HKDF-SHA-256, 16384, Segment 0  . . . . 137
       E.19.2.  AES-256-GCM, TurboSHAKE-256, 65536, Segment 1  . . . 138
     E.20. Negative SnapVerify Vector  . . . . . . . . . . . . . . . 138
       E.20.1.  Tampered Accumulator, Snapshot Tag Not Recomputed  . 138
   Appendix F.  Changes from draft-sullivan-cfrg-raae-00 . . . . . . 139
   Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 141
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . . 141

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 tag and the count into
   a public snapshot value that an adversary cannot forge without the
   content-derived key.

Sullivan                 Expires 7 January 2027                 [Page 5]
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 | mutable |    |  none | present      |       |
      |   '----------------------'    '----------------------'       |
      '--------------------------------------------------------------'
                                   |
                                   v   provides
      .----------------------------.      .------------------------.
      |  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 tags and the
      count are exactly the set the writer last recorded, under a
      content-derived key.  It does not establish freshness against
      whole-object rollback, which a consuming protocol must supply.

   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 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 raAE primitive and its extended
   snapshot operations.  Section 4 defines SEAL.  Section 5 states the

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

   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, and named instantiations are in Section 4.10,
   Section 4.11, and Section 4.12, and the appendices provide the test
   vectors.

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 is a keyed multiset hash over the
   segment tags, the MSet-XOR-Hash of Clarke, Devadas, van Dijk,
   Gassend, and Suh ([MSetHash]), published behind a deterministic mask
   this document adds (Section 4.7.4).  Each segment contributes a keyed
   KDF evaluation of its index and AEAD tag, the contributions XOR into
   an accumulator that any rewrite updates in O(1), and a domain-
   separated snapshot tag binds the segment count and the accumulator.

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

   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.2 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 them combines: arbitrary-order encryption, in-
   place authenticated rewrite, and an O(1) updatable 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.

   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.

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

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

   A subscript denotes a per-segment value: X_i is the value X for the
   segment at index i, as in A_i, P_i, ct_i, and tag_i.  A value written
   f(i), as in segment_key(i) or nonce(i), is computed from the index by
   the named derivation.  X[a:b] is the octet range of X from offset a
   inclusive to offset b exclusive.

   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.

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 concrete 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 (Section 4.10.2).

   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.

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

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

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

   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.5) but
      does not mandate this encoding.  Another profile MAY use any
      injective encoding that meets Section 5.5.

   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.

   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 7 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.  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 per-segment authentication still passes on each segment
   it is shown.  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.2).  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.2.3).

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

   Rewriting gives a storage layer something to attack: it can roll a
   segment back to an older valid copy, substitute one valid same-index
   segment for another, or drop one while per-segment authentication
   still passes on what it presents.  A scheme that supports rewriting
   MAY carry a snapshot, a value over the current set of segments that a
   reader checks to detect these changes.

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

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

   SnapVerify(S, segments, snapshot):  Deterministic.  Takes the
      encryption state S, the present segments (the (position,
      ciphertext segment) pairs of the current object state), and the
      snapshot.  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.  When the scheme supports incremental
   update, an update can run in time independent of the total segment
   count.  This is an implementation goal, not a syntactic requirement
   of the interface.  The base primitive has no snapshot value.  The
   snapshot, the two signature changes above, RewriteSeg, and SnapVerify
   are defined by this document.

   These additions define the extended raAE interface of this document:
   the tuple (KeyGen, StartEnc, EncSeg, StartDec, DecSeg, RewriteSeg,
   SnapVerify) over the auxiliary snapshot value.  The first five
   algorithms are those of Section 3.2, with the snapshot outputs of
   StartEnc and EncSeg defined above.  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.  Length change adds no further
   algorithm, as the next paragraph describes.

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

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

   Length changes occur only at the end of the message: a holder may
   append segments or drop a suffix, but cannot remove or renumber front
   or interior segments, because positions are index-addressed.  Each
   step updates the snapshot, and Section 4.9.2.2 gives the construction
   for both directions.

4.  SEAL: A Concrete raAE Construction

   SEAL is a parameterized construction for realizing the raAE primitive
   defined in Section 3.  A SEAL instantiation combines an AEAD, a KDF,
   a key schedule, a nonce-generation method, a commitment mechanism,
   and an optional snapshot authenticator to produce an raAE scheme for
   segmented stored content.

   The raAE interface defines what operations and security properties a
   scheme provides.  SEAL defines how those operations are realized from
   standard cryptographic components.  Different SEAL instantiations MAY
   select different AEADs, KDFs, nonce modes, commitment mechanisms, or
   snapshot authenticators, provided they satisfy the requirements of
   this section.

   The remainder of this section specifies the common SEAL construction.
   Section 5 analyzes its security, and concrete parameter choices and
   interoperable suites are in Section 4.10.

   The key hierarchy is shown below.  A CEK and per-content salt feed
   the payload schedule, which derives four values.  The payload key
   feeds per-segment keys (optionally through epoch keys), and each
   segment produces an AEAD tag.  When a snapshot authenticator is
   configured, every tag feeds it to produce the snapshot.

Sullivan                 Expires 7 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

4.1.  Construction Overview

   A commitment lets a reader reject a wrong key or parameter set before
   decrypting anything.  An optional snapshot authenticates the current
   set of segments.

   SEAL realizes the raAE operations of Section 3.2 as follows:

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

         +============+==========================================+
         | 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

   This section names every parameter, input, and derived symbol the
   construction uses.  Table 2 summarizes them, grouped by what sets
   each one.  The entries that follow define the suite choices, the
   profile-level constants, the algorithm-determined sizes, and the per-
   message inputs.  Derived values are defined where they are computed,
   in the sections the table cites.

    +===================+===================+=============+==========+
    | Parameter         | Type or range     | Set by      | Defined  |
    |                   |                   |             | in       |
    +===================+===================+=============+==========+
    | AEAD              | RFC 5116          | suite       | Section  |
    |                   | algorithm         |             | 4.10.1   |
    +-------------------+-------------------+-------------+----------+
    | KDF               | kdf_id from       | suite       | Section  |
    |                   | Table 10          |             | 4.3      |
    +-------------------+-------------------+-------------+----------+
    | segment_max       | power of two, at  | suite       | Section  |
    |                   | least 4096        |             | 4.10     |

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

    +-------------------+-------------------+-------------+----------+
    | 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  |
    |                   | ("SEAL-DATA" in   |             | 4.4.2    |
    |                   | SEAL)             |             |          |
    +-------------------+-------------------+-------------+----------+
    | commitment_length | integer, at least | profile     | Appendix |
    |                   | 16, default Nh    |             | C.4      |
    +-------------------+-------------------+-------------+----------+
    | Nk, Nn, Nt        | 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  |
    |                   | derived mode only | message     | 4.5      |
    +-------------------+-------------------+-------------+----------+

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

    | 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,
   the commitment derivation, and the snapshot value for every suite.
   They are specified in Section 4.4.2, Section 4.6, and Section 4.7
   respectively, and are encoded identically across all SEAL cipher
   suites.  The resulting 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.  See Table 10 for the permitted KDFs.

   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.9 are computed at this
      size.

   epoch_length:  A non-negative integer r in 0 to 63.  Each epoch

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

      covers 2^r consecutive segments aligned to a multiple of 2^r
      (Section 4.5.2).  Profiles MAY restrict r further per AEAD
      (Section 4.10).  The value sets a rotation granularity, not an on/
      off switch: r = 0 selects the finest rotation, a fresh epoch key
      for every segment, and no value of r disables epoch-key
      derivation.  A flat key, one epoch key covering all segments, is r
      = 63.

   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, the default mode each SEAL suite uses in
      the mutable profile (Table 9), and the valid (nonce_mode, snap_id)
      tuples for each profile in Section 4.10.2.

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.  They are defined in
   Section 2.2, with concrete values in Table 9 and Table 10.  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

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

      separates payload schedule outputs across messages even when the
      CEK is reused.  Section 4.9.1.1 and Section 4.9.2.2 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.

   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 (Section 4.5) computes the per-message values commitment,
   payload_key, snap_key, and nonce_base once from the CEK and
   payload_info (the commitment also binds G, Section 4.6), and they are
   fixed for the message's lifetime.  The per-segment values
   epoch_key(i), segment_key(i), nonce(i), segment_aad(i, is_final,
   A_i), and tag(i) are defined where they are computed: Section 4.5.2,
   Section 4.5.3, Section 4.4.2, and Section 4.8.

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 of at most 0xFFFE
   octets is emitted literally behind its 2-octet length, identical to a
   plain length prefix.  The reserved length 0xFFFF is a typed prefix
   meaning that an Nh-octet digest LH(x) of an over-large field follows
   in place of the field itself.

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

   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)

   Routing LH through the KDF would encode-frame x and recurse, because
   frame of an over-large x would re-enter LH.  LH therefore runs the
   native primitive directly on x.  The injectivity of encode and the
   domain-separation and collision properties of LH are established in
   Section 5.5.

   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.  SEAL's two profiles
   instantiate the combiner at protocol_id SEAL-RW-v1 and SEAL-RO-v1
   (Section 4.10.2).

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

4.3.1.  Two-Step KDF

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

   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)

   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)

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

   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.5 and demonstrated in Appendix E.3).  The
   two forms are not mutually injective: a cipher suite's kdf_id
   (Table 10) 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.

   The following example expands M for combiner vector KDF.33
   (Appendix E.3): TurboSHAKE-256, label "commit", ikm a single 32-octet
   element of repeated 0xAA, info the two elements 010203 and 0405, and
   L = 64.  Each frame is a 2-octet length followed by the element, and
   the ikm and info lists are each one nested encode:

   M, 71 octets, in frame order:

   000a 5345414c2d52572d7631      frame(protocol_id "SEAL-RW-v1")
   0006 636f6d6d6974              frame(label "commit")
   0022 0020 aa..aa (32 octets)   frame(encode(...ikm)): one inner
                                  frame wrapping the single element
   0009 0003 010203 0002 0405     frame(encode(...info)): inner
                                  frames of 3 and 2 octets
   0002 0040                      frame(uint16(L)), L = 64

   XOF(M, 64) = the KDF.33 output

   With info = [], the empty sequence, the fourth frame is the two
   octets 0000: encode() of no elements is the empty octet string, and
   its frame is a zero length with no content.  With info = [""], one
   zero-length element, the inner encode is 0000 and the fourth frame is
   0002 0000.  KDF.8 and KDF.28 (Appendix E.3) exercise the same
   distinction in the two-step form.

4.4.  SEAL Encodings and Labels

   SEAL fixes the concrete encodings the combiner and the AEAD consume:
   the payload_info tuple, the segment AAD, and the derivation labels.

4.4.1.  Payload Info Construction

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

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

   Element encodings for SEAL:

   *  aead_id: 2 octets, uint16(id), the unsigned 16-bit AEAD identifier
      from Table 9 (for example, 0x0002 for AES-256-GCM).

   *  segment_max_be: 4 octets, uint32(segment_max).  SEAL's segment
      sizes are given in Section 4.10.

   *  kdf_id: 2 octets, uint16(id), the unsigned 16-bit KDF identifier
      from Table 10 (0x0001 for HKDF-SHA-256 per [RFC9180] Section 7.2;
      0x0013 for TurboSHAKE-256 per [I-D.ietf-hpke-pq]).

   *  snap_id: 2 octets, uint16(id), the snapshot authenticator
      identifier from Table 11 (0x0000 for none, 0x0001 for the masked
      multiset hash).

   *  nonce_mode: 1 octet, the nonce construction (Table 12): 0x00 for
      random, 0x01 for derived.  Table 9 gives the default mode each
      SEAL suite uses in the mutable profile.  A profile MAY select
      another valid (nonce_mode, snap_id) tuple.

   *  epoch_length_u8: 1 octet, uint8(epoch_length).  Valid values per
      Table 9.  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.  It is bound
   transitively via protocol_id.  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).

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

   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: index and is_final are bound in the nonce
     if A_i is empty:
       return ""              ;; no AEAD associated-data pass
     return encode(aad_label, A_i)

    +=============+======================+============================+
    |             | 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

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

   (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 example test
   vectors use an empty A_i, so the random-mode vectors keep the three-
   element encoding and the derived-mode vector has an empty
   segment_aad.

   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.

   Unauthorized truncation is detectable, and Section 4.9.1.2 requires a
   decryptor to reject it.  A reader that sees the highest-indexed
   present segment carry is_final = 0 knows more data must follow.
   Authorized truncation by the CEK holder instead re-marks the new
   final segment and updates the snapshot (Section 4.9.2.2).  Extension
   is also caught: appending after a segment marked is_final = 1 either
   invalidates the original final segment on re-read or produces a
   ciphertext that cannot verify.

   Each segment binds both its index and its finality bit, through the
   AAD in random nonce mode and through the nonce in derived nonce mode.
   This per-segment binding, rather than reliance on the snapshot alone,
   catches these attacks.  A reader can check them without holding all
   tags before decrypting any one segment.

   The per-segment AEAD binds a segment's index and finality, not its
   length (through the AAD in random nonce mode and through the nonce in
   derived nonce mode).  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    | "acc_key"     |
    +----------------------------+-------------------+---------------+

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

    | 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 label strings
   are frozen for wire compatibility.  In particular the snapshot
   authenticator key snap_key uses the label string "acc_key", retained
   from an earlier name.  These are the always-present key-schedule
   labels.  The masked multiset hash (Section 4.7.4), the plaintext-
   bound nonce construction (Appendix A), and hedged randomness
   (Appendix B) each define their own labels.

4.5.  Key Schedule and Nonce Generation

   A message's entire key hierarchy grows from two random values: the
   32-octet CEK and the per-content salt.  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.  The
   commitment allows early rejection of a wrong key and additionally
   binds the global associated data G (Section 4.2.4).  The payload key
   encrypts segments through epoch keys.  The snapshot authenticator key
   is used by the configured snapshot authenticator.  The nonce base
   (derived-mode only) seeds deterministic per-segment nonces.

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

   payload_info = [aead_id,
                   uint32(segment_max),    ;; segment_max_be
                   kdf_id,
                   snap_id,
                   nonce_mode,
                   uint8(epoch_length),    ;; epoch_length_u8
                   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

   AES-128-GCM, AES-256-GCM, and ChaCha20-Poly1305 use a 96-bit nonce.
   At a 2^(-32) collision-probability target, the random-nonce budget is
   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:

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

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

   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 is write-once
   (Section 4.10.2).  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 7 January 2027                [Page 29]
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 in a write-  |
     | requirement   |                   | once profile              |
     +---------------+-------------------+---------------------------+
     | 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.9.

   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 7 January 2027                [Page 30]
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))

   No per-segment nonce storage is required.

   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.9.4 for the resulting size limit.

   A derived nonce is fixed by the segment index, so re-encrypting a
   segment reuses its nonce.  An MRAE AEAD such as AES-256-GCM-SIV
   ([RFC8452]) tolerates that reuse, degrading to equality leakage
   rather than plaintext recovery, within the per-segment rewrite limit
   given in Section 5.9.  A non-MRAE AEAD does not: reusing its nonce
   leaks plaintext, so with a non-MRAE AEAD, derived nonce mode MUST be
   confined to a write-once profile, in which each segment is encrypted
   exactly once.

   A write-once profile rewrites nothing and performs no length change.
   A rewrite would repeat a derived nonce, and a length change re-marks
   the terminal segment under a fresh nonce (is_final flips the low
   bit).  The write-once discipline is the simplest rule that keeps
   every derived nonce unique.  It MUST draw a fresh salt for every
   object, so the nonce base differs, and MUST NOT re-encrypt under that
   salt after a crash (Section 6.2).

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

   Folding is_final into the nonce also removes a per-segment cost.  The
   nonce binds the index and finality, so the per-segment associated
   data need not carry them: segment_aad is empty when the caller
   supplies no A_i, and is encode(aad_label, A_i) otherwise
   (Section 4.4.2).  When A_i is empty the AEAD processes no associated
   data, removing the per-segment associated-data pass that random nonce
   mode incurs.  This is the structural reason 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

   Per-segment AEAD authenticates the ciphertext core together with the
   segment index and finality bit (through the segment AAD in random
   nonce mode and through the nonce in derived nonce mode) so position
   binding for the segment being opened is already provided.  Two
   further properties remain: context commitment, provided here, and
   snapshot membership, provided by the snapshot authenticator
   (Section 4.7).  The commitment lets a reader reject an incorrect CEK
   or parameter context before attempting any segment decryption,
   providing ra-CMT-style context commitment (Section 5.2.2) for the
   construction.

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

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

   G is the global associated data input of StartEnc in the raAE
   primitive (Section 3.2), binding whole-message application context
   such as a name, version, or policy.  The key schedule commits G by
   appending it as one length-prefixed element after payload_info in the
   commitment info input (Section 4.5), so the commitment covers G just
   as the primitive's ciphertext header T_g does ([FLRR25]).

   G is bound through the commitment, which is fixed when the content is
   created, so G is immutable: changing it invalidates the stored
   commitment.  Segment contents remain rewritable through the snapshot
   authenticator (Section 4.7).

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

   G defaults to the empty octet string, so a message whose application
   supplies no context commits over an empty final element.  G is never
   stored.  A decryptor supplies it from application context, and 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 set of segment tags into
   the public snapshot value.  A SEAL profile selects one with snap_id
   (Table 11).

4.7.1.  Interface and Requirements

   A snapshot authenticator provides the following operations:

   add(i, tag):  Fold one segment's tag into the running value.

   remove(i, tag):  Take one segment's tag back out.  An updatable
      authenticator provides this operation, so a single segment can be
      rewritten or dropped without rebuilding.  An add-only
      authenticator omits it and rebuilds the value by re-adding the
      surviving segments.

   set_length(n):  Set the segment count to n.

   snapshot():  Bind the current state into the snapshot value, which
      authenticates the (index, tag) set and the count n_seg.

   verify(snapshot):  Recompute the snapshot value over the current
      (index, tag) set and accept only if it matches the stored
      snapshot, in constant time.

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

   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.  Finality is not checked here: 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.

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

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

   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.  SEAL's masked
   multiset hash realizes verify in Section 4.7.4.

   SnapVerify above checks the whole-object target.  An authenticator
   MAY also support a single-segment target that verifies one (index,
   tag) against the recorded set.  The masked multiset hash reads all
   tags and supports the whole-object target only.  The snapshot value
   stays a single target-independent value of length Na, with no per-
   segment proof stored.

   A conforming authenticator's snapshot() MUST bind both the (index,
   tag) 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.
   How the value is computed, and whether a single-segment change
   updates it in place or rebuilds it, is the authenticator's choice.
   The masked multiset hash (Section 4.7.4) updates in place in O(1).

   The snapshot value length is written Na and MAY depend on n_seg, with
   Na = 0 meaning no value.  A fixed-length authenticator suits any
   layout, while a count-dependent one is supported only by the split
   layout of a mutable object (Section 4.11).

   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 tag.  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
   tag changes:

   1.  Under the current count, remove each changed segment's current
       tag (remove(i, tag)).  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 tag (add(i, tag)).  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 7 January 2027                [Page 34]
Internet-Draft                    raAE                         July 2026

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

   +===========+===========+=============+==============+==============+
   | Operation | Count     | Tags        | Tags added   | Terminal re- |
   |           |           | removed     |              | 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

   Each operation re-encrypts only the segments whose tag changes, so a
   caller that cannot recover a re-encrypted segment's plaintext cannot
   perform it.

   This sequence uses remove, so it is the updatable-authenticator path.
   An add-only authenticator instead resets and re-adds the surviving
   segments to rebuild the snapshot value.

4.7.2.  Selecting an Authenticator

   A SEAL profile selects its snapshot authenticator with snap_id
   (Table 11): 0x0000 for none, or 0x0001 for the masked multiset hash.

4.7.3.  None

   With snap_id = 0x0000 there is 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).

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

4.7.4.  Masked Multiset Hash

   With snap_id = 0x0001 the snapshot authenticator builds an updatable,
   masked multiset hash over the segment tags.  It accumulates one
   indexed, keyed contribution per segment, in the MSet-XOR-Hash form of
   Clarke et al.  ([MSetHash]), then publishes that accumulator behind a
   deterministic mask this document adds.  Its per-segment contribution
   is:

   contrib(i) = KDF(protocol_id, contrib_label,
                    [snap_key],
                    [uint64(i), tag(i)], Nh)

   The masked multiset hash fixes three labels: contrib_label =
   "acc_contrib", snapshot_tag_label = "snapshot_tag", and
   snapshot_mask_label = "snapshot_mask", each distinct from all other
   SEAL labels.

   The finality bit is bound through tag(i): it is an AEAD input in both
   nonce modes (segment_aad in random mode, the low nonce bit in derived
   mode, Section 4.5.3.2), so flipping it changes tag(i), hence
   contrib(i), hence the accumulator.  No explicit binding in contrib is
   needed.

   The masked multiset hash aggregates the per-segment contributions
   into the accumulator acc by bitwise XOR:

   acc = contrib(0) XOR contrib(1) XOR ... XOR contrib(n_seg-1)

   The accumulator is an Nh-octet value, with the all-zero string as the
   value for the empty segment set.  XOR is order-independent, so the
   accumulator does not depend on segment order, and it is its own
   inverse, so rewriting segment i removes its old contribution and adds
   the new one by XOR, in O(1) time and without re-reading any other
   segment.

   An object with n_seg = 0 is a valid empty object.  It holds the salt,
   the commitment, and the snapshot value, with no ciphertext segments
   and no per-segment tags.  Its accumulator is the XOR over the empty
   segment set, namely 0^Nh, and the same masking as any other count
   applies, so the empty snapshot is not a fixed constant but a masked
   authenticator over zero segments:

   acc          = 0^Nh
   snapshot_tag = snaptag(0, 0^Nh)
   mask         = snapmask(0, snapshot_tag)
   snapshot     = snapval(0, 0^Nh) = mask || snapshot_tag

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

   An empty object is distinct from a zero-length plaintext, which is
   one final segment (n_seg = 1) whose plaintext has length 0.

   To rewrite segment i without re-reading the other tags, the writer
   first recovers the accumulator from the stored snapshot by removing
   the mask, acc = wrapped_acc XOR snapmask(n_seg, snapshot_tag).  It
   then XORs contrib(i) computed from the old tag (stored alongside the
   ciphertext) out of acc, XORs in contrib(i) computed from the new tag,
   and produces the new snapshot value over the unchanged count.  The
   wrapped_acc and snapshot_tag MUST come from locally trusted snapshot
   state (Section 4.9.2.1).

   The accumulator is linear, and publishing it in the clear would let a
   write adversary recombine the differences between successive values
   into a non-historical segment set (Appendix C.5).  The masked
   multiset hash therefore does two things.  First it authenticates the
   count and accumulator with the snapshot tag, a message authentication
   code (MAC) under snap_key with its own label:

   snaptag(n_seg, acc) = KDF(protocol_id, snapshot_tag_label,
                             [snap_key],
                             [uint64(n_seg), acc], Nh)

   Write snapshot_tag = snaptag(n_seg, acc) for the present count and
   accumulator.  Second, the masked multiset hash derives a mask from
   snap_key under the third label, seeded by that synthetic tag rather
   than by a fresh nonce, and XORs it into the accumulator to form the
   masked accumulator wrapped_acc:

   snapmask(n_seg, snapshot_tag) =
       KDF(protocol_id, snapshot_mask_label,
           [snap_key],
           [uint64(n_seg), snapshot_tag], Nh)

   mask        = snapmask(n_seg, snapshot_tag)
   wrapped_acc = acc XOR mask
   snapshot    = wrapped_acc || snapshot_tag

   Seeding the mask with the synthetic tag rather than a fresh nonce is
   the synthetic-IV derandomization of deterministic authenticated
   encryption ([DAE]): the snapshot stays a deterministic function of
   (n_seg, acc) while the published accumulator is hidden behind a one-
   time pad (Appendix C.5).  The count n_seg is not stored in the
   snapshot value.  The verifier supplies it as the number of segments
   present, and snaptag binds it under the MAC.

   The masked multiset hash stores wrapped_acc and snapshot_tag, each Nh
   octets, so Na = 2*Nh.  Section 4.7.1 defines Na in general.

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

   As a function of the count and accumulator, the snapshot value is

   snapval(n_seg, acc) = wrapped_acc || snapshot_tag

   The snapshot tag binds n_seg and the accumulator under snap_key, and
   the mask hides the accumulator behind a tag-derived one-time pad.
   The forgery bound and the masking argument are in Section 5.8 and
   Appendix C.5.

   SnapVerify runs only after the verifier has re-derived and checked
   the commitment as part of decryption (Section 4.9.1.2).  The
   snapshot's per-object binding rests on snap_key (Appendix C.5).

   The masked multiset hash realizes verify(snapshot) for the SnapVerify
   of Section 4.7.1.  SnapVerify supplies the count n_seg and the
   present segment tags:

  verify(snapshot):
    ;; Caller (SnapVerify, {{snapshot-interface}}) MUST already have
    ;; checked that the present indices are exactly 0..n_seg-1, each
    ;; once.  This accumulator is order-independent under XOR, so a
    ;; duplicate or missing index is invisible here and MUST NOT be
    ;; skipped by the caller.
    acc_calc      = XOR over i of contrib(i)   ;; present segment tags
    tag_calc      = snaptag(n_seg, acc_calc)
    snapshot_calc = (acc_calc XOR snapmask(n_seg, tag_calc)) || tag_calc
    compare snapshot_calc to snapshot in constant time
            (on any mismatch, reject)
    return accept

   The comparison runs in constant time (Section 6.9).  Because the
   accumulator is order-independent under XOR, a duplicate or missing
   index can leave acc_calc recomputing to the genuine accumulator and
   the comparison passing, which is why SnapVerify's index-set check
   (Section 4.7.1) is mandatory.

   verify returns only accept or reject.  An implementation MUST NOT
   surface the recomputed accumulator or any value derived from it, and
   MUST NOT signal through an error code or timing whether the snapshot
   tag matched while the masked accumulator did not.  The mask hides the
   accumulator only against a one-bit verifier: exposing it, or
   distinguishing a tag-valid accumulator-mismatch from a plain reject,
   reinstates the recombination attack of Appendix C.5.

   A modified tag or count changes the recomputed snapshot, and a
   different key or parameter context fails the commitment check that
   precedes SnapVerify (Section 4.9.1.2).  The forgery bound is in
   Section 5.8 and the rollback limitation in Section 6.6.

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

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.2.2) and the rewrite procedure
   (Section 4.9.2.1) compose them.

   Each subroutine is the cryptographic core of one operation of the
   base or extended raAE interface (Section 3.2, Section 3.3), refining
   the operation-level mapping of Table 1 to the signature level.  The
   primitive's position identifier p = (i, b) appears here as the
   explicit arguments i and is_final.  Its immutable state S is realized
   by the payload schedule: the segment_key(i), nonce(i), and
   segment_aad calls below read the schedule from context rather than
   taking S as an argument.  Its message segment M_i is the plaintext
   P_i, and its opaque ciphertext segment C_i is stored as the field
   triple (nonce_metadata(i), ct_i, tag_i).

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

      Table 7: Segment subroutines and the primitive operations they
                                 realize

   These subroutines emit ct_i and tag_i as separate fields, and ct_i
   has length len(P_i), which can be shorter than segment_max.  The
   consuming format conveys each segment's ciphertext length to the
   decoder so DecryptSegment can recover the two fields, as required by
   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

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

   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

   EncryptSegment(i, is_final, A_i, P_i):
     key   = segment_key(i)
     nonce = nonce(i)                        ;; per nonce_mode
     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 the AEADs in Table 9 the tag is the final
   Nt octets of C_i, so ct_i is the first len(P_i) octets and C_i =
   ct_i || tag_i.  EncryptSegment splits C_i at that boundary, and
   DecryptSegment reassembles it.

   The caller folds tag_i into the snapshot authenticator with add(i,
   tag_i) (Section 4.7).  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, nonce_metadata_i, ct_i, tag_i):
     key   = segment_key(i)
     nonce = nonce_metadata_i or nonce(i)    ;; per nonce_mode (above)
     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.

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

   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
   (new_nonce_metadata_i, new_ct_i, new_tag_i) replaces the stored nonce
   metadata, ciphertext, and tag for segment i.

   RewriteSegment produces the replacement ciphertext and tag only.  The
   caller updates the snapshot authenticator by reading the stored old
   tag and calling remove(i, old_tag_i) then add(i, new_tag_i)
   (Section 4.9.2.1).

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 (add(i, tag), remove(i, tag),
   set_length(n), snapshot(), and verify()) without referring to how any
   is computed.  The authenticator selected by snap_id (Table 11)
   realizes those operations.  For the masked multiset hash they reduce
   to the accumulator, snapshot-tag, and mask formulas of Section 4.7.4.

   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 (snap_id = 0x0000, Table 11), 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 phase derives the per-
   message schedule and writes the commitment.  The second encrypts each
   segment independently and, under a snapshot authenticator, adds its
   tag with add(i, tag).  Then snapshot() binds the whole set into the
   stored snapshot value.  Because the segments are independent, the
   second phase may run in any order or in parallel.

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

      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

               Figure 4: Key Schedule and Segment Encryption

   The per-segment tags then feed the snapshot authenticator, which adds
   each one and binds them into the snapshot value (Section 4.7).

   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
       nonce_metadata_i, ct_i, tag_i
           = EncryptSegment(i, is_final, empty, P_i)
       store nonce_metadata_i, ct_i, tag_i
       if snapshot authentication is enabled (snap_id != 0x0000):
           add(i, tag_i)

   if snapshot authentication is enabled (snap_id != 0x0000):
       set_length(n_seg)
       snapshot = snapshot()
       store snapshot

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

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

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 (snap_id
   != 0x0000), whole-set authenticity is a separate and stronger check
   that requires every tag.  It detects any added, dropped, reordered,
   or re-marked segment, and same-index rollback to an older sibling.  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 (snap_id =
   0x0000) 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, nonce_metadata_i, ct_i, tag_i)
        (return its error on failure)
 if snapshot authentication is enabled and all tags are available:
     if SnapVerify(snapshot) fails:  return error  (do not deliver P_i)
 return P_i

   Here SnapVerify is the three-argument SnapVerify(S, segments,
   snapshot) of Section 3.3, with S the derived schedule and segments
   the present (index, tag) pairs.

   SnapVerify needs every tag, so a reader that streams segments in
   order cannot gate their release on snapshot integrity without first
   buffering all tags or using a layout that carries the tags in a
   header.  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
   segment does not carry is_final = 1.  A run of segments 0 through k-1
   whose last segment (index k-1) carries is_final = 0 is incomplete,
   and the decryptor MUST fail rather than return the partial plaintext.

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

   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 is unforgeable without the CEK: in derived
   nonce mode it occupies the low bit of the segment nonce
   (Section 4.5.3), and in random nonce mode it is bound through
   segment_aad (Section 4.4.2).  An adversary therefore cannot re-mark a
   non-final segment as final and can only drop trailing segments, which
   this check detects.

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

   Truncation to an empty object is covered too.  A profile with no
   snapshot authenticator forbids the zero-segment object, so a valid
   object always has at least one segment, and a decryptor MUST reject
   one that has none.  Under a snapshot authenticator the snapshot binds
   the count, so the empty object (n_seg = 0) is 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.  Under a snapshot authenticator, when all segment tags are
   available (for example, a full read or an integrity audit), the
   reader MUST run SnapVerify (Section 4.7) on the stored snapshot
   before delivering any plaintext, and MUST return an error if
   SnapVerify fails.  With no snapshot authenticator there is no such
   check, and per-segment authentication stands alone.

   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

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

   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 and length change are available only in a mutable profile,
   which configures a snapshot authenticator (snap_id = 0x0001).  Each
   re-encrypts only the segments whose tag changes and updates the
   snapshot over the new segment set.  A caller that cannot recover a
   re-encrypted segment's plaintext cannot perform them.

4.9.2.1.  Rewriting Segment i

   A rewrite touches exactly one segment and never reads another.
   Replacing a segment removes its old tag from the snapshot
   authenticator and adds the new one, then updates the snapshot over
   the unchanged count with snapshot().  The update trusts, rather than
   re-verifies, the stored snapshot state.  The old tag is already
   stored alongside the old ciphertext, so no other segment is read or
   decrypted (Section 4.7).  This single-segment update and the trust in
   stored snapshot state are properties of an updatable authenticator
   like the masked multiset hash, which folds the change in O(1).  An
   add-only authenticator re-reads the surviving tags to rebuild on
   rewrite.

   The procedure is:

   read   old_tag_i
   new_nonce_metadata_i, new_ct_i, new_tag_i
          = RewriteSegment(i, is_final, empty, new_P_i)
   remove(i, old_tag_i)                    (count n_seg unchanged)
   add(i, new_tag_i)
   snapshot      = snapshot()
   store  new_nonce_metadata_i, new_ct_i, new_tag_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 (AES-256-GCM-SIV).  MRAE
   AEADs are designed to tolerate nonce reuse, degrading to equality
   leakage rather than plaintext recovery, within the per-segment
   rewrite limit in Section 5.9.5.  The snapshot update proceeds
   identically.

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

   The stored snapshot cannot be validated during an in-place rewrite.
   Validation is SnapVerify (Section 4.7), which recomputes the
   authenticator from every segment's tag and so requires reading all
   tags.  During a rewrite the application trusts the stored snapshot
   state, applies remove and add for the one changed segment, and
   produces the new value with snapshot().  Because it trusts that
   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 that an application performs
   when it has access to all tags (for example, on a full read or an
   integrity audit).

4.9.2.2.  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 (Figure 5).  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.

 Both directions share one shape (no terminal re-mark for the
 empty object):

   1. re-mark the single terminal segment   remove + add (new count)
   2. update the boundary segments by tag    remove or add  (each)
   3. update the snapshot                    snapshot()

   append   (n_seg' = n_seg + k):
      terminal = old final n_seg-1  (is_final 1 -> 0); none if n_seg = 0
      add IN   the new segments       n_seg..n_seg+k-1
   truncate (n_seg' = m):
      terminal = new final m-1      (is_final 0 -> 1); none if m = 0
      remove   the discarded segments m..n_seg-1

                     Figure 5: Append and Truncate

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

 re-mark the terminal segment t:
    append:    t = n_seg - 1    is_final: 1 -> 0
    truncate:  t = m - 1        is_final: 0 -> 1

 if a terminal segment t exists (n_seg >= 1 for append, m >= 1 for
 truncate):
    read   salt, payload schedule, snapshot value, segment t
           (truncate also reads old_tag_j for discarded j in m..n_seg-1)
    P_t    = plaintext of segment t       (decrypt, or use if held)
    meta, ct, new_tag_t
           = RewriteSegment(t, is_final_t, empty, P_t)
    under the old count:  remove(t, old_tag_t)
 else:
    (append from empty: no old terminal; the appended loop below
     marks the last new segment is_final = 1.  truncate to m = 0:
     no segment remains, so nothing is re-marked.)
 truncate:  for j in m .. n_seg-1:  remove(j, old_tag_j)

 n_seg' = n_seg+k (append) or m (truncate)
 set_length(n_seg')

 if a terminal segment t exists:  add(t, new_tag_t)
 append:    for j in n_seg .. n_seg+k-1:
               meta_j, ct_j, tag_j
                   = EncryptSegment(j, is_final_j, empty, P_j)
               add(j, tag_j)
            (is_final_j = 1 only for the last segment)

 snapshot      = snapshot()
 store  segment t and snapshot; append adds the new segments,
        truncate drops segments m..n_seg-1

   Changing message length re-encrypts the terminal segment, except when
   truncating to the empty object (m = 0), where no segment remains.  A
   caller that cannot recover that segment's plaintext cannot do it.

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

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

   Both operations count against the same per-CEK AEAD usage budget as
   initial encryption (Section 5.9).  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 can make the same (index, finality bit)
   pair recur, and only an MRAE AEAD tolerates the resulting nonce reuse
   (Section 4.5).

   Applications that do not need length changes MAY simply 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.

   Test vectors for the SEAL profile are provided in Appendix E, and the
   serialization layouts are in Section 4.11.

4.10.  SEAL Suites

   This section lists example algorithm suites for the SEAL
   construction.  SEAL's concrete framing and procedures are defined in
   Section 4.

4.10.1.  Algorithms

   SEAL defines the following AEAD algorithms.  Each has a code point, a
   key size, a nonce size, a default nonce mode, and an epoch_length
   range.  The key size Nk is 16 octets for AES-128-GCM and 32 octets
   for the other suites.  All use a 16-octet authentication tag (Nt =
   16).

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

    +===================+=========+====+====+=========+==============+
    | Algorithm         | aead_id | Nk | Nn | default | epoch_length |
    |                   |         |    |    | mode    |              |
    +===================+=========+====+====+=========+==============+
    | AES-128-GCM       | 0x0001  | 16 | 12 | random  | 0 to 63      |
    |                   |         |    |    |         | (default 0)  |
    +-------------------+---------+----+----+---------+--------------+
    | AES-256-GCM       | 0x0002  | 32 | 12 | random  | 0 to 63      |
    |                   |         |    |    |         | (default 0)  |
    +-------------------+---------+----+----+---------+--------------+
    | ChaCha20-Poly1305 | 0x001D  | 32 | 12 | random  | 0 to 63      |
    |                   |         |    |    |         | (default 0)  |
    +-------------------+---------+----+----+---------+--------------+
    | AES-256-GCM-SIV   | 0x001F  | 32 | 12 | derived | 0 to 63      |
    |                   |         |    |    |         | (default 0)  |
    +-------------------+---------+----+----+---------+--------------+
    | AEGIS-256         | 0x0021  | 32 | 32 | random  | 63           |
    +-------------------+---------+----+----+---------+--------------+
    | AEGIS-256X2       | 0x0024  | 32 | 32 | random  | 63           |
    +-------------------+---------+----+----+---------+--------------+

                      Table 9: SEAL AEAD algorithms

   The aead_id values are the unsigned 16-bit code points from the IANA
   AEAD Algorithms Registry ([RFC5116]), encoded as uint16(id).  The
   registry's textual identifiers are, in table order, AEAD_AES_128_GCM,
   AEAD_AES_256_GCM, AEAD_CHACHA20_POLY1305, AEAD_AES_256_GCM_SIV,
   AEAD_AEGIS256, and AEAD_AEGIS256X2.  AES-128-GCM and AES-256-GCM are
   specified in [NIST-SP-800-38D], ChaCha20-Poly1305 in [RFC8439], AES-
   256-GCM-SIV in [RFC8452], and AEGIS-256 and AEGIS-256X2 in
   [I-D.irtf-cfrg-aegis-aead].  The AEGIS code points 0x0021 and 0x0024
   are early allocations that firm up when that I-D is published as an
   RFC.

   The 96-bit-nonce AEADs (AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305)
   and the MRAE AES-256-GCM-SIV (in derived nonce mode) rotate the
   segment key and may set epoch_length anywhere in 0 to 63.  The 256-
   bit-nonce AEADs (AEGIS-256, AEGIS-256X2) use a flat key (epoch_length
   = 63, one epoch key covering every segment).  Section 5.9.6 gives the
   per-suite budgets that fix these ranges.

   The default nonce_mode column gives each AEAD's mode in the mutable
   profile, SEAL-RW-v1.  The immutable profile, SEAL-RO-v1, instead
   pairs a derived nonce with any of these AEADs, because its write-once
   rule keeps every derived nonce unique and needs no MRAE AEAD
   (Section 4.10.2).

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

   SEAL permits the KDF cipher suites in Table 10, identified by entries
   from the HPKE KDF Registry ([RFC9180] Section 7.2 and
   [I-D.ietf-hpke-pq]):

     +========+================+===============================+====+
     | kdf_id | Name           | Construction                  | Nh |
     +========+================+===============================+====+
     | 0x0001 | HKDF-SHA-256   | Two-step HKDF-Extract+Expand  | 32 |
     +--------+----------------+-------------------------------+----+
     | 0x0002 | HKDF-SHA-384   | Two-step HKDF-Extract+Expand  | 48 |
     +--------+----------------+-------------------------------+----+
     | 0x0003 | HKDF-SHA-512   | Two-step HKDF-Extract+Expand  | 64 |
     +--------+----------------+-------------------------------+----+
     | 0x0013 | TurboSHAKE-256 | One-step XOF (absorb+squeeze) | 64 |
     +--------+----------------+-------------------------------+----+

                Table 10: Permitted SEAL KDF Cipher Suites

   HKDF-SHA-256 is specified in [RFC5869].  TurboSHAKE-256 is the
   extendable-output mode of the SHA-3 family selected by
   [I-D.ietf-hpke-pq].  The kdf_id values are the unsigned 16-bit code
   points from the HPKE KDF Registry, encoded as uint16(id).  Nh and
   commitment_length equal the KDF's primitive output size, 32 octets
   for HKDF-SHA-256, 48 for HKDF-SHA-384, and 64 for HKDF-SHA-512 and
   TurboSHAKE-256.  HKDF-SHA-256 is the baseline KDF.  The others are
   optional alternatives.

   The two-step Extract and Expand are HKDF-Extract and HKDF-Expand.
   The one-step XOF uses TurboSHAKE256 with D = 0x1F, the Derive
   convention's domain-separator byte, which an implementation MUST NOT
   change.

   The snapshot authenticator is selected by snap_id:

      +=========+======================+===========================+
      | snap_id | Name                 | Snapshot value            |
      +=========+======================+===========================+
      | 0x0000  | none                 | none produced             |
      +---------+----------------------+---------------------------+
      | 0x0001  | masked multiset hash | snapshot, per Section 4.7 |
      +---------+----------------------+---------------------------+

                  Table 11: SEAL Snapshot Authenticators

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

   snap_id = 0x0000 selects no snapshot authenticator: no snapshot value
   is produced and a reader relies on per-segment authentication alone.
   An immutable (write-once) profile enforces snap_id = 0x0000.  A
   profile that supports rewrite requires snap_id = 0x0001, so every
   rewritable object carries whole-object integrity (Section 4.9.2).

   The nonce mode is carried explicitly by nonce_mode:

                         +============+=========+
                         | nonce_mode | Name    |
                         +============+=========+
                         | 0x00       | random  |
                         +------------+---------+
                         | 0x01       | derived |
                         +------------+---------+

                        Table 12: SEAL Nonce Modes

   The two constructions are defined in Section 4.5.3.

   The supported maximum segment sizes are 16384 and 65536 octets.  Both
   values are powers of two and at least 4096 octets.  The 16384-octet
   size aligns to 16 KiB memory pages (for example, on Apple Silicon).
   The 65536-octet size aligns to 64 KiB (four 16 KiB pages).

   The aad_label is "SEAL-DATA".  Under snap_id = 0x0001 the snapshot
   authenticator is the masked multiset hash (Section 4.7), with
   wrapped_acc and the snapshot tag each an Nh-octet value, so Na =
   2*Nh.

4.10.2.  Composing a SEAL Suite

   A SEAL suite fixes an AEAD and a KDF (Table 9, Table 10), a maximum
   segment size, a snapshot authenticator (snap_id, Table 11), a nonce
   mode (nonce_mode, Table 12), and an epoch length.  The protocol_id
   identifies the parameters a profile fixes, and only certain
   (nonce_mode, snap_id) tuples are valid under each one.  This document
   defines two named profiles, SEAL-RW-v1 and SEAL-RO-v1.

   A profile's payload_info MUST carry the full parameter context
   affecting key derivation, AEAD operations, AAD construction, and
   nonce construction, so that the commitment (Section 4.6) binds that
   context.

   SEAL-RW-v1 is the mutable profile (read-write).  It requires snap_id
   0x0001 (the masked multiset hash), so every rewritable object carries
   whole-object integrity, and permits a random nonce or a derived nonce
   with an MRAE AEAD.  It supports rewrite, extend, and truncate, and

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

   carries SEAL's snapshot machinery: the accumulator, its mask, the
   snapshot value, and SnapVerify.  Unauthorized truncation surfaces at
   two points: the terminal finality check of Section 4.9.1.2, and
   SnapVerify over the complete segment set, which also binds the
   segment count.

   SEAL-RO-v1 is the immutable profile (read-only).  Here "immutable"
   names the writer's write-once discipline, not a tamper-evidence
   guarantee.  It selects a derived nonce and sets snap_id to 0x0000, so
   that no snapshot authenticator runs, and it is write-once: an
   encryptor MUST NOT rewrite a segment once it has been written.  The
   rule is load-bearing: a rewrite would repeat the segment's derived
   nonce, with the consequences given in Section 6.2.  Because each
   derived nonce is then used only once, the profile works with any
   AEAD, including a non-MRAE one.  See Section 4.5.3.

   SEAL-RO-v1 provides per-segment confidentiality and integrity,
   binding the segment index and the finality bit, and key commitment
   through the commitment field, but not snapshot or whole-object
   integrity.  Whole-object integrity, when needed, comes from the
   snapshot in the mutable profile or a layer above SEAL.  Truncation
   detection rests on the finality bit alone and surfaces only when the
   highest-indexed present segment verifies under is_final = 1
   (Section 4.9.1.2), so a consumer of streamed plaintext has no
   completeness guarantee before that terminal check.

      +=============+===================+=========+=================+
      | protocol_id | nonce_mode        | snap_id | mutability      |
      +=============+===================+=========+=================+
      | SEAL-RW-v1  | random or derived | 0x0001  | rewrite/extend/ |
      |             |                   |         | truncate        |
      +-------------+-------------------+---------+-----------------+
      | SEAL-RO-v1  | derived           | 0x0000  | write-once      |
      +-------------+-------------------+---------+-----------------+

                          Table 13: SEAL profiles

   An encryptor MUST set payload_info to a (nonce_mode, snap_id) tuple
   that is valid for its protocol_id, and a decryptor MUST reject any
   object whose tuple is not.  A derived nonce under SEAL-RW-v1 requires
   an MRAE AEAD; SEAL-RO-v1 admits any AEAD because the write-once rule
   keeps each derived nonce unique.

4.10.2.1.  Choosing a Profile

   Pick the profile from how the stored content changes after it is
   first written.

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

   SEAL-RW-v1 (mutable) fits content updated in place: editable files,
   mutable object stores, and append-or-truncate logs.  It carries
   snap_id 0x0001, so a reader detects tampering with the current
   segment set as a whole: any added, dropped, reordered, or re-marked
   segment, a same-index rollback, or a count change (Section 5.2.3).
   Whole-object freshness beyond replay still comes from a layer above
   SEAL (Section 6.6).  A derived nonce under this profile requires an
   MRAE AEAD, while a random nonce works with any of the suites.

   SEAL-RO-v1 (immutable) fits write-once content: archives, backups,
   content-addressed blobs, and write-once media.  It stores no per-
   segment nonce and works with any AEAD, so it is the smaller and
   simpler choice when content is never rewritten.  Whole-object
   integrity, if needed, comes from a layer above SEAL.

   Section 5.9.6 covers epoch_length selection, and Section 4.10.1
   covers the per-AEAD trade-offs that further narrow the suite.

4.11.  Serialization Layouts

   This section describes three serialization layouts a consuming
   protocol can use to store raAE output: linear, aligned, and split.
   The parameterized SEAL construction mandates none of them.  Each
   named instantiation binds one, and the consuming protocol pins the
   remaining details (Section 4.12).  The commitment field in every
   layout is commitment_length octets (Section 4.2.3); the figures
   annotate it with its default, commitment_length = Nh.

4.11.1.  Linear Layout

   In a linear layout the salt, commitment, snapshot value, and segment
   data appear in sequence.  The salt comes first because it is needed
   to derive all payload schedule values.  The commitment follows so a
   reader can reject a wrong key before reading any segment data.  The
   snapshot value (Na octets), the configured authenticator's output,
   precedes the segment data so a streaming reader has it before the
   segments and can check it once all are read.  Segments then follow in
   index order.

   When the object has at least one segment, that final segment carries
   is_final = 1.  An empty object (n_seg = 0) has zero segments, so no
   segment is final.

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

   +------+------------+---------------+----------+-----+----------+
   | salt | commitment | snapshot      | segment  | ... | segment  |
   | (32) | (Nh)       |     (Na)      |  0 data  |     | n_seg-1  |
   |      |            |               | [nonce]  |     | [nonce]  |
   |      |            |               | ct + tag |     | ct + tag |
   +------+------------+---------------+----------+-----+----------+

                          Figure 6: Linear Layout

   Brackets mark the nonce, which precedes the ciphertext and tag for a
   segment and is stored only in random nonce mode.  In derived nonce
   mode (AES-256-GCM-SIV) the nonce is recomputed from the key schedule,
   so no nonce is stored.

   A streaming reader recovers segment boundaries from the segment
   lengths.  Because a segment MAY be shorter than segment_max
   (Section 2), a linear layout that is to be read as a stream MUST keep
   every non-final segment at the full segment_max, leaving only the
   final segment short.  A reader then finds each boundary at the fixed
   segment length.  A layout that stores shorter interior segments MUST
   record their lengths so the reader can locate each segment.

   Linear layout supports streaming writes.  A writer emits the salt,
   commitment, and a placeholder for the snapshot value, then streams
   segments.  After all segments are written the writer seeks back to
   the snapshot position and writes the final value in place.

4.11.2.  Aligned Layout

   In an aligned layout the ciphertext segments occupy slots aligned to
   segment_max, so a reader can seek to any segment with page-aligned I/
   O.  An arbitrary-length prefix, which the consuming protocol uses for
   its own machinery and which raAE does not specify, comes first; the
   raAE header follows; the ciphertext follows the header.

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

   +--------------------------------------------+
   | prefix (consuming protocol machinery,      |
   | arbitrary length; not specified here)      |
   +--------------------------------------------+
   | header: salt, commitment, snapshot,        |
   | per-segment metadata (broken out below)    |
   +--------------------------------------------+
   | leading slot: either the first ciphertext  |
   | segment (< B), or zero padding to a        |
   | multiple of B                              |
   +============================================+
   | ciphertext segment            (= B)        |
   +--------------------------------------------+
   | ...                                        |
   +--------------------------------------------+
   | final ciphertext segment      (<= B)       |
   +--------------------------------------------+

                          Figure 7: Aligned Layout

   Offsets are measured from index 0, the start of the prefix.  Let B =
   segment_max and let H be the offset at which the ciphertext begins
   (the prefix length plus the header length).  The leading slot, from H
   up to the first segment boundary M * B, is filled in one of two ways,
   chosen before writing:

   *  No padding: the first ciphertext segment occupies the slot, with M
      = ceil(H / B).  It is shorter than B and ends on the boundary M *
      B.

   *  Padding: the slot is zero-padded to a multiple of B, with M >=
      ceil(H / B) (the next boundary, or a larger multiple to reserve
      whole segment slots for append headroom).

   From M * B onward every ciphertext segment begins at a multiple of B
   and is a full B octets, with the final segment at most B.  H, M, and
   the first-segment length all follow from the prefix and header sizes,
   so a writer computes them before emitting any ciphertext.

   The header holds the salt, the commitment, the snapshot value, and
   one metadata entry per segment:

   +------+------------+---------------+----------------------+
   | salt | commitment | snapshot      | per-segment metadata |
   | (32) |    (Nh)    |     (Na)      | (n_seg * meta_len)   |
   +------+------------+---------------+----------------------+

                      Figure 8: Aligned Layout Header

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

   Each metadata entry holds the segment's stored nonce and its AEAD
   tag:

   +------------+-----------+
   | [nonce(i)] |   tag(i)  |
   |    (Nn)    | (Nt = 16) |
   +------------+-----------+

                          Figure 9: Metadata Entry

   The bracketed nonce is present only in random nonce mode.  The tag is
   always present, Nt = 16 octets in every SEAL suite (Table 9).  Each
   metadata entry holds the Np-octet presented nonce and the Nt-octet
   tag, so meta_len = Np + Nt octets.  A random-nonce entry sets Np = Nn
   and is Nn + Nt octets.  A derived-nonce entry recomputes the nonce
   from the key schedule, so Np = 0 and the entry is Nt octets.  The
   per-suite values are:

           +===========================+============+==========+
           | AEAD                      | nonce mode | meta_len |
           +===========================+============+==========+
           | AES-128-GCM, AES-256-GCM, | random (Nn | 28       |
           | ChaCha20-Poly1305         | = 12)      |          |
           +---------------------------+------------+----------+
           | AEGIS-256, AEGIS-256X2    | random (Nn | 48       |
           |                           | = 32)      |          |
           +---------------------------+------------+----------+
           | AES-256-GCM-SIV           | derived    | 16       |
           +---------------------------+------------+----------+

                   Table 14: Metadata entry size by AEAD

   The n_seg entries total n_seg * meta_len octets, so the whole header
   is 32 + commitment_length + Na + n_seg * meta_len octets.  With the
   default commitment_length = Nh and the masked multiset hash's Na = 2
   * Nh, the header is 32 + 3 * Nh + n_seg * meta_len octets.

   A reader verifies the commitment and the snapshot value from the
   header alone, then seeks to any segment using these offsets.  Because
   the snapshot is computed from the per-segment tags alone (the
   snapshot authenticator takes the segment tag, not the ciphertext),
   and the header holds every tag in its metadata entries, a reader
   authenticates the whole object's snapshot from the header without
   reading or streaming any ciphertext.  This supports efficient random-
   access reads.

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

4.11.3.  Split Layout

   A split layout separates the ciphertext from the metadata into two
   streams that grow independently.  The data stream holds the
   ciphertext segments, each a full segment_max except the last.
   Segment i is at offset i * B.  The metadata stream holds the salt,
   the commitment, the n_seg per-segment metadata entries (each meta_len
   octets, broken out in Figure 9), and the snapshot value last.
   Because the snapshot is computed from the per-segment tags alone
   (Section 4.7.4) and every tag lives in the metadata stream, a reader
   authenticates the snapshot by reading only the metadata stream, never
   the data stream that holds the ciphertext.

   data stream:

   +--------------------+
   | seg 0 ct    (= B)  |
   +--------------------+
   | seg 1 ct    (= B)  |
   +--------------------+
   | ...                |
   +--------------------+
   | seg n_seg-1 (<= B) |
   +--------------------+

   metadata stream:

   +------+------------+------------+-----+------------+---------------+
   | salt | commitment |   meta_0   | ... | meta_last  | snapshot      |
   | (32) |    (Nh)    | (meta_len) |     | (meta_len) |     (Na)      |
   +------+------------+------------+-----+------------+---------------+

                          Figure 10: Split Layout

   Because neither stream embeds the other, both grow by appending.
   Extending a message appends one ciphertext segment to the data
   stream, appends one metadata entry to the metadata stream, and
   rewrites the trailing snapshot value.  Truncating drops the tail of
   each stream and rewrites the snapshot value.  Neither operation
   shifts an existing ciphertext segment, which the in-place aligned
   layout cannot avoid once the header grows.

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

4.11.4.  Immutable-Profile Layouts

   Under an immutable profile (SEAL-RO-v1: snap_id = 0x0000 with a
   derived nonce), two fields drop out of the layouts above.  No
   snapshot authenticator runs, so there is no snapshot value, and each
   nonce is recomputed from the key schedule, so Np = 0 and no nonce is
   stored.  A metadata entry is then the Nt-octet tag alone.  The linear
   layout reduces to the salt, the commitment, and the per-segment
   ciphertext and tags.  The aligned and split headers reduce to 32 +
   commitment_length + Nt * n_seg octets, the salt and commitment
   followed by one tag per segment.  In the aligned layout every
   ciphertext segment begins at a multiple of segment_max, so a reader
   seeks to any segment by arithmetic on its index and verifies it from
   its own tag, with no shared snapshot to read or maintain.

4.12.  SEAL Named Instantiations

   SEAL has many parameters (Section 4.2).  A relying protocol that does
   not want to choose them all can cite one of the named instantiations
   in the table below.  Each row fixes a profile, a segment size, the
   nonce mode, a snapshot authenticator, and one of the serialization
   layouts of Section 4.11, leaving the cipher suite (an aead_id and a
   kdf_id from Section 4.10) to the referencing protocol.  Each
   instantiation applies to a cipher suite the same way, so a protocol
   writes SEAL-simple(aead_id, kdf_id), SEAL-disk(aead_id, kdf_id), and
   so on, to obtain a complete raAE scheme.

    +=================+==========+===========+==========+=====+=======+
    | Name            |Profile   |segment_max|nonce_mode|epoch|layout |
    +=================+==========+===========+==========+=====+=======+
    | SEAL-attachment |SEAL-RO-v1|65536      |derived   |32   |linear |
    +-----------------+----------+-----------+----------+-----+-------+
    | SEAL-simple     |SEAL-RW-v1|65536      |random    |16   |linear |
    +-----------------+----------+-----------+----------+-----+-------+
    | SEAL-memory     |SEAL-RW-v1|16384      |random    |16   |aligned|
    +-----------------+----------+-----------+----------+-----+-------+
    | SEAL-disk       |SEAL-RW-v1|16384      |random    |16   |split  |
    +-----------------+----------+-----------+----------+-----+-------+
    | SEAL-compact    |SEAL-RW-v1|16384      |derived   |16   |aligned|
    +-----------------+----------+-----------+----------+-----+-------+

                    Table 15: SEAL named instantiations

   Each instantiation is named for its primary use case, described
   below.  The snapshot authenticator follows the profile: SEAL-RO-v1
   sets snap_id 0x0000 and SEAL-RW-v1 sets snap_id 0x0001
   (Section 4.10.2).

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

   Every instantiation uses commitment_length = Nh and a fresh 32-octet
   salt per object (Section 4.9.1.1).  The epoch_length is the value in
   the table.  The write-once SEAL-attachment performs no rewrites, so
   it takes a larger epoch (32), while the four mutable schemes take a
   conservative 16 that leaves the per-epoch-key budget headroom for
   rewrites, which reuse the epoch key (Section 5.9).  A 256-bit-nonce
   suite (AEGIS-256, AEGIS-256X2) uses a flat key (epoch_length 63)
   regardless of the row (Table 9), and a referencing protocol MAY
   override the epoch.  Each instantiation binds the layout named in its
   row (Section 4.11).  The layout fixes field order and placement, and
   the consuming protocol pins the remaining serialization details, such
   as the aligned layout's prefix and leading slot, for byte-level
   interoperability.  SEAL-compact is mutable with a derived nonce, so
   an in-place rewrite reuses that nonce, which requires an MRAE AEAD
   (Section 4.10.2).  The write-once SEAL-attachment and the random-
   nonce SEAL-simple, SEAL-memory, and SEAL-disk admit any AEAD.

   SEAL-attachment is for write-once content read whole.  It carries no
   snapshot authenticator, because under the immutable profile per-
   segment authentication and the finality bit detect truncation,
   reordering, and tampering on a whole-object read, and write-once
   leaves no earlier version to roll a segment back to (Section 6.6).
   Its linear layout takes the reduced immutable form (Section 4.11.4).

   SEAL-simple is the basic mutable object with whole-object integrity
   from the masked multiset hash (Section 4.7.4), stored in the linear
   layout (Section 4.11.1).  SEAL-memory targets in-memory random access
   with the aligned layout (Section 4.11.2).  SEAL-disk rewrites
   individual segments on stored media, with the split layout
   (Section 4.11.3) holding the headers apart from the segment data so a
   rewrite touches one segment and extension appends to both streams.

   SEAL-compact is the aligned layout with a derived nonce.  Like SEAL-
   memory it stores each segment at a fixed offset for random access,
   but the derived nonce is recomputed rather than stored, so each per-
   segment metadata entry is Nt octets instead of Nn + Nt
   (Section 4.11.2).  Because that region scales with the object,
   removing the stored nonce saves Nn octets per segment, a substantial
   part of the metadata for the large random-access objects the aligned
   layout targets.  It reuses the derived nonce on an in-place rewrite,
   so it requires an MRAE AEAD and the rewrite is deterministic.

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

5.  Security Analysis

   This section states the construction's target security properties,
   the assumptions its components must satisfy, and the operational
   limits on its use, but does not reproduce the formal proofs.  The
   division of labor is deliberate.  The ra-ROR and ra-CMT notions are
   taken unchanged from [FLRR25], whose proofs apply to SEAL's
   realization of the base interface.  Snapshot integrity is the one
   notion this document defines.  Appendix C.5 argues its bound, and
   integrating that argument into a combined proof is deferred to
   [SEALPROOFS], the companion formal write-up, in preparation, that
   this document cites for every deferred proof.  The limits of
   Section 5.9 are operational deployment bounds, not proof obligations.
   The security notions are defined in Section 5.2.

5.1.  Operational Summary

   The construction provides the following properties against an
   adversary that observes ciphertexts, tampers with stored segments or
   their order, and attempts decryption with chosen keys, but does not
   know the CEK or per-content salt:

   Confidentiality:  The construction targets ra-ROR (Section 5.2.1):
      the adversary learns nothing about the plaintext beyond what the
      underlying AEAD already permits.  The adversary observes the
      message's segment count and the per-segment lengths from the wire
      format.  Segment boundary metadata is not confidential.

   Integrity:  A reader that runs snapshot verification, including its
      index-set check over the correct segment count n_seg
      (Section 4.7.1), detects any added, dropped, reordered, or re-
      marked segment, including same-index rollback to an older valid
      segment.  Per-segment AEAD verification alone detects modification
      of individual segments and relocation of a segment to a different
      index, but reverting a segment to a previous version at the same
      index is not detected.  Snapshot verification realizes the
      snapshot integrity notion of Section 5.2.3.  Replacement of the
      entire message with a previous valid version under the same CEK is
      not detected, even when performing snapshot verification.
      Rollback resistance at the message level is the application's
      responsibility (Section 6.6).

   Context commitment:  A reader that verifies the commitment
      (Section 4.6) rejects a wrong CEK, parameter context, or global
      associated data before decrypting any segment, per the ra-CMT
      notion (Section 5.2.2).  Commitment to segment positions is out of
      scope.  See Section 5.7 for that gap and its non-normative
      mitigations.

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

   Rewrite safety:  An individual segment can be rewritten in place
      under the same CEK without re-derivation of other keys, provided
      the per-key AEAD usage budget (Section 5.9) is not exceeded.  A
      rewrite reuses the segment's derived nonce, so in derived nonce
      mode it MUST use an MRAE AEAD (Section 4.5.3.2).  Rewrite safety
      is otherwise a corollary of ra-ROR and snapshot integrity
      (Section 5.3).

   Out of scope:  Atomicity of writes (the application MUST use write-
      ahead logging or copy-on-write); confidentiality of segment count
      or layout; traffic-analysis resistance; side channels in the
      application's storage layer; protection of the CEK before
      encryption or after decryption.

5.2.  Security Notions

   raAE has two security tiers.  The base tier comprises the two notions
   inherited from [FLRR25], ra-ROR and ra-CMT, 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 and ra-CMT are in [FLRR25].

5.2.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 a rewrite reuses
   the position's derived nonce.  This is a deliberate nonce-repeating
   query.  The underlying MRAE AEAD handles it under the equality-
   leakage relaxation that derived nonce mode documents (Appendix C.6),
   not the unmodified nonce-respecting game.

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

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

5.2.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 the position-
   respecting variant ra-CMT the two contexts share a position.  The ra-
   CMT-p variant lets the adversary choose the positions freely.
   Because the scheme is random access, committing one segment's context
   commits the full ciphertext's context.  Both game variants are
   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.2.3.  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,
   snapshot integrity, is the one this document adds.  The construction
   that realizes it is in Section 4.7, its bound is in Section 5.8, and
   the supporting reduction is in Appendix C.5.  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 (snap_id != 0x0000) and omits it otherwise
   (Section 4.10.2).

5.3.  Relations to Other Notions

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

   nOAE2 ([Tink]):  nOAE2 is the nonce-based online authenticated

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

      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.2.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.2.1) and snapshot integrity (Section 5.2.3).  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.6).
   Each rewrite also counts against the per-key AEAD usage budget
   (Section 5.9).

   Appending and truncating likewise add no algorithm (Section 4.9.2.2)
   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.2.3, 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.4.  Adversary Model and Assumptions

   The adversary model is that of the ra-ROR game (Section 5.2.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.  Every bound in this section assumes
   the CEK is secret and uniform: 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.  The construction claims the properties
   below against this adversary.

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

   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 and, in
      random nonce mode, per-segment nonces.

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

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

   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.

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

   For the HKDF cipher suites (HKDF-SHA-256, HKDF-SHA-384, and HKDF-SHA-
   512), the PRF assumptions are placed on HKDF keyed by the CEK or
   payload_key, and the collision-resistance assumption on the commit
   derivation reduces to the collision resistance of the underlying
   SHA-2 variant (SHA-256, SHA-384, or SHA-512).  Because every SEAL KDF
   output is at most Nh octets, HKDF-Expand makes a single HMAC call per
   derivation.  The extractor-then-PRF analysis of HKDF is in [RFC5869].

   For TurboSHAKE-256 (the one-step XOF cipher suite defined in
   [I-D.ietf-hpke-pq]), the same PRF and collision-resistance
   assumptions are placed on the XOF as instantiated by that HPKE KDF
   registry entry, which fixes the primitive and its parameters but
   carries no security assumptions of its own.

5.5.  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).

   The per-component requirements any raAE construction must satisfy are
   as follows.

   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:  The construction MUST define the encoding of the tuple
      (protocol_id, label, ikm, info, L) into the underlying primitive
      input, and that encoding MUST be injective: distinct tuples MUST
      map to distinct primitive inputs.  This is a requirement on the
      encoding, not on the KDF.  The KDF need not itself be injective,
      because injectivity is supplied by the encoding placed in front of
      it.  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 encoding admits inputs too large to
      encode literally, it MAY substitute a fixed-length digest of the

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

      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:  A KDF output for one derivation role, such as
      payload_key, MUST be computationally independent of the output for
      any other role, such as snap_key, even when derived from the same
      CEK and payload_info.  This property follows from label uniqueness
      and PRF security of the underlying primitive.

   Snapshot authenticator:  The construction MUST bind the current set
      of segment tags and the segment count into a public snapshot value
      that an adversary without the authenticator's secret key cannot
      forge for a modified set of tags 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.

   SEAL's construction (Section 4) satisfies these requirements.  Its
   KDF (Section 4.3), any of the cipher suites in Table 10 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, the
   masked multiset hash's labels in Section 4.7.4, 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.  SEAL's masked multiset hash
   (Section 4.7) satisfies the snapshot authenticator requirement, with
   its forgery argument in Section 5.8.

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

   encode is injective.  Among fields of at most 0xFFFE octets each
   frame entry is self-delimiting, so the concatenation parses uniquely
   regardless of the number of arguments, and distinct input tuples
   produce distinct output strings.  For over-large fields the encoding
   is injective only up to the collision resistance of LH, not
   unconditionally: a literal entry carries a length prefix in the range
   0x0000 through 0xFFFE while a digest entry carries the reserved
   prefix 0xFFFF, so a literal entry and a digest entry never collide,
   and a collision between two digest entries reduces to a collision in
   LH.  A 0xFFFF entry is bind-only: it commits to the field but does
   not carry it, so a protocol that must recover a field from the
   encoding MUST keep that field at most 0xFFFE octets.  No SEAL input
   approaches 0xFFFE octets, so for SEAL frame is byte-identical to a
   plain 2-octet length prefix and LH is never invoked.

   The "raAE-LP-v1" prefix (the HKDF-Extract salt in the two-step class,
   a fixed input prefix in the one-step class) is distinct from every
   protocol_id and label, so LH inputs are domain-separated from encode
   inputs.  LH is a shared collision-resistant digest rather than a per-
   protocol separator: the same over-large field yields the same LH
   value in every protocol that reuses this combiner.  Cross-protocol
   separation comes from protocol_id in the KDF inputs and from
   aad_label in the segment AAD, not from LH.

   A concrete SEAL suite specifies the following.

   AEAD:  One of the algorithms from Section 4.10.1, with associated Nk,
      Nn, and Nt values.

   KDF:  One of the KDF cipher suites from Table 10.

   nonce_mode:  A per-object payload_info field constrained by the
      profile, not a suite-fixed lock.  Table 9 gives the default mode
      each suite uses in the mutable profile.  A profile MAY select any
      valid (nonce_mode, snap_id) tuple (Section 6.5): in the mutable
      profile an MRAE AEAD MAY use either mode, and the immutable
      profile SEAL-RO-v1 pairs a derived nonce with any AEAD because
      write-once keeps every derived nonce unique.

   epoch_length:  The key-rotation granularity, with range given by
      Table 9.  Per Section 5, a 96-bit-nonce AEAD rotates the segment
      key to bound per-key nonce-collision risk and an MRAE AEAD rotates
      to bound its per-key encryption count, so both take epoch_length
      in 0 to 63.  A 256-bit-nonce AEAD makes both negligible and uses a
      flat key.

   segment_max:  One of the sizes from Section 4.10: 16384 or 65536
      octets.

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

   Fábrega et al.  ([FLRR25]) proved ra-ROR and ra-CMT security for a
   construction that instantiates the same component contracts
   enumerated above, and SEAL's analysis of those notions follows the
   same structure.  SEAL's additional components (the epoch keys and the
   snapshot maintained across rewrite and length change) are analyzed in
   Section 5.6 and Section 5.8.

5.6.  Segment Confidentiality and Integrity

   The construction targets ra-ROR security (Section 5.2.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]).
   This section states the property and the operational quantities a
   deployment needs.

   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.

   The multi-message advantage grows linearly in the number of messages.
   In derived nonce mode the salt-collision term q_m^2/2^256 is the only
   quadratic floor for the 256-bit-key suites.  For AES-128-GCM the
   epoch-key collision floor E^2/2^128 (Appendix C.2) is an additional
   quadratic term that dominates.  In random nonce mode, with or without
   the plaintext-bound hedge, the nonce-collision term is also
   quadratic:

   nonce collision:  q^2 / 2^(8*Nn + 1)
   at Nn = 12:       q^2 / 2^97

   where 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.9.

   Segment size enters the analysis only through the forgery and block-
   size terms, both bounded in Section 5.9.  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

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

   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.7.  Commitment Security

   The ra-CMT notion is defined in Section 5.2.2.

   raAE's commitment target is ra-CMT (random-access context
   commitment), not the per-AEAD notion CMT-1 ([RFC9771]).  CMT-1 is key
   commitment defined for AEADs, but raAE is a higher-level construction
   whose commitment binds the CEK and the full payload_info, which
   together carry the full parameter context that affects encryption,
   decryption, AAD construction, nonce construction, and key derivation.

   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 with HKDF-SHA-256 and about 2^256 with
   TurboSHAKE-256.  The reduction outline for this assumption and the
   collision quantities for a general commitment_length are in
   Appendix C.4.

   The commitment bounds the ra-CMT variant in which the positions match
   (Section 5.2.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 natively
   key-committing, 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.

   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.

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

   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
   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 position commitment, on the
      order of 16 to 64 octets per segment, bound alongside the segment
      so that no segment opens at two positions.

   Several AEADs including AES-GCM ([NIST-SP-800-38D]) and
   ChaCha20-Poly1305 ([RFC8439]) lack strong native key or context
   commitment.  CMT-4 ([RFC9771]) is full commitment to key, nonce,
   associated data, and plaintext.  None of the SEAL AEADs is relied
   upon to provide CMT-1 or CMT-4.  In particular, AES-256-GCM-SIV is
   not a key-committing AEAD, and key-commitment attacks against it are
   known (for example partitioning oracles).  raAE obtains ra-CMT
   context commitment from the external commitment over (CEK,
   payload_info, G) regardless of the AEAD's own committing or non-
   committing properties, provided that the commitment check is not
   bypassed and that payload_info contains the full parameter context
   that influences any later derivation or AEAD operation.

   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.9).  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].

   The ra-CMT and ra-CMT-p notions are defined in [FLRR25].  SEAL
   realizes ra-CMT through the external commitment over (CEK,
   payload_info, G), independent of the underlying AEAD's own commitment
   level.  Position binding for ra-CMT-p is inherited from the
   underlying AEAD's commitment level, as described above.  This

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

   document states these properties and their component bounds.  The
   exact accounting of the per-segment associated data and position
   terms in the ra-CMT-p reduction is the open item deferred to the
   proof in preparation ([SEALPROOFS]).

5.8.  Snapshot Authenticator Security

   Snapshot authentication is an extension this document adds to the
   [FLRR25] raAE framework.  The raAE primitive and its ra-ROR and ra-
   CMT notions are taken unchanged from [FLRR25], whose proofs apply to
   SEAL's realization of the base interface.  The snapshot authenticator
   adds two operations (RewriteSeg, SnapVerify) over an auxiliary
   snapshot value and one new security property, snapshot integrity
   (Section 5.2.3).  Integrating its reduction into a single combined
   proof with the ra-ROR framework is in preparation and will be
   published separately ([SEALPROOFS]).

   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 added, dropped, reordered, re-
   marked, or otherwise altered segment.  It gives no protection among
   parties that share the CEK, because any CEK-holder can recompute
   snap_key, and it is not a third-party-verifiable commitment to a
   segment set.  An application that needs sender attribution or third-
   party verifiability MUST add a signing layer over the snapshot
   context.

   Per-segment AEAD binds each segment's index and finality bit.  The
   snapshot authenticator adds authentication of the full set of segment
   tags and the count n_seg as a single unit, which detects same-index
   rollback, segment-set modification, and count changes.  The index-set
   check in SnapVerify (Section 4.7.1) is mandatory: an authenticator's
   verify MAY accept a malformed index multiset, so without the check a
   duplicated or dropped index could pass.

   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.

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

5.8.1.  Masked Multiset Hash

   SEAL's masked multiset hash (snap_id 0x0001) publishes snapshot =
   wrapped_acc || snapshot_tag.  The snapshot tag is a MAC over the
   count and accumulator under snap_key, and wrapped_acc is that
   accumulator hidden behind a deterministic, tag-derived one-time pad.
   The mask is what stops a write adversary from recombining the
   differences between published accumulators into a non-historical
   segment set.  Its three labels, contrib_label, snapshot_tag_label,
   and snapshot_mask_label, are distinct under the encode frame.

   Its forgery advantage Adv_acc is bounded by a fresh-input MAC term, a
   mix-and-match term, and a birthday term in the number of published
   snapshots that the deterministic masking introduces, on no assumption
   beyond the multi-user PRF the key schedule already uses.
   Appendix C.2 states the bound and Appendix C.5 derives it.

5.9.  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 (AES-256-GCM-SIV in SEAL) 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 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.9.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 7 January 2027                [Page 72]
Internet-Draft                    raAE                         July 2026

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

   For a random-nonce AEAD an epoch key has one budget, shared by the
   segments under it.  For a derived-nonce MRAE AEAD an epoch key has
   two: how many distinct segment nonces it may cover, and how many
   times any one segment may be re-encrypted at its fixed nonce.

5.9.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 16: Usage-limit classes

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

   Random-nonce collision and the block-size birthday bound the
   confidentiality of fresh-nonce encryption, and forgery bounds
   integrity for every decryption.  Two further classes apply only in
   derived-nonce MRAE mode: a derived-key collision across the distinct
   segment nonces under an epoch key, and a data-volume limit on
   repeated encryption of a single hot segment, one rewritten many times
   at its one derived nonce.  A sixth class applies only to 128-bit-key
   AEADs: a collision across the distinct epoch keys that holds the
   number of epoch keys per payload_key below about 2^48
   (Section 5.9.6).

5.9.3.  Binding Limits for Profiled Suites

   For each profiled suite the binding limit is the smallest applicable
   class.  At 65536-octet (64 KiB) segments and a 2^-32 advantage
   target:

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

   +====================+================+===========+=================+
   | Suite / mode       | Binding limit  | Budget    | Failure mode    |
   +====================+================+===========+=================+
   | AES-128-GCM,       | random-nonce   | ~2^32     | confidentiality |
   | random             | collision      | per       |                 |
   |                    |                | epoch     |                 |
   |                    |                | key       |                 |
   +--------------------+----------------+-----------+-----------------+
   | AES-256-GCM,       | random-nonce   | ~2^32     | confidentiality |
   | random             | collision      | per       |                 |
   |                    |                | epoch     |                 |
   |                    |                | key       |                 |
   +--------------------+----------------+-----------+-----------------+
   | ChaCha20-Poly1305, | random-nonce   | ~2^32     | confidentiality |
   | random             | collision      | per       |                 |
   |                    |                | epoch     |                 |
   |                    |                | key       |                 |
   +--------------------+----------------+-----------+-----------------+
   | AES-256-GCM-SIV,   | MRAE distinct- | ~2^48     | confidentiality |
   | derived, distinct  | nonce          | per       | and integrity   |
   | segments           |                | epoch     |                 |
   |                    |                | key       |                 |
   +--------------------+----------------+-----------+-----------------+
   | AES-256-GCM-SIV,   | fixed-nonce    | ~2^36     | confidentiality |
   | derived, hot       | data volume    | per       |                 |
   | segment            |                | segment   |                 |
   |                    |                | at 64     |                 |
   |                    |                | KiB       |                 |
   +--------------------+----------------+-----------+-----------------+
   | AEGIS-256, random  | forgery bound  | ~2^83     | integrity       |
   |                    |                | per key   |                 |
   +--------------------+----------------+-----------+-----------------+
   | AEGIS-256X2,       | forgery bound  | ~2^83     | integrity       |
   | random             |                | per key   |                 |
   +--------------------+----------------+-----------+-----------------+

           Table 17: Binding limits for profiled suites at 64 KiB

   The 96-bit-nonce suites bind on random-nonce collision.  AEGIS makes
   nonce collision negligible with a 256-bit nonce (~2^112) and binds on
   forgery.  A derived-nonce MRAE AEAD has the two limits above, the
   distinct-derived-nonce ceiling and the fixed-nonce data-volume cap,
   not a single shared pool.

5.9.4.  Maximum Write-Once Object Size

   Two limits bound a write-once object: each epoch key's AEAD write
   budget, and the 2^63 segment index ceiling.

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

   Under a flat key (one epoch key for the whole object), the AEAD
   budget sets the size:

         +==========================+===========================+
         | Suite                    | Flat-key write-once limit |
         +==========================+===========================+
         | AES-128-GCM, AES-256-GCM | ~2^36 segments            |
         +--------------------------+---------------------------+
         | AES-256-GCM-SIV          | ~2^48 segments            |
         +--------------------------+---------------------------+
         | ChaCha20-Poly1305,       | 2^63 segments             |
         | AEGIS-256, AEGIS-256X2   |                           |
         +--------------------------+---------------------------+

                 Table 18: Flat-key write-once size limit

   For the block ciphers this limit is a confidentiality bound.  The
   AES-GCM suites (AES-128-GCM and AES-256-GCM) bind on the block-size
   birthday and AES-256-GCM-SIV on the distinct-derived-nonce budget.
   ChaCha20-Poly1305 and AEGIS have no write-count confidentiality bound
   below the index ceiling.  The AES-128-GCM, AES-256-GCM, and
   ChaCha20-Poly1305 figures assume derived nonce mode, which these non-
   MRAE suites may use only in a write-once profile.  In the default
   random nonce mode they bind earlier, at the random-nonce-collision
   budget of about 2^32 per epoch key (Table 17).

   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 64 KiB
   segments.  For AES-128-GCM this requires a sufficiently large
   epoch_length.  At epoch_length 0 its epoch-key collision floor caps
   the object near 2^48 segments (Section 5.9.6).  Reaching 2^63 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 distinct-derived-nonce budget of about
   2^48.  Rewrite capacity is a separate condition (Section 5.9.5).

5.9.5.  Rewrite Capacity

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

   For the random-nonce AEADs, 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:

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

    +====================+==============+==============+=============+
    | Suite / mode       | epoch_length | Segments per | Rewrites    |
    |                    |              | epoch key    | per segment |
    +====================+==============+==============+=============+
    | AES-128-GCM, AES-  | 0            | 1            | ~2^32       |
    | 256-GCM, random    |              |              |             |
    +--------------------+--------------+--------------+-------------+
    | AES-128-GCM, AES-  | 6            | 64           | ~2^26       |
    | 256-GCM, random    |              |              |             |
    +--------------------+--------------+--------------+-------------+
    | AES-128-GCM, AES-  | 10           | 1024         | ~2^22       |
    | 256-GCM, random    |              |              |             |
    +--------------------+--------------+--------------+-------------+
    | ChaCha20-Poly1305, | 0            | 1            | ~2^32       |
    | random             |              |              |             |
    +--------------------+--------------+--------------+-------------+
    | ChaCha20-Poly1305, | 6            | 64           | ~2^26       |
    | random             |              |              |             |
    +--------------------+--------------+--------------+-------------+
    | ChaCha20-Poly1305, | 10           | 1024         | ~2^22       |
    | random             |              |              |             |
    +--------------------+--------------+--------------+-------------+

                 Table 19: Rewrite share by epoch_length

   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:

     +==================+==============+==============+=============+
     | Suite / mode     | epoch_length | Segments per | Hot-segment |
     |                  |              | epoch key    | rewrite cap |
     +==================+==============+==============+=============+
     | AES-256-GCM-SIV, | 0            | 1            | ~2^36 at 64 |
     | derived          |              |              | KiB         |
     +------------------+--------------+--------------+-------------+
     | AES-256-GCM-SIV, | 6            | 64           | ~2^36 at 64 |
     | derived          |              |              | KiB         |
     +------------------+--------------+--------------+-------------+
     | AES-256-GCM-SIV, | 10           | 1024         | ~2^36 at 64 |
     | derived          |              |              | KiB         |
     +------------------+--------------+--------------+-------------+

              Table 20: GCM-SIV rewrite cap by epoch_length

   The hot-segment cap is length-dependent: about 2^36 at 64 KiB
   segments and about 2^38 at 16 KiB.  The distinct-derived-nonce budget
   stays about 2^48 per epoch key.  A derived-nonce MRAE AEAD thus has

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

   two separate constraints, the distinct derived nonces per epoch key
   and the repeated encryptions at one derived nonce.  AEGIS uses a flat
   key, and its forgery budget, about 2^83 per key from
   [I-D.irtf-cfrg-aegis-aead], exceeds any reachable rewrite workload.

   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.9.6.  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.  AEGIS has a
   256-bit nonce and a high forgery floor, so a flat key (epoch_length
   63) is the natural choice.

   The cipher suite's default epoch_length, used when a referencing
   protocol does not choose one, is 0 for the suites with an
   epoch_length range and 63 for the AEGIS suites.  epoch_length 0
   derives a fresh epoch key per segment, the finest rotation, giving
   each segment the largest share of the random-nonce collision pool.
   The AEGIS 256-bit nonce makes a flat key safe.  The named
   instantiations (Section 4.12) do not take this default: each pins an
   epoch_length tuned to its profile and object size, trading some
   rotation for fewer epoch keys while staying within budget.

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

   For AES-128-GCM the 128-bit AEAD key adds one further constraint.
   The epoch-key collision term (Appendix C.2) is about E^2/2^128 over
   the E distinct epoch keys, so an AES-128-GCM profile SHOULD keep
   distinct epoch keys per payload_key below about 2^48, which holds
   that term within the 2^-32 target.  At epoch_length 0 this caps an
   AES-128-GCM object at about 2^48 segments, far below the 2^63 index
   ceiling, so it constrains only extreme object sizes.

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

5.9.7.  Derivations

   The per-suite figures come from the bounds below.

5.9.7.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.9.7.4.

5.9.7.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), block-cipher AEADs have a distinguishing bound that grows
   with the total number of cipher blocks processed under a key.  For
   the AES-GCM suites (AES-128-GCM and AES-256-GCM), if s is the total
   number of AAD-plus-plaintext 128-bit blocks and q is the number of
   encryption queries under a key, the confidentiality advantage is at
   most:

   CA <= ((s + q + 1)^2) / 2^129

   For 65536-octet segments (L = 4096 blocks per segment), s = L * q in
   the worst case, so CA scales as q^2 * L^2 / 2^129.  In random nonce
   mode the nonce-collision bound q^2 / 2^97 dominates for typical
   deployments because L^2 / 2^32 is small.  In derived nonce mode the
   nonce-collision term vanishes and the block-size term is the binding
   confidentiality constraint.

   For ChaCha20-Poly1305 there is no comparable block-size bound because
   ChaCha20 is a stream cipher, leaving nonce collision and forgery as
   the only relevant terms.  Section 5.9.7.4 gives the derived-nonce
   block-size limits.  No analogous block-size confidentiality bound has
   been published for AEGIS-256 or AEGIS-256X2.  Nonce collision
   (negligible at a 256-bit nonce) and the per-key margin govern AEGIS
   confidentiality.  The per-query forgery bound governs integrity.

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

   SEAL implementations MUST compute usage budgets from the AEAD-
   specific confidentiality and integrity bounds, not from nonce-
   collision probability alone.  Table 17 gives the binding limit per
   suite.

5.9.7.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 and segment_max.

   For the AES-GCM suites (AES-128-GCM and AES-256-GCM)
   ([I-D.irtf-cfrg-aead-limits] Section 5.1):

   IA <= 2 * v * (L + 1) / 2^128

   where v is the number of forgery attempts and L = 4096 blocks per
   segment.

   For ChaCha20-Poly1305 ([I-D.irtf-cfrg-aead-limits] Section 5.2):

   IA <= v * (L' + 1) / 2^103

   Here v is the number of forgery attempts and L' is the segment length
   in 16-octet Poly1305 blocks (about 4096 at 65536-octet segments), per
   [I-D.irtf-cfrg-aead-limits].  The 2^103 denominator (not 2^128)
   reflects Poly1305's per-query forgery bound.  At 65536-octet
   segments, the integrity limit for ChaCha20-Poly1305 is tighter than
   for AES-GCM.

5.9.7.4.  Derived-Nonce Bounds

   A derived-nonce MRAE AEAD has two limits the random-nonce analysis
   above does not capture.

   Across the distinct segment nonces under one epoch key, the derived-
   key analysis of [RFC8452] Section 9 ([BHT18]) bounds the number of
   distinct derived nonces at about 2^48 for a 2^-32 advantage.

   For a single hot segment, every rewrite reuses that segment's one
   derived nonce, so N rewrites of an L-block segment run AES-CTR under
   one derived per-record key.  The binding 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 * L blocks and q = N
   queries:

   ((s + q + 1)^2) / 2^129 <= 2^-32

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

   The N * L term dominates, so this holds while N * L stays below about
   2^48, giving N <= about 2^48 / L.  That is about 2^36 rewrites of one
   64 KiB segment (L = 4096) and about 2^38 at 16 KiB.  This per-nonce
   cap does not divide by 2^epoch_length, because the segment reuses the
   same derived nonce regardless of epoch_length.

   Distinct plaintexts under the fixed nonce produce distinct synthetic
   IVs and hence distinct counter keystreams (the GCM-SIV synthetic-IV
   construction, [RFC8452]), so confidentiality degrades 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.2.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.  Each subsection below describes a way one of
   these can fail and what breaks.

   Integrity across the SEAL suite is bounded by the 16-octet AEAD tag
   (Nt = 16): no suite member offers more than approximately 128 bits of
   forgery resistance per query (Table 17).  The AEGIS algorithms'
   256-bit keys raise confidentiality margins, not the tag-length
   forgery floor.

6.1.  Detection Summary

   The table below maps common failure modes to the check that detects
   them and notes the cases where raAE provides no detection.  The rows
   detected by SnapVerify assume a snapshot authenticator is configured
   (snap_id != 0x0000).  Without one, those modes go undetected.  The
   one exception is a dropped trailing segment: the per-segment finality
   requirement of Section 4.9.1.2 detects it in any profile, with no
   snapshot authenticator.

    +==============+==================================================+
    | Failure mode | Detected by                                      |
    +==============+==================================================+
    | Wrong CEK,   | The commitment, before any segment decryption,   |
    | salt, or     | provided reader and writer use the same          |
    | parameter    | payload_info construction.                       |
    | set          |                                                  |
    +--------------+--------------------------------------------------+
    | Modified     | AEAD.Decrypt for the affected segment.           |
    | ciphertext   |                                                  |
    | core or AEAD |                                                  |

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

    | tag          |                                                  |
    +--------------+--------------------------------------------------+
    | Segment      | AEAD.Decrypt: the segment index and finality bit |
    | moved to a   | are authenticated by segment_aad (random nonce   |
    | different    | mode) or by the nonce (derived nonce mode).      |
    | index        |                                                  |
    +--------------+--------------------------------------------------+
    | Segment      | Detected when the copied segment was encrypted   |
    | copied from  | under a different CEK or salt.  Reusing a salt   |
    | another      | with the same CEK breaks this separation         |
    | object at    | (Section 6.7).                                   |
    | the same     |                                                  |
    | index        |                                                  |
    +--------------+--------------------------------------------------+
    | Segment      | Not detected by per-segment AEAD alone; detected |
    | copied from  | by SnapVerify, unless the whole object           |
    | another      | (including snapshot) is rolled back to that      |
    | version at   | earlier valid version.                           |
    | the same     |                                                  |
    | index        |                                                  |
    +--------------+--------------------------------------------------+
    | Dropped      | The finality requirement of Section 4.9.1.2, in  |
    | trailing     | any profile: the highest-indexed present segment |
    | segment(s)   | then carries is_final = 0 and the decryptor      |
    | (truncation) | rejects.  Truncation to zero present segments is |
    |              | rejected by the zero-segment prohibition without |
    |              | a snapshot authenticator, and detected by        |
    |              | SnapVerify with one (Section 6.6).               |
    +--------------+--------------------------------------------------+
    | Missing      | SnapVerify, which checks the segment count,      |
    | interior,    | finality, and recomputed snapshot value.         |
    | duplicated,  |                                                  |
    | reordered,   |                                                  |
    | or inserted  |                                                  |
    | segment      |                                                  |
    +--------------+--------------------------------------------------+
    | Stale        | SnapVerify, unless the stale value is part of a  |
    | snapshot     | whole-object rollback to a previously valid      |
    | value        | snapshot.                                        |
    +--------------+--------------------------------------------------+
    | Whole-object | Not detected by raAE alone; the consuming        |
    | rollback     | protocol needs authenticated external freshness  |
    |              | state.                                           |
    +--------------+--------------------------------------------------+
    | Concurrent   | Not a cryptographic forgery; the consuming       |
    | lost update  | protocol needs writer serialization or another   |
    |              | way to publish object state atomically.          |
    +--------------+--------------------------------------------------+

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

    | Equality     | Not an authentication failure; rewriting equal   |
    | leakage in   | plaintext at the same index under derived nonce  |
    | derived      | mode can reveal equality (Section 4.5.3,         |
    | nonce mode   | Section 6.2).                                    |
    +--------------+--------------------------------------------------+

          Table 21: 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 AES-GCM and ChaCha20-Poly1305, nonce reuse also
   recovers the polynomial 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 in a write-once
   profile that draws a fresh salt per object and never re-encrypts
   under it after a crash (Section 4.5.3.2).  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.

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

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

   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.  Each SEAL AEAD
   additionally sets a default nonce mode (see Table 9).  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.5.  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:

    +============+==============+====================================+
    | AEAD class | random nonce | derived nonce                      |
    +============+==============+====================================+
    | non-MRAE   | valid        | mutable: unsafe; write-once: valid |
    +------------+--------------+------------------------------------+
    | MRAE       | wasteful     | valid                              |
    +------------+--------------+------------------------------------+

                    Table 22: Nonce mode by AEAD class

   Rewrite is where the coupling matters.  A derived nonce is fixed by
   the segment index, so a rewrite reuses it, while a random nonce is
   drawn fresh every time.  A repeat is catastrophic for a non-MRAE AEAD
   and only equality-leaking for an MRAE one, which is what the table
   reflects.  Section 4.5.3.2 gives the rules and their consequences.

   The optional plaintext-bound construction (Appendix A) is an
   encryptor-side hedge over random nonce mode, not a separate nonce
   mode.  See Section 4.10.1 for SEAL's per-AEAD guidance.

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

6.6.  Snapshot Integrity Limitations

   Snapshot integrity has the following 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.2.3: 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 over the segment tags authenticates
   the tag set, its positions, and the count.  It does not confirm that
   a tag is a valid AEAD tag for the ciphertext beside it.  Decrypting
   that 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
   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.8).

   Detecting these substitutions is a benefit of the design, not a
   limitation.  It is the property that distinguishes raAE's snapshot
   integrity from per-segment AEAD authenticity.

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

   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 not a separate limitation.  It 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 under derived
   nonces, a combination the construction forbids (Section 4.5.3.2),
   would permit plaintext recovery.

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

   Rewriting introduces the following hazards.

   Applications MUST track total segment encryptions per key and freeze
   the object before exceeding the budget in Section 5.9.5.  For the 96-
   bit-nonce AEADs (AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305) the
   binding limit is the per-epoch-key collision pool of roughly 2^32
   encryptions, counted across every segment that shares the key.
   Spread evenly, that pool gives each segment a uniform rewrite share
   of roughly 2^(32 - epoch_length), as tabulated in Section 5.9.5.  See
   Section 5.9.6.  Exceeding the per-epoch-key pool risks nonce
   collisions and plaintext recovery.

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

   A mutable profile with derived nonces and an MRAE AEAD (SEAL-RW-v1)
   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.9.5), 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.

   For the masked multiset hash, when multiple writers rewrite different
   segments concurrently, each computes an independent accumulator
   difference (old_contrib XOR new_contrib).  Applying these differences
   is commutative, but the read-modify-write on the stored accumulator
   requires coordination.  Supplying that coordination, for example a
   compare-and-swap on the published snapshot value and segment count,
   is the consuming protocol's responsibility, consistent with the
   serialization and storage transactions this document places out of
   scope.  The snapshot tag and the mask MUST be recomputed over the
   final accumulator and segment count inside the same critical section
   that publishes the snapshot update.  Otherwise a storage layer can
   publish a masked accumulator and a snapshot tag that were computed
   for different accumulators.  As a recovery mechanism, the accumulator
   can always be rebuilt from scratch by XOR-ing all contrib values and
   then re-masked.

   Length changes are a separate concurrency case.  Append and truncate
   change the segment count and re-mark a terminal segment.  Those
   updates do not commute with each other or with a concurrent rewrite
   of the old or new terminal segment unless the consuming protocol
   serializes them.

   Per-segment associated data A_i is rewritable, not fixed at creation.
   Unlike a global associated data value G, which the commitment fixes
   when the object is created (Section 4.6), A_i rides the per-segment
   AEAD associated data (Section 4.4.2), so a rewrite can replace a
   segment's A_i, for example to change a policy or version field.  A
   reader therefore cannot treat A_i as context fixed at creation the
   way it can treat G.  An application that needs context fixed at
   creation places it in G, which the commitment binds, rather than 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.

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

6.9.  Constant-Time Implementation

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

   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 HKDF-Extract and HKDF-Expand execute in constant
   time with respect to their key inputs.  In practice this is satisfied
   by HMAC 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.
   SnapVerify MUST compare the full recomputed snapshot value, the
   masked accumulator and the snapshot tag together, in one constant-
   time comparison, so that no observable difference reveals which half
   differs (Section 4.7.4).  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.8).

   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.  It
   deliberately does not address four concerns that belong to the
   consuming protocol.

   The CEK must remain available as long as any reader needs access, so
   there is no forward secrecy.  Ciphertexts are not bound to any sender
   identity.  A signing or MAC layer is needed for sender
   authentication.  Key identifiers and structural features of the
   encrypted format are visible, so unlinkability requires application-
   layer measures.  Finally, 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.

   These concerns are not artifacts of raAE's design.  Any raAE
   construction inherits them from the consuming protocol's scope.

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

6.11.  Cross-Application Domain Separation

   Two applications that both reuse the same SEAL profile label
   (Section 4.10.2) 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 (Section 4.10.2) unchanged MAY use that profile's label.

7.  IANA Considerations

   This document has no IANA actions.

   SEAL consumes identifiers from existing IANA registries: the AEAD
   Algorithms Registry ([RFC5116]) for aead_id values and the HPKE KDF
   Registry ([RFC9180] Section 7.2) for kdf_id values.  No new raAE-side
   registries are created.

   The following code points are early allocations in their respective
   registries.  Each registry reference firms up when the referenced I-D
   is published as an RFC, and the corresponding SEAL normative
   reference is a downref under IRTF stream conventions until then.

   +==============+======+================+============================+
   | Registry     |Code  | Algorithm      | Reference                  |
   |              |point |                |                            |
   +==============+======+================+============================+
   | AEAD         |0x0021| AEGIS-256      | [I-D.irtf-cfrg-aegis-aead] |
   | Algorithms   |      |                |                            |
   | ([RFC5116])  |      |                |                            |
   +--------------+------+----------------+----------------------------+
   | AEAD         |0x0024| AEGIS-256X2    | [I-D.irtf-cfrg-aegis-aead] |
   | Algorithms   |      |                |                            |
   | ([RFC5116])  |      |                |                            |
   +--------------+------+----------------+----------------------------+
   | HPKE KDF     |0x0013| TurboSHAKE-256 | [I-D.ietf-hpke-pq]         |
   | ([RFC9180]   |      |                |                            |
   | Section      |      |                |                            |
   | 7.2)         |      |                |                            |
   +--------------+------+----------------+----------------------------+

                   Table 23: Early-Allocation Code Points

   Future SEAL profiles MAY consume additional entries from either
   registry without revising this document.

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

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-04, 2 March
              2026, <https://datatracker.ietf.org/doc/html/draft-ietf-
              hpke-pq-04>.

   [I-D.irtf-cfrg-aegis-aead]
              Denis, F. and S. Lucas, "The AEGIS Family of Authenticated
              Encryption Algorithms", Work in Progress, Internet-Draft,
              draft-irtf-cfrg-aegis-aead-18, 5 October 2025,
              <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-
              aegis-aead-18>.

   [NIST-SP-800-38D]
              Dworkin, M., "Recommendation for Block Cipher Modes of
              Operation: Galois/Counter Mode (GCM) and GMAC",
              NIST Special Publication 800-38D, November 2007,
              <https://nvlpubs.nist.gov/nistpubs/Legacy/SP/
              nistspecialpublication800-38d.pdf>.

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

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

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

   [RFC8439]  Nir, Y. and A. Langley, "ChaCha20 and Poly1305 for IETF
              Protocols", RFC 8439, DOI 10.17487/RFC8439, June 2018,
              <https://www.rfc-editor.org/rfc/rfc8439>.

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

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

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

   [DAE]      Rogaway, P. and T. Shrimpton, "A Provable-Security
              Treatment of the Key-Wrap Problem", EUROCRYPT 2006, LNCS
              4004, pp. 373-390, DOI 10.1007/11761679_23, 2006,
              <https://doi.org/10.1007/11761679_23>.

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

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

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

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

   [MSetHash] Clarke, D., Devadas, S., van Dijk, M., Gassend, B., and G.
              E. Suh, "Incremental Multiset Hash Functions and Their
              Application to Memory Integrity Checking", ASIACRYPT 2003,
              LNCS 2894, pp. 188-207, DOI 10.1007/978-3-540-40061-5_12,
              2003, <https://doi.org/10.1007/978-3-540-40061-5_12>.

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

   [SEALPROOFS]
              TBD, "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>.

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

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(plaintext_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 24: Plaintext-bound construction labels

   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.  Component vectors for both KDF classes are in
   Appendix E.19.

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

   LH is the over-large-field digest of Section 4.3, which runs the
   cipher suite's native KDF primitive directly on its input and returns
   Nh octets.  It is collision-resistant per Section 5.5.  Decryptors
   never compute pt_digest.

   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.  No additional
   information beyond this equality is leaked.

   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.

   The construction is observationally equivalent to nonce_mode "random"
   at the wire format.  A decryptor cannot distinguish whether the
   encryptor used a fresh CSPRNG call or this construction to produce
   the stored nonce.  Implementations that elect to use this
   construction internally do not need to advertise it.

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.

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

   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.  An optional encryptor-side construction that
   mixes plaintext content into the per-segment nonce derivation to
   defend against state duplication is described in Appendix A.  That
   construction is orthogonal to hedging and the two MAY be combined.

Appendix C.  Proof Status and Security Claim Provenance

   This appendix is informative.  It states what is proven, where, and
   by whom.  Each result below is inherited from [FLRR25], argued in
   this document, or deferred to a companion proof paper in preparation
   ([SEALPROOFS]).

   Inherited from [FLRR25]:  The ra-ROR and ra-CMT games, their
      advantages, and their proofs apply to SEAL's realization of the
      base interface, summarized in Section 5.6 and Section 5.7.  The
      ra-CMT-p notion and its base proof are likewise inherited, but
      SEAL's realization of its position binding is argued here (see
      below).

   Argued in this document:  The mechanisms this document adds beyond
      [FLRR25] are argued in the subsections below.  These are the
      snapshot authenticator that realizes snapshot integrity, the nonce
      modes, the per-segment associated data and position binding of ra-
      CMT-p (bound stated here, formal accounting deferred), and the
      injectivity and domain separation of the KDF combiner.  The
      combiner argument is structural and proof-complete (Section 4.3).
      The others state their bounds.  Their full proofs are not here.

   Referenced from external work:  The capacity, rewrite, and maximum-
      object-size bounds (Section 5.9) are operational ceilings derived
      from [I-D.irtf-cfrg-aead-limits], [RFC8452] Section 9, and
      [BHT18], not security reductions proven here.

   Deferred to [SEALPROOFS]:  The formal proof of snapshot integrity as
      an extension of the ra-ROR framework, the real-or-random treatment
      of the derived-nonce equality leakage (which relaxes that
      framework's nonce-respecting hypothesis to deterministic MRAE),
      and the per-segment associated data and position accounting of ra-
      CMT-p.

   Precedent, not proof:  The derived-nonce unique-nonce transform rests

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

      on TLS 1.3 ([RFC8446]) and STREAM ([HRRV15]) precedent, treated in
      Appendix C.6.  That precedent does not prove SEAL-RO-v1.  The KDF
      hierarchy, the arbitrary-position ra-ROR syntax, the ra-CMT
      commitment, the epoch accounting, and the object-level semantics
      remain SEAL-specific proof obligations.

   The combiner's input encoding is injective and canonical, so distinct
   (protocol_id, label, ikm, info, L) tuples map to distinct primitive
   inputs and a given tuple has one encoding across implementations
   (Section 4.3, Section 5.5).  Injectivity comes from the length-
   prefixed encoding, not from the KDF, which need not itself be
   injective.  Collision resistance is assumed only of LH, and only for
   over-large fields.  The commitment derivation carries its own
   separate collision-resistance assumption (Appendix C.4).

   The capacity and usage limits in Section 5.9, including the maximum
   write-once object size (Section 5.9.4) and the derived nonce bounds
   (Section 5.9.7.4), are operational ceilings.  They are referenced
   from [I-D.irtf-cfrg-aead-limits], [RFC8452] Section 9 with [BHT18],
   and the 2^63 segment-index ceiling, not proven here.

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              |
   |position    |position-     |        |                              |

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

   |commitment) |binding       |        |                              |
   |            |realization   |        |                              |
   |            |and per-      |        |                              |
   |            |segment       |        |                              |
   |            |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.5     | resistance of LH for over-   |
   |            |              |        | large fields only            |
   +------------+--------------+--------+------------------------------+
   |Snapshot    |this          |Appendix| mu-PRF KDF under snap_key;   |
   |integrity   |document,     |C.5     | MAC unforgeability of        |
   |(masked     |Appendix C.5  |        | snapshot_tag over (n_seg,    |
   |multiset    |              |        | acc); deterministic-masking  |
   |hash)       |              |        | birthday and mix-and-match   |
   |            |              |        | terms; per-object separation |
   |            |              |        | via salt-bound snap_key      |
   +------------+--------------+--------+------------------------------+
   |AEAD usage, |external work |Section | [I-D.irtf-cfrg-aead-limits], |
   |rewrite, and|(operational, |5.9,    | [RFC8452] Section 9 with     |
   |max-object  |not proven    |Section | [BHT18], 2^63 segment-index  |
   |bounds      |here)         |5.9.4,  | ceiling                      |
   |            |              |Section |                              |
   |            |              |5.9.7.4 |                              |
   +------------+--------------+--------+------------------------------+
   |Derived-    |precedent,    |Section | write-once uniqueness        |
   |nonce       |not proof     |4.5.3.2,| discipline reducing to       |
   |unique-nonce|(TLS 1.3      |Appendix| nonce-respecting AEAD        |
   |transform   |[RFC8446],    |C.6     | security                     |
   |            |STREAM        |        |                              |
   |            |[HRRV15])     |        |                              |
   +------------+--------------+--------+------------------------------+
   |Derived-    |this          |Appendix| MRAE AEAD ([RFC8452]); per-  |
   |nonce       |document;     |C.6     | segment fixed-nonce data-    |
   |equality    |full proof in |        | volume cap                   |
   |leakage     |[SEALPROOFS]  |        |                              |
   |(MRAE)      |              |        |                              |
   +------------+--------------+--------+------------------------------+

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

                Table 25: Provenance of the security claims

C.2.  Advantage Notation and Adversary Parameters

   For a ra-ROR adversary (Section 5.4) 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 E 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_acc

   The terms in the bound are as follows.

   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_acc
      below.  It is not counted again here.

   Adv_muROR(AEAD, B_AEAD)  The multi-user real-or-random advantage of
      the AEAD over sigma total segment queries.  There is one mu-ROR
      user per distinct segment key, for E epoch keys total (E = q_m
      when each message uses a single flat epoch key).  This advantage
      absorbs a key-collision birthday term of about E^2/2^(8*Nk) over

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

      the E distinct keys.  For the 256-bit-key suites (Nk = 32) that
      term is about E^2/2^256 and is negligible.  For AES-128-GCM (Nk =
      16) it is about E^2/2^128 and is the binding epoch-key collision
      floor.  Section 5.9.6 bounds E 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.9.7.1.  The derived-mode statement relies on
      the deterministic-MRAE analysis in Appendix C.6.

   Adv_acc  The masked multiset hash's snapshot forgery advantage,
      present only under snap_id 0x0001 and zero otherwise.  SEAL
      authenticates the XOR accumulator (Section 4.7) with a snapshot
      tag, a MAC under snap_key, and masks the published accumulator
      with a deterministic tag-derived pad.  A different snapshot
      authenticator contributes its own term in place of Adv_acc.

   The Adv_acc term is bounded by:

Adv_acc <= Adv_muPRF_acc
           + q_s^2 / 2^(8*Nh)          (snapshot-collision birthday)
           + q_v / 2^(8*Nh)            (fresh-input tag forgery)
           + q_s * q_v / 2^(8*Nh)      (mix-and-match accumulator guess)

   Here Adv_muPRF_acc is the snap_key subset of B_KDF's Level B queries,
   counted here and not again in Adv_muPRF(KDF, B_KDF).  q_s is the
   number of published snapshot states the adversary observes and q_v
   the number of SnapVerify queries it makes.  The q_s^2 birthday term
   is the cost of the deterministic masking (Appendix C.5).  The
   dominant terms are that birthday and the mix-and-match q_s * q_v /
   2^(8*Nh), and for the SEAL suites (8*Nh of 256, 384, or 512) every
   term is negligible.

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, then the
   payload_key- and snap_key-keyed outputs, with uniformly random values
   (Adv_muPRF at the two keying levels).  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.6).  The snapshot
   authenticator's forgery enters separately as Adv_acc (Section 5.8).

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

   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.

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.  The
   collision-resistance assumption captured in Section 4.5 is what makes
   the reduction sound.

   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
   gives about 2^128 (capped by SHA-256's own 2^128 collision resistance
   for HKDF-SHA-256), 48 octets gives about 2^192 (capped by SHA-384's
   2^192 for HKDF-SHA-384), and 64 octets gives about 2^256 (for HKDF-
   SHA-512, capped by SHA-512's 2^256, and for TurboSHAKE-256).  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 for ra-CMT-p is inherited from the underlying AEAD's
   commitment level (Section 5.7).  The notion and base proof are
   inherited from [FLRR25].  The exact per-segment associated data and
   position accounting is deferred to [SEALPROOFS].

C.5.  Snapshot Authenticator

   SEAL's snapshot authenticator (snap_id 0x0001) is the MSet-XOR-Hash
   of Clarke et al.  ([MSetHash]) with a deterministic mask this
   document adds.  Each segment contributes a keyed KDF evaluation of
   its index and tag, the contributions XOR into an accumulator, and the
   published value masks that accumulator under snap_key.  A different
   authenticator that meets the requirement of Section 5.5 carries its
   own argument.

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

   The adversary has full read and write access to the stored segments,
   their metadata, and the snapshot, and wins by making SnapVerify
   accept a (segment set, snapshot) pair other than the writer's current
   state.  Whole-object rollback to an earlier honest state is excluded
   and is the application's freshness responsibility (Section 6.6).

   Publishing the accumulator in the clear would be insecure.  That is
   the MSet-XOR-Hash with its mask removed, which is only set-collision
   resistant.  A write adversary reads the accumulator across honest
   rewrites, collects the contribution differences old_contrib XOR
   new_contrib, and after more than 8*Nh of them solves a GF(2) system
   for a subset of segments it can revert without changing the
   accumulator.  The current snapshot tag still verifies, so a non-
   historical mixture of versions is accepted with no MAC forgery.

   The deterministic mask defeats this attack.  Here wrapped_acc = acc
   XOR snapmask(n_seg, snapshot_tag) hides the accumulator behind a one-
   time pad keyed by snap_key and seeded by the synthetic snapshot tag,
   the synthetic-IV derandomization of deterministic authenticated
   encryption ([DAE]).  Two published states that collide on (n_seg,
   acc), or on the snapshot tag at equal count, would expose a raw
   accumulator difference.  Over q_s published states that costs a
   birthday term q_s^2 / 2^m, with m = 8*Nh.  Off that event the masks
   are independent one-time pads, the published transcript is
   independent of every accumulator, and the recombination above has no
   linear system left to solve.  Security reduces to the PRF security of
   the KDF.  The mask protects the accumulator only against a verifier
   that returns one bit, which is why SnapVerify does not surface the
   recovered accumulator (Section 4.7.4).

   A forgery is then one of two events.  Either a fresh snapshot-tag
   input is guessed, a MAC forgery bounded by q_v / 2^m over q_v
   verifications, or a different segment set is made to hit a published
   accumulator by chance, a mix-and-match bounded by q_s * q_v / 2^m
   against q_s published states.  The mix-and-match term is a set
   collision on the keyed contribution function and relies on the set-
   collision resistance of the MSet-XOR-Hash-style construction
   ([MSetHash]).  The formal bound for this term is discharged in
   [SEALPROOFS].  Collecting the terms, the snapshot forgery advantage
   Adv_acc of Appendix C.2 is

   Adv_acc <= Adv_muPRF_acc + q_s^2 / 2^m + q_v / 2^m + q_s * q_v / 2^m

   with m = 8*Nh and dominant terms q_s^2 / 2^m and q_s * q_v / 2^m,
   both negligible at Nh of 32, 48, or 64.  The argument relies on
   segment AEAD authenticity, already charged as Adv_muROR, and adds no
   term beyond Adv_acc.  Per-object separation comes from the salt-bound
   snap_key, and the authenticator needs no assumption beyond the multi-

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

   user PRF the key schedule already uses.  It does not need the
   commitment's collision resistance.  Integrating this reduction into
   the combined ra-ROR proof is in preparation ([SEALPROOFS]).

C.6.  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.  Under the write-once uniqueness discipline every derived
   nonce is distinct, which reduces unique-nonce record protection to
   nonce-respecting AEAD security.  This is precedent, not a SEAL-
   specific proof.

   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.  Several considerations motivate this.

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

   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:  This matters even for content written once:
      large content with many segments can place many AEAD invocations
      under a single key.

   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 immutable profile SEAL-RO-v1 the write-once
   rule keeps every derived nonce unique, so derived mode pairs with any
   AEAD.  Table 9 gives the default nonce_mode each suite uses in the
   mutable profile, and a profile MAY select another valid (nonce_mode,
   snap_id) tuple.

D.3.  Snapshot Authenticator Design Rationale

   Three shapes were considered for whole-object integrity over an
   updatable segment set.  A MAC over the concatenated tag list is the
   simplest, but a rewrite changes one tag in the middle of the input,
   so the writer recomputes over all n_seg tags on every update.  A
   Merkle tree over the tags updates in O(log n) and can offer per-
   segment inclusion proofs, but it either stores interior nodes that
   grow with the object or re-reads segment tags to rebuild paths, and
   it rests on collision resistance of a hash.  The masked multiset hash
   updates in O(1) per rewrite, stores a single value of 2*Nh octets
   regardless of object size, needs no per-segment proofs, and needs
   only the multi-user PRF assumption the key schedule already carries.
   Its costs are the ones this document states explicitly: the

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

   accumulator stays masked, the verifier returns a single bit
   (Section 4.7.4), and the deterministic mask adds the q_s^2 birthday
   term to the bound (Appendix C.5).  A profile that needs per-segment
   inclusion proofs or third-party verifiability needs a different
   authenticator under its own snap_id (Section 4.7.1).

   The accumulator is on the wire so a stateless writer can resume the
   O(1) update from the stored snapshot alone, rather than holding it in
   trusted state or re-reading every tag.  Publishing it is why the mask
   and the one-bit verifier are needed: an exposed accumulator would let
   a write adversary recombine observed values (Appendix C.5).

Appendix E.  Test Vectors

   This appendix is informative.

   All vectors use protocol_id = "SEAL-RW-v1", CEK = 32 octets of 0xAA,
   and salt = 32 octets of 0x04.  Each block opens with its parameter
   set, grouped into three buckets: the cipher suite (aead_id, kdf_id),
   the geometry (segment_max), and the operational parameters
   (epoch_length, nonce_mode, snap_id).  aead_id and kdf_id are the
   2-octet IANA code points from Table 9 and Table 10.  Then come the
   payload_info elements as encoded on the wire, the payload schedule
   outputs, the per-segment values, and the snapshot fields.
   Hexadecimal values wrap at 16 octets per line.

   The snapshot fields are the internal accumulator acc, the mask
   snapmask(n_seg, snapshot_tag), the published wrapped_acc = acc XOR
   mask, and the snapshot tag.  The snapshot stored on the wire is
   wrapped_acc || snapshot_tag (Section 4.7.4).  The accumulator is an
   intermediate value and is not on the wire, and the count is recovered
   from the segment set.

   Single-segment plaintexts are "Hello, SEAL!" (12 octets).  Two-
   segment messages append "Two segments of SEAL" (20 octets) as the
   final segment.  Most vectors use nonce_mode "random" with stored
   nonces 0x03 and 0x07 repeated to the AEAD nonce length.  The derived-
   nonce vector in Appendix E.17 instead recomputes each nonce from
   nonce_base, and the cross-epoch vector in Appendix E.18 sets
   epoch_length 0 and exposes the intermediate epoch_key and segment_key
   for each segment.  Appendix E.1 gives the full KDF trace for one
   commitment.  The other blocks list schedule outputs only.  The
   eighteen computed positive vectors, plus the negative SnapVerify
   vector in Appendix E.20, are published byte-for-byte as raae-
   v1-vectors.json in the draft repository.

   The vectors are organized by purpose:

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

   Annotated walkthrough:  Appendix E.1 shows one complete HKDF-SHA-256
      trace, including the commitment KDF inputs.  Use it to debug
      framing, payload_info construction, commitment derivation, segment
      AAD, accumulator contribution, and snapshot_tag computation.

   Combiner injectivity coverage:  Appendix E.3 exercises the KDF
      combiner in isolation and demonstrates encode() injectivity,
      including the empty-sequence and same-octets-different-grouping
      cases.  The 38 combiner vectors are published as raae-v1-combiner-
      kdf-vectors.json.

   Cipher-suite coverage:  The single-segment and two-segment vectors
      exercise the listed AEAD and segment-size combinations with HKDF-
      SHA-256.  Use these to check AEAD code points, segment_max
      encoding, nonce storage, and finality-bit handling.

   KDF coverage:  Appendix E.15 covers the TurboSHAKE-256 KDF suite and
      its 64-octet Nh outputs.

   Rewrite coverage:  Appendix E.16 shows a segment rewrite and the
      corresponding accumulator and snapshot_tag update.

   Derived-nonce coverage:  Appendix E.17 covers AES-256-GCM-SIV in
      derived nonce mode, where the nonce is recomputed rather than
      stored.

   Epoch coverage:  Appendix E.18 shows epoch_length = 0, the finest
      rotation, and exposes per-segment epoch_key and segment_key
      values.  The AEGIS-256 blocks exercise the opposite endpoint, the
      flat key at epoch_length = 63.

   Plaintext-bound nonce coverage:  Appendix E.19 exposes the component
      values of the optional plaintext-bound nonce construction, which
      no end-to-end vector can reach.

   Global associated data coverage:  Appendix E.2 pins the commitment's
      G input at its empty default, which equals the Appendix E.1
      commitment, and at a nonempty value.

   Empty-AAD coverage:  All vectors use empty per-segment A_i.  As
      specified in Section 4.4.2, an empty A_i is omitted from the
      encoding rather than encoded as a zero-length fourth element.

   Negative coverage:  Appendix E.20 changes the accumulator without
      recomputing the snapshot tag; SnapVerify rejects the stored
      snapshot.

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

   The JSON file is the complete corpus for automated tests.  The text
   below is intended for debugging and review.

E.1.  Single Segment, AES-256-GCM, HKDF-SHA-256, 16384

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   16384
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00004000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       47ea0ec7409b9b95d676019917a19f1c
       5831eb236aba459063458e525d130d0c
     payload_key  (32 octets):
       c1f2663e99977428dc0fec1566ce15e9
       1398634ab9b1d004945de48560707062
     snap_key     (32 octets):
       bc314ecaa8ff6c1c4ebc13b54597a10d
       2bcf412b40c428a0e411a828fcfb52ef

   Segment 0 (is_final=1):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000101
     ciphertext   (12 octets):
       6a2b84e72ce8edbf4259eebd
     tag          (16 octets):
       a821834621b302b0eb00b0245fff2efb

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

     contrib      (32 octets):
       97b74013b135f6fe1739da05e1720b90
       dc596a6d09e29bfe437bb710391c9ba8

   accumulator  (32 octets):
       97b74013b135f6fe1739da05e1720b90
       dc596a6d09e29bfe437bb710391c9ba8
   mask         (32 octets):
       9356a1f7905b40b4561315a6892503d6
       2b0c7162aa19285f939325709f5847fb
   wrapped_acc  (32 octets):
       04e1e1e4216eb64a412acfa368570846
       f7551b0fa3fbb3a1d0e89260a644dc53
   snapshot_tag (32 octets):
       4e7bb00b4216798e02e511b26f0167c2
       a3f6c791407994e1f503f3923e591438

   KDF trace for the commitment (HKDF-SHA-256):
     extract_input = encode(protocol_id, "commit", CEK):
       000a5345414c2d52572d76310006636f
       6d6d69740020aaaaaaaaaaaaaaaaaaaa
       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
       aaaaaaaaaaaa
     prk = HKDF-Extract(salt = protocol_id, extract_input):
       8eb0007f1e8ac96904742b4fb4448aba
       9d8a4b319f72f7e4a6d7bb8aab95737d
     expand_info = encode(protocol_id, "commit", ...payload_info, G,
                          I2OSP(32, 2)):
       000a5345414c2d52572d76310006636f
       6d6d6974000200020004000040000002
       00010002000100010000010100200404
       04040404040404040404040404040404
       04040404040404040404040404040000
       00020020
     commitment = HKDF-Expand(prk, expand_info, 32):
       47ea0ec7409b9b95d676019917a19f1c
       5831eb236aba459063458e525d130d0c

E.2.  Commitment with Global Associated Data

   These vectors pin the G input (Section 4.6) against the schedule of
   Appendix E.1: the same CEK, salt, and payload_info with G at its
   empty default and at a nonempty value.  The default case equals the
   Appendix E.1 commitment, since every commitment includes the G
   element.  These values are printed here only and are not part of the
   end-to-end corpus.

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

   G default (empty):
     commitment   (32 octets):
       47ea0ec7409b9b95d676019917a19f1c
       5831eb236aba459063458e525d130d0c
     (the Single Segment, AES-256-GCM, HKDF-SHA-256, 16384
      commitment)

   G = "raae-demo-g":
     G            (11 octets):
       726161652d64656d6f2d67
     commitment   (32 octets):
       d8eedb1fa0f77428cc33d252eb307796
       ae3bb911c2f6ea7a9e5b0bde312afd73

E.3.  KDF Combiner Vectors

   These vectors exercise the KDF combiner (Section 4.3) in isolation.
   They demonstrate that encode() is injective over (protocol_id, label,
   ikm, info, L): distinct inputs, including inputs whose octets
   concatenate to the same string under a different grouping, produce
   distinct framed inputs and therefore distinct outputs.  The full set
   of 38 combiner vectors, covering both KDF classes and every SEAL
   label, is published byte-for-byte as raae-v1-combiner-kdf-
   vectors.json in the draft repository.  All blocks below use ikm equal
   to a single 32-octet element of 0xAA.  Hexadecimal values wrap at 16
   octets per line.

   The first pair frames the same five info octets 01 02 03 04 05 two
   ways.  Because encode length-prefixes each element, the two
   expand_info values differ, so the outputs differ.  The second pair
   shows that the empty sequence and a one-element sequence whose
   element is the empty octet string are distinct.  The third pair
   repeats the distinction in the one-step form, where encode(...ikm)
   and encode(...info) are each a single nested element of the message.

  KDF.29  HKDF-SHA-256, label "commit"  (info = [010203, 0405])
    expand_info = encode(protocol_id, "commit", ...info,
                       I2OSP(32, 2)):
      000a5345414c2d52572d76310006636f
      6d6d6974000301020300020405000200
      20
    output (32 octets):
      0dfb8948fcc220f61f43f291648903b7
      1fe6e5208647b6e18d3308f59fca0fa0

  KDF.30  HKDF-SHA-256, label "commit"  (info = [0102, 030405])
    expand_info = encode(protocol_id, "commit", ...info,
                       I2OSP(32, 2)):

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

      000a5345414c2d52572d76310006636f
      6d6d6974000201020003030405000200
      20
    output (32 octets):
      299aa40869ae880bc8a064bb5afe38c4
      13f420ff30bcbfac7651d5e248b3db98

  KDF.8  HKDF-SHA-256, label "commit"  (info = [], the empty sequence)
    expand_info = encode(protocol_id, "commit", ...info,
                       I2OSP(32, 2)):
      000a5345414c2d52572d76310006636f
      6d6d697400020020
    output (32 octets):
      90073e3e9f1c855c2b7460e851f75d1a
      063a1daf007f81e4a695da1a0f97fca6

  KDF.28  HKDF-SHA-256, label "commit"  (info = [""], one empty element)
    expand_info = encode(protocol_id, "commit", ...info,
                       I2OSP(32, 2)):
      000a5345414c2d52572d76310006636f
      6d6d6974000000020020
    output (32 octets):
      5a4b4b2d59f5989c598f05a0a448acda
      faf27e10914c3894430ee7482c9a1913

  KDF.33  TurboSHAKE-256, label "commit"  (info = [010203, 0405])
    encoded_input = encode(protocol_id, "commit",
                         encode(...ikm), encode(...info),
                         I2OSP(64, 2)):
      000a5345414c2d52572d76310006636f
      6d6d697400220020aaaaaaaaaaaaaaaa
      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      aaaaaaaaaaaaaaaa0009000301020300
      02040500020040
    output (64 octets):
      dcefbcdced8b413e18303d2ffe1cac63
      44ee71b13324caa91d1712efc6b81ca8
      9ce2b62ce3aedde0ed16e14d7d17e2f2
      bc69f5e856eb96f9e4845f8522b0a9b5

  KDF.34  TurboSHAKE-256, label "commit"  (info = [0102, 030405])
    encoded_input = encode(protocol_id, "commit",
                         encode(...ikm), encode(...info),
                         I2OSP(64, 2)):
      000a5345414c2d52572d76310006636f
      6d6d697400220020aaaaaaaaaaaaaaaa
      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      aaaaaaaaaaaaaaaa0009000201020003

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

      03040500020040
    output (64 octets):
      02958e6256193c71b0cc4b8ac3273b31
      15d1ac30fd9aab537ad6916206be9828
      9146b56526054b3c11e22f2c375d0b24
      43e8d2ad2e6a89b874aa9ef4ce2c9c77

E.4.  Single Segment, AES-256-GCM, HKDF-SHA-256, 65536

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       9285553e10209c27bb5858b621426513
       b0832f26d7ee813d9dd62c218ce6972a
     payload_key  (32 octets):
       bb78da70d5e99d36c78e8a8b1a79b620
       e4a4250dd6b471024c379917dfbb2de7
     snap_key     (32 octets):
       953950ab75bdefd67ef15bbd7665b8af
       d3c9ced50ce7cb369e789606fc455025

   Segment 0 (is_final=1):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000101

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

     ciphertext   (12 octets):
       1815f12b13f7ee2532f0fcca
     tag          (16 octets):
       df4b1428af3c5ecb6d804159fec249e0
     contrib      (32 octets):
       73e62d2574a38dc44b406a0c2f2d57b1
       2b7ca777b053cdbb4e9d6f1b3257991a

   accumulator  (32 octets):
       73e62d2574a38dc44b406a0c2f2d57b1
       2b7ca777b053cdbb4e9d6f1b3257991a
   mask         (32 octets):
       dfd59806ded61dbf83bab8a7e143da0e
       01714d207c2f53af86e00c875590093b
   wrapped_acc  (32 octets):
       ac33b523aa75907bc8fad2abce6e8dbf
       2a0dea57cc7c9e14c87d639c67c79021
   snapshot_tag (32 octets):
       5a7713eab7ce2f7f246647aa407e14fa
       f295a04333f06c27cdc1193252a9b8bc

E.5.  Single Segment, ChaCha20-Poly1305, HKDF-SHA-256, 16384

   Parameter set:
     cipher suite:
       aead_id       0x001d  (AEAD_CHACHA20_POLY1305)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   16384
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 001d
     segment_max_be  ( 4 octets): 00004000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       9ef7166bbce42787fd834f79d29f85b6

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

       6a050b24f372ecfb79a66b3f2fdc1acb
     payload_key  (32 octets):
       d0f1d392a371642db684a23858c0193c
       2d7406cb4360c81ef9190391cacf885f
     snap_key     (32 octets):
       b156708dc559791d78014bae5e01b5fd
       f8a397c2d140fd9b9468e3cceeb8aa5d

   Segment 0 (is_final=1):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000101
     ciphertext   (12 octets):
       f1d968bc047a7bf6a15ef400
     tag          (16 octets):
       567deca2d91b732fd1f814a65335df79
     contrib      (32 octets):
       235bfbd70b8ce751d3720bea8351f039
       dac89c0055d817a5b949a8582c590035

   accumulator  (32 octets):
       235bfbd70b8ce751d3720bea8351f039
       dac89c0055d817a5b949a8582c590035
   mask         (32 octets):
       3beeed96dd10cd4bc3ec5f439a789d84
       acd1542b0edabd0c48c1bfb4766af53e
   wrapped_acc  (32 octets):
       18b51641d69c2a1a109e54a919296dbd
       7619c82b5b02aaa9f18817ec5a33f50b
   snapshot_tag (32 octets):
       b7a4b41dfb8de76d9ebaf0833f72d03b
       277bab9453c9085553dee456c998f4b7

E.6.  Single Segment, ChaCha20-Poly1305, HKDF-SHA-256, 65536

   Parameter set:
     cipher suite:
       aead_id       0x001d  (AEAD_CHACHA20_POLY1305)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

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

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 001d
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       ed76666a233fc9724c82f209aea191fa
       bdf8e65f12fa97f0a4e317839ee56f19
     payload_key  (32 octets):
       a859c3a684d35378bbbcf7ed48286313
       3e3af8d2cbf8d40687d693243c32cdea
     snap_key     (32 octets):
       aa42a852946818754780e48a9209a451
       345367bd07a04ad794c62a703366aa90

   Segment 0 (is_final=1):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000101
     ciphertext   (12 octets):
       db9cf72ba226e3210aa9fcb5
     tag          (16 octets):
       f5048c0d08372770fe066f2b5c052ab8
     contrib      (32 octets):
       aec6ba40c8e7234e704d3a689866dcb0
       efb84a6f0c75e27ea45756486d2b9a72

   accumulator  (32 octets):
       aec6ba40c8e7234e704d3a689866dcb0
       efb84a6f0c75e27ea45756486d2b9a72
   mask         (32 octets):
       b372584c8a52e2daec61e6b3b2740b87
       c56913270ebf83456636645bccbd125c
   wrapped_acc  (32 octets):
       1db4e20c42b5c1949c2cdcdb2a12d737
       2ad1594802ca613bc2613213a196882e
   snapshot_tag (32 octets):
       2eb1e1d010fa697a4c577445e36aacc6
       3cfbaafc893b8cd6730099c560d3524a

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

E.7.  Single Segment, AEGIS-256, HKDF-SHA-256, 16384

   Parameter set:
     cipher suite:
       aead_id       0x0021  (AEAD_AEGIS256)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   16384
     operational:
       epoch_length  63
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0021
     segment_max_be  ( 4 octets): 00004000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 3f
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       c4e0d853da06a0d7da0f062952ce8c1d
       c9936ec06b883accd2117aed9475f0cb
     payload_key  (32 octets):
       7b69e4c6a70d806c97315c4f37e698f8
       ad104677c20b4336ad81c9de7544246a
     snap_key     (32 octets):
       fb987468cf2e7f1321b8130b68933c7f
       039a39b0606fc7bc106d3169a9323d73

   Segment 0 (is_final=1):
     nonce        (32 octets):
       05050505050505050505050505050505
       05050505050505050505050505050505
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000101
     ciphertext   (12 octets):
       91c6c2100dd9d365e5a6df47
     tag          (16 octets):
       f48dd988d409eb7b90b4fe6447ec7b25
     contrib      (32 octets):
       176e02c54d994c99f50928a7c67386fb

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

       ea17424dbcf70230e9f4bea73f5265a4

   accumulator  (32 octets):
       176e02c54d994c99f50928a7c67386fb
       ea17424dbcf70230e9f4bea73f5265a4
   mask         (32 octets):
       5e9bb90f0671afe58fb72584dce62ae6
       6bfaa33159a97eefc2de2304c8b2528a
   wrapped_acc  (32 octets):
       49f5bbca4be8e37c7abe0d231a95ac1d
       81ede17ce55e7cdf2b2a9da3f7e0372e
   snapshot_tag (32 octets):
       cb35b42e68a265b2c6a09de9b381044b
       29f46e98342a44f6eaae3eb8f7470789

E.8.  Single Segment, AEGIS-256, HKDF-SHA-256, 65536

   Parameter set:
     cipher suite:
       aead_id       0x0021  (AEAD_AEGIS256)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  63
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0021
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 3f
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       6bb3b3000bbdba28de3a8fcf29fd862e
       094e2e28c6df0d677aeba07ab747fe18
     payload_key  (32 octets):
       425c1db85e1d3c85025ab41d5e263db9
       c4969b4599942fa582d2394f0c5870e4
     snap_key     (32 octets):
       4bb7fb2a1e5036cbe9aa018af5b5fe56

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

       2fd60a1c388c54168621a40530ae4237

   Segment 0 (is_final=1):
     nonce        (32 octets):
       05050505050505050505050505050505
       05050505050505050505050505050505
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000101
     ciphertext   (12 octets):
       f53c634ccf8aab1157fa44fd
     tag          (16 octets):
       90b6fa24f3cd9cb2b18574536f7bfdfc
     contrib      (32 octets):
       0b649e2b2702281a67ac5ab72c4b8e68
       afbe4135ee9a5fe693f34b6383377a24

   accumulator  (32 octets):
       0b649e2b2702281a67ac5ab72c4b8e68
       afbe4135ee9a5fe693f34b6383377a24
   mask         (32 octets):
       462e3c1a58d6f5f665988d3a28769729
       3bb3fa914b43a3d99b69da1b9491d1a3
   wrapped_acc  (32 octets):
       4d4aa2317fd4ddec0234d78d043d1941
       940dbba4a5d9fc3f089a917817a6ab87
   snapshot_tag (32 octets):
       34303daf7ba4f37eeddd4fd2bb382bb2
       439ceaecb5c240fc2839e2602d3a7d33

E.9.  Two Segment, AES-256-GCM, HKDF-SHA-256, 16384

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   16384
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00004000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001

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

     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       47ea0ec7409b9b95d676019917a19f1c
       5831eb236aba459063458e525d130d0c
     payload_key  (32 octets):
       c1f2663e99977428dc0fec1566ce15e9
       1398634ab9b1d004945de48560707062
     snap_key     (32 octets):
       bc314ecaa8ff6c1c4ebc13b54597a10d
       2bcf412b40c428a0e411a828fcfb52ef

   Segment 0 (is_final=0):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       6a2b84e72ce8edbf4259eebd
     tag          (16 octets):
       1574936244d54aedf589c87002dbac90
     contrib      (32 octets):
       322c4622cd9f50552740d1eee7a530eb
       3fd371e44178b8ce18816b53dd3f1587
   Segment 1 (is_final=1):
     nonce        (12 octets):
       070707070707070707070707
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       50b0eda5d7a86a5a94e501f317020173
       6d755d56
     tag          (16 octets):
       f22fb2b4bfed679d1d90d2a0814e429c
     contrib      (32 octets):
       7455e0472187dcd04a5747d508587a8c
       9f3e281818188be0edd46be8e32d4a6e

   accumulator  (32 octets):
       4679a665ec188c856d17963beffd4a67
       a0ed59fc5960332ef55500bb3e125fe9

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

   mask         (32 octets):
       ad55f19bb8997c8ad0def92830f0ce09
       4542ec804f7b99e66f294164985979a8
   wrapped_acc  (32 octets):
       eb2c57fe5481f00fbdc96f13df0d846e
       e5afb57c161baac89a7c41dfa64b2641
   snapshot_tag (32 octets):
       a08c73b5c414542cc06830d893d0eaca
       c749418dea32b11d5cc121d6b2db93b8

E.10.  Two Segment, AES-256-GCM, HKDF-SHA-256, 65536

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       9285553e10209c27bb5858b621426513
       b0832f26d7ee813d9dd62c218ce6972a
     payload_key  (32 octets):
       bb78da70d5e99d36c78e8a8b1a79b620
       e4a4250dd6b471024c379917dfbb2de7
     snap_key     (32 octets):
       953950ab75bdefd67ef15bbd7665b8af
       d3c9ced50ce7cb369e789606fc455025

   Segment 0 (is_final=0):
     nonce        (12 octets):
       030303030303030303030303

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

     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       1815f12b13f7ee2532f0fcca
     tag          (16 octets):
       2597e2f2243b98c4bb7f320dc2f46ce3
     contrib      (32 octets):
       0d8b3cb23192377e88232945f623150b
       1a1c0b61745a4fa39a5f65e162b6e672
   Segment 1 (is_final=1):
     nonce        (12 octets):
       070707070707070707070707
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       f17c9cac3693dcb4bdd524714da804d4
       c4390056
     tag          (16 octets):
       97d4f0d1303a2b112eac5aae081ef6bf
     contrib      (32 octets):
       a8e8df627852127e058558353da2def9
       9a83928b4c96ef37a5d0b08068b1a87c

   accumulator  (32 octets):
       a563e3d049c025008da67170cb81cbf2
       809f99ea38cca0943f8fd5610a074e0e
   mask         (32 octets):
       946a2744cf3fd572a03993d434705704
       47d1ce03f4769035a5058780660e5eff
   wrapped_acc  (32 octets):
       3109c49486fff0722d9fe2a4fff19cf6
       c74e57e9ccba30a19a8a52e16c0910f1
   snapshot_tag (32 octets):
       5ce50c9e90db4bbc28297372e401625c
       2e43203ce8008c452ea4355f0941ef67

E.11.  Two Segment, ChaCha20-Poly1305, HKDF-SHA-256, 16384

   Parameter set:
     cipher suite:
       aead_id       0x001d  (AEAD_CHACHA20_POLY1305)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   16384
     operational:
       epoch_length  1

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

       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 001d
     segment_max_be  ( 4 octets): 00004000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       9ef7166bbce42787fd834f79d29f85b6
       6a050b24f372ecfb79a66b3f2fdc1acb
     payload_key  (32 octets):
       d0f1d392a371642db684a23858c0193c
       2d7406cb4360c81ef9190391cacf885f
     snap_key     (32 octets):
       b156708dc559791d78014bae5e01b5fd
       f8a397c2d140fd9b9468e3cceeb8aa5d

   Segment 0 (is_final=0):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       f1d968bc047a7bf6a15ef400
     tag          (16 octets):
       0359d2adbe709e374e6fae7830001295
     contrib      (32 octets):
       92c78ada192f60346b35491986711454
       9e20d72ede4b78a9567cf414365bc781
   Segment 1 (is_final=1):
     nonce        (12 octets):
       070707070707070707070707
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       4d8f7a1b6aa589808c384a52bd90e4d0
       a44ed35e
     tag          (16 octets):

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

       61c3caca0ecda929269f52978f4a60e1
     contrib      (32 octets):
       85db0789dfd84dfaeb095fc28101d929
       af58800d6ae8882353c83c9a6013492c

   accumulator  (32 octets):
       171c8d53c6f72dce803c16db0770cd7d
       31785723b4a3f08a05b4c88e56488ead
   mask         (32 octets):
       e399bc51986eaf7f8d7cbcb3e76da43a
       b9607c01e413dd462639c4fd50191f32
   wrapped_acc  (32 octets):
       f48531025e9982b10d40aa68e01d6947
       88182b2250b02dcc238d0c730651919f
   snapshot_tag (32 octets):
       f4bfbdff53178451463ef23c73a31ab5
       06a6acfb49282af14598b2f49f32ceeb

E.12.  Two Segment, ChaCha20-Poly1305, HKDF-SHA-256, 65536

   Parameter set:
     cipher suite:
       aead_id       0x001d  (AEAD_CHACHA20_POLY1305)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 001d
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       ed76666a233fc9724c82f209aea191fa
       bdf8e65f12fa97f0a4e317839ee56f19
     payload_key  (32 octets):
       a859c3a684d35378bbbcf7ed48286313

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

       3e3af8d2cbf8d40687d693243c32cdea
     snap_key     (32 octets):
       aa42a852946818754780e48a9209a451
       345367bd07a04ad794c62a703366aa90

   Segment 0 (is_final=0):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       db9cf72ba226e3210aa9fcb5
     tag          (16 octets):
       6423011bc81f13a30ef51ff32f209cff
     contrib      (32 octets):
       fab6f671b544bb356337a2b811475663
       cc5fab22c29a6770c6cd035bc44d0554
   Segment 1 (is_final=1):
     nonce        (12 octets):
       070707070707070707070707
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       85ead0c3a974dd014622ec0e2ba9a6e6
       199a7b88
     tag          (16 octets):
       3ee3399f906110b8e7900805f2b72a85
     contrib      (32 octets):
       361a4ce5127403db2e54950d48a81af1
       a71913771db2885bcb6bcdab971a3611

   accumulator  (32 octets):
       ccacba94a730b8ee4d6337b559ef4c92
       6b46b855df28ef2b0da6cef053573345
   mask         (32 octets):
       b62dbfa20e0725e6cc0bb81b169f6294
       a8b1d7b94968ac589c9b7ebcffc37882
   wrapped_acc  (32 octets):
       7a810536a9379d0881688fae4f702e06
       c3f76fec96404373913db04cac944bc7
   snapshot_tag (32 octets):
       e0b3b1cadba56bb4994d7872b57aff7f
       42215a8e2b7a2241cffd5107f571d560

E.13.  Two Segment, AEGIS-256, HKDF-SHA-256, 16384

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

   Parameter set:
     cipher suite:
       aead_id       0x0021  (AEAD_AEGIS256)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   16384
     operational:
       epoch_length  63
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0021
     segment_max_be  ( 4 octets): 00004000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 3f
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       c4e0d853da06a0d7da0f062952ce8c1d
       c9936ec06b883accd2117aed9475f0cb
     payload_key  (32 octets):
       7b69e4c6a70d806c97315c4f37e698f8
       ad104677c20b4336ad81c9de7544246a
     snap_key     (32 octets):
       fb987468cf2e7f1321b8130b68933c7f
       039a39b0606fc7bc106d3169a9323d73

   Segment 0 (is_final=0):
     nonce        (32 octets):
       05050505050505050505050505050505
       05050505050505050505050505050505
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       91c6c2100dd9d365e5a6df47
     tag          (16 octets):
       c4837c14751196e622301d3e8a5e00b2
     contrib      (32 octets):
       002805d6180149a3852b8afd82b40db9
       4d4e2af23a11bfb1e2922e5e3efb4210
   Segment 1 (is_final=1):

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

     nonce        (32 octets):
       09090909090909090909090909090909
       09090909090909090909090909090909
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       006704b222fa9285da01b706be831b76
       ead7332c
     tag          (16 octets):
       9965b57015a2b058514fb1fca7708242
     contrib      (32 octets):
       f1edcc4f336fb96b7319d30bca9a9194
       e6795e34a3a0b19652521d749dd2e767

   accumulator  (32 octets):
       f1c5c9992b6ef0c8f63259f6482e9c2d
       ab3774c699b10e27b0c0332aa329a577
   mask         (32 octets):
       0affb88aa98af47cf91aa6c80b733679
       070bc7b44df36f22859f0c89a91a3cc9
   wrapped_acc  (32 octets):
       fb3a711382e404b40f28ff3e435daa54
       ac3cb372d4426105355f3fa30a3399be
   snapshot_tag (32 octets):
       3d8899806c647a198c1c4e23f6ce8a2e
       be5d8cba11d65a16bbd2e7d5c4f415fc

E.14.  Two Segment, AEGIS-256, HKDF-SHA-256, 65536

   Parameter set:
     cipher suite:
       aead_id       0x0021  (AEAD_AEGIS256)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  63
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0021
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 3f

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

     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       6bb3b3000bbdba28de3a8fcf29fd862e
       094e2e28c6df0d677aeba07ab747fe18
     payload_key  (32 octets):
       425c1db85e1d3c85025ab41d5e263db9
       c4969b4599942fa582d2394f0c5870e4
     snap_key     (32 octets):
       4bb7fb2a1e5036cbe9aa018af5b5fe56
       2fd60a1c388c54168621a40530ae4237

   Segment 0 (is_final=0):
     nonce        (32 octets):
       05050505050505050505050505050505
       05050505050505050505050505050505
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       f53c634ccf8aab1157fa44fd
     tag          (16 octets):
       c466896ca6da6509959b1c0c10dd688d
     contrib      (32 octets):
       e558127502262f71ac5ce07b9e0e101f
       177a5428a10ecb464cfcd731d75b35fe
   Segment 1 (is_final=1):
     nonce        (32 octets):
       09090909090909090909090909090909
       09090909090909090909090909090909
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       40865396160e5aa905a96d3a6552f6cc
       fecf30ec
     tag          (16 octets):
       ddd6e4979a6d648400b236abc617d033
     contrib      (32 octets):
       23f4cfab2a5601a75d7f87148c5f32fd
       d8ab5ac1a16d25c9688e61b7d09171bb

   accumulator  (32 octets):
       c6acddde28702ed6f123676f125122e2
       cfd10ee90063ee8f2472b68607ca4445

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

   mask         (32 octets):
       8d8832a7c865352b6ebcfabaa1c85c69
       0aacfbfb2bf08a73cc090281bea1ca42
   wrapped_acc  (32 octets):
       4b24ef79e0151bfd9f9f9dd5b3997e8b
       c57df5122b9364fce87bb407b96b8e07
   snapshot_tag (32 octets):
       016300d12db61dc1b6b11fbeee8ecaf8
       614efe5802f3fc919ab8aa665cdf9294

E.15.  TurboSHAKE-256 Cipher Suite Vectors

   These two vectors exercise the one-step TurboSHAKE-256 cipher suite
   (Table 10), for which Nh = 64.  The commitment, snap_key, contrib,
   the accumulator, and the snapshot tag are therefore 64 octets, while
   payload_key (Nk) and the nonces (Nn) are unchanged.

E.15.1.  Single Segment, AES-256-GCM, TurboSHAKE-256, 65536

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0013  (TurboSHAKE-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0013
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (64 octets):
       b19991b71ed275d98070eab735179d60
       be397354a85f6d6f58e74dcb90f0ff43
       8271da594a267d81aaa74a88736ba549
       d9e88c1b9d9a972135220b76c9568483
     payload_key  (32 octets):

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

       bdecddf1340029c520b9b4a9e1b15144
       d283209261a58113294728e337d14ea8
     snap_key     (64 octets):
       92fc2e47ac72bbdbcac62a67ced07dad
       a1e907bd82e92a68ba5f6098ec067931
       e59683904d5213ddd0abe237ac0f9450
       ef33180028f2ea7e47d738e6f3faed01

   Segment 0 (is_final=1):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000101
     ciphertext   (12 octets):
       429b98993decaa7c1792d52d
     tag          (16 octets):
       be8cd796db427f283859fa6722708d5b
     contrib      (64 octets):
       371669ebb5f158b73bd65f0f66a33878
       3e2372d1cbfced76ff866e264fb6c85f
       151dcdf2662d286cc065844a2b5aff57
       200d689ad4ee7d027df20be43747bbf2

   accumulator  (64 octets):
       371669ebb5f158b73bd65f0f66a33878
       3e2372d1cbfced76ff866e264fb6c85f
       151dcdf2662d286cc065844a2b5aff57
       200d689ad4ee7d027df20be43747bbf2
   mask         (64 octets):
       39bc62cc8b75a8745da4cf36061350a1
       a1c439359cde43df5355ce7c8527cb0f
       23dbf74cd0534517d729fc1ebad29d15
       b27c8f0373ca74ccc7a19de9e174ce39
   wrapped_acc  (64 octets):
       0eaa0b273e84f0c36672903960b068d9
       9fe74be45722aea9acd3a05aca910350
       36c63abeb67e6d7b174c785491886242
       9271e799a72409ceba53960dd63375cb
   snapshot_tag (64 octets):
       75dd576b0a3f5ba7181b3e183e6ef741
       b1e7ea93a7852fc0c7657ed905f74eb6
       45570ac0b639c2f901797f1152c8c7d4
       196aed0cf4af2308431af242399b0c22

E.15.2.  Two Segment, AES-256-GCM, TurboSHAKE-256, 65536

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

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0013  (TurboSHAKE-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0013
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (64 octets):
       b19991b71ed275d98070eab735179d60
       be397354a85f6d6f58e74dcb90f0ff43
       8271da594a267d81aaa74a88736ba549
       d9e88c1b9d9a972135220b76c9568483
     payload_key  (32 octets):
       bdecddf1340029c520b9b4a9e1b15144
       d283209261a58113294728e337d14ea8
     snap_key     (64 octets):
       92fc2e47ac72bbdbcac62a67ced07dad
       a1e907bd82e92a68ba5f6098ec067931
       e59683904d5213ddd0abe237ac0f9450
       ef33180028f2ea7e47d738e6f3faed01

   Segment 0 (is_final=0):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       429b98993decaa7c1792d52d
     tag          (16 octets):
       c2afc8ba9d2d163d600a88ed34420cc8
     contrib      (64 octets):

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

       97b151445a7f50b4f41811e8b9d0f4c9
       04648ba6d13085e7d7180d94321aa3f8
       4f895847053ce9c66e4b27f4251f6ffc
       356e72ec1a867e2b405163732b65b8c1
   Segment 1 (is_final=1):
     nonce        (12 octets):
       070707070707070707070707
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       7597ac827f175c664e7bebb8b828753b
       fc778463
     tag          (16 octets):
       78545349b2e5092b9d279c97abfe1511
     contrib      (64 octets):
       df8a6116f5535741f7973cfbb2aa6ef0
       78f54da534fea79f953ef95b6a60c5d8
       eaa6a034c9dc8186f27726ae99772694
       0cb46e83581e1466f34a46a76abbca41

   accumulator  (64 octets):
       483b3052af2c07f5038f2d130b7a9a39
       7c91c603e5ce22784226f4cf587a6620
       a52ff873cce068409c3c015abc684968
       39da1c6f42986a4db31b25d441de7280
   mask         (64 octets):
       49cc05dd25532375d143f69b276b0b8d
       5246388217b39b7ef2262b6e7f293fdc
       a43408f13b9172cb3e98a72c735d2546
       e15b860122ebea099a7cbd987bfee991
   wrapped_acc  (64 octets):
       01f7358f8a7f2480d2ccdb882c1191b4
       2ed7fe81f27db906b000dfa1275359fc
       011bf082f7711a8ba2a4a676cf356c2e
       d8819a6e607380442967984c3a209b11
   snapshot_tag (64 octets):
       f6b15b8cf01fd11587f9fe7a32185abe
       31ac84194ae3eed199a5b19ba83b0cdf
       bf0c8e3b4f48199b01bdd1710d87c076
       9d0cdc82f5292a913b7f1d14cd93b843

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

E.16.  Segment Rewrite Vector

   This vector applies RewriteSegment (Section 4.9.2.1) to segment 0 of
   a two-segment AES-256-GCM message, replacing its plaintext under a
   fresh nonce.  acc_delta = old_contrib XOR new_contrib, the new
   accumulator is the old accumulator XOR acc_delta, and the snapshot
   tag is recomputed over the count and the new accumulator.

E.16.1.  Two Segment, AES-256-GCM, HKDF-SHA-256, 65536 (Rewrite)

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  1
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 01
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       9285553e10209c27bb5858b621426513
       b0832f26d7ee813d9dd62c218ce6972a
     payload_key  (32 octets):
       bb78da70d5e99d36c78e8a8b1a79b620
       e4a4250dd6b471024c379917dfbb2de7
     snap_key     (32 octets):
       953950ab75bdefd67ef15bbd7665b8af
       d3c9ced50ce7cb369e789606fc455025

   Segment 0 (is_final=0):
     nonce        (12 octets):
       030303030303030303030303
     segment_aad  (24 octets):
       00095345414c2d444154410008000000

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

       0000000000000100
     ciphertext   (12 octets):
       1815f12b13f7ee2532f0fcca
     tag          (16 octets):
       2597e2f2243b98c4bb7f320dc2f46ce3
     contrib      (32 octets):
       0d8b3cb23192377e88232945f623150b
       1a1c0b61745a4fa39a5f65e162b6e672
   Segment 1 (is_final=1):
     nonce        (12 octets):
       070707070707070707070707
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       f17c9cac3693dcb4bdd524714da804d4
       c4390056
     tag          (16 octets):
       97d4f0d1303a2b112eac5aae081ef6bf
     contrib      (32 octets):
       a8e8df627852127e058558353da2def9
       9a83928b4c96ef37a5d0b08068b1a87c

   accumulator  (32 octets):
       a563e3d049c025008da67170cb81cbf2
       809f99ea38cca0943f8fd5610a074e0e
   mask         (32 octets):
       946a2744cf3fd572a03993d434705704
       47d1ce03f4769035a5058780660e5eff
   wrapped_acc  (32 octets):
       3109c49486fff0722d9fe2a4fff19cf6
       c74e57e9ccba30a19a8a52e16c0910f1
   snapshot_tag (32 octets):
       5ce50c9e90db4bbc28297372e401625c
       2e43203ce8008c452ea4355f0941ef67

   Rewrite of segment 0:
     new_nonce    (12 octets):
       0b0b0b0b0b0b0b0b0b0b0b0b
     new_ciphertext (22 octets):
       f20adfd4e5ab8016903d7eaa022f65c7
       0a3f9988b1e5
     new_tag      (16 octets):
       ff3268f44b36f41c84a2e85d0a975d38
     old_contrib  (32 octets):
       0d8b3cb23192377e88232945f623150b
       1a1c0b61745a4fa39a5f65e162b6e672
     new_contrib  (32 octets):

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

       d1799e445a84608aae7dfca35bc03813
       138fd92f58adb6c1fec48907e9a90f9e
     acc_delta    (32 octets):
       dcf2a2f66b1657f4265ed5e6ade32d18
       0993d24e2cf7f962649bece68b1fe9ec
     new_accumulator (32 octets):
       7991412622d672f4abf8a4966662e6ea
       890c4ba4143b59f65b1439878118a7e2
     new_mask        (32 octets):
       76615f532f527eaecac7d2fa4232fc32
       10596f72a1e2637cfbb5db656d53c9ac
     new_wrapped_acc (32 octets):
       0ff01e750d840c5a613f766c24501ad8
       995524d6b5d93a8aa0a1e2e2ec4b6e4e
     new_snapshot_tag (32 octets):
       bba55e58311ebbd38d7880a9ebec3d19
       3212c0600ce04aeeb7c18ee62e33b9cc

E.17.  Derived-Nonce Cipher Suite Vector

   This vector exercises AES-256-GCM-SIV (Table 9), the MRAE cipher
   suite that uses derived nonce mode.  There is no stored per-segment
   nonce: each nonce is recomputed from nonce_base by the formula in
   Section 4.5.3.2, which XORs uint64((i << 1) | is_final), the segment
   index and finality bit, into the low 8 octets of nonce_base (here Nn
   = 12).  The block applies RewriteSegment to segment 0.  Because the
   nonce is recomputed deterministically, the rewrite reuses the same
   nonce as the original segment 0.  AES-256-GCM-SIV is misuse-
   resistant, so the reuse leaks only equality of identical plaintext-
   and-context pairs, not plaintext.

E.17.1.  Two Segment, AES-256-GCM-SIV, HKDF-SHA-256, 65536 (Rewrite)

   Parameter set:
     cipher suite:
       aead_id       0x001f  (AEAD_AES_256_GCM_SIV)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  0
       nonce_mode    derived
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 001f
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001

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

     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 01
     epoch_length_u8 ( 1 octets): 00
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       bf20f8c7691934f0ccf767b2a5ac19e4
       67228674414f68d839a6698a3edd1813
     payload_key  (32 octets):
       d2f4ae67c4024a3b61b902188a75cdc4
       757245350393608e8d4af530b91a4411
     snap_key     (32 octets):
       18e303acfa725f11d6a75a48723fb408
       c481e5703032b0e5f1724461f8901bbc
     nonce_base   (12 octets):
       8a2860a4c1e733427aaa7aeb

   Segment 0 (is_final=0):
     nonce        (12 octets):  (derived from nonce_base, not stored)
       8a2860a4c1e733427aaa7aeb
     epoch_key    (32 octets):
       a65f10ea805ada25b9f1ef7527383cde
       423b104e8813edaed5490747633291c6
     segment_key  (32 octets):
       a65f10ea805ada25b9f1ef7527383cde
       423b104e8813edaed5490747633291c6
     segment_aad  ( 0 octets): (empty)
     ciphertext   (12 octets):
       b3b34ccfb3481851057f1eab
     tag          (16 octets):
       2d143f398a84cdfd47146c194e1c177c
     contrib      (32 octets):
       fce4eed2d488b1ee8994c270cd145202
       ea63b9fd0c0f7401c5cad41c767e91c6
   Segment 1 (is_final=1):
     nonce        (12 octets):  (derived from nonce_base, not stored)
       8a2860a4c1e733427aaa7ae8
     epoch_key    (32 octets):
       3cd69f36c405895994a14b8b5aafaf09
       09517de95d17e6b903cf350fa8769826
     segment_key  (32 octets):
       3cd69f36c405895994a14b8b5aafaf09
       09517de95d17e6b903cf350fa8769826
     segment_aad  ( 0 octets): (empty)
     ciphertext   (20 octets):

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

       3392acaffbaaa0224644ee4b0efa53ad
       c0d21628
     tag          (16 octets):
       408046d4fb0789a8ae0c41ddb0f66fc3
     contrib      (32 octets):
       7e2e00b404bf5962b6220c4196298f4b
       d25bff62bd9e3230ddd0d344e2b78cc1

   accumulator  (32 octets):
       82caee66d037e88c3fb6ce315b3ddd49
       3838469fb1914631181a075894c91d07
   mask         (32 octets):
       b0c48fd39186cb0b55dd036ffd1c46ef
       73c6b282977ecd28e6065cdcc64e36d2
   wrapped_acc  (32 octets):
       320e61b541b123876a6bcd5ea6219ba6
       4bfef41d26ef8b19fe1c5b8452872bd5
   snapshot_tag (32 octets):
       44dea9b3ed7c07f3e95bfe10848430f3
       cc1059251c3cf85d2c2e717634155aaf

   Rewrite of segment 0:
     new_nonce    (12 octets):
       8a2860a4c1e733427aaa7aeb
     new_ciphertext (22 octets):
       f1cb96bd31369de3d8f26e007bf71759
       51a0c59330b0
     new_tag      (16 octets):
       74105b3b59dd624421f67f295921841d
     old_contrib  (32 octets):
       fce4eed2d488b1ee8994c270cd145202
       ea63b9fd0c0f7401c5cad41c767e91c6
     new_contrib  (32 octets):
       64064c4b612f62cafad57b458158d125
       08164dc2bef7594568a978f6f2a1ae55
     acc_delta    (32 octets):
       98e2a299b5a7d3247341b9354c4c8327
       e275f43fb2f82d44ad63acea84df3f93
     new_accumulator (32 octets):
       1a284cff65903ba84cf7770417715e6e
       da4db2a003696b75b579abb210162294
     new_mask        (32 octets):
       5f4185e7b2b940639b4fa672174edf71
       a88c8015423ed35d14134b1741d869a2
     new_wrapped_acc (32 octets):
       4569c918d7297bcbd7b8d176003f811f
       72c132b54157b828a16ae0a551ce4b36
     new_snapshot_tag (32 octets):

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

       a4ad2d7fa8abbbec998af5c3ced3514f
       e420923c403ba57771bad99a8d03034a

E.18.  Cross-Epoch Key Vector

   This vector sets epoch_length = 0, the finest epoch partition, so the
   epoch index equals the segment index and each segment is sealed under
   a distinct epoch key (Section 4.5.2).  The block exposes the
   intermediate epoch_key(i) and segment_key(i) for each segment.  At
   epoch_length = 0 the shift is the identity, so segment_key(i) equals
   epoch_key(i), and epoch_key(0) and epoch_key(1) differ.

E.18.1.  Two Segment, AES-256-GCM, HKDF-SHA-256, 65536, epoch_length 0

   Parameter set:
     cipher suite:
       aead_id       0x0002  (AEAD_AES_256_GCM)
       kdf_id        0x0001  (HKDF-SHA-256)
     geometry:
       segment_max   65536
     operational:
       epoch_length  0
       nonce_mode    random
       snap_id       0x0001  (masked multiset hash)

   payload_info (the KDF frames each element):
     aead_id         ( 2 octets): 0002
     segment_max_be  ( 4 octets): 00010000
     kdf_id          ( 2 octets): 0001
     snap_id         ( 2 octets): 0001
     nonce_mode      ( 1 octets): 00
     epoch_length_u8 ( 1 octets): 00
     salt            (32 octets):
       04040404040404040404040404040404
       04040404040404040404040404040404

   Payload schedule:
     commitment   (32 octets):
       248167fa761884de975ed84dd2464c7b
       0e85cfaf205470750ca644137da76517
     payload_key  (32 octets):
       e27e393efb0b8abec87b27fa0ae3f19c
       0f19093877aae8267d14be74b035eeb6
     snap_key     (32 octets):
       f152bcb8e03852f726a7824c902e9b4f
       aa9b849478cd115c1a3de02b8f04ddb8

   Segment 0 (is_final=0):

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

     nonce        (12 octets):
       030303030303030303030303
     epoch_key    (32 octets):
       cfe9ccdc21e8021fd5cada3fff397f2b
       86431ec14eb0ac60809e4aee4a497f36
     segment_key  (32 octets):
       cfe9ccdc21e8021fd5cada3fff397f2b
       86431ec14eb0ac60809e4aee4a497f36
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000000000100
     ciphertext   (12 octets):
       04b77b3d7370bf0ce5baeb78
     tag          (16 octets):
       4fd2abdb95a887e32aacced927ea7666
     contrib      (32 octets):
       22f6f5e04dc24fcd3ea57d2aab707c37
       7530de5b5cde77959c85888afe189675
   Segment 1 (is_final=1):
     nonce        (12 octets):
       070707070707070707070707
     epoch_key    (32 octets):
       c6b0ed6d72fe7fe3114623c98f527e3d
       3644cfdc88c56f6e4550495dc92b3fe2
     segment_key  (32 octets):
       c6b0ed6d72fe7fe3114623c98f527e3d
       3644cfdc88c56f6e4550495dc92b3fe2
     segment_aad  (24 octets):
       00095345414c2d444154410008000000
       0000000001000101
     ciphertext   (20 octets):
       550d0675f7ed31bf5377805fcf64bb30
       38167fe1
     tag          (16 octets):
       15c5bbacef49c9e0cc6f4a16a1fb0204
     contrib      (32 octets):
       e9341dfae1376b08122e20e8580b1e94
       7b771e1cf4b11cf5472868cc34a18870

   accumulator  (32 octets):
       cbc2e81aacf524c52c8b5dc2f37b62a3
       0e47c047a86f6b60dbade046cab91e05
   mask         (32 octets):
       4b770b765273b67eda59116abc4521c7
       28998adf914b868f6c94bcdda7f57910
   wrapped_acc  (32 octets):
       80b5e36cfe8692bbf6d24ca84f3e4364
       26de4a983924edefb7395c9b6d4c6715

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

   snapshot_tag (32 octets):
       7ec104576a2197294a35d2d28000331e
       30dc4172f1f18492950e15ef0c1f1742

E.19.  Plaintext-Bound Nonce Component Vectors

   These vectors exercise the optional plaintext-bound nonce
   construction (Appendix A) component by component: the plaintext
   digest pt_digest, the bound digest pt_hash, the framed nonce_ctx, and
   the final nonce.  The construction is encryptor-only and its output
   is indistinguishable from random mode on the wire, so no end-to-end
   vector exercises it; component values are the only way to check an
   implementation byte for byte.  The labels are those of Table 24, and
   nonce_ctx enters the final derivation as a single framed info element
   after the payload_info elements.

   Each block reuses the payload_key, payload_info, and salt of a
   published cipher-suite block, so the values chain into the payload
   schedules above.  The random_input value stands in for the fresh
   Random(Nn) draw of the construction, and both blocks bind the
   plaintext "Hello, SEAL!".  These component vectors are printed in
   this appendix only and are not part of the end-to-end corpus.

E.19.1.  AES-256-GCM, HKDF-SHA-256, 16384, Segment 0

   The payload schedule is that of Appendix E.1.

   plaintext    (12 octets):
       48656c6c6f2c205345414c21
   random_input (12 octets):
       0f0f0f0f0f0f0f0f0f0f0f0f
   pt_digest    (32 octets):
       e66fec4cada0ccdb73930622ef393d5b
       a05fb73bdd81205a9f828f75e85ded81
   pt_hash      (32 octets):
       072fa800d5069a226a7322c5b3fb704f
       8564fd2075dd9de6de274a2b5645faaa
   nonce_ctx    (56 octets):
       000a5345414c2d52572d763100080000
       0000000000000020072fa800d5069a22
       6a7322c5b3fb704f8564fd2075dd9de6
       de274a2b5645faaa
   nonce        (12 octets):
       ef044c5a935e8bd52db61582

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

E.19.2.  AES-256-GCM, TurboSHAKE-256, 65536, Segment 1

   The payload schedule is that of the single-segment TurboSHAKE-256
   block (Appendix E.15).  The segment index is 1, visible in the second
   framed element of nonce_ctx.

   plaintext    (12 octets):
       48656c6c6f2c205345414c21
   random_input (12 octets):
       0f0f0f0f0f0f0f0f0f0f0f0f
   pt_digest    (64 octets):
       f809e1b9b0e28d0fd1dce5cf9e4aae59
       fde2b08a551c311b621323a5d2f3c78d
       e55c22edcdd091231c4509849acf592a
       85ab446dfcff4fac008194e6ef59d9b4
   pt_hash      (64 octets):
       ad6a35f94960ee1004391bdfaee16149
       ef56bca4fd5b98abfec56fdb80752624
       ade63d71f3b15e9aa5dd9fb0ffa8e533
       f7ef5caa7620432cf1c1bf7d97611536
   nonce_ctx    (88 octets):
       000a5345414c2d52572d763100080000
       0000000000010040ad6a35f94960ee10
       04391bdfaee16149ef56bca4fd5b98ab
       fec56fdb80752624ade63d71f3b15e9a
       a5dd9fb0ffa8e533f7ef5caa7620432c
       f1c1bf7d97611536
   nonce        (12 octets):
       dbd450bb6f147795caeeee12

E.20.  Negative SnapVerify Vector

   This vector demonstrates the snapshot integrity check.  It takes the
   honest state of the two-segment AES-256-GCM, HKDF-SHA-256, 65536
   vector and flips the first octet of the stored masked accumulator,
   leaving the snapshot tag unchanged.  SnapVerify recomputes the
   snapshot from the two present segment tags (Section 4.7.4): the
   recomputed accumulator is the honest one, so the recomputed snapshot
   tag equals the stored tag, but the recomputed wrapped accumulator
   differs from the tampered one.  The single constant-time comparison
   of the full recomputed snapshot against the stored value therefore
   fails, and SnapVerify returns reject without revealing which half
   differed.  A consumer MUST treat this entry as expect-reject and MUST
   NOT accept it as a valid snapshot.

E.20.1.  Tampered Accumulator, Snapshot Tag Not Recomputed

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

   Source: the two-segment AES-256-GCM, HKDF-SHA-256, 65536 vector;
           the tamper flips the first octet of the stored masked
           accumulator, with the snapshot_tag left unchanged.

   tampered_accumulator (32 octets):
       a463e3d049c025008da67170cb81cbf2
       809f99ea38cca0943f8fd5610a074e0e
   mask                 (32 octets):
       946a2744cf3fd572a03993d434705704
       47d1ce03f4769035a5058780660e5eff
   tampered_wrapped_acc (32 octets):
       3009c49486fff0722d9fe2a4fff19cf6
       c74e57e9ccba30a19a8a52e16c0910f1
   snapshot_tag (32 octets):
       5ce50c9e90db4bbc28297372e401625c
       2e43203ce8008c452ea4355f0941ef67

   SnapVerify recomputes the snapshot from the present segment tags
   and compares it, whole, against the stored value in constant
   time. The recomputed wrapped accumulator differs from the stored
   tampered one, so the comparison fails.

   SnapVerify result: reject

Appendix F.  Changes from draft-sullivan-cfrg-raae-00

   This appendix is informative.  It summarizes the substantive changes
   from the -00 revision.

   *  SEAL: the -00 monolithic raAE-v1 profile became SEAL, a
      parameterized construction with two named profiles, SEAL-RW-v1
      (mutable) and SEAL-RO-v1 (write-once).  payload_info gained
      snap_id (the snapshot authenticator identifier) and dropped
      aad_label, segment_max is a power of two of at least 4096 octets,
      and the five named instantiations fix complete parameter sets and
      a serialization layout (Section 4.12).

   *  Structural split: the raAE primitive (Section 3), the SEAL
      construction that realizes it (Section 4), and the cipher suites
      (Section 4.10) are now specified separately.

   *  Snapshot authenticator (Section 4.7): -00 published the bare XOR
      accumulator as its whole-object check.  That design is superseded
      for a security reason: a write adversary can recombine observed
      accumulator differences into a non-historical segment set that
      still verifies (Appendix C.5), so the -00 snapshot offers no
      whole-object integrity against rewrites.  The replacement is the
      masked multiset hash: a snapshot tag MACs the count and

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

      accumulator, and a deterministic, tag-derived mask hides the
      accumulator, so the published value is wrapped_acc ||
      snapshot_tag.

   *  Wire format, code points: aead_id and kdf_id are now 2-octet IANA
      code points.

   *  Wire format, salt: the per-content salt is now a fixed 32 octets.

   *  Wire format, KDF output size: TurboSHAKE-256 uses Nh = 64.

   *  KDF framing: the KDF framing function is total, and the one-step
      form frames ikm and info each as one element.

   *  Security analysis: reorganized to be property-oriented.  The body
      states properties, assumptions, requirements, and operational
      limits.  The reductions, bounds, and proof symbols are in
      Appendix C, and the formal proofs are deferred to a companion
      paper in preparation.

   *  Integrity requirements: unauthorized truncation detection is a
      normative decryptor requirement, n_seg = 0 is disallowed without a
      snapshot authenticator, snapshot verification is required when all
      segment tags are available, commitment_length is at least 16
      octets, and the snapshot comparison is constant-time.

   *  SEAL-compact named instantiation: added SEAL-compact (SEAL-RW-v1,
      derived nonce, aligned layout), naming an already-buildable
      combination that gives large random-access objects compact per-
      segment metadata.  Byte-neutral.

   *  The wire-format and snapshot changes above are reflected in a
      regenerated test-vector corpus (Appendix E).

   *  Normative tightenings from implementation evidence: epoch-key
      derivation applies at every epoch_length and payload_key is never
      a segment key (Section 4.5.2), a SEAL-RO-v1 encryptor MUST NOT
      rewrite a written segment (Section 4.10.2), streamed plaintext is
      unverified for completeness until the terminal finality check
      (Section 4.9.1.2), and the SnapVerify comparison covers the full
      snapshot value in one constant-time comparison (Section 6.9).

   *  Presentation, from the same evidence: the plaintext-bound
      construction's labels are tabulated adjacent to the construction
      (Appendix A), the profiles state where truncation detection
      surfaces, and the layout size formulas carry Nt symbolically.

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

   *  Test vectors, from the same evidence: component vectors for the
      plaintext-bound nonce construction (Appendix E.19), a worked byte-
      layout example for the one-step KDF (Section 4.3.2), and
      regenerated TurboSHAKE-256 cipher-suite vectors matching the
      nested one-step framing this document specifies.

   *  Terminology: the interface extension is named the extended raAE
      interface throughout, replacing the earlier "mutable raAE"
      phrasing, so no text suggests two primitives named raAE.  Mutable
      and immutable now describe only the SEAL profiles' write
      discipline.

   *  Attribution: the introduction credits the base interface and
      security notions to Fábrega et al., related work names FLOE as the
      base-interface construction of that work, and the extension
      section states which interface tier each construction realizes.

   *  Global associated data: G is a per-message input, the StartEnc G
      of the primitive, always the last element of the commitment
      derivation and empty by default.  It is never stored.  Every
      commitment value changes, and the test-vector corpus is
      regenerated.  Appendix E.2 pins the default and a nonempty G.

Acknowledgments

   The author thanks Andrés Fábrega, Thomas Ristenpart, Gregory Rubin,
   Richard Barnes, Thibault Meunier, Kenny Paterson, Christopher Patton,
   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 7 January 2027               [Page 141]