How-To Guide: Namecoin Integration in Amethyst

Complete guide to using censorship-resistant Namecoin blockchain names as NIP-05 identities in Amethyst, including name registration, ElectrumX setup, DVM exchange, and the NMC Exchange Data Vending Machine for easy Namecoin acquisition.

How-To Guide: Namecoin Integration in Amethyst

What This Is

Amethyst — the Android Nostr client — includes built-in support for resolving Namecoin blockchain names as NIP-05 identities. Instead of relying on a web server to verify alice@example.com, a user can set their NIP-05 address to something like alice@example.bit, and Amethyst will verify it directly against the Namecoin blockchain via ElectrumX servers.

This is censorship-resistant identity: no web server to seize, no DNS to hijack, no TLS certificate to revoke. The name-to-pubkey mapping lives in Namecoin UTXOs.

This guide covers how the system works, how to use it as an end-user, and how to register or update a Namecoin name value so that it resolves to your Nostr pubkey.


Part 1: Using Namecoin Names in Amethyst (End-User)

Searching for Namecoin Users

Open Amethyst’s search bar and type any of these formats:

Search Input What It Does
alice@example.bit Looks up the alice entry in Namecoin name d/example
example.bit Looks up the root (_) entry in d/example
d/example Direct Namecoin domain namespace lookup (root entry)
id/alice Direct Namecoin identity namespace lookup

Amethyst queries the Namecoin blockchain through an ElectrumX server, resolves the name to a Nostr public key, and shows the matching user profile at the top of search results. There is a 400ms debounce on the search input to avoid flooding the server with requests.

NIP-05 Verification via Namecoin

If a Nostr profile has a .bit address in its nip05 metadata field (e.g. m@testls.bit), Amethyst will automatically verify it against the blockchain instead of making an HTTP request. The verification badge works the same as traditional NIP-05 — the only difference is the trust anchor: blockchain consensus rather than a web server.

Configuring Namecoin Settings

Navigate to Settings → Namecoin Settings in Amethyst. From here you can:

  • Enable/disable Namecoin resolution entirely
  • Add custom ElectrumX servers — useful if you run your own server for privacy
  • Remove servers from the custom list
  • Test server connectivity — checks TLS, latency, and optionally resolves a test name
  • Pin TLS certificates — after testing a server with a self-signed cert, you can pin its certificate via TOFU (Trust On First Use)
  • Reset to defaults — reverts to the built-in server list

Server String Format

When adding a custom server, use the format:

host:port          → TLS connection (default)
host:port:tcp      → Plaintext TCP (for .onion or local servers)

Examples:

electrumx.testls.space:50002
my-local-server.lan:50001:tcp
i665jpw...dsid.onion:50002

Tor Integration

If you have Tor enabled in Amethyst and have set “NIP-05 verifications via Tor” to on, all Namecoin ElectrumX connections are routed through your Tor SOCKS proxy. The server list also switches to prioritize .onion addresses:

Tor Setting Primary Server Fallback
Off electrumx.testls.space:50002 nmc2.bitcoins.sk:57002
On .onion:50002 (hidden service) electrumx.testls.space:50002 (via Tor)

Toggling Tor on or off in settings takes effect on the next lookup — no app restart needed.

Default ElectrumX Servers

Amethyst ships with these built-in servers:

Server Port TLS Notes
electrumx.testls.space 50002 Yes (self-signed, pinned) Primary
nmc2.bitcoins.sk 57002 Yes (self-signed, pinned) Fallback
46.229.238.187 57002 Yes (self-signed, pinned) IP fallback

The self-signed certificates for these servers are pinned directly into the Amethyst binary, so connections succeed even on devices with strict TLS enforcement (Samsung One UI 7, GrapheneOS).


Part 2: Registering & Updating a Namecoin Name Value

Amethyst itself is a read-only consumer of Namecoin data — it resolves names but does not write to the blockchain. To register or update a Namecoin name so that it points to your Nostr pubkey, you need to interact with the Namecoin blockchain directly using Namecoin Core (the full node software) or a compatible wallet.

