<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.39 (Ruby 3.4.9) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-denis-xet-04" category="info" submissionType="independent" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.33.0 -->
  <front>
    <title abbrev="XET">XET: Content-Addressable Storage Protocol for Efficient Data Transfer</title>
    <seriesInfo name="Internet-Draft" value="draft-denis-xet-04"/>
    <author initials="F." surname="Denis" fullname="Frank Denis">
      <organization>Independent Contributor</organization>
      <address>
        <email>fde@00f.net</email>
      </address>
    </author>
    <date year="2026"/>
    <keyword>Internet-Draft</keyword>
    <abstract>
      <?line 66?>

<t>This document specifies XET, a content-addressable storage (CAS) protocol designed for efficient storage and transfer of large files with chunk-level deduplication.</t>
      <t>XET uses content-defined chunking to split files into variable-sized chunks, aggregates chunks into containers called xorbs, and enables deduplication across files and repositories through cryptographic hashing.</t>
    </abstract>
    <note removeInRFC="true">
      <name>Discussion Venues</name>
      <t>Source for this draft and an issue tracker can be found at
    <eref target="https://github.com/jedisct1/draft-denis-xet"/>.</t>
    </note>
  </front>
  <middle>
    <?line 72?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>Large-scale data storage and transfer systems face fundamental challenges in efficiency: storing multiple versions of similar files wastes storage space, and transferring unchanged data wastes bandwidth.
Traditional approaches such as file-level deduplication miss opportunities to share common content between different files, while fixed-size chunking fails to handle insertions and deletions gracefully.</t>
      <t>XET addresses these challenges through a content-addressable storage protocol that operates at the chunk level.
By using content-defined chunking with a rolling hash algorithm, XET creates stable chunk boundaries that remain consistent even when files are modified.</t>
      <t>This enables efficient deduplication not only within a single file across versions, but also across entirely different files that happen to share common content.</t>
      <t>The protocol is designed around several key principles:</t>
      <ul spacing="normal">
        <li>
          <t>Determinism: Given the same input data, any conforming implementation <bcp14>MUST</bcp14> produce identical chunks, hashes, and serialized formats, ensuring interoperability.</t>
        </li>
        <li>
          <t>Content Addressing: All objects (chunks, xorbs, files) are identified by cryptographic hashes of their content, enabling integrity verification and natural deduplication.</t>
        </li>
        <li>
          <t>Efficient Transfer: The reconstruction-based download model allows clients to fetch only the data they need, supporting range queries and parallel downloads.</t>
        </li>
        <li>
          <t>Algorithm Agility: The chunking and hashing algorithms are encapsulated in algorithm suites, enabling future evolution while maintaining compatibility within a deployment.</t>
        </li>
        <li>
          <t>Provider Agnostic: While originally developed for machine learning model and dataset storage, XET is a generic protocol applicable to any large file storage scenario.</t>
        </li>
      </ul>
      <t>This specification provides the complete details necessary for implementing interoperable XET clients and servers.
It defines the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> algorithm suite as the default, using <tt>BLAKE3</tt> for cryptographic hashing, <tt>Gearhash</tt> for content-defined chunking, and <tt>LZ4</tt> for compression.</t>
      <section anchor="use-cases">
        <name>Use Cases</name>
        <t>XET is particularly well-suited for scenarios involving:</t>
        <ul spacing="normal">
          <li>
            <t>Machine Learning: Model checkpoints often share common layers and parameters across versions, enabling significant storage savings through deduplication.</t>
          </li>
          <li>
            <t>Dataset Management: Large datasets with incremental updates benefit from chunk-level deduplication, where only changed portions need to be transferred.</t>
          </li>
          <li>
            <t>Container Images: OCI container images share common base layers across different applications and versions. Content-defined chunking enables deduplication not only across image layers but also across similar content in unrelated images.</t>
          </li>
          <li>
            <t>Version Control: Similar to Git LFS but with content-aware chunking that enables sharing across different files, not just versions of the same file.</t>
          </li>
          <li>
            <t>Content Distribution: The reconstruction-based model enables efficient range queries and partial downloads of large files.</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="terminology">
      <name>Terminology</name>
      <t>The key words “<bcp14>MUST</bcp14>”, “<bcp14>MUST NOT</bcp14>”, “<bcp14>REQUIRED</bcp14>”, “<bcp14>SHALL</bcp14>”, “<bcp14>SHALL
NOT</bcp14>”, “<bcp14>SHOULD</bcp14>”, “<bcp14>SHOULD NOT</bcp14>”, “<bcp14>RECOMMENDED</bcp14>”, “<bcp14>NOT RECOMMENDED</bcp14>”,
“<bcp14>MAY</bcp14>”, and “<bcp14>OPTIONAL</bcp14>” in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
      <?line -18?>

<t>Throughout this document, the following terms apply:</t>
      <table>
        <thead>
          <tr>
            <th align="left">Term</th>
            <th align="left">Definition</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">Algorithm Suite</td>
            <td align="left">A specification of the cryptographic hash function and content-defined chunking algorithm used by an XET deployment. All participants in an XET system <bcp14>MUST</bcp14> use the same algorithm suite for interoperability.</td>
          </tr>
          <tr>
            <td align="left">Chunk</td>
            <td align="left">A variable-sized unit of data derived from a file using content-defined chunking. Chunks are the fundamental unit of deduplication in XET.</td>
          </tr>
          <tr>
            <td align="left">Chunk Hash</td>
            <td align="left">A 32-byte cryptographic hash that uniquely identifies a chunk based on its content.</td>
          </tr>
          <tr>
            <td align="left">Xorb</td>
            <td align="left">A container object that aggregates multiple compressed chunks for efficient storage and transfer. The name derives from “XET orb.”</td>
          </tr>
          <tr>
            <td align="left">Xorb Hash</td>
            <td align="left">A 32-byte cryptographic hash computed from the chunk hashes within a xorb using a Merkle tree construction.</td>
          </tr>
          <tr>
            <td align="left">File Hash</td>
            <td align="left">A 32-byte cryptographic hash that uniquely identifies a file based on its chunk composition.</td>
          </tr>
          <tr>
            <td align="left">Shard</td>
            <td align="left">A binary metadata structure that describes file reconstructions and xorb contents, used for registering uploads and enabling deduplication.</td>
          </tr>
          <tr>
            <td align="left">Term</td>
            <td align="left">A reference to a contiguous range of chunks within a specific xorb, used to describe how to reconstruct a file.</td>
          </tr>
          <tr>
            <td align="left">File Reconstruction</td>
            <td align="left">An ordered list of terms that describes how to reassemble a file from chunks stored in xorbs.</td>
          </tr>
          <tr>
            <td align="left">Content-Defined Chunking (CDC)</td>
            <td align="left">An algorithm that determines chunk boundaries based on file content rather than fixed offsets, enabling stable boundaries across file modifications.</td>
          </tr>
          <tr>
            <td align="left">Content-Addressable Storage (CAS)</td>
            <td align="left">A storage system where objects are addressed by cryptographic hashes of their content rather than by location or name.</td>
          </tr>
          <tr>
            <td align="left">Global Deduplication</td>
            <td align="left">The process of identifying chunks that already exist in the storage system to avoid redundant uploads.</td>
          </tr>
        </tbody>
      </table>
      <section anchor="notational-conventions">
        <name>Notational Conventions</name>
        <t>All multi-byte integers in binary formats (xorb headers, shard structures) use little-endian byte order unless otherwise specified.</t>
        <t>Hash values are 32 bytes (256 bits).
When serialized, they are stored as raw bytes.
When displayed as strings, they use a specific byte-swapped hexadecimal format (see <xref target="hash-string-format"/>).</t>
        <t>Range specifications in this document use exclusive end: <tt>[start, end)</tt>.
Example: <tt>{"start": 0, "end": 4}</tt> means indices 0, 1, 2, 3.</t>
        <section anchor="pseudo-code-conventions">
          <name>Pseudo-Code Conventions</name>
          <t>Pseudo-code in this document uses the following conventions:</t>
          <ul spacing="normal">
            <li>
              <t><tt>for i = a to b:</tt> iterates with <tt>i</tt> taking values <tt>a, a+1, ..., b</tt> (inclusive)</t>
            </li>
            <li>
              <t><tt>for each x in list:</tt> iterates over each element in <tt>list</tt></t>
            </li>
            <li>
              <t><tt>//</tt> denotes integer division (truncating toward zero)</t>
            </li>
            <li>
              <t><tt>%</tt> denotes the modulo operator</t>
            </li>
            <li>
              <t><tt>array[start:end]</tt> slices from index <tt>start</tt> (inclusive) to <tt>end</tt> (exclusive)</t>
            </li>
            <li>
              <t><tt>+</tt> on arrays denotes concatenation</t>
            </li>
          </ul>
        </section>
      </section>
    </section>
    <section anchor="protocol-overview">
      <name>Protocol Overview</name>
      <t>XET operates as a client-server protocol.
Clients perform content-defined chunking locally, query for deduplication opportunities, form xorbs from new chunks, and upload both xorbs and shards to the server.
The CAS server provides APIs for reconstruction queries, global deduplication, and persistent storage.</t>
      <section anchor="upload-flow">
        <name>Upload Flow</name>
        <t>The upload process transforms files into content-addressed storage:</t>
        <ol spacing="normal" type="1"><li>
            <t>Chunking: Split files into variable-sized chunks using content-defined chunking (see <xref target="content-defined-chunking"/>).</t>
          </li>
          <li>
            <t>Deduplication: Query for existing chunks to avoid redundant uploads (see <xref target="deduplication"/>).</t>
          </li>
          <li>
            <t>Xorb Formation: Group new chunks into xorbs, applying compression (see <xref target="xorb-format"/>).</t>
          </li>
          <li>
            <t>Xorb Upload: Upload serialized xorbs to the CAS server.</t>
          </li>
          <li>
            <t>Shard Formation: Create shard metadata describing file reconstructions.</t>
          </li>
          <li>
            <t>Shard Upload: Upload the shard to register files in the system.</t>
          </li>
        </ol>
      </section>
      <section anchor="download-flow">
        <name>Download Flow</name>
        <t>The download process reconstructs files from stored chunks:</t>
        <ol spacing="normal" type="1"><li>
            <t>Reconstruction Query: Request reconstruction information for a file hash.</t>
          </li>
          <li>
            <t>Term Processing: Parse the ordered list of terms describing the file.</t>
          </li>
          <li>
            <t>Data Fetching: Download required xorb ranges using provided URLs.</t>
          </li>
          <li>
            <t>Chunk Extraction: Deserialize and decompress chunks from xorb data.</t>
          </li>
          <li>
            <t>File Assembly: Concatenate chunks in term order to reconstruct the file.</t>
          </li>
        </ol>
      </section>
    </section>
    <section anchor="algorithm-suites">
      <name>Algorithm Suites</name>
      <t>XET is designed as a generic framework where the specific chunking algorithm and cryptographic hash function are parameters defined by an algorithm suite.
This enables future algorithm agility while maintaining full backward compatibility within a deployment.</t>
      <section anchor="suite-definition">
        <name>Suite Definition</name>
        <t>An algorithm suite specifies:</t>
        <ol spacing="normal" type="1"><li>
            <t>Cryptographic Hash Function: The hash algorithm used for all content addressing (chunk hashes, xorb hashes, file hashes, verification hashes).</t>
          </li>
          <li>
            <t>Content-Defined Chunking Algorithm: The rolling hash function and boundary detection logic used to split files into chunks.</t>
          </li>
          <li>
            <t>Compression Format: The compression algorithm used for chunk data within xorbs.</t>
          </li>
          <li>
            <t>Keying Material: Domain separation keys for the hash function.</t>
          </li>
          <li>
            <t>Algorithm Parameters: Chunk size bounds, mask values, lookup tables, and other constants.</t>
          </li>
        </ol>
      </section>
      <section anchor="suite-requirements">
        <name>Suite Requirements</name>
        <t>Any conforming algorithm suite <bcp14>MUST</bcp14> satisfy:</t>
        <ul spacing="normal">
          <li>
            <t>Determinism: Identical inputs <bcp14>MUST</bcp14> produce identical outputs across all implementations.</t>
          </li>
          <li>
            <t>Collision Resistance: The hash function <bcp14>MUST</bcp14> provide at least 128 bits of collision resistance.</t>
          </li>
          <li>
            <t>Preimage Resistance: The hash function <bcp14>MUST</bcp14> provide at least 128 bits of preimage resistance.</t>
          </li>
          <li>
            <t>Keyed Mode: The hash function <bcp14>MUST</bcp14> support keyed operation for domain separation.</t>
          </li>
        </ul>
      </section>
      <section anchor="suite-negotiation">
        <name>Suite Negotiation</name>
        <t>The algorithm suite used by an XET deployment is determined out-of-band, typically by the CAS server configuration.
All clients interacting with a given server <bcp14>MUST</bcp14> use the same suite.
Binary formats (xorbs, shards) do not contain suite identifiers; the suite is determined implicitly by the deployment context.</t>
      </section>
      <section anchor="defined-suites">
        <name>Defined Suites</name>
        <t>This specification defines one algorithm suite:</t>
        <ul spacing="normal">
          <li>
            <t><tt>XET-BLAKE3-GEARHASH-LZ4</tt>: Uses <tt>BLAKE3</tt> for all cryptographic hashing, <tt>Gearhash</tt> for content-defined chunking, and <tt>LZ4</tt> for compression. This is the default and currently only defined suite.</t>
          </li>
        </ul>
        <t>Future specifications <bcp14>MAY</bcp14> define additional suites with different algorithms.</t>
      </section>
    </section>
    <section anchor="content-defined-chunking">
      <name>Content-Defined Chunking</name>
      <t>Content-defined chunking (CDC) splits files into variable-sized chunks based on content rather than fixed offsets.
This produces deterministic chunk boundaries that remain stable across file modifications, enabling efficient deduplication.</t>
      <t>This section describes the chunking algorithm for the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite.
Other algorithm suites <bcp14>MAY</bcp14> define different chunking algorithms with different parameters.</t>
      <section anchor="gearhash-algorithm">
        <name>Gearhash Algorithm</name>
        <t>The <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite uses a <tt>Gearhash</tt>-based rolling hash algorithm <xref target="GEARHASH"/>.
