Discussion: https://github.com/dogecoin/dogecoin/discussions/4056
Draft DIP: 353 Layer: Applications Title: Email Payment Addresses for Dogecoin Author: Paulo Vidal | github.com/qlpqlp | x.com/inevitable360 Comments-Summary: No comments yet. Comments-URI: https://github.com/dogecoin/dogecoin/discussions Status: Draft Type: Standards Track Created: 2026-09-06 License: MIT Requires: BIP 21 (adapted as dogecoin: URIs)
Copyright
This DIP is licensed under the MIT license.
Abstract
This DIP specifies how a Dogecoin wallet turns an email-style identifier (user@domain) into a Dogecoin payment address using DNS TXT records and DNSSEC. The wallet uses only:
- the identifier the payer typed
- public DNS
- this specification
The wallet MUST NOT need an account, an API key, a vendor HTTP endpoint, or knowledge of any mail-forwarding inbox.
The domain in the identifier is the zone the wallet queries. There is no seed list, no bootstrap hostname, and no phone-number identifier in this specification.
This is the Dogecoin counterpart to BIP 353 (DNS Payment Instructions). BIP 353 stores a plaintext bitcoin: URI at a DNS label derived from the local-part. This DIP keeps the same motivation: a DNSSEC-backed name that wallets can resolve without a vendor API. The on-the-wire format already deployed as PMD-1 is specified below.
Trust model
Read this before the byte format.
DNSSEC authenticates the zone, not a person. If Alice publishes records on a zone she controls, a validating wallet learns what that zone signed. If Alice asks a registrar (including a hosted product such as PayMeDoge) to publish records on its zone, she trusts that operator the same way she trusts a DNS host. This DIP does not remove that trust. It names it.
The sovereign path is the one BIP 353 reviewers already know: the payee publishes a DNSSEC TXT on a zone they control. A hosted registrar is optional convenience for people who do not run DNS. It is not a required hop. Wallets MUST resolve alice@example.net from example.net, not from a third-party directory.
Hashed DNS labels in this DIP are not secret names. DNS has no secret entries. Anyone who knows the identifier can compute the label. Anyone who can guess common local-parts can query those labels. The hash only stops a zone transfer from listing alice, shop, and tips in the clear. That is not a confidentiality mechanism and MUST NOT be described as one.
Encryption in this DIP is not privacy from the zone operator, and not privacy from someone who already knows or can guess the identifier. The operator who published the record already has the mapping. The encryption only stops a casual dig of a hashed name from printing a Dogecoin address. Version 1 does not provide strong confidentiality of that address against a motivated attacker.
Motivation
Dogecoin addresses are long Base58Check strings. People already share email addresses. Wallets, shops, and exchanges need a way to turn user@domain into a Dogecoin address without a central HTTP API and without trusting an unsigned resolver.
The DNS already provides a global namespace. With DNSSEC it provides a proof from a single trusted root. Recursive resolvers are everywhere, so a payer's IP address is usually not sent to the payee.
This model was first shown for Dogecoin in 2022 as a plaintext TXT on the payee's own domain (see History). BIP 353 later specified a related model for Bitcoin. This DIP is the Dogecoin wallet standard for that idea, with PMD-1 as the record format.
History
The idea of mapping a memorable name to a Dogecoin address through a DNS TXT record started in early 2022, by the author of this DIP (Paulo Vidal, @inevitable360).
The first public working flow was posted on 21 October 2022:
That thread showed a domain owner adding one TXT of the form dogecoin:<address>, then a resolver turning that domain into a pay URI. A live prototype remains at what-is-dogecoin.com/inevitabledomains.
That first form is the sovereign path: the user defines the TXT on their own DNS. A shop that already has a domain can still use it. The same flow is in production on ShibeShip.com: the buyer types an email or domain, the shop looks up the TXT, and the Dogecoin address is filled in. No vendor payment API is required.
PMD-1 is a later record format for hosted names on a registrar zone: hashed lookup labels (so a zone transfer is not a public directory of local-parts) and an encrypted payload (so a casual listing of a hashed name does not print the address). Authenticity is still DNSSEC. BIP 353 (assigned February 2024) is a parallel Bitcoin standard. It is not the origin of this work.
Relationship to BIP 353
This is not a line-by-line patch of BIP 353. The dogecoin/dips README says a DIP should only make minor changes to a BIP, and that a larger divergence should be filed as a standards-track RFC. This draft is numbered DIP 353 so reviewers can read it next to BIP 353. Maintainers may refile it as an RFC if they prefer that process.
Kept from BIP 353:
- DNS TXT as the publication channel
- DNSSEC as the authenticity requirement
- human-readable
user@domainidentifiers - wallets MUST prefer a raw address or a direct payment URI when one is already available
- CNAME / DNAME are allowed when the whole chain is DNSSEC-signed
- cache lifetime is bounded by the signed TTL
Different, and why:
| BIP 353 | This DIP (PMD-1) | Reason |
|---|---|---|
user.user._bitcoin-payment.domain |
_pmd.e.<base32(sha256(id))>.domain |
A zone transfer of a busy registrar zone should not list every local-part. The label is computed from the identifier. It is not a secret. |
Plaintext bitcoin: URI |
AES-256-GCM ciphertext of a JSON payload | A casual dig of a hashed name should not print the address. This is obfuscation, not confidentiality from the zone operator or from someone who knows the identifier. |
| Bitcoin / Lightning URIs | Dogecoin P2PKH, net=doge |
Dogecoin mainnet only in version 1. |
A wallet that only implements BIP 353 will not resolve a PMD-1 record, and a wallet that only implements this DIP will not resolve a BIP 353 record. The two schemes can coexist on the same domain because they use different owner names. A zone MAY also publish a BIP 353-style plaintext dogecoin: URI for Bitcoin-family wallets. That record is out of scope here.
Specification
General rules for handling
Dogecoin wallets MUST NOT prefer DNS-based resolving when a Dogecoin address or a direct dogecoin: URI is already available and would suffice.
Wallets MUST NOT call a vendor HTTP API to resolve an identifier defined by this DIP. DNS-over-HTTPS is an allowed transport for the DNS query. It is not a substitute for this specification.
The forwarding inbox of a mail service, if any, is out of scope. It MUST NEVER appear in a DNS record specified here.
Wallets MUST NOT query a seed list, a bootstrap hostname, or any directory of operators to resolve user@domain. The domain in the identifier is the zone.
Identifiers
This DIP defines one identifier kind: email. A telephone number has no DNS domain. Mapping E.164 to a payment record would require wallets to know which zone to query (a discovery step similar to DNS seeds for finding peers). That is not part of this DIP. See Out of scope.
An email identifier is local@domain. Implementations MUST accept any domain an operator publishes, not only a single vendor zone.
Canonicalization (every implementation MUST produce the same UTF-8 bytes):
- Trim surrounding ASCII whitespace.
- Split on the last
@. Reject if it is missing, leading, or trailing. - Reject if local or domain contains a space.
- NFC-normalize local and domain if a Unicode normalizer is available. If not, the input MUST already be NFC.
- Lowercase ASCII
A-Zonly, in both local and domain. Do not apply locale-specific case folding. - Do not strip Gmail dots. Do not remove
+tags. Do not invent mailbox-provider rules. - If the domain contains a non-ASCII code point, convert it with IDNA ToASCII (UTS #46). Then lowercase the ASCII result.
- Reject an empty local, an empty domain, or a domain with no
.. - Join as
local + "@" + domain.
If the trimmed input starts with +, implementations MUST reject it as unsupported in this version. If it contains no @, implementations MAY try an include at _pmd.<input> (see below). Otherwise reject.
DNS naming
The payment TXT is not placed at a hostname that contains the local-part.
H = SHA-256(UTF-8(canonical_identifier)) label = lowercase Base32(H) # RFC 4648 alphabet, no padding
Base32 alphabet: abcdefghijklmnopqrstuvwxyz234567.
Process the 256-bit digest as a bit string, left to right, in 5-bit groups. Pad the last group with zeros if needed. The label is 52 characters.
_pmd.e.<label>.<zone>
<zone> is the domain from the identifier (example.net for alice@example.net). Each label is under 63 characters.
A human pay page at {local}.{zone} (for example alice.paymedoge.com) MAY exist. That page is not part of wallet resolution and MUST NOT be used as the lookup name.
Custom domain include
A person who uses their own domain as an alias, while the payment TXT lives on another zone, publishes a TXT at _pmd.<their-domain>:
v=pmd1;include=alice@paymedoge.com
A wallet that is asked to resolve pay@shop.example.com (or only shop.example.com) SHOULD:
- Query TXT at
_pmd.shop.example.com(and, if needed,_pmd.example.com). - If the record is an include, canonicalize the included identifier and resolve that identifier as specified below (at most three hops; stop if a loop is detected).
- If there is no include, treat
shop.example.comas the zone and open the hashed PMD-1 TXT forpay@shop.example.comon that zone. - Refuse the payment if any of those answers lacks DNSSEC.
The include value MUST be an email identifier as defined above. It MUST NOT be a forwarding inbox.
v=1 is accepted as an alias of v=pmd1 on include records only.
Following an include means the payer trusts the included zone the same way they would if they had typed that email to begin with.
Encryption
Suite: AES-256-GCM + HKDF-SHA-256.
Implementations MUST NOT invent a custom cipher.
Key derivation:
IKM = UTF-8(canonical_identifier) salt = 16 random bytes, unique per record info = "PMDv1|e" (ASCII) L = 32 key = HKDF-SHA-256(IKM, salt, info, L)
The identifier is a weak secret. The random salt stops rainbow tables. It does not stop guessing a specific record. See Security.
AEAD:
- Algorithm: AES-256-GCM
- Nonce: 12 random bytes, unique per record
- Tag: 16 bytes
- AAD: UTF-8 of the lookup FQDN (no trailing dot)
- Plaintext: compact JSON, no extra spaces
{"v":1,"net":"doge","a":"DQHWoQW4X36fSNSAPeDMbvef15ujtN6S8K"}
net is doge for Dogecoin mainnet. The payload MUST NOT store a forwarding email, a phone number, a display name, or a private key.
Version 1 a MUST be a Dogecoin mainnet P2PKH address: Base58Check, version byte 0x1E, typically 34 characters starting with D. Wallets MUST reject any other address type in version 1.
Ciphertext c is AES-GCM output including the 16-byte tag.
TXT record
One logical TXT value:
v=1;enc=A256GCM;kdf=HKDF-SHA256;s=<b64url>;n=<b64url>;c=<b64url>
| Field | Meaning |
|---|---|
v |
Protocol version. 1 for this DIP |
enc |
A256GCM |
kdf |
HKDF-SHA256 |
s |
salt, base64url, no padding |
n |
nonce, base64url, no padding |
c |
ciphertext plus tag, base64url, no padding |
Base64url is RFC 4648 section 5.
The TXT RR's RDATA MUST consist of one or more DNS <character-string>s (RFC 1035 §3.3.14), each ≤255 bytes. Clients MUST reconstruct the protocol string by concatenating those fields in RDATA order, without inserting separators, before parsing. Clients MUST NOT concatenate across multiple TXT RRs at the same owner name.
Clients MUST ignore any TXT record at the same label that does not begin with (ignoring case) v=1;enc=. Clients encountering multiple matching TXT records at the same label MUST treat the records as invalid and refuse to use any payment instructions therein.
The record MUST NOT contain the forwarding email, the plaintext identifier, a user name, an IP address, a private key, or DNS API credentials.
All payment instructions MUST be DNSSEC-signed.
Payment instructions MAY resolve through CNAME or DNAME records as long as all such records and the ultimate records pointed to by them are DNSSEC-signed.
Resolution
resolve(user@domain) -> Dogecoin address
- Validate and canonicalize the email identifier.
- Let
zonebe the domain part. - Query TXT
_pmd.<zone>(DNSSEC). If it is an include, follow it (at most three hops) and restart from step 1 with the included identifier. - Compute
label = Base32(SHA-256(canonical)). - Query TXT
_pmd.e.<label>.<zone>(DNSSEC). - Refuse the record if authentication fails. Do not decrypt a TXT that did not pass DNSSEC.
- If there is no TXT, fail with
not_found. - Parse the PMD-1 fields. Reject unknown
v,enc, orkdf. - Derive the HKDF key. Decrypt AES-256-GCM using AAD = lookup name.
- If the tag fails, fail with
decrypt_failed. - Parse JSON. Require
v=1,net=doge, and a Dogecoin P2PKH address that passes Base58Check (version0x1E). - Return the address. Optionally also return
dogecoin:<address>.
Clients MUST NOT trust a remote resolver to validate DNSSEC records on their behalf unless that resolver is a local validating stub the user already trusts for all DNS. A wallet that uses DNS-over-HTTPS MUST require the Authenticated Data (AD) flag and MUST treat a missing AD flag or SERVFAIL as failure.
Clients MUST NOT accept DNSSEC signatures which use SHA-1 or RSA with keys shorter than 1024 bits. Resolvers MAY accept SHA-1 DS records.
While clients MAY cache the payment instructions they receive from the DNS, clients MUST NOT cache them for longer than the TTL provided by their DNS resolver, and further MUST NOT cache them for longer than the lowest initial TTL (which is signed as a part of DNSSEC signatures) received in the full DNSSEC chain leading from the DNS root to the resolved TXT record.
Errors
| Code | When |
|---|---|
invalid_identifier |
Canonicalization failed, or a phone number was supplied |
not_found |
No TXT at the lookup name |
unsupported_version |
v is not 1 |
unsupported_suite |
enc or kdf is unknown |
decrypt_failed |
GCM tag mismatch or malformed ciphertext |
invalid_payload |
JSON missing fields or bad address |
unauthenticated |
DNSSEC validation failed |
Address reuse and TTL
Recommended TTL:
| Event | TTL |
|---|---|
| Normal published record | 300 seconds |
| Shortly after an address change | 60 seconds |
| Emergency replacement | 60 seconds |
| Account deletion | Delete the record. Caches may keep the old value until the previous TTL expires |
Payment instructions with on-chain addresses which will be reused SHOULD be rotated as regularly as practical. Operators who need a faster cut SHOULD lower TTL before a planned change.
There is no instant global revocation on the public DNS.
Display
When displaying a verified human-readable name, wallets SHOULD show the identifier the user typed after canonicalization, for example alice@paymedoge.com.
Wallets MAY prefix an email identifier with Ð, i.e. Ðuser@domain, to reduce confusion with ordinary email. They SHOULD parse recipient information in both user@domain and Ðuser@domain forms. The Ð is not included in the identifier that is hashed or in the DNS label which is resolved.
Wallets providing the ability for users to "copy" their address information SHOULD copy the underlying dogecoin: URI directly, rather than the human-readable name. This avoids an additional DNS lookup by the application in which it is pasted. Wallets that nevertheless provide users the ability to copy their human-readable name MUST copy the canonical identifier (and, if they use the Ð prefix, MUST include it).
Record control (registries)
This section is for a registry or operator that publishes PMD-1 records. Payment-resolving wallets do not implement it.
If the payee publishes on their own zone, they already control mutations through their DNS account.
If the payee uses a hosted registrar, two acts MUST be kept separate:
| Act | Who | What it proves |
|---|---|---|
| Pay | Anyone | The name stays live. Coins go to the published address. |
| Edit or close | The holder of the keys for the published address | Authorization to mutate the record. |
A payment received from any Dogecoin wallet MAY be accepted as consideration for creating or renewing a name. That payment MUST NOT be treated as authorization to change the Dogecoin address, change the forwarding inbox, change the include target, or delete the name.
To mutate a live record, the registry MUST verify a compact recoverable ECDSA signature over a challenge, using the address already published for that identifier.
- Magic prefix:
Dogecoin Signed Message:\n, as implemented by Dogecoin Coresignmessage/verifymessage. - Challenge: a short, exact UTF-8 string that names the identifier, for example
PayMeDoge edit alice@paymedoge.com. - Signature: 65-byte compact recoverable signature, Base64.
- Verification MUST recover the public key and check that the resulting P2PKH address equals the published address.
If the signature does not match, the registry MUST refuse the mutation. There is no administrative override in this specification.
A registry MAY expire and delete a record after a published unpaid grace period. That is a billing event, not a signature event. Renewal payment MAY come from any wallet.
A compromised or malicious zone operator can replace the TXT and redirect the next payment. DNSSEC will still validate, because the zone key is theirs. Users who do not accept that risk MUST publish on a zone they control.
Security
What DNSSEC provides
Encryption does not prove that the record belongs to the zone owner. A lying resolver can return a record the attacker encrypted with the same identifier. DNSSEC is what authenticates the zone.
| Property | What provides it |
|---|---|
| DNS authenticity | DNSSEC. Required. |
| Confidentiality | Weak. Identifier-derived key. Not confidentiality from the zone operator. |
| Payload integrity after decrypt | AES-GCM tag, bound to the lookup name as AAD. |
If DNSSEC validation fails, the wallet MUST refuse to pay. Do not fall back to an unsigned answer.
The hard limit
The encryption key is derived from the identifier.
Email addresses have low entropy. Anyone who can read a TXT record, or enumerate possible identifiers and query DNS, can try identifiers offline until decryption succeeds.
Version 1 does not provide strong confidentiality of the Dogecoin address against a motivated attacker.
It does:
- hide the local-part from the DNS hostname
- hide the address from a casual
digreader who does not try the identifier - bind the ciphertext to the lookup name (AAD)
- stop precomputed rainbow tables via a per-record salt
It does not:
- stop someone who already knows
alice@example.comfrom decrypting Alice's record - stop bulk guessing of common names
- hide the mapping from the zone operator who published it
- replace DNSSEC
- create secret or unenumerable DNS names
Sharing alice@example.com is sharing a payment pointer. This is not anonymous payment infrastructure.
DNS enumeration
The hostname is a hash, so a zone transfer is a list of hashes, not names. Guessing still works from the identifier side.
Those wishing to avoid enumeration should treat every published name as a public payment pointer.
Private DNS querying
A recursive resolver sees the lookup name (a hash), not the identifier. DoH hides the query from the local network but not from the DoH operator. For the best privacy, payers are encouraged to perform DNS resolution over Tor or another VPN technology.
The authoritative server for the zone sees which hashed labels are queried. That is ordinary DNS logging. This DIP does not claim query unlinkability against the zone operator.
Compromised zone
An attacker who controls the DNS provider or the zone key can replace or delete records. Users should treat a sudden address change as suspicious. There is no timestamp inside the version 1 payload. Replay of an old address is the same as a stale cache.
Rationale
Hashed names rather than BIP 353 labels
BIP 353's user.user._bitcoin-payment.domain is easy to type and easy to audit. It also publishes every local-part in the zone. Registrar names are often short (shop, tips, alice). Putting them in the hostname would make that zone a public directory. Hashing costs one SHA-256. It does not make the name secret.
Encryption rather than a plaintext URI
BIP 353 stores a BIP 21 URI in the clear so hardware wallets can show it after checking DNSSEC alone. PMD-1 adds a decrypt step so a casual listing of a hashed name does not print an address. The authenticity of the publication is still DNSSEC. The GCM tag only proves the payload was sealed for that lookup name with a key derived from the identifier the wallet already has.
A hardware wallet MAY refuse PMD-1 and accept only a plaintext dogecoin: URI on a user-controlled zone. That is compatible with this DIP: this DIP MUST NOT be the only way to pay Dogecoin.
Payment versus keys
A common mistake is to treat "the coins arrived from address X" as "address X owns this name". Anyone can send Dogecoin. Only the holder of the registered keys can sign Dogecoin Signed Message:\n. Registries that collapse those two acts let a payer take over a name.
DNS rather than HTTP
HTTP(S) resolution reintroduces a TLS certificate-authority dependency, leaks the payer's IP address to the payee or an intermediary, and usually needs a vendor-specific API. DNS plus DNSSEC avoids all three for the resolve path.
No seed directory
A seed or peer list would put a well-known operator in the wallet resolve path. Email identifiers already name a DNS zone. Wallets query that zone. Independent operators publish PMD-1 on their zone. They do not need to copy another operator's payment records, and wallets do not need a directory to find them.
Out of scope
Telephone numbers. An E.164 number has no DNS domain, so this specification does not define phone identifiers. A later optional idea would need wallets to know which zones hold those records (a discovery problem, like Bitcoin DNS seeds). That is not proposed here. This specification is complete for email identifiers.
A directory of operators (_pmdseeds, bootstrap hostnames, HTTP announce). Not used for wallet resolve. Not specified here.
Mail forwarding. A different product feature. Never in DNS.
Backwards Compatibility
This work does not change the Dogecoin consensus rules.
Existing wallets that only accept a raw address or a dogecoin: URI continue to work. They MAY add this DIP as an additional input method.
A zone MAY also publish BIP 353-style records for Bitcoin wallets under _bitcoin-payment. Those records are out of scope here.
Version 1 payloads accept only P2PKH. A later version MUST use a new v and a new HKDF info string. Wallets MUST ignore unknown versions rather than guess.
Test vectors
These vectors use fictional data only. They are the official version 1 vectors. Implementations MUST match them before shipping.
Zone: paymedoge.com
Address: DQHWoQW4X36fSNSAPeDMbvef15ujtN6S8K
Salt (hex): 00112233445566778899aabbccddeeff
Nonce (hex): 000102030405060708090a0b
Input: Alice@PayMeDoge.com
Canonical: alice@paymedoge.com
SHA-256: a0fa48a80ca85b5e0b26189c67ecedad7948050adf1a59834e8946cd98469b3c
Label: ud5erkamvbnv4czgdcogp3hnvv4uqbik34nfta2orfdm3gcgtm6a
Lookup name: _pmd.e.ud5erkamvbnv4czgdcogp3hnvv4uqbik34nfta2orfdm3gcgtm6a.paymedoge.com
HKDF info: PMDv1|e
Key (hex): 3358b90a5c4751744fccec7b1b460fb90de8037af3d33690525bfc710affff2a
Plaintext: {"v":1,"net":"doge","a":"DQHWoQW4X36fSNSAPeDMbvef15ujtN6S8K"}
TXT:
v=1;enc=A256GCM;kdf=HKDF-SHA256;s=ABEiM0RVZneImaq7zN3u_w;n=AAECAwQFBgcICQoL;c=EWrNmKVJb_m4MBSZaacDyAjm-lrDQZtPS4fAXscgY-EE-v3W6vUoyLVRqk_jrrcemq8OJk1E5q73pNKrxVl2npkEpQygO96X3WG9F80
Machine-readable copy: protocol/vectors/v1.json in the PayMeDoge reference repository (paymedoge.com).
Reference implementations
- Specification and libraries:
protocol/in the PayMeDoge repository - JavaScript / TypeScript:
protocol/js/paymedoge.js - Python:
protocol/python/paymedoge.py - Rust:
protocol/rust/ - PHP publisher:
app/src/PmdProtocol.php - Dogecoin message verify:
app/src/DogeMessage.php
A wallet integration is:
const { address } = await PayMeDoge.resolve("alice@paymedoge.com");
Deployment
A payee SHOULD publish PMD-1 on a DNSSEC-signed zone they control.
A hosted registrar MAY publish records for users who do not run DNS. That operator is trusted for those names, like any DNS host. One such deployment is paymedoge.com. Resolution does not call that site's HTTP API.
The earlier plaintext TXT flow from 2022 remains useful for a shop that already has a domain. ShibeShip.com resolves that form at checkout.
Dogecoin Core does not need a consensus change to adopt this DIP. Wallet UI support (parse Ðuser@domain, resolve TXT, require DNSSEC, display the resulting address) is sufficient.
Acknowledgements
This work started in early 2022 as a Dogecoin DNS TXT payment pointer, first shown in public on 21 October 2022 and kept live on what-is-dogecoin.com and ShibeShip.com. BIP 353 by Matt Corallo and Bastien Teinturier later set out a related Bitcoin design (DNS, DNSSEC, human-readable names).
https://i.redd.it/td7s7b6ojboh1.png
Source: r/Dogecoiners · by /u/qlp79qlp
