<?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-00" 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-00"/>
    <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 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>
      <dl>
        <dt>Algorithm Suite:</dt>
        <dd>
          <t>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.</t>
        </dd>
        <dt>Chunk:</dt>
        <dd>
          <t>A variable-sized unit of data derived from a file using content-defined chunking. Chunks are the fundamental unit of deduplication in XET.</t>
        </dd>
        <dt>Chunk Hash:</dt>
        <dd>
          <t>A 32-byte cryptographic hash that uniquely identifies a chunk based on its content.</t>
        </dd>
        <dt>Xorb:</dt>
        <dd>
          <t>A container object that aggregates multiple compressed chunks for efficient storage and transfer. The name derives from “XET orb.”</t>
        </dd>
        <dt>Xorb Hash:</dt>
        <dd>
          <t>A 32-byte cryptographic hash computed from the chunk hashes within a xorb using a Merkle tree construction.</t>
        </dd>
        <dt>File Hash:</dt>
        <dd>
          <t>A 32-byte cryptographic hash that uniquely identifies a file based on its chunk composition.</t>
        </dd>
        <dt>Shard:</dt>
        <dd>
          <t>A binary metadata structure that describes file reconstructions and xorb contents, used for registering uploads and enabling deduplication.</t>
        </dd>
        <dt>Term:</dt>
        <dd>
          <t>A reference to a contiguous range of chunks within a specific xorb, used to describe how to reconstruct a file.</t>
        </dd>
        <dt>File Reconstruction:</dt>
        <dd>
          <t>An ordered list of terms that describes how to reassemble a file from chunks stored in xorbs.</t>
        </dd>
        <dt>Content-Defined Chunking (CDC):</dt>
        <dd>
          <t>An algorithm that determines chunk boundaries based on file content rather than fixed offsets, enabling stable boundaries across file modifications.</t>
        </dd>
        <dt>Content-Addressable Storage (CAS):</dt>
        <dd>
          <t>A storage system where objects are addressed by cryptographic hashes of their content rather than by location or name.</t>
        </dd>
        <dt>Global Deduplication:</dt>
        <dd>
          <t>The process of identifying chunks that already exist in the storage system to avoid redundant uploads.</t>
        </dd>
      </dl>
      <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-byte (256-bit) values. 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>:</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 algorithm is defined independently of 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>:</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>The minimum number of children (2) has 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>
            <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 [MIN_CHILDREN-1, end) using 0-based indexing
    for i from (MIN_CHILDREN - 1) 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:
- The hash as a fixed-length 64-character lowercase hexadecimal string
- A space, colon, space (<tt> : </tt>)
- The size as a decimal integer
- A newline character (<tt>\n</tt>)</t>
          </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>:</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>
        </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, <strong>including headers</strong>. 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 distance 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 distance 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 14-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 that include 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 Authorization 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 trades storage for bandwidth. 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, max-age=31536000, immutable
ETag: "<xorb_hash>"
]]></artwork>
          <t>The <tt>immutable</tt> directive indicates the content will never change, allowing caches to skip revalidation entirely.</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>CDN cache keys <bcp14>SHOULD</bcp14> include:</t>
          <ul spacing="normal">
            <li>
              <t>The xorb hash (from the URL path)</t>
            </li>
            <li>
              <t>The byte range (if Range header is present)</t>
            </li>
          </ul>
          <t>CDN cache keys <bcp14>SHOULD NOT</bcp14> include:</t>
          <ul spacing="normal">
            <li>
              <t>Authorization headers (these vary per user but content is identical)</t>
            </li>
            <li>
              <t>Query string parameters for pre-signed URLs (these vary but content is identical)</t>
            </li>
          </ul>
        </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="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 1701?>

<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>
        <t>Key crates:</t>
        <ul spacing="normal">
          <li>
            <t><tt>cas_types</tt>: Common type definitions</t>
          </li>
          <li>
            <t><tt>cas_client</tt>: CAS API client implementation</t>
          </li>
          <li>
            <t><tt>mdb_shard</tt>: Shard format serialization</t>
          </li>
          <li>
            <t><tt>deduplication</tt>: Chunking and deduplication logic</t>
          </li>
          <li>
            <t><tt>merklehash</tt>: Hash computation functions</t>
          </li>
        </ul>
      </section>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The XET protocol was invented by Hailey Johnson and Yucheng Low at Hugging Face. This specification is based on the reference implementation and documentation developed by the Hugging Face team.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA9W9+3bbSNIn+L+eAmOfmZa6RBkASZBUV/WsbMtlf+1bS66+
uWtFXBIS2hSpjyBt63P5O/Mgu+fss+yjzJPsLy6ZSICk7Oqq3p11n1ZJJJCX
uEdkRGSv19tbVauZOQ7u/eX0zXHwaDFfmfmqd1IUS1PXaTYzwflqsUwvTfB6
uVgt8sUsKBfL4LQsq7zCo8HjdJUGb5bpvC7N8t5emmVL817Gu7dXLPJ5eo3h
i2VarnqFmVd176NZ9cJwL09X5nKxvD0Oqnm52KtulsfBarmuV3EYTsJ4r15n
11VdV4v5m9sbQ08V5sbgx3y1987cflgsi+PgGda7nGPAxzTBXrpeXS2Wx3tB
0Atk4idY2bvgMU2MT4NgsbxM59V/pCuMS6+7MXnvyypbY7v8pLlOq9lxUBbm
fwvD8giT7BVYMrYWh/Hw3h422d+rV+m8uEhnizm+uDX1Xn2dLlcX/75erEwt
n9xUx8FbQO4wqBfL1dKUNX67vaZfftzbmy+W11jMe0OLfvj85A+n/WOe3uJF
PwtezU1Qruc5LfwwKNN6FZj3Znn74coszT1+pdk9/esBYljCvx0FJ+vrtK4X
8/YX50fBS4xQbzz+6jcAxVyh4L7421Hw52qWLz72Xv3mqUmXMppABAAJe2HU
Cyey9HR5aVbHwdVqdVMfP3hwWa2u1tlRvrh+ILvprUzqfq9vTF4/yGaL7AGW
CXTi9/Sd6R/dFCWGe/63QRsg+ICwem2CJww7ILfOl9UNAeYOOPz1CBiezYBF
f93R8Esrnv3HgP/PCyzM+wegafrggtdwUfIajq6LvT0iYw+Z35+enD09OX/a
Xj0ReO8S8LtK6yuQJ3Z8GJw/e/G4l+a5mZklFlbwuwE9Uc0v79gTUHhW/aMu
qn+862DjS7uql3jvQWsxeOXJyfmbR48ftVdMS6QPgxNebQCC99jfSozHpqzm
WPmjq/X8HVYdnNzcLBdpfsXigoXEY1Osb2ZVnn4BU4+PgidmfrmBvqfrLR+l
7c+eHgX/VqXdl/94FDyvOm//+Sj4S5VujPi3q423+dPFuk03Cf9Zm2VlakK8
3cMP56cvn/0lOHnzqHmqi4cPHz4crWuIpI9HEEcP8sUcotPMc/MgXeVR8mBl
8qs54DTr1YYFYP3gBuIYYGbQPfjI635xevaH56dtXJ0EjytgOZ0F59XlPF2t
lyZ4mNbAy2IepISs9xgFY+CJ03m+vGWuCZ6oXLkDKWdgn6PghVm+mxkPEtFk
PNoBiUdnf3395hU/cRg8f/noPIgn/cPg5uYo6CeTXn803tvr9XpBmtWrZZqv
9vbeXFV1APZaXxNlkVyoSgwaQJUcYvW5klrqKadaldP+o5Pzg+DGqqgCS7kk
ciTiM45Y7dNEwitVWcGiDGaEoKCsZpjsA5gkyImKezOIRxrLI9ujvT2sJgD2
areeQkk/t6S/WmDxs2qlI1ZzfPA+XVa04l5d/Yd9FoogvbxcmkuAstaP5Gka
OsWgS3ycQmgVwcfFMqPnsXIzp4Hq9sKCNF8u6lqnpMeW5mZRV9gxgXB1tVys
L7ExQvnicpneXFW5lTBHgojrqiiA3L37pFWXi2LNNLG395yg06uxEENYT7eD
sb6F7L7GAtKcFVWREhZBZ/kV7WB+yZBwyMih92kcgtf1eraqbjA69BmTO+Gk
rq4r4MVihTRD7WaubzDLYWsBPBLomPgX8OKF6lsZnvtQFaurIzJUikoZIFUJ
ReOuIahSgd42tAdkiQSLmxto8PUcAxBIgeWrFAwGeXqNR5QcgsysPhgzD4qq
ZLZWMjgMPlzhv/jjoymYChqCKWFp8IBYPFBAHGeWK4YEbbGAXpC/gLjclOvZ
7FYJUXmBMQwJ4QPbovxuxnEss7qCKl3csALCtCsaUFYYMECOgoe3oHta7k7C
Z95JgyX0LP1J5BWkMxh5+Pz6kPgYBGhSwSQvQybIFkQvSqiYekm2F0O0rmoG
KlYwBwDxQwkccL9eFCQfiiOVHJYvGn5v43C+wAbns1teZkXykHYzE8a3/GNJ
8DCAJYjF1wv7DQnOpcHrHcTKkq9ATVjdDqLgJXrAJjlnRVS6pN1DgGJqUCVM
WzxXzXPiiPoYrAnFCavouoIJe30cfF8RKAg5NdlA1fwG6yRqJ3a4pQnJCiHw
V9cY4dpqjeDFD+dvaAXga7xGJi+pGCeJCFlGJQwJ83TGgkpMGnxu5vWaeawi
k5sJJasg5IgSe9YMCNRxwHOwF2azYJH9w+SrOti306gcY8gdMBplKYTIILvd
IqAMiwNsuFpacB4Kru1qLkFft4Q5jGKlIXbB+i/dFOA9z3yxjstxQPhZGiI5
OCEs+XoZa85i8WE+W6QF0RvkAvhr8QFieUbvM9OWZgXpwZRFaGHJg19ug7kx
BWz9NYsNWuySZFPw72vWlbzGm3RJDDtzs9S8wBPLNMHJJQNZ1ucYjV5V4d0w
mHAFRGt6U69nbEcSlbuh6nW1MrUHu3LNBoJ5v5itGWoioYj3SPsIq1/fAG6C
6YZx4DXNFrfXQtk9cg3fA41LrHa+qEFXMK94KMx8WUHWEteQEAHZiE6+htyF
7IBogSfBOkCAOxfJXRunrEVsgGHS4NJAI4IqHBuB5wivJEiAByL/RpM3uiLH
hpfVwooJtSuUUG5k6TXvFGIW+DMrFsdzk5OwXN7ygh0zdVgAE7FYU3JQ7iEp
chQ8IwlEIpKlczDFgz3rFfTE+5l28UNaiKnIlCnU4qGK3On3aqVPeTU7JTDN
P7VD85M7FP79+8EP0BePAOpaVAlAA2oE8kA7S5KSZgYDlNYkKLNwJDUOinlP
PE7If6GofK6oPA5eMC6hWPN3N4uKwLIosdy2ZJylt2TeWCa4JhlXb0phR6wk
LRltnh1Xp7SKRtVtcvpjJaYX6RwvEP6OA7ZnLJmpwQd5uzRqsKxvClZRGcit
JCtuubjebRGSXoc2EP631gczPClsEgFEm5lpDBXWWL3gT7JHiTssZvDm1OLB
499j2udPzlkHiUFqVfgHBqGzNEn1WL1H4GUaEBhu2B+k//4Bj69lZjlFQg+1
RPljqF6Oh3CkZKd4FMbd1L1bZd2qSj1R1zG9iSqDN6zpFrPF5a3oTNKHFOup
g3ukwe4dyn+Dl6/497PTP/7w7Oz0Mf1+/vTk+XP3y54+cf701Q/PHze/NW8+
evXixenLx/IyPg1aH+3de3Hy13uiEO+9ev3m2auXJ8/vkUhdtfwUQohgmMUC
PDXimLTeKzgukYkYfvjo9f/9f0WD4NOn/3L25FEcRZPPn/WPcTQa4A+ybmQ2
MVL4T9Ije2RagC5YmIOv0hvy8EhVE84BzIAIEND77VuCzI/HwbdZfhMNfq8f
0IZbH1qYtT5kmG1+svGyAHHLR1umcdBsfd6BdHu9J39t/W3h7n347X+fkbjp
ReP//vs9ohHm/cV61cYLww6Ci9Q1swoIq2aNcQux1SjYc5Jwx3sU3mhrBmWO
TQHqwnCMrN2i2E2xrsW2SeesKzzlyTaSSN3qJiVJSUiWx8ShErMNIzSc2tUY
rJ42jTKOxMjGOs4neTC0PbZUoLZhURYi5VJRnXeb+UcS5BFzg4HseXtu7Jbp
XfGW7KKCpxT74pX14152u9oKZZZtGA4iBOzgrEQyBNRrsIGNalV7hvZfYGHK
4M6LVjNUhvRcbud4kvJnP8p65l8RODhimUhRZoVhLTCkyDcMn+zonqzl63ZL
K1ivLB4a30stYGd5kf2s+Ek1HIMVGRP4ohlQeEJ4/KVwZmJog5kXRYul2IJM
dQ69U8g0GYw9GExQ5qlGCmhFa6aTlKwhkYjiaHf0iSgJ3p8isz4U1iFcAGXk
CoqXfyPqwwVD6MOu7idFIotaGg2vsZHIg1eX68W6Vh0FalWkN46hSgJejq4C
L9v1B5C69Le3AYWWhfxZa2u8DkiUJQgFI82wExYvLJI6kHFDpyDHa7IvFQ+N
GSJxENEr7E8RY+2Kw+4/evzoQBfQSA6dVPxKG3zy/XCHdZ7bxjaWKShzSW/P
JZCBbZRkRfmGmnj23lheaEqddsGSv+5tJ04c1FPRbC0+EYpqcqlzSXLIBkK+
3olsbQYvzRZW8C+Zq7G472eLDDKtFbim9agvT/4BDas8c8tCUxAkkmYGLBa3
gflICK/Ua2/vhEjy/aKicF1BAMO6lLzFSH+5EPcdy2iitzUpsJmIL+FrdoPJ
gMYsyoTquQf7zFJXWAm+P2QrsWgYE044KRfojBX0g5kXFUNjZYRaIRhmvEsC
1YeqNi4sS0YsyRcol9laIzJWyuzHw6SXVasD/fII7iDZ/y6sIIYNv6OknBI3
fuCZ7eNFVd+Ql8Bfki0KU19fpCV7XEpv9eoPZCfBLzYfsdW8uk5nCoNgv4aA
/PSJCKEnA/Xkm8+fD7CNMxYDLe1f8xSNCZ03sA/kyJCQbQM8H1cwKX4Sy/nj
Ktj276fgFNLq3FynFHep6e+PKfmUW5/e+e8nTNPb/S/ofNv9+yv/8TRP37x5
HUwZNlMlH283z+b5DGrovdG/p4y578LeZDKZQgFARwoyg9C5Z/hqczfT9XJ2
sZRZQLxTjqZc0EHCdNs0n+5BvixX946DEEY78IDfMO7nu+akacTwoDPkjyL2
6xZuPn7FNAM3iTI5vooOg/gw6LvdsC5UafoV0/CDF7yqC0wyJSfctB7aRgJw
k9xh/Cs4c+8r80F8+CZ+y2YSByV6Eo9wUROYbxqswMPEBrtNWBKJs9ntIbtx
Egdp23WtiPghs5toJNFWc/OhOekA+Ytkg2qARyuPcbyEYMaRNJaPvFoxriD/
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
OCacn6qlrPPa5Gs6zdYnNepwqFkaC1f8je2pVankJ3njjQ/blcy2+r7Jt5P3
LLOeusRSOyJ0gD2aswlBXnb6LL2FbcMddV6JBfWTCOWfgie88a/41/TJ0RY4
P6MTDr+sNSs/0aEc/cd269y/Jr8/M0G4wbrNzJF9uS//edRAjDey36KmQ43U
6MuDzsyPvM4ZdBPKnXsedmb+YZ5/3dw/iU1lt8mAFsKy3pEQnU3Nn4ZT9ZG7
Ra+bJVb8ztJwCz6v0xr4+d2ckqHtDNosSlbCi+VlQAM8pI4xfMbEq5DgR38b
Z1rvrtV3WfMUKJt8QXbSaDQ6jKOhjWs1LbWvfVUsE4J5tJJNk9ZdJxpp38Qx
AedLtlFFJPwnNph/Cl5S8XIHYX6h188h6q3E/HN7PXlk/lMwfbmYm2lndS8X
ftuW3zXN/9lx7VX1xuoiO9zzvw3ao7kP5eoWbczld4XZstnYvvkQiOI+M8Dm
gIf5KaDPgkv9kMTpTZPO74ssmfYnkU/efOf5FYiU04KbT3u1fPpZEKpg2We+
C+GVshKvXAM+ImNy6PzS3iMq39ZiEX9/Yilxo2HylIW4lpoSzY3ieh6vOpl6
Xzcga4iwhi/A8dMnfE+liKRD5FnRPvLswVEgArkrxdUw16MReZHbl2wvG/en
FKBJY+9FvWotfhN1spP4gFyC1YdFD07ipWmNp0UEtvG0zUTSWx00HlTCOiTu
7kmyUbpcwl0+0Kolog07a/AaFr6hVjl6+ZNR3ZNRyYAc/Ni2Jqpnmaw4miJw
8OjmWOpB9AvNkly6oWWNkFgt6nQdpNTfarmsx7D3TsLgJApO4uCkT6QdBg+j
4GEcPKS/HoXBoyh4FAeP6K+jo6Mf93hrpqDgBr2K5/EQvsH3GAbv4gX9M6Zx
8LL+2acxMRAPs3l2Qru/4GVfDPz6tDlFPLzqM/5QoERRhbc/HgbN/3eUb3qJ
iPLm2yr4r8Hgx1bFW9Wta2tCR/v6VohJ9Neo+TVufu3TGO0tred2U5cCuguJ
5NsG9ReyOW+3nW8kSgs6smks8+BBMNCV0rFeweHbOe3InYmms5wz2GRhkvEs
BbL0GwGuGfGbYD/igrDgW29EM6vZ1BBYgkBZ3ewPDn50ZYjSMsmSbBsvEu1p
CnGb4A9NSWchtJAuXixCfFBtiWrRu35gSz//TnxeXR5HI2eGq/RSCCHKFbCh
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
SM/eH+iV3mnxVPtSepsL7Z168tVBm9Ry1OIN5jnrnuzwT+jfz/ZRvuKfzajf
7bH8kzco3/nPuTvkinz//NXDk+cXj08f//D64vT5s++fPXx+Sk7KI5uVbWbV
ZZUpSW673daem7rbZ/iZXvf6Vkn478Ex+qkRYRtAtmqLDY1fCci77K4NM+cO
swub8xLe09oz2uyRisZlJMDcnD3SnzYOoxkSdeAORmxCn5dGwi9aIXl2+scf
np2dPtZUQs5e0A4i1ADIgsuem7ARLAcnRPD65Psq9TqM0InK0T+nLb82lh8d
7I1brzTRKp2y++7BXpT4Lzhjdefz8WBjgudyZ8POV9pHEv4rZJY4O2jjvXaw
g5b2pZkG4x1v3D3RsA0DZsEvTZUMdr5z92R6VdaGCUTXP+5F4cAbVY7V+UJj
Li6qrg2E9vXNFhL4YV59DMzNgns/wDwvYI9EUbwxGCah3JVqefu1g8SCBQHt
hoMVJWN/DuGUjqW5SXOjxHvJXnrKlqdabJuvjAe75tny8MTfuIqGnZgU1ccm
NJm8x42UEBGmWH3DCnFvz14ks9omyuyhkoicw47osLWdrUtXuxXuJl3Kpcqq
L31+4TXs7T3n0uaCsxq535UMqCmN08PGcWx9TYmC6mw5r0sTFiWOBcEXxbZb
wS+QVG80jaRowqJbqE2SUTrdWhsJ5sVPWSKxBtFQ0aatLlacMh2fD9MZhlSv
utVIJjHArUkoAmtnmDTiYguc4bPfAWbv2/8PoNx4r/8ckJ3U/9fD2JeT26DM
/tAdcPa//ypIJ78upBtx/QtgfTeYoy2usDyrpve2IMAvw460kPDaid0sF/Zi
bXeZeCFHo53B/MiiSzCUkZpmW9I8jb6xZUA22NRSf8EPdXpp6GaJ7RbvUjOt
6s7FKNUuaSwnhys5ylMLs9nlUfBILyQmA8reTS4dLadeCywR5kdNHy3qj3Uo
x6vetSMH0+ZEgppP6AUy3EeDwSylkpp+aFPfSTP8pt5ce9NNs1kw1E+fC011
FPXul4ZvzcnN1qyyZ6VlG7t0brxHLhrr8A4sJbemVee6lS4476+dCPfpftv5
kDb+WpGtcYrezLw3XbxSmoctpeLvpcE59YwnPt3W9IVTJiksKOb/c4b3uaam
Pm5D4M/WY9UG/WqP1/L0zuokyqp91wYOVpW+X1SFdx7dvS3Na2ZDF1HZK4m4
W3xg4+jdFW470s7pFU1ZcdmSTFezWznA1jtJW5C8JDlJt8vlcrmLS2y0F1ZZ
pM5hxiyW76wXqRf5Ctd10brVtRTfaiufUparDSAUVZ0TrvjO404OpN6TLI7Y
qlo2qK5v65WxxQ6n7ArLCf0jauQLa3Fv7yWV4M0c1Iluv9pn5hsLNjztqhQZ
8Mz1EBSJbutB9Czev1qg23Cegu4i8Dp9477UhU1T32AxYqF1eXscTG1P+Yia
5vClgwIOSlC+tdfY8YI5Idzuwvb6/Hd+bHUXjrZEDnrpTSVNkbDDV8Q0LGpE
9PvZy6mSppd+72QYgV/TZ/kSZq+lib2dsG8LeNoi3Er4L4nu32nqCN9DQxKb
5vcFJSHDE8L2fiROVqf0e2KqO2QoVSZW8621EZyxrZT5B57RVqCt6e43YYvt
qlRyThQqueoe6lXEJ2mufbFSNOBxa5sE2OakTWK5ZCODjennEj/p5gvuedkR
WDqPYNQqPO5nkm/RdazZGHBWp1HTwWpuwVUL7k4U/oAMeORa49SSSX6lYWWp
tXYXnjsI25xqJw20CIF8HTC/E4MgcWxrLhLyhJqF1XRW26FjAl+pr9nsbREr
11TAymR4iDVRR9ZLbhBlbzOkgqLNbCIR/nzc95qXDGjMqesPX1p7uV6sW31B
JXfftRBp696ebYNlrz+B6aRp867B5diiG1QXUT+xA5vzlOa5uWEANaNS8r2j
VNLAxHPElnKoSMzbBNn2H6nMP5FLCllfnIuEPZC2mrarydM3b15TMIy7KtR+
HjBfXqhFEMHixiz9iomTNRDJ2k+xBHksQoJLBdxdn0HaepAjYw9hE3Eq1jsz
t+xP48FC1Isk5dRPLffWV8f27W8JSDXd0YFRfm9defxum4PV9SKvGG5QQzda
UTQlMpge2ztRJe+5w+a077tUCA3DXeW747gDWJGPAsba3eZR6+xEhdcVWyB0
gQAvGijHQHpu0TSdWbazHKG9XfEXb8qdBLU78tjeJ9cLW7NbU1NCxoyt3hFw
tGA7PW6jZl9xWFDF4FRJqkcJ3Hhy6iXYPVhAVq96Uqc49b0MhQG9z8dhNEVT
SUMP3qRLLulxhLO/uJF8vgNasyqF1qLvWsk/auyDy7p3rk/sHfDm9mq5NjUo
Y50Z8q7ecye2dr2cV+4hPd/9qiG90JeI83sYxA/eRw86dS0PPnGcpio0rfN1
Cn3XXBIlG9ZHsFfX9J4sC+oTqpezqT7f0nP3M8D4SiFqiUFG1QI5tmC++8Rn
Qp97nyAKPithE7V0mu4y2iiDJmgK6jw07U8pgvbqD1PNjCVs7FEm7L0d1Uv3
jgNuA3+PdSv+essHVp/02OoebQif3vvWXZVArUd/f+/QPuDOvkS44tk46Y9H
ffeAneaTOwm7x1u1M+tn2BI+sR0kPu/Znz/y6koDlXdBuHYjbSzJrj3wp9qc
ffv8GyvA7N7q1ssZQeFqtbqpjx88ODo6utf+9uJnTxT1o3DUXHf+ubVz6svx
2WYaO+xKdy4hnl3VaMcamvXKz5rSM6mJbNX+sWhh5OPVV52y0232F/ODQwde
epHeSPih6fZJhgs94nPn3t4T/kh6Gno7sevW8zcOt8gSpWECR2zYkeG5Aewp
1XuZntrvP5w93+B8d/Sub7SAo6N3Sk15DFbGKiltSUWH29QG1FpnjmmxT8/N
g9OZrIm81XYLPlsPzTcB+AYoN/ZtPVt7l2LDOG1qR/36aoZv07fqdLnE8i2l
KGQHkAUPuQKPZQm2/2zOBbGNRNPzPXk6Cn6Yp6qQTOE9zk1SbljPsmaSxwcB
OYJPaGNWMrpeimxh8mNRookY9PA5u1hco+UN34g2Vg3iZWkTzzv8YVUNfBta
zZ1WbavFj9yG0cZ52KHdjM909ILYgg+03VZP7mgosgefmgjOXSqiecqR8s9W
E9vEuB4e6TGsanUdplXs2RmgjZ4DuyYOBi4lVQce3DYzi3GgtZtUAL6394Ma
UulGohJJGbFqFZqvX50LONn6t9B88MnJ6rtg6B4CCF1Tkp8JQdGaDxcF/PhO
19pgX8BH+VauGfEXwN/Roh9S6lwEKMCshQyHZDR+Ec3U/95LJZqWcBEhUbSf
r9ip6l4ysZridyLtbIMjeKzE0V/P2ewJw6oV55AaOilzWdn2z3J5n2IcWVXA
ReZn67U7MBMrlQ1hn2iYYltUwyTMrQqoFJhanLK32GLQLgHJwZ3VgDvQKiPb
wJpmG3TQfBeX7MIzfDaQLWluTwlTFz7pNSJICKeWO1u4ZC0Vue9AEm7fdGvl
z5TUrcI59pXUB1XMsiPD18b9C1FrMft6uVgt8sUMglgci96NfvL5zovuXYX+
jb3xwfNzuX8k0YO2A6fbmyKVV7SzvXOIJr0cQXNQVvZeHf/mq+YeWUqs1qBr
T68g7uU6HGdXuzYO/Gn7+KFpuO03LpcIuutcTgEdjWU1z0vURWKQ7IVyWza7
pfi4G3purwLvrFZ0qVDH6bW9G2SVrWj7sb0J1L9dhQmupmNyuJIzrivT1lMa
dedgVDsobgeSsJ1GFzkI3qQE8l0A/SMbqD55/ez4n41+Ejcx7DbOmMBiwhEv
zQeb+xf8uaLKTGODmU0zEzz32I/P2Bd09FaUS3XJ3HXfJDuzwU7/2O+lz+jh
zmfUpIA6e857fiTooEnD1EvKaktEs5nXdZca0nkdUqgkkBt/qenJVK9tRa5t
2JbDVvTCf2qT+5XLj+DQrZKp3w+kbBGSNAWRp5qdu2dEE25rx99AY6DQsJI2
dXEZEQQe7RJ8NAuVet67tmcNY6rsYq5sqVzauQoWikpNSfRz0HN6pwHBTe7/
JIWG9ZqDUOV65uLXEgoTYNrsLHcU49c0GttgxY8WeTJoaCW4RxNybVlT0Oxa
aBw3pwFWTh02N2XvjmYzMyqytl065dAm7pugbWvRyIFPHc2tYfqKf3Xf5wOf
RGyRB7l76YdOjcfwSG9qcwcMUv7A67KorxuYJRZmlk5aNNHAra2x7yYEMQS+
iHVq4WEvJCJKpb44fH11botOXMNzd3FR3tw6IS1wWPY09OMpWxjL1pDZRVVu
e64Fkn+xoeQ3M3jdEQDrRH3bs9MkgN1YwP4wW9/1jQT/3BUrqo2/y0MvjsxH
nRlfIwo/07BBxft/YU9RxUojJzVT8S6nmXot+OzWf1ggpg/7Z5/+04+3ptHS
SxSfr+ZuMXzEbWPfntlhnfxfZnj4oYItpoc4oO3AZGOE7g5AHn9tpHFHRN0P
pW9p0uQf5rVjFDpxK6AY9qJwMB6Ohq79hzVDXnPE4cxxju1o6wINlql+QaTp
rqiSNjNb2KP8jYjSD2fPpRGQnvN0USYdnz3V7SiFeeYxf91q1WWNp8U7akrv
z0aM7bQk62I6cWs94UWgrE7bvKWOxNOL9J3REBJoYGpD6vbUjQJVcllgC3kk
jN0GnHvox0QcjwnkqC8HcbzZXCbo5He7kiokfQKIoEAUTHwLUZ/4B8euv/Ej
6ebWwNE+785t9XI+APb1F2JY0rmp3eVMOpO1Op11G9ISTE/bLdY61wR60cKW
4j6xHfEoKuVUc7sP16GQ7e6+XpKIGrdbrGnLN2dtsnVNulk6jfa3tldzzb3Y
B7a9vLTRNdD/ZzrN4lbN0vyLtQQd4vB9fy6NRa75A5SAXGlqV9PVPOyfyNc9
voOksCL+82ftPUlwvTJzPsTVR4PLdVXIQSzlfy3b4zLrs5ewpakcd3J3VuXS
cMtiOfltmnipt0HcfcKUZ+fd2pdNveFg/6YV2K3VbQUoq/zd7PbAraqTnUML
Ee+l7VNA5NOc9hiMICkO+FOsccbu5fZj6IaLGBR0/nSLGahDBvMw1rWYC31z
o21QkRAnZUmxC12m1YxyDqgRr+tCSPJvS5c+ba6kKUTKQtomtG0XtqPyrm0a
l0FQpkLFiZ0NvTxqEQQfVm+lFM4YI5GmfnPqHVxDpwIjfmESKVuPlDazyLSR
ptXK7rTbEp30HLcgJnnBCQUynLa+rpSS2iu1h6tyvv7s+hqWkWQo7e1JU0/m
Se5As3EtWb68vVktLpfpzRUQ2eSr2B6LPKiu/Q5INFeS0PWzRcrUQ3VXZF2t
bo9dyhdVzgSXfN0J84vkjORXrNcol6Opd+Pvn+J3WJ96mqAJPk3/a+2rQUCx
se7m3Uetdxsic+1ZaQQ9LpALJjzYOeSmTbaHoqMRBV5Jo+4ko1mojy22b5rH
PAGvBiELCW6SSPGYijpJOVbWSKW7/9sm1ngn+xaeC0GwGPTSxbG6hsAg0cYU
aYSgJCmtk/qwkuwEgl5HylDH8Ypak0vL+HwtbX9d0yvsAK6DUh6f3fTOKQ9A
rHxltZ2SJN8hRgVALrHR08ytPqa0XpsyaA/ptX9kE/TxKBJqar2k7Cue9p1x
1eX8N8n6x0zFtoCRn2s1hu+GwFxz7QU3u7Wh+Palhge2prWZNziviNXt/cnz
CotvZVsJVu2N2Rz7DpZUuEI3aPEwdLdexXok4HKwdGb8205kT99D5q5nqeSA
7U7opB6XVckeHV0AYN+xzW6fzQu6/nXt0knpTGtuepfkOlEKNmcasaBu6xhp
f79yXp9YrceQUWQWLZsBCMOU5ua0ls2kpVetpyLRJICO/q5Xcu09mXyyifV8
3ehhsc74Chh3fd+hE6NVd0NObTtq4U7NZKJm6YzFMgBvE0FtYUx+yyR4Va2o
86q9eun0fSWi/dwJa9gijG9ODVVBoHwrdzPU0o63JQUOA2NHAv7peo6C2ogS
nUhIcLFe5i0flpH1/OyHYP+5oRzQM5twS9cAHcCAdeqJJIeDi1YVm+ubBXEH
GwtEMBjriRvryVKs1q8creY6ouBqQcVDHPin6oZe+oEECZZI59QVRaWZat4Z
w21m62tycZdNsiFpCWqIBVK4kRZZEE9s2u+UKZohLaYQxVa474R9toEp2wUW
o3xppYjGpWEEiUhzXlMjys7SD56w39+0AEXviKFyYEMJinVStHrCzQdRZB/T
hQou27ktRXl65mSIJGsk2vkbP6gWOendxeg8GOYRVRh1R3xS8ie5L2AbVeyA
XWFqBxXOlgL4PlTF6mpXViJpDMpItLy1zShez2ekbt1Y0oIFLE7E7AhYgX7f
71HQNtK0/7GdyiZoCTrclvc9yBzsyqTXqLQVf3qKwVjr2VyFrLnkoMlt95tD
2kN1dnz0AOEN059ozRaKlo4K2hFne3wAoQgokZQo/pHmPLw8rgN0DVnb4djl
7zsSPW97AC7rvSWbd+Xc70Kzl/pfS0BE8vldMuEOR6Olj55XYF7YJXt7P8xn
1TvTNV8Ou94L5e0SAqmdKrhU3t6Qed/fWZjjwkPpZtEJi5jlYsXtqSFiqkUh
V7dQnixFk3g99OwF+1u3TVPrVqN71+L6g72cB6+oi8aOHrdhlyEO/UxsW3rD
Fio5RjsFG0suSxPtrSpW7Nww2DGD9RBbCDjnk7cOgVQkOaSZx0xy1ymusN9c
Y7Pmy4M4E5iveW0Xqxxsb3+oBGO4e3QAuBdLzhRmorErViIkq4s9Oe865YqX
IXKYkprOm6SmxkX9Qjvzrs+8MxuKzcbayFOcpcsNJwWEaiRT5YwPletqvtYw
HzZBwp5UjbsW2ZP65nYhNbiV9t0nv0KobUd3SibrH+yCYJVc35DqlW7+BEPY
LxJxu2YfvNecLW4BR1V6G9Pjbj5KJHfihkr4oeH5CeylIDOTmTnl+yRstGKv
k4/a8JcSaEZ1eMY2cTE3dA0ToV4u8+nZvCym0rkxBYu2pmF97uldDhVajefy
hPkyTikx2Aj2NM3Q3Xr04iy+7vlmSQnXMq5VHzYe5xKknQo5FvPRb+oe7KtT
ODO2typzVI/87eVidgzbLANDsjHcA/1+14+G/SQMw8PAvbl3+ia9bOWM/v6e
lyPjnpsCCUs1rhrRImF7WzEFceH7zIdkXMohjrotNvq8NJ4TKSVN3Kz4yWZ+
eSfi5FC4a8fL6j1WRoWUPS7PswkhO+jEeu1drmQhrOGsXSx0u2ktPdlVULX0
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
AA==

-->

</rfc>