<tt>Gearhash</tt> maintains a 64-bit state that is updated with each input byte using a lookup table, providing fast and deterministic boundary detection.</t>
      </section>
      <section anchor="algorithm-parameters">
        <name>Algorithm Parameters</name>
        <t>The following constants define the chunking behavior for the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite:</t>
        <artwork><![CDATA[
TARGET_CHUNK_SIZE  = 65536      # 64 KiB (2^16 bytes)
MIN_CHUNK_SIZE     = 8192       # 8 KiB (TARGET / 8)
MAX_CHUNK_SIZE     = 131072     # 128 KiB (TARGET * 2)
MASK               = 0xFFFF000000000000  # 16 one-bits
]]></artwork>
        <t>The <tt>Gearhash</tt> algorithm uses a lookup table of 256 64-bit constants.
Implementations of the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite <bcp14>MUST</bcp14> use the table defined in <xref target="GEARHASH"/> (see <xref target="gearhash-table"/> for the complete lookup table).</t>
      </section>
      <section anchor="algorithm-description">
        <name>Algorithm Description</name>
        <t>The algorithm maintains a 64-bit rolling hash value and processes input bytes sequentially:</t>
        <artwork><![CDATA[
function chunk_file(data):
    h = 0                    # 64-bit rolling hash
    start_offset = 0         # Start of current chunk
    chunks = []
    n = length(data)

    for i = 0 to n - 1:      # Inclusive range [0, n-1]
        b = data[i]
        h = ((h << 1) + TABLE[b]) & 0xFFFFFFFFFFFFFFFF  # 64-bit wrap

        chunk_size = i - start_offset + 1

        if chunk_size < MIN_CHUNK_SIZE:
            continue

        if chunk_size >= MAX_CHUNK_SIZE:
            chunks.append(data[start_offset : i + 1])
            start_offset = i + 1
            h = 0
            continue

        if (h & MASK) == 0:
            chunks.append(data[start_offset : i + 1])
            start_offset = i + 1
            h = 0

    if start_offset < n:
        chunks.append(data[start_offset : n])

    return chunks
]]></artwork>
      </section>
      <section anchor="boundary-rules">
        <name>Boundary Rules</name>
        <t>The following rules govern chunk boundary placement:</t>
        <ol spacing="normal" type="1"><li>
            <t>Boundaries <bcp14>MUST NOT</bcp14> be placed before <tt>MIN_CHUNK_SIZE</tt> bytes have been processed in the current chunk.</t>
          </li>
          <li>
            <t>Boundaries <bcp14>MUST</bcp14> be forced when <tt>MAX_CHUNK_SIZE</tt> bytes have been processed, regardless of hash value.</t>
          </li>
          <li>
            <t>Between minimum and maximum sizes, boundaries are placed when <tt>(h &amp; MASK) == 0</tt>.</t>
          </li>
          <li>
            <t>The final chunk <bcp14>MAY</bcp14> be smaller than <tt>MIN_CHUNK_SIZE</tt> if it represents the end of the file.</t>
          </li>
          <li>
            <t>Files smaller than <tt>MIN_CHUNK_SIZE</tt> produce a single chunk.</t>
          </li>
        </ol>
      </section>
      <section anchor="determinism-requirements">
        <name>Determinism Requirements</name>
        <t>Implementations <bcp14>MUST</bcp14> produce identical chunk boundaries for identical input data.
For the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite, this requires:</t>
        <ul spacing="normal">
          <li>
            <t>Using the exact lookup table values from <xref target="gearhash-table"/></t>
          </li>
          <li>
            <t>Using 64-bit wrapping arithmetic for hash updates</t>
          </li>
          <li>
            <t>Processing bytes in sequential order</t>
          </li>
          <li>
            <t>Applying boundary rules consistently</t>
          </li>
        </ul>
        <t>Other algorithm suites <bcp14>MUST</bcp14> specify their own determinism requirements.</t>
      </section>
      <section anchor="performance-optimization">
        <name>Performance Optimization</name>
        <t>Implementations <bcp14>MAY</bcp14> skip boundary checks until <tt>chunk_size</tt> reaches <tt>MIN_CHUNK_SIZE</tt>, since boundaries are forbidden before that point.</t>
        <t>They <bcp14>MUST</bcp14> still update the rolling hash for every byte; skipping hash updates would change <tt>h</tt> and therefore alter boundary placement, violating determinism.</t>
      </section>
    </section>
    <section anchor="hashing-methods">
      <name>Hashing Methods</name>
      <t>XET uses cryptographic hashing for content addressing, integrity verification, and deduplication.
The specific hash function is determined by the algorithm suite.
All hashes are 32 bytes (256 bits) in length.</t>
      <t>This section describes the hashing methods for the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite, which uses <tt>BLAKE3</tt> keyed hashing <xref target="BLAKE3"/> for all cryptographic hash computations.
Different key values provide domain separation between hash types.</t>
      <section anchor="chunk-hashes">
        <name>Chunk Hashes</name>
        <t>Chunk hashes uniquely identify individual chunks based on their content.
The algorithm suite determines how chunk hashes are computed.</t>
        <t>For the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite, chunk hashes use <tt>BLAKE3</tt> keyed hash with <tt>DATA_KEY</tt> as the key:</t>
        <artwork><![CDATA[
DATA_KEY = {
  0x66, 0x97, 0xf5, 0x77, 0x5b, 0x95, 0x50, 0xde,
  0x31, 0x35, 0xcb, 0xac, 0xa5, 0x97, 0x18, 0x1c,
  0x9d, 0xe4, 0x21, 0x10, 0x9b, 0xeb, 0x2b, 0x58,
  0xb4, 0xd0, 0xb0, 0x4b, 0x93, 0xad, 0xf2, 0x29
}
]]></artwork>
        <artwork><![CDATA[
function compute_chunk_hash(chunk_data):
    return blake3_keyed_hash(DATA_KEY, chunk_data)
]]></artwork>
      </section>
      <section anchor="xorb-hashes">
        <name>Xorb Hashes</name>
        <t>Xorb hashes identify xorbs based on their constituent chunks.
The hash is computed using a Merkle tree construction where leaf nodes are chunk hashes.
The Merkle tree construction is defined separately from the hash function.</t>
        <section anchor="internal-node-hash-function">
          <name>Internal Node Hash Function</name>
          <t>Internal node hashes combine child hashes with their sizes.
The hash function is determined by the algorithm suite.</t>
          <t>For the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite, internal node hashes use <tt>BLAKE3</tt> keyed hash with <tt>INTERNAL_NODE_KEY</tt> as the key:</t>
          <artwork><![CDATA[
INTERNAL_NODE_KEY = {
  0x01, 0x7e, 0xc5, 0xc7, 0xa5, 0x47, 0x29, 0x96,
  0xfd, 0x94, 0x66, 0x66, 0xb4, 0x8a, 0x02, 0xe6,
  0x5d, 0xdd, 0x53, 0x6f, 0x37, 0xc7, 0x6d, 0xd2,
  0xf8, 0x63, 0x52, 0xe6, 0x4a, 0x53, 0x71, 0x3f
}
]]></artwork>
          <t>The input to the hash function is a string formed by concatenating lines for each child:</t>
          <artwork><![CDATA[
{hash_hex} : {size}\n
]]></artwork>
          <t>Where:</t>
          <ul spacing="normal">
            <li>
              <t><tt>{hash_hex}</tt> is the 64-character lowercase hexadecimal representation of the child hash as defined in <xref target="hash-string-format"/></t>
            </li>
            <li>
              <t><tt>{size}</tt> is the decimal representation of the child’s byte size</t>
            </li>
            <li>
              <t>Lines are separated by newline characters (<tt>\n</tt>)</t>
            </li>
          </ul>
        </section>
        <section anchor="merkle-tree">
          <name>Merkle Tree Construction</name>
          <t>XET uses an aggregated hash tree construction with variable fan-out, not a traditional binary Merkle tree.
This algorithm iteratively collapses a list of (hash, size) pairs until a single root hash remains.</t>
          <section anchor="algorithm-parameters-1">
            <name>Algorithm Parameters</name>
            <artwork><![CDATA[
MEAN_BRANCHING_FACTOR = 4
MIN_CHILDREN = 2
MAX_CHILDREN = 2 * MEAN_BRANCHING_FACTOR + 1  # 9
]]></artwork>
          </section>
          <section anchor="cut-point-determination">
            <name>Cut Point Determination</name>
            <t>The tree structure is determined by the hash values themselves.
A cut point occurs when:</t>
            <ol spacing="normal" type="1"><li>
                <t>At least 3 children have been accumulated AND the current hash modulo MEAN_BRANCHING_FACTOR equals zero, OR</t>
              </li>
              <li>
                <t>The maximum number of children (9) has been reached, OR</t>
              </li>
              <li>
                <t>The end of the input list is reached</t>
              </li>
            </ol>
            <t>Note: When the input has 2 or fewer hashes, all are merged together.
This ensures each internal node has at least 2 children.</t>
            <artwork><![CDATA[
function next_merge_cut(hashes):
    # hashes is a list of (hash, size) pairs
    # Returns the number of entries to merge (cut point)
    n = length(hashes)
    if n <= 2:
        return n

    end = min(MAX_CHILDREN, n)

    # Check indices 2 through end-1 (0-based indexing)
    # Minimum merge is 3 children when input has more than 2 hashes
    for i = 2 to end - 1:
        h = hashes[i].hash
        # Interpret last 8 bytes of hash as little-endian 64-bit unsigned int
        hash_value = u64_le(h[24:32])
        if hash_value % MEAN_BRANCHING_FACTOR == 0:
            return i + 1  # Cut after element i (include i+1 elements)

    return end
]]></artwork>
          </section>
          <section anchor="merging-hash-sequences">
            <name>Merging Hash Sequences</name>
            <artwork><![CDATA[
function merged_hash_of_sequence(hash_pairs):
    # hash_pairs is a list of (hash, size) pairs
    buffer = ""
    total_size = 0

    for each (h, s) in hash_pairs:
        buffer += hash_to_string(h) + " : " + decimal_string(s) + "\n"
        total_size += s

    new_hash = blake3_keyed_hash(INTERNAL_NODE_KEY, utf8_encode(buffer))
    return (new_hash, total_size)
]]></artwork>
            <t>This produces lines like:</t>
            <artwork><![CDATA[
cfc5d07f6f03c29bbf424132963fe08d19a37d5757aaf520bf08119f05cd56d6 : 100
]]></artwork>
            <t>Each line contains:</t>
            <ul spacing="normal">
              <li>
                <t>The hash as a fixed-length 64-character lowercase hexadecimal string</t>
              </li>
              <li>
                <t>A space, colon, space (<tt> : </tt>)</t>
              </li>
              <li>
                <t>The size as a decimal integer</t>
              </li>
              <li>
                <t>A newline character (<tt>\n</tt>)</t>
              </li>
            </ul>
          </section>
          <section anchor="root-computation">
            <name>Root Computation</name>
            <artwork><![CDATA[
function compute_merkle_root(entries):
    # entries is a list of (hash, size) pairs
    if length(entries) == 0:
        return ZERO_HASH  # 32 zero bytes

    hv = entries  # Working copy

    while length(hv) > 1:
        write_idx = 0
        read_idx = 0

        while read_idx < length(hv):
            cut = read_idx + next_merge_cut(hv[read_idx:])
            hv[write_idx] = merged_hash_of_sequence(hv[read_idx:cut])
            write_idx += 1
            read_idx = cut

        hv = hv[0:write_idx]

    return hv[0].hash
]]></artwork>
            <t>Where <tt>ZERO_HASH</tt> is 32 bytes of zeros, and <tt>hv[start:end]</tt> denotes slicing elements from index <tt>start</tt> (inclusive) to <tt>end</tt> (exclusive).</t>
          </section>
        </section>
        <section anchor="xorb-hash-computation">
          <name>Xorb Hash Computation</name>
          <t>The xorb hash is the root of a Merkle tree built from chunk hashes:</t>
          <artwork><![CDATA[
function compute_xorb_hash(chunk_hashes, chunk_sizes):
    n = length(chunk_hashes)
    entries = []
    for i = 0 to n - 1:
        entries.append((chunk_hashes[i], chunk_sizes[i]))
    return compute_merkle_root(entries)
]]></artwork>
        </section>
      </section>
      <section anchor="file-hashes">
        <name>File Hashes</name>
        <t>File hashes identify files based on their complete chunk composition.
The computation is similar to xorb hashes, but with an additional final keyed hash step for domain separation.</t>
        <t>For the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite, file hashes use an all-zero key (<tt>ZERO_KEY</tt>) for the final hash:</t>
        <artwork><![CDATA[
ZERO_KEY = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}
]]></artwork>
        <artwork><![CDATA[
function compute_file_hash(chunk_hashes, chunk_sizes):
    n = length(chunk_hashes)
    entries = []
    for i = 0 to n - 1:
        entries.append((chunk_hashes[i], chunk_sizes[i]))
    merkle_root = compute_merkle_root(entries)
    return blake3_keyed_hash(ZERO_KEY, merkle_root)
]]></artwork>
        <t>For empty files (zero bytes), there are no chunks, so <tt>compute_merkle_root([])</tt> returns <tt>ZERO_HASH</tt> (32 zero bytes).
The file hash is therefore <tt>blake3_keyed_hash(ZERO_KEY, ZERO_HASH)</tt>.</t>
      </section>
      <section anchor="verification-hashes">
        <name>Term Verification Hashes</name>
        <t>Term verification hashes are used in shards to prove that the uploader possesses the actual file data, not just metadata.
