# Verification Descriptor

A verification descriptor tells a client how to verify one ENS record. It is a
short ASCII value stored in the discovery record for that record.

```text
ensrv1 a=<authority-version> m=<method> [u=<uri>]
```

For example:

```text
ensrv1 a=1 m=https-origin.v1
ensrv1 a=1 m=account-signature.bip322.v1 u=ipfs://bafk...
```

The descriptor does not contain a claim, signature, or proof. It only selects
the rules and, when required by the method, tells the verifier where to fetch
the proof.

## Fields

| Field | Required        | Meaning                                                                                |
| ----- | --------------- | -------------------------------------------------------------------------------------- |
| `a`   | Yes             | Authority algorithm version used to find the current authority for the exact ENS name. |
| `m`   | Yes             | Immutable method identifier that defines the complete target-verification procedure.   |
| `u`   | Method-specific | Absolute URI of an external proof resource.                                            |

`u` is a location, not proof data. Version 1 does not allow inline JSON,
signatures, base64, or `data:` URIs. A method that does not need an external
location must forbid `u`.

## Format

There are only two valid shapes:

```text
ensrv1 a=<number> m=<method-id>
ensrv1 a=<number> m=<method-id> u=<absolute-uri>
```

Read every part after `ensrv1` as `name=value`:

* `ensrv1` is the exact, case-sensitive protocol identifier.
* `a` is a whole number from `1` to `4294967295`. Do not use `+`, `-`, or
  leading zeroes. For example, use `a=1`, not `a=01`.
* `m` is a lowercase method identifier ending in `.v<number>`, such as
  `https-origin.v1` or `account-signature.bip322.v1`. Each dot-separated name
  starts with a letter, may contain letters, digits, and hyphens, and ends with
  a letter or digit.
* `u`, when the method requires it, is an absolute URI as defined by
  [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986.html). It must include a scheme,
  such as `https://` or `ipfs://`.

The complete descriptor is at most 2,048 ASCII bytes. `m` is at most 64 bytes
and `u` is at most 1,024 bytes.

## Encoding Rules

* Use exactly one ASCII space between tokens.
* Do not use leading or trailing whitespace, repeated spaces, tabs, or line
  breaks.
* Emit fields in `a`, `m`, `u` order.
* Treat field order as semantically irrelevant when parsing.
* Include `a` and `m` exactly once. Include `u` only when the selected method
  requires or permits it.
* Reject duplicate fields, unknown fields, empty values, non-ASCII bytes, and
  unsupported versions or methods.

For `u`, split the token on its first `=` so `=` can still appear inside the
URI. The URI must be absolute and must not contain user information or a
fragment. Each method explicitly lists its allowed URI schemes and retrieval
rules. A verifier must reject every scheme the method does not list.

## Parser Procedure

1. Apply the byte and ASCII limits before tokenizing.
2. Require the exact case-sensitive prefix `ensrv1`.
3. Split on single ASCII spaces, then split each field on its first `=`.
4. Reject missing, empty, duplicate, or unknown fields.
5. Validate `a`, `m`, and the optional `u` using the rules above.
6. Load the exact authority and method versions. Do not fall back to an older
   interpretation.
7. Apply the method's `u` policy and URI retrieval rules.
8. Require the fetched proof envelope to contain exactly `"v": "ensrv1"`.

## Open Issues

<Accordion>
  <AccordionItem>
    <AccordionTitle>How are authority versions registered?</AccordionTitle>

    <AccordionContent>
      `a` isolates ENS authority changes from the rest of the protocol, but the
      registry and migration process are not yet defined. Before publication, the
      specification needs one canonical registry describing each version, its ENS
      deployments, evaluation rules, and activation policy.

      Version 1 can describe current ENS contracts. A future ENS architecture should
      allocate a new value only when the rule for finding the exact-name authority
      changes; it should not require a new descriptor grammar or method version.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>How are method identifiers allocated?</AccordionTitle>

    <AccordionContent>
      Method identifiers must be globally unambiguous because `m` selects security
      rules and is signed in the common claim. The remaining question is who assigns
      names and how experiments avoid colliding with permanent methods.

      The registry should record the immutable identifier, supported record types,
      descriptor field policy, proof schema, result relationship, and normative
      specification. Changing verification semantics must allocate a new version.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Should one record advertise multiple methods?</AccordionTitle>

    <AccordionContent>
      Version 1 selects exactly one method. Multiple methods need explicit semantics:
      all required, any accepted, ordered fallback, or client choice. Encoding a list
      before those semantics are defined would make clients disagree about what a
      positive result means.

      If a real use case needs composition, it should be added in a new descriptor
      version with a defined result and downgrade policy.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Which external URI profiles belong in version 1?</AccordionTitle>

    <AccordionContent>
      The base grammar can validate an absolute URI, but interoperable fetching needs
      scheme-specific rules. HTTPS needs redirect, TLS, network-address, media-type,
      size, and decoding limits. IPFS needs a canonical CID form and exact byte
      retrieval rules.

      Each initial method must finish those rules before the protocol is frozen.
      Schemes such as `http`, `data`, `file`, `javascript`, `blob`, `ftp`, and
      unregistered content-addressing schemes remain unsupported unless a future
      method defines their security model.
    </AccordionContent>
  </AccordionItem>
