Skip to main content

SayWhere Geocoding System: Human-Memorable Geographic Coordinates
draft-saywhere-geocoding-01

Document Type Active Internet-Draft (individual)
Author Hugo O'Connor
Last updated 2025-10-19
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-saywhere-geocoding-01
Network Working Group                                        H. O'Connor
Internet-Draft                                    Anuna Research Pty Ltd
Intended status: Informational                           20 October 2025
Expires: 23 April 2026

   SayWhere Geocoding System: Human-Memorable Geographic Coordinates
                      draft-saywhere-geocoding-01

Abstract

   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.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 23 April 2026.

Copyright Notice

   Copyright (c) 2025 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

O'Connor                  Expires 23 April 2026                 [Page 1]
Internet-Draft             SayWhere Geocoding               October 2025

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   4
   2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .   5
     2.1.  Requirements Language . . . . . . . . . . . . . . . . . .   5
     2.2.  Core Concepts . . . . . . . . . . . . . . . . . . . . . .   5
     2.3.  Phrase Types  . . . . . . . . . . . . . . . . . . . . . .   6
   3.  System Architecture . . . . . . . . . . . . . . . . . . . . .   6
     3.1.  Encoding Pipeline . . . . . . . . . . . . . . . . . . . .   6
     3.2.  Decoding Pipeline . . . . . . . . . . . . . . . . . . . .   7
     3.3.  Format Specifications . . . . . . . . . . . . . . . . . .   7
       3.3.1.  Hierarchical Format . . . . . . . . . . . . . . . . .   7
       3.3.2.  Precision vs. Length Table  . . . . . . . . . . . . .   8
   4.  Wordlist Specification  . . . . . . . . . . . . . . . . . . .   9
     4.1.  BIP-39 Wordlist (REQUIRED)  . . . . . . . . . . . . . . .   9
     4.2.  Requirements  . . . . . . . . . . . . . . . . . . . . . .   9
     4.3.  File Format . . . . . . . . . . . . . . . . . . . . . . .  10
     4.4.  Available Wordlists . . . . . . . . . . . . . . . . . . .  10
     4.5.  Versioning  . . . . . . . . . . . . . . . . . . . . . . .  11
   5.  Encoding Algorithm  . . . . . . . . . . . . . . . . . . . . .  11
     5.1.  Hierarchical Encoding . . . . . . . . . . . . . . . . . .  11
       5.1.1.  Input Parameters  . . . . . . . . . . . . . . . . . .  11
       5.1.2.  Algorithm Steps . . . . . . . . . . . . . . . . . . .  11
       5.1.3.  Example Execution . . . . . . . . . . . . . . . . . .  13
   6.  Decoding Algorithm  . . . . . . . . . . . . . . . . . . . . .  14
     6.1.  Hierarchical Decoding (RECOMMENDED) . . . . . . . . . . .  14
       6.1.1.  Input Parameters  . . . . . . . . . . . . . . . . . .  15
       6.1.2.  Algorithm Steps . . . . . . . . . . . . . . . . . . .  15
   7.  Hierarchical Properties . . . . . . . . . . . . . . . . . . .  17
     7.1.  Prefix Relationships  . . . . . . . . . . . . . . . . . .  17
     7.2.  Spatial Containment . . . . . . . . . . . . . . . . . . .  17
     7.3.  Use Cases . . . . . . . . . . . . . . . . . . . . . . . .  17
       7.3.1.  Progressive Disclosure  . . . . . . . . . . . . . . .  17
       7.3.2.  Search and Filtering  . . . . . . . . . . . . . . . .  18
   8.  Checksum Computation  . . . . . . . . . . . . . . . . . . . .  18
     8.1.  Design Philosophy . . . . . . . . . . . . . . . . . . . .  18
     8.2.  Per-Word Parity Checksum  . . . . . . . . . . . . . . . .  18
       8.2.1.  Purpose . . . . . . . . . . . . . . . . . . . . . . .  18
       8.2.2.  Algorithm . . . . . . . . . . . . . . . . . . . . . .  18
       8.2.3.  Properties  . . . . . . . . . . . . . . . . . . . . .  19
     8.3.  Optional Terminal Checksum  . . . . . . . . . . . . . . .  20
       8.3.1.  Purpose . . . . . . . . . . . . . . . . . . . . . . .  20