The hash function is determined by the algorithm suite.</t>
        <t>For the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> suite, verification hashes use <tt>BLAKE3</tt> keyed hash with <tt>VERIFICATION_KEY</tt> as the key:</t>
        <artwork><![CDATA[
VERIFICATION_KEY = {
  0x7f, 0x18, 0x57, 0xd6, 0xce, 0x56, 0xed, 0x66,
  0x12, 0x7f, 0xf9, 0x13, 0xe7, 0xa5, 0xc3, 0xf3,
  0xa4, 0xcd, 0x26, 0xd5, 0xb5, 0xdb, 0x49, 0xe6,
  0x41, 0x24, 0x98, 0x7f, 0x28, 0xfb, 0x94, 0xc3
}
]]></artwork>
        <t>The input is the raw concatenation of chunk hashes (not hex-encoded) for the term’s chunk range:</t>
        <artwork><![CDATA[
function compute_verification_hash(chunk_hashes, start_index, end_index):
    # Range is [start_index, end_index) - end is exclusive
    buffer = empty_byte_array()
    for i = start_index to end_index - 1:
        buffer += chunk_hashes[i]  # 32 bytes each
    return blake3_keyed_hash(VERIFICATION_KEY, buffer)
]]></artwork>
      </section>
      <section anchor="hash-string-format">
        <name>Hash String Representation</name>
        <t>When representing hashes as strings, a specific byte reordering is applied before hexadecimal encoding.</t>
        <section anchor="conversion-procedure">
          <name>Conversion Procedure</name>
          <t>The 32-byte hash is interpreted as four little-endian 64-bit unsigned values, and each value is printed as 16 hexadecimal digits:</t>
          <ol spacing="normal" type="1"><li>
              <t>Divide the 32-byte hash into four 8-byte segments</t>
            </li>
            <li>
              <t>Interpret each segment as a little-endian 64-bit unsigned value</t>
            </li>
            <li>
              <t>Format each value as a zero-padded 16-character lowercase hexadecimal string</t>
            </li>
            <li>
              <t>Concatenate the four strings (64 characters total)</t>
            </li>
          </ol>
          <artwork><![CDATA[
function hash_to_string(hash):
    out = ""
    for segment = 0 to 3:
        offset = segment * 8
        value = u64_le(hash[offset : offset + 8])
        out += hex16(value)    # 16-digit lowercase hex
    return out

function string_to_hash(hex_string):
    hash = empty_byte_array()
    for segment = 0 to 3:
        start = segment * 16
        value = parse_hex_u64(hex_string[start : start + 16])
        hash += u64_le_bytes(value)
    return hash
]]></artwork>
          <t>Where:</t>
          <ul spacing="normal">
            <li>
              <t><tt>u64_le(bytes)</tt> interprets 8 bytes as a little-endian 64-bit unsigned integer</t>
            </li>
            <li>
              <t><tt>u64_le_bytes(value)</tt> converts a 64-bit unsigned integer to 8 little-endian bytes</t>
            </li>
            <li>
              <t><tt>hex16(value)</tt> formats a 64-bit value as a 16-character lowercase hexadecimal string</t>
            </li>
            <li>
              <t><tt>parse_hex_u64(str)</tt> parses a 16-character hexadecimal string as a 64-bit unsigned integer</t>
            </li>
          </ul>
        </section>
        <section anchor="example">
          <name>Example</name>
          <artwork><![CDATA[
Original hash bytes (indices 0-31):
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]

Reordered bytes:
[7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24]

String representation:
07060504030201000f0e0d0c0b0a090817161514131211101f1e1d1c1b1a1918
]]></artwork>
        </section>
      </section>
    </section>
    <section anchor="xorb-format">
      <name>Xorb Format</name>
      <t>A xorb is a container that aggregates multiple compressed chunks for efficient storage and transfer.
Xorbs are identified by their xorb hash (see <xref target="xorb-hashes"/>).</t>
      <section anchor="size-constraints">
        <name>Size Constraints</name>
        <artwork><![CDATA[
MAX_XORB_SIZE   = 67108864  # 64 MiB maximum serialized size
MAX_XORB_CHUNKS = 8192      # Maximum chunks per xorb
]]></artwork>
        <t>Implementations <bcp14>MUST NOT</bcp14> exceed either limit.
When collecting chunks:</t>
        <ol spacing="normal" type="1"><li>
            <t>Stop if adding the next chunk would exceed <tt>MAX_XORB_SIZE</tt></t>
          </li>
          <li>
            <t>Stop if the chunk count would exceed <tt>MAX_XORB_CHUNKS</tt></t>
          </li>
          <li>
            <t>Target approximately 1,024 chunks per xorb for typical workloads</t>
          </li>
        </ol>
      </section>
      <section anchor="binary-format">
        <name>Binary Format</name>
        <t>Serialized xorbs have a footer so readers can locate metadata by seeking from the end:</t>
        <artwork><![CDATA[
+-------------------------------------------------------------+
|                 Chunk Data Region (variable)                |
|   [chunk header + compressed bytes repeated per chunk]      |
+-------------------------------------------------------------+
|                 CasObjectInfo Footer (variable)             |
+-------------------------------------------------------------+
|     Info Length (32-bit unsigned LE, footer length only)    |
+-------------------------------------------------------------+
]]></artwork>
        <t>The final 4-byte little-endian integer stores the length of the <tt>CasObjectInfo</tt> block immediately preceding it (the length does not include the 4-byte length field itself).</t>
        <t>The chunk data region consists of consecutive chunk entries, each containing an 8-byte header followed by the compressed chunk data.</t>
      </section>
      <section anchor="chunk-header-format">
        <name>Chunk Header Format</name>
        <t>Each chunk header is 8 bytes with the following layout:</t>
        <table>
          <thead>
            <tr>
              <th align="left">Offset</th>
              <th align="left">Size</th>
              <th align="left">Field</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">0</td>
              <td align="left">1</td>
              <td align="left">Version (must be 0)</td>
            </tr>
            <tr>
              <td align="left">1</td>
              <td align="left">3</td>
              <td align="left">Compressed Size (little-endian, bytes)</td>
            </tr>
            <tr>
              <td align="left">4</td>
              <td align="left">1</td>
              <td align="left">Compression Type</td>
            </tr>
            <tr>
              <td align="left">5</td>
              <td align="left">3</td>
              <td align="left">Uncompressed Size (little-endian, bytes)</td>
            </tr>
          </tbody>
        </table>
        <section anchor="version-field">
          <name>Version Field</name>
          <t>The version field <bcp14>MUST</bcp14> be <tt>0</tt> for this specification.
Implementations <bcp14>MUST</bcp14> reject chunks with unknown version values.</t>
        </section>
        <section anchor="size-fields">
          <name>Size Fields</name>
          <t>Both size fields use 3-byte little-endian encoding, supporting values up to 16,777,215 bytes.
Given the maximum chunk size of 128 KiB, this provides ample range.</t>
          <t>Implementations <bcp14>MUST</bcp14> validate size fields before allocating buffers or invoking decompression:</t>
          <ul spacing="normal">
            <li>
              <t><tt>uncompressed_size</tt> <bcp14>MUST</bcp14> be greater than zero and <bcp14>MUST NOT</bcp14> exceed <tt>MAX_CHUNK_SIZE</tt> (128 KiB). Chunks that declare larger sizes <bcp14>MUST</bcp14> be rejected and the containing xorb considered invalid.</t>
            </li>
            <li>
              <t><tt>compressed_size</tt> <bcp14>MUST</bcp14> be greater than zero and <bcp14>MUST NOT</bcp14> exceed the lesser of <tt>MAX_CHUNK_SIZE</tt> and the remaining bytes in the serialized xorb payload. Oversize or truncated compressed payloads <bcp14>MUST</bcp14> cause the xorb to be rejected.</t>
            </li>
          </ul>
        </section>
        <section anchor="compression-type">
          <name>Compression Type</name>
          <table>
            <thead>
              <tr>
                <th align="left">Value</th>
                <th align="left">Name</th>
                <th align="left">Description</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">0</td>
                <td align="left">
                  <tt>None</tt></td>
                <td align="left">No compression; data stored as-is</td>
              </tr>
              <tr>
                <td align="left">1</td>
                <td align="left">
                  <tt>LZ4</tt></td>
                <td align="left">
                  <tt>LZ4</tt> Frame format compression</td>
              </tr>
              <tr>
                <td align="left">2</td>
                <td align="left">
                  <tt>ByteGrouping4LZ4</tt></td>
                <td align="left">Byte grouping preprocessing followed by <tt>LZ4</tt></td>
              </tr>
            </tbody>
          </table>
        </section>
      </section>
      <section anchor="compression-schemes">
        <name>Compression Schemes</name>
        <section anchor="none-type-0">
          <name><tt>None</tt> (Type 0)</name>
          <t>Data is stored without modification.
Used when compression would increase size or for already-compressed data.</t>
        </section>
        <section anchor="lz4-type-1">
          <name><tt>LZ4</tt> (Type 1)</name>
          <t><tt>LZ4</tt> Frame format compression <xref target="LZ4"/> (not <tt>LZ4</tt> block format).
Each compressed chunk is a complete <tt>LZ4</tt> frame.
This is the default compression scheme for most data.</t>
        </section>
        <section anchor="bytegrouping4lz4-type-2">
          <name><tt>ByteGrouping4LZ4</tt> (Type 2)</name>
          <t>A two-stage compression optimized for structured data (e.g., floating-point arrays):</t>
          <ol spacing="normal" type="1"><li>
              <t>Byte Grouping Phase: Reorganize bytes by position within 4-byte groups</t>
            </li>
            <li>
              <t><tt>LZ4</tt> Compression: Apply <tt>LZ4</tt> to the reorganized data</t>
            </li>
          </ol>
          <t>Byte grouping transformation:</t>
          <artwork><![CDATA[
Original:  [A0 A1 A2 A3 | B0 B1 B2 B3 | C0 C1 C2 C3 | ...]
Grouped:   [A0 B0 C0 ... | A1 B1 C1 ... | A2 B2 C2 ... | A3 B3 C3 ...]
]]></artwork>
          <artwork><![CDATA[
function byte_group_4(data):
    n = length(data)
    groups = [[], [], [], []]

    for i = 0 to n - 1:
        groups[i % 4].append(data[i])

    return groups[0] + groups[1] + groups[2] + groups[3]

function byte_ungroup_4(grouped_data, original_length):
    n = original_length
    base_size = n // 4         # Integer division
    remainder = n % 4

    # Group sizes: first 'remainder' groups get base_size + 1
    sizes = []
    for i = 0 to 3:
        if i < remainder:
            sizes.append(base_size + 1)
        else:
            sizes.append(base_size)

    # Extract groups from grouped_data
    groups = []
    offset = 0
    for i = 0 to 3:
        groups.append(grouped_data[offset : offset + sizes[i]])
        offset += sizes[i]

    # Interleave back to original order
    data = []
    for i = 0 to n - 1:
        group_idx = i % 4
        pos_in_group = i // 4  # Integer division
        data.append(groups[group_idx][pos_in_group])

    return data
]]></artwork>
          <t>When the data length is not a multiple of 4, the remainder bytes are distributed to the first groups.
For example, with 10 bytes the group sizes are 3, 3, 2, 2 (first two groups get the extra bytes).</t>
        </section>
        <section anchor="compression-selection">
          <name>Compression Selection</name>
          <t>Implementations <bcp14>MAY</bcp14> use any strategy to select compression schemes.
If compression increases size, implementations <bcp14>SHOULD</bcp14> use compression type <tt>0</tt> (<tt>None</tt>).</t>
          <t><tt>ByteGrouping4LZ4</tt> (Type 2) is typically beneficial for structured numerical data such as <tt>float32</tt> or <tt>float16</tt> tensors, where bytes at the same position within 4-byte groups tend to be similar.</t>
        </section>
      </section>
      <section anchor="casobjectinfo-footer">
        <name><tt>CasObjectInfo</tt> Footer</name>
        <t>The metadata footer sits immediately before the 4-byte length trailer.
Implementations <bcp14>MUST</bcp14> serialize fields in this exact order and reject unknown idents or versions.</t>
        <section anchor="main-header">
          <name>Main Header</name>
          <ul spacing="normal">
            <li>
              <t>Ident: <tt>"XETBLOB"</tt> (7 ASCII bytes)</t>
            </li>
            <li>
              <t>Version: 8-bit unsigned, <bcp14>MUST</bcp14> be <tt>1</tt></t>
            </li>
            <li>
              <t>Xorb hash: 32-byte Merkle hash from <xref target="xorb-hashes"/></t>
            </li>
          </ul>
        </section>
        <section anchor="hash-section">
          <name>Hash Section</name>
          <ul spacing="normal">
            <li>
              <t>Ident: <tt>"XBLBHSH"</tt> (7 bytes)</t>
            </li>
            <li>
              <t>Hashes version: 8-bit unsigned, <bcp14>MUST</bcp14> be <tt>0</tt></t>
            </li>
            <li>
              <t><tt>num_chunks</tt>: 32-bit unsigned</t>
            </li>
            <li>
              <t>Chunk hashes: 32 bytes each, in chunk order</t>
            </li>
          </ul>
        </section>
        <section anchor="boundary-section">
          <name>Boundary Section</name>
          <ul spacing="normal">
            <li>
              <t>Ident: <tt>"XBLBBND"</tt> (7 bytes)</t>
            </li>
            <li>
              <t>Boundaries version: 8-bit unsigned, <bcp14>MUST</bcp14> be <tt>1</tt></t>
            </li>
            <li>
              <t><tt>num_chunks</tt>: 32-bit unsigned</t>
            </li>
            <li>
              <t>Chunk boundary offsets: Array of <tt>num_chunks</tt> 32-bit unsigned values.
Each value is the end offset (in bytes) of the corresponding chunk in the serialized chunk data region, including headers.
Chunk 0 starts at offset 0; chunk <tt>i</tt> starts at <tt>chunk_boundary_offsets[i-1]</tt>.</t>
            </li>
            <li>
              <t>Unpacked chunk offsets: Array of <tt>num_chunks</tt> 32-bit unsigned values.
Each value is the end offset of the corresponding chunk in the concatenated uncompressed stream.</t>
            </li>
          </ul>
        </section>
        <section anchor="trailer">
          <name>Trailer</name>
          <ul spacing="normal">
            <li>
              <t><tt>num_chunks</tt>: 32-bit unsigned (repeated for convenience)</t>
            </li>
            <li>
              <t>Hashes section offset from end: 32-bit unsigned byte offset from the end of the footer to the start of the hash section</t>
            </li>
            <li>
              <t>Boundary section offset from end: 32-bit unsigned byte offset from the end of the footer to the start of the boundary section</t>
            </li>
            <li>
              <t>Reserved: 16 bytes, zero</t>
            </li>
          </ul>
          <t>The 4-byte length trailer that follows the footer stores <tt>info_length</tt> (little-endian 32-bit unsigned) for the <tt>CasObjectInfo</tt> block only.
