<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.29 (Ruby 3.2.3) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

]>


<rfc ipr="trust200902" docName="draft-saywhere-geocoding-00" category="info" submissionType="independent" xml:lang="en">
  <front>
    <title abbrev="SayWhere Geocoding">SayWhere Geocoding System: Human-Memorable Geographic Coordinates</title>

    <author initials="H." surname="O'Connor" fullname="Hugo O'Connor">
      <organization>Anuna Research Pty Ltd</organization>
      <address>
        <email>hugo@anuna.io</email>
        <uri>https://codeberg.org/anuna/saywhere</uri>
      </address>
    </author>

    <date year="2025" month="October" day="12"/>

    
    
    <keyword>geocoding</keyword> <keyword>geolocation</keyword> <keyword>coordinates</keyword> <keyword>geohash</keyword> <keyword>BIP-39</keyword>

    <abstract>


<?line 86?>

<t>This document specifies SayWhere, an open-source system for encoding geographic coordinates (latitude, longitude, and optional altitude) into human-memorable word phrases and decoding them back to coordinates. The system provides deterministic, reversible encoding with two-layer error detection (per-word parity and optional terminal word-phrase checksum) and supports three-dimensional positioning for multi-level structures. SayWhere introduces hierarchical variable-length phrases with true prefix relationships, enabling precision scaling from regional (1 word) to meter-level accuracy (6 words). The system uses the Bitcoin Improvement Proposal 39 (BIP-39) mnemonic wordlist for multilingual support and geohash spatial indexing for efficient location encoding.</t>



    </abstract>



  </front>

  <middle>


<?line 90?>

<section anchor="introduction"><name>Introduction</name>

<section anchor="motivation"><name>Motivation</name>

<t>Geographic coordinates (latitude, longitude) are precise but difficult to communicate verbally or memorize. A typical coordinate pair such as (40.7128, -74.0060) requires exact decimal precision and is prone to transcription errors. SayWhere addresses this by encoding coordinates into memorable word phrases while maintaining precision, determinism, and providing error detection capabilities.</t>

<t>This challenge becomes critical in natural disasters and emergency response scenarios, where communication infrastructure may be compromised and rapid verbal location sharing essential for coordinating rescue operations. Word-based location phrases can be communicated over radio, written on paper, or relayed through human chains without requiring functional GPS devices or internet connectivity.</t>

<t>Traditional postal addresses do not always provide the level of precision desired, assume a built environment, and often require some tacit knowledge of that built environment. Existing proprietary systems use closed algorithms, lack transparency and require a centralized service to resolve word phrases creating a single point of failure which is unaceptable in critical environments. Plus Codes use alphanumeric strings that are harder to communicate verbally. Traditional geohash uses Base32 strings that are not human-memorable. SayWhere provides an open, transparent alternative with hierarchical structure, optional altitude, multi-lingual support, and error detection.</t>

</section>
<section anchor="design-goals"><name>Design Goals</name>

<t><list style="numbers" type="1">
  <t><strong>Deterministic</strong>: Same coordinates always produce identical word phrases</t>
  <t><strong>Reversible</strong>: Word phrases can be decoded back to original coordinates</t>
  <t><strong>Human-Friendly</strong>: Words are common, easy to spell, and phonetically distinct</t>
  <t><strong>Error Detection</strong>: Two-layer validation with per-word parity and optional terminal checksum tp validate a word phrase.</t>
  <t><strong>3D Support</strong>: Optional altitude component for vertical positioning</t>
  <t><strong>Open Standard</strong>: Public domain algorithm based on established prior art with no proprietary restrictions</t>
  <t><strong>Hierarchical</strong>: Variable-length phrases (1-6 words) with true prefix relationships</t>
</list></t>

</section>
<section anchor="comparison-to-existing-systems"><name>Comparison to Existing Systems</name>

<t><list style="symbols">
  <t><strong>Proprietary word-based systems</strong>: Closed algorithms, fixed-length (typically 3 words), no error detection, no altitude support</t>
  <t><strong>Plus Codes</strong>: Alphanumeric (not word-based), harder to communicate verbally</t>
  <t><strong>Geohash</strong>: Base32 strings, not human-memorable</t>
  <t><strong>SayWhere</strong>: Open source, hierarchical word phrases, 3D support, two-layer error detection (LSB parity + optional terminal checksum), true prefix relationships, hand-verifiable checksums</t>
</list></t>

</section>
<section anchor="technical-differentiation"><name>Technical Differentiation</name>

<t>SayWhere is built upon established open technologies as prior art:</t>

<t><list style="symbols">
  <t><strong>Geohash</strong> (Niemeyer, 2008): Spatial indexing system using base-32 strings</t>
  <t><strong>BIP-39</strong> (Palatinus et al., 2013): Mnemonic wordlist standard with 2,048 words</t>
</list></t>

<t>SayWhere combines geohash spatial indexing with BIP-39 word encoding to create hierarchical variable-length phrases. This differs from fixed-length proprietary systems that use cell-based integer decomposition approaches. The use of geohash as the intermediate representation (rather than proprietary integer encoding) and the hierarchical prefix relationships are key distinguishing features.</t>

</section>
</section>
<section anchor="terminology"><name>Terminology</name>

<section anchor="requirements-language"><name>Requirements Language</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?>

</section>
<section anchor="core-concepts"><name>Core Concepts</name>

<dl>
  <dt>Hierarchical Word Phrase:</dt>
  <dd>
    <t>Variable-length sequence of words (1-N words) representing location with increasing precision</t>
  </dd>
  <dt>Prefix Relationship:</dt>
  <dd>
    <t>Shorter phrases represent a bounded area that contain all longer phrases with the same prefix</t>
  </dd>
  <dt>Location Words:</dt>
  <dd>
    <t>Words encoding the position of cell within a base32 cell grid (excluding checksum and altitude)</t>
  </dd>
  <dt>Checksum Word:</dt>
  <dd>
    <t>Optional terminal validation word from a distinct 32-word vocabulary for phrase-level error detection</t>
  </dd>
  <dt>Altitude Units:</dt>
  <dd>
    <t>Optional numeric component for vertical position</t>
  </dd>
  <dt>Wordlist:</dt>
  <dd>
    <t>An ordered array of words used for encoding/decoding (BIP-39 standard)</t>
  </dd>
  <dt>Precision Level:</dt>
  <dd>
    <t>Spatial resolution determined by phrase length</t>
  </dd>
  <dt>Geohash:</dt>
  <dd>
    <t>A geocoding system using base32 strings for spatial indexing</t>
  </dd>
</dl>

</section>
<section anchor="phrase-types"><name>Phrase Types</name>

<dl>
  <dt>Hierarchical Phrase:</dt>
  <dd>
    <t>Pure spatial encoding without terminal checksum (maintains prefix relationships)</t>
  </dd>
  <dt>Validated Phrase:</dt>
  <dd>
    <t>Includes terminal checksum word for phrase-level error detection</t>
  </dd>
  <dt>3D Phrase:</dt>
  <dd>
    <t>Includes altitude component for vertical positioning</t>
  </dd>
</dl>

</section>
</section>
<section anchor="system-architecture"><name>System Architecture</name>

<section anchor="encoding-pipeline"><name>Encoding Pipeline</name>

<t>The encoding process transforms geographic coordinates into word phrases through the following pipeline:</t>

<t><list style="numbers" type="1">
  <t>Input validation: Verify latitude [-90, 90], longitude [-180, 180], altitude [-30000, 30000]</t>
  <t>Geohash generation: Convert coordinates to base32 geohash string</t>
  <t>Chunk processing: Split geohash into 2-character chunks (10 bits each)</t>
  <t>Parity calculation: Add 1-bit LSB parity to each chunk</t>
  <t>Word mapping: Map 11-bit values (10 data + 1 parity) to BIP-39 wordlist</t>
  <t>Phrase assembly: Join location words with dots for hierarchical structure</t>
  <t>Optional: Compute and append CRC-8 terminal checksum word from 32-word vocabulary</t>
</list></t>

</section>
<section anchor="decoding-pipeline"><name>Decoding Pipeline</name>

<t>The decoding process reverses the encoding to recover coordinates:</t>