Prerequisites

  1. Namecoin Core or Electrum-NMC installed and synced — download from namecoin.org (this guide uses Namecoin Core as an example)
  2. NMC (Namecoin coins) in your wallet — needed to pay registration and update fees (0.01 NMC per registration operation plus associated fees)
  3. Your Nostr hex public key — the 64-character hex string (not npub1...). You can find this in Amethyst under your profile settings or by converting your npub using a tool like https://nostrdeck.com/key-converter.php

Step 1: Choose Your Namespace

Amethyst supports two Namecoin namespaces:

Domain namespace (d/) — maps a domain-like name to one or more Nostr pubkeys. This is the most common choice and mirrors NIP-05’s user@domain format.

Identity namespace (id/) — maps a personal identity name to a single Nostr pubkey.

For most users, the d/ namespace is the right choice because it allows user@name.bit style addresses.

Step 2: Register a New Name

Open a terminal and use namecoin-cli:

# Register a name in the domain namespace
# This creates a "pre-registration" (name_new) first
namecoin-cli name_new "d/yourname"

This returns a transaction ID and a random value. Save both — you need the random value for the next step. Wait for the transaction to get at least 12 confirmations (about 2 hours).

Then finalize the registration:

namecoin-cli name_firstupdate "d/yourname" <random_value> '<json_value>'

Step 3: Set the Name Value for Nostr

The JSON value you store in the Namecoin name is what Amethyst reads to find your Nostr pubkey. There are several supported formats.

Simple Form — Single User, Root Domain

If you just want yourname.bit to resolve to your pubkey:

{
  "nostr": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"
}
namecoin-cli name_firstupdate "d/yourname" <random> \
  '{"nostr":"b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"}'

This makes yourname.bit and _@yourname.bit resolve to the given pubkey.

Extended Form — Multiple Users with Relay Hints

If you want to host multiple identities under one .bit domain (like a NIP-05 server hosting multiple users):

{
  "nostr": {
    "names": {
      "_": "aaaa000000000000000000000000000000000000000000000000000000000001",
      "alice": "bbbb000000000000000000000000000000000000000000000000000000000002",
      "bob": "cccc000000000000000000000000000000000000000000000000000000000003"
    },
    "relays": {
      "bbbb000000000000000000000000000000000000000000000000000000000002": [
        "wss://relay.example.com",
        "wss://nos.lol"
      ]
    }
  }
}

With this value stored in d/yourname:

  • _@yourname.bit or yourname.bit → resolves to the _ pubkey
  • alice@yourname.bit → resolves to Alice’s pubkey, with relay hints
  • bob@yourname.bit → resolves to Bob’s pubkey
namecoin-cli name_firstupdate "d/yourname" <random> \
  '{"nostr":{"names":{"_":"aaaa...0001","alice":"bbbb...0002"},"relays":{"bbbb...0002":["wss://relay.example.com"]}}}'

Identity Namespace Form (id/)

For the id/ namespace, the value format is simpler:

{
  "nostr": "cccc000000000000000000000000000000000000000000000000000000000003"
}

Or with relay hints:

{
  "nostr": {
    "pubkey": "dddd000000000000000000000000000000000000000000000000000000000004",
    "relays": ["wss://relay.example.com"]
  }
}
namecoin-cli name_firstupdate "id/youridentity" <random> \
  '{"nostr":{"pubkey":"dddd...0004","relays":["wss://relay.example.com"]}}'

Step 4: Update an Existing Name

To change the Nostr pubkey (or any other data) associated with an already-registered name, use name_update:

namecoin-cli name_update "d/yourname" \
  '{"nostr":{"names":{"_":"<new_hex_pubkey>","alice":"<alice_hex_pubkey>"},"relays":{"<alice_hex_pubkey>":["wss://relay.example.com"]}}}'

This broadcasts a NAME_UPDATE transaction to the Namecoin blockchain. Once confirmed, Amethyst (and any other client that supports Namecoin NIP-05) will resolve the name to the new value.

