<?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.30 (Ruby 3.4.7) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-denis-xet-03" 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-03"/>
    <author initials="F." surname="Denis" fullname="Frank Denis">
      <organization>Independent Contributor</organization>
      <address>
        <email>fde@00f.net</email>
      </address>
    </author>
    <date year="2025"/>
    <keyword>Internet-Draft</keyword>
    <abstract>
      <?line 66?>

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

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

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

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

        chunk_size = i - start_offset + 1

        if chunk_size < MIN_CHUNK_SIZE:
            continue

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

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

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

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

    end = min(MAX_CHILDREN, n)

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

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

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

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

    hv = entries  # Working copy

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

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

        hv = hv[0:write_idx]

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

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

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

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

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

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

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

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

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

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

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

Chunk 1: unpacked_segment_bytes = 2000
         byte_range_start = 1000

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

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

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

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

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

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

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

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

Chunk hash 2 (raw hex):
  2cce73e063324e6e271e360c77cc780e65ab984b053bdb78220fa74f08fc77e2

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

Verification hash (XET string):
  eb06a8ad81d588ac05d1d9a079232d9c1e7d0b07232fa58091caa7bf333a2768
]]></artwork>
      </section>
      <section anchor="reference-files">
        <name>Reference Files</name>
        <t>Complete reference files including sample chunks, xorbs, and shards are available at:
https://huggingface.co/datasets/xet-team/xet-spec-reference-files</t>
      </section>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The XET protocol was invented by Hailey Johnson and Yucheng Low at Hugging Face.