<t><list style="numbers" type="1">
  <t>Phrase parsing: Split on dots, validate word format</t>
  <t>Checksum detection: Identify and separate terminal checksum word (if present)</t>
  <t>Word lookup: Find each location word in BIP-39 wordlist to get 11-bit index</t>
  <t>LSB parity validation: Verify 1-bit parity for each location word</t>
  <t>Terminal checksum validation: If present, validate phrase-level checksum</t>
  <t>Chunk extraction: Extract 10-bit chunk value from each location word</t>
  <t>Geohash reconstruction: Concatenate chunks to form geohash string</t>
  <t>Coordinate decoding: Decode geohash to latitude/longitude with bounds</t>
</list></t>

</section>
<section anchor="format-specifications"><name>Format Specifications</name>

<section anchor="hierarchical-format"><name>Hierarchical Format</name>

<t>Hierarchical phrases maintain true prefix relationships:</t>

<figure><artwork><![CDATA[
grape                                  # Region (~900km)
grape.column                           # City (~28km)
grape.column.hip                       # Neighborhood (~900m)
grape.column.hip.thought               # Street (~27m)
grape.column.hip.thought.pull          # Door (~90cm)
grape.column.hip.thought.pull.wave     # Sub-meter (~2.7cm)
]]></artwork></figure>

<t><strong>Key Property:</strong> Each shorter phrase represents an area containing all longer phrases with the same prefix.</t>

<t><strong>Error Detection:</strong> Two independent layers:
1. Each location word contains a built-in LSB parity bit for single-word error detection
2. Optional terminal checksum word validates the entire phrase (with ~3% False Negative)</t>

<t><strong>With Terminal Checksum:</strong>
~~~~
grape.column.hip.seal           # Validated 3-word phrase
~~~~
Where "seal" is from the 32-word checksum vocabulary and validates "grape.column.hip".</t>

</section>
<section anchor="precision-vs-length-table"><name>Precision vs. Length Table</name>

<t>Precision is constrained by geohash spatial indexing:</t>

<texttable title="Precision Mapping for Hierarchical Phrases" anchor="precision-table">
      <ttcol align='left'>Words</ttcol>
      <ttcol align='left'>Geohash Chars</ttcol>
      <ttcol align='left'>Grid Dimensions</ttcol>
      <ttcol align='left'>Avg Size</ttcol>
      <ttcol align='left'>Use Case</ttcol>
      <c>1</c>
      <c>2</c>
      <c>1,252km × 624km</c>
      <c>~900km</c>
      <c>Country/Large Region</c>
      <c>2</c>
      <c>4</c>
      <c>39.1km × 19.5km</c>
      <c>~28km</c>
      <c>City</c>
      <c>3</c>
      <c>6</c>
      <c>1.2km × 609m</c>
      <c>~900m</c>
      <c>Neighborhood</c>
      <c>4</c>
      <c>8</c>
      <c>38.2m × 19m</c>
      <c>~27m</c>
      <c>Building</c>
      <c>5</c>
      <c>10</c>
      <c>1.2m × 59.5cm</c>
      <c>~90cm</c>
      <c>Room/Precise Position</c>
      <c>6</c>
      <c>12</c>
      <c>3.7cm × 1.9cm</c>
      <c>~2.7cm</c>
      <c>Sub-Meter Precision</c>
      <c>7</c>
      <c>14</c>
      <c>1.2mm × 0.6mm</c>
      <c>~0.85mm</c>
      <c>Millimeter Precision</c>
      <c>8</c>
      <c>16</c>
      <c>37μm × 19μm</c>
      <c>~27μm</c>
      <c>Micron-Level Precision</c>
</texttable>

<t><strong>Key Insight:</strong> The 2,048-word BIP-39 vocabulary provides sufficient combinations for encoding geohash data. Each word encodes 2 geohash characters (10 bits) plus 1 parity bit, utilizing the full 11-bit address space.</t>

<t><strong>Extensibility:</strong> The hierarchical encoding pattern can be extended beyond 6 words as measurement devices and positioning technologies improve. The algorithm supports phrases of any length, with each additional word adding approximately 2 geohash characters of precision. Future applications with centimeter or millimeter-accurate positioning systems can use 7, 8, or more words while maintaining full backward compatibility with shorter phrases.</t>

</section>
</section>
</section>
<section anchor="wordlist-specification"><name>Wordlist Specification</name>

<section anchor="bip-39-wordlist-required"><name>BIP-39 Wordlist (REQUIRED)</name>

<t>SayWhere uses the BIP-39 mnemonic wordlist <xref target="BIP39"/> as its standard wordlist. This provides significant advantages:</t>

<t><list style="symbols">
  <t><strong>Size:</strong> Exactly 2,048 words (11 bits) - perfect for encoding 2 geohash characters (10 bits) + 1 parity bit</t>
  <t><strong>Battle-tested:</strong> Used by millions in cryptocurrency wallets since 2013</t>
  <t><strong>Multilingual:</strong> Official wordlists in 9 languages</t>
  <t><strong>Widely distributed:</strong> BIP-39 wordlists are embedded in countless applications and hardware devices worldwide, ensuring availability and consistency</t>
  <t><strong>Open source:</strong> No licensing restrictions</t>
  <t><strong>Existing ecosystem:</strong> Libraries available in all major languages</t>
</list></t>

</section>
<section anchor="requirements"><name>Requirements</name>

<t>A compliant wordlist <bcp14>MUST</bcp14> satisfy these criteria:</t>

<t><list style="numbers" type="1">
  <t><strong>Size:</strong> Exactly 2,048 words (index 0 to 2,047)</t>
  <t><strong>Character Set:</strong> Lowercase ASCII letters [a-z] only</t>
  <t><strong>Length:</strong> Each word 3-8 characters (BIP-39 standard)</t>
  <t><strong>Uniqueness:</strong> No duplicate words</t>
  <t><strong>Ordering:</strong> Stable ordering (indices never change within a version)</t>
  <t><strong>Phonetic Distinctness:</strong> First 4 letters must be unique (BIP-39 property)</t>
  <t><strong>Family-Friendly:</strong> No profanity or offensive terms</t>
</list></t>

</section>
<section anchor="file-format"><name>File Format</name>

<t>Wordlists <bcp14>MUST</bcp14> be stored in JSON format:</t>

<figure><sourcecode type="json"><![CDATA[
{
  "version": "1.0.0",
  "language": "en",
  "description": "BIP-39 English wordlist for SayWhere",
  "created": "2025-10-10",
  "word_count": 2048,
  "source": "https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt",
  "license": "MIT",
  "words": [
    "abandon",
    "ability",
    "able",
    "...",
    "zoo"
  ]
}
]]></sourcecode></figure>

</section>
<section anchor="available-wordlists"><name>Available Wordlists</name>

<t>BIP-39 provides wordlists in the following languages:</t>

<t><list style="symbols">
  <t>English</t>
  <t>Spanish</t>
  <t>French</t>
  <t>Italian</t>
  <t>Japanese</t>
  <t>Korean</t>
  <t>Chinese (Simplified)</t>
  <t>Chinese (Traditional)</t>
  <t>Czech</t>
  <t>Portuguese</t>
</list></t>

</section>
<section anchor="versioning"><name>Versioning</name>

<t>Wordlist versions <bcp14>MUST</bcp14> follow semantic versioning (MAJOR.MINOR.PATCH):</t>

<t><list style="symbols">
  <t><strong>MAJOR:</strong> Incompatible changes (words removed/reordered)</t>
  <t><strong>MINOR:</strong> Backward-compatible additions</t>
  <t><strong>PATCH:</strong> Bug fixes (typo corrections)</t>
</list></t>

<t><strong>Critical:</strong> Encoding and decoding <bcp14>MUST</bcp14> use the same wordlist version.</t>

</section>
</section>
<section anchor="encoding-algorithm"><name>Encoding Algorithm</name>

<section anchor="hierarchical-encoding"><name>Hierarchical Encoding</name>

<section anchor="input-parameters"><name>Input Parameters</name>

<figure><artwork><![CDATA[
latitude:     float  # -90.0 to 90.0 (degrees)
longitude:    float  # -180.0 to 180.0 (degrees)
altitude:     float  # OPTIONAL, in meters (planned)
max_precision: int   # 1-6 words (default: 3)
wordlist:     array  # Array of 2,048 words (BIP-39)
]]></artwork></figure>

</section>
<section anchor="algorithm-steps"><name>Algorithm Steps</name>

<t><strong>Step 1: Validate Input</strong></t>