Important notes on updates:

  • Each name_update costs a small NMC fee
  • Names expire after 36,000 blocks (~36 weeks) if not updated or renewed. Amethyst checks expiry and will treat expired names as non-existent.
  • To simply renew without changing the value, you can name_update with the same value
  • Updates replace the entire value — there is no partial update mechanism

Step 5: Set Your NIP-05 in Your Nostr Profile

Once your Namecoin name is registered and confirmed on the blockchain, update your Nostr profile’s nip05 field in Amethyst:

  1. Go to your profile → Edit
  2. Set the NIP-05 field to your Namecoin address, e.g. alice@yourname.bit
  3. Save

Amethyst (and other Namecoin-aware clients) will verify this address against the blockchain and show the verification badge.

Step 6: Verify It Works

In Amethyst’s search bar, type your Namecoin identifier. You should see your profile appear at the top of results:

Test Query Expected Result
alice@yourname.bit Your profile (matched via alice entry)
yourname.bit Your profile (matched via _ root entry)
d/yourname Your profile (direct namespace lookup)

Part 3: How It Works Under the Hood

Resolution Flow

When Amethyst encounters a .bit address, here is what happens:

1. User types "alice@example.bit" in search (or a profile has it in nip05)

2. NamecoinNameResolver.parseIdentifier() parses it:
   → namecoinName = "d/example", localPart = "alice", namespace = DOMAIN

3. ElectrumXClient builds a canonical "name index script":
   OP_NAME_UPDATE(0x53) + push("d/example") + push("") + OP_2DROP + OP_DROP + OP_RETURN

4. Computes the Electrum-style scripthash:
   SHA-256(script) → reverse bytes → hex encode

5. Queries the ElectrumX server:
   → blockchain.scripthash.get_history(scripthash)
   ← [{tx_hash: "abc...", height: 814278}, ...]

6. Fetches the latest transaction (last entry = most recent name update):
   → blockchain.transaction.get(tx_hash, verbose=true)

7. Checks block headers to verify the name hasn't expired:
   → blockchain.headers.subscribe
   ← current height; if (current - update_height) >= 36000 → expired

8. Parses the NAME_UPDATE script from the transaction output:
   Extracts: name string + JSON value

9. NamecoinNameResolver.extractFromDomainValue() reads the JSON:
   Finds "nostr" → "names" → "alice" → hex pubkey

10. Returns NamecoinNostrResult(pubkey, relays, namecoinName, localPart)

Caching

Resolved names are cached in an LRU cache (default 500 entries, 1-hour TTL). Both positive and negative results are cached. The cache is keyed by the normalized (lowercased, trimmed) identifier.

Architecture Layers

The implementation is split across two modules:

Quartz (library, no Android dependencies):

  • NamecoinNameResolver — identifier parsing, value extraction, resolution orchestration
  • ElectrumXClient — TCP/TLS connection to ElectrumX, JSON-RPC, script parsing
  • NamecoinLookupCache — LRU cache with TTL
  • IElectrumXClient — interface for testing/mocking

Amethyst (Android app):

  • NamecoinNameService — application singleton, wires up caching and proxy-aware client
  • NamecoinSettings / NamecoinSharedPreferences — persistent config
  • NamecoinSettingsScreen / NamecoinSettingsSection — settings UI
  • ProxiedSocketFactory — SOCKS5 proxy routing for Tor
  • RoleBasedHttpClientBuilder.socketFactoryForNip05() — Tor-aware socket creation

The integration into NIP-05 is minimal: Nip05Client checks if an identifier matches .bit / d/ / id/ patterns, and routes to NamecoinNameResolver instead of making an HTTP fetch. Non-Namecoin identifiers are completely unaffected.


Part 4: Security Considerations

Tor integration — When enabled, all ElectrumX connections go through the Tor SOCKS proxy. The .onion server is preferred for end-to-end onion routing. Socket factory and server list are evaluated per-request via lambdas, so toggling Tor takes effect immediately.

TLS certificate pinning — The primary ElectrumX servers use self-signed certificates. Their PEM-encoded certs are pinned in the Amethyst binary. Users can pin additional certs via the TOFU flow in settings (test server → view fingerprint → confirm → pin). This is necessary because Samsung One UI 7 and GrapheneOS reject trust-all TrustManagers.