This length field is not counted inside the footer itself.</t>
        </section>
      </section>
    </section>
    <section anchor="file-reconstruction">
      <name>File Reconstruction</name>
      <t>A file reconstruction is an ordered list of terms that describes how to reassemble a file from chunks stored in xorbs.</t>
      <section anchor="term-structure">
        <name>Term Structure</name>
        <t>Each term specifies:</t>
        <ul spacing="normal">
          <li>
            <t>Xorb Hash: Identifies the xorb containing the chunks</t>
          </li>
          <li>
            <t>Chunk Range: Start (inclusive) and end (exclusive) indices within the xorb</t>
          </li>
          <li>
            <t>Unpacked Length: Expected byte count after decompression (for validation)</t>
          </li>
        </ul>
      </section>
      <section anchor="reconstruction-rules">
        <name>Reconstruction Rules</name>
        <ol spacing="normal" type="1"><li>
            <t>Terms <bcp14>MUST</bcp14> be processed in order.</t>
          </li>
          <li>
            <t>For each term, extract chunks at indices <tt>[start, end)</tt> from the specified xorb.</t>
          </li>
          <li>
            <t>Decompress chunks according to their compression headers.</t>
          </li>
          <li>
            <t>Concatenate decompressed chunk data in order.</t>
          </li>
          <li>
            <t>For range queries, apply <tt>offset_into_first_range</tt> to skip initial bytes.</t>
          </li>
          <li>
            <t>Validate that the total reconstructed size matches expectations.</t>
          </li>
        </ol>
      </section>
      <section anchor="range-queries">
        <name>Range Queries</name>
        <t>When downloading a byte range rather than the complete file:</t>
        <ol spacing="normal" type="1"><li>
            <t>The reconstruction API returns only terms overlapping the requested range.</t>
          </li>
          <li>
            <t>The <tt>offset_into_first_range</tt> field indicates bytes to skip in the first term.</t>
          </li>
          <li>
            <t>The client <bcp14>MUST</bcp14> truncate output to match the requested range length.</t>
          </li>
        </ol>
      </section>
    </section>
    <section anchor="shard-format">
      <name>Shard Format</name>
      <t>A shard is a binary metadata structure that describes file reconstructions and xorb contents.
Shards serve two purposes:</t>
      <ol spacing="normal" type="1"><li>
          <t>Upload Registration: Describing newly uploaded files and xorbs to the CAS server</t>
        </li>
        <li>
          <t>Deduplication Response: Providing information about existing chunks for deduplication</t>
        </li>
      </ol>
      <section anchor="overall-structure">
        <name>Overall Structure</name>
        <artwork><![CDATA[
+--------------------------------------------------------+
|                    Header (48 bytes)                   |
+--------------------------------------------------------+
|                    File Info Section                   |
|              (variable, ends with bookend)             |
+--------------------------------------------------------+
|                    CAS Info Section                    |
|              (variable, ends with bookend)             |
+--------------------------------------------------------+
|                   Footer (200 bytes)                   |
|                (omitted for upload API)                |
+--------------------------------------------------------+
]]></artwork>
      </section>
      <section anchor="data-types">
        <name>Data Types</name>
        <t>All multi-byte integers are little-endian.
Field sizes are stated explicitly (e.g., “8-bit unsigned”, “32-bit unsigned”, “64-bit unsigned”).
Hash denotes a 32-byte (256-bit) value.</t>
      </section>
      <section anchor="shard-header">
        <name>Header</name>
        <t>The header is 48 bytes at offset 0:</t>
        <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       32    Tag (magic identifier)
32      8     Version (64-bit unsigned, MUST be 2)
40      8     Footer Size (64-bit unsigned, 0 if footer omitted)
]]></artwork>
        <t>The header version (<tt>2</tt>) and footer version (<tt>1</tt>) are independent version numbers that may evolve separately.</t>
        <section anchor="magic-tag">
          <name>Magic Tag</name>
          <t>The 32-byte magic tag identifies the shard format and the application deployment:</t>
          <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       14    Application Identifier (ASCII, null-padded)
14      1     Null byte (0x00)
15      17    Magic sequence (fixed)
]]></artwork>
          <t>The magic sequence (bytes 15-31) <bcp14>MUST</bcp14> be exactly:</t>
          <artwork><![CDATA[
SHARD_MAGIC_SEQUENCE = {
  0x55, 0x69, 0x67, 0x45, 0x6a, 0x7b, 0x81, 0x57,
  0x83, 0xa5, 0xbd, 0xd9, 0x5c, 0xcd, 0xd1, 0x4a, 0xa9
}
]]></artwork>
          <t>The application identifier (bytes 0-13) is deployment-specific and identifies the XET application context.
For Hugging Face deployments, the identifier <bcp14>MUST</bcp14> be <tt>"HFRepoMetaData"</tt> (ASCII):</t>
          <artwork><![CDATA[
HF_APPLICATION_ID = {
  0x48, 0x46, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x65,
  0x74, 0x61, 0x44, 0x61, 0x74, 0x61
}
]]></artwork>
          <t>Other deployments <bcp14>MAY</bcp14> define their own application identifiers.
If the identifier is shorter than 14 bytes, it <bcp14>MUST</bcp14> be null-padded on the right.</t>
          <t>Implementations <bcp14>MUST</bcp14> verify that bytes 15-31 match the expected magic sequence before processing.
Implementations <bcp14>MAY</bcp14> additionally verify the application identifier to ensure compatibility with the expected deployment.</t>
        </section>
      </section>
      <section anchor="file-info-section">
        <name>File Info Section</name>
        <t>The file info section contains zero or more file blocks, each describing a file reconstruction.
The section ends with a bookend entry.</t>
        <section anchor="file-block-structure">
          <name>File Block Structure</name>
          <t>Each file block contains:</t>
          <ol spacing="normal" type="1"><li>
              <t><tt>FileDataSequenceHeader</tt> (48 bytes)</t>
            </li>
            <li>
              <t><tt>FileDataSequenceEntry</tt> entries (48 bytes each, count from header)</t>
            </li>
            <li>
              <t><tt>FileVerificationEntry</tt> entries (48 bytes each, if flag set)</t>
            </li>
            <li>
              <t><tt>FileMetadataExt</tt> (48 bytes, if flag set)</t>
            </li>
          </ol>
        </section>
        <section anchor="filedatasequenceheader">
          <name><tt>FileDataSequenceHeader</tt></name>
          <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       32    File Hash
32      4     File Flags (32-bit unsigned)
36      4     Number of Entries (32-bit unsigned)
40      8     Reserved (zeros)
]]></artwork>
          <t>File Flags:</t>
          <table>
            <thead>
              <tr>
                <th align="left">Bit</th>
                <th align="left">Name</th>
                <th align="left">Description</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">31</td>
                <td align="left">
                  <tt>WITH_VERIFICATION</tt></td>
                <td align="left">
                  <tt>FileVerificationEntry</tt> present for each entry</td>
              </tr>
              <tr>
                <td align="left">30</td>
                <td align="left">
                  <tt>WITH_METADATA_EXT</tt></td>
                <td align="left">
                  <tt>FileMetadataExt</tt> present at end</td>
              </tr>
            </tbody>
          </table>
        </section>
        <section anchor="filedatasequenceentry">
          <name><tt>FileDataSequenceEntry</tt></name>
          <t>Each entry describes a term in the file reconstruction:</t>
          <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       32    CAS Hash (xorb hash)
32      4     CAS Flags (32-bit unsigned, reserved, MUST be set to 0)
36      4     Unpacked Segment Bytes (32-bit unsigned)
40      4     Chunk Index Start (32-bit unsigned)
44      4     Chunk Index End (32-bit unsigned, exclusive)
]]></artwork>
          <t>The chunk range is specified as <tt>[chunk_index_start, chunk_index_end)</tt> (end-exclusive).</t>
        </section>
        <section anchor="fileverificationentry">
          <name><tt>FileVerificationEntry</tt></name>
          <t>Present only when <tt>WITH_VERIFICATION</tt> flag is set:</t>
          <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       32    Range Hash (verification hash)
32      16    Reserved (zeros)
]]></artwork>
          <t>The range hash is computed as described in <xref target="verification-hashes"/>.</t>
        </section>
        <section anchor="filemetadataext">
          <name><tt>FileMetadataExt</tt></name>
          <t>Present only when <tt>WITH_METADATA_EXT</tt> flag is set:</t>
          <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       32    SHA-256 Hash of file contents
32      16    Reserved (zeros)
]]></artwork>
        </section>
        <section anchor="bookend-entry">
          <name>Bookend Entry</name>
          <t>The file info section ends with a 48-byte bookend:</t>
          <ul spacing="normal">
            <li>
              <t>Bytes 0-31: All <tt>0xFF</tt></t>
            </li>
            <li>
              <t>Bytes 32-47: All <tt>0x00</tt></t>
            </li>
          </ul>
        </section>
      </section>
      <section anchor="cas-info-section">
        <name>CAS Info Section</name>
        <t>The CAS info section contains zero or more CAS blocks, each describing a xorb and its chunks.
The section ends with a bookend entry.</t>
        <section anchor="cas-block-structure">
          <name>CAS Block Structure</name>
          <t>Each CAS block contains:</t>
          <ol spacing="normal" type="1"><li>
              <t><tt>CASChunkSequenceHeader</tt> (48 bytes)</t>
            </li>
            <li>
              <t><tt>CASChunkSequenceEntry</tt> entries (48 bytes each, count from header)</t>
            </li>
          </ol>
        </section>
        <section anchor="caschunksequenceheader">
          <name><tt>CASChunkSequenceHeader</tt></name>
          <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       32    CAS Hash (xorb hash)
32      4     CAS Flags (32-bit unsigned, reserved, MUST be set to 0)
36      4     Number of Entries (32-bit unsigned)
40      4     Num Bytes in CAS (32-bit unsigned, total uncompressed)
44      4     Num Bytes on Disk (32-bit unsigned, serialized xorb size)
]]></artwork>
        </section>
        <section anchor="caschunksequenceentry">
          <name><tt>CASChunkSequenceEntry</tt></name>
          <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       32    Chunk Hash
32      4     Chunk Byte Range Start (32-bit unsigned)
36      4     Unpacked Segment Bytes (32-bit unsigned)
40      4     Flags (32-bit unsigned)
44      4     Reserved (32-bit unsigned, zeros)
]]></artwork>
          <section anchor="chunk-byte-range-start-calculation">
            <name>Chunk Byte Range Start Calculation</name>
            <t>The <tt>chunk_byte_range_start</tt> field is the cumulative byte offset of this chunk within the uncompressed xorb data.
It is calculated as the sum of <tt>unpacked_segment_bytes</tt> for all preceding chunks in the xorb:</t>
            <artwork><![CDATA[
function calculate_byte_range_starts(chunks):
    position = 0
    for each chunk in chunks:
        chunk.byte_range_start = position
        position += chunk.unpacked_segment_bytes
]]></artwork>
            <t>Example for a xorb with three chunks:</t>
            <artwork><![CDATA[
Chunk 0: unpacked_segment_bytes = 1000
         byte_range_start = 0

Chunk 1: unpacked_segment_bytes = 2000
         byte_range_start = 1000

Chunk 2: unpacked_segment_bytes = 500
         byte_range_start = 3000
]]></artwork>
            <t>This field enables efficient seeking within a xorb without decompressing all preceding chunks.</t>
          </section>
          <section anchor="chunk-flags">
            <name>Chunk Flags</name>
            <table>
              <thead>
                <tr>
                  <th align="left">Bit</th>
                  <th align="left">Name</th>
                  <th align="left">Description</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td align="left">31</td>
                  <td align="left">
                    <tt>GLOBAL_DEDUP_ELIGIBLE</tt></td>
                  <td align="left">Chunk is eligible for global deduplication queries (see <xref target="global-deduplication"/>)</td>
                </tr>
                <tr>
                  <td align="left">0-30</td>
                  <td align="left">Reserved</td>
                  <td align="left">
                    <bcp14>MUST</bcp14> be zero</td>
                </tr>
              </tbody>
            </table>
          </section>
        </section>
        <section anchor="bookend-entry-1">
          <name>Bookend Entry</name>
          <t>The CAS info section ends with a 48-byte bookend (same format as file info bookend).</t>
        </section>
      </section>
      <section anchor="shard-footer">
        <name>Footer</name>
        <t>The footer is 200 bytes at the end of the shard.
It is <bcp14>REQUIRED</bcp14> for stored shards but <bcp14>MUST</bcp14> be omitted when uploading shards via the upload API.</t>
        <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       8     Version (64-bit unsigned, MUST be 1)
8       8     File Info Offset (64-bit unsigned)
16      8     CAS Info Offset (64-bit unsigned)
24      8     File Lookup Offset (64-bit unsigned)
32      8     File Lookup Num Entries (64-bit unsigned)
40      8     CAS Lookup Offset (64-bit unsigned)
48      8     CAS Lookup Num Entries (64-bit unsigned)
56      8     Chunk Lookup Offset (64-bit unsigned)
64      8     Chunk Lookup Num Entries (64-bit unsigned)
72      32    Chunk Hash Key
104     8     Shard Creation Timestamp (64-bit unsigned, Unix epoch seconds)
112     8     Shard Key Expiry (64-bit unsigned, Unix epoch seconds)
120     48    Reserved (zeros)
168     8     Stored Bytes on Disk (64-bit unsigned)
176     8     Materialized Bytes (64-bit unsigned)
184     8     Stored Bytes (64-bit unsigned)
192     8     Footer Offset (64-bit unsigned)
]]></artwork>
        <t>Total size: 200 bytes</t>
        <section anchor="lookup-tables">
          <name>Lookup Tables</name>
          <t>Between the CAS info section and the footer, stored shards include lookup tables for efficient searching:</t>
          <section anchor="file-lookup-table">
            <name>File Lookup Table</name>
            <t>Located at <tt>file_lookup_offset</tt>, contains <tt>file_lookup_num_entries</tt> entries.
Each entry is 12 bytes:</t>
            <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       8     Truncated File Hash (64-bit unsigned, first 8 bytes of hash)
8       4     File Info Entry Index (32-bit unsigned)
]]></artwork>
            <t>Entries are sorted by truncated hash for binary search.</t>
          </section>
          <section anchor="cas-lookup-table">
            <name>CAS Lookup Table</name>
            <t>Located at <tt>cas_lookup_offset</tt>, contains <tt>cas_lookup_num_entries</tt> entries.
Each entry is 12 bytes:</t>
            <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       8     Truncated CAS Hash (64-bit unsigned, first 8 bytes of hash)
8       4     CAS Info Entry Index (32-bit unsigned)
]]></artwork>
            <t>Entries are sorted by truncated hash for binary search.</t>
          </section>
          <section anchor="chunk-lookup-table">
            <name>Chunk Lookup Table</name>
            <t>Located at <tt>chunk_lookup_offset</tt>, contains <tt>chunk_lookup_num_entries</tt> entries.