<figure><artwork><![CDATA[
IF latitude < -90.0 OR latitude > 90.0:
    RAISE ERROR "Invalid latitude"

IF longitude < -180.0 OR longitude > 180.0:
    RAISE ERROR "Invalid longitude"

IF max_precision < 1 OR max_precision > 6:
    RAISE ERROR "max_precision must be 1-6"

IF length(wordlist) != 2048:
    RAISE ERROR "Invalid wordlist size"
]]></artwork></figure>

<t><strong>Step 2: Generate Full Geohash</strong></t>

<figure><artwork><![CDATA[
# Each word encodes 2 geohash characters
geohash_chars = max_precision * 2
geohash = geohash_encode(latitude, longitude, geohash_chars)

# Example: (40.7128, -74.0060, 3 words) → 6 chars → "dr5reg"
]]></artwork></figure>

<t><strong>Step 3: Chunk-Based Word Generation</strong></t>

<figure><artwork><![CDATA[
FUNCTION geohash_to_word_indices_hierarchical(geohash, word_count):
    """
    Convert geohash to word indices using chunk-based encoding.

    KEY PROPERTIES:
    1. Each word encodes 2 geohash characters (10 bits)
    2. BIP-39 wordlist (2048 words = 11 bits) provides 1 extra bit for checksum
    3. Fully reversible: words → geohash is deterministic O(1) operation
    4. Prefix-preserving: shorter phrases are prefixes of longer ones
    """
    base32_alphabet = "0123456789bcdefghjkmnpqrstuvwxyz"
    wordlist_size = 2048  # BIP-39 standard
    word_indices = []

    # Each word encodes a 2-character geohash chunk
    FOR position FROM 0 TO word_count - 1:
        # Extract 2-character chunk at this position
        chunk_start = position * 2
        chunk_end = chunk_start + 2
        chunk = geohash[chunk_start : chunk_end]

        # Convert 2-char chunk to 10-bit value (0-1023)
        char1 = chunk[0]
        char2 = chunk[1]
        char1_index = index_of(char1 in base32_alphabet)  # 0-31 (5 bits)
        char2_index = index_of(char2 in base32_alphabet)  # 0-31 (5 bits)

        chunk_value = (char1_index * 32) + char2_index  # 0-1023 (10 bits)

        # Calculate simple parity checksum (1 bit)
        checksum_bit = popcount(chunk_value) MOD 2  # Count of 1-bits mod 2

        # Combine: (10-bit data << 1) | 1-bit checksum = 11-bit word index
        word_index = (chunk_value << 1) | checksum_bit  # 0-2047

        word_indices.append(word_index)

    RETURN word_indices
END FUNCTION
]]></artwork></figure>

<t><strong>Step 4: Build Hierarchical Phrases</strong></t>

<figure><artwork><![CDATA[
phrases = []

FOR word_count FROM 1 TO max_precision:
    # Geohash prefix for this precision (2 chars per word)
    geohash_prefix = geohash[0 : word_count * 2]

    # Generate word indices for this precision level
    word_indices = geohash_to_word_indices_hierarchical(geohash_prefix, word_count)

    # Map indices to words
    words = [wordlist[idx] for idx in word_indices]

    # Join with dots
    phrase = join(words, ".")
    phrases.append(phrase)

RETURN phrases
]]></artwork></figure>

</section>
<section anchor="example-execution"><name>Example Execution</name>

<t>Input: New York City (40.7128, -74.0060), max_precision = 3</t>

<figure><artwork><![CDATA[
Geohash (6 chars): "dr5reg"

# Word 1: Encodes "dr" (chars 0-1)
chunk_1 = "dr"
char1_index = 12 (d), char2_index = 23 (r)
chunk_value_1 = 12 * 32 + 23 = 407
checksum_1 = popcount(407) % 2 = 6 % 2 = 0
word_index_1 = (407 << 1) | 0 = 814
→ wordlist[814] = "grape"

Phrase 1: "grape"  # ~900km region

# Word 2: Encodes "5r" (chars 2-3)
chunk_2 = "5r"
char1_index = 5 (5), char2_index = 23 (r)
chunk_value_2 = 5 * 32 + 23 = 183
checksum_2 = popcount(183) % 2 = 6 % 2 = 0
word_index_2 = (183 << 1) | 0 = 366
→ wordlist[366] = "column"

Phrase 2: "grape.column"  # ~28km city

# Word 3: Encodes "eg" (chars 4-5)
chunk_3 = "eg"
char1_index = 13 (e), char2_index = 15 (g)
chunk_value_3 = 13 * 32 + 15 = 431
checksum_3 = popcount(431) % 2 = 7 % 2 = 1
word_index_3 = (431 << 1) | 1 = 863
→ wordlist[863] = "hip"

Phrase 3: "grape.column.hip"  # ~900m neighborhood

Output:
[
    "grape",                  # ~900km region
    "grape.column",           # ~28km city
    "grape.column.hip"        # ~900m neighborhood
]
]]></artwork></figure>

<t><strong>Prefix Guarantee:</strong> Each phrase is a proper prefix of all subsequent phrases. This ensures true spatial hierarchy where shorter phrases represent areas that contain all locations with longer matching prefixes.</t>

</section>
</section>
</section>
<section anchor="decoding-algorithm"><name>Decoding Algorithm</name>

<section anchor="hierarchical-decoding-recommended"><name>Hierarchical Decoding (RECOMMENDED)</name>

<section anchor="input-parameters-1"><name>Input Parameters</name>

<figure><artwork><![CDATA[
phrase:   string  # "word1.word2.word3..." (variable length)
wordlist: array   # BIP-39 wordlist (2,048 words)
]]></artwork></figure>

</section>
<section anchor="algorithm-steps-1"><name>Algorithm Steps</name>

<t><strong>Step 1: Parse Phrase</strong></t>

<figure><artwork><![CDATA[
words = split(phrase, ".")
word_count = length(words)

IF word_count < 1 OR word_count > 6:
    RAISE ERROR "Invalid hierarchical phrase length (must be 1-6 words)"

FOR each word IN words:
    IF NOT is_lowercase_alphabetic(word):
        RAISE ERROR "Invalid word format"
    IF length(word) < 3 OR length(word) > 8:
        RAISE ERROR "Word length out of BIP-39 range"
]]></artwork></figure>

<t><strong>Step 2: Decode Each Word with Checksum Validation</strong></t>

<figure><artwork><![CDATA[
FUNCTION decode_word_with_checksum(word, wordlist):
    """
    Decode a single word and validate its built-in checksum.
    Returns the 2-character geohash chunk.
    """
    base32_alphabet = "0123456789bcdefghjkmnpqrstuvwxyz"

    # Find word in wordlist
    word_index = index_of(word in wordlist)
    IF word_index == -1:
        RAISE ERROR "Word not found in wordlist"

    # Extract checksum bit (LSB)
    checksum_bit = word_index AND 1

    # Extract chunk value (10 bits)
    chunk_value = word_index >> 1  # 0-1023

    # Validate checksum
    expected_checksum = popcount(chunk_value) MOD 2
    IF checksum_bit != expected_checksum:
        RAISE ERROR "Checksum validation failed for word: " + word

    # Convert chunk value back to 2 geohash characters
    char1_index = chunk_value / 32  # Integer division
    char2_index = chunk_value MOD 32

    chunk = base32_alphabet[char1_index] + base32_alphabet[char2_index]

    RETURN chunk
END FUNCTION
]]></artwork></figure>

<t><strong>Step 3: Reconstruct Geohash</strong></t>

<figure><artwork><![CDATA[
geohash = ""

FOR each word IN words:
    chunk = decode_word_with_checksum(word, wordlist)
    geohash = geohash + chunk

# Example: ["grape", "column", "hip"] → "dr" + "5r" + "eg" → "dr5reg"
]]></artwork></figure>

<t><strong>Step 4: Decode Geohash to Coordinates</strong></t>

<figure><artwork><![CDATA[
(latitude, longitude, lat_error, lon_error) = geohash_decode(geohash)

# Standard geohash decoding algorithm
# Returns center point and error bounds
]]></artwork></figure>

<t><strong>Step 5: Return Result</strong></t>

<figure><artwork><![CDATA[
RETURN {
    "coordinates": {
        "latitude": latitude,
        "longitude": longitude
    },
    "bounds": {
        "latitude": {"min": latitude - lat_error, "max": latitude + lat_error},
        "longitude": {"min": longitude - lon_error, "max": longitude + lon_error}
    },
    "precision_level": word_count,
    "geohash": geohash
}
]]></artwork></figure>

</section>
</section>
</section>
<section anchor="hierarchical-properties"><name>Hierarchical Properties</name>