O'Connor                  Expires 23 April 2026                 [Page 2]
Internet-Draft             SayWhere Geocoding               October 2025

       8.3.2.  Checksum Wordlist . . . . . . . . . . . . . . . . . .  20
       8.3.3.  CRC-8 Algorithm . . . . . . . . . . . . . . . . . . .  20
       8.3.4.  Examples  . . . . . . . . . . . . . . . . . . . . . .  22
       8.3.5.  Encoding with Terminal Checksum . . . . . . . . . . .  22
       8.3.6.  Decoding with Checksum Detection  . . . . . . . . . .  22
       8.3.7.  Error Detection Capabilities  . . . . . . . . . . . .  23
       8.3.8.  Two-Layer Error Detection . . . . . . . . . . . . . .  24
   9.  LSB parity passes (both valid BIP-39 words) . . . . . . . . .  24
     9.1.  Field Verification (BACKUP) . . . . . . . . . . . . . . .  24
       9.1.1.  Use Cases . . . . . . . . . . . . . . . . . . . . . .  25
   10. Altitude Support  . . . . . . . . . . . . . . . . . . . . . .  25
     10.1.  Design Philosophy  . . . . . . . . . . . . . . . . . . .  25
     10.2.  Quantization . . . . . . . . . . . . . . . . . . . . . .  26
     10.3.  Range Limits . . . . . . . . . . . . . . . . . . . . . .  26
   11. URN Format  . . . . . . . . . . . . . . . . . . . . . . . . .  27
     11.1.  Specification  . . . . . . . . . . . . . . . . . . . . .  27
     11.2.  Components . . . . . . . . . . . . . . . . . . . . . . .  27
     11.3.  Examples . . . . . . . . . . . . . . . . . . . . . . . .  27
     11.4.  Parsing Grammar (ABNF) . . . . . . . . . . . . . . . . .  27
   12. Security Considerations . . . . . . . . . . . . . . . . . . .  28
     12.1.  Intellectual Property Considerations . . . . . . . . . .  30
       12.1.1.  Technical Distinctions . . . . . . . . . . . . . . .  30
       12.1.2.  Mathematical Incompatibility . . . . . . . . . . . .  30
       12.1.3.  Patent Landscape . . . . . . . . . . . . . . . . . .  31
       12.1.4.  Defensive Publication  . . . . . . . . . . . . . . .  31
   13. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  31
   14. Implementation Guidance . . . . . . . . . . . . . . . . . . .  33
     14.1.  Performance Optimization . . . . . . . . . . . . . . . .  33
     14.2.  Testing Requirements . . . . . . . . . . . . . . . . . .  33
     14.3.  Reference Implementation . . . . . . . . . . . . . . . .  34
     14.4.  Web Application Demo . . . . . . . . . . . . . . . . . .  34
   15. References  . . . . . . . . . . . . . . . . . . . . . . . . .  34
     15.1.  Normative References . . . . . . . . . . . . . . . . . .  34
     15.2.  Informative References . . . . . . . . . . . . . . . . .  35
   Appendix A.  Geohash Algorithm Details  . . . . . . . . . . . . .  35
     A.1.  Encoding Pseudocode . . . . . . . . . . . . . . . . . . .  35
   Appendix B.  Test Vectors . . . . . . . . . . . . . . . . . . . .  36
     B.1.  Hierarchical Encoding Test Cases  . . . . . . . . . . . .  36
       B.1.1.  Test Case 1: New York City  . . . . . . . . . . . . .  36
       B.1.2.  Test Case 2: London . . . . . . . . . . . . . . . . .  37
       B.1.3.  Test Case 3: Equator Crossing . . . . . . . . . . . .  37
       B.1.4.  Test Case 4: With Terminal Checksum . . . . . . . . .  38
   Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . .  39
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  39

O'Connor                  Expires 23 April 2026                 [Page 3]
Internet-Draft             SayWhere Geocoding               October 2025

1.  Introduction

   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.

   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.

   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.

   The design goals for SayWhere are:

   1.  *Deterministic*: Same coordinates always produce identical word
       phrases

   2.  *Reversible*: Word phrases can be decoded back to original
       coordinates

   3.  *Human-Friendly*: Words are common, easy to spell, and
       phonetically distinct

   4.  *Error Detection*: Two-layer validation with per-word parity and
       optional terminal checksum tp validate a word phrase.

   5.  *3D Support*: Optional altitude component for vertical
       positioning

   6.  *Open Standard*: Public domain algorithm based on established
       prior art with no proprietary restrictions

O'Connor                  Expires 23 April 2026                 [Page 4]
Internet-Draft             SayWhere Geocoding               October 2025

   7.  *Hierarchical*: Variable-length phrases (1-6 words) with true
       prefix relationships

   Compared to existing systems:

   *  *Proprietary word-based systems*: Closed algorithms, fixed-length
      (typically 3 words), no error detection, no altitude support

   *  *Plus Codes*: Alphanumeric (not word-based), harder to communicate
      verbally

   *  *Geohash*: Base32 strings, not human-memorable

   *  *SayWhere*: Open source, hierarchical word phrases, 3D support,
      two-layer error detection (LSB parity + optional terminal
      checksum), true prefix relationships, hand-verifiable checksums

   SayWhere is built upon established open technologies as prior art:

   *  *Geohash* (Niemeyer, 2008): Spatial indexing system using base-32
      strings

   *  *BIP-39* (Palatinus et al., 2013): Mnemonic wordlist standard with
      2,048 words

   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.