</Accordion>

## Decisions

<Accordion>
  <AccordionItem>
    <AccordionTitle>Why use compact key-value text instead of JSON or binary?</AccordionTitle>

    <AccordionContent>
      The descriptor is stored in an ENS text record and contains only two required
      values plus one optional URI. A small key-value grammar is readable in wallets,
      cheap to publish, and simple to parse.

      JSON adds quoting, escaping, Unicode, and duplicate-member behavior for no
      needed structure; [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.html) notes that
      duplicate names produce unpredictable behavior across implementations. Binary
      formats such as CBOR would need another text encoding and would make records
      harder to inspect.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Why use spaces instead of semicolons or query syntax?</AccordionTitle>

    <AccordionContent>
      A raw space cannot occur inside an RFC 3986 URI, so it is an unambiguous field
      separator. Semicolons are valid reserved URI characters and would need escaping
      or context-sensitive parsing. Query syntax introduces `&`, `=`, percent
      encoding, and nested-URI encoding rules without reducing the record size.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Why are descriptor, authority, and method versions separate?</AccordionTitle>

    <AccordionContent>
      They change for different reasons:

      * `ensrv1` versions the descriptor grammar and common protocol.
      * `a=1` versions the algorithm for finding current ENS authority.
      * the final part of `m`, such as `.v1`, versions one verification method.

      An ENS authority migration should not rename every proof method. A change to
      Bitcoin signature validation should not change HTTPS verification. Separate
      versions keep those upgrades isolated and make unsupported behavior fail
      closed.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Why are the field names only one letter?</AccordionTitle>

    <AccordionContent>
      Every byte is stored in an onchain text-record value, and the fields have fixed
      meanings in the versioned grammar. `a`, `m`, and `u` keep repeated descriptors
      small without making the value opaque. SDKs should expose descriptive property
      names such as `authorityVersion`, `method`, and `proofUri`.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Why can `u` contain only an external location?</AccordionTitle>

    <AccordionContent>
      Keeping proof bytes outside ENS avoids large record values and supports normal
      proof renewal without rewriting the descriptor. It also gives every method one
      clear transport boundary with explicit size and security limits.

      Inline `data:` or base64 values mix location and payload, expand the ENS value,
      and add another decoding path. A signature itself is still proof data, so it
      belongs in the method's proof envelope rather than in `u`.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Why is there no descriptor hash field?</AccordionTitle>

    <AccordionContent>
      An earlier descriptor design included this field:

      ```text
      ensrv1 a=1 m=<method> u=<proof-uri> h=0x<64-hex-digits>
      ```

      `h` was the Keccak-256 hash of the exact proof file bytes fetched from `u`. Its
      purpose was to pin a mutable URI to one specific file. If the server returned
      different bytes, their hash would not equal `h`, so the verifier would reject
      them before parsing the proof.

      That byte pin is not needed for the current verification model. A verifier does
      not trust a proof merely because its bytes match `h`. It parses the proof,
      compares the complete claim with live ENS state, and validates the authority
      signature and all method-specific target evidence. Replacing the file with
      unsigned or altered data therefore cannot create a valid result.

      The target side is also covered by each method:

      * HTTPS verification fetches the proof from the exact origin derived from the
        live record.
      * Account verification requires the target account's signature.
      * An IPFS CID already commits to the exact resource bytes.
      * DNS verification stores the complete proof envelope in its
        DNSSEC-authenticated TXT record. The live DNS publication is
        target-controlled evidence, not a descriptor hash.

      Keeping `h` in ENS would also make routine renewal expensive. New timestamps
      and signatures change the proof file bytes, which changes `h`; the publisher
      would have to update both the external file and the ENS record every time.
      Without descriptor `h`, a valid proof can be renewed at the same location
      without an ENS transaction.

      Therefore `h` is not a general descriptor field. If a method needs an exact
      byte commitment, it must define that commitment inside its own
      target-controlled evidence.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Why reject unknown fields instead of ignoring them?</AccordionTitle>

    <AccordionContent>
      A future field may add a security requirement. If an older verifier ignores it,
      the same descriptor can mean something different to two clients. Closed parsing
      forces incompatible changes to use a new `ensrv` version, where unsupported
      clients return a non-positive result.
    </AccordionContent>
  </AccordionItem>

  <AccordionItem>
    <AccordionTitle>Why accept reordered fields but emit one order?</AccordionTitle>

    <AccordionContent>
      Field order does not change descriptor meaning and the descriptor is not signed
      or hashed as one byte string. Accepting reordered fields avoids rejecting an
      otherwise identical value, while canonical `a`, `m`, `u` output keeps records
      consistent and easy to compare. Duplicate fields remain invalid in every order.
    </AccordionContent>
  </AccordionItem>
</Accordion>

See [Method Profiles](../methods/overview) for method-specific `u` rules.