<section anchor="prefix-relationships"><name>Prefix Relationships</name>

<t>SayWhere hierarchical phrases exhibit true spatial prefix relationships:</t>

<figure><artwork><![CDATA[
grape                           # Contains all locations starting with "grape.*"
grape.column                    # Contains all locations starting with "grape.column.*"
grape.column.hip                # Contains all locations starting with "grape.column.hip.*"
grape.column.hip.thought        # Contains all locations starting with "grape.column.hip.thought.*"
]]></artwork></figure>

<t><strong>Mathematical Property:</strong> If phrase A is a prefix of phrase B, then the spatial area of A contains the spatial area of B.</t>

</section>
<section anchor="spatial-containment"><name>Spatial Containment</name>

<t><strong>Containment Guarantee:</strong> Any location encoded as "grape.column.hip.thought.pull" will always be contained within the spatial bounds of:</t>

<t><list style="symbols">
  <t>"grape.column.hip.thought" (more precise)</t>
  <t>"grape.column.hip" (less precise)</t>
  <t>"grape.column" (even less precise)</t>
  <t>"grape" (least precise)</t>
</list></t>

</section>
<section anchor="use-cases"><name>Use Cases</name>

<section anchor="progressive-disclosure"><name>Progressive Disclosure</name>

<figure><artwork><![CDATA[
"Meet me in tokyo"                    # City-level
"Meet me in shibuya.tokyo"           # District-level
"Meet me at station.shibuya.tokyo"   # Building-level
]]></artwork></figure>

</section>
<section anchor="search-and-filtering"><name>Search and Filtering</name>

<figure><sourcecode type="sql"><![CDATA[
-- Find all locations in a neighborhood
SELECT * FROM locations WHERE phrase LIKE 'downtown.seattle.%'

-- Find all locations in a city
SELECT * FROM locations WHERE phrase LIKE 'seattle.%'
]]></sourcecode></figure>

</section>
</section>
</section>
<section anchor="checksum-computation"><name>Checksum Computation</name>

<section anchor="design-philosophy"><name>Design Philosophy</name>

<t>SayWhere uses per-word parity checksums for error detection. Each word contains a built-in 1-bit parity checksum in its LSB. This provides error detection while maintaining hierarchical prefix relationships.</t>

</section>
<section anchor="per-word-parity-checksum"><name>Per-Word Parity Checksum</name>

<section anchor="purpose"><name>Purpose</name>

<t>Built-in per-word validation that:</t>

<t><list style="numbers" type="1">
  <t>Detects single-bit errors in each word independently</t>
  <t>Maintains hierarchical prefix relationships</t>
  <t>Requires no additional checksum words</t>
  <t>Works for phrases of any length (1-6 words)</t>
</list></t>

</section>
<section anchor="algorithm"><name>Algorithm</name>

<t>Each word in the BIP-39 wordlist (2,048 words = 11 bits) encodes:</t>

<t><list style="symbols">
  <t><strong>10 bits:</strong> Geohash chunk data (2 base32 characters)</t>
  <t><strong>1 bit:</strong> Parity checksum (LSB)</t>
</list></t>

<figure><artwork><![CDATA[
FUNCTION compute_word_with_parity(chunk_value):
    """
    Encode a 10-bit geohash chunk into an 11-bit word index with parity.

    Args:
        chunk_value: Integer 0-1023 (10 bits of geohash data)

    Returns:
        word_index: Integer 0-2047 (11 bits: 10 data + 1 parity)
    """
    # Calculate even parity bit
    parity_bit = popcount(chunk_value) MOD 2

    # Combine: shift data left 1 bit, OR with parity in LSB
    word_index = (chunk_value << 1) | parity_bit

    RETURN word_index
END FUNCTION

FUNCTION validate_word_parity(word_index):
    """
    Validate the parity checksum of a word.

    Args:
        word_index: Integer 0-2047 from wordlist lookup

    Returns:
        Boolean: True if parity is valid, False otherwise
    """
    # Extract parity bit (LSB)
    stored_parity = word_index AND 1

    # Extract data bits
    chunk_value = word_index >> 1

    # Recalculate expected parity
    expected_parity = popcount(chunk_value) MOD 2

    RETURN stored_parity == expected_parity
END FUNCTION
]]></artwork></figure>

</section>
<section anchor="properties"><name>Properties</name>

<t><list style="symbols">
  <t><strong>Error Detection:</strong> Detects any odd number of bit flips in the 10-bit chunk</t>
  <t><strong>Probability:</strong> 50% chance of detecting even number of bit flips</t>
  <t><strong>No False Positives:</strong> Valid words always pass parity check</t>
  <t><strong>Zero Overhead:</strong> No additional words required</t>
  <t><strong>Prefix Preserving:</strong> Shorter phrases remain valid prefixes</t>
</list></t>

</section>
</section>
<section anchor="optional-terminal-checksum"><name>Optional Terminal Checksum</name>

<section anchor="purpose-1"><name>Purpose</name>

<t>An optional terminal checksum word <bcp14>MAY</bcp14> be appended to any phrase to provide phrase-level error detection for transmission errors. The terminal checksum:</t>

<t><list style="numbers" type="1">
  <t>Uses a distinct 32-word vocabulary (auto-detectable)</t>
  <t>Validates the entire phrase (word substitution, omission, transposition)</t>
  <t>Provides near-uniform distribution for optimal error detection</t>
  <t>Complements per-word LSB parity for two-layer error detection</t>
</list></t>

</section>
<section anchor="checksum-wordlist"><name>Checksum Wordlist</name>

<t>The terminal checksum uses a 32-word vocabulary distinct from the BIP-39 location wordlist:</t>

<figure><artwork><![CDATA[
# Colors (indices 0-15)
red, blue, green, yellow, orange, purple, pink, brown,
black, white, gray, silver, gold, bronze, cyan, magenta

# Animals (indices 16-31)
cat, dog, fox, bear, lion, wolf, eagle, hawk,
deer, fish, frog, snake, owl, crow, seal, whale
]]></artwork></figure>

<t>These words are:
- <strong>Distinct</strong>: Never overlap with BIP-39 location words
- <strong>Memorable</strong>: Colors and animals are universally understood
- <strong>Phonetically clear</strong>: Easy to communicate verbally over radio/phone</t>

</section>
<section anchor="crc-8-algorithm"><name>CRC-8 Algorithm</name>

<t>For systems with computational capability (phones, computers, calculators), use CRC-8 for optimal error detection:</t>

<figure><artwork><![CDATA[
FUNCTION compute_terminal_checksum_crc8(location_words, wordlist):
    """
    Compute CRC-8 based terminal checksum.
    Provides uniform distribution across all 32 checksum words.

    Uses CRC-8-CCITT: polynomial 0x07, initial value 0xFF.
    Computes CRC over 11-bit word indices for optimal uniformity.
    """
    # Step 1: Get word indices from wordlist
    indices = []
    FOR word IN location_words:
        index = FIND_INDEX(word IN wordlist)  # 0-2047 (11 bits)
        indices.APPEND(index)
    END FOR

    # Step 2: Pack 11-bit indices into byte array
    num_bits = LENGTH(indices) * 11
    num_bytes = CEILING(num_bits / 8)
    bytes = ALLOCATE_BYTES(num_bytes)

    bit_position = 0
    FOR index IN indices:
        # Write 11 bits of index into byte array
        FOR bit FROM 0 TO 10:
            bit_value = (index >> (10 - bit)) AND 1
            byte_index = bit_position / 8  # Integer division
            bit_in_byte = bit_position MOD 8
            bytes[byte_index] |= (bit_value << (7 - bit_in_byte))
            bit_position = bit_position + 1
        END FOR
    END FOR

    # Step 3: Compute CRC-8 using lookup table
    crc = 0xFF  # Initial value
    FOR byte IN bytes:
        index = crc XOR byte
        crc = CRC8_TABLE[index]
    END FOR

    # Step 4: Map to checksum word
    checksum_index = crc MOD 32

    RETURN CHECKSUM_32[checksum_index]
END FUNCTION
]]></artwork></figure>

<t>The CRC-8 lookup table (256 bytes) is provided in the reference implementation.</t>

<t><strong>Properties:</strong>
- <strong>Distribution:</strong> Chi-square = 18.85 (essentially perfect uniform distribution)
- <strong>Error Detection:</strong> 96.9% (theoretical maximum)
- <strong>Computation:</strong> Fast with lookup table (~10 operations per byte)
- <strong>Implementation:</strong> Available in all programming languages</t>