2.  Terminology

2.1.  Requirements Language

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
   "OPTIONAL" in this document are to be interpreted as described in
   BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
   capitals, as shown here.

2.2.  Core Concepts

   Hierarchical Word Phrase:  Variable-length sequence of words (1-N
      words) representing location with increasing precision

   Prefix Relationship:  Shorter phrases represent a bounded area that

O'Connor                  Expires 23 April 2026                 [Page 5]
Internet-Draft             SayWhere Geocoding               October 2025

      contain all longer phrases with the same prefix

   Location Words:  Words encoding the position of cell within a base32
      cell grid (excluding checksum and altitude)

   Checksum Word:  Optional terminal validation word from a distinct
      32-word vocabulary for phrase-level error detection

   Altitude Units:  Optional numeric component for vertical position

   Wordlist:  An ordered array of words used for encoding/decoding
      (BIP-39 standard)

   Precision Level:  Spatial resolution determined by phrase length

   Geohash:  A geocoding system using base32 strings for spatial
      indexing

2.3.  Phrase Types

   Hierarchical Phrase:  Pure spatial encoding without terminal checksum
      (maintains prefix relationships)

   Validated Phrase:  Includes terminal checksum word for phrase-level
      error detection

   3D Phrase:  Includes altitude component for vertical positioning

3.  System Architecture

3.1.  Encoding Pipeline

   The encoding process transforms geographic coordinates into word
   phrases through the following pipeline:

   1.  Input validation: Verify latitude [-90, 90], longitude [-180,
       180], altitude [-30000, 30000]

   2.  Geohash generation: Convert coordinates to base32 geohash string

   3.  Chunk processing: Split geohash into 2-character chunks (10 bits
       each)

   4.  Parity calculation: Add 1-bit LSB parity to each chunk

   5.  Word mapping: Map 11-bit values (10 data + 1 parity) to BIP-39
       wordlist

O'Connor                  Expires 23 April 2026                 [Page 6]
Internet-Draft             SayWhere Geocoding               October 2025

   6.  Phrase assembly: Join location words with dots for hierarchical
       structure

   7.  Optional: Compute and append CRC-8 terminal checksum word from
       32-word vocabulary

3.2.  Decoding Pipeline

   The decoding process reverses the encoding to recover coordinates:

   1.  Phrase parsing: Split on dots, validate word format

   2.  Checksum detection: Identify and separate terminal checksum word
       (if present)

   3.  Word lookup: Find each location word in BIP-39 wordlist to get
       11-bit index

   4.  LSB parity validation: Verify 1-bit parity for each location word

   5.  Terminal checksum validation: If present, validate phrase-level
       checksum

   6.  Chunk extraction: Extract 10-bit chunk value from each location
       word

   7.  Geohash reconstruction: Concatenate chunks to form geohash string

   8.  Coordinate decoding: Decode geohash to latitude/longitude with
       bounds

3.3.  Format Specifications

3.3.1.  Hierarchical Format

   Hierarchical phrases maintain true prefix relationships:

   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)

   *Key Property:* Each shorter phrase represents an area containing all
   longer phrases with the same prefix.

O'Connor                  Expires 23 April 2026                 [Page 7]
Internet-Draft             SayWhere Geocoding               October 2025

   *Error Detection:* 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)

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

3.3.2.  Precision vs. Length Table

   Precision is constrained by geohash spatial indexing:

   +=======+===============+=================+==========+==============+
   | Words | Geohash Chars | Grid Dimensions | Avg      | Use Case     |
   |       |               |                 | Size     |              |
   +=======+===============+=================+==========+==============+
   | 1     | 2             | 1,252km × 624km | ~900km   | Country/     |
   |       |               |                 |          | Large Region |
   +-------+---------------+-----------------+----------+--------------+
   | 2     | 4             | 39.1km × 19.5km | ~28km    | City         |
   +-------+---------------+-----------------+----------+--------------+
   | 3     | 6             | 1.2km × 609m    | ~900m    | Neighborhood |
   +-------+---------------+-----------------+----------+--------------+
   | 4     | 8             | 38.2m × 19m     | ~27m     | Building     |
   +-------+---------------+-----------------+----------+--------------+
   | 5     | 10            | 1.2m × 59.5cm   | ~90cm    | Room/Precise |
   |       |               |                 |          | Position     |
   +-------+---------------+-----------------+----------+--------------+
   | 6     | 12            | 3.7cm × 1.9cm   | ~2.7cm   | Sub-Meter    |
   |       |               |                 |          | Precision    |
   +-------+---------------+-----------------+----------+--------------+
   | 7     | 14            | 1.2mm × 0.6mm   | ~0.85mm  | Millimeter   |
   |       |               |                 |          | Precision    |
   +-------+---------------+-----------------+----------+--------------+
   | 8     | 16            | 37μm × 19μm     | ~27μm    | Micron-Level |
   |       |               |                 |          | Precision    |
   +-------+---------------+-----------------+----------+--------------+

            Table 1: Precision Mapping for Hierarchical Phrases

   *Key Insight:* 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.