Each entry is 16 bytes:</t>
            <artwork><![CDATA[
Offset  Size  Field
------  ----  -----
0       8     Truncated Chunk Hash (64-bit unsigned, first 8 bytes of hash)
8       4     CAS Entry Index (32-bit unsigned)
12      4     Chunk Index within CAS (32-bit unsigned)
]]></artwork>
            <t>Entries are sorted by truncated hash for binary search.
When keyed hash protection is enabled, the truncated hash is computed from the keyed chunk hash, not the original.</t>
          </section>
        </section>
        <section anchor="chunk-hash-key-usage">
          <name>Chunk Hash Key Usage</name>
          <t>In global deduplication responses, chunk hashes in the CAS info section are protected with a keyed hash.
Clients <bcp14>MUST</bcp14>:</t>
          <ol spacing="normal" type="1"><li>
              <t>Compute <tt>keyed_hash(footer.chunk_hash_key, their_chunk_hash)</tt> for each local chunk</t>
            </li>
            <li>
              <t>Search for matches in the shard’s CAS info section using the keyed hashes</t>
            </li>
            <li>
              <t>Use matched xorb references for deduplication</t>
            </li>
          </ol>
          <t>If <tt>chunk_hash_key</tt> is all zeros, chunk hashes are stored without keyed hash protection.</t>
        </section>
      </section>
    </section>
    <section anchor="deduplication">
      <name>Deduplication</name>
      <t>XET supports chunk-level deduplication at multiple levels to minimize storage and transfer overhead.</t>
      <section anchor="local-session-deduplication">
        <name>Local Session Deduplication</name>
        <t>Within a single upload session, implementations <bcp14>SHOULD</bcp14> track chunk hashes to avoid processing identical chunks multiple times.</t>
      </section>
      <section anchor="cached-metadata-deduplication">
        <name>Cached Metadata Deduplication</name>
        <t>Implementations <bcp14>MAY</bcp14> cache shard metadata locally to enable deduplication against recently uploaded content without network queries.</t>
      </section>
      <section anchor="global-deduplication">
        <name>Global Deduplication</name>
        <t>The global deduplication API enables discovering existing chunks across the entire storage system.</t>
        <section anchor="eligibility-criteria">
          <name>Eligibility Criteria</name>
          <t>Not all chunks are eligible for global deduplication queries.
A chunk is eligible if:</t>
          <ol spacing="normal" type="1"><li>
              <t>It is the first chunk of a file, OR</t>
            </li>
            <li>
              <t>The last 8 bytes of its hash, interpreted as a little-endian 64-bit unsigned integer, satisfy: <tt>value % 1024 == 0</tt></t>
            </li>
          </ol>
        </section>
        <section anchor="query-process">
          <name>Query Process</name>
          <ol spacing="normal" type="1"><li>
              <t>For eligible chunks, query the global deduplication API.</t>
            </li>
            <li>
              <t>On a match, the API returns a shard containing CAS info for xorbs containing the chunk.</t>
            </li>
            <li>
              <t>Chunk hashes in the response are protected with a keyed hash; match by computing keyed hashes of local chunk hashes.</t>
            </li>
            <li>
              <t>Record matched xorb references for use in file reconstruction terms.</t>
            </li>
          </ol>
        </section>
        <section anchor="keyed-hash-security">
          <name>Keyed Hash Security</name>
          <t>The keyed hash protection ensures that clients can only identify chunks they already possess:</t>
          <ol spacing="normal" type="1"><li>
              <t>The server never reveals raw chunk hashes to clients.</t>
            </li>
            <li>
              <t>Clients must compute <tt>keyed_hash(key, local_hash)</tt> to find matches.</t>
            </li>
            <li>
              <t>A match confirms the client has the data, enabling reference to the existing xorb.</t>
            </li>
          </ol>
        </section>
      </section>
      <section anchor="fragmentation-prevention">
        <name>Fragmentation Prevention</name>
        <t>Aggressive deduplication can fragment files across many xorbs, harming read performance.
Implementations <bcp14>SHOULD</bcp14>:</t>
        <ul spacing="normal">
          <li>
            <t>Prefer longer contiguous chunk ranges over maximum deduplication</t>
          </li>
          <li>
            <t>Target minimum run lengths (e.g., 8 chunks or 1 MiB) before accepting deduplicated references</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="upload-protocol">
      <name>Upload Protocol</name>
      <t>This section describes the complete procedure for uploading files.</t>
      <section anchor="step-1-chunking">
        <name>Step 1: Chunking</name>
        <t>Split each file into chunks using the algorithm in <xref target="content-defined-chunking"/>.</t>
        <t>For each chunk:</t>
        <ol spacing="normal" type="1"><li>
            <t>Compute the chunk hash (see <xref target="chunk-hashes"/>)</t>
          </li>
          <li>
            <t>Record the chunk data, hash, and size</t>
          </li>
        </ol>
      </section>
      <section anchor="step-2-deduplication">
        <name>Step 2: Deduplication</name>
        <t>For each chunk, attempt deduplication in order:</t>
        <ol spacing="normal" type="1"><li>
            <t>Local Session: Check if chunk hash was seen earlier in this session</t>
          </li>
          <li>
            <t>Cached Metadata: Check local shard cache for chunk hash</t>
          </li>
          <li>
            <t>Global API: For eligible chunks, query the global deduplication API</t>
          </li>
        </ol>
        <t>Record deduplication results:</t>
        <ul spacing="normal">
          <li>
            <t>New chunks: Will be included in xorbs</t>
          </li>
          <li>
            <t>Deduplicated chunks: Record existing xorb hash and chunk index</t>
          </li>
        </ul>
      </section>
      <section anchor="step-3-xorb-formation">
        <name>Step 3: Xorb Formation</name>
        <t>Group new (non-deduplicated) chunks into xorbs:</t>
        <ol spacing="normal" type="1"><li>
            <t>Collect chunks maintaining their order within files</t>
          </li>
          <li>
            <t>Form xorbs targeting ~64 MiB total size</t>
          </li>
          <li>
            <t>Compute compression for each chunk</t>
          </li>
          <li>
            <t>Compute xorb hash for each xorb (see <xref target="xorb-hashes"/>)</t>
          </li>
        </ol>
      </section>
      <section anchor="step-4-xorb-serialization-and-upload">
        <name>Step 4: Xorb Serialization and Upload</name>
        <t>For each new xorb:</t>
        <ol spacing="normal" type="1"><li>
            <t>Serialize using the format in <xref target="xorb-format"/></t>
          </li>
          <li>
            <t>Upload to the CAS server</t>
          </li>
          <li>
            <t>Verify successful response</t>
          </li>
        </ol>
        <t>All xorbs <bcp14>MUST</bcp14> be uploaded before proceeding to shard upload.</t>
      </section>
      <section anchor="step-5-shard-formation">
        <name>Step 5: Shard Formation</name>
        <t>Build the shard structure:</t>
        <ol spacing="normal" type="1"><li>
            <t>For each file, construct file reconstruction terms</t>
          </li>
          <li>
            <t>Compute verification hashes for each term (see <xref target="verification-hashes"/>)</t>
          </li>
          <li>
            <t>Compute file hash (see <xref target="file-hashes"/>)</t>
          </li>
          <li>
            <t>Compute SHA-256 of raw file contents</t>
          </li>
          <li>
            <t>Build CAS info blocks for new xorbs</t>
          </li>
        </ol>
      </section>
      <section anchor="step-6-shard-upload">
        <name>Step 6: Shard Upload</name>
        <ol spacing="normal" type="1"><li>
            <t>Serialize the shard without footer</t>
          </li>
          <li>
            <t>Upload to the CAS server</t>
          </li>
          <li>
            <t>Verify successful response</t>
          </li>
        </ol>
      </section>
      <section anchor="ordering-and-concurrency">
        <name>Ordering and Concurrency</name>
        <t>The following ordering constraints apply:</t>
        <ul spacing="normal">
          <li>
            <t>All xorbs referenced by a shard <bcp14>MUST</bcp14> be uploaded before the shard</t>
          </li>
          <li>
            <t>Chunk computation for a file must complete before xorb formation</t>
          </li>
          <li>
            <t>Xorb hash computation must complete before shard formation</t>
          </li>
        </ul>
        <t>Within these constraints, operations <bcp14>MAY</bcp14> be parallelized:</t>
        <ul spacing="normal">
          <li>
            <t>Multiple files can be chunked concurrently</t>
          </li>
          <li>
            <t>Multiple xorbs can be uploaded concurrently</t>
          </li>
          <li>
            <t>Deduplication queries can run in parallel</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="download-protocol">
      <name>Download Protocol</name>
      <t>This section describes the complete procedure for downloading files.</t>
      <section anchor="step-1-query-reconstruction">
        <name>Step 1: Query Reconstruction</name>
        <t>Request file reconstruction information from the CAS server by providing the file hash.
For partial downloads (range queries), specify the desired byte range.</t>
      </section>
      <section anchor="step-2-parse-response">
        <name>Step 2: Parse Response</name>
        <t>The reconstruction response provides:</t>
        <ul spacing="normal">
          <li>
            <t>Bytes to skip in the first term (for range queries)</t>
          </li>
          <li>
            <t>An ordered list of terms to process</t>
          </li>
          <li>
            <t>URLs and byte ranges for downloading xorb data</t>
          </li>
        </ul>
      </section>
      <section anchor="step-3-download-xorb-data">
        <name>Step 3: Download Xorb Data</name>
        <t>For each term:</t>
        <ol spacing="normal" type="1"><li>
            <t>Identify the xorb and byte range needed for the term’s chunk range</t>
          </li>
          <li>
            <t>Download the xorb data from the provided URL</t>
          </li>
          <li>
            <t>Use HTTP range requests when only a portion of the xorb is needed</t>
          </li>
        </ol>
        <t>Multiple terms may reference the same xorb; implementations <bcp14>SHOULD</bcp14> avoid redundant downloads.</t>
      </section>
      <section anchor="step-4-extract-chunks">
        <name>Step 4: Extract Chunks</name>
        <t>For each downloaded xorb range:</t>
        <ol spacing="normal" type="1"><li>
            <t>Parse chunk headers sequentially</t>
          </li>
          <li>
            <t>Decompress chunk data according to compression type</t>
          </li>
          <li>
            <t>Extract chunks for the term’s index range</t>
          </li>
        </ol>
      </section>
      <section anchor="step-5-assemble-file">
        <name>Step 5: Assemble File</name>
        <ol spacing="normal" type="1"><li>
            <t>For the first term, skip <tt>offset_into_first_range</tt> bytes</t>
          </li>
          <li>
            <t>Concatenate extracted chunks in term order</t>
          </li>
          <li>
            <t>For range queries, truncate to requested length</t>
          </li>
          <li>
            <t>Write to output file or buffer</t>
          </li>
        </ol>
      </section>
      <section anchor="caching-recommendations">
        <name>Caching Recommendations</name>
        <t>See <xref target="caching-considerations"/> for comprehensive caching guidance.
Key recommendations:</t>
        <ul spacing="normal">
          <li>
            <t>Cache decompressed chunks by hash for reuse across files and sessions</t>
          </li>
          <li>
            <t>Avoid caching reconstruction API responses (pre-signed URLs expire quickly)</t>
          </li>
          <li>
            <t>Cache shard metadata for local deduplication during uploads</t>
          </li>
        </ul>
      </section>
      <section anchor="error-handling">
        <name>Error Handling</name>
        <t>Implementations <bcp14>SHOULD</bcp14> implement:</t>
        <ul spacing="normal">
          <li>
            <t>Retry logic with exponential backoff for transient failures</t>
          </li>
          <li>
            <t>Validation of decompressed chunk sizes against headers</t>
          </li>
          <li>
            <t>Hash verification of reconstructed files when possible</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="caching-considerations">
      <name>Caching Considerations</name>
      <t>XET’s content-addressable design enables effective caching at multiple levels.
This section provides guidance for implementers on caching strategies and considerations.</t>
      <section anchor="content-immutability">
        <name>Content Immutability</name>
        <t>Objects in XET are identified by cryptographic hashes of their content.
This content-addressable design provides a fundamental property: content at a given hash never changes.
A xorb with hash H will always contain the same bytes, and a chunk with hash C will always decompress to the same data.</t>
        <t>This immutability enables aggressive caching:</t>
        <ul spacing="normal">
          <li>
            <t>Cached xorb data never becomes stale</t>
          </li>
          <li>
            <t>Cached chunk data can be reused indefinitely</t>
          </li>
          <li>
            <t>Cache invalidation is never required for content objects</t>
          </li>
        </ul>
        <t>The only time-sensitive elements are authentication tokens and pre-signed URLs, which are discussed separately below.</t>
      </section>
      <section anchor="client-side-chunk-caching">
        <name>Client-Side Chunk Caching</name>
        <t>Implementations <bcp14>SHOULD</bcp14> cache decompressed chunk data to avoid redundant decompression and network requests.
The chunk hash provides a natural cache key.</t>
        <section anchor="cache-key-design">
          <name>Cache Key Design</name>
          <t>Chunk caches <bcp14>SHOULD</bcp14> use the chunk hash (32 bytes or its string representation) as the cache key.
Since hashes uniquely identify content, there is no risk of cache collisions or stale data.</t>
        </section>
        <section anchor="cache-granularity">
          <name>Cache Granularity</name>
          <t>Implementations <bcp14>MAY</bcp14> cache at different granularities:</t>
          <ul spacing="normal">
            <li>
              <t>Individual chunks: Fine-grained, maximizes deduplication benefit</t>
            </li>
            <li>
              <t>Chunk ranges: Coarser-grained, reduces metadata overhead</t>
            </li>
            <li>
              <t>Complete xorbs: Simplest, but may cache unused chunks</t>
            </li>
          </ul>
          <t>For most workloads, caching individual chunks by hash provides the best balance of storage efficiency and hit rate.</t>
        </section>
        <section anchor="eviction-strategies">
          <name>Eviction Strategies</name>
          <t>Since all cached content remains valid indefinitely, eviction is based purely on resource constraints:</t>
          <ul spacing="normal">
            <li>
              <t>LRU (Least Recently Used): Effective for workloads with temporal locality</t>
            </li>
            <li>
              <t>LFU (Least Frequently Used): Effective for workloads with stable hot sets</t>
            </li>
            <li>
              <t>Size-aware LRU: Prioritizes keeping smaller chunks that are cheaper to re-fetch</t>
            </li>
          </ul>
          <t>Implementations <bcp14>SHOULD</bcp14> track cache size and implement eviction when storage limits are reached.</t>
        </section>
      </section>
      <section anchor="xorb-data-caching">
        <name>Xorb Data Caching</name>
        <t>Raw xorb data (compressed chunks with headers) <bcp14>MAY</bcp14> be cached by clients or intermediaries.</t>
        <section anchor="client-side-xorb-cache">
          <name>Client-Side Xorb Cache</name>
          <t>Caching raw xorb byte ranges avoids repeated downloads but requires decompression on each use.