Name expiry — Namecoin names expire after ~36,000 blocks (~250 days) if not renewed. The ElectrumX client checks the current block height against the name’s last update height and treats expired names as non-existent.

Server trust — The client trusts that the ElectrumX server returns accurate transaction data. The Namecoin blockchain itself is the trust anchor — a MITM could return stale data but cannot forge name registrations. For higher assurance, SPV proof verification could be added in the future.


Quick Reference

Identifier Format Summary

User Input Namecoin Name Looked-Up Entry Namespace
alice@example.bit d/example alice Domain
_@example.bit d/example _ (root) Domain
example.bit d/example _ (root) Domain
d/example d/example _ (root) Domain
id/alice id/alice _ (root) Identity

Name Value JSON Formats

Domain simple:

{"nostr": "<64-char-hex-pubkey>"}

Domain extended (multi-user + relays):

{"nostr": {"names": {"_": "<hex>", "alice": "<hex>"}, "relays": {"<hex>": ["wss://..."]}}}

Identity simple:

{"nostr": "<64-char-hex-pubkey>"}

Identity with relays:

{"nostr": {"pubkey": "<hex>", "relays": ["wss://..."]}}

Namecoin CLI Commands

# Register a new name
namecoin-cli name_new "d/yourname"
# Returns: [txid, random_value]
# Example:
#   [
#     "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
#     "6e4a2d190f7b"
#   ]
# SAVE BOTH — you need the random value (2nd element) for name_firstupdate.
# Wait for at least 12 confirmations (~2 hours) before proceeding.

# Finalize registration with the random value from name_new
namecoin-cli name_firstupdate "d/yourname" <random> '<json>'

# Update an existing name
namecoin-cli name_update "d/yourname" '<new_json>'

# Check a name's current value
namecoin-cli name_show "d/yourname"

# List your names
namecoin-cli name_list

Getting Namecoins via DVM (NIP-90)

Don’t have NMC? You can acquire Namecoin through a Nostr-native exchange service — no centralized exchange account needed.

The NMC Exchange DVM is a NIP-90 Data Vending Machine that accepts Lightning Bitcoin (⚡ sats) or Cashu ecash (🥜) and sends NMC directly to your Namecoin address.

How it works:

  1. Send a kind:5950 job request to the DVM with your NMC address and desired amount (0.2–0.5 NMC)
  2. The DVM responds with a Lightning invoice or Cashu payment info
  3. Pay via Lightning zap or Cashu ecash
  4. Receive NMC at your designated address — the DVM sends the kind:6950 result with the NMC transaction ID

Rate: $10 USD per NMC (max 0.5 NMC per order)

Payment methods: Lightning Bitcoin ⚡ | Cashu ecash 🥜

DVM address (NIP-89):

        
Referenced article not yet available naddr1qvzqqq…d5njfjn5

View on NostrHub: NMC Exchange DVM

Example job request:

{
  "kind": 5950,
  "tags": [
    ["i", "<your-nmc-address>", "text"],
    ["param", "amount", "0.5"],
    ["bid", "10000000"]
  ],
  "content": ""
}

This is an experimental service — no guarantees of uptime, but it’s a quick way to get NMC for name registrations without touching a centralized exchange.

Testing (for Developers)

# Run unit tests
./gradlew :quartz:jvmTest --tests "*NamecoinNameResolverTest*"

# Build and install debug APK
./gradlew assemblePlayDebug
adb install -r amethyst/build/outputs/apk/play/debug/amethyst-play-universal-debug.apk

# Monitor ElectrumX connections
adb root && adb shell tcpdump -i any -nn port 50002 or port 50006

Live Test Data

The name d/testls is registered on the Namecoin blockchain with value:

{"nostr": {"names": {"_": "6cdebccabda1dfa058ab85352a79509b592b2bdfa0370325e28ec1cb4f18667d"}}}

So _@testls.bit (or simply testls.bit) resolves to Vitor Pamplona’s Nostr profile.


No comments yet.