<?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.29 (Ruby 3.4.4) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-denis-xet-01" category="info" submissionType="independent" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.31.0 -->
  <front>
    <title abbrev="XET">XET: Content-Addressable Storage Protocol for Efficient Data Transfer</title>
    <seriesInfo name="Internet-Draft" value="draft-denis-xet-01"/>
    <author initials="F." surname="Denis" fullname="Frank Denis">
      <organization>Independent Contributor</organization>
      <address>
        <email>fde@00f.net</email>
      </address>
    </author>
    <date year="2025"/>
    <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-GEARHASH-BLAKE3</tt> algorithm suite as the default, using <tt>Gearhash</tt> for content-defined chunking and <tt>BLAKE3</tt> for cryptographic hashing.</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>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 use different conventions depending on context:</t>
        <table>
          <thead>
            <tr>
              <th align="left">Context</th>
              <th align="left">End Semantics</th>
              <th align="left">Example</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">HTTP <tt>Range</tt> header</td>
              <td align="left">Inclusive</td>
              <td align="left">
                <tt>bytes=0-999</tt> means bytes 0 through 999</td>
            </tr>
            <tr>
              <td align="left">
                <tt>url_range</tt> in <tt>fetch_info</tt></td>
              <td align="left">Inclusive</td>
              <td align="left">
                <tt>{"start": 0, "end": 999}</tt> means bytes 0 through 999</td>
            </tr>
            <tr>
              <td align="left">Chunk index ranges</td>
              <td align="left">Exclusive</td>
              <td align="left">
                <tt>{"start": 0, "end": 4}</tt> means chunks 0, 1, 2, 3</td>
            </tr>
            <tr>
              <td align="left">Shard chunk ranges</td>
              <td align="left">Exclusive</td>
              <td align="left">
                <tt>chunk_index_end</tt> is exclusive</td>
            </tr>
          </tbody>
        </table>
      </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>Content-Defined Chunking Algorithm: The rolling hash function and boundary detection logic used to split files into chunks.</t>
          </li>
          <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>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-GEARHASH-BLAKE3</tt>: Uses <tt>Gearhash</tt> for content-defined chunking and <tt>BLAKE3</tt> for all cryptographic hashing. 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-GEARHASH-BLAKE3</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-GEARHASH-BLAKE3</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-GEARHASH-BLAKE3</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-GEARHASH-BLAKE3</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 = []

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

        chunk_size = i - start_offset + 1

        # Skip boundary checks until minimum size reached
        if chunk_size < MIN_CHUNK_SIZE:
            continue

        # Force boundary at maximum size
        if chunk_size >= MAX_CHUNK_SIZE:
            chunks.append(data[start_offset : i + 1])
            start_offset = i + 1
            h = 0
            continue

        # Check for natural boundary
        if (h & MASK) == 0:
            chunks.append(data[start_offset : i + 1])
            start_offset = i + 1
            h = 0

    # Emit final chunk if any data remains
    if start_offset < length(data):
        chunks.append(data[start_offset : length(data)])

    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-GEARHASH-BLAKE3</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 hash computation for the first <tt>MIN_CHUNK_SIZE - 64 - 1</tt> bytes of each chunk, as boundary tests are not performed in this region.</t>
        <t>This optimization does not affect output correctness because the <tt>Gearhash</tt> window is 64 bytes, ensuring the hash state is fully populated by the time boundary tests begin.</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-GEARHASH-BLAKE3</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-GEARHASH-BLAKE3</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-GEARHASH-BLAKE3</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>
          <artwork><![CDATA[
function compute_internal_hash(children):
    buffer = ""
    for (hash, size) in children:
        buffer += hash_to_string(hash) + " : " + str(size) + "\n"
    return blake3_keyed_hash(INTERNAL_NODE_KEY, buffer.encode("utf-8"))
]]></artwork>
        </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)
    if length(hashes) <= 2:
        return length(hashes)

    end = min(MAX_CHILDREN, length(hashes))

    # Check indices [2, end) using 0-based indexing
    # Minimum merge is 3 children when input has more than 2 hashes
    for i from 2 to end:
        h = hashes[i].hash
        # Interpret last 8 bytes of hash as little-endian 64-bit unsigned int
        hash_value = bytes_to_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 (h, s) in hash_pairs:
        buffer += hash_to_string(h) + " : " + str(s) + "\n"
        total_size += s

    new_hash = blake3_keyed_hash(INTERNAL_NODE_KEY, buffer.encode("utf-8"))
    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 = copy(entries)

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

        while read_idx < length(hv):
            # Find the next cut point
            next_cut = read_idx + next_merge_cut(hv[read_idx:])

            # Merge this slice into one parent node
            hv[write_idx] = merged_hash_of_sequence(hv[read_idx:next_cut])
            write_idx += 1

            read_idx = next_cut

        hv = hv[0:write_idx]

    return hv[0].hash
]]></artwork>
          </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):
    # Build leaf entries
    entries = []
    for i from 0 to length(chunk_hashes):
        entries.append((chunk_hashes[i], chunk_sizes[i]))

    # Compute root using the aggregated hash tree algorithm
    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-GEARHASH-BLAKE3</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):
    # Build (hash, size) pairs for Merkle tree
    entries = zip(chunk_hashes, chunk_sizes)
    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 32 zero bytes.