<t><strong>Key Insight:</strong> Computing CRC over word indices rather than strings eliminates structural biases from dots and letter frequencies, achieving near-perfect uniformity (chi-square of 18.85 vs target of 44.3 for uniform distribution).</t>

</section>
<section anchor="examples"><name>Examples</name>

<t><strong>Example 1: New York City</strong>
~~~~
Location: "grape.column.hip"</t>

<t>CRC-8 Calculation:
  Word indices: [814, 366, 863]
  Packed bytes: [0xCC, 0xDB, 0x6F]
  CRC-8 (polynomial 0x07, init 0xFF): 0x1E
  Checksum index: 0x1E % 32 = 30
  Checksum: CHECKSUM_32[30] = "seal"</t>

<t>Result: "grape.column.hip.seal"
~~~~</t>

<t><strong>Example 2: London</strong>
~~~~
Location: "kit.puzzle"</t>

<t>CRC-8 Calculation:
  Word indices: [1004, 1434]
  Packed bytes: [0xFA, 0xD5, 0x00]
  CRC-8 (polynomial 0x07, init 0xFF): 0xA4
  Checksum index: 0xA4 % 32 = 4
  Checksum: CHECKSUM_32[4] = "orange"</t>

<t>Result: "kit.puzzle.orange"
~~~~</t>

</section>
<section anchor="encoding-with-terminal-checksum"><name>Encoding with Terminal Checksum</name>

<t>To create a validated phrase:</t>

<figure><artwork><![CDATA[
FUNCTION encode_with_checksum(latitude, longitude, num_words):
    # Standard hierarchical encoding
    location_words = encode_location(latitude, longitude, num_words)

    # Compute terminal checksum
    checksum_word = compute_terminal_checksum(location_words)

    # Append checksum
    RETURN location_words + [checksum_word]
END FUNCTION
]]></artwork></figure>

</section>
<section anchor="decoding-with-checksum-detection"><name>Decoding with Checksum Detection</name>

<t>Decoders <bcp14>MUST</bcp14> automatically detect and validate terminal checksums:</t>

<figure><artwork><![CDATA[
FUNCTION decode_with_checksum_detection(phrase):
    words = SPLIT(phrase, ".")

    IF LENGTH(words) < 2:
        # No checksum possible
        RETURN decode_location(words), checksum_valid=FALSE
    END IF

    last_word = words[LENGTH(words) - 1]

    # Check if last word is from checksum vocabulary
    IF last_word IN CHECKSUM_32:
        # Treat as checksum
        location_words = words[0 : LENGTH(words) - 1]
        provided_checksum = last_word

        # Compute expected checksum
        expected_checksum = compute_terminal_checksum(location_words)

        # Validate
        IF provided_checksum == expected_checksum:
            coordinates = decode_location(location_words)
            RETURN coordinates, checksum_valid=TRUE
        ELSE:
            RAISE ERROR "Terminal checksum validation failed"
        END IF
    ELSE:
        # All words are location words
        coordinates = decode_location(words)
        RETURN coordinates, checksum_valid=FALSE
    END IF
END FUNCTION
]]></artwork></figure>

</section>
<section anchor="error-detection-capabilities"><name>Error Detection Capabilities</name>

<t>The terminal checksum detects:</t>

<t><list style="symbols">
  <t><strong>Word substitution</strong>: "grape" misheard as "grace"</t>
  <t><strong>Word omission</strong>: "grape.column.hip" → "grape.hip"</t>
  <t><strong>Word transposition</strong>: "grape.column" → "column.grape"</t>
  <t><strong>Word addition</strong>: Unintended extra words</t>
</list></t>

<t><strong>Detection Rate</strong>: 5-bit checksum provides ~97% detection of transmission errors (1/32 false negative rate).</t>

</section>
<section anchor="two-layer-error-detection"><name>Two-Layer Error Detection</name>

<t>Terminal checksum and per-word LSB parity work together:</t>

<texttable>
      <ttcol align='left'>Layer</ttcol>
      <ttcol align='left'>Scope</ttcol>
      <ttcol align='left'>Detects</ttcol>
      <ttcol align='left'>When Checked</ttcol>
      <c>LSB Parity</c>
      <c>Per-word</c>
      <c>Bit corruption in individual words</c>
      <c>During word decode</c>
      <c>Terminal Checksum</c>
      <c>Whole phrase</c>
      <c>Wrong word, order, omissions</c>
      <c>After all words decoded</c>
</texttable>

<t><strong>Example: Error caught by terminal checksum</strong>
~~~~
Sent: "grape.column.hip.seal"
Received: "grape.color.hip.seal" (column → color)</t>

</section>
</section>
</section>
<section anchor="lsb-parity-passes-both-valid-bip-39-words"><name>LSB parity passes (both valid BIP-39 words)</name>
<t># Terminal checksum fails:
expected = compute_terminal_checksum(["grape", "color", "hip"]) → "whale"
received = "seal"
# Error detected! ✗
~~~~</t>

<section anchor="field-verification-backup"><name>Field Verification (BACKUP)</name>

<t>The following simplified checksum <bcp14>MAY</bcp14> be calculated and verified in emergency situations using printed reference cards:</t>

<figure><artwork><![CDATA[
┌──────────────────────────────────────┐
│   SAYWHERE CHECKSUM CALCULATOR       │
├──────────────────────────────────────┤
│ STEP 1: First Letter Values          │
│ a=1  b=2  c=3  d=4  e=5  f=6  g=7   │
│ h=8  i=9  j=10 k=11 l=12 m=13 n=14  │
│ o=15 p=16 q=17 r=18 s=19 t=20 u=21  │
│ v=22 w=23 x=24 y=25 z=26             │
│                                      │
│ STEP 2: Count letters in each word   │
│ STEP 3: Count number of words        │
│ STEP 4: Add all three sums           │
│ STEP 5: Divide by 32, use remainder  │
│                                      │
│ CHECKSUM LOOKUP TABLE:               │
│ 0=red    8=black   16=cat   24=deer │
│ 1=blue   9=white   17=dog   25=fish │
│ 2=green  10=gray   18=fox   26=frog │
│ 3=yellow 11=silver 19=bear  27=snake│
│ 4=orange 12=gold   20=lion  28=owl  │
│ 5=purple 13=bronze 21=wolf  29=crow │
│ 6=pink   14=cyan   22=eagle 30=seal │
│ 7=brown  15=magenta 23=hawk 31=whale│
└──────────────────────────────────────┘
]]></artwork></figure>

<section anchor="use-cases-1"><name>Use Cases</name>

<t><strong>Emergency Response</strong>
~~~~
Hiker (over radio): "My location is grape column hip seal"
Dispatcher: <em>validates checksum</em>
System: ✓ Checksum valid - location confirmed
Dispatcher: "Coordinates confirmed, dispatching rescue team"
~~~~</t>

<t><strong>Error Detection</strong>
~~~~
Sent: "grape.column.hip.seal"
Received: "grape.hip.seal" (word dropped)</t>

<t>System calculates:
  Expected: compute_terminal_checksum(["grape", "hip"]) → "yellow"
  Received: "seal"
  ✗ Mismatch - transmission error detected</t>

<t>Response: "Please repeat location, checksum error detected"
~~~~</t>

</section>
</section>
</section>
<section anchor="altitude-support"><name>Altitude Support</name>

<section anchor="design-philosophy-1"><name>Design Philosophy</name>

<t>SayWhere altitude components are expressed as unitless integers representing quantized steps. The step size is a configuration parameter, not part of the phrase itself.</t>

<t><strong>Rationale:</strong> Unitless values maintain:</t>

<t><list style="symbols">
  <t><strong>Phrase brevity:</strong> ".20" vs ".60m" or ".20meters"</t>
  <t><strong>Simplicity:</strong> Consistent with horizontal coordinate abstraction</t>
  <t><strong>Flexibility:</strong> Applications can choose appropriate step sizes without breaking compatibility</t>
  <t><strong>Voice-friendly:</strong> Easier to communicate "twenty" than "twenty meters"</t>
</list></t>

</section>
<section anchor="quantization"><name>Quantization</name>

<t>Altitude <bcp14>MUST</bcp14> be quantized to fixed-step increments:</t>

<figure><artwork><![CDATA[
altitude_step = 3.0  # meters (configuration parameter, not in phrase)
altitude_units = ROUND(altitude_meters / altitude_step)
]]></artwork></figure>

