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, . [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . 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, . 15.2. Informative References [RFC3552] Rescorla, E. and B. Korver, "Guidelines for Writing RFC Text on Security Considerations", RFC 3552, BCP 72, July 2003, . [RFC7258] Farrell, S. and H. Tschofenig, "Pervasive Monitoring Is an Attack", RFC 7258, BCP 188, May 2014, . [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", RFC 8126, BCP 26, June 2017, . [BIP39] Palatinus, M., Rusnak, P., Voisine, A., and S. Bowe, "BIP 0039: Mnemonic code for generating deterministic keys", September 2013, . [GEOHASH] Niemeyer, G., "Geohash", 2008, . [GEOWORDS] mfrank, "GeoWords", n.d., . 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]