The file hash is therefore <tt>blake3_keyed_hash(ZERO_KEY, zero_hash())</tt>, where <tt>zero_hash()</tt> is 32 zero bytes.</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-GEARHASH-BLAKE3</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):
    buffer = bytes()
    for i from start_index to end_index:  # end_index is exclusive
        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 (e.g., in API paths), 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 in 0..4:                       # segments 0,1,2,3
        offset = segment * 8
        value  = little_endian_to_u64(hash[offset : offset + 8])
        out   += format("{:016x}", value)      # always 16 hex digits
    return out

function string_to_hash(hex_string):
    hash = []
    for segment in 0..4:
        start = segment * 16
        value = parse_u64_from_hex(hex_string[start : start + 16])
        hash.extend(u64_to_little_endian_bytes(value))
    return hash
]]></artwork>
        </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 from 0 to n:
        groups[i % 4].append(data[i])

    return concatenate(groups[0], groups[1], groups[2], groups[3])

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

    # Calculate group sizes
    sizes = [base_size + (1 if i < remainder else 0) for i in range(4)]

    # Extract groups
    groups = []
    offset = 0
    for size in sizes:
        groups.append(grouped_data[offset : offset + size])
        offset += size

    # Interleave back to original order
    data = []
    for i from 0 to n:
        group_idx = i % 4
        pos_in_group = i / 4
        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 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 (see <xref target="global-dedup-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="cas-api">
      <name>CAS API</name>
      <t>The CAS (Content Addressable Storage) API provides HTTP endpoints for upload and download operations.</t>
      <section anchor="authentication">
        <name>Authentication</name>
        <t>All API requests require authentication via Bearer token in the <tt>Authorization</tt> header:</t>
        <artwork><![CDATA[
Authorization: Bearer <access_token>
]]></artwork>
        <t>Tokens have associated scopes:</t>
        <ul spacing="normal">
          <li>
            <t><tt>read</tt>: Required for reconstruction and global deduplication queries</t>
          </li>
          <li>
            <t><tt>write</tt>: Required for xorb and shard uploads (includes <tt>read</tt> permissions)</t>
          </li>
        </ul>
        <t>Token acquisition is provider-specific and outside the scope of this specification.</t>
      </section>
      <section anchor="common-headers">
        <name>Common Headers</name>
        <t>Request headers:</t>
        <ul spacing="normal">
          <li>
            <t><tt>Authorization</tt>: Bearer token (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 requests (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="reconstruction-api">
        <name>Get File Reconstruction</name>
        <t>Retrieves reconstruction information for downloading a file.</t>
        <artwork><![CDATA[
GET /v1/reconstructions/{file_id}
]]></artwork>
        <t>Path Parameters:</t>
        <ul spacing="normal">
          <li>
            <t><tt>file_id</tt>: File hash as hex string (see <xref target="hash-string-format"/>)</t>
          </li>
        </ul>
        <t>Optional Headers:</t>
        <ul spacing="normal">
          <li>
            <t><tt>Range: bytes={start}-{end}</tt>: Request specific byte range (end inclusive)</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 for HTTP <tt>Range</tt> header (end inclusive).
The start offset is always aligned to a chunk header boundary, so clients can parse chunk headers sequentially from the start of the fetched data.</t>
          </li>
        </ul>
        <t>Error Responses:</t>
        <ul spacing="normal">
          <li>
            <t><tt>400 Bad Request</tt>: Invalid <tt>file_id</tt> format</t>
          </li>
          <li>
            <t><tt>401 Unauthorized</tt>: Invalid or expired 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="global-dedup-api">
        <name>Query Chunk Deduplication</name>
        <t>Checks if a chunk exists in the system for deduplication.</t>
        <artwork><![CDATA[
GET /v1/chunks/default-merkledb/{chunk_hash}
]]></artwork>
        <t>Path Parameters:</t>
        <ul spacing="normal">
          <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>Response (<tt>404 Not Found</tt>): Chunk 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 /v1/xorbs/default/{xorb_hash}
]]></artwork>
        <t>Path Parameters:</t>
        <ul spacing="normal">
          <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>: Invalid or expired 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 /v1/shards
]]></artwork>
        <t>Request Body: Serialized shard without footer (binary, 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>: Invalid or expired token</t>
          </li>
          <li>
            <t><tt>403 Forbidden</tt>: Insufficient token scope</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 via <tt>POST</tt> to <tt>/v1/xorbs/default/{xorb_hash}</tt></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 via <tt>POST</tt> to <tt>/v1/shards</tt></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 reconstruction information:</t>
        <artwork><![CDATA[
GET /v1/reconstructions/{file_id}
Authorization: Bearer <token>
]]></artwork>
        <t>For range queries, include the <tt>Range</tt> header:</t>
        <artwork><![CDATA[
Range: bytes=0-1048575
]]></artwork>
      </section>
      <section anchor="step-2-parse-response">
        <name>Step 2: Parse Response</name>
        <t>Extract from the response:</t>
        <ul spacing="normal">
          <li>
            <t><tt>offset_into_first_range</tt>: Bytes to skip in first term</t>
          </li>
          <li>
            <t><tt>terms</tt>: Ordered list of terms to process</t>
          </li>
          <li>
            <t><tt>fetch_info</tt>: URLs and ranges for downloading 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>Look up <tt>fetch_info</tt> by xorb hash</t>
          </li>
          <li>
            <t>Find <tt>fetch_info</tt> entry covering the term’s chunk range</t>
          </li>
          <li>
            <t>Make HTTP <tt>GET</tt> request to the URL with <tt>Range</tt> header</t>
          </li>
          <li>
            <t>Download the xorb byte range</t>
          </li>
        </ol>
        <t>Multiple terms may share <tt>fetch_info</tt> entries; 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.
However, reconstruction API requests include Bearer tokens in the <tt>Authorization</tt> header and <bcp14>SHOULD NOT</bcp14> be cached by intermediaries (the <tt>private</tt> directive prevents this).</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 responses reveal that a chunk exists somewhere in the system, though not where</t>
            </li>
            <li>
              <t>The keyed hash rotation and shard expiry limit the window for existence probing</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 (64 MiB)</t>
          </li>
          <li>
            <t>Maximum xorb size limits (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 1794?>

<section anchor="gearhash-table">
      <name>Gearhash Lookup Table</name>
      <t>The <tt>XET-GEARHASH-BLAKE3</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-GEARHASH-BLAKE3</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>The conversion formula:</t>
        <artwork><![CDATA[
function hash_to_string(h):
    # h is a 32-byte array
    result = ""
    for i from 0 to 4:
        start = i * 8
        end = (i + 1) * 8
        u64_bytes = slice(h, start, end)
        u64_val = little_endian_to_u64(u64_bytes)
        result += format("{:016x}", u64_val)
    return result
]]></artwork>
      </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 test vector B.3, 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:
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
yavbURxhao92GLTakgX7tagpbC9Oe9mY8dWumt/xgPxxa1eIT1Vere1OHACI
eSdSXdgVi4WdeTI6iaVebIGZiGBnYssx5pc0Pz9xhdjSzuQVj5ZYtfJkWNhs
VmjXwp4piK7nEFj3nrDQ6JjEL07+Kk8i99O5oSwR+TCtwWyzrUim7uX4nx7s
1Wh7vdO9yjC594jHN1/WrI1P74vuPJGdwocsmqDqnN+fgSnuv70+P8dTuCfr
0mReiUCzHlkTamkzWi0NdmdLyVm+oq12s9vcs3S8HFtzbJ2r1UKYJjTOWgHE
POaeNXFKeOrgu6TI7E6GBVtBj/P587DnUInWXXCwJB4Ai8VTWEvsAiDJ+UkF
70FhhQXngJJrSweoXBnYF+bNmcZSwdFGgm3NgwGxSwAzKGxuhZGqGvStg83U
dfqhgjP9inMFZvKf//mfvTcn59+fvbk8ffr25R8uL5797czzvvOS0ShK2Ffw
AODi/aF65B2G/2eQsHPkqPfi2cvWKx6+NQmmoaffmvBLPLz30JvASyd/2X4p
iAJ/HMpLKObc137rhfjaxR86DozvPP/jE/jnO//o/QTZJh5jQ5tjPLLH3VLI
ms7JoWxFf6PggaO/PGvrCzpd4T4EbQkhHl6zIKB0Fx+1Nasrgwb0NHyuz9Dk
SrqLPeqijFOX1RXRO5C8RSekyrF7g2064oUay5GbgJW4wIQySuhBwBq9gt1P
yKsO0ZI64nqUazyhXZ6nB7sWwCUt6Cy7ZCbaeht0EPyKVCsWOTwpvSXs+Tvv
3Q89+oASNNi881GJx/T89bW7NvyXwRv40bvqB/MZrvnw8Nr79lsvOPK+8d6c
PHp+9i774cj7H4Jt7j9nK7cgMXtmGAYI6cvfwUoG7Y194wX2UdjZ+2pp2QHl
cALLAVDPPeQWN5sb1rxXyHlUYd6sSneeb702Odp90oIwMrnYKHfeJ/UqV3Zi
YHU36Ucz3Z5pfv+d16bgzjxsHVFmfkEAf9fa+jFAA7b/w1Hrrc6x0yOtBwiV
vrihUwQdHb5ORNebczcDp/s/PGQnR953MOq/cP09XubZDVmUC10JgIvCZGry
LLEWwBWi8Hlr5G/3IPKXF+2+B2unN1cKYCS0K4wSeMkjjQ7nm7naEjwr/NC7
qkHDXrTVmDtvOU9zzvcl2/yRVW90UiTmbNJTYCUoOCZgnm2cnQmvAfkFiIkV
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
CkldX6G9qGDxrXwrPlV9aTr5vr0VVq3gzWk0DN6pWJEc8agWLJ0r934T3tP3
wHM385SzwPZnc2JTy6okiw5b/ut3dFvbZ4sCr/3dmFxSjGkt1OAKTSfMv6Zs
I2LUbRnDDe/XxupjrfUYeBSqRSs7AJ4wJroZqaXTaPFVbamwN8m7IObYrPtU
8oYqH29is9hYOczaGV36Yq5t7Bs2WnU3ZMS2wRbqyYwqapbOiS0D4HUWqK6K
ye8IBa+rNTZaVTot9EPFrP3CMOuenDflhQojELrl2xgabrzb4gJ9T+mR4Pzx
Qo4C+4YinrBLsN6s8pYNS4f1/Pytd/hcYQLouc62xYt/jkCBNeIJOYeBi5QU
q5tljdRBygIiDIz1xIz1ZMVa61eO1lARkXddY+UQOf6xtGGQ3iIjgSVipLpC
rzRhzXulqKtsc4Mm7sqmG6KUwG5YgApL7o8F7IlU+708RdKjWRVC3wo1ndDP
WpiSXqBPlC4rZda4UnRAzNKM1WRZ2Xl66zD7w20NkOUOKypH2pUgp46CViLc
FIhC/RivUDCpzm0uStMTJQNL0kqint/aQQ3zSecOTmPBEI2IwGg67BPTP9F8
AbIRwb5BRVNc3QIZAjkSJ2DgoritijUlWTabmyWHivccw5JzFTXF7VKVNwu8
Pc0Zl9QiIHxEcYPW5hIzp21BW3WTJsh6Kp24xYdkAHHowOtoX3K9+Ko1U5TY
Bp3lQGcwZPayA5vu7vaL1KF2MockrPCGsJJlaevgVgY32n5oHVQAVglQQt5R
/CPNaXh+XAboqre60bFJ6TeIe9G2C0wifItj703Dv1eCSx0huUk4xd8kGe4x
P1pS6nkFJA3aSq/3djGv3quuUtPv2jSY0YsHiF1VgXb57S1O+P29tTrGaZRu
16EQ41nVa2pSDYynqgu+wgUzaNHHROvBZy/JCruzra1bje5No+tbfUkPvCKG
G5l/1Iadh+i7Gdq6Gof0VjSX9rI74mcaJ9pblVPRc4MaDzNou7F1ABcUj+sg
SIX8hPt7zDmlHb0Nh/Y6mw1dIkQ5wnTpb7t+5Wh3R0RBGEVNpD2Ae7GiHGJC
Gr1iQULUxci+cy7XrmgZzJ0x2enCJjtZw/ULPc27lvTeLClSJhvFT1H2LvWg
ZBCK6ozFNC5UbqrFRpx/sAkUAa27Ix1ZoO5qLsutpO8+WhuMbXsaVhJav9UL
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
BwY31q2dIwEA

-->

</rfc>
