LNS — LEZ Name Service: .lez names, private by default

LNS — LEZ Name Service: .lez names, private by default

Posting as a suggested RFP. Feedback welcome; I’d be glad to apply if it becomes one.

What it is

Human-readable names for the Logos Execution Zone: pay alice.lez instead of a 32-byte account ID.

  • Private by default. A name carries private receiving keys. Paying alice.lez sends a private transfer: the chain shows neither recipient nor amount, and the payer never learns an account, balance or history. Paying from a private account hides the payer too.
  • Public by choice. A holder who wants an openly payable name (a shop, a project, donations) can publish a public address on it instead, or as well.
  • The chain never sees names. A name becomes an identifier and a key on your machine; the chain stores only the identifier and an encrypted record. Nobody can list or browse names, unless a holder opts in.
  • Optional public listing. A holder can list a name in an on-chain directory so people can find and browse it, even if payments to it stay private.
  • Hidden holders. The chain keeps a per-name tag of the holder, so two names of the same person can’t be linked, and a holder using a private account never appears on chain.
  • Records: text entries (chat, inbox, agent) and a page per name.
  • Logos Chat usernames backed by LNS (see ideas #43): a chat username can be an LNS name, which gives it uniqueness from the LEZ registry. A name’s chat entry points at the holder’s chat address, so typing alice.lez in a chat app opens a conversation with the right person, and the app can show the name as verified when the record points back at the sender. Opt-in per name.
  • No server in between. The client talks to the LEZ sequencer directly and reads the registry’s program from the chain to prove private changes.

A working prototype is live on the LEZ testnet (registry 66nUvzJtTxA729aUpTcAWDrb7cV9Heb2bDzceHQhLYad):

curl -fsSL https://logos-names.wrapit.workers.dev/install.sh | sh
names resolve jef.lez

Code (MIT/Apache-2.0): GitHub - jefdiesel/logos-names: Name registry for the Logos Execution Zone: wallet aliases, text records and pages by name · GitHub. The spec is in SPEC.md.

Why

People can’t use 32-byte account IDs, so every chain grows a name service. The existing ones (ENS, SNS, Handshake) only map names to public addresses, so a name becomes a permanent public label on an account, and anyone can list every name and owner. On a privacy chain that should be a choice, not the only option. LEZ’s private accounts make private names possible, and LNS keeps public names for the cases that want them.

What exists

  • ENS / SNS / Handshake: public directories. Names, owners and addresses are all public.
  • ENS + stealth addresses (Umbra, EIP-5564): payments to a name go to one-time addresses, but the name and its owner are still public.
  • This prototype: register, renew, transfer, release, private payments to a name (tested end to end from a fresh install), private holders, names bridge from the Logos Blockchain, and an MCP server for AI agents. Built in about two days.

Scope (suggested RFP)

Full spec, in Logos RFP format (tier S, 2–3 weeks): logos-names/docs/RFP-private-naming.md at main · jefdiesel/logos-names · GitHub

In short:

  1. Names never reach the chain (slow client-side derivation; identifier plus encrypted record).
  2. Private by default: receiving keys made at registration; payments to them are private.
  3. Public by choice: a holder can publish a public address on a name, and can list a name in an opt-in directory (payments can stay private).
  4. Hidden holders behind per-name tags.
  5. Register / renew / transfer / release with terms, expiry, grace period and fees to a treasury.
  6. Logos Chat usernames backed by LNS names.
  7. Clients talk to a LEZ sequencer directly; no gateway, faucet or indexer required.
  8. CLI, SDK (Rust and JS), MCP server, and a spec that other wallets can implement.

Future ideas: a website at every name (alice.<gateway domain>), and subnames such as pay.alice.lez.

Risks and deployment

  • Proof time: a private transfer takes about 3.5 minutes to prove on an M4 Mac, all on CPU (RISC Zero 3.0.5 has its Apple GPU backend disabled). About 2 min is the circuit, about 47 s a Keccak proof and about 47 s recursion. Faster proving in LEZ would help every private app.
  • Unlisted names can be checked one at a time: anyone who types an exact name sees that it exists, when it was last changed and what its holder published. A private name shows no address, balance or payment history. A name with a public address shows that address, and so its balance and history, to anyone who looks it up; that’s the holder’s choice.
  • Funding: bridging from the Logos Blockchain takes about 12 hours on today’s testnet (finality).
  • Testnet resets wipe names; the registry gets redeployed with a migration path.
5 Likes

This is cool! Could it be also used alongside Logos Storage for “websites” - I have this “logos storage data” viewer which also renders markdown (x link), so instead of pasting a CID to fetch, I could paste vpavlin.lez and you’d get HTML or Markdown with my “profile page” or something like that?

Apparently this is already supported:)