<t>Standard step configurations:</t>

<texttable title="Altitude Step Configurations" anchor="altitude-steps">
      <ttcol align='left'>Use Case</ttcol>
      <ttcol align='left'>Step Size</ttcol>
      <ttcol align='left'>Example Input</ttcol>
      <ttcol align='left'>Encoded Units</ttcol>
      <ttcol align='left'>Notes</ttcol>
      <c>Buildings</c>
      <c>3.0m</c>
      <c>60.0m</c>
      <c>.20</c>
      <c>Typical floor height</c>
      <c>Drones</c>
      <c>1.0m</c>
      <c>60.0m</c>
      <c>.60</c>
      <c>Precise vertical control</c>
      <c>Aircraft</c>
      <c>100.0m</c>
      <c>6000.0m</c>
      <c>.60</c>
      <c>Flight levels (FL060)</c>
      <c>Mining/Caves</c>
      <c>5.0m</c>
      <c>-50.0m</c>
      <c>.-10</c>
      <c>Underground operations</c>
</texttable>

</section>
<section anchor="range-limits"><name>Range Limits</name>

<figure><artwork><![CDATA[
MIN_ALTITUDE_UNITS = -1000  # Lowest representable value
MAX_ALTITUDE_UNITS = 10000  # Highest representable value
]]></artwork></figure>

</section>
</section>
<section anchor="urn-format"><name>URN Format</name>

<section anchor="specification"><name>Specification</name>

<t>SayWhere defines a canonical URN format (<xref target="RFC8141"/> compliant):</t>

<figure><artwork><![CDATA[
urn:saywhere:{language}:{word1}.{word2}.{word3}.{wordN}.{checksum}[:{altitude}]
]]></artwork></figure>

</section>
<section anchor="components"><name>Components</name>

<t><list style="symbols">
  <t><spanx style="verb">urn:saywhere</spanx> - Namespace identifier (fixed)</t>
  <t><spanx style="verb">{language}</spanx> - ISO 639-1 language code (2 lowercase letters)</t>
  <t><spanx style="verb">{word1}.{word2}.{word3}.{checksum}</spanx> - Word phrase</t>
  <t><spanx style="verb">{altitude}</spanx> - <bcp14>OPTIONAL</bcp14> signed integer altitude units (unitless)</t>
</list></t>

<t>The terminal checksum is <bcp14>MUST</bcp14> be from a distinct wordlist to the location words to enable the parser to determine if the final word in the word phrase is a location word or the terminal checksum.</t>

</section>
<section anchor="examples-1"><name>Examples</name>

<figure><artwork><![CDATA[
# Without terminal checksum
urn:saywhere:en:grape.column.hip

# With terminal checksum
urn:saywhere:en:grape.column.hip.seal

# With altitude: 20 units (= 60m with 3.0m steps)
urn:saywhere:en:grape.column.hip.seal:20

# Underground: -5 units (= -15m with 3.0m steps)
urn:saywhere:en:grape.column.hip.seal:-5

# Spanish wordlist with checksum
urn:saywhere:es:manzana.montana.atardecer.rojo

# French wordlist with checksum and altitude
urn:saywhere:fr:pomme.montagne.coucher.rouge:15
]]></artwork></figure>

</section>
<section anchor="parsing-grammar-abnf"><name>Parsing Grammar (ABNF)</name>

<figure><sourcecode type="abnf"><![CDATA[
saywhere-urn = "urn:saywhere:" language ":" words [":" altitude]
language     = 2ALPHA
words        = word "." word "." word "." word
word         = 3*15ALPHA
altitude     = ["-"] 1*4DIGIT  ; Unitless integer

ALPHA        = %x61-7A  ; lowercase a-z
DIGIT        = %x30-39  ; 0-9
]]></sourcecode></figure>

</section>
</section>
<section anchor="security-considerations"><name>Security Considerations</name>

<t>This section follows the guidelines in <xref target="RFC3552"/> for security considerations in protocol specifications.</t>

<section anchor="location-privacy"><name>Location Privacy</name>

<t>SayWhere phrases encode precise geographic locations and can reveal sensitive information about individuals' whereabouts. Privacy considerations include:</t>

<t><list style="symbols">
  <t><strong>Data Minimization</strong>: Implementations <bcp14>SHOULD NOT</bcp14> log or store phrases without explicit user consent</t>
  <t><strong>User Awareness</strong>: Users <bcp14>SHOULD</bcp14> be warned that phrases reveal precise physical locations that persist over time</t>
  <t><strong>Sharing Controls</strong>: Applications <bcp14>SHOULD</bcp14> implement access controls before transmitting or displaying location phrases</t>
  <t><strong>Hierarchical Disclosure</strong>: Applications can leverage hierarchical phrases to enable progressive disclosure, sharing only the precision level necessary for the use case</t>
  <t><strong>Pervasive Monitoring</strong>: Per <xref target="RFC7258"/>, implementations should consider that location data transmission may be subject to pervasive monitoring attacks</t>
</list></t>

<t>Location phrases shared in public forums, radio communications, or other non-confidential channels should be considered public information accessible to any party.</t>

</section>
<section anchor="checksum-limitations"><name>Checksum Limitations</name>

<t>SayWhere provides two layers of error detection (per-word LSB parity and optional terminal checksum), but neither provides security:</t>

<t><list style="symbols">
  <t><strong>No Authentication</strong>: Checksums do NOT provide cryptographic authentication or integrity protection</t>
  <t><strong>Accidental Errors Only</strong>: Checksums ONLY detect accidental transmission/transcription errors, not deliberate tampering</t>
  <t><strong>Not Security Critical</strong>: Do not rely on checksums for security-critical applications requiring authenticated location data</t>
  <t><strong>Malicious Modification</strong>: An attacker can easily generate valid phrases with correct checksums for arbitrary locations</t>
  <t><strong>Limited Entropy</strong>: Terminal checksum uses only 5 bits (32 values), providing ~3% false negative rate</t>
</list></t>

<t>The terminal checksum is designed for <strong>error detection</strong> (communication integrity), not <strong>security</strong> (adversarial protection).</t>

<t>Applications requiring authenticated location assertions should implement additional cryptographic signatures or message authentication codes.</t>

</section>
<section anchor="wordlist-integrity"><name>Wordlist Integrity</name>

<t>Implementations depend on wordlist consistency for correct operation:</t>

<t><list style="symbols">
  <t><strong>Verification Required</strong>: Implementations <bcp14>MUST</bcp14> verify wordlist integrity using cryptographic checksums (SHA-256 or better recommended)</t>
  <t><strong>Corruption Impact</strong>: Corrupted or modified wordlists produce incorrect encodings that may place users in unintended or dangerous locations</t>
  <t><strong>Supply Chain Security</strong>: Consider signing wordlist files for distribution and verifying signatures before use</t>
  <t><strong>Version Control</strong>: Implementations should verify the wordlist version matches the expected version for the encoding/decoding operation</t>
</list></t>

<t>A compromised wordlist could enable man-in-the-middle attacks where locations are systematically mistranslated.</t>

</section>
<section anchor="denial-of-service"><name>Denial of Service</name>

<t>Implementations should protect against resource exhaustion:</t>

<t><list style="symbols">
  <t><strong>Rate Limiting</strong>: Implementations <bcp14>SHOULD</bcp14> rate-limit encoding/decoding operations, particularly in network-facing services</t>
  <t><strong>Batch Size Limits</strong>: Batch operations <bcp14>SHOULD</bcp14> enforce maximum size limits to prevent memory exhaustion</t>
  <t><strong>Early Validation</strong>: Invalid input <bcp14>SHOULD</bcp14> be rejected early in processing to avoid expensive computation</t>
</list></t>

</section>
</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>

<t>This section follows the guidelines in <xref target="RFC8126"/> for IANA considerations sections.</t>

<t>This document requests the registration of the "saywhere" URN namespace in the "Uniform Resource Names (URN) Namespaces" registry, in accordance with the procedures defined in <xref target="RFC8141"/>.</t>

<section anchor="urn-namespace-registration"><name>URN Namespace Registration</name>

<t>Per <xref target="RFC8141"/> Section 6, the following registration template is provided:</t>