O'Connor                  Expires 23 April 2026                 [Page 8]
Internet-Draft             SayWhere Geocoding               October 2025

   *Extensibility:* 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.

4.  Wordlist Specification

4.1.  BIP-39 Wordlist (REQUIRED)

   SayWhere uses the BIP-39 mnemonic wordlist [BIP39] as its standard
   wordlist.  This provides significant advantages:

   *  *Size:* Exactly 2,048 words (11 bits) - perfect for encoding 2
      geohash characters (10 bits) + 1 parity bit

   *  *Battle-tested:* Used by millions in cryptocurrency wallets since
      2013

   *  *Multilingual:* Official wordlists in 9 languages

   *  *Widely distributed:* BIP-39 wordlists are embedded in countless
      applications and hardware devices worldwide, ensuring availability
      and consistency

   *  *Open source:* No licensing restrictions

   *  *Existing ecosystem:* Libraries available in all major languages

4.2.  Requirements

   A compliant wordlist MUST satisfy these criteria:

   1.  *Size:* Exactly 2,048 words (index 0 to 2,047)

   2.  *Character Set:* Lowercase ASCII letters [a-z] only

   3.  *Length:* Each word 3-8 characters (BIP-39 standard)

   4.  *Uniqueness:* No duplicate words

   5.  *Ordering:* Stable ordering (indices never change within a
       version)

   6.  *Phonetic Distinctness:* First 4 letters must be unique (BIP-39
       property)

O'Connor                  Expires 23 April 2026                 [Page 9]
Internet-Draft             SayWhere Geocoding               October 2025

   7.  *Family-Friendly:* No profanity or offensive terms

4.3.  File Format

   Wordlists MUST be stored in JSON format:

   {
     "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"
     ]
   }

4.4.  Available Wordlists

   BIP-39 provides wordlists in the following languages:

   *  English

   *  Spanish

   *  French

   *  Italian

   *  Japanese

   *  Korean

   *  Chinese (Simplified)

   *  Chinese (Traditional)

   *  Czech

   *  Portuguese

O'Connor                  Expires 23 April 2026                [Page 10]
Internet-Draft             SayWhere Geocoding               October 2025

4.5.  Versioning

   Wordlist versions MUST follow semantic versioning
   (MAJOR.MINOR.PATCH):

   *  *MAJOR:* Incompatible changes (words removed/reordered)

   *  *MINOR:* Backward-compatible additions

   *  *PATCH:* Bug fixes (typo corrections)

   *Critical:* Encoding and decoding MUST use the same wordlist version.

5.  Encoding Algorithm

5.1.  Hierarchical Encoding

5.1.1.  Input Parameters

   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)

5.1.2.  Algorithm Steps

   *Step 1: Validate Input*

   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"

   *Step 2: Generate Full Geohash*

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

O'Connor                  Expires 23 April 2026                [Page 11]
Internet-Draft             SayWhere Geocoding               October 2025

   *Step 3: Chunk-Based Word Generation*

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

   *Step 4: Build Hierarchical Phrases*

O'Connor                  Expires 23 April 2026                [Page 12]
Internet-Draft             SayWhere Geocoding               October 2025

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

5.1.3.  Example Execution

   Input: New York City (40.7128, -74.0060), max_precision = 3

O'Connor                  Expires 23 April 2026                [Page 13]
Internet-Draft             SayWhere Geocoding               October 2025

   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
   ]

   *Prefix Guarantee:* 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.

6.  Decoding Algorithm

6.1.  Hierarchical Decoding (RECOMMENDED)

O'Connor                  Expires 23 April 2026                [Page 14]
Internet-Draft             SayWhere Geocoding               October 2025

6.1.1.  Input Parameters

   phrase:   string  # "word1.word2.word3..." (variable length)
   wordlist: array   # BIP-39 wordlist (2,048 words)

6.1.2.  Algorithm Steps

   *Step 1: Parse Phrase*

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"

   *Step 2: Decode Each Word with Checksum Validation*

O'Connor                  Expires 23 April 2026                [Page 15]
Internet-Draft             SayWhere Geocoding               October 2025

 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

   *Step 3: Reconstruct Geohash*

   geohash = ""

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

   # Example: ["grape", "column", "hip"] → "dr" + "5r" + "eg" → "dr5reg"

   *Step 4: Decode Geohash to Coordinates*

   (latitude, longitude, lat_error, lon_error) = geohash_decode(geohash)

   # Standard geohash decoding algorithm
   # Returns center point and error bounds