Also here is a report from my reviewer agent: LNS — LEZ Name Service: full review :slight_smile:

Cool stuff:-)

1 Like

yeah URL was planned, i did think that subdomains on a public domain would be nice ie jef.logos.co or a neutral community site. but onchain md could be more suitable for the project

thanks for the reviewer agent report! very helpful and tackling those now.

1 Like

Thanks for the review, it was useful. Both blockers are fixed in registry v4.1, now live on the LEZ testnet as 2PXg3SSmh5hvECTz4xcfV2d5YvxwyF6yVhpnjTokzCkX (it replaces 66nUvz…LYad).

Front-running on Register (1.1): registration is now commit-then-reveal. Commit publishes only SHA256("logos-names/v4/commitment" ‖ id ‖ owner_tag ‖ secret), so the name, the holder and a random secret stay hidden. Register reveals them and consumes the commitment. A commitment must be at least 15 minutes old and at most 24 hours old before it can be revealed. A reveal someone sees in the mempool is useless to them: it is bound to the committer’s owner tag, and their own commitment would be too new. Unit tests in core/src/lib.rs cover this: a_seen_reveal_cannot_be_replayed_for_another_account, a_reveal_waits_for_its_commitment_to_age, a_reveal_without_a_commitment_is_refused, an_old_commitment_cannot_be_revealed, a_live_commitment_cannot_be_reset.

Configure deploy race (1.2): the first Configure must be signed by the program’s own header account, which only the deployer holds during deployment. Tests: nobody_but_the_deployer_configures_a_fresh_registry and the_deployer_configures_a_fresh_registry_and_then_only_its_admin. On a test chain (v4, same code paths; v4.1 only widened the time windows so private proofs fit), a stranger’s Configure on a fresh deploy was refused.

Write flows end to end (4.1): all done today on the official testnet, by fresh wallets made with the released CLI, every action from a private account:

  • register by commit, then reveal (jef.lez, logos.lez and a new user’s name);
  • transfer to another wallet’s private account (block 23088);
  • the old holder’s release refused after the transfer;
  • the new holder taking over with fresh receiving keys (block 23131);
  • release, after which the name resolves as not registered (block 23159).

Fixed salt (1.3): your numbers were, if anything, generous to us. At hashcat’s PBKDF2-SHA256 rate on an RTX 4090, five million common names take about a minute, and the fixed salt means that dictionary works against every registry. SPEC §1 now says so plainly. A memory-hard KDF (Argon2id) is the real fix, planned for the next registry version.

Owner tags (1.4): SPEC §1 now says plainly that the holder of a name held from a public account can be found after the fact, by testing public accounts against the tag. A private-account holder stays hidden, which is why names are held privately by default.

The gateway (1.5, 1.7): the website no longer resolves names at all; it is static files. Pages are viewed with names open <name>, which reads the page from the chain on the viewer’s machine and serves it on 127.0.0.1, under a policy that loads nothing from the network (SPEC §12.2). §12.3 specifies resolving in the browser once sequencers allow cross-origin requests: the name goes after #, and nothing relays.

Installer (1.8): releases are now signed (ed25519, ssh-keygen -Y), and install.sh refuses a missing or bad signature.

Websites on Logos Storage: yes. A name can carry a cid text entry, so your viewer can take vpavlin.lez, resolve it in the client (JS resolver in resolver/; in a browser that needs the testnet RPC to allow CORS, which I asked for in Allow browser access (CORS) on the LEZ testnet RPC · Issue #992 · logos-blockchain/logos-execution-zone · GitHub), and fetch that CID from Logos Storage. Would that work for you?

Would you be up for a re-review of v4.1?

1 Like