docsReference LibraryGuidesReference Implementation

Reference Implementation Guide — DogeTag Offers and ÐWhisper

This guide gives minimal implementation sketches. It is intentionally small: production wallets still need full transaction construction, fee selection, encryption review, reorg handling, and secure key storage.

For parser conformance vectors and runtime debugging workflow, see:

Send a ÐMP DogeTag Offer

A DogeTag Offer has two parts:

  • A 43-byte Ð:𝕏 OP_RETURN payload, or a 40-byte Ð:X fallback payload when space is tight.
  • A spendable DOGE output to the intended recipient, called the attention amount.

Encode the Payload

import hashlib
import struct
 
 
DXD_MARKER_BRAND = "Ð:𝕏".encode("utf-8")
DXD_MARKER_FALLBACK = "Ð:X".encode("utf-8")
ERA2_LIMIT = 76
 
 
def choose_dxd_marker(body: bytes) -> bytes:
    if len(DXD_MARKER_BRAND + body) <= ERA2_LIMIT:
        return DXD_MARKER_BRAND
    return DXD_MARKER_FALLBACK
 
 
def dogetag_payload(asset_id: str, asset_type: str, price_koinu: int, expiry_delta: int, nonce: int,
                    full_offer_intended: bool = True, sound_hint: bool = False,
                    dogewhisper_link: bool = False) -> bytes:
    flags = 0
    if full_offer_intended:
        flags |= 1 << 0
    if sound_hint:
        flags |= 1 << 1
    if dogewhisper_link:
        flags |= 1 << 2
 
    asset_type_byte = {
        "inscription": 0x01,
        "collection": 0x02,
    }[asset_type]
 
    asset_hash16 = hashlib.sha256(asset_id.encode("utf-8")).digest()[:16]
 
    body = bytes([
        0x01,              # version
        0x01,              # kind: buy offer
        flags,
        asset_type_byte,
    ]) + asset_hash16 + struct.pack("<QII", price_koinu, expiry_delta, nonce)
    return choose_dxd_marker(body) + body

Build the Transaction

def build_dogetag_transaction(wallet, recipient_address, payload, attention_koinu):
    tx = wallet.new_transaction()
    tx.add_op_return(payload)
    tx.add_output(recipient_address, attention_koinu)
    tx.fund_and_sign()
    return tx

Wallets SHOULD enforce a configurable minimum attention amount and SHOULD warn that price_koinu is not escrow.

Decode the Payload

def decode_dogetag(payload: bytes) -> dict:
    if payload.startswith(DXD_MARKER_BRAND):
        marker = "Ð:𝕏"
        offset = len(DXD_MARKER_BRAND)
    elif payload.startswith(DXD_MARKER_FALLBACK):
        marker = "Ð:X"
        offset = len(DXD_MARKER_FALLBACK)
    else:
        raise ValueError("not a DXD DogeTag payload")
 
    body = payload[offset:]
    if len(body) != 36:
        raise ValueError("invalid DogeTag body length")
 
    version, kind, flags, asset_type = body[0], body[1], body[2], body[3]
    price_koinu, expiry_delta, nonce = struct.unpack("<QII", body[20:36])
 
    return {
        "marker": marker,
        "version": version,
        "kind": "buy_offer" if kind == 0x01 else "unknown",
        "flags": {
            "full_dmp_offer_intended": bool(flags & 0x01),
            "sound_hint": bool(flags & 0x02),
            "dogewhisper_link": bool(flags & 0x04),
        },
        "asset_type": "inscription" if asset_type == 0x01 else "collection",
        "asset_hash16": body[4:20].hex(),
        "price_koinu": str(price_koinu),
        "expiry_height_delta": expiry_delta,
        "nonce": nonce,
    }

Decoded objects SHOULD validate against ../../protocols/dmp/schemas/dmp-offer-signal-decoded.json.

Create a ÐWhisper Message

ÐWhisper has:

  • A Ð:W OP_RETURN signal for discovery, short messages, room announcements, and notification hints.
  • An encrypted inscription payload for longer content, room metadata, member envelopes, and media references.

Prepare Recipient Keys