O'Connor                  Expires 23 April 2026                [Page 16]
Internet-Draft             SayWhere Geocoding               October 2025

   *Step 5: Return Result*

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
}

7.  Hierarchical Properties

7.1.  Prefix Relationships

   SayWhere hierarchical phrases exhibit true spatial prefix
   relationships:

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.*"

   *Mathematical Property:* If phrase A is a prefix of phrase B, then
   the spatial area of A contains the spatial area of B.

7.2.  Spatial Containment

   *Containment Guarantee:* Any location encoded as
   "grape.column.hip.thought.pull" will always be contained within the
   spatial bounds of:

   *  "grape.column.hip.thought" (more precise)

   *  "grape.column.hip" (less precise)

   *  "grape.column" (even less precise)

   *  "grape" (least precise)

7.3.  Use Cases

7.3.1.  Progressive Disclosure

O'Connor                  Expires 23 April 2026                [Page 17]
Internet-Draft             SayWhere Geocoding               October 2025

   "Meet me in tokyo"                    # City-level
   "Meet me in shibuya.tokyo"           # District-level
   "Meet me at station.shibuya.tokyo"   # Building-level

7.3.2.  Search and Filtering

   -- 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.%'

8.  Checksum Computation

8.1.  Design Philosophy

   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.

8.2.  Per-Word Parity Checksum

8.2.1.  Purpose

   Built-in per-word validation that:

   1.  Detects single-bit errors in each word independently

   2.  Maintains hierarchical prefix relationships

   3.  Requires no additional checksum words

   4.  Works for phrases of any length (1-6 words)

8.2.2.  Algorithm

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

   *  *10 bits:* Geohash chunk data (2 base32 characters)

   *  *1 bit:* Parity checksum (LSB)

O'Connor                  Expires 23 April 2026                [Page 18]
Internet-Draft             SayWhere Geocoding               October 2025

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

8.2.3.  Properties

   *  *Error Detection:* Detects any odd number of bit flips in the
      10-bit chunk

   *  *Probability:* 50% chance of detecting even number of bit flips

O'Connor                  Expires 23 April 2026                [Page 19]
Internet-Draft             SayWhere Geocoding               October 2025

   *  *No False Positives:* Valid words always pass parity check

   *  *Zero Overhead:* No additional words required

   *  *Prefix Preserving:* Shorter phrases remain valid prefixes

8.3.  Optional Terminal Checksum

8.3.1.  Purpose

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

   1.  Uses a distinct 32-word vocabulary (auto-detectable)

   2.  Validates the entire phrase (word substitution, omission,
       transposition)

   3.  Provides near-uniform distribution for optimal error detection

   4.  Complements per-word LSB parity for two-layer error detection

8.3.2.  Checksum Wordlist

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

   # 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

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

8.3.3.  CRC-8 Algorithm

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

O'Connor                  Expires 23 April 2026                [Page 20]
Internet-Draft             SayWhere Geocoding               October 2025

   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

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

O'Connor                  Expires 23 April 2026                [Page 21]
Internet-Draft             SayWhere Geocoding               October 2025

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

   *Key Insight:* 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).

8.3.4.  Examples

   *Example 1: New York City* ~~~~ Location: "grape.column.hip"

   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"

   Result: "grape.column.hip.seal" ~~~~

   *Example 2: London* ~~~~ Location: "kit.puzzle"

   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"

   Result: "kit.puzzle.orange" ~~~~

8.3.5.  Encoding with Terminal Checksum

   To create a validated phrase:

   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

8.3.6.  Decoding with Checksum Detection

   Decoders MUST automatically detect and validate terminal checksums:

O'Connor                  Expires 23 April 2026                [Page 22]
Internet-Draft             SayWhere Geocoding               October 2025

   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

8.3.7.  Error Detection Capabilities

   The terminal checksum detects:

   *  *Word substitution*: "grape" misheard as "grace"

   *  *Word omission*: "grape.column.hip" → "grape.hip"

   *  *Word transposition*: "grape.column" → "column.grape"

   *  *Word addition*: Unintended extra words

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

O'Connor                  Expires 23 April 2026                [Page 23]
Internet-Draft             SayWhere Geocoding               October 2025

8.3.8.  Two-Layer Error Detection

   Terminal checksum and per-word LSB parity work together:

       +============+==========+===================+===============+
       | Layer      | Scope    | Detects           | When Checked  |
       +============+==========+===================+===============+
       | LSB Parity | Per-word | Bit corruption in | During word   |
       |            |          | individual words  | decode        |
       +------------+----------+-------------------+---------------+
       | Terminal   | Whole    | Wrong word,       | After all     |
       | Checksum   | phrase   | order, omissions  | words decoded |
       +------------+----------+-------------------+---------------+

                                  Table 2

   *Example: Error caught by terminal checksum* ~~~~ Sent:
   "grape.column.hip.seal" Received: "grape.color.hip.seal" (column →
   color)