This uses local storage to reduce bandwidth consumption.
Implementations <bcp14>SHOULD</bcp14> prefer caching decompressed chunks unless bandwidth is severely constrained.</t>
        </section>
        <section anchor="byte-range-considerations">
          <name>Byte Range Considerations</name>
          <t>When caching partial xorb downloads (byte ranges), implementations <bcp14>SHOULD</bcp14>:</t>
          <ol spacing="normal" type="1"><li>
              <t>Cache at chunk-header-aligned boundaries to enable independent chunk extraction</t>
            </li>
            <li>
              <t>Track which byte ranges are cached for each xorb hash</t>
            </li>
            <li>
              <t>Coalesce adjacent cached ranges when possible</t>
            </li>
          </ol>
        </section>
      </section>
      <section anchor="shard-metadata-caching">
        <name>Shard Metadata Caching</name>
        <t>Shard metadata enables deduplication without network queries.
Implementations <bcp14>SHOULD</bcp14> cache shards from recent uploads for local deduplication.</t>
        <section anchor="cache-lifetime">
          <name>Cache Lifetime</name>
          <t>Unlike content objects, shard metadata has implicit lifetime constraints:</t>
          <ul spacing="normal">
            <li>
              <t>Global deduplication responses include a <tt>chunk_hash_key</tt> that rotates periodically</t>
            </li>
            <li>
              <t>The <tt>shard_key_expiry</tt> field in the footer indicates when the key expires</t>
            </li>
            <li>
              <t>After expiry, keyed hash matches will fail</t>
            </li>
          </ul>
          <t>Implementations <bcp14>SHOULD</bcp14> evict cached deduplication shards when their keys expire.</t>
        </section>
        <section anchor="cache-size">
          <name>Cache Size</name>
          <t>Shard metadata is relatively compact (typically under 1 MiB per upload session).
Implementations <bcp14>MAY</bcp14> cache several hundred recent shards without significant storage impact.</t>
        </section>
      </section>
      <section anchor="pre-signed-url-handling">
        <name>Pre-Signed URL Handling</name>
        <t>The reconstruction API returns pre-signed URLs for downloading xorb data.
These URLs have short expiration times (typically minutes to hours) and <bcp14>MUST NOT</bcp14> be cached beyond their validity period.</t>
        <t>Implementations <bcp14>MUST</bcp14>:</t>
        <ul spacing="normal">
          <li>
            <t>Use URLs promptly after receiving them</t>
          </li>
          <li>
            <t>Re-query the reconstruction API if URLs have expired</t>
          </li>
          <li>
            <t>Never persist URLs to disk for later sessions</t>
          </li>
        </ul>
        <t>Reconstruction responses <bcp14>SHOULD</bcp14> be treated as ephemeral and re-fetched when needed rather than cached.</t>
      </section>
      <section anchor="http-caching-headers">
        <name>HTTP Caching Headers</name>
        <section anchor="server-recommendations">
          <name>Server Recommendations</name>
          <t>CAS servers <bcp14>SHOULD</bcp14> return appropriate HTTP caching headers for xorb downloads:</t>
          <t>For xorb content (immutable):</t>
          <artwork><![CDATA[
Cache-Control: public, immutable, max-age=<url_ttl_seconds>
ETag: "<xorb_hash>"
]]></artwork>
          <ul spacing="normal">
            <li>
              <t><tt>max-age</tt> <bcp14>MUST</bcp14> be set to a value no greater than the remaining validity window of the pre-signed URL used to serve the object (e.g., a URL that expires in 900 seconds <bcp14>MUST NOT</bcp14> be served with <tt>max-age</tt> larger than 900).</t>
            </li>
            <li>
              <t>Servers <bcp14>SHOULD</bcp14> also emit an <tt>Expires</tt> header aligned to the URL expiry time.</t>
            </li>
            <li>
              <t>Shared caches <bcp14>MUST NOT</bcp14> serve the response after either header indicates expiry, even if the content is immutable.</t>
            </li>
          </ul>
          <t>The <tt>immutable</tt> directive still applies within that bounded window, allowing caches to skip revalidation until the signature expires.</t>
          <t>For reconstruction API responses (ephemeral):</t>
          <artwork><![CDATA[
Cache-Control: private, no-store
]]></artwork>
          <t>Reconstruction responses contain pre-signed URLs that expire and <bcp14>MUST NOT</bcp14> be cached by intermediaries.</t>
          <t>For global deduplication responses:</t>
          <artwork><![CDATA[
Cache-Control: private, max-age=3600
Vary: Authorization
]]></artwork>
          <t>Deduplication responses are user-specific and may be cached briefly by the client.</t>
        </section>
        <section anchor="client-recommendations">
          <name>Client Recommendations</name>
          <t>Clients <bcp14>SHOULD</bcp14> respect <tt>Cache-Control</tt> headers from servers.
When downloading xorb data, clients <bcp14>MAY</bcp14> cache responses locally even if no caching headers are present, since content-addressed data is inherently immutable.</t>
        </section>
      </section>
      <section anchor="cdn-integration">
        <name>CDN Integration</name>
        <t>XET deployments typically serve xorb data through CDNs.
The content-addressable design is well-suited for CDN caching:</t>
        <ul spacing="normal">
          <li>
            <t>Hash-based URLs enable cache key stability</t>
          </li>
          <li>
            <t>Immutable content eliminates cache invalidation complexity</t>
          </li>
          <li>
            <t>Range requests enable partial caching of large xorbs</t>
          </li>
        </ul>
        <section anchor="cdn-cache-keys">
          <name>CDN Cache Keys</name>
          <t>Effective cache key design determines whether multiple users can share cached xorb data.
Since xorb content is immutable and identified by hash, the ideal cache key includes only the xorb hash and byte range, maximizing cache reuse.
However, access control requirements constrain this choice.</t>
          <t>Two URL authorization strategies are applicable to XET deployments:</t>
          <t><strong>Edge-Authenticated URLs.</strong>
The URL path contains the xorb hash with no signature parameters.
Authorization is enforced at the CDN edge via signed cookies or tokens validated on every request.
The cache key is derived from the xorb hash and byte range only, excluding any authorization tokens.
This allows all authorized users to share the same cache entries.
This pattern requires CDNs capable of per-request authorization; generic shared caches without edge auth <bcp14>MUST NOT</bcp14> be used.</t>
          <t><strong>Query-Signed URLs.</strong>
The URL includes signature parameters in the query string (similar to pre-signed cloud storage URLs).
Cache keys <bcp14>MUST</bcp14> include all signature-bearing query parameters.
Each unique signature produces a separate cache entry, resulting in lower hit rates.
This approach works with any CDN but sacrifices cache efficiency for simplicity.</t>
          <t>For both strategies:</t>
          <ul spacing="normal">
            <li>
              <t>Cache keys <bcp14>SHOULD</bcp14> include the byte range when <tt>Range</tt> headers are present</t>
            </li>
            <li>
              <t>Cache keys <bcp14>SHOULD NOT</bcp14> include <tt>Authorization</tt> headers, since different users have different tokens but request identical content</t>
            </li>
          </ul>
          <t>For deployments with access-controlled content (e.g., gated models requiring user agreement), see <xref target="access-controlled-content"/> for additional CDN considerations.</t>
        </section>
        <section anchor="range-request-caching">
          <name>Range Request Caching</name>
          <t>CDNs <bcp14>SHOULD</bcp14> cache partial responses (<tt>206 Partial Content</tt>) by byte range.
When a subsequent request covers a cached range, the CDN can serve from cache without contacting the origin.</t>
          <t>Some CDNs support range coalescing, where multiple partial caches are combined to serve larger requests.
This is particularly effective for XET where different users may request different chunk ranges from the same xorb.</t>
        </section>
      </section>
      <section anchor="proxy-and-intermediary-considerations">
        <name>Proxy and Intermediary Considerations</name>
        <t>Corporate proxies and other intermediaries <bcp14>MAY</bcp14> cache XET traffic.</t>
        <t>Pre-signed URLs include authentication in the URL itself, allowing unauthenticated intermediaries to cache responses.</t>
        <t>However, reconstruction API requests include authentication tokens and <bcp14>SHOULD NOT</bcp14> be cached by intermediaries.</t>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <section anchor="content-integrity">
        <name>Content Integrity</name>
        <t>XET provides content integrity through cryptographic hashing:</t>
        <ul spacing="normal">
          <li>
            <t>Chunk hashes verify individual chunk integrity</t>
          </li>
          <li>
            <t>Xorb hashes verify complete xorb contents</t>
          </li>
          <li>
            <t>File hashes verify complete file reconstruction</t>
          </li>
        </ul>
        <t>Implementations <bcp14>SHOULD</bcp14> verify hashes when possible, particularly for downloaded content.</t>
      </section>
      <section anchor="authentication-and-authorization">
        <name>Authentication and Authorization</name>
        <t>Token-based authentication controls access to storage operations.
Implementations <bcp14>MUST</bcp14>:</t>
        <ul spacing="normal">
          <li>
            <t>Transmit tokens only over TLS-protected connections</t>
          </li>
          <li>
            <t>Avoid logging tokens</t>
          </li>
          <li>
            <t>Implement token refresh before expiration</t>
          </li>
          <li>
            <t>Use minimum required scope (prefer read over write)</t>
          </li>
        </ul>
      </section>
      <section anchor="global-deduplication-privacy">
        <name>Global Deduplication Privacy</name>
        <t>The keyed hash protection in global deduplication prevents enumeration attacks:</t>
        <ul spacing="normal">
          <li>
            <t>Servers never reveal raw chunk hashes</t>
          </li>
          <li>
            <t>Clients can only match chunks they possess</t>
          </li>
          <li>
            <t>The chunk hash key rotates periodically, and shard expiry limits the reuse window</t>
          </li>
        </ul>
      </section>
      <section anchor="access-controlled-content">
        <name>Access-Controlled Content</name>
        <t>XET deployments may support access-controlled or “gated” content, where users must be authorized (e.g., by accepting terms of service or requesting access) before downloading certain files.
This has several implications for XET implementations.</t>
        <section anchor="repository-level-access-control">
          <name>Repository-Level Access Control</name>
          <t>Access control in XET is typically enforced at the repository or file level, not at the xorb or chunk level.
The reconstruction API <bcp14>MUST</bcp14> verify that the requesting user has access to the file before returning pre-signed URLs.
Unauthorized requests <bcp14>MUST</bcp14> return <tt>401 Unauthorized</tt> or <tt>403 Forbidden</tt>.</t>
        </section>
        <section anchor="cdn-considerations-for-gated-content">
          <name>CDN Considerations for Gated Content</name>
          <t>Since the same xorb may be referenced by both public and access-controlled files, CDN caching requires careful design:</t>
          <t><strong>Edge-Authenticated Deployments.</strong>
When using edge authentication (cookies or tokens validated per-request), the CDN enforces access control on every request.
Xorbs referenced only by access-controlled files remain protected even when cached.
This is the recommended approach for deployments with gated content.</t>
          <t><strong>Query-Signed URL Deployments.</strong>
When using query-signed URLs, each authorized user receives unique signatures.
Cache efficiency is reduced, but access control is enforced by signature validity.
Deployments <bcp14>MAY</bcp14> choose to exclude xorbs from access-controlled repositories from CDN caching entirely.</t>
        </section>
        <section anchor="cross-repository-deduplication">
          <name>Cross-Repository Deduplication</name>
          <t>The same chunk may exist in both access-controlled and public repositories.
XET’s content-addressable design allows storage deduplication across access boundaries:</t>
          <ul spacing="normal">
            <li>
              <t>When a user uploads to a public repository, chunks matching access-controlled content may be deduplicated</t>
            </li>
            <li>
              <t>The user does not gain access to the access-controlled repository; they simply avoid re-uploading data they already possess</t>
            </li>
            <li>
              <t>The keyed hash protection in global deduplication (<xref target="global-deduplication"/>) ensures users can only match chunks they possess</t>
            </li>
          </ul>
          <t>This is a storage optimization, not an access control bypass.
Implementations <bcp14>MUST</bcp14> still enforce repository-level access control for all download operations.</t>
        </section>
        <section anchor="privacy-implications">
          <name>Privacy Implications</name>
          <t>Deployments with access-controlled content <bcp14>SHOULD</bcp14> consider:</t>
          <ul spacing="normal">
            <li>
              <t>Global deduplication queries reveal chunk existence (via 200/404 responses), though not which repositories contain the chunk</t>
            </li>
            <li>
              <t>Keyed hash protection in responses ensures clients can only identify chunks they already possess; key rotation limits temporal correlation</t>
            </li>
            <li>
              <t>For highly sensitive content, deployments <bcp14>MAY</bcp14> exclude chunks from the global deduplication index entirely</t>
            </li>
          </ul>
        </section>
      </section>
      <section anchor="denial-of-service-considerations">
        <name>Denial of Service Considerations</name>
        <t>Large file uploads could exhaust server resources.
