<?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.35 (Ruby 3.4.9) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-denis-uricrypt-04" category="info" submissionType="independent" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.32.0 -->
  <front>
    <title abbrev="URICrypt">Prefix-Preserving Encryption for URIs</title>
    <seriesInfo name="Internet-Draft" value="draft-denis-uricrypt-04"/>
    <author initials="F." surname="Denis" fullname="Frank Denis">
      <organization>Fastly Inc.</organization>
      <address>
        <email>fde@00f.net</email>
      </address>
    </author>
    <date year="2026"/>
    <keyword>Internet-Draft</keyword>
    <abstract>
      <?line 19?>

<t>This document specifies URICrypt, a deterministic, prefix-preserving
encryption scheme for Uniform Resource Identifiers (URIs). URICrypt
encrypts URI paths while preserving their hierarchical structure,
enabling systems that rely on URI prefix relationships to continue
functioning with encrypted URIs. The scheme provides authenticated
encryption for each URI path component, preventing tampering,
reordering, or mixing of encrypted segments.</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-uricrypt"/>.</t>
    </note>
  </front>
  <middle>
    <?line 29?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>This document specifies URICrypt, a method for encrypting Uniform
Resource Identifiers (URIs) while preserving their hierarchical
structure. The primary motivation is to enable systems that rely on
URI prefix relationships for routing, filtering, or access control to
continue functioning with encrypted URIs.</t>
      <t>URICrypt achieves prefix preservation through a chained encryption
model where the encryption of each URI component depends
cryptographically on all preceding components. This ensures that URIs
sharing common prefixes produce ciphertexts that also share common
encrypted prefixes.</t>
      <t>The scheme uses an extendable-output function (XOF) as its cryptographic primitive
and provides authenticated encryption for each component, preventing
tampering, reordering, or mixing of encrypted segments. URICrypt is a
reversible encryption scheme: encrypted URIs can be fully decrypted to
recover the original URIs, but only with possession of the secret key.</t>
      <section anchor="use-cases-and-motivations">
        <name>Use Cases and Motivations</name>
        <t>The main motivations include:</t>
        <ul spacing="normal">
          <li>
            <t>Access Control in CDNs: Content Delivery Networks often use URI
prefixes for routing and access control. URICrypt allows encryption of
resource paths while preserving the prefix structure needed for
CDN operations.</t>
          </li>
          <li>
            <t>Privacy-Preserving Logging: Systems can log encrypted URIs
without exposing sensitive path information, while still enabling
analysis based on URI structure.</t>
          </li>
          <li>
            <t>Confidential Data Sharing: When sharing links to sensitive
resources, URICrypt prevents the path structure itself from
revealing confidential information.</t>
          </li>
          <li>
            <t>Token-Based Access Systems: Systems that issue time-limited
access tokens can use URICrypt to obfuscate the underlying
resource location while maintaining routability.</t>
          </li>
          <li>
            <t>Multi-tenant Systems: In systems where multiple tenants share
infrastructure, URICrypt can isolate tenant data while allowing
shared components to be processed efficiently.</t>
          </li>
          <li>
            <t>Privacy-Preserving Analytics: URICrypt can complement IPCrypt
<xref target="I-D.draft-denis-ipcrypt"/>. Together, they enable systems to perform
analytics on encrypted network flows and resource access patterns
without exposing sensitive information about either the network
endpoints or the specific resources being accessed.</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="terminology">
      <name>Terminology</name>
      <t>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”,
“SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and
“OPTIONAL” in this document are to be interpreted as described in BCP
14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as
shown here.</t>
      <t>Throughout this document, the following terms and conventions apply:</t>
      <ul spacing="normal">
        <li>
          <t>URI: Uniform Resource Identifier as defined in <xref target="RFC3986"/>.</t>
        </li>
        <li>
          <t>URI Component: A segment of a URI path, terminated by ‘/’, ‘?’, or