<dl>
  <dt>Namespace ID:</dt>
  <dd>
    <t>saywhere</t>
  </dd>
  <dt>Registration Information:</dt>
  <dd>
    <t>Version 1, 2025-10-12</t>
  </dd>
  <dt>Declared registrant:</dt>
  <dd>
    <t>SayWhere Contributors</t>
  </dd>
  <dt/>
  <dd>
    <t>Anuna Research Pty Ltd</t>
  </dd>
  <dt/>
  <dd>
    <t>Email: contact@saywhere.org</t>
  </dd>
  <dt/>
  <dd>
    <t>URI: https://codeberg.org/anuna/saywhere</t>
  </dd>
  <dt>Declaration of syntactic structure:</dt>
  <dd>
    <t>See Section 9 of this document</t>
  </dd>
  <dt>Relevant ancillary documentation:</dt>
  <dd>
    <t>This document serves as the specification for the saywhere URN namespace</t>
  </dd>
  <dt>Identifier uniqueness considerations:</dt>
  <dd>
    <t>Uniqueness is guaranteed by the deterministic encoding algorithm specified in this document. Each unique geographic coordinate (latitude, longitude, altitude) and wordlist language combination produces a unique URN.</t>
  </dd>
  <dt>Identifier persistence considerations:</dt>
  <dd>
    <t>SayWhere URNs remain valid and decodable as long as the corresponding wordlist version is available. Wordlists follow semantic versioning and are maintained in public repositories for long-term availability.</t>
  </dd>
  <dt>Process of identifier assignment:</dt>
  <dd>
    <t>SayWhere URNs are not centrally assigned. Any party can generate a valid SayWhere URN by applying the deterministic encoding algorithm specified in this document to geographic coordinates.</t>
  </dd>
  <dt>Process for identifier resolution:</dt>
  <dd>
    <t>SayWhere URNs are decoded to geographic coordinates using the deterministic decoding algorithm specified in Section 7 of this document. Resolution requires access to the appropriate wordlist version.</t>
  </dd>
  <dt>Rules for Lexical Equivalence:</dt>
  <dd>
    <t>Two SayWhere URNs are lexically equivalent if and only if they are identical after Unicode normalization (NFC) and case normalization (lowercase). The comparison is case-insensitive and performed on Unicode-normalized strings.</t>
  </dd>
  <dt>Conformance with URN Syntax:</dt>
  <dd>
    <t>SayWhere URNs conform to the URN syntax specified in <xref target="RFC8141"/>. The syntax is formally defined using ABNF in Section 9 of this document.</t>
  </dd>
  <dt>Validation mechanism:</dt>
  <dd>
    <t>Validation consists of: (1) syntax validation per the ABNF grammar, (2) verification that each location word exists in the specified language wordlist, (3) validation of per-word LSB parity checksums, and (4) if present, validation of the terminal checksum word as specified in Section 10.</t>
  </dd>
  <dt>Scope:</dt>
  <dd>
    <t>Global</t>
  </dd>
</dl>

</section>
</section>
<section anchor="implementation-guidance"><name>Implementation Guidance</name>

<section anchor="performance-optimization"><name>Performance Optimization</name>

<t><strong>In-Memory Wordlist:</strong></t>

<figure><artwork><![CDATA[
# Load wordlist(s) once at startup
wordlist = load_wordlist("saywhere-en-v1.0.0.json")

# Create bidirectional lookup dictionaries
word_to_index = {}
index_to_word = {}

FOR index, word IN wordlist:
    word_to_index[word] = index
    index_to_word[index] = word

# Use for O(1) lookups during encoding/decoding
]]></artwork></figure>

</section>
<section anchor="testing-requirements"><name>Testing Requirements</name>

<t>Implementations <bcp14>MUST</bcp14> pass:</t>

<t><list style="numbers" type="1">
  <t>All test vectors in <xref target="appendix-test-vectors"/></t>
  <t>Roundtrip tests (encode → decode → verify coordinates match)</t>
  <t>Per-word LSB parity validation tests</t>
  <t>Terminal checksum validation tests (detection and validation)</t>
  <t>Error handling tests (both parity and checksum errors)</t>
  <t>Boundary condition tests (poles, dateline, altitude extremes)</t>
  <t>Altitude quantization tests (different step sizes)</t>
  <t>Checksum error detection tests (substitution, omission, transposition)</t>
</list></t>

</section>
<section anchor="reference-implementation"><name>Reference Implementation</name>

<t>A reference implementation in Scheme (Guile) is available for testing and validation purposes. This implementation is provided as an example and is not required for conformance:</t>

<t><list style="symbols">
  <t>Repository: <eref target="https://codeberg.org/anuna/saywhere">https://codeberg.org/anuna/saywhere</eref></t>
  <t>License: GNU GPL v3</t>
</list></t>

<t>Implementations in other languages that pass the test vectors in <xref target="appendix-test-vectors"/> are considered conformant.</t>

</section>
<section anchor="web-application-demo"><name>Web Application Demo</name>

<t>An interactive web application is available for exploring SayWhere encoding and decoding:</t>

<t><list style="symbols">
  <t>Demo: <eref target="https://saywhere.org/grape/column/hip">https://saywhere.org/grape/column/hip</eref></t>
</list></t>

<t>The demo allows users to:</t>

<t><list style="symbols">
  <t>Visualize hierarchical phrase resolution on an interactive map</t>
  <t>Encode coordinates to word phrases</t>
  <t>Decode word phrases to geographic locations</t>
  <t>Explore the spatial containment relationships between different precision levels</t>
  <t>Test error detection capabilities</t>
</list></t>

</section>
</section>


  </middle>

  <back>


<references title='References' anchor="sec-combined-references">

    <references title='Normative References' anchor="sec-normative-references">



<reference anchor="RFC8141">
  <front>
    <title>Uniform Resource Names (URNs)</title>
    <author fullname="P. Saint-Andre" initials="P." surname="Saint-Andre"/>
    <author fullname="J. Klensin" initials="J." surname="Klensin"/>
    <date month="April" year="2017"/>
    <abstract>
      <t>A Uniform Resource Name (URN) is a Uniform Resource Identifier (URI) that is assigned under the "urn" URI scheme and a particular URN namespace, with the intent that the URN will be a persistent, location-independent resource identifier. With regard to URN syntax, this document defines the canonical syntax for URNs (in a way that is consistent with URI syntax), specifies methods for determining URN-equivalence, and discusses URI conformance. With regard to URN namespaces, this document specifies a method for defining a URN namespace and associating it with a namespace identifier, and it describes procedures for registering namespace identifiers with the Internet Assigned Numbers Authority (IANA). This document obsoletes both RFCs 2141 and 3406.</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="8141"/>
  <seriesInfo name="DOI" value="10.17487/RFC8141"/>
</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 title='Informative References' anchor="sec-informative-references">

<reference anchor="RFC3552" target="https://www.rfc-editor.org/info/rfc3552">
  <front>
    <title>Guidelines for Writing RFC Text on Security Considerations</title>
    <author initials="E." surname="Rescorla" fullname="E. Rescorla">
      <organization></organization>
    </author>
    <author initials="B." surname="Korver" fullname="B. Korver">
      <organization></organization>
    </author>
    <date year="2003" month="July"/>
  </front>
  <seriesInfo name="RFC" value="3552"/>
  <seriesInfo name="BCP" value="72"/>
</reference>
<reference anchor="RFC7258" target="https://www.rfc-editor.org/info/rfc7258">
  <front>
    <title>Pervasive Monitoring Is an Attack</title>
    <author initials="S." surname="Farrell" fullname="S. Farrell">
      <organization></organization>
    </author>
    <author initials="H." surname="Tschofenig" fullname="H. Tschofenig">
      <organization></organization>
    </author>
    <date year="2014" month="May"/>
  </front>
  <seriesInfo name="RFC" value="7258"/>
  <seriesInfo name="BCP" value="188"/>
</reference>
<reference anchor="RFC8126" target="https://www.rfc-editor.org/info/rfc8126">
  <front>
    <title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
    <author initials="M." surname="Cotton" fullname="M. Cotton">
      <organization></organization>
    </author>
    <author initials="B." surname="Leiba" fullname="B. Leiba">
      <organization></organization>
    </author>
    <author initials="T." surname="Narten" fullname="T. Narten">
      <organization></organization>
    </author>
    <date year="2017" month="June"/>
  </front>
  <seriesInfo name="RFC" value="8126"/>
  <seriesInfo name="BCP" value="26"/>
