<?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.4.7) -->


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

]>


<rfc ipr="trust200902" docName="draft-saywhere-geocoding-01" 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>
        <postal>
          <country>Australia</country>
        </postal>
        <email>hugo@anuna.io</email>
        <uri>https://codeberg.org/anuna/saywhere</uri>
      </address>
    </author>

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

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

    <abstract>


<?line 93?>

<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 97?>

<section anchor="introduction"><name>Introduction</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>

<t>The design goals for SayWhere are:</t>

<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>

<t>Compared to existing systems:</t>

<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>

<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 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>

<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>

<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>

<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>

<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 anchor="intellectual-property-considerations"><name>Intellectual Property Considerations</name>

<t>The authors are aware that proprietary word-based geocoding systems exist, including systems covered by patents held by What3Words Limited (e.g., CA2909524A1, GB2540897B, and related patents in multiple jurisdictions). These patents claim specific technical approaches to converting geographic coordinates into word phrases.</t>

<t>SayWhere uses fundamentally different technical mechanisms that distinguish it from these proprietary systems:</t>

<section anchor="technical-distinctions"><name>Technical Distinctions</name>

<t><list style="numbers" type="1">
  <t><strong>Prior Art Foundation</strong>: SayWhere combines two established public domain technologies:
  <list style="symbols">
      <t>Geohash spatial indexing (Niemeyer, 2008) for coordinate encoding</t>
      <t>BIP-39 mnemonic wordlist (Palatinus et al., 2013) for word mapping</t>
    </list></t>
  <t><strong>Hierarchical Variable-Length Encoding</strong>: SayWhere uses 1-6+ word phrases with true prefix relationships, where shorter phrases represent spatial areas containing all longer phrases with the same prefix. This hierarchical property is fundamentally incompatible with fixed-length systems.</t>
  <t><strong>Direct Geohash Mapping</strong>: SayWhere uses deterministic chunk-based mapping (2 geohash characters → 1 word) without shuffling algorithms, attractiveness ratings, or cell-decomposition transformations.</t>
  <t><strong>Error Detection vs. Error Magnification</strong>: SayWhere provides two-layer error detection (per-word parity + optional terminal checksum) rather than error magnification through shuffling.</t>
  <t><strong>Open Intermediate Representation</strong>: The geohash intermediate representation is directly observable and reversible, unlike proprietary integer-based cell decomposition schemes.</t>
</list></t>

</section>
<section anchor="mathematical-incompatibility"><name>Mathematical Incompatibility</name>

<t>The hierarchical prefix relationship (where "grape" contains "grape.column" which contains "grape.column.hip") is mathematically incompatible with shuffling-based approaches that intentionally disperse similar inputs to distant outputs. This fundamental design choice ensures SayWhere operates in a different technical space.</t>

</section>
<section anchor="patent-landscape"><name>Patent Landscape</name>

<t>The authors believe SayWhere's use of published prior art (geohash + BIP-39) combined with hierarchical variable-length encoding represents a distinct technical approach not covered by known third-party patents. However, the authors make no legal determination regarding patent validity, enforceability, or scope.</t>

<t>Implementors are encouraged to:</t>

<t><list style="numbers" type="1">
  <t>Consult legal counsel regarding patent implications in their jurisdiction</t>
  <t>Review the technical differences documented in this specification</t>
  <t>Note that geohash (2008) and BIP-39 (2013) predate many word-based geocoding patents</t>
  <t>Consider that the hierarchical variable-length approach differs fundamentally from fixed-length cell-decomposition methods</t>
</list></t>

</section>
<section anchor="defensive-publication"><name>Defensive Publication</name>

<t>This specification serves as a defensive publication documenting the combination of geohash spatial indexing with BIP-39 word encoding for hierarchical variable-length location phrases. The reference implementation is released under GNU GPL v3, ensuring perpetual public availability.</t>

<t>Per RFC 8179, the IETF makes no determination about the validity or applicability of any claimed intellectual property rights. This disclosure is provided for informational purposes to assist implementors in making informed decisions.</t>

</section>
</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>

<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 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>
<reference anchor="GEOWORDS" target="https://mfrank.codeberg.page/GeoWords">
  <front>
    <title>GeoWords</title>
    <author initials="" surname="mfrank" fullname="mfrank">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>


    </references>

</references>


<?line 1268?>

<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 <xref target="GEOHASH"/> created by Gustavo Niemeyer and the BIP-39 wordlist <xref target="BIP39"/> developed by the Bitcoin community. The altitude component was inspired by the GeoWords <xref target="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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
KS4argHT+whWiI8f4/ArAdTrdglCvY3BxlroHIwZOpv4t9v9euiMN9ZCZ7xh
oLNxL3DEgTPVvjYOOm5qnbTkiPPID+d2uzYaC9EyG8E1sEolE2llhd0UVWfF
7L7WjA0mQBStQ0ustZV6bUgGLlRmpmi2uj/z/EtdeRo7Pr9WeNjyocCkY3Q/
D11hn23zYwlmVmpUHySVGXyr3pR6W3uaPPLjm5U9pJ45iVZ8CjJ9LRQCvDYX
4kI+Fyv7Oa3MPV9ZTeNJ4a/mOytrGBftYclN/Pz06PCi7E9nHGs0NymwUt+p
vs/PHXvHM7ElfFXJ+dkI8PR47GpLSy23YDy50cH46HzfsgOHBzKAmI4ms6Jc
8U15PG3Vs87rDF9oIWM+z3jj67NgTdQg6zlnezgscQz+NC+wlWALLSHHWtyW
QeLywJqBmlqGh/B9nOw4KtdCGOWtcnJlAOvcpX4l6ktXRlFkHxFs1ozzQc8q
3odetMXRyuJXB+DXNK5HroEVJLk4e7XvWF5CmHLfJc+uh8LcaReveol9Jpxb
bRbGpNjpPKqKjK+bdWWyXzHRld1wD4WpMH90+rk8LfcpxoQWGMvW66oOEGoU
YySfIy46qLv2A5jQKWQrGVWhq1Ayz7MvlTxmBsbWKykWVyrrirolfbHB1jWa
YlR7lSASNeth5TKlLElNEkgIPM4Iuii7Wb5BZS2wf97d/sbTzCJlyapiluTJ
J3SKX7HWO9HB0MCVhobLQ86GI9ZZVhaE1mAF/hxoaI3y8xb8YJESd0ncLgcX
kyZ/VucTYsPp06j+f1av4RvCBC+croki9vO6UGEmXBi61ObIn9lyzAP5GQmh
+I7/UtIRwWydQASeLq1enoYgwVu4iqA5R8JaYUF4jGlsdc30M0t1xZaEEHHK
Zg6PdgUmPbCbzWTl+NnjBYcavJOAPXYu71ax2zCJ5ySZ3M9jnoWTkNZw6pdI
M1eAuH9xagIu8jt2yfMWC8YNREa4TOlkF6uDZ1mmzf5Ira48qA7tO0vNHyLV
ZefFNLO+i3Izu86K2Xot0zNxDLYhCoLV4fR36pe//ItHMg6iMJ5KyFCTY6nx
dLz3x1enTaEYLrBGbsNguDloE4g1nGlHbG5OpGKX44m2+FILj0sdQxxbduoJ
zZOAFWwyvl/++b/88s//4f/7f/+VOv5HIrXn4x/F3cSwAWpvfLT36mh8QeeJ
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

-->

</rfc>