Servers <bcp14>SHOULD</bcp14> implement:</t>
        <ul spacing="normal">
          <li>
            <t>Rate limiting on API endpoints</t>
          </li>
          <li>
            <t>Maximum shard size limits</t>
          </li>
          <li>
            <t>Maximum xorb size limits (<tt>MAX_XORB_SIZE</tt>, 64 MiB)</t>
          </li>
        </ul>
      </section>
    </section>
    <section numbered="false" anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document does not require any IANA actions.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-combined-references">
      <name>References</name>
      <references anchor="sec-normative-references">
        <name>Normative References</name>
        <reference anchor="BLAKE3" target="https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf">
          <front>
            <title>BLAKE3: One function, fast everywhere</title>
            <author initials="J." surname="Aumasson">
              <organization/>
            </author>
            <author initials="S." surname="Neves">
              <organization/>
            </author>
            <author initials="J." surname="O'Connor">
              <organization/>
            </author>
            <author initials="Z." surname="Wilcox-O'Hearn">
              <organization/>
            </author>
            <date year="2020" month="January" day="09"/>
          </front>
        </reference>
        <reference anchor="LZ4" target="https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md">
          <front>
            <title>LZ4 Frame Format Description</title>
            <author initials="Y." surname="Collet">
              <organization/>
            </author>
            <date year="2015"/>
          </front>
        </reference>
        <reference anchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner" initials="S." surname="Bradner"/>
            <date month="March" year="1997"/>
            <abstract>
              <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B." surname="Leiba"/>
            <date month="May" year="2017"/>
            <abstract>
              <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
      </references>
      <references anchor="sec-informative-references">
        <name>Informative References</name>
        <reference anchor="GEARHASH" target="https://github.com/srijs/rust-gearhash">
          <front>
            <title>rust-gearhash: Fast, SIMD-accelerated GEAR hashing</title>
            <author initials="S." surname="Rijsdijk">
              <organization/>
            </author>
            <date year="2020"/>
          </front>
        </reference>
        <reference anchor="FASTCDC" target="https://www.usenix.org/conference/atc16/technical-sessions/presentation/xia">
          <front>
            <title>FastCDC: A Fast and Efficient Content-Defined Chunking Approach for Data Deduplication</title>
            <author initials="D." surname="Feng">
              <organization/>
            </author>
            <author initials="Y." surname="Hu">
              <organization/>
            </author>
            <author initials="Y." surname="Hua">
              <organization/>
            </author>
            <author initials="H." surname="Jiang">
              <organization/>
            </author>
            <author initials="Q." surname="Liu">
              <organization/>
            </author>
            <author initials="W." surname="Xia">
              <organization/>
            </author>
            <author initials="Y." surname="Zhang">
              <organization/>
            </author>
            <author initials="Y." surname="Zhou">
              <organization/>
            </author>
            <date year="2016"/>
          </front>
          <seriesInfo name="USENIX ATC 2016" value=""/>
        </reference>
        <reference anchor="MERKLE">
          <front>
            <title>A Digital Signature Based on a Conventional Encryption Function</title>
            <author initials="R. C." surname="Merkle">
              <organization/>
            </author>
            <date year="1987"/>
          </front>
          <seriesInfo name="CRYPTO 1987, LNCS 293, pp. 369-378" value=""/>
        </reference>
      </references>
    </references>
    <?line 1617?>

<section anchor="recommended-api">
      <name>Recommended HTTP API</name>
      <t>This appendix defines a recommended HTTP API for CAS servers implementing the XET protocol.
This is informative guidance; deployments <bcp14>MAY</bcp14> use different URL structures, authentication mechanisms, or transport protocols entirely.</t>
      <section anchor="authentication">
        <name>Authentication</name>
        <t>API requests requiring authorization use a Bearer token in the <tt>Authorization</tt> header:</t>
        <artwork><![CDATA[
Authorization: Bearer <access_token>
]]></artwork>
        <t>Token format, acquisition and refresh mechanisms are deployment-specific.</t>
      </section>
      <section anchor="common-headers">
        <name>Common Headers</name>
        <t>Request headers:</t>
        <ul spacing="normal">
          <li>
            <t><tt>Authorization</tt>: Bearer token (when authentication is required)</t>
          </li>
          <li>
            <t><tt>Content-Type</tt>: <tt>application/octet-stream</tt> for binary uploads</t>
          </li>
          <li>
            <t><tt>Range</tt>: Byte range for partial downloads (optional)</t>
          </li>
        </ul>
        <t>Response headers:</t>
        <ul spacing="normal">
          <li>
            <t><tt>Content-Type</tt>: <tt>application/json</tt> or <tt>application/octet-stream</tt></t>
          </li>
        </ul>
      </section>
      <section anchor="get-file-reconstruction">
        <name>Get File Reconstruction</name>
        <t>Retrieves reconstruction information for downloading a file.</t>
        <artwork><![CDATA[
GET /api/v1/reconstructions/{file_hash}
]]></artwork>
        <t>Path parameters:</t>
        <ul spacing="normal">
          <li>
            <t><tt>file_hash</tt>: File hash as hex string (see <xref target="hash-string-format"/>)</t>
          </li>
        </ul>
        <t>Optional request headers:</t>
        <ul spacing="normal">
          <li>
            <t><tt>Range: bytes={start}-{end}</tt>: Request reconstruction for a specific byte range</t>
          </li>
        </ul>
        <t>Response (<tt>200 OK</tt>):</t>
        <sourcecode type="json"><![CDATA[
{
  "offset_into_first_range": 0,
  "terms": [
    {
      "hash": "<xorb_hash_hex>",
      "unpacked_length": 263873,
      "range": {
        "start": 0,
        "end": 4
      }
    }
  ],
  "fetch_info": {
    "<xorb_hash_hex>": [
      {
        "range": {
          "start": 0,
          "end": 4
        },
        "url": "https://...",
        "url_range": {
          "start": 0,
          "end": 131071
        }
      }
    ]
  }
}
]]></sourcecode>
        <t>Response fields:</t>
        <ul spacing="normal">
          <li>
            <t><tt>offset_into_first_range</tt>: Bytes to skip in first term (for range queries)</t>
          </li>
          <li>
            <t><tt>terms</tt>: Ordered list of reconstruction terms</t>
          </li>
          <li>
            <t><tt>fetch_info</tt>: Map from xorb hash to fetch information</t>
          </li>
        </ul>
        <t>Fetch info fields:</t>
        <ul spacing="normal">
          <li>
            <t><tt>range</tt>: Chunk index range this entry covers</t>
          </li>
          <li>
            <t><tt>url</tt>: Pre-signed URL for downloading xorb data</t>
          </li>
          <li>
            <t><tt>url_range</tt>: Byte range within the xorb (end inclusive), directly usable as HTTP <tt>Range</tt> header values</t>
          </li>
        </ul>
        <t>Chunk index ranges (<tt>range</tt> fields) continue to use the document-wide <tt>[start, end)</tt> convention (exclusive end; see <xref target="notational-conventions"/>), while <tt>url_range</tt> follows HTTP Range semantics and is therefore inclusive.</t>
        <t>Error responses:</t>
        <ul spacing="normal">
          <li>
            <t><tt>400 Bad Request</tt>: Invalid file hash format</t>
          </li>
          <li>
            <t><tt>401 Unauthorized</tt>: Missing or invalid token</t>
          </li>
          <li>
            <t><tt>404 Not Found</tt>: File does not exist</t>
          </li>
          <li>
            <t><tt>416 Range Not Satisfiable</tt>: Invalid byte range</t>
          </li>
        </ul>
      </section>
      <section anchor="query-chunk-deduplication">
        <name>Query Chunk Deduplication</name>
        <t>Checks if a chunk exists in the global deduplication index.</t>
        <artwork><![CDATA[
GET /api/v1/chunks/{namespace}/{chunk_hash}
]]></artwork>
        <t>Path parameters:</t>
        <ul spacing="normal">
          <li>
            <t><tt>namespace</tt>: Deduplication namespace (e.g., <tt>default-merkledb</tt>)</t>
          </li>
          <li>
            <t><tt>chunk_hash</tt>: Chunk hash as hex string (see <xref target="hash-string-format"/>)</t>
          </li>
        </ul>
        <t>Response (<tt>200 OK</tt>): Shard format binary (see <xref target="shard-format"/>)</t>
        <t>The returned shard contains CAS info for xorbs that include the queried chunk.
Chunk hashes in the response are protected with a keyed hash (see <xref target="global-deduplication"/>).</t>
        <t>Response (<tt>404 Not Found</tt>): Chunk is not tracked by global deduplication.</t>
      </section>
      <section anchor="upload-xorb">
        <name>Upload Xorb</name>
        <t>Uploads a serialized xorb to storage.</t>
        <artwork><![CDATA[
POST /api/v1/xorbs/{namespace}/{xorb_hash}
Content-Type: application/octet-stream
]]></artwork>
        <t>Path parameters:</t>
        <ul spacing="normal">
          <li>
            <t><tt>namespace</tt>: Storage namespace (e.g., <tt>default</tt>)</t>
          </li>
          <li>
            <t><tt>xorb_hash</tt>: Xorb hash as hex string (see <xref target="hash-string-format"/>)</t>
          </li>
        </ul>
        <t>Request body: Serialized xorb binary (see <xref target="xorb-format"/>)</t>
        <t>Response (<tt>200 OK</tt>):</t>
        <sourcecode type="json"><![CDATA[
{
  "was_inserted": true
}
]]></sourcecode>
        <t>The <tt>was_inserted</tt> field is <tt>false</tt> if the xorb already existed; this is not an error.</t>
        <t>Error responses:</t>
        <ul spacing="normal">
          <li>
            <t><tt>400 Bad Request</tt>: Hash mismatch or invalid xorb format</t>
          </li>
          <li>
            <t><tt>401 Unauthorized</tt>: Missing or invalid token</t>
          </li>
          <li>
            <t><tt>403 Forbidden</tt>: Insufficient token scope</t>
          </li>
        </ul>
      </section>
      <section anchor="upload-shard">
        <name>Upload Shard</name>
        <t>Uploads a shard to register files in the system.</t>
        <artwork><![CDATA[
POST /api/v1/shards
Content-Type: application/octet-stream
]]></artwork>
        <t>Request body: Serialized shard without footer (see <xref target="shard-format"/>)</t>
        <t>Response (<tt>200 OK</tt>):</t>
        <sourcecode type="json"><![CDATA[
{
  "result": 0
}
]]></sourcecode>
        <t>Result values:</t>
        <ul spacing="normal">
          <li>
            <t><tt>0</tt>: Shard already exists</t>
          </li>
          <li>
            <t><tt>1</tt>: Shard was registered</t>
          </li>
        </ul>
        <t>Error responses:</t>
        <ul spacing="normal">
          <li>
            <t><tt>400 Bad Request</tt>: Invalid shard format or referenced xorb missing</t>
          </li>
          <li>
            <t><tt>401 Unauthorized</tt>: Missing or invalid token</t>
          </li>
          <li>
            <t><tt>403 Forbidden</tt>: Insufficient token scope</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="gearhash-table">
      <name>Gearhash Lookup Table</name>
      <t>The <tt>XET-BLAKE3-GEARHASH-LZ4</tt> content-defined chunking algorithm requires a lookup table of 256 64-bit constants.
