The Sigil Name System (SNS) maps human-readable names like alice.sigil to DIDs and records (mailbox, website, weave). Registration uses a commit-reveal scheme to prevent front-running: you publish a salted hash first, wait one epoch, then reveal.

When to use this

  • Reserve a human-readable alias for your DID.
  • Bind an SNS name to your website, mailbox, or Weave node.
  • Front-run-proof registration of contested names.

Prerequisites

  • A funded DID.
  • A name that passes normalize_name (lowercase ASCII letters, digits, and hyphens; no leading/trailing hyphen).

Recipe

1

Commit

Pick a 32-byte random salt. The commitment is BLAKE3("sns/commit/v1" || name || salt || owner_did). The Rust SDK exposes sns::compute_namehash and sns::normalize_name; for other languages compute it manually.
import { blake3 } from '@noble/hashes/blake3';
import { bytesToHex } from '@noble/ciphers/utils';
import { randomBytes } from 'node:crypto';

function snsCommitment(name: string, salt: Uint8Array, ownerDid: string): string {
  const enc = new TextEncoder();
  const parts = new Uint8Array(
    enc.encode('sns/commit/v1').length + name.length + salt.length + ownerDid.length,
  );
  let offset = 0;
  for (const part of [enc.encode('sns/commit/v1'), enc.encode(name), salt, enc.encode(ownerDid)]) {
    parts.set(part, offset);
    offset += part.length;
  }
  return bytesToHex(blake3(parts));
}

const salt = randomBytes(32);
const commitment = snsCommitment('alice', salt, process.env.SIGIL_SENDER_DID!);

await signAndSend({
  RegisterUsername: {
    action: 'Commit',
    commitment,
    deposit: 1_000_000,        // refunded on reveal
  },
});

// PERSIST: { name: 'alice', salt: bytesToHex(salt) } until reveal.
Losing the salt means losing the deposit and the reservation. Persist (name, salt, owner_did) to durable storage immediately.
2

Wait one epoch

The chain enforces a one-epoch (1,000-block, ~100 min on testnet) cool-down. Query the activation status to confirm.
curl -s "$SIGIL_RPC_URL" -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_getNetworkActivationStatus","params":{}}'
Compare the returned current_epoch with the epoch in which your commit landed.
3

Reveal

The reveal includes the name, salt, and your full record set.
await signAndSend({
  RegisterUsername: {
    action: 'Reveal',
    name: 'alice',
    salt: saltHex,
    owner_did: process.env.SIGIL_SENDER_DID,
    records: {
      mailbox: 'did:oas:sigil:agent:alice...',
      website: 'https://alice.example',
      weave: null,
    },
  },
});
The chain verifies BLAKE3("sns/reveal/v1" || ...) == stored_commitment, refunds the deposit, and writes the name record.

Resolving a name

curl -s "$SIGIL_RPC_URL" -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_resolveName",
       "params":{"name":"alice.sigil"}}'
Response:
{
  "name": "alice.sigil",
  "owner_did": "did:oas:sigil:agent:alice...",
  "registered_at_height": 184201,
  "expires_at_height": 1_184_201,
  "metadata_cid": null,
  "is_reserved": false,
  "is_disputed": false
}

Common errors

SymptomCauseFix
commitment not foundReveal before commit, or wrong saltRe-derive the commitment locally and compare
cool-down not elapsedRevealed within one epochWait until current_epoch advances
name normalization rejectedDisallowed charactersStick to [a-z0-9-] and pass normalize_name first
name already reservedReserved system name (e.g. admin)Pick a different name

See also