</reference>
<reference anchor="BIP39" target="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki">
  <front>
    <title>BIP 0039: Mnemonic code for generating deterministic keys</title>
    <author initials="M." surname="Palatinus" fullname="Marek Palatinus">
      <organization></organization>
    </author>
    <author initials="P." surname="Rusnak" fullname="Pavol Rusnak">
      <organization></organization>
    </author>
    <author initials="A." surname="Voisine" fullname="Aaron Voisine">
      <organization></organization>
    </author>
    <author initials="S." surname="Bowe" fullname="Sean Bowe">
      <organization></organization>
    </author>
    <date year="2013" month="September"/>
  </front>
</reference>
<reference anchor="GEOHASH" target="https://en.wikipedia.org/wiki/Geohash">
  <front>
    <title>Geohash</title>
    <author initials="G." surname="Niemeyer" fullname="Gustavo Niemeyer">
      <organization></organization>
    </author>
    <date year="2008"/>
  </front>
</reference>


    </references>

</references>


<?line 1227?>

<section anchor="geohash-algorithm-details"><name>Geohash Algorithm Details</name>

<section anchor="encoding-pseudocode"><name>Encoding Pseudocode</name>

<figure><artwork><![CDATA[
FUNCTION geohash_encode(latitude, longitude, precision):
    lat_min = -90.0
    lat_max = 90.0
    lon_min = -180.0
    lon_max = 180.0

    bits = []
    is_longitude = true

    # Generate precision * 5 bits (base32 = 5 bits per char)
    WHILE length(bits) < (precision * 5):
        IF is_longitude:
            mid = (lon_min + lon_max) / 2
            IF longitude > mid:
                bits.append(1)
                lon_min = mid
            ELSE:
                bits.append(0)
                lon_max = mid
        ELSE:
            mid = (lat_min + lat_max) / 2
            IF latitude > mid:
                bits.append(1)
                lat_min = mid
            ELSE:
                bits.append(0)
                lat_max = mid

        is_longitude = NOT is_longitude

    # Convert bits to base32 string
    base32_chars = "0123456789bcdefghjkmnpqrstuvwxyz"
    geohash = ""

    FOR i = 0 TO length(bits) STEP 5:
        chunk = bits[i:i+5]
        value = binary_to_decimal(chunk)
        geohash += base32_chars[value]

    RETURN geohash
END FUNCTION
]]></artwork></figure>

</section>
</section>
<section anchor="appendix-test-vectors"><name>Test Vectors</name>

<section anchor="hierarchical-encoding-test-cases"><name>Hierarchical Encoding Test Cases</name>

<section anchor="test-case-1-new-york-city"><name>Test Case 1: New York City</name>

<figure><artwork><![CDATA[
Input:
  latitude: 40.7128
  longitude: -74.0060
  max_precision: 3
  wordlist_version: "1.0.0"

Expected Output (Hierarchical):
  geohash: "dr5reg"
  phrases: [
    "grape",
    "grape.column",
    "grape.column.hip"
  ]

Verification:
  - Each phrase is a prefix of the next phrase ✓
  - Decoding "grape.column" returns coordinates within NYC metro area ✓
  - Decoding "grape.column.hip" returns precise location ✓
]]></artwork></figure>

</section>
<section anchor="test-case-2-london"><name>Test Case 2: London</name>

<figure><artwork><![CDATA[
Input:
  latitude: 51.5074
  longitude: -0.1278
  max_precision: 4
  wordlist_version: "1.0.0"

Expected Output:
  geohash: "gcpvj0du"
  phrases: [
    "kit",
    "kit.puzzle",
    "kit.puzzle.marine",
    "kit.puzzle.marine.grit"
  ]

Prefix Tests:
  - "kit" contains all locations starting with "kit.*" ✓
  - "kit.puzzle" ⊂ "kit" ✓
  - "kit.puzzle.marine" ⊂ "kit.puzzle" ✓
]]></artwork></figure>

</section>
<section anchor="test-case-3-equator-crossing"><name>Test Case 3: Equator Crossing</name>

<figure><artwork><![CDATA[
Input:
  latitude: 0.0
  longitude: 0.0
  max_precision: 3
  wordlist_version: "1.0.0"

Expected Output:
  geohash: "7zzzzz"
  phrases: [
    "divert",
    "divert.zone",
    "divert.zone.zone"
  ]

Note: Tests edge case at equator and prime meridian
]]></artwork></figure>

</section>
<section anchor="test-case-4-with-terminal-checksum"><name>Test Case 4: With Terminal Checksum</name>

<figure><artwork><![CDATA[
Input:
  latitude: 40.7128
  longitude: -74.0060
  num_words: 3
  include_checksum: true

Expected Output:
  location_phrase: "grape.column.hip"

  Checksum calculation:
    Word indices: [814, 366, 863]
    Packed bytes: [0xCC, 0xDB, 0x6F]
    CRC-8 (polynomial 0x07, init 0xFF): 0x1E
    Checksum index: 0x1E % 32 = 30
    Checksum: "seal"

  Full phrase: "grape.column.hip.seal"

Validation:
  - Decoding detects "seal" is from checksum vocabulary ✓
  - Computes checksum for ["grape", "column", "hip"] → "seal" ✓
  - Checksum validates, returns coordinates with checksum_valid=true ✓

Error Detection Test:
  Corrupted: "grape.color.hip.seal" (column→color)
  Expected checksum for ["grape", "color", "hip"] → "whale" ≠ "seal"
  Validation fails, error detected ✓
]]></artwork></figure>

</section>
</section>
</section>
<section numbered="false" anchor="acknowledgments"><name>Acknowledgments</name>

<t>The SayWhere system uses the geohash algorithm created by Gustavo Niemeyer and the BIP-39 wordlist developed by the Bitcoin community. The altitude component was taken from the Geowords implementation by mfrank. We thank these contributors for their foundational work.</t>

<t>Special thanks to the open-source community for feedback and testing of the SayWhere implementation.</t>

</section>


  </back>

<!-- ##markdown-source:
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
GOR/1RQtPv2/maJFRTTnEnkU0creV2GSedvz2JIF/0obOTVWidoh2Crp5s1N
ll94WWAxeTyesCCHtCRIAVNATH34wp3DNHnw6e3bqB99velO3Zo8MbB+pEuI
dUSCkVBIkvk58Nic8oPCDN5yA8U8+SbL97rjmUKhvtcM6eOT9dzo4atupb6X
j9j+XskgYe5y5Zu0KsqiWV/pa7Qqym2vvr1Si56WbqftVbzLGrUWba+5rlRM
YLySO4FUzR84EwUNEO8CLntJmL04WgfOez/sBUGrz+TwKG6MrvieLvTVXHfN
j8mjDU4Tk6RnXv/6l3/iKvZMfunUaWoS6XtcT2ewPv5xF2HMaSIpth9vSQ6/
mtZMNIrVL1HZnepwK2qzXDy8lJud1mZ7e6O0lO1Wp7u9s7qSG79pJYtLNxnN
b39qjxfrFu99lJtl8rJvrDxpzRBr8vCLFpyOel11gkcAI5N15V68FMuPJWJH
00+rdlX8Ualf//M/6rbWvDZDtKVctQcWCReEkZpA+5Z01YR9Lg8vl/Bxb6nk
wV+14YrLtP0Bf+sWaYy0eXad5FfrQ+LWw3skz2UlEObel4VQ4XgisT/Q7EM9
bbY7pRHpHTPajGNcpb4OUBt9iQhdk5nk9xIqmw9EYKYD01wSAi39rAGYzTlg
rrlal13HS98yKmaQ+XySnS9Ks/ObEu18QaodP5+MSa2j5OrpB+epj0d5RrZ+
kZKN9QFzafCx9Bl2Q9n0fe6UM+HJ565ekfZtGyWzAfT2h+hxOVMC336Bhirl
XAhAR8zPRiB87rQ3jUyf9XZHwB6blnco2z+TrX79T//qznx9X0w6QTMrntby
iY0ajt7Hyd2Utp5YhT725aRqOB5UOd4GhyKg/FmVUhzzErjDLlstuzhbu+QB
Yp/UqwXRzttEHUekWCO1ALbzuqToYyhZydx5sl5E+Qh3g+ognXwpNt/V82Lq
Dh6e4D1pbza7KqleEjtcMjZQ27PrNIjft0jl5hNK71E+k0skjJPSeOuiVK64
0ue/OF0CrJ6whyIyDNWtV4DGHje1n9iOmVu6DsMx39XEc9c2Ei0vWKiWU7n9
X6S4lVFGtQAA

-->

</rfc>