def recipient_key_id(compressed_pubkey_bytes: bytes) -> str:
    return "sha256:" + hashlib.sha256(compressed_pubkey_bytes).hexdigest()

Wallets SHOULD discover recipient chat keys from verified ÐMS records, ÐWhisper key announcements, or a local address book.

Encrypt the Message

This pseudocode omits library-specific details:

from base64 import b64encode
 
 
def to_b64(value: bytes) -> str:
    return "base64:" + b64encode(value).decode("utf-8")
 
 
def create_dogewhisper_message(sender_chat_key, recipient_pubkey, plaintext: bytes, context: dict) -> dict:
    content_key = random_bytes(32)
    nonce = random_bytes(24)
    aad = "Ð:W-1.0".encode("utf-8")
 
    ciphertext = xchacha20poly1305_encrypt(content_key, nonce, plaintext, aad)
    epk, shared_secret = secp256k1_ecdh(sender_chat_key.ephemeral(), recipient_pubkey)
    wrapping_key = hkdf_sha256(shared_secret, info=b"dogewhisper-wrap-v1")
    wrapped_key = wrap_content_key(wrapping_key, content_key, aad)
 
    canonical_encrypted_bytes = ciphertext
 
    return {
        "p": "Ð:W",
        "v": "1.0",
        "op": "message",
        "chain": "dogecoin",
        "context": context,
        "cipher": "xchacha20poly1305",
        "kem": "secp256k1-ecdh-hkdf-sha256",
        "recipients": [
            {
                "kid": recipient_key_id(recipient_pubkey),
                "epk": epk.hex(),
                "wrapped_key": to_b64(wrapped_key),
            }
        ],
        "nonce": to_b64(nonce),
        "aad": to_b64(aad),
        "ciphertext": to_b64(ciphertext),
        "content_hash": "sha256:" + hashlib.sha256(canonical_encrypted_bytes).hexdigest(),
    }

The resulting object SHOULD validate against ../../protocols/dwhisper/schemas/dogewhisper-message.json.

Emit a ÐWhisper Signal

DOGEWHISPER_SIGNAL_MAGIC = "Ð:W".encode("utf-8")
 
 
def dogewhisper_signal(recipient_pubkey_bytes: bytes, ciphertext_or_content_id: bytes, flags: int,
                       expiry_delta: int, nonce: int) -> bytes:
    recipient_hash16 = hashlib.sha256(recipient_pubkey_bytes).digest()[:16]
    content_hash16 = hashlib.sha256(ciphertext_or_content_id).digest()[:16]
    return (
        DOGEWHISPER_SIGNAL_MAGIC
        + bytes([0x01, 0x01, flags, 0x00])
        + recipient_hash16
        + content_hash16
        + struct.pack("<II", expiry_delta, nonce)
    )

Decrypt a Message

def decrypt_dogewhisper_message(local_chat_key, message: dict) -> bytes | None:
    my_kid = recipient_key_id(local_chat_key.public_key_bytes())
    envelope = next((r for r in message["recipients"] if r["kid"] == my_kid), None)
    if envelope is None:
        return None
 
    shared_secret = secp256k1_ecdh(local_chat_key.private_key, bytes.fromhex(envelope["epk"]))
    wrapping_key = hkdf_sha256(shared_secret, info=b"dogewhisper-wrap-v1")
    content_key = unwrap_content_key(wrapping_key, decode_b64(envelope["wrapped_key"]), aad=decode_b64(message["aad"]))
 
    return xchacha20poly1305_decrypt(
        content_key,
        nonce=decode_b64(message["nonce"]),
        ciphertext=decode_b64(message["ciphertext"]),
        aad=decode_b64(message["aad"]),
    )

Never render decrypted content as active HTML, SVG, or script. Treat decrypted bytes as untrusted user content.

Implementation Checklist

  • Use separate chat keys and spend keys.
  • Validate payload lengths before parsing.
  • Treat OP_RETURN signals as hints until matched against wallet inventory or indexed state.
  • Keep DogeTags, ÐWhisper messages, and ÐMP offers as separate state machines.
  • Make sound hints opt-in and rate-limited.
  • Roll back indexed state on reorgs.