This specification is based on the reference implementation and documentation developed by the Hugging Face team.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA9W9+Xobx7Uv+j+eoo/87RMyIaDuxkzbOYeiKEs7miLKiRNH
l+ihmuwIBLjRgCRuWftZ7rPcJ7u/NVR1dQOg5NjJOVv5QpNAdw2r1jxVt9vt
rMv13BwH9344e30cnC4Xa7NYd0/yfGWqKknnJjhfL1fJpQlerpbrZbacB8Vy
FZwVRZmVeDR4mKyT4PUqWVSFWd3rJGm6Mu9kvHudfJktkmsMn6+SYt3NzaKs
uh/Muhv2O1myNpfL1e1xUC6KZae8WR0H69WmWsdhOA3jTrVJr8uqKpeL17c3
hp7KzY3Bj8W689bcvl+u8uPgCda7WmDAhzRBJ9msr5ar404QdAOZ+BFW9jZ4
SBPj0yBYri6TRfmfyRrj0utuTN77qkw32C4/aa6Tcn4cFLn532FY9DBJJ8eS
sbU4jIf3Othkv1Otk0V+kcyXC3xxa6pOdZ2s1hf/sVmuTSWf3JTHwY+A3FFQ
LVfrlSkq/HZ7Tb+86XQWy9U1FvPO0KIfPD35w1n/mKe356KfBS8WJig2i4wW
fhQUSbUOzDuzun1/ZVbmHr9S757+dQExLOHfe8HJ5jqpquWi+cV5L3iOEaqt
x1/8BqBYKBTcF3/tBX8u59nyQ/fFbx6bZCWjCUQAkLAbRt1wKktPVpdmfRxc
rdc31fH9+5fl+mqT9rLl9X3ZTXdtEvd7dWOy6n46X6b3sUwcJ35P3pp+7yYv
MNzTvw6aAMEHdKrXJnjEsMPhVtmqvCHA3AGHv/RwwvM5TtFfdzT83Irn/zng
//MCc/PuPnCaPrjgNVwUvIbedd7pEBp7h/nd2cmrxyfnj5urJwTvXgJ+V0l1
BfTEjo+C8yfPHnaTLDNzs8LCcn43oCfKxeUde8IRvir/XuXl39+2TuNzu6pW
eO9+YzF45dHJ+evTh6fNFdMS6cPghFcbAOE98rcc46EpygVWfnq1WbzFqoOT
m5vVMsmumF0wk3ho8s3NvMySz5zUw17wyCwut47v8WbHR0nzs8e94N/LpP3y
H3vB07L19p97wQ9lsjXiX6+23uZPl5sm3oz4z8qsSlPRwds9fH9+9vzJD8HJ
69P6qfY5vH//vrepwJI+9MCO7mfLBVinWWTmfrLOotH9tcmuFoDTvFsZZoDV
/RuwY4CZQXf/A6/72dmrPzw9a57VSfCwxCkn8+C8vFwk683KBA+SCueyXAQJ
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
LzQF//eds9fJ5XFw7xuagtnR7+9Jtmc3mOlbs3b1aaK9ZxfL5tUwcuj2eheH
X+/BlJbvrTO1SQlyXza3/ubeemRJMge2SQ4JP8XcUZkYcbxpGNoqggaeawGB
3Eztlq+35PAa8eYhteI9bx5RMq8gWKGRUTfS2ZnMNLONp6wcVuOdViQclGmR
hwMbMbk139yS6l3VuUnCgOVWQNvHy3Fty5gpfcXd5qcHX3sJ5kbvFJu5D2Yg
l5Uqx9WafQ987bDXYpSa5JAiwQCiIzniK444xqYLt6GElfG8ABsYiHPxWgAM
CTdS1LPQvIu7vYiOAPfh66p8l9Dl4wu6ZGS5MoKAe6ncemLaPNVDkr0M8HZb
A360L5/PzfiZZVvi6o/CsPOnZHV7HJxsIE5WGmSX7TzcoxPopfGrZsspsjG9
ZWOpBXk+br1sqYbyvoMPqdLveBCNv6ZewN4uZjXvIUVK+VZvuyupk09Hzpqo
RWu9GZtCatEXHKLN5CQ3j10VR5Q0m5m2c8/oBTJ8zfWVkWhkA/Vp2w+fy7UM
K42hko/Rb1hVi0chwtqAWl+tlpvLKxrC+m72exexiPdmPu9Wm9J2L6SpfXcc
+YW7YiyLl1z0c+d6Ycu0VPv2id2GI2tDluCCqT/bdsFJSPSDvPyqGbLSiaz1
YSFNyYvE8eogv4DL+Zzw2VnDbSzL1B3nhggEVhDrccymnD+ZEFUCwKQ3Ofz0
tBfxOjQEls+3mv3UcusEcd3RfFeZVZdtE9sr08r6qa0a5w9yvEycnL3O4+V7
Ui6OOCeuEuYBxLcGquCKU+Nt5fuyzJjFvl8ys098cm54xFeuFxhtDuyzhYZA
kN/+9iy/NN2T2v+piNL77W8Z+2iGm2Tt7nisWltlaQZKqrkvuUKv6ZjIbd1Y
GxdUAEkzqXnhuDaO3mAFXDKq/DJbLt+W4kNUR6y9CI8brxHEbi2eKYnUp0IG
HHifX5Ox71z45LTZjnQ3Xty2oCnzqzcgkcbn5LSyT2EawTrN+PEirLImV5zD
I9xQxt1qUTsgiMrx5A0fEEgDWmZXd9ZcydfBpVnQLR4yjRPm1jRgGNIbDcFC
+kuPDpmzEDzboHG8DpN3naE14URzVn/ugV7tIUF5J+iy+XKTO8uEpoE2c2rP
RjUPZ2bO5/WE3dQkPLJM46MQVzWJR9hf4GopHtLEOd89iN8eaW6fODflqnHn
l3TnSSovjU6Wva3DBgoQTpKbqEoyDqc53uf5Obk62prctyqoU75n0hGgFxnl
7dtwoXcxq4eM0lPolQSUd8ijnWPROdvxZg1ic2NYOVY7tAVj2cqpP1RKs+4x
QkCvvkOYpezSl2MCM2ZeXWVec8+Zq2ryJZPu9TKn+hbBfQ610m2MCZR0ZnSU
lsIB6q3hujqcxqjrtoci7LZjfraPuc2ycS4fJreGp8aKJ08jnMXhiPIU+HON
Hs4OSRj4KTKshNBlOqmmLziwcdEH34PnOaaOHLdj+cRCX24G4GVYMmYmK5dv
1zVj2NP58toIs9CiIkWaTLxhfGOp3NfjpKEveK1jbXmdlgvfpFHjww8WyS19
/DY1M1mRwtTwbJMQkbnaKCW5JgKF+rtGVnndfN9moVjXxfKDRA+e1Crw7ZZj
83S5Iqe8JGF9sGHfJesBTd3Z0wBpwSBKIt4eN/JqKOaOHzVDgMr2mD/ylRKe
PbJZJA152Zp5vWyrnpjWifqd5ojqTHvW4oUjPbq/23D4ytVtbAf2K/1mO7Lv
x8tZf+VAGQHQBYKc4mS/dyrrdsjcxYT9yg3tVNqOOdUD+vmK9fOZH/aqk0m7
Uii959kd+XV7PYf6ro7U8CMfNenB94/V3E4Q+aR5dHRmTXur85pOU1Xy1kEr
z6usPkh0qtK0zrXcfdkVw/k1pZSQn0AxhlVTLuR4/fS8WxcdYZ6F5FvUSTfz
pfQGllfZGLAxIv6IssiA0Fc2T7T2+akPzhWD2HB8lWHRnKdTMI9JclnLe8ph
OtxfdveSbNfsznqjck+d7I2U1pCeSZee2SJL8NS3Io6tZ8WvLtoqLiKMbdcw
aV2QV8CkhUvqAvei4KSH7nKWa5EGe5XVQ6NxtrU1CdT3IZgkcvC0FquWND9+
tV9GbtuaxJWt1NgW1UDleyyf79VBduHuytP1wnJP41WpTlnMrpRHL/EoWK6U
GeekKVtjzZrndSVAvvGemRU7TDR3lgXQVVI5l7goWYrpVv60olVW6hvufbWE
qvuUi20FhIGCsNM5aZpZmvzTuEavbaCs3Jh80W5p85aksFsfYpbkClf4+94+
p/tWb2iZxYGKtSICQM0DXJKvgk9ctnpjsS/Mep3vF95BObmiV6izo3c2CKPA
f0zu/xuEfcpHTMscWt+s5xnmTelBJ/CddASwSqFY1Q2hbl1EzaR31o/FASyZ
SVvYyEhw5DsxalspgwpDafriCdhnuz6sMZ9sHFbTpDTEmUgewz24y9b0jLHD
Wn9TBKnaNvu2ZfpDO++fGYmSzY59q3vaKw5lT9V7G8wlW86/RdklYhK2Wlum
2KWhX+q15FZObRuEd8CNTbJmDhSHZVs2sMZbXPpObaxV1gj07CcOppEFl0va
SguYvqcAAKvtPuu373Uetvq/Z1fLZcVeDjHobRUBa5zbEHd0XVqt1Ec6Kcp2
dy6cUsZqt2Yv7cK6187oZwbA1zdQLRhxGEb67fk5t0xIwV9K7/PJleqGsIpB
qwxekmsVnHVonoWf2ix8WjYezRGT9kJuj+qCsrUmbu418pTU/XI1lYk8Ub40
cmcbpay2mNodx3L7tUhZNrJvXeJbty7hVHfpdimxzv7zNIeD/X3kbHFz7V/8
jEbgqDTx1De+jZzHVNGxaCN9enuTVHvUOw2bKFF4YNK2Eq2hbPdKK2gb6iOj
tCpZrOVZ8dppENVnbHtrRqt42J9hYCtzVNmy2SAgD7mvgzx/cRjeH4SD2mJi
hstWBcFK8kQaJOtnvEoVYleL1neceG3d27P8h2rUv65VOxrYKm82UYwvtZxb
lZhcJVfl5RX7+G3SqVOx2rdXWJ5lixesmbwTV6WWwfIouVTILMjYhwJ2rgpY
23R+yl53ViMs7WfLDTW8/HCVkJKn5UU2kY5uFmuGIVt57mSFMwjYrW97X+Q3
y1LssmdaO65FjZR6JhDzvnM9dy0wD2bPTn64+OHFqwcX50/+ejY7CqQolcyF
4MnJ85P2vj4ey805Jv/2XpHMK3PPVnHly2zD5ovjQKpKsJOPx5J8JCIJ6oBE
yfk0zStPrnIonHb28StP3HaTm9JOIxdslx/0AhIi+tWuATg444XfHTSts0et
bK5EqwW9qwYD9tiU+K+30IdMh9rjQvLcFZFSFnhT6bk2lFZeVtdUwqd1CGwd
2Nmrpvxr2bRQo32fRe3Pa7rOudQjeGCgtaluZX0qux2VGsdsfHds3/9G+NAF
j/N727iOxhToUAQFy9DGt5JKIdZqvVnJ2d6+RceWCVxfLxd1FoX1HaoXlVG+
tfDj5u4OWFFru5EsgKhRFUZQpblL939hgJl3V8v9JXQ+LItvuZ35vapsTUrX
+oePJflPfIDF7pq/5Y04SQ9pLxreb2zmrqX8vaKDIbtg7wLFfjfrXdes0pQU
93jHbH9/dWMrz0hKWrVV6Hcgh/ugs/vvovutWxDvc+UxJ4TolUAvKUJVRw1k
g+6h2XHtJKKkmytwTxfJYJ8zfdOVj1y1OAD3QmHovJoNAOqdqpzw/u1Hbir8
qfsRZP9pdux8z63tS+Wui6bXHmXvlMgDHQYv/jDTlAQ6jA5dqnRvTwHaveMg
pCuU7rEVjr9+5LbHH7X58T3a3b1GHs0FQPD7e0f2AddBWQrN8Gw86k/GffeA
neaj66d8j/drZ9bPsHd8MtAPPnXszze8Ok5tuiAEcCNtLcmuPfCn2p599/xb
K8Ds3uo2qzlB4Wq9vqmO79/v9Xr3mt9e/OyJon4UjqN6tsbO33Tot082YURP
V66iFwzaV1B4vF08+9nC2RkfPl590Sqf3dkhgMjDHQdeepbciNJRB0upPw49
4pNsp/PIfdTYiV33ad3rQpfIQWsOymlkhB4HsGfHQdMVf0f9rrzRAI6NmjWv
KOYrToL6euMjTTyi7EwxokD+LJKbkTa9vtwWunjrJ5XEv2C2OpSOOYsN25q2
CMYqG933lKfeunE440vHxcxw16/Qd19ryGuhKiWsj/pZ6qnA5UZYtbd9dwE3
b0MCXZW5TkjmSIxA3AMr8RU5WICtSj2jnznUJcdPGDzgC2KZYQG8TyTFw+v3
IOcvT7ecR0CdUtrBcQK/vMkCUR4fBNSu7BEZopYNO32MjQB+LBrpTujhc24E
xleIeqvxWaXrBSbH1bLGubVMRRk+iW9tuFD2fp16h+gRhfz+xwVESwUuaT7d
/1inR98lftwbs1YjnsB9Y12pM+iOyWa+7l6b1VsYWemMKbqex1HWzxZhu6SK
psRrnxRVMnSYxtXFNIC4Mcl1aPJmV7RqV080dmn6IW5hUbntjvZLWqN9puF7
r7HbJuodOtYkqMdVMeJc2oUOohNq+xDy43U636vRlGzdGVJHaRR/Xr44rxGI
wdLEHyfzPnV8Jew42KdsfSGWnauzYS9+CVq56WfHXmOQn4dUotyky/z2uO7F
ovBoIlSjA88ehGypOe+TCnIJYKawxDHVxBv/wsyZ/713bciM7b+ZzUyVpg1q
wYu/If9axJEiAWx/Qyzxy1kjV1lfw5pg34/H8byOK/8Qm/Sd78Tzqo3riy3W
BQfTfKxkGm6gJdMm1yfRVd9mpV5lWxZsG0tuYahUGfwsVNyLALs68exlLV+A
CpLGQ9qXp0jhExXYck7hzLK0xnGzphG576hNmQUNNcr4mdKwcY8uv+j8+hLx
kPP9554+DK5kxeTqd5KmRqX6eZcTGbVF6eyHs9fdB09P/nDW7353dvLq8cn5
4+7Tvw5mzr2szeoC26zOa2rn4i5Jo2s7aZTU2UnbeLJqmXAXxrbb0l7Vw8mp
4sS02hLfxqtHKBXTGreQ5E7Ql+Lp65MHT+lmXjEKwg9pOJnk/WRqJoOwGA7l
lt3RMM7Gxbg/NXkc5iO5sTeNJ9PRdIL/jeOE7+wdpWEymebDdDQx2Xg8PtIx
+6NJMRz3zSQdJ/0o5Rt/ozwb9Ud5Zqb4OR3w+3E4TgbZwAyHwwGNwjf5DsaD
tD8YxZO4P02y1I2ZhqNk0jdRlvTTacTX305DM57koywuwjhNCp4HD0zjvBhH
wzCfJhO+HXhipsNw2E+icDLCXnM75jCJTTEoonTST8JxHMudw2GRZNPBtJiE
4yIx9Bmm6Yd9k07CHNPJTcXTaRqOTZ5Fw3GY5GFhxxwBIHGRYktF3g/HvKcQ
/4bhJI6iqUkGI77GNxsA8n3a06TIspg/wxThaDxJilF/PEgKt84iwmrGSToZ
Jfl40OcxiziKp0VapGaUZmP5bDCJosF0OB5m00ky4Hu2ee4wCkfT4WA8TrOh
HTMq0qQ/noRRMs1MkvG9yv20CEdFPhr1k8E0HeWyz9FkbKbjSWxgv8q5jacA
5WjcTwCsfGL6dkwzwEDF1Iyw02IQ87XE8TAG+CKsfziewrLjz9J8mPeLfDyJ
cELTVNaZm0Ge5XkeRZkzlDFmkkz7+GiY4MNpzJcc5+l4MDHpKMKGgLX8WQKM
w3nnxSgO00IuQwa8RmaYJ1EaTrM4jeyYgHeR9cMk68dxEsV8xv3h0MRJYbKo
GA9iuaU6zqfTbFIMsjCOgJe8zhTGzSAdJFNoQxlGcWc0TofRZBxH+Tgc53LX
dT+ejNLRcDJOi36cCTzoOEAvE6ytiMchwz2JomE+wvZTQCMcT+2Yg8mgAOyz
6TiNTTTlMbMsS8ZpCmhGfdMPGZ5pEQ8ng2QUp2lYRCOeB8scm0nUH8XDPM2y
iR2T5h+HWH0+GU+HQ6GPxIymII6oT2cnsEvz8ZjQLS5yHHzCtFGkoPgwKgh8
WZg5nM/GTLUTM6IDiccCJxxCFI2i0KTDfMj4jVNIowKEjrWNQ7m/Ow3TGGQx
mo7HOXjBuF5nlqVZfzIyyTjJ5ZZvbGMwzUFuxXTcL2TvwMK+KcZ5GAGgY7kK
OwPp5nGOl9M8zQtjxxwXMUh7Ohpl42kEkmZcCvvjBA9mo2wYDnKep+gX0Tgb
jSIg3yicMh0kGeCL7eMRQGvi1jkGDKdT0GsxSIZgCcKXJv2xMSOwzCwxOePX
yJhJkk+B9cNROJ4MLS7kUxNFYE4mz90ZTU046qdpnMdRhg3wmGCV6XhcRHES
Rnmc8nmYbDgMYyDuaDSIUrngezwp0ukgmQwG0ywaZKP6jIY4ioj2CT5fuPn7
IJc+cA8L5TvXJ/E46/fjUZxN0iiJee/RYDQeFmEKoksGEebRMUEmKfjpaDCd
5CYzTB/gVdGoKKaTuBiG/aEROoxjiIGiGPQHRTphXJjmKV4BY52MChzqpKb3
4aSYZAnOsADpJbLOSR5NJyOQfzYa5Pw+GPlkHGK4JC2mifA/g91kOIM8MuMU
W3LrjCcAZQF0HoANT+W69P4QyJgWoO3hZCo3zUPqhAkQY5olcWaEVyVjMwYK
gdeZIdh6TUdZFGZgTXHaz8C6RJ6N43GBcwYtFiYXfgEQFlE2AsqCvQD75ZJ2
8LkoycIx0GYY95u0WRRJ3u+beGDkfVgdE+LcoJBJxPuECI7j8TBJB2Aw4UD4
An6NokmUY7rJdOh4SJpOSV6Hg3hA0pOfBb2EWd4fj0bDCDJq4uQE/gQ4IT1G
jEtZOJyAy06GEwhE4LRbJ7QFABIriocmFPyeRtNxkUKCYJYxBDzjoomIn+RR
nI4GaWbk4vowG+IYxsQwcVJuncZE4+k4Gg9MHA9kn5BFU2bSMQQ42KisE3rB
cJxNwQXAVgVGYZSN87GJ+4M0NZGTcUmKcxxjD5OkP8lSkTN5VCQhMC8DiFPh
AWGajoB26diMQoCLz33Q7/dzKCXTIokhEN2Y4H15PwWvAiPMoqQvfHEQTcJ4
ABELUSX8bzRMhgQ6EpERJufnRuMEmgo472SQDge1zjAlVpnnIyxgCNK35xGH
MTA+mUQD0bcmWT5KDZSfPAXFDJkHQLDjvNORmSZgMEPHl4yZDob9dAhuie2K
fpFD1RiaZBolY+Co0CZpFSkRbTJIkvFobOfORukwAx5EQzP06L0fhdF4YkJI
BJGb0BBzfAaqm6Qgm6HoEYPI5NhjHEO/KXjtkFbEBeKwADFmoeNLUBDBjQwU
mXE4ymM+9wnwPOsPTB/yLU0Eb6A3TnEaOEUoE7nqZSHIdAooGcjd0cDRJsii
n6fEJkGc04hlbE7yZRQl+DBKRkLvJoa4H5sBeDOgMBL5js2Bd4R9KFcQR46H
5CaBZM2gp8ZTyCDFbwMQZWAuk6w/6vNnpOQlOelm0MH6IrOTEdSiAVQBMFSQ
hzv3OIOeDflQQEfIoM2IzgE2O4bgBOZDJDhcKKCHF5DPGRCAYQzkzEGXmLyY
DiaO3icJaSE4nRSCGlqB6IqTmBRtKGIASMF4A3wNTRZnxASTaCr0Npr2gUkg
7+HU9KMGX8rAO7JsnGH9qrtnoN/+sBgNxtOsL3rhKMZB9sfDaQ7uNLQ6floY
KPPQifrTscMlOo8MxNIHt81hQzAPSYGYfZweGDEkel/giefAl8ABimEke0/j
McmmKWEz80S3znyIwSawOdLRSGTXODL9KTT3EZY07g8yObchQFSEUHZpnL7w
WXxbxBASILBi4tYJhhYTLYAUcR4CuyH2C50Zchwnqvwvy7MJoJdCEcLZTVVG
QakCFxhmOBMTOl4HOQ6VixTQeDzOhqJnk8aRQoGHShpnwoOGUPNSDJZAWoBH
1LRJq4S2C63e2UdFH+ebFNBXclIoBBfBS8COoKZDJkOs85qgoRIljqZgS9MB
z43fJknGn2P9sYNnBGkE3SCOhoMUpJ85/XUyBEoNyaLKBb9gRkHeRjhmIKmM
Oc2h5kGHisBCR2Hs6B3qIyme4JlQwoQ2DQ2I846LGPic8vupgYQLYxIpBmYY
wwMgA3YMo2wARgjtzNH7AHruIO8PBzAwJn21uSZg79D0hjSoyIk0GgASYR8K
SjIaFcL7oWMBjiAkEDvZkJY28WCOpQ4TsGowLtE1h2l/SDboEDpjyjibmcEA
QAYfmph8OuL9pBCXsYGQg/6JmRwuFWQFjpJxFMNWgcbGsIMgggYMewj7Mona
bNhwCL0uhLIF9sbP4QwggwfQlmjoQUNngJyEupaxns84m0KtLPogHTMF9TF+
T8JBH/CkgxsYsZ9BeobsxQQ8HpatG7OACgltZTCEHZomwkOGYL7gaxg3gaEw
SS0uAHFA8pAfY7G1oSPGUCEmMImxjL7jyZMUdDiBXJgMADkjOgfOOALnBvxH
GJXHzKGmTkd4CvpsPIh5zIgEDBSz0XgKO6if1LI4JkOigKCLyO7mZ/GLwS7H
YP7ZcKQ4m0xh6EFBGUK+Gj2j8Wg4nYYpzEOIY4dL4MNAJ0OmZga9QeTMmGYl
Vt2PYOMy3kxj4sSTAXQOM82FjqCvFjBDMfM4B1zcuUOpGEHjCum//TQX/TMm
62sIC5g8C2LLjAZDUp8gokn4DxnuA9CLGUIe5pMJMNnT6/JkCjM4h3k0nWSF
PY8kSePCwHIcFgK7KZhUSpyCNj9knIVCBJELTgtun8AecT4WoEGUFTkgMAGb
mKqNkUUGdgwECtbA8xSgExMWsMyKFELAzQ3+28c5xVPM6Ph80i+mpDMMcIbR
hOFJOu4UHBkCPhkWIk/CIVj+MBkTMY4hqJh/xfkEB9wHo81IArgzmsIWAnWO
Bn0QTyI8JIeEG4EJJ9AAY7FlYGAUUTGIYOVAKZ2oLREPMthP40GSjePavxSO
xrCJp9DKYILD1GHY5WNImWnaJ+nVF54KAdofZyl4Cs4/EblFCrPpA6GwTVgP
bkzojngGrCkF2Q5l/lGexLDLhglkTAYE5XlgP8MAZHcZjB+eZ2SyDLCHWgiy
S03N52GcQG2dRtBPMQjDDpYnNNdsWJC2BoXMngfJDBhhI2DkQGyuZBhBNwEb
hKJc27CTQT+OgOLpFDSjNgZoFwoH8APoBD2E8XsU9kOaYGJAs4l8BoWsGICx
mul0MIKl4vOlQTHq9yc49lBkDywziDRMUGQZeBDTgQER0ApHUMomkeAnOFKR
grAGUJfB25wfLJoUfUASlnA2zftiY7BTEYidk27XF9kDNgizcAB9oxjDlhfd
BueDkx1BzEHcjdPOG++eavHDll6W4Gy1qdZd6wOeBRmXyH38aJ2+fAfJV8Fr
ctn/yWTr5YrKwNb4s/tO/vzU7mtPXwb6JcflbD/l/U7l2nfMLl/Nq6rvufOm
F+/ukwW1MD44OT998uTwOHhsMHnw5+Vqnv8P+92V+YBvBpMRmCP+V8ThcAyY
xvh9EEedjlxISAU8ePJIm0+G3X7EN62DHrIiDSfANwgMWDIw73KMNQVsUyDl
AMQCOoI4MYM4H4KHxhAIyciMR+Somdjx+Ta3na0saRYSRjIHJBFYD6HmNJxC
lGKuHFZnEZO3cJJD4mO+FJYP9G8zxjyw9bNUjpb6+fB1SzLPKeUByLXHDbi9
1kxBDgLomtyFF3rxlpQH0D2JFDO30b1iuVl95i4u9chL31O+yUAy/fk2SQA4
yU1WXlOwtLwsyefPS+dlC+R/DHu9fvSGoBKGQRgFYRyE/SAcBOEwCEdBOA7C
SRBOgzAJwjQIsyDMg9AEYYE3ojCIIrohNOoH0SCIhjRrNA6iSRBNgygJojSI
siDKg8gEUUF3199IpLg+H54Zthl0FwAbVkPE1gjsfki0NEzCKfSBcQQtN4Ia
BuZC0roAO4EoAelD7EYTOQ/qls34zslJ6+WFTDCjPr4usXh3hNTRSlYfoiMO
IQuucqXMsufL3Owhj9MruiQjoi1dtdAQNAErGVy6PxmTEg1rOIamTa5niFiK
hoyLEYzECJQzwGOjKaW5pAW0iDxMYKGPphhVLv0FhDo6V7xnrpGBeRsDZ0Po
1RCvFMmAeQUtoQ/FFmYB9OB+GoJPw4xMR0P6qMig/xUJpGccu7limusB9yoP
UsOdVygTIFcmcCQx/znddAfY/I06YL2fU1YtE9ov3XLAm/3bAkP90h0FvJe/
LVw8sgEwTJCa0SAbQ5ZnWQ4rdtCHPQfjEwpdOMimwyl54iBJwmFuwG2gZQ+n
wNAIaiMs7ywaOKbwJ7+ntyTJbKMLc8vjgFqCNG5JcxLibnwLknT5Tu6Wse3r
uTsZ8VUh7AOKl3tsUFD9sGcx1eWmRI4bCwdO8gEUImgKQwodAYo4KBxYhIML
s5h8c1A2RlDhRhF+g02Pc43ycDSE0pbSZS/e2HFz7Bg6x7hP3mdwVTMi9dxA
+8Ip4iQnoRkNE5zeAKcINRaSPI5DnN6gAJ/GMyamcnJvv6VInNHANs/+Vffx
ayz3T+27fLawznDcMcknUT4kKxnoRSpZCFOkH8Psisw4Bxsc468C6jwUsyxJ
KOAD3TYejyYO6165KyMe8Z1RHdd1uL5MwqYX2PYpVUKPuGu59Io6V/OqDWne
JeVcMvHWxx2bi3m14eLjIslML1vep6Q/apN7/4NZd9cmueZfKGu266bvymVW
HSqUfbtYvp+bnC/L21sS0Myw53SAknPtJA3oMdZlboN/X14tKs0h/8smuzLY
2NPle6r0fCyLDB7RKrVrvSbyumRvKete2rwmC6pmvSoPbjMG9fYBquJZ3shS
6F1/soBA0Ov8/x3yFuB8JQEA

-->

</rfc>