Implementations of this suite <bcp14>MUST</bcp14> use the exact values below for determinism.</t>
      <artwork><![CDATA[
TABLE = [
    0xb088d3a9e840f559, 0x5652c7f739ed20d6, 0x45b28969898972ab, 0x6b0a89d5b68ec777,
    0x368f573e8b7a31b7, 0x1dc636dce936d94b, 0x207a4c4e5554d5b6, 0xa474b34628239acb,
    0x3b06a83e1ca3b912, 0x90e78d6c2f02baf7, 0xe1c92df7150d9a8a, 0x8e95053a1086d3ad,
    0x5a2ef4f1b83a0722, 0xa50fac949f807fae, 0x0e7303eb80d8d681, 0x99b07edc1570ad0f,
    0x689d2fb555fd3076, 0x00005082119ea468, 0xc4b08306a88fcc28, 0x3eb0678af6374afd,
    0xf19f87ab86ad7436, 0xf2129fbfbe6bc736, 0x481149575c98a4ed, 0x0000010695477bc5,
    0x1fba37801a9ceacc, 0x3bf06fd663a49b6d, 0x99687e9782e3874b, 0x79a10673aa50d8e3,
    0xe4accf9e6211f420, 0x2520e71f87579071, 0x2bd5d3fd781a8a9b, 0x00de4dcddd11c873,
    0xeaa9311c5a87392f, 0xdb748eb617bc40ff, 0xaf579a8df620bf6f, 0x86a6e5da1b09c2b1,
    0xcc2fc30ac322a12e, 0x355e2afec1f74267, 0x2d99c8f4c021a47b, 0xbade4b4a9404cfc3,
    0xf7b518721d707d69, 0x3286b6587bf32c20, 0x0000b68886af270c, 0xa115d6e4db8a9079,
    0x484f7e9c97b2e199, 0xccca7bb75713e301, 0xbf2584a62bb0f160, 0xade7e813625dbcc8,
    0x000070940d87955a, 0x8ae69108139e626f, 0xbd776ad72fde38a2, 0xfb6b001fc2fcc0cf,
    0xc7a474b8e67bc427, 0xbaf6f11610eb5d58, 0x09cb1f5b6de770d1, 0xb0b219e6977d4c47,
    0x00ccbc386ea7ad4a, 0xcc849d0adf973f01, 0x73a3ef7d016af770, 0xc807d2d386bdbdfe,
    0x7f2ac9966c791730, 0xd037a86bc6c504da, 0xf3f17c661eaa609d, 0xaca626b04daae687,
    0x755a99374f4a5b07, 0x90837ee65b2caede, 0x6ee8ad93fd560785, 0x0000d9e11053edd8,
    0x9e063bb2d21cdbd7, 0x07ab77f12a01d2b2, 0xec550255e6641b44, 0x78fb94a8449c14c6,
    0xc7510e1bc6c0f5f5, 0x0000320b36e4cae3, 0x827c33262c8b1a2d, 0x14675f0b48ea4144,
    0x267bd3a6498deceb, 0xf1916ff982f5035e, 0x86221b7ff434fb88, 0x9dbecee7386f49d8,
    0xea58f8cac80f8f4a, 0x008d198692fc64d8, 0x6d38704fbabf9a36, 0xe032cb07d1e7be4c,
    0x228d21f6ad450890, 0x635cb1bfc02589a5, 0x4620a1739ca2ce71, 0xa7e7dfe3aae5fb58,
    0x0c10ca932b3c0deb, 0x2727fee884afed7b, 0xa2df1c6df9e2ab1f, 0x4dcdd1ac0774f523,
    0x000070ffad33e24e, 0xa2ace87bc5977816, 0x9892275ab4286049, 0xc2861181ddf18959,
    0xbb9972a042483e19, 0xef70cd3766513078, 0x00000513abfc9864, 0xc058b61858c94083,
    0x09e850859725e0de, 0x9197fb3bf83e7d94, 0x7e1e626d12b64bce, 0x520c54507f7b57d1,
    0xbee1797174e22416, 0x6fd9ac3222e95587, 0x0023957c9adfbf3e, 0xa01c7d7e234bbe15,
    0xaba2c758b8a38cbb, 0x0d1fa0ceec3e2b30, 0x0bb6a58b7e60b991, 0x4333dd5b9fa26635,
    0xc2fd3b7d4001c1a3, 0xfb41802454731127, 0x65a56185a50d18cb, 0xf67a02bd8784b54f,
    0x696f11dd67e65063, 0x00002022fca814ab, 0x8cd6be912db9d852, 0x695189b6e9ae8a57,
    0xee9453b50ada0c28, 0xd8fc5ea91a78845e, 0xab86bf191a4aa767, 0x0000c6b5c86415e5,
    0x267310178e08a22e, 0xed2d101b078bca25, 0x3b41ed84b226a8fb, 0x13e622120f28dc06,
    0xa315f5ebfb706d26, 0x8816c34e3301bace, 0xe9395b9cbb71fdae, 0x002ce9202e721648,
    0x4283db1d2bb3c91c, 0xd77d461ad2b1a6a5, 0xe2ec17e46eeb866b, 0xb8e0be4039fbc47c,
    0xdea160c4d5299d04, 0x7eec86c8d28c3634, 0x2119ad129f98a399, 0xa6ccf46b61a283ef,
    0x2c52cedef658c617, 0x2db4871169acdd83, 0x0000f0d6f39ecbe9, 0x3dd5d8c98d2f9489,
    0x8a1872a22b01f584, 0xf282a4c40e7b3cf2, 0x8020ec2ccb1ba196, 0x6693b6e09e59e313,
    0x0000ce19cc7c83eb, 0x20cb5735f6479c3b, 0x762ebf3759d75a5b, 0x207bfe823d693975,
    0xd77dc112339cd9d5, 0x9ba7834284627d03, 0x217dc513e95f51e9, 0xb27b1a29fc5e7816,
    0x00d5cd9831bb662d, 0x71e39b806d75734c, 0x7e572af006fb1a23, 0xa2734f2f6ae91f85,
    0xbf82c6b5022cddf2, 0x5c3beac60761a0de, 0xcdc893bb47416998, 0x6d1085615c187e01,
    0x77f8ae30ac277c5d, 0x917c6b81122a2c91, 0x5b75b699add16967, 0x0000cf6ae79a069b,
    0xf3c40afa60de1104, 0x2063127aa59167c3, 0x621de62269d1894d, 0xd188ac1de62b4726,
    0x107036e2154b673c, 0x0000b85f28553a1d, 0xf2ef4e4c18236f3d, 0xd9d6de6611b9f602,
    0xa1fc7955fb47911c, 0xeb85fd032f298dbd, 0xbe27502fb3befae1, 0xe3034251c4cd661e,
    0x441364d354071836, 0x0082b36c75f2983e, 0xb145910316fa66f0, 0x021c069c9847caf7,
    0x2910dfc75a4b5221, 0x735b353e1c57a8b5, 0xce44312ce98ed96c, 0xbc942e4506bdfa65,
    0xf05086a71257941b, 0xfec3b215d351cead, 0x00ae1055e0144202, 0xf54b40846f42e454,
    0x00007fd9c8bcbcc8, 0xbfbd9ef317de9bfe, 0xa804302ff2854e12, 0x39ce4957a5e5d8d4,
    0xffb9e2a45637ba84, 0x55b9ad1d9ea0818b, 0x00008acbf319178a, 0x48e2bfc8d0fbfb38,
    0x8be39841e848b5e8, 0x0e2712160696a08b, 0xd51096e84b44242a, 0x1101ba176792e13a,
    0xc22e770f4531689d, 0x1689eff272bbc56c, 0x00a92a197f5650ec, 0xbc765990bda1784e,
    0xc61441e392fcb8ae, 0x07e13a2ced31e4a0, 0x92cbe984234e9d4d, 0x8f4ff572bb7d8ac5,
    0x0b9670c00b963bd0, 0x62955a581a03eb01, 0x645f83e5ea000254, 0x41fce516cd88f299,
    0xbbda9748da7a98cf, 0x0000aab2fe4845fa, 0x19761b069bf56555, 0x8b8f5e8343b6ad56,
    0x3e5d1cfd144821d9, 0xec5c1e2ca2b0cd8f, 0xfaf7e0fea7fbb57f, 0x000000d3ba12961b,
    0xda3f90178401b18e, 0x70ff906de33a5feb, 0x0527d5a7c06970e7, 0x22d8e773607c13e9,
    0xc9ab70df643c3bac, 0xeda4c6dc8abe12e3, 0xecef1f410033e78a, 0x0024c2b274ac72cb,
    0x06740d954fa900b4, 0x1d7a299b323d6304, 0xb3c37cb298cbead5, 0xc986e3c76178739b,
    0x9fabea364b46f58a, 0x6da214c5af85cc56, 0x17a43ed8b7a38f84, 0x6eccec511d9adbeb,
    0xf9cab30913335afb, 0x4a5e60c5f415eed2, 0x00006967503672b4, 0x9da51d121454bb87,
    0x84321e13b9bbc816, 0xfb3d6fb6ab2fdd8d, 0x60305eed8e160a8d, 0xcbbf4b14e9946ce8,
    0x00004f63381b10c3, 0x07d5b7816fcc4e10, 0xe5a536726a6a8155, 0x57afb23447a07fdd,
    0x18f346f7abc9d394, 0x636dc655d61ad33d, 0xcc8bab4939f7f3f6, 0x63c7a906c1dd187b
]
]]></artwork>
      <t>This table is from the <tt>rust-gearhash</tt> crate <xref target="GEARHASH"/>.</t>
    </section>
    <section anchor="test-vectors">
      <name>Test Vectors</name>
      <t>The following test vectors are for the <tt>XET-BLAKE3-GEARHASH-LZ4</tt> algorithm suite.</t>
      <section anchor="chunk-hash-test-vector">
        <name>Chunk Hash Test Vector</name>
        <artwork><![CDATA[
Input (ASCII): Hello World!
Input (hex): 48656c6c6f20576f726c6421

Hash (raw hex, bytes 0-31):
  a29cfb08e608d4d8726dd8659a90b9134b3240d5d8e42d5fcb28e2a6e763a3e8

Hash (XET string representation):
  d8d408e608fb9ca213b9909a65d86d725f2de4d8d540324be8a363e7a6e228cb
]]></artwork>
      </section>
      <section anchor="hash-string-conversion-test-vector">
        <name>Hash String Conversion Test Vector</name>
        <t>The XET hash string format interprets the 32-byte hash as four little-endian 64-bit unsigned values and prints each as 16 hexadecimal digits.</t>
        <artwork><![CDATA[
Hash bytes [0..31]:
  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
  10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f

Expected XET string:
  07060504030201000f0e0d0c0b0a090817161514131211101f1e1d1c1b1a1918
]]></artwork>
        <t>See the <tt>hash_to_string</tt> function in <xref target="hash-string-format"/> for the conversion algorithm.</t>
      </section>
      <section anchor="internal-node-hash-test-vector">
        <name>Internal Node Hash Test Vector</name>
        <artwork><![CDATA[
Child 1:
  hash (XET string): c28f58387a60d4aa200c311cda7c7f77f686614864f5869eadebf765d0a14a69
  size: 100

Child 2:
  hash (XET string): 6e4e3263e073ce2c0e78cc770c361e2778db3b054b98ab65e277fc084fa70f22
  size: 200

Buffer being hashed (ASCII, with literal \n newlines):
  c28f58387a60d4aa200c311cda7c7f77f686614864f5869eadebf765d0a14a69 : 100\n
  6e4e3263e073ce2c0e78cc770c361e2778db3b054b98ab65e277fc084fa70f22 : 200\n

Result (XET string):
  be64c7003ccd3cf4357364750e04c9592b3c36705dee76a71590c011766b6c14
]]></artwork>
      </section>
      <section anchor="verification-range-hash-test-vector">
        <name>Verification Range Hash Test Vector</name>
        <t>Input: Two chunk hashes from the Internal Node Hash Test Vector above, concatenated as raw bytes (not XET string format).</t>
        <artwork><![CDATA[
Chunk hash 1 (raw hex):
  aad4607a38588fc2777f7cda1c310c209e86f564486186f6694aa1d065f7ebad

Chunk hash 2 (raw hex):
  2cce73e063324e6e271e360c77cc780e65ab984b053bdb78220fa74f08fc77e2

Concatenated input (64 bytes, raw hex):
  aad4607a38588fc2777f7cda1c310c209e86f564486186f6694aa1d065f7ebad
  2cce73e063324e6e271e360c77cc780e65ab984b053bdb78220fa74f08fc77e2

Verification hash (XET string):
  eb06a8ad81d588ac05d1d9a079232d9c1e7d0b07232fa58091caa7bf333a2768
]]></artwork>
      </section>
      <section anchor="reference-files">
        <name>Reference Files</name>
        <t>Complete reference files including sample chunks, xorbs, and shards are available at:
https://huggingface.co/datasets/xet-team/xet-spec-reference-files</t>
      </section>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The XET protocol was invented by Hailey Johnson and Yucheng Low at Hugging Face.
This specification is based on the reference implementation and documentation developed by the Hugging Face team.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA9W9+Xobx7Uv+j+eoo/87RMyIaDuxkzbOYeiKEs7miLKiRNH
l+ihmuwIBLjRgCRuWftZ7rPcJ7u/NVR1dQOg5NjJOVv5QpNAdw2r1jxVt9vt
rMv13BwH9344e30cnC4Xa7NYd0/yfGWqKknnJjhfL1fJpQlerpbrZbacB8Vy
FZwVRZmVeDR4mKyT4PUqWVSFWd3rJGm6Mu9kvHudfJktkmsMn6+SYt3NzaKs
uh/MuhsOOlmyNpfL1e1xUC6KZae8WR0H69WmWsdhOA3jTrVJr8uqKpeL17c3
hp7KzY3Bj8W689bcvl+u8uPgCda7WmDAhzRBJ9msr5ar404QdAOZ+BFW9jZ4
SBPj0yBYri6TRfmfyRrj0utuTN77qkw32C4/aa6Tcn4cFLn532FY9DBJJ8eS
sbU4jEf3Othkv1Otk0V+kcyXC3xxa6pOdZ2s1hf/sVmuTSWf3JTHwY+A3FFQ
LVfrlSkq/HZ7Tb+86XQWy9U1FvPO0KIfPD35w1n/mKe356KfBS8WJig2i4wW
fhQUSbUOzDuzun1/ZVbmHr9S757+dQExLOHfe8HJ5jqpquWi+cV5L3iOEaqt
x1/8BqBYKBTcF3/tBX8u59nyQ/fFbx6bZCWjCUQAkLAbRt1wKktPVpdmfRxc
rdc31fH9+5fl+mqT9rLl9X3ZTXdtEvd7dWOy6n46X6b3sUwcJ35P3pp+7yYv
MNzTvw6aAMEHdKrXJnjEsMPhVtmqvCHA3AGHv/RwwvM5TtFfdzT83Irn/zng
//MCc/PuPnCaPrjgNVwUvIbedd7pEBp7h/nd2cmrxyfnj5urJwTvXgJ+V0l1
BfTEjo+C8yfPHnaTLDNzs8LCcn43oCfKxeUde8IRvir/XuXl39+2TuNzu6pW
eO9+YzF45dHJ+evTh6fNFdMS6cPghFcbAOE98rcc46EpygVWfnq1WbzFqoOT
m5vVMsmumF0wk3ho8s3NvMySz5zUw17wyCwut47v8WbHR0nzs8e94N/LpP3y
H3vB07L19p97wQ9lsjXiX6+23uZPl5sm3oz4z8qsSlPRwds9fH9+9vzJD8HJ
69P6qfY5vH//vrepwJI+9MCO7mfLBVinWWTmfrLOotH9tcmuFoDTvFsZZoDV
/RuwY4CZQXf/A6/72dmrPzw9a57VSfCwxCkn8+C8vFwk683KBA+SCueyXAQJ
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
UYJLom358zndQ/rWgDaeU15HI+4CQWS/pNVYYGA7KXkMsqtynvspuQoO1q88
CPxMXvjlZFTuWt3d5PTk+euzV89Pnl48f/HwbA9dbT3jCCxkhB8bJhchmnFN
LoOxIDEj90iQv2D0njIJCHnKTyGKSUI/Q0Z+o28M+Y2cfw6ZREYFE+m4nm8k
z8Q6BxPoiJ8d2rFoPUk9xlgIvbAERocjGp3GzrdOKtF0J3aFa+JenXFCiSDM
E10KDmODQpCznC6uzIdPsGE+Ej58+ttCJv4zYbj4qOunZtY/DM0O6gE57qEJ
wIwxq4yqCf10KqdKN0tCHC7SeTY8I7syrnh6Xtesdk1/dvzfVOKuoxcxwlMG
AOePKa0xlBbm/VzIQzcCMT7722J2KPSmtPuaaPfUp92PX13zV10ia19toXCu
rQXQPe7gHITe1vccFMmiu9yspcAwoWQV5yvXpDyPhajHuSZEyaAq3xHvoEhV
cqMOLk0BOKA1HDEYDoObpFxZRdTZJavlci0rFde0iPG9rknCjGdnJ88vHrw6
eX76+Mnz7y4enZy+fvEKlDdQ/+CTpw9fnT3HB7H6/uoPgt8Gu9+GYU7Okqnl
96RJAOVfknbrDCYvYsVgrRPTd/Kr2tBkvLmuzPwdsbsTWLuqOAfLDJZvxbak
2NcnNkbXF0xasY5jjdoEj19rqfzJ84cN05mn0xSz3ZuEXZHMK05POwpevOJ0
DkpLU2t3sblOpbeMm/lgekjjyuRiL+T8al9e9cxT4RF88GzJ8bOdzvMltdzh
DMn6KRoypvzcwoBw6zYO0BO5SYZZXXLU+9KQzu9SEipK/rQu8RZDr4ObsVt+
r6UeLMyH9QUPfoETONAIvqgFXzkBfjf+6sOvWIsQflDDzVA3NmmzwtMEB+6k
D9tOQp3d+n4WwTfAz9rjo2rKQpw6BOdvyUVx4GM0iFadPqT3wsxzqZqxKyHH
m90oOAg1WsEZhaC8Q33tmXo9ZLnYu4d27OCoD+xabb4FRpfFNzycMe2a1kk+
zoa/Uh7+sXzTcy5XmfyJrbkN5nRwEzVlrI8GczZzfNWa3yw0aQZgrSciCSHu
5G+DzWhwMTcHVz/Gg+N+7DnlysJ/8N/20Mm2+09Po7R8gnhDUpDocQmjmp5J
Ga+/i+zHVdMph314DAaM9ZLEI2tS5+xnyEzVwlmhBdZQL5bFRaWPMfpcMEY2
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

-->

</rfc>