9.  LSB parity passes (both valid BIP-39 words)

   # Terminal checksum fails: expected =
   compute_terminal_checksum(["grape", "color", "hip"]) → "whale"
   received = "seal" # Error detected! ✗ ~~~~

9.1.  Field Verification (BACKUP)

   The following simplified checksum MAY be calculated and verified in
   emergency situations using printed reference cards:

O'Connor                  Expires 23 April 2026                [Page 24]
Internet-Draft             SayWhere Geocoding               October 2025

   ┌──────────────────────────────────────┐
   │   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│
   └──────────────────────────────────────┘

9.1.1.  Use Cases

   *Emergency Response* ~~~~ Hiker (over radio): "My location is grape
   column hip seal" Dispatcher: _validates checksum_ System: ✓ Checksum
   valid - location confirmed Dispatcher: "Coordinates confirmed,
   dispatching rescue team" ~~~~

   *Error Detection* ~~~~ Sent: "grape.column.hip.seal" Received:
   "grape.hip.seal" (word dropped)

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

   Response: "Please repeat location, checksum error detected" ~~~~

10.  Altitude Support

10.1.  Design Philosophy

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

O'Connor                  Expires 23 April 2026                [Page 25]
Internet-Draft             SayWhere Geocoding               October 2025

   *Rationale:* Unitless values maintain:

   *  *Phrase brevity:* ".20" vs ".60m" or ".20meters"

   *  *Simplicity:* Consistent with horizontal coordinate abstraction

   *  *Flexibility:* Applications can choose appropriate step sizes
      without breaking compatibility

   *  *Voice-friendly:* Easier to communicate "twenty" than "twenty
      meters"

10.2.  Quantization

   Altitude MUST be quantized to fixed-step increments:

  altitude_step = 3.0  # meters (configuration parameter, not in phrase)
  altitude_units = ROUND(altitude_meters / altitude_step)

   Standard step configurations:

     +===========+===========+=========+=========+==================+
     | Use Case  | Step Size | Example | Encoded | Notes            |
     |           |           | Input   | Units   |                  |
     +===========+===========+=========+=========+==================+
     | Buildings | 3.0m      | 60.0m   | .20     | Typical floor    |
     |           |           |         |         | height           |
     +-----------+-----------+---------+---------+------------------+
     | Drones    | 1.0m      | 60.0m   | .60     | Precise vertical |
     |           |           |         |         | control          |
     +-----------+-----------+---------+---------+------------------+
     | Aircraft  | 100.0m    | 6000.0m | .60     | Flight levels    |
     |           |           |         |         | (FL060)          |
     +-----------+-----------+---------+---------+------------------+
     | Mining/   | 5.0m      | -50.0m  | .-10    | Underground      |
     | Caves     |           |         |         | operations       |
     +-----------+-----------+---------+---------+------------------+

                  Table 3: Altitude Step Configurations

10.3.  Range Limits

   MIN_ALTITUDE_UNITS = -1000  # Lowest representable value
   MAX_ALTITUDE_UNITS = 10000  # Highest representable value

O'Connor                  Expires 23 April 2026                [Page 26]
Internet-Draft             SayWhere Geocoding               October 2025

11.  URN Format

11.1.  Specification

   SayWhere defines a canonical URN format ([RFC8141] compliant):

urn:saywhere:{language}:{word1}.{word2}.{word3}.{wordN}.{checksum}[:{altitude}]

11.2.  Components

   *  urn:saywhere - Namespace identifier (fixed)

   *  {language} - ISO 639-1 language code (2 lowercase letters)

   *  {word1}.{word2}.{word3}.{checksum} - Word phrase

   *  {altitude} - OPTIONAL signed integer altitude units (unitless)

   The terminal checksum is MUST 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.

11.3.  Examples

   # 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

11.4.  Parsing Grammar (ABNF)

O'Connor                  Expires 23 April 2026                [Page 27]
Internet-Draft             SayWhere Geocoding               October 2025

   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

12.  Security Considerations

   This section follows the guidelines in [RFC3552] for security
   considerations in protocol specifications.

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

   *  *Data Minimization*: Implementations SHOULD NOT log or store
      phrases without explicit user consent

   *  *User Awareness*: Users SHOULD be warned that phrases reveal
      precise physical locations that persist over time

   *  *Sharing Controls*: Applications SHOULD implement access controls
      before transmitting or displaying location phrases

   *  *Hierarchical Disclosure*: Applications can leverage hierarchical
      phrases to enable progressive disclosure, sharing only the
      precision level necessary for the use case

   *  *Pervasive Monitoring*: Per [RFC7258], implementations should
      consider that location data transmission may be subject to
      pervasive monitoring attacks

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

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

   *  *No Authentication*: Checksums do NOT provide cryptographic
      authentication or integrity protection

   *  *Accidental Errors Only*: Checksums ONLY detect accidental
      transmission/transcription errors, not deliberate tampering