‘#’ characters. For encryption purposes, components include the
trailing terminator except for the final component.</t>
        </li>
        <li>
          <t>Scheme: The URI scheme (e.g., “https://”) which is preserved in
plaintext.</t>
        </li>
        <li>
          <t>XOF: Extendable-Output Function, a cryptographic function that can
produce output of arbitrary length.</t>
        </li>
        <li>
          <t>SIV: Synthetic Initialization Vector, a value derived from the
accumulated state of all previous components, used for
authentication and as input to keystream generation.</t>
        </li>
        <li>
          <t>SIVLEN: The length of the Synthetic Initialization Vector in bytes,
defined as 16 bytes (128 bits) for this specification.</t>
        </li>
        <li>
          <t>PADBS: Padding Block Size, the number of bytes to which ciphertext
components are aligned. Defined as 3 bytes for this specification
to ensure efficient Base64url encoding without padding characters.</t>
        </li>
        <li>
          <t>Domain Separation: The practice of using distinct inputs to
cryptographic functions to ensure outputs for different purposes
are not compatible.</t>
        </li>
        <li>
          <t>Prefix-preserving Encryption: An encryption scheme where, if two
plaintexts share a common prefix, their corresponding ciphertexts
also share a common (encrypted) prefix.</t>
        </li>
        <li>
          <t>Chained Encryption: A mode where encryption of each component
depends cryptographically on all preceding components.</t>
        </li>
      </ul>
    </section>
    <section anchor="uri-processing">
      <name>URI Processing</name>
      <t>This section describes how URIs are processed for encryption and
decryption.</t>
      <t>The overall encryption flow transforms a plaintext URI into an encrypted
URI while preserving its hierarchical structure:</t>
      <artwork><![CDATA[
+-------------------------------------------------------------+
|                         Input URI                           |
|          "https://example.com/path/to/resource"             |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                    URI Decomposition                        |
+-------------------------------------------------------------+
|  Scheme: "https://"                                         |
|  Components: ["example.com/", "path/", "to/", "resource"]   |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                 Chained Encryption Process                  |
+-------------------------------------------------------------+
|  For each component in sequence:                            |
|    1. Update state with plaintext                           |
|    2. Generate SIV from accumulated state                   |
|    3. Derive keystream using SIV                            |
|    4. Encrypt component with keystream                      |
|    5. Output: SIV || encrypted_component                    |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                    Encoding & Assembly                      |
+-------------------------------------------------------------+
|  1. Concatenate all (SIV || encrypted_component) pairs      |
|  2. Apply base64url encoding                                |
|  3. Prepend original scheme                                 |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                       Encrypted URI                         |
|          "https://HOGo9vauZ3b3xsPNPQng5apS..."              |
+-------------------------------------------------------------+
]]></artwork>
      <section anchor="uri-component-extraction">
        <name>URI Component Extraction</name>
        <t>Before encryption, a URI must be split into its scheme and path
components. The path is further divided into individual components for
chained encryption. Components are terminated by ‘/’, ‘?’, or ‘#’
characters, which allows proper handling of query strings and fragments.</t>
        <section anchor="full-uris">
          <name>Full URIs</name>
          <t>For a full URI including a scheme:</t>
          <artwork><![CDATA[
Input:  "https://example.com/a/b/c"

Components:

- Scheme: "https://"
- Component 1: "example.com/"
- Component 2: "a/"
- Component 3: "b/"
- Component 4: "c"
]]></artwork>
          <t>For a URI with query parameters:</t>
          <artwork><![CDATA[
Input:  "https://example.com/path?foo=bar&baz=qux"

Components:

- Scheme: "https://"
- Component 1: "example.com/"
- Component 2: "path?"
- Component 3: "foo=bar&baz=qux"
]]></artwork>
          <t>For a URI with a fragment:</t>
          <artwork><![CDATA[
Input:  "https://example.com/path#section"

Components:

- Scheme: "https://"
- Component 1: "example.com/"
- Component 2: "path#"
- Component 3: "section"
]]></artwork>
          <t>Note that all components except the last include their trailing terminator
character (‘/’, ‘?’, or ‘#’). This ensures proper reconstruction during decryption.</t>
        </section>
        <section anchor="path-only-uris">
          <name>Path-Only URIs</name>
          <t>For absolute paths (URIs starting with ‘/’ but without a scheme), the
leading ‘/’ is treated as the first component:</t>
          <artwork><![CDATA[
Input:  "/a/b/c"

Components:

- Scheme: "" (empty)
- Component 1: "/"
- Component 2: "a/"
- Component 3: "b/"
- Component 4: "c"
]]></artwork>
          <t>For a path with query parameters:</t>
          <artwork><![CDATA[
Input:  "/path/to/file?param=value"

Components:

- Scheme: "" (empty)
- Component 1: "/"
- Component 2: "path/"
- Component 3: "to/"
- Component 4: "file?"
- Component 5: "param=value"
]]></artwork>
          <t>The leading ‘/’ is explicitly encrypted as a component to maintain
consistency and enable proper prefix preservation for absolute paths.</t>
          <t>This character receives its own SIV and is encrypted, ensuring that the
root path is authenticated like any other path component and that
different keys and contexts produce different ciphertexts for that path,
consistent with other paths.</t>
          <t>In applications where all paths are guaranteed to be absolute and the <tt>'/'</tt> path
can be considered a special case, ciphertext expansion can be reduced by
removing the leading <tt>'/'</tt> character from the URI prior to encryption,
treating the path as relative with <tt>'/'</tt> as implicit.</t>
        </section>
      </section>
      <section anchor="component-reconstruction">
        <name>Component Reconstruction</name>
        <t>During decryption, components are joined to reconstruct the original
path:</t>
        <artwork><![CDATA[
Components: ["example.com/", "a/", "b/", "c"]
Reconstructed Path: "example.com/a/b/c"

When combined with the scheme: "https://example.com/a/b/c"
]]></artwork>
        <t>For absolute paths without a scheme:</t>
        <artwork><![CDATA[
Components: ["/", "a/", "b/", "c"]
Reconstructed Path: "/a/b/c"
]]></artwork>
      </section>
    </section>
    <section anchor="cryptographic-operations">
      <name>Cryptographic Operations</name>
      <t>The chained encryption model creates cryptographic dependencies between components, ensuring prefix preservation.</t>
      <artwork><![CDATA[
  URI: "https://example.com/path/to/resource"

  +-------------------+
  |   Component 1:    |
  |  "example.com/"   |
  +-------------------+
            |
            | Plaintext absorbed into components_xof
            v
  +-------------------+
  | SIV1 generation   |------> SIV1 (SIVLEN bytes)
  +-------------------+         |
                                |
                                v
                      Encrypt("example.com/")
                                |
                                v
                      Output1 = SIV1 || Ciphertext1
            |
            | State carries forward
            v
  +-------------------+
  |   Component 2:    |
  |     "path/"       |
  +-------------------+
            |
            | Plaintext absorbed (includes Component 1 state)
            v
  +-------------------+
  | SIV2 generation   |------> SIV2 (depends on 1)
  +-------------------+         |
                                |
                                v
                      Encrypt("path/")
                                |
                                v
                      Output2 = SIV2 || Ciphertext2
            |
            | State carries forward
            v
  +-------------------+
  |   Component 3:    |
  |      "to/"        |
  +-------------------+
            |
            | Plaintext absorbed (includes 1 + 2 state)
            v
  +-------------------+
  | SIV3 generation   |------> SIV3 (depends on 1, 2)
  +-------------------+         |
                                |
                                v
                      Encrypt("to/")
                                |
                                v
                      Output3 = SIV3 || Ciphertext3
            |
            | State carries forward
            v
  +-------------------+
  |   Component 4:    |
  |    "resource"     |
  +-------------------+
            |
            | Plaintext absorbed (includes 1 + 2 + 3 state)
            v
  +-------------------+
  | SIV4 generation   |------> SIV4 (depends on 1, 2, 3)
  +-------------------+         |
                                |
                                v
                      Encrypt("resource")
                                |
                                v
                      Output4 = SIV4 || Ciphertext4

  Final Output: Output1 || Output2 || Output3 || Output4
]]></artwork>
      <t>If URIs share a common prefix <tt>example.com/path/</tt>, their <tt>Output1</tt> and <tt>Output2</tt> will be identical.</t>
      <section anchor="xof-init">
        <name>XOF Initialization</name>
        <t>The base XOF is initialized with the secret key and context
parameters using length-prefixed encoding to prevent ambiguities.</t>
        <t>Two XOF instances are derived from the base XOF:</t>
        <ol spacing="normal" type="1"><li>
            <t>Components XOF: Updated with each component’s plaintext to
generate SIVs</t>
          </li>
          <li>
            <t>Base Keystream XOF: Used as the starting point for generating
keystream for each component</t>
          </li>
        </ol>
        <artwork><![CDATA[
  Input: len(key) || key || len(context) || context

  +-----------------------------------------------------+
  | base_xof = TurboSHAKE128(domain_sep=0x1F)           |
  | base_xof.update(len(secret_key))                    |
  | base_xof.update(secret_key)                         |
  | base_xof.update(len(context))                       |
  | base_xof.update(context)                            |
  +-----------------------------------------------------+
                            |
                            v
               +------------------------+
               |   Clone Base State     |
               +------------------------+
                            |
           +----------------+----------------+
           v                                 v
  +--------------------+          +--------------------+
  |  Components XOF    |          | Base Keystream XOF |
  +--------------------+          +--------------------+
  |   update("IV")     |          |   update("KS")     |
  +--------------------+          +--------------------+
           |                                 |
           |                                 |
           v                                 v
   For SIV Generation              For Keystream Base
   (Updated with each              (Cloned for each
    component plaintext)            component's keystream)
]]></artwork>
        <t>The initialization process is:</t>
        <artwork><![CDATA[
base_xof = TurboSHAKE128()
base_xof.update(len(secret_key))
base_xof.update(secret_key)
base_xof.update(len(context))
base_xof.update(context)

components_xof = base_xof.clone()
components_xof.update("IV")

base_keystream_xof = base_xof.clone()
base_keystream_xof.update("KS")
]]></artwork>
        <t>Note on XOF cloning: The <tt>.clone()</tt> operation creates a new XOF instance with
an identical internal state, preserving all previously absorbed data. After
cloning, the original and cloned XOFs can be updated and read from
independently. This allows the <tt>components_xof</tt> to maintain a running state
across all components while <tt>base_keystream_xof</tt> remains unchanged for creating
per-component keystreams.</t>
      </section>
      <section anchor="component-encryption">
        <name>Component Encryption</name>
        <t>For each component, the encryption process follows a precise sequence
that ensures both confidentiality and authenticity:</t>
        <ol spacing="normal" type="1"><li>
            <t>Update <tt>components_xof</tt> with the component plaintext</t>
          </li>
          <li>
            <t>Squeeze the SIV from <tt>components_xof</tt> (<tt>SIVLEN</tt> bytes). This requires cloning <tt>components_xof</tt> before reading, as reading may finalize the XOF.</t>
          </li>
          <li>
            <t>Create <tt>keystream_xof</tt> by cloning <tt>base_keystream_xof</tt> and updating it with SIV</t>
          </li>
          <li>
            <t>Calculate padding needed for base64 encoding</t>
          </li>
          <li>
            <t>Generate a keystream of length <tt>(component_length + padding)</tt></t>
          </li>
          <li>
            <t>XOR the padded component with the keystream</t>
          </li>
          <li>
            <t>Output SIV concatenated with <tt>encrypted_component</tt></t>
          </li>
        </ol>
        <t>The padding ensures clean base64url encoding without padding characters. Since
base64 encoding works with groups of 3 bytes (producing 4 characters), we pad each
<tt>(SIV || encrypted_component)</tt> pair to have a length that’s a multiple of PADBS:</t>
        <artwork><![CDATA[
total_bytes = SIVLEN (SIV) + component_len
padding_len = (PADBS - total_bytes % PADBS) % PADBS
]]></artwork>
        <t>This formula calculates:</t>
        <ul spacing="normal">
          <li>
            <t>How many bytes are needed to reach the next multiple of PADBS</t>
          </li>
          <li>
            <t>The outer modulo handles the case where <tt>total_bytes</tt> is already a multiple of PADBS</t>
          </li>
        </ul>
        <t>The <tt>components_xof</tt> maintains state across all components.
After generating the SIV for component <tt>N</tt>, the XOF can be updated with component <tt>N+1</tt>’s
plaintext. This chaining ensures that each component’s encryption depends on
all previous components, thus enabling the prefix-preserving property.</t>
      </section>
      <section anchor="component-decryption">
        <name>Component Decryption</name>
        <t>For each encrypted component, the decryption process is:</t>
        <ol spacing="normal" type="1"><li>
            <t>Read SIV from input (<tt>SIVLEN</tt> bytes)</t>
          </li>
          <li>
            <t>Create <tt>keystream_xof</tt> by cloning <tt>base_keystream_xof</tt> and updating it with SIV</t>
          </li>
          <li>
            <t>Decrypt bytes incrementally to determine component boundaries:
            </t>
            <ul spacing="normal">
              <li>
                <t>Generate keystream bytes one at a time from the XOF</t>
              </li>
              <li>
                <t>XOR each encrypted byte with its corresponding keystream byte</t>
              </li>
              <li>
                <t>Check each decrypted byte for component terminators (<tt>'/'</tt>, <tt>'?'</tt>, <tt>'#'</tt>)</t>
              </li>
              <li>
                <t>When a terminator is found, the component is complete.</t>
              </li>
              <li>
                <t>Skip any padding bytes (null bytes) after the component</t>
              </li>
            </ul>
          </li>
          <li>
            <t>Update <tt>components_xof</tt> with the complete plaintext component (including terminator)</t>
          </li>
          <li>
            <t>Generate the expected SIV from <tt>components_xof</tt></t>
          </li>
          <li>
            <t>Compare the expected SIV with the received SIV (constant-time)</t>
          </li>
          <li>
            <t>If mismatch, return <tt>error</tt></t>
          </li>
        </ol>
        <section anchor="component-boundary-detection">
          <name>Component Boundary Detection</name>
          <t>During decryption, component boundaries are discovered dynamically by examining the decrypted plaintext:</t>
          <ul spacing="normal">
            <li>
              <t>Each component (except possibly the last) ends with a terminator character (<tt>'/'</tt>, <tt>'?'</tt>, or <tt>'#'</tt>)</t>
            </li>
            <li>
              <t>When a terminator is encountered, we know the component is complete</t>
            </li>
            <li>
              <t>After finding the terminator, we skip padding bytes to align to the next PADBS-byte boundary.</t>
            </li>
            <li>
              <t>The padding length can be calculated: <tt>padding = (PADBS - ((SIVLEN + bytes_read) % PADBS)) % PADBS</tt></t>
            </li>
          </ul>
          <t>This approach eliminates the need for explicit length encoding, as the component structure itself provides the necessary boundary information.</t>
          <t>Any tampering with the encrypted data will cause the SIV comparison to fail.</t>
        </section>
      </section>
      <section anchor="padding-and-encoding">
        <name>Padding and Encoding</name>
        <t>To enable clean base64url encoding without padding characters (‘=’), each
encrypted component pair <tt>(SIV || ciphertext)</tt> is padded to be a multiple of PADBS bytes.
This is necessary because base64 encoding processes 3 bytes at a time to produce
4 characters of output.</t>
        <t>The padding calculation <tt>(PADBS - (SIVLEN + component_len) % PADBS) % PADBS</tt> ensures the following:</t>
        <ul spacing="normal">
          <li>
            <t>If <tt>(SIVLEN + component_len) % PADBS = 0</tt>: no padding needed (already aligned)</t>
          </li>
          <li>
            <t>If <tt>(SIVLEN + component_len) % PADBS = 1</tt>: add 2 bytes of padding</t>
          </li>
          <li>
            <t>If <tt>(SIVLEN + component_len) % PADBS = 2</tt>: add 1 byte of padding</t>
          </li>
        </ul>
        <t>With the default value of <tt>PADBS=3</tt>, this padding scheme provides partial length-hiding.
For example, with <tt>SIVLEN=16</tt>, components “abc”, “abcd”, and “abcde” all produce 21-byte
outputs after padding. Without the secret key, a passive adversary cannot determine
the exact original component size.</t>
        <t>The final output is encoded using URL-safe base64 <xref target="RFC4648"/>, with ‘-‘ replacing
‘+’ and ‘_’ replacing ‘/’ for URI compatibility.</t>
        <t>Note: Encrypted URIs may contain slash characters (‘/’) at arbitrary locations
in the base64-encoded ciphertext portion (i.e., after the scheme for full URIs,
or after the leading ‘/’ for path-only URIs). These slashes may or may not
correspond to the original URI structure and serve aesthetic or structural
purposes only. They are not part of the encrypted data. During decryption, all
slashes within the ciphertext must be removed before base64 decoding.</t>
        <t>For example, these are equivalent encrypted representations:
- <tt>https://ABC123def456GHI789</tt>
- <tt>https://ABC123/def456/GHI789</tt>
- <tt>https://ABC/123/def/456/GHI/789</tt></t>
        <t>All three would be decoded identically by removing slashes to produce
<tt>ABC123def456GHI789</tt> before base64 decoding.</t>
      </section>
    </section>
    <section anchor="algorithm-specification">
      <name>Algorithm Specification</name>
      <t>This section provides the complete algorithms for encryption and
decryption. The following functions and operations are used throughout
the algorithms:</t>
      <ul spacing="normal">
        <li>
          <t><tt>TurboSHAKE128()</tt>: Creates a new TurboSHAKE128 XOF instance with domain separation parameter 0x1F. This function produces an extensible output function (XOF) that can generate arbitrary-length outputs.</t>
        </li>
        <li>
          <t><tt>.update(data)</tt>: Absorbs the provided data into the XOF state. Data is processed sequentially and updates the internal state of the XOF.</t>
        </li>
        <li>
          <t><tt>.read(length)</tt>: Squeezes the specified number of bytes from the XOF’s output. Each call continues from where the previous read left off, producing a continuous stream of pseudorandom bytes.</t>
        </li>
        <li>
          <t><tt>.clone()</tt>: Creates a new XOF instance with an identical internal state to the original. This enables multiple independent computation paths from the same initial state.</t>
        </li>
        <li>
          <t>XOR operation: The bitwise exclusive OR operation between two byte sequences of equal length. This operation is used to combine plaintext with keystream for encryption, and ciphertext with keystream for decryption.</t>
        </li>
        <li>
          <t><tt>base64url_encode(data)</tt>: Converts binary data to a base64 string using URL-safe encoding (replacing ‘+’ with ‘-‘ and ‘/’ with ‘_’) and omitting padding characters.</t>
        </li>
        <li>
          <t><tt>base64url_decode(string)</tt>: Converts a URL-safe base64 string back to binary data, automatically handling the absence of padding characters.</t>
        </li>
        <li>
          <t><tt>Stream(data)</tt>: Creates a sequential reader for binary data, enabling byte-by-byte or block-based access to the contents.</t>
        </li>
        <li>
          <t><tt>constant_time_compare(a, b)</tt>: Compares two byte sequences in constant time, regardless of their contents. This prevents timing attacks by ensuring the comparison duration does not depend on which bytes differ.</t>
        </li>
        <li>
          <t><tt>len(data)</tt>: Returns the length of the provided data in bytes.</t>
        </li>
        <li>
          <t>Concatenation: The operation of joining two byte sequences end-to-end to form a single sequence.</t>
        </li>
        <li>
          <t><tt>zeros(count)</tt>: Generates a sequence of zero-valued bytes of the specified length, used for padding.</t>
        </li>
        <li>
          <t><tt>remove_padding(data)</tt>: Removes trailing zero bytes from a byte sequence to recover the original data length.</t>
        </li>
        <li>
          <t><tt>join(components)</tt>: Combines multiple path components into a single path string, preserving the terminator characters (<tt>'/'</tt>, <tt>'?'</tt>, <tt>'#'</tt>) that are included in each component.</t>
        </li>
      </ul>
      <section anchor="encryption-algorithm">
        <name>Encryption Algorithm</name>
        <t>Input: secret_key, context, uri_string</t>
        <t>Output: encrypted_uri</t>
        <t>Steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>Split URI into scheme and components</t>
          </li>
          <li>
            <t>Initialize XOF instances as described in <xref target="xof-init"/></t>
          </li>
          <li>
            <t><tt>encrypted_output = empty byte array</tt></t>
          </li>
          <li>
            <t>For each component:
            </t>
            <ul spacing="normal">
              <li>
                <t>Update <tt>components_xof</tt> with <tt>component</tt></t>
              </li>
              <li>
                <t><tt>SIV = components_xof.clone().read(SIVLEN)</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof = base_keystream_xof.clone()</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof.update(SIV)</tt></t>
              </li>
              <li>
                <t><tt>padding_len = (PADBS - (SIVLEN + len(component)) % PADBS) % PADBS</tt></t>
              </li>
              <li>
                <t><tt>keystream = keystream_xof.read(len(component) + padding_len)</tt></t>
              </li>
              <li>
                <t><tt>padded_component = component concatenated with zeros(padding_len)</tt></t>
              </li>
              <li>
                <t><tt>encrypted_part = padded_component XOR keystream</tt></t>
              </li>
              <li>
                <t><tt>encrypted_output = encrypted_output concatenated with SIV concatenated with encrypted_part</tt></t>
              </li>
            </ul>
          </li>
          <li>
            <t><tt>base64_output = base64url_encode(encrypted_output)</tt></t>
          </li>
          <li>
            <t>If scheme is not empty: Return <tt>scheme + base64_output</tt></t>
          </li>
          <li>
            <t>Else if original URI started with ‘/’: Return <tt>'/' + base64_output</tt></t>
          </li>
          <li>
            <t>Else: Return <tt>base64_output</tt></t>
          </li>
        </ol>
      </section>
      <section anchor="decryption-algorithm">
        <name>Decryption Algorithm</name>
        <t>Input: secret_key, context, encrypted_uri</t>
        <t>Output: decrypted_uri or error</t>
        <t>Note: For path-only URIs (those starting with ‘/’), the output format is:
- ‘/’ followed by the base64url-encoded encrypted components
- This preserves the absolute path indicator in the encrypted form</t>
        <t>Steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>Split encrypted URI into scheme and base64 part</t>
          </li>
          <li>
            <t>Remove all slash characters (‘/’) from the base64 part (the encrypted ciphertext after the scheme). These slashes may appear at arbitrary locations for aesthetic or structural purposes but are not part of the encrypted data.</t>
          </li>
          <li>
            <t><tt>decoded = base64url_decode(base64_part)</tt> If decoding fails, return <tt>error</tt></t>
          </li>
          <li>
            <t>Initialize XOF instances as described in <xref target="xof-init"/></t>
          </li>
          <li>
            <t><tt>decrypted_components = empty list</tt></t>
          </li>
          <li>
            <t><tt>position = 0</tt></t>
          </li>
          <li>
            <t>While <tt>position &lt; len(decoded)</tt>:
            </t>
            <ul spacing="normal">
              <li>
                <t><tt>SIV = decoded[position:position+SIVLEN]</tt> If not enough bytes, return <tt>error</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof = base_keystream_xof.clone()</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof.update(SIV)</tt></t>
              </li>
              <li>
                <t><tt>component_start = position + SIVLEN</tt></t>
              </li>
              <li>
                <t><tt>component = empty byte array</tt></t>
              </li>
              <li>
                <t><tt>position = position + SIVLEN</tt></t>
              </li>
              <li>
                <t>While <tt>position &lt; len(decoded)</tt>:
                </t>
                <ul spacing="normal">
                  <li>
                    <t><tt>decrypted_byte = decoded[position] XOR keystream_xof.read(1)</tt></t>
                  </li>
                  <li>
                    <t><tt>position = position + 1</tt></t>
                  </li>
                  <li>
                    <t>If <tt>decrypted_byte == 0x00</tt>: continue (skip padding)</t>
                  </li>
                  <li>
                    <t><tt>component.append(decrypted_byte)</tt></t>
                  </li>
                  <li>
                    <t>If <tt>decrypted_byte</tt> is <tt>'/'</tt>, <tt>'?'</tt>, or <tt>'#'</tt>:
                    </t>
                    <ul spacing="normal">
                      <li>
                        <t><tt>total_len = position - component_start</tt></t>
                      </li>
                      <li>
                        <t><tt>position = position + ((PADBS - ((SIVLEN + total_len) % PADBS)) % PADBS)</tt></t>
                      </li>
                      <li>
                        <t>Break inner loop</t>
                      </li>
                    </ul>
                  </li>
                </ul>
              </li>
              <li>
                <t>Update <tt>components_xof</tt> with <tt>component</tt></t>
              </li>
              <li>
                <t><tt>expected_SIV = components_xof.clone().read(SIVLEN)</tt></t>
              </li>
              <li>
                <t>If <tt>constant_time_compare(SIV, expected_SIV) == false</tt>, return <tt>error</tt></t>
              </li>
              <li>
                <t><tt>decrypted_components.append(component)</tt></t>
              </li>
            </ul>
          </li>
          <li>
            <t><tt>decrypted_path = join(decrypted_components)</tt></t>
          </li>
          <li>
            <t>Return <tt>scheme + decrypted_path</tt></t>
          </li>
        </ol>
      </section>
    </section>
    <section anchor="implementation-details">
      <name>Implementation Details</name>
      <section anchor="turboshake128-usage">
        <name>TurboSHAKE128 Usage</name>
        <t>Implementations MUST use TurboSHAKE128 with a domain separation
parameter of <tt>0x1F</tt> for all operations. The TurboSHAKE128 XOF is used
for:</t>
        <ul spacing="normal">
          <li>
            <t>Generating SIVs from the components XOF</t>
          </li>
          <li>
            <t>Generating keystream for encryption/decryption</t>
          </li>
          <li>
            <t>All XOF operations in the initialization</t>
          </li>
        </ul>
        <t>TurboSHAKE128 is specified in <xref target="RFC9861"/> and provides the security
properties needed for this construction.</t>
      </section>
      <section anchor="key-and-context-handling">
        <name>Key and Context Handling</name>
        <t>The secret key MUST be at least <tt>SIVLEN</tt> bytes long. Keys shorter than <tt>SIVLEN</tt>
bytes MUST be rejected. Implementations SHOULD validate that the key
does not consist of repeated patterns (e.g., identical first and
second halves) as a best practice.</t>
        <t>The context parameter is a string that provides domain separation.
Different applications SHOULD use different context strings to prevent
cross-application attacks. The context string MAY be empty.</t>
        <t>Both key and context are length-prefixed when absorbed into the base
XOF:</t>
        <artwork><![CDATA[
base_xof.update(len(secret_key) as uint8)
base_xof.update(secret_key)
base_xof.update(len(context) as uint8)
base_xof.update(context)
]]></artwork>
        <t>The length is encoded as a single byte, limiting keys and contexts to
255 bytes. This is sufficient for all practical use cases.</t>
      </section>
      <section anchor="error-handling">
        <name>Error Handling</name>
        <t>Implementations MUST NOT reveal the cause of decryption failures. All
error conditions (invalid base64, incorrect padding, SIV mismatch,
insufficient data) MUST result in identical, generic error messages.</t>
        <t>SIV comparison MUST be performed in constant-time to prevent timing
attacks.</t>
      </section>
    </section>
    <section anchor="security-guarantees">
      <name>Security Guarantees</name>
      <t>URICrypt provides the following cryptographic security guarantees:</t>
      <section anchor="confidentiality">
        <name>Confidentiality</name>
        <t>URICrypt achieves semantic security for URI path components through its use of TurboSHAKE128 as a pseudorandom function. Each component is encrypted using a unique keystream derived from the following:</t>
        <ul spacing="normal">
          <li>
            <t>The secret key</t>
          </li>
          <li>
            <t>The application context</t>
          </li>
          <li>
            <t>A synthetic initialization vector (SIV) that depends on all preceding components</t>
          </li>
        </ul>
        <t>This construction ensures that:</t>
        <ul spacing="normal">
          <li>
            <t>An attacker without the secret key cannot recover plaintext components from ciphertexts.</t>
          </li>
          <li>
            <t>The keystream generation is computationally indistinguishable from random for each unique (key, context, path-prefix) tuple.</t>
          </li>
          <li>
            <t>Components are protected by at least 128 bits of security against brute-force attacks.</t>
          </li>
        </ul>
      </section>
      <section anchor="authenticity-and-integrity">
        <name>Authenticity and Integrity</name>
        <t>Each URI component is authenticated through the SIV mechanism:</t>
        <ul spacing="normal">
          <li>
            <t>The SIV acts as a Message Authentication Code (MAC) computed over the component and all preceding components.</t>
          </li>
          <li>
            <t>Any modification to a component will cause the SIV verification to fail during decryption.</t>
          </li>
          <li>
            <t>The chained construction ensures that reordering, insertion, or deletion of components is detected.</t>
          </li>
          <li>
            <t>Authentication provides 128-bit security against forgery attempts.</t>
          </li>
        </ul>
      </section>
      <section anchor="prefix-preserving-property">
        <name>Prefix-Preserving Property</name>
        <t>URICrypt maintains a controlled information leakage pattern:</t>
        <ul spacing="normal">
          <li>
            <t>URIs sharing a common prefix will produce ciphertexts with the same encrypted prefix.</t>
          </li>
          <li>
            <t>This property is deterministic and intentional, enabling systems to perform prefix-based operations.</t>
          </li>
          <li>
            <t>The leakage is limited to prefix structure only—no information about non-matching suffixes is revealed.</t>
          </li>
        </ul>
      </section>
      <section anchor="domain-separation">
        <name>Domain Separation</name>
        <t>The context parameter provides cryptographic domain separation:</t>
        <ul spacing="normal">
          <li>
            <t>Different contexts with the same key produce completely independent ciphertexts.</t>
          </li>
          <li>
            <t>This prevents cross-context attacks where ciphertexts from one application could be used in another.</t>
          </li>
          <li>
            <t>Context binding is cryptographically enforced through the XOF initialization.</t>
          </li>
        </ul>
      </section>
      <section anchor="key-commitment">
        <name>Key Commitment</name>
        <t>URICrypt provides full key-commitment security.</t>
        <t>The scheme is fully key-committing, meaning that a ciphertext can only be decrypted with the exact key that was used to encrypt it. It is computationally infeasible to find two different keys that successfully decrypt the same ciphertext to valid plaintexts.</t>
      </section>
      <section anchor="resistance-to-common-attacks">
        <name>Resistance to Common Attacks</name>
        <t>URICrypt resists several categories of attacks:</t>
        <t>Chosen-plaintext Attacks (CPA): While deterministic, URICrypt is CPA-secure for unique inputs. The determinism is a design requirement for prefix preservation.</t>
        <t>Tampering Detection: Any bit flip, truncation, or modification in the ciphertext will be detected with overwhelming probability (1 - 2<sup>-128</sup>).</t>
        <t>Length-extension Attacks: The use of length-prefixed encoding and domain separation prevents length-extension attacks.</t>
        <t>Replay Attacks: Within a single (key, context) pair, replay is possible due to determinism. Applications requiring replay protection should incorporate timestamps or nonces into the context.</t>
        <t>Key Recovery: TurboSHAKE128’s security properties ensure that observing ciphertexts does not leak information about the secret key.</t>
      </section>
      <section anchor="security-bounds">
        <name>Security Bounds</name>
        <t>The security of URICrypt is bounded by the following:</t>
        <ul spacing="normal">
          <li>
            <t>Key strength: Minimum 128-bit security with <tt>SIVLEN</tt>-byte keys</t>
          </li>
          <li>
            <t>Collision resistance: 2<sup>64</sup> birthday bound for SIV collisions</t>
          </li>
          <li>
            <t>Authentication security: 2<sup>-128</sup> probability of successful forgery</t>
          </li>
          <li>
            <t>Computational security: Based on TurboSHAKE128’s proven security as an XOF</t>
          </li>
        </ul>
      </section>
      <section anchor="limitations-and-trade-offs">
        <name>Limitations and Trade-offs</name>
        <t>URICrypt makes specific security trade-offs for functionality, including the following:</t>
        <ul spacing="normal">
          <li>
            <t>Deterministic encryption: Same inputs produce same outputs, enabling certain traffic analysis</t>
          </li>
          <li>
            <t>Partial length obfuscation: With <tt>PADBS=3</tt>, exact component lengths are partially hidden</t>
          </li>
          <li>
            <t>Prefix structure leakage: The hierarchical structure of URIs is preserved by design</t>
          </li>
          <li>
            <t>SIV length configuration: Implementations MAY adjust <tt>SIVLEN</tt> for different usage bounds. Larger values (24 or 32 bytes) increase birthday bound resistance at the cost of ciphertext expansion. However, 16 bytes is generally recommended as it provides practical collision resistance with acceptable overhead</t>
          </li>
          <li>
            <t>Padding block size configuration: The default <tt>PADBS=3</tt> already provides partial length-hiding. Implementations MAY adjust <tt>PADBS</tt> to increase size obfuscation. Larger values create larger size buckets but increase ciphertext expansion. The value MUST remain a multiple of 3 to ensure efficient Base64url encoding without padding characters</t>
          </li>
        </ul>
        <t>These trade-offs are intentional and necessary for the prefix-preserving functionality. Applications requiring stronger privacy guarantees should evaluate whether URICrypt’s properties align with their threat model.</t>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>URICrypt provides confidentiality and integrity for URI paths while
preserving prefix relationships. The encryption is fully reversible:
encrypted URIs can be decrypted to recover the original plaintext URIs,
but only with knowledge of the secret key. The security properties depend on:</t>
      <ul spacing="normal">
        <li>
          <t>Key Secrecy: The security of URICrypt depends entirely on the
secrecy of the secret key. Keys MUST be generated using a
cryptographically secure random number generator <xref target="RFC4086"/> and
stored securely.</t>
        </li>
        <li>
          <t>Deterministic Encryption: URICrypt is deterministic - identical
inputs produce identical outputs. This allows observers to detect
when the same URI is encrypted multiple times. Applications
requiring unlinkability SHOULD incorporate additional entropy (e.g.,
via the context parameter).</t>
        </li>
        <li>
          <t>Prefix Preservation: While essential for functionality, prefix
preservation leaks information about URI structure. Systems where
this information is sensitive SHOULD consider alternative
approaches.</t>
        </li>
        <li>
          <t>Context Separation: The context parameter prevents cross-context
attacks. Applications MUST use distinct contexts for different
purposes, even when sharing keys.</t>
        </li>
        <li>
          <t>Component Authentication: Each component is authenticated via
the SIV mechanism. Any modification, reordering, or truncation of
components will be detected during decryption.</t>
        </li>
        <li>
          <t>Length Obfuscation: The default <tt>PADBS=3</tt> configuration provides partial
length-hiding. Applications requiring stronger length-hiding
SHOULD consider using larger <tt>PADBS</tt> values or padding components to fixed lengths.</t>
        </li>
        <li>
          <t>Key Reuse: Using the same key with different contexts is safe, but
using the same (key, context) pair for different applications is
NOT RECOMMENDED.</t>
        </li>
      </ul>
    </section>
    <section numbered="false" anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no actions for IANA.</t>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The author would like to thank Maciej Soltysiak for highlighting the importance of properly supporting query parameters and fragments in URI encryption.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-normative-references">
      <name>Normative References</name>
      <reference anchor="I-D.draft-denis-ipcrypt">
        <front>
          <title>Methods for IP Address Encryption and Obfuscation</title>
          <author fullname="Frank Denis" initials="F." surname="Denis">
            <organization>Fastly Inc.</organization>
          </author>
          <date day="15" month="March" year="2026"/>
          <abstract>
            <t>   This document specifies secure, efficient methods for encrypting IP
   addresses for privacy-preserving storage, logging, and analytics.
   Unlike truncation, which destroys data irreversibly, these methods
   are reversible with the encryption key while providing strong privacy
   guarantees.

   Four modes are defined: ipcrypt-deterministic (format-preserving, IP-
   address output), ipcrypt-pfx (prefix-preserving, native address
   size), ipcrypt-nd and ipcrypt-ndx (non-deterministic with random
   tweaks).  All support high-performance processing at network speeds
   and produce interoperable results across implementations.

            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-denis-ipcrypt-13"/>
      </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>
      <reference anchor="RFC3986">
        <front>
          <title>Uniform Resource Identifier (URI): Generic Syntax</title>
          <author fullname="T. Berners-Lee" initials="T." surname="Berners-Lee"/>
          <author fullname="R. Fielding" initials="R." surname="Fielding"/>
          <author fullname="L. Masinter" initials="L." surname="Masinter"/>
          <date month="January" year="2005"/>
          <abstract>
            <t>A Uniform Resource Identifier (URI) is a compact sequence of characters that identifies an abstract or physical resource. This specification defines the generic URI syntax and a process for resolving URI references that might be in relative form, along with guidelines and security considerations for the use of URIs on the Internet. The URI syntax defines a grammar that is a superset of all valid URIs, allowing an implementation to parse the common components of a URI reference without knowing the scheme-specific requirements of every possible identifier. This specification does not define a generative grammar for URIs; that task is performed by the individual specifications of each URI scheme. [STANDARDS-TRACK]</t>
          </abstract>
        </front>
        <seriesInfo name="STD" value="66"/>
        <seriesInfo name="RFC" value="3986"/>
        <seriesInfo name="DOI" value="10.17487/RFC3986"/>
      </reference>
      <reference anchor="RFC4648">
        <front>
          <title>The Base16, Base32, and Base64 Data Encodings</title>
          <author fullname="S. Josefsson" initials="S." surname="Josefsson"/>
          <date month="October" year="2006"/>
          <abstract>
            <t>This document describes the commonly used base 64, base 32, and base 16 encoding schemes. It also discusses the use of line-feeds in encoded data, use of padding in encoded data, use of non-alphabet characters in encoded data, use of different encoding alphabets, and canonical encodings. [STANDARDS-TRACK]</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="4648"/>
        <seriesInfo name="DOI" value="10.17487/RFC4648"/>
      </reference>
      <reference anchor="RFC9861">
        <front>
          <title>KangarooTwelve and TurboSHAKE</title>
          <author fullname="B. Viguier" initials="B." surname="Viguier"/>
          <author fullname="D. Wong" initials="D." role="editor" surname="Wong"/>
          <author fullname="G. Van Assche" initials="G." role="editor" surname="Van Assche"/>
          <author fullname="Q. Dang" initials="Q." role="editor" surname="Dang"/>
          <author fullname="J. Daemen" initials="J." role="editor" surname="Daemen"/>
          <date month="October" year="2025"/>
          <abstract>
            <t>This document defines four eXtendable-Output Functions (XOFs), hash functions with output of arbitrary length, named TurboSHAKE128, TurboSHAKE256, KT128, and KT256.</t>
            <t>All four functions provide efficient and secure hashing primitives, and the last two are able to exploit the parallelism of the implementation in a scalable way.</t>
            <t>This document is a product of the Crypto Forum Research Group. It builds up on the definitions of the permutations and of the sponge construction in NIST FIPS 202 and is meant to serve as a stable reference and an implementation guide.</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="9861"/>
        <seriesInfo name="DOI" value="10.17487/RFC9861"/>
      </reference>
      <reference anchor="RFC4086">
        <front>
          <title>Randomness Requirements for Security</title>
          <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd"/>
          <author fullname="J. Schiller" initials="J." surname="Schiller"/>
          <author fullname="S. Crocker" initials="S." surname="Crocker"/>
          <date month="June" year="2005"/>
          <abstract>
            <t>Security systems are built on strong cryptographic algorithms that foil pattern analysis attempts. However, the security of these systems is dependent on generating secret quantities for passwords, cryptographic keys, and similar quantities. The use of pseudo-random processes to generate secret quantities can result in pseudo-security. A sophisticated attacker may find it easier to reproduce the environment that produced the secret quantities and to search the resulting small set of possibilities than to locate the quantities in the whole of the potential number space.</t>
            <t>Choosing random quantities to foil a resourceful and motivated adversary is surprisingly difficult. This document points out many pitfalls in using poor entropy sources or traditional pseudo-random number generation techniques for generating such quantities. It recommends the use of truly random hardware techniques and shows that the existing hardware on many systems can be used for this purpose. It provides suggestions to ameliorate the problem when a hardware solution is not available, and it gives examples of how large such quantities need to be for some applications. 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="106"/>
        <seriesInfo name="RFC" value="4086"/>
        <seriesInfo name="DOI" value="10.17487/RFC4086"/>
      </reference>
    </references>
    <?line 827?>

<section anchor="pseudocode">
      <name>Pseudocode</name>
      <section anchor="uri-component-extraction-1">
        <name>URI Component Extraction</name>
        <artwork><![CDATA[
function extract_components(uri_string):
  if uri_string contains "://":
     scheme = substring up to and including "://"
     path = substring after "://"
  else:
     scheme = ""
     path = uri_string

  components = []

  // For absolute paths, treat leading "/" as first component
  if path starts with "/":
     components.append("/")
     path = substring after first "/"

  while path is not empty:
     terminator_pos = find_next_terminator(path)
     if terminator_pos found:
        component = substring(path, 0, terminator_pos + 1)
        path = substring(path, terminator_pos + 1)
        components.append(component)
     else:
        components.append(path)
        path = ""

  return (scheme, components)

function find_next_terminator(path):
  for i from 0 to length(path) - 1:
     if path[i] == '/' or path[i] == '?' or path[i] == '#':
        return i
  return not_found
]]></artwork>
      </section>
      <section anchor="xof-initialization">
        <name>XOF Initialization</name>
        <artwork><![CDATA[
function initialize_xofs(secret_key, context):
  // Initialize base XOF
  base_xof = TurboSHAKE128(0x1F)

  // Absorb key and context with length prefixes
  base_xof.update(uint8(len(secret_key)))
  base_xof.update(secret_key)
  base_xof.update(uint8(len(context)))
  base_xof.update(context)

  // Create components XOF
  components_xof = base_xof.clone()
  components_xof.update("IV")

  // Create base keystream XOF
  base_keystream_xof = base_xof.clone()
  base_keystream_xof.update("KS")

  return (components_xof, base_keystream_xof)
]]></artwork>
      </section>
      <section anchor="encryption-algorithm-1">
        <name>Encryption Algorithm</name>
        <artwork><![CDATA[
function uricrypt_encrypt(secret_key, context, uri_string):
  // Extract components
  (scheme, components) = extract_components(uri_string)

  // Initialize XOF instances with secret key and context
  (components_xof, base_keystream_xof) =
      initialize_xofs(secret_key, context)
  if error: return error

  encrypted_output = byte_array()

  // Process each component
  for component in components:
     // Update components XOF for SIV computation
     components_xof.update(component)

     // Generate SIVLEN-byte Synthetic Initialization Vector (SIV)
     siv = components_xof.clone().squeeze(SIVLEN)

     // Create keystream XOF for this component
     keystream_xof = base_keystream_xof.clone()
     keystream_xof.update(siv)

     // Calculate padding for base64 encoding alignment
     // The total bytes (SIV + component) must be a multiple of PADBS
     // to produce clean base64 output without padding characters
     component_len = len(component)
     padding_len = (PADBS - (SIVLEN + component_len) % PADBS) % PADBS

     // Generate keystream
     keystream = keystream_xof.squeeze(component_len + padding_len)

     // Pad component to align with base64 encoding requirements
     padded_component = component + byte_array(padding_len)

     // Encrypt using XOR with keystream
     encrypted_part = xor_bytes(padded_component, keystream)

     // Append to output
     encrypted_output.extend(siv)
     encrypted_output.extend(encrypted_part)

  // Base64 encode with URL-safe characters and no padding
  base64_output = base64_urlsafe_no_pad_encode(encrypted_output)

  // Return with appropriate prefix
  if scheme != "":
     return scheme + base64_output
  else if uri_string starts with "/":
     return "/" + base64_output
  else:
     return base64_output
]]></artwork>
      </section>
      <section anchor="decryption-algorithm-1">
        <name>Decryption Algorithm</name>
        <artwork><![CDATA[
function uricrypt_decrypt(secret_key, context, encrypted_uri):
  // Split scheme and base64
  if encrypted_uri contains "://":
     scheme = substring up to and including "://"
     base64_part = substring after "://"
  else if encrypted_uri starts with "/":
     // Path-only URI: strip leading "/" before decoding
     scheme = ""
     base64_part = substring after first "/"
  else:
     scheme = ""
     base64_part = encrypted_uri

  // Remove all slashes from the base64 part (the encrypted ciphertext)
  // Slashes may appear at arbitrary locations after the scheme for
  // aesthetic/structural purposes, but are not part of the encrypted data
  base64_part = base64_part.replace("/", "")

  // Decode base64
  try:
     decoded = base64_urlsafe_no_pad_decode(base64_part)
  catch:
     return error("Decryption failed")

  // Initialize XOF instances with secret key and context
  (components_xof, base_keystream_xof) =
      initialize_xofs(secret_key, context)
  if error: return error

  decrypted_components = []
  input_stream = ByteStream(decoded)

  // Process each component
  while not input_stream.empty():
     // Read SIV
     siv = input_stream.read(SIVLEN)
     if len(siv) != SIVLEN:
        return error("Decryption failed")

     // Create keystream XOF
     keystream_xof = base_keystream_xof.clone()
     keystream_xof.update(siv)

     // Decrypt byte-by-byte to find component boundary
     component = byte_array()
     component_start = input_stream.position()

     while not input_stream.empty():
        // Decrypt one byte
        encrypted_byte = input_stream.read(1)
        if len(encrypted_byte) != 1:
           return error("Decryption failed")

        keystream_byte = keystream_xof.squeeze(1)
        decrypted_byte = xor_bytes(encrypted_byte, keystream_byte)[0]

        // Skip padding (null bytes)
        if decrypted_byte == 0x00:
           continue

        // Add to component
        component.append(decrypted_byte)

        // Check for terminator
        if decrypted_byte == '/' or decrypted_byte == '?' or decrypted_byte == '#':
           // Component complete - skip remaining padding
           total_len = input_stream.position() - component_start
           padding_len = (PADBS - ((SIVLEN + total_len) % PADBS)) % PADBS
           input_stream.skip(padding_len)
           break

     // Update XOF with plaintext
     components_xof.update(component)

     // Generate expected SIV
     expected_siv = components_xof.clone().squeeze(SIVLEN)

     // Authenticate using constant-time comparison to prevent timing attacks
     if not constant_time_equal(siv, expected_siv):
        return error("Decryption failed")

     decrypted_components.append(component)

  // Reconstruct URI
  path = "".join(decrypted_components)
  return scheme + path
]]></artwork>
      </section>
      <section anchor="padding-and-encoding-1">
        <name>Padding and Encoding</name>
        <artwork><![CDATA[
function calculate_padding(component_len):
  // Calculate padding needed for base64 encoding alignment
  // The combined SIV (SIVLEN bytes) + component must be divisible by PADBS
  // for clean base64 encoding without '=' padding characters
  total_len = SIVLEN + component_len
  return (PADBS - total_len % PADBS) % PADBS

function base64_urlsafe_no_pad_encode(data):
  // Use standard base64 encoding
  encoded = standard_base64_encode(data)
  // Make URL-safe and remove padding for URI compatibility
  encoded = encoded.replace('+', '-')
                   .replace('/', '_')
                   .rstrip('=')
  return encoded

function base64_urlsafe_no_pad_decode(encoded):
  // Add padding if needed for standard decoder
  padding = (4 - len(encoded) % 4) % 4
  if padding > 0:
     encoded = encoded + ('=' * padding)
  // Make standard base64
  encoded = encoded.replace('-', '+')
                   .replace('_', '/')
  // Decode
  return standard_base64_decode(encoded)
]]></artwork>
      </section>
    </section>
    <section anchor="test-vectors">
      <name>Test Vectors</name>
      <t>These test vectors were generated using the reference Rust implementation
of URICrypt with TurboSHAKE128.</t>
      <artwork><![CDATA[
Test Configuration:
secret_key (hex): 0102030405060708090a0b0c0d0e0f10
context: "test-context"
]]></artwork>
      <section anchor="test-vector-1-full-uri">
        <name>Test Vector 1: Full URI</name>
        <artwork><![CDATA[
Input: "https://example.com/a/b/c"
Output: "https://HOGo9vauZ3b3xsPNPQng5apSzL5V7QW94C7USgN8mHZJ337AKSWOu
         cUwMuD-uUfF95SsSHCNgBkXUnH1uGll_YtBltXSqKEHNcYJJwbdFdhfWz19"
]]></artwork>
      </section>
      <section anchor="test-vector-2-path-only-uri">
        <name>Test Vector 2: Path-Only URI</name>
        <artwork><![CDATA[
Input: "/a/b/c"
Output: "/b9bCOhqZsvU9XxGOMk6d8QFQhTIdI_xYKpds2lWXpZCms5-az9wtfUft3rec
         3d9YkUo0N7VcxO5MXfxE5UobvgTJX8UpRdNN"
]]></artwork>
      </section>
      <section anchor="test-vector-3-multi-component-path">
        <name>Test Vector 3: Multi-Component Path</name>
        <artwork><![CDATA[
Input: "https://cdn.example.com/videos/2025/03/file.mp4"
Output: "https://hxUM2N3txwYjGxjvCpWn30SznxR0v0fDbkSQgCTXCUu7Rq8iSbWP4
         0OvYxKs9zC3kw1JNzAc4Wuj7RZvRd0VUprJWLs5KJPnWsA9Kguxa_J7XviTS3G
         Tqf-XZdPxYyq1Y1MXVE9_4ojHwm6jBDUkVthAkuNe5Cqk_h6d"
]]></artwork>
      </section>
      <section anchor="test-vector-4-root-with-scheme">
        <name>Test Vector 4: Root with Scheme</name>
        <artwork><![CDATA[
Input: "https://example.com/"
Output: "https://HOGo9vauZ3b3xsPNPQng5apSzL5V7QW94C7USgN8"
]]></artwork>
      </section>
      <section anchor="test-vector-5-simple-path">
        <name>Test Vector 5: Simple Path</name>
        <artwork><![CDATA[
Input: "/path/to/resource"
Output: "/b9bCOhqZsvU9XxGOMk6d8QFQPTuMlsQKDBhAbc77JvsdRj0kxiFipunATQmm
         CkNhAe0BPP2EqQoxORElY_ukfUYSrr9mIMfiO9joa3Kn5RS7eSKr"
]]></artwork>
      </section>
      <section anchor="test-vector-6-uri-with-query-parameters">
        <name>Test Vector 6: URI with Query Parameters</name>
        <artwork><![CDATA[
Input: "https://example.com/search?q=test&limit=10"
Output: "https://HOGo9vauZ3b3xsPNPQng5apSzL5V7QW94C7USgN8cl2BBtuWmxTsI
         Ij59ka3KeDsaqXFGnKgW9aLLR36YvUf9ORkMnVE5PTR_3DiO43hL9WjdSu7L9
         FN"
]]></artwork>
      </section>
      <section anchor="test-vector-7-uri-with-fragment">
        <name>Test Vector 7: URI with Fragment</name>
        <artwork><![CDATA[
Input: "https://docs.example.com/guide#installation"
Output: "https://ypHTiw0JUMcr4bUjQH9Dxo8wGWHyfFlLq8VrOE-zX6IbgLFxYX_Jm
         2hzivywvrpIBWa-9Jl6nSZLq2pd35QwkDsc1-_Kao2BvyBB19ndu1PpwQv1wy
         uA"
]]></artwork>
      </section>
      <section anchor="test-vector-8-uri-with-query-and-fragment">
        <name>Test Vector 8: URI with Query and Fragment</name>
        <artwork><![CDATA[
Input: "/api/v2/users?id=123#profile"
Output: "/b9bCOhqZsvU9XxGOMk6d8QFQwcP2C3bJVNVZDge7zfub_ai4x6LaUlXp-XjZ
         XOgZlLloIbasK-JKlbeKeKV2rctq5bX9zQh1KogN2zaggTMZioUb4kwGIKp8Z
         y744xQwGDG64n6GhN56XEM8LvBfJuEj6ZgsjeLbTPIMbCmO0pJhzVSh"
]]></artwork>
      </section>
    </section>
  </back>
  <!-- ##markdown-source:
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
y38KJdBKmME0bySnv9tJ6wr3hX28H7NNxNnThzB7ha2WFuu2+m8d8QJNFLCl
niu+wCxS9vmZOCj8jDOvQHPHGP5ihEpG9cDpirYXiDM8haETOObZETIkHJwr
Bvk0MU2+64SveUadF7VRcFdvi+WV5dXlteX15Y3lzeVny8+Xt5b95e5yb7m/
HCwPVpY9qfXjE+4woIpXWNB8zVojPlv8UlZBdZ6dv+8haVVwRbd5ffIq3rrx
889r3bW79PT49F003PCn598ON94/e/dha3332eX58Pj55PXnN2trz7bfnn84
yc1m9i5vj/K9Zn45eLm1cZ6ev949Hu5cf7yMXq/kr8bjq0/Zzjj7eP717f7r
496nN29uu/2X/dHgw7eVrepFrbbZYj+RFru7stIylrpb3d2T0dfP6c3l1se7
VydH15v95+9evhtdHPQPru4+vZ3209Xxh4/Tz7uTdKPpf9u6zQaXg2wtCXpm
GWv9rU/Xl/Hy8bP3vbuTjaOPg7v9jcu4ezO8ePPx+eX0rH98XA3vWlscoeu0
aZQnhL96Q3r9qGVvCkZLxOnS6vLqxtLy2tIApGhrMl2v2KbR3eXR6vFadnf7
6curuy83u9MP0dry+bfo7mz5Znmw170+fzfcvfi4e5k/O/v6PDzvfjhdN+tb
Prn5dPc23fq2u3Z9u/Lm+Nt2b/1D/uXZ2eebs/7y+8tp8ubDYbrx9s1p9CHd
3no7zO/8qzfPPt6EF+drr8w4F18HzY+f+6d3n2ZfVz6tHH18v791tR5/eX07
2fyys3d5/T4bbV/nx8HG7tfrq9Fmvxpp621xFsfqPQcS4A9T8J8g3mooNtri
nI56xY5VPCf+MM2dXuRH4/Td272d0Xa39+zZm5u0f/Zl+foufBlO82j74t1k
YnC5e3082g6Wd05PV/e/vovvTs72x5+u8uvB5afzJNmaHBwNwpOtL7G/9jba
ODt/Fpy/TaoXskkRb4zNdxRfcarjKx7GaxpgxPNPX18gx/kbJYW9WFn+E9ju
jVd3drL8w+TuIj0w6z34srF1DYsJ9lL/68eXr6K3ww9b/uHh2drmp5vLwdbJ
2fVR9H5/4/Ti7GptLzxZXxsdbn340j/Pnx1umWFezjmIzywkvJTxJNWL78e9
1DmGwxzO4RPy8Iw55LNi9bPp64vwdvnN5VEvWe9efnn3emvvLn5+++rD69ng
5fjw6/P3ycl+89vHzYPu8PDl3aePV2+s3V4dfQtvZrc3yfRg54Pf3Hoz3ozO
Px9+XZ321zbe3V7vpb2V5tVbP17duZnt7KxsRf185XR6++5m5XZmhsm3q1f/
vEQCqBhV42HJn4ZLN6tLeQr08VPYf7GyuvZkmsTIfh5D5re909Xdte6b98fv
P+8Ng2ffBnn3yg/X7zYP/cvxx2nz45fPBuKPJ8PP48NxfADC+23zzdtxN3gb
vH2/mvSyrxvdj1vf3o1W3sbD49Vv/nB4cfQ5jC+769e3rw7eTp9bw8yera/f
vbt9tfdqcz3afDU63tj8uH/0/PBmZ/Am3/+y+XmYfgkOuxenB0fd3cnJ8vTN
6Nv78xFj678BzR2OS8unAAA=

-->

</rfc>