O'Connor                  Expires 23 April 2026                [Page 28]
Internet-Draft             SayWhere Geocoding               October 2025

   *  *Not Security Critical*: Do not rely on checksums for security-
      critical applications requiring authenticated location data

   *  *Malicious Modification*: An attacker can easily generate valid
      phrases with correct checksums for arbitrary locations

   *  *Limited Entropy*: Terminal checksum uses only 5 bits (32 values),
      providing ~3% false negative rate

   The terminal checksum is designed for *error detection*
   (communication integrity), not *security* (adversarial protection).

   Applications requiring authenticated location assertions should
   implement additional cryptographic signatures or message
   authentication codes.

   Implementations depend on wordlist consistency for correct operation:

   *  *Verification Required*: Implementations MUST verify wordlist
      integrity using cryptographic checksums (SHA-256 or better
      recommended)

   *  *Corruption Impact*: Corrupted or modified wordlists produce
      incorrect encodings that may place users in unintended or
      dangerous locations

   *  *Supply Chain Security*: Consider signing wordlist files for
      distribution and verifying signatures before use

   *  *Version Control*: Implementations should verify the wordlist
      version matches the expected version for the encoding/decoding
      operation

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

   Implementations should protect against resource exhaustion:

   *  *Rate Limiting*: Implementations SHOULD rate-limit encoding/
      decoding operations, particularly in network-facing services

   *  *Batch Size Limits*: Batch operations SHOULD enforce maximum size
      limits to prevent memory exhaustion

   *  *Early Validation*: Invalid input SHOULD be rejected early in
      processing to avoid expensive computation

O'Connor                  Expires 23 April 2026                [Page 29]
Internet-Draft             SayWhere Geocoding               October 2025

12.1.  Intellectual Property Considerations

   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.

   SayWhere uses fundamentally different technical mechanisms that
   distinguish it from these proprietary systems:

12.1.1.  Technical Distinctions

   1.  *Prior Art Foundation*: SayWhere combines two established public
       domain technologies:

       *  Geohash spatial indexing (Niemeyer, 2008) for coordinate
          encoding

       *  BIP-39 mnemonic wordlist (Palatinus et al., 2013) for word
          mapping

   2.  *Hierarchical Variable-Length Encoding*: 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.

   3.  *Direct Geohash Mapping*: SayWhere uses deterministic chunk-based
       mapping (2 geohash characters → 1 word) without shuffling
       algorithms, attractiveness ratings, or cell-decomposition
       transformations.

   4.  *Error Detection vs. Error Magnification*: SayWhere provides two-
       layer error detection (per-word parity + optional terminal
       checksum) rather than error magnification through shuffling.

   5.  *Open Intermediate Representation*: The geohash intermediate
       representation is directly observable and reversible, unlike
       proprietary integer-based cell decomposition schemes.

12.1.2.  Mathematical Incompatibility

   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.

O'Connor                  Expires 23 April 2026                [Page 30]
Internet-Draft             SayWhere Geocoding               October 2025

12.1.3.  Patent Landscape

   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.

   Implementors are encouraged to:

   1.  Consult legal counsel regarding patent implications in their
       jurisdiction

   2.  Review the technical differences documented in this specification

   3.  Note that geohash (2008) and BIP-39 (2013) predate many word-
       based geocoding patents

   4.  Consider that the hierarchical variable-length approach differs
       fundamentally from fixed-length cell-decomposition methods

12.1.4.  Defensive Publication

   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.

   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.

13.  IANA Considerations

   This section follows the guidelines in [RFC8126] for IANA
   considerations sections.

   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 [RFC8141].

   Per [RFC8141] Section 6, the following registration template is
   provided:

   Namespace ID:  saywhere

O'Connor                  Expires 23 April 2026                [Page 31]
Internet-Draft             SayWhere Geocoding               October 2025

   Registration Information:  Version 1, 2025-10-12

   Declared registrant:  SayWhere Contributors

      Anuna Research Pty Ltd

      Email: contact@saywhere.org

      URI: https://codeberg.org/anuna/saywhere

   Declaration of syntactic structure:  See Section 9 of this document

   Relevant ancillary documentation:  This document serves as the
      specification for the saywhere URN namespace

   Identifier uniqueness considerations:  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.

   Identifier persistence considerations:  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.

   Process of identifier assignment:  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.

   Process for identifier resolution:  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.

   Rules for Lexical Equivalence:  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.

   Conformance with URN Syntax:  SayWhere URNs conform to the URN syntax
      specified in [RFC8141].  The syntax is formally defined using ABNF
      in Section 9 of this document.

   Validation mechanism:  Validation consists of: (1) syntax validation

O'Connor                  Expires 23 April 2026                [Page 32]
Internet-Draft             SayWhere Geocoding               October 2025

      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.

   Scope:  Global

14.  Implementation Guidance

14.1.  Performance Optimization

   *In-Memory Wordlist:*

   # 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

14.2.  Testing Requirements

   Implementations MUST pass:

   1.  All test vectors in Appendix B

   2.  Roundtrip tests (encode → decode → verify coordinates match)

   3.  Per-word LSB parity validation tests

   4.  Terminal checksum validation tests (detection and validation)

   5.  Error handling tests (both parity and checksum errors)

   6.  Boundary condition tests (poles, dateline, altitude extremes)

   7.  Altitude quantization tests (different step sizes)

   8.  Checksum error detection tests (substitution, omission,
       transposition)

O'Connor                  Expires 23 April 2026                [Page 33]
Internet-Draft             SayWhere Geocoding               October 2025

14.3.  Reference Implementation

   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:

   *  Repository: https://codeberg.org/anuna/saywhere
      (https://codeberg.org/anuna/saywhere)

   *  License: GNU GPL v3

   Implementations in other languages that pass the test vectors in
   Appendix B are considered conformant.

14.4.  Web Application Demo

   An interactive web application is available for exploring SayWhere
   encoding and decoding:

   *  Demo: https://saywhere.org/grape/column/hip
      (https://saywhere.org/grape/column/hip)

   The demo allows users to:

   *  Visualize hierarchical phrase resolution on an interactive map

   *  Encode coordinates to word phrases

   *  Decode word phrases to geographic locations

   *  Explore the spatial containment relationships between different
      precision levels

   *  Test error detection capabilities

15.  References

15.1.  Normative References

   [RFC8141]  Saint-Andre, P. and J. Klensin, "Uniform Resource Names
              (URNs)", RFC 8141, DOI 10.17487/RFC8141, April 2017,
              <https://www.rfc-editor.org/rfc/rfc8141>.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/rfc/rfc2119>.

O'Connor                  Expires 23 April 2026                [Page 34]
Internet-Draft             SayWhere Geocoding               October 2025

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/rfc/rfc8174>.

15.2.  Informative References

   [RFC3552]  Rescorla, E. and B. Korver, "Guidelines for Writing RFC
              Text on Security Considerations", RFC 3552, BCP 72, July
              2003, <https://www.rfc-editor.org/info/rfc3552>.

   [RFC7258]  Farrell, S. and H. Tschofenig, "Pervasive Monitoring Is an
              Attack", RFC 7258, BCP 188, May 2014,
              <https://www.rfc-editor.org/info/rfc7258>.

   [RFC8126]  Cotton, M., Leiba, B., and T. Narten, "Guidelines for
              Writing an IANA Considerations Section in RFCs", RFC 8126,
              BCP 26, June 2017,
              <https://www.rfc-editor.org/info/rfc8126>.

   [BIP39]    Palatinus, M., Rusnak, P., Voisine, A., and S. Bowe, "BIP
              0039: Mnemonic code for generating deterministic keys",
              September 2013,
              <https://github.com/bitcoin/bips/blob/master/bip-
              0039.mediawiki>.

   [GEOHASH]  Niemeyer, G., "Geohash", 2008,
              <https://en.wikipedia.org/wiki/Geohash>.

   [GEOWORDS] mfrank, "GeoWords", n.d.,
              <https://mfrank.codeberg.page/GeoWords>.

Appendix A.  Geohash Algorithm Details

A.1.  Encoding Pseudocode

O'Connor                  Expires 23 April 2026                [Page 35]
Internet-Draft             SayWhere Geocoding               October 2025

   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

Appendix B.  Test Vectors

B.1.  Hierarchical Encoding Test Cases

B.1.1.  Test Case 1: New York City

O'Connor                  Expires 23 April 2026                [Page 36]
Internet-Draft             SayWhere Geocoding               October 2025

 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 ✓

B.1.2.  Test Case 2: London

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

B.1.3.  Test Case 3: Equator Crossing

O'Connor                  Expires 23 April 2026                [Page 37]
Internet-Draft             SayWhere Geocoding               October 2025

   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

B.1.4.  Test Case 4: With Terminal Checksum

  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 ✓

O'Connor                  Expires 23 April 2026                [Page 38]
Internet-Draft             SayWhere Geocoding               October 2025

Acknowledgments

   The SayWhere system uses the geohash algorithm [GEOHASH] created by
   Gustavo Niemeyer and the BIP-39 wordlist [BIP39] developed by the
   Bitcoin community.  The altitude component was inspired by the
   GeoWords [GEOWORDS] implementation by mfrank.  We thank these
   contributors for their foundational work.

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

Author's Address

   Hugo O'Connor
   Anuna Research Pty Ltd
   Australia
   Email: hugo@anuna.io
   URI:   https://codeberg.org/anuna/saywhere

O'Connor                  Expires 23 April 2026                [Page